Skip to content

Commit

Permalink
Use rtree spatial index from PlanetilerConfig bounds by default for G…
Browse files Browse the repository at this point in the history
…eopackages (#635)
  • Loading branch information
bdon authored Feb 20, 2025
1 parent 8287efb commit 6f18e0a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ public Planetiler addShapefileSource(String projection, String name, Path defaul
* @see Downloader
*/
public Planetiler addGeoPackageSource(String projection, String name, Path defaultPath, String defaultUrl) {

Path path = getPath(name, "geopackage", defaultPath, defaultUrl);
boolean keepUnzipped = getKeepUnzipped(name);
return addStage(name, "Process features in " + path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.onthegomap.planetiler.Profile;
import com.onthegomap.planetiler.collection.FeatureGroup;
import com.onthegomap.planetiler.config.Bounds;
import com.onthegomap.planetiler.config.PlanetilerConfig;
import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.FileUtils;
Expand All @@ -16,12 +17,17 @@
import java.util.function.Consumer;
import mil.nga.geopackage.GeoPackage;
import mil.nga.geopackage.GeoPackageManager;
import mil.nga.geopackage.features.index.FeatureIndexManager;
import mil.nga.geopackage.features.index.FeatureIndexType;
import mil.nga.geopackage.features.user.FeatureColumns;
import mil.nga.geopackage.features.user.FeatureDao;
import mil.nga.geopackage.features.user.FeatureRow;
import mil.nga.geopackage.geom.GeoPackageGeometryData;
import mil.nga.sf.GeometryEnvelope;
import org.geotools.api.referencing.FactoryException;
import org.geotools.api.referencing.operation.MathTransform;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.geometry.jts.WKBReader;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
Expand All @@ -39,9 +45,14 @@ public class GeoPackageReader extends SimpleReader<SimpleFeature> {
private final GeoPackage geoPackage;
private final MathTransform coordinateTransform;

GeoPackageReader(String sourceProjection, String sourceName, Path input, Path tmpDir, boolean keepUnzipped) {
private final Bounds bounds;

GeoPackageReader(String sourceProjection, String sourceName, Path input, Path tmpDir, boolean keepUnzipped,
Bounds bounds) {

super(sourceName);
this.keepUnzipped = keepUnzipped;
this.bounds = bounds;

if (sourceProjection != null) {
try {
Expand Down Expand Up @@ -105,7 +116,7 @@ public static void process(String sourceProjection, String sourceName, List<Path
SourceFeatureProcessor.processFiles(
sourceName,
sourcePaths,
path -> new GeoPackageReader(sourceProjection, sourceName, path, tmpDir, keepUnzipped),
path -> new GeoPackageReader(sourceProjection, sourceName, path, tmpDir, keepUnzipped, config.bounds()),
writer, config, profile, stats
);
}
Expand Down Expand Up @@ -138,7 +149,22 @@ public void readFeatures(Consumer<SimpleFeature> next) throws Exception {
MathTransform transform = (coordinateTransform != null) ? coordinateTransform :
CRS.findMathTransform(CRS.decode("EPSG:" + srsId), latLonCRS);

for (var feature : features.queryForAll()) {
FeatureIndexManager indexer = new FeatureIndexManager(geoPackage,
features);

Iterable<FeatureRow> results;

if (this.bounds != null && indexer.isIndexed()) {
var l = this.bounds.latLon();
indexer.setIndexLocation(FeatureIndexType.RTREE);
var bbox = new ReferencedEnvelope(l.getMinX(), l.getMaxX(), l.getMinY(), l.getMaxY(), latLonCRS);
var bbox2 = bbox.transform(CRS.decode("EPSG:" + srsId), true);
results = indexer.query(new GeometryEnvelope(bbox2.getMinX(), bbox2.getMinY(), bbox2.getMaxX(), bbox2.getMaxY()));
} else {
results = features.queryForAll();
}

for (FeatureRow feature : results) {
GeoPackageGeometryData geometryData = feature.getGeometry();
byte[] wkb;
if (geometryData == null || (wkb = geometryData.getWkb()).length == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.onthegomap.planetiler.TestUtils;
import com.onthegomap.planetiler.config.Bounds;
import com.onthegomap.planetiler.geo.GeoUtils;
import com.onthegomap.planetiler.stats.Stats;
import com.onthegomap.planetiler.util.FileUtils;
Expand All @@ -17,7 +18,9 @@
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;

class GeoPackageReaderTest {
Expand All @@ -37,7 +40,7 @@ void testReadGeoPackage(boolean keepUnzipped) throws IOException {
for (var path : List.of(pathOutsideZip, pathInZip)) {
for (var proj : projections) {
try (
var reader = new GeoPackageReader(proj, "test", path, tmpDir, keepUnzipped)
var reader = new GeoPackageReader(proj, "test", path, tmpDir, keepUnzipped, null)
) {
for (int iter = 0; iter < 2; iter++) {
String id = "path=" + path + " proj=" + proj + " iter=" + iter;
Expand Down Expand Up @@ -66,26 +69,46 @@ void testReadGeoPackage(boolean keepUnzipped) throws IOException {
}
}


@ParameterizedTest
@CsvSource({
"geopackage.gpkg,4",
"geopackage-unindexed.gpkg,86"
})
@Timeout(30)
void testReadGeoPackageSpatialIndex(String dbName, int expectedCount) throws Exception {
Path path = TestUtils.pathToResource(dbName);

var proj = "EPSG:4326";

try (
var reader =
new GeoPackageReader(proj, "test", path, tmpDir, false, new Bounds(new Envelope(-77.0306, -77.0192, 38.8894, 38.9014)));
) {
String id = "path=" + path + " proj=" + proj;
assertEquals(86, reader.getFeatureCount(), id);
List<Geometry> points = new ArrayList<>();
reader.readFeatures(feature -> {
points.add(feature.latLonGeometry());
});
assertEquals(expectedCount, points.size(), id);
}
}

@Test
@Timeout(30)
void testReadEmptyGeoPackage() throws IOException {
void testReadEmptyGeoPackage() throws Exception {
Path path = TestUtils.pathToResource("empty-geom.gpkg");

try (
var reader = new GeoPackageReader(null, "test", path, tmpDir, false)
var reader = new GeoPackageReader(null, "test", path, tmpDir, false, null)
) {
for (int iter = 0; iter < 2; iter++) {
String id = "iter=" + iter;
assertEquals(1, reader.getFeatureCount(), id);
AtomicInteger found = new AtomicInteger(0);
WorkerPipeline.start("test", Stats.inMemory())
.fromGenerator("geopackage", reader::readFeatures, 1)
.addBuffer("reader_queue", 100, 1)
.sinkToConsumer("counter", 1, elem -> {
found.incrementAndGet();
}).await();
assertEquals(0, found.get());
}
assertEquals(1, reader.getFeatureCount());
AtomicInteger found = new AtomicInteger(0);
reader.readFeatures(feature -> {
found.incrementAndGet();
});
assertEquals(0, found.get());
}
}
}
Binary file not shown.

0 comments on commit 6f18e0a

Please sign in to comment.