diff --git a/planetiler-core/src/main/java/com/onthegomap/planetiler/reader/GeoPackageReader.java b/planetiler-core/src/main/java/com/onthegomap/planetiler/reader/GeoPackageReader.java index e4568a9b..e326436a 100644 --- a/planetiler-core/src/main/java/com/onthegomap/planetiler/reader/GeoPackageReader.java +++ b/planetiler-core/src/main/java/com/onthegomap/planetiler/reader/GeoPackageReader.java @@ -25,11 +25,14 @@ import org.geotools.referencing.CRS; import org.locationtech.jts.geom.Geometry; import org.opengis.referencing.FactoryException; import org.opengis.referencing.operation.MathTransform; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility that reads {@link SourceFeature SourceFeatures} from the vector geometries contained in a GeoPackage file. */ public class GeoPackageReader extends SimpleReader { + private static final Logger LOGGER = LoggerFactory.getLogger(GeoPackageReader.class); private final boolean keepUnzipped; private Path extractedPath = null; @@ -122,6 +125,7 @@ public class GeoPackageReader extends SimpleReader { public void readFeatures(Consumer next) throws Exception { var latLonCRS = CRS.decode("EPSG:4326"); long id = 0; + boolean loggedMissingGeometry = false; for (var featureName : geoPackage.getFeatureTables()) { FeatureDao features = geoPackage.getFeatureDao(featureName); @@ -136,11 +140,16 @@ public class GeoPackageReader extends SimpleReader { for (var feature : features.queryForAll()) { GeoPackageGeometryData geometryData = feature.getGeometry(); - if (geometryData == null) { + byte[] wkb; + if (geometryData == null || (wkb = geometryData.getWkb()).length == 0) { + if (!loggedMissingGeometry) { + loggedMissingGeometry = true; + LOGGER.warn("Geopackage file contains empty geometry: {}", geoPackage.getPath()); + } continue; } - Geometry featureGeom = (new WKBReader()).read(geometryData.getWkb()); + Geometry featureGeom = (new WKBReader()).read(wkb); Geometry latLonGeom = (transform.isIdentity()) ? featureGeom : JTS.transform(featureGeom, transform); FeatureColumns columns = feature.getColumns(); diff --git a/planetiler-core/src/test/java/com/onthegomap/planetiler/reader/GeoPackageReaderTest.java b/planetiler-core/src/test/java/com/onthegomap/planetiler/reader/GeoPackageReaderTest.java index 1957a262..ea0675be 100644 --- a/planetiler-core/src/test/java/com/onthegomap/planetiler/reader/GeoPackageReaderTest.java +++ b/planetiler-core/src/test/java/com/onthegomap/planetiler/reader/GeoPackageReaderTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import com.onthegomap.planetiler.TestUtils; -import com.onthegomap.planetiler.collection.IterableOnce; import com.onthegomap.planetiler.geo.GeoUtils; import com.onthegomap.planetiler.stats.Stats; import com.onthegomap.planetiler.util.FileUtils; @@ -13,7 +12,8 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; @@ -45,9 +45,7 @@ class GeoPackageReaderTest { List points = new ArrayList<>(); List names = new ArrayList<>(); WorkerPipeline.start("test", Stats.inMemory()) - .readFromTiny("files", List.of(Path.of("dummy-path"))) - .addWorker("geopackage", 1, - (IterableOnce p, Consumer next) -> reader.readFeatures(next)) + .fromGenerator("geopackage", reader::readFeatures, 1) .addBuffer("reader_queue", 100, 1) .sinkToConsumer("counter", 1, elem -> { assertTrue(elem.getTag("name") instanceof String); @@ -67,4 +65,27 @@ class GeoPackageReaderTest { } } } + + @Test + @Timeout(30) + void testReadEmptyGeoPackage() throws IOException { + Path path = TestUtils.pathToResource("empty-geom.gpkg"); + + try ( + var reader = new GeoPackageReader(null, "test", path, tmpDir, false) + ) { + 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()); + } + } + } } diff --git a/planetiler-core/src/test/resources/empty-geom.gpkg b/planetiler-core/src/test/resources/empty-geom.gpkg new file mode 100644 index 00000000..c8294df1 Binary files /dev/null and b/planetiler-core/src/test/resources/empty-geom.gpkg differ