From cba889010857ec360e6cd3c1b5456d14e805d7d8 Mon Sep 17 00:00:00 2001 From: Martin Raifer Date: Thu, 21 Jan 2021 16:47:18 +0100 Subject: [PATCH] fix building of multipolygon geometries with degenerate inner rings like two or more identical inner rings --- CHANGELOG.md | 2 ++ .../util/geometry/OSHDBGeometryBuilder.java | 4 ++- ...yBuilderMultipolygonInvalidInnersTest.java | 34 +++++++++++++++++++ .../relations/invalid-inner-rings.osm | 32 +++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 oshdb-util/src/test/java/org/heigit/ohsome/oshdb/util/geometry/relations/OSHDBGeometryBuilderMultipolygonInvalidInnersTest.java create mode 100644 oshdb-util/src/test/resources/relations/invalid-inner-rings.osm diff --git a/CHANGELOG.md b/CHANGELOG.md index 033ca1565..650ccf74e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,12 +20,14 @@ import org.heigit.ohsome.oshdb.api.db.OSHDBH2; ### bugfixes * don't change cluster state when executing queries on an Ignite cluster. ([#335]) +* fix bug when building multipolygon geometries with certain invalid inner ring configurations (e.g. duplicate inner rings). ([#334]) ### upgrading from 0.6.0 * If you already used the “ohsome filter” functionality from OSHDB version 0.6 and imported one or more classes from the ohsome filter module, you would need to adjust the package names from `org.heigit.ohsome.filter` to `org.heigit.ohsome.oshdb.filter`. [#306]: https://github.com/GIScience/oshdb/pull/306 +[#334]: https://github.com/GIScience/oshdb/issues/334 [#335]: https://github.com/GIScience/oshdb/pull/335 diff --git a/oshdb-util/src/main/java/org/heigit/ohsome/oshdb/util/geometry/OSHDBGeometryBuilder.java b/oshdb-util/src/main/java/org/heigit/ohsome/oshdb/util/geometry/OSHDBGeometryBuilder.java index 4c8910b9c..1c5eb546b 100644 --- a/oshdb-util/src/main/java/org/heigit/ohsome/oshdb/util/geometry/OSHDBGeometryBuilder.java +++ b/oshdb-util/src/main/java/org/heigit/ohsome/oshdb/util/geometry/OSHDBGeometryBuilder.java @@ -242,7 +242,9 @@ private static Geometry getMultiPolygonGeometry( List> innerRingsNodes = OSHDBGeometryBuilder.buildRings(innerLines); // check if there are any touching inner/outer rings, merge any mergeTouchingRings(innerRingsNodes); + // create JTS rings for non-degenerate rings only List innerRings = innerRingsNodes.stream() + .filter(ring -> ring.size() >= LinearRing.MINIMUM_VALID_SIZE) .map(ring -> geometryFactory.createLinearRing( ring.stream().map(node -> new Coordinate(node.getLongitude(), node.getLatitude())) .toArray(Coordinate[]::new))) @@ -349,7 +351,7 @@ private static void mergeTouchingRings(Collection> ringsNode // merge this ring (ringNodes) into the previously encountered one (targetNodes) LinkedList targetNodes = ringSegments.get(segment); // remove all segments pointing to the target ring, as we will rebuild it from scratch - ringSegments.values().remove(targetNodes); + ringSegments.values().removeAll(Collections.singleton(targetNodes)); // cut and rewind target and current rings to the matching segment we found cutAtSegment(targetNodes, segment); cutAtSegment(ringNodes, segment); diff --git a/oshdb-util/src/test/java/org/heigit/ohsome/oshdb/util/geometry/relations/OSHDBGeometryBuilderMultipolygonInvalidInnersTest.java b/oshdb-util/src/test/java/org/heigit/ohsome/oshdb/util/geometry/relations/OSHDBGeometryBuilderMultipolygonInvalidInnersTest.java new file mode 100644 index 000000000..48d2bd7eb --- /dev/null +++ b/oshdb-util/src/test/java/org/heigit/ohsome/oshdb/util/geometry/relations/OSHDBGeometryBuilderMultipolygonInvalidInnersTest.java @@ -0,0 +1,34 @@ +package org.heigit.ohsome.oshdb.util.geometry.relations; + +import static org.junit.Assert.assertTrue; + +import org.heigit.ohsome.oshdb.osm.OSMEntity; +import org.heigit.ohsome.oshdb.util.OSHDBTimestamp; +import org.heigit.ohsome.oshdb.util.geometry.OSHDBGeometryBuilder; +import org.heigit.ohsome.oshdb.util.geometry.helpers.OSMXmlReaderTagInterpreter; +import org.heigit.ohsome.oshdb.util.geometry.helpers.TimestampParser; +import org.heigit.ohsome.oshdb.util.taginterpreter.TagInterpreter; +import org.heigit.ohsome.oshdb.util.xmlreader.OSMXmlReader; +import org.junit.Test; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Polygon; + +public class OSHDBGeometryBuilderMultipolygonInvalidInnersTest { + private final OSMXmlReader testData = new OSMXmlReader(); + private final TagInterpreter tagInterpreter; + private final OSHDBTimestamp timestamp = + TimestampParser.toOSHDBTimestamp("2014-01-01T00:00:00Z"); + + public OSHDBGeometryBuilderMultipolygonInvalidInnersTest() { + testData.add("./src/test/resources/relations/invalid-inner-rings.osm"); + tagInterpreter = new OSMXmlReaderTagInterpreter(testData); + } + + @Test + public void test() { + // data has invalid (duplicate) inner rings + OSMEntity entity = testData.relations().get(1L).get(0); + Geometry result = OSHDBGeometryBuilder.getGeometry(entity, timestamp, tagInterpreter); + assertTrue(result instanceof Polygon); + } +} diff --git a/oshdb-util/src/test/resources/relations/invalid-inner-rings.osm b/oshdb-util/src/test/resources/relations/invalid-inner-rings.osm new file mode 100644 index 000000000..a472b93f7 --- /dev/null +++ b/oshdb-util/src/test/resources/relations/invalid-inner-rings.osm @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file