kopia lustrzana https://github.com/onthegomap/planetiler
170 wiersze
6.3 KiB
Java
170 wiersze
6.3 KiB
Java
package com.onthegomap.planetiler.reader;
|
|
|
|
import com.onthegomap.planetiler.Profile;
|
|
import com.onthegomap.planetiler.collection.FeatureGroup;
|
|
import com.onthegomap.planetiler.config.PlanetilerConfig;
|
|
import com.onthegomap.planetiler.stats.Stats;
|
|
import com.onthegomap.planetiler.util.FileUtils;
|
|
import java.io.IOException;
|
|
import java.io.UncheckedIOException;
|
|
import java.net.URLEncoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.function.Consumer;
|
|
import mil.nga.geopackage.GeoPackage;
|
|
import mil.nga.geopackage.GeoPackageManager;
|
|
import mil.nga.geopackage.features.user.FeatureColumns;
|
|
import mil.nga.geopackage.features.user.FeatureDao;
|
|
import mil.nga.geopackage.geom.GeoPackageGeometryData;
|
|
import org.geotools.geometry.jts.JTS;
|
|
import org.geotools.geometry.jts.WKBReader;
|
|
import org.geotools.referencing.CRS;
|
|
import org.locationtech.jts.geom.Geometry;
|
|
import org.opengis.referencing.FactoryException;
|
|
import org.opengis.referencing.operation.MathTransform;
|
|
|
|
/**
|
|
* Utility that reads {@link SourceFeature SourceFeatures} from the vector geometries contained in a GeoPackage file.
|
|
*/
|
|
public class GeoPackageReader extends SimpleReader<SimpleFeature> {
|
|
|
|
private final boolean keepUnzipped;
|
|
private Path extractedPath = null;
|
|
private final GeoPackage geoPackage;
|
|
private final MathTransform coordinateTransform;
|
|
|
|
GeoPackageReader(String sourceProjection, String sourceName, Path input, Path tmpDir, boolean keepUnzipped) {
|
|
super(sourceName);
|
|
this.keepUnzipped = keepUnzipped;
|
|
|
|
if (sourceProjection != null) {
|
|
try {
|
|
var sourceCRS = CRS.decode(sourceProjection);
|
|
var latLonCRS = CRS.decode("EPSG:4326");
|
|
coordinateTransform = CRS.findMathTransform(sourceCRS, latLonCRS);
|
|
} catch (FactoryException e) {
|
|
throw new FileFormatException("Bad reference system", e);
|
|
}
|
|
} else {
|
|
coordinateTransform = null;
|
|
}
|
|
|
|
try {
|
|
geoPackage = openGeopackage(input, tmpDir);
|
|
} catch (IOException e) {
|
|
throw new UncheckedIOException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a {@link GeoPackageManager} for the given path. If {@code input} refers to a file within a ZIP archive,
|
|
* first extract it.
|
|
*/
|
|
private GeoPackage openGeopackage(Path input, Path unzippedDir) throws IOException {
|
|
var inputUri = input.toUri();
|
|
if ("jar".equals(inputUri.getScheme())) {
|
|
extractedPath = keepUnzipped ? unzippedDir.resolve(URLEncoder.encode(input.toString(), StandardCharsets.UTF_8)) :
|
|
Files.createTempFile(unzippedDir, "", ".gpkg");
|
|
FileUtils.createParentDirectories(extractedPath);
|
|
if (!keepUnzipped || FileUtils.isNewer(input, extractedPath)) {
|
|
try (var inputStream = inputUri.toURL().openStream()) {
|
|
FileUtils.safeCopy(inputStream, extractedPath);
|
|
}
|
|
}
|
|
return GeoPackageManager.open(false, extractedPath.toFile());
|
|
}
|
|
|
|
return GeoPackageManager.open(false, input.toFile());
|
|
}
|
|
|
|
|
|
/**
|
|
* Renders map features for all elements from an OGC GeoPackage based on the mapping logic defined in {@code
|
|
* profile}.
|
|
*
|
|
* @param sourceProjection code for the coordinate reference system of the input data, to be parsed by
|
|
* {@link CRS#decode(String)}
|
|
* @param sourceName string ID for this reader to use in logs and stats
|
|
* @param sourcePaths paths to the {@code .gpkg} files on disk
|
|
* @param tmpDir path to temporary directory for extracting data from zip files
|
|
* @param writer consumer for rendered features
|
|
* @param config user-defined parameters controlling number of threads and log interval
|
|
* @param profile logic that defines what map features to emit for each source feature
|
|
* @param stats to keep track of counters and timings
|
|
* @param keepUnzipped to keep unzipped files around after running (speeds up subsequent runs, but uses more disk)
|
|
* @throws IllegalArgumentException if a problem occurs reading the input file
|
|
*/
|
|
public static void process(String sourceProjection, String sourceName, List<Path> sourcePaths, Path tmpDir,
|
|
FeatureGroup writer, PlanetilerConfig config, Profile profile, Stats stats, boolean keepUnzipped) {
|
|
SourceFeatureProcessor.processFiles(
|
|
sourceName,
|
|
sourcePaths,
|
|
path -> new GeoPackageReader(sourceProjection, sourceName, path, tmpDir, keepUnzipped),
|
|
writer, config, profile, stats
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public long getFeatureCount() {
|
|
long numFeatures = 0;
|
|
|
|
for (String name : geoPackage.getFeatureTables()) {
|
|
FeatureDao features = geoPackage.getFeatureDao(name);
|
|
numFeatures += features.count();
|
|
}
|
|
return numFeatures;
|
|
}
|
|
|
|
@Override
|
|
public void readFeatures(Consumer<SimpleFeature> next) throws Exception {
|
|
var latLonCRS = CRS.decode("EPSG:4326");
|
|
long id = 0;
|
|
|
|
for (var featureName : geoPackage.getFeatureTables()) {
|
|
FeatureDao features = geoPackage.getFeatureDao(featureName);
|
|
|
|
// GeoPackage spec allows this to be 0 (undefined geographic CRS) or
|
|
// -1 (undefined cartesian CRS). Both cases will throw when trying to
|
|
// call CRS.decode
|
|
long srsId = features.getSrsId();
|
|
|
|
MathTransform transform = (coordinateTransform != null) ? coordinateTransform :
|
|
CRS.findMathTransform(CRS.decode("EPSG:" + srsId), latLonCRS);
|
|
|
|
for (var feature : features.queryForAll()) {
|
|
GeoPackageGeometryData geometryData = feature.getGeometry();
|
|
if (geometryData == null) {
|
|
continue;
|
|
}
|
|
|
|
Geometry featureGeom = (new WKBReader()).read(geometryData.getWkb());
|
|
Geometry latLonGeom = (transform.isIdentity()) ? featureGeom : JTS.transform(featureGeom, transform);
|
|
|
|
FeatureColumns columns = feature.getColumns();
|
|
SimpleFeature geom = SimpleFeature.create(latLonGeom, new HashMap<>(columns.columnCount()),
|
|
sourceName, featureName, ++id);
|
|
|
|
for (int i = 0; i < columns.columnCount(); ++i) {
|
|
if (i != columns.getGeometryIndex()) {
|
|
geom.setTag(columns.getColumnName(i), feature.getValue(i));
|
|
}
|
|
}
|
|
|
|
next.accept(geom);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
geoPackage.close();
|
|
|
|
if (!keepUnzipped && extractedPath != null) {
|
|
FileUtils.delete(extractedPath);
|
|
}
|
|
}
|
|
}
|