diff --git a/src/main/java/org/openmaptiles/layers/Water.java b/src/main/java/org/openmaptiles/layers/Water.java index 6ea1afae..bab3bfec 100644 --- a/src/main/java/org/openmaptiles/layers/Water.java +++ b/src/main/java/org/openmaptiles/layers/Water.java @@ -53,6 +53,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.TopologyException; import org.locationtech.jts.geom.util.GeometryFixer; import org.openmaptiles.OpenMapTilesProfile; import org.openmaptiles.generated.OpenMapTilesSchema; @@ -126,10 +127,11 @@ record WaterInfo(int minZoom, int maxZoom, String clazz) {} if (geom.isValid()) { lakeInfo.geom = geom; } else { - LOGGER.warn("fixing geometry of NE lake {}", feature.getLong("ne_id")); + LOGGER.warn("Fixing geometry of NE lake {}", feature.getLong("ne_id")); lakeInfo.geom = GeometryFixer.fix(geom); } lakeInfo.name = feature.getString("name"); + lakeInfo.neId = feature.getLong("ne_id"); var neLakeNameMap = neLakeNameMaps.computeIfAbsent(table, t -> new ConcurrentHashMap<>()); @@ -213,7 +215,12 @@ void attemptNeLakeIdMapping(Tables.OsmWaterPolygon element) throws GeometryExcep } // match by intersection: - var items = neLakeIndex.getIntersecting(geom); + List items; + try { + items = neLakeIndex.getIntersecting(geom); + } catch (TopologyException e) { + throw new GeometryException("intersecting", "Error getting intersecting NE lakes from the index", e); + } for (var lakeInfo : items) { fillOsmIdIntoNeLake(element, geom, lakeInfo, false); } @@ -224,12 +231,25 @@ void attemptNeLakeIdMapping(Tables.OsmWaterPolygon element) throws GeometryExcep * otherwise `true`, to make sure we DO check the intersection but to avoid checking it twice. */ void fillOsmIdIntoNeLake(Tables.OsmWaterPolygon element, Geometry geom, LakeInfo lakeInfo, - boolean intersetsCheckNeeded) { + boolean intersetsCheckNeeded) throws GeometryException { final Geometry neGeom = lakeInfo.geom; if (intersetsCheckNeeded && !neGeom.intersects(geom)) { return; } - var intersection = neGeom.intersection(geom); + Geometry intersection; + try { + intersection = neGeom.intersection(geom); + } catch (TopologyException e) { + stats.dataError("omt_water_intersection"); + LOGGER.warn("omt_water_intersection, NE ID: {}, OSM ID: {}", + lakeInfo.neId, element.source().id(), e); + final var geomFixed = GeometryFixer.fix(geom); + try { + intersection = neGeom.intersection(geomFixed); + } catch (TopologyException e2) { + throw new GeometryException("omt_water_intersection_fix", "Error getting intersection", e); + } + } // Should match following in OpenMapTiles: Distinct on keeps just the first occurence -> order by 'area_ratio DESC' // With a twist: NE geometry is always the same, hence we can make it a little bit faster by dropping "ratio" @@ -272,6 +292,7 @@ private static class LakeInfo { String clazz; Geometry geom; Long osmId; + long neId; double area; public LakeInfo(int minZoom, int maxZoom, String clazz) { @@ -280,6 +301,7 @@ public LakeInfo(int minZoom, int maxZoom, String clazz) { this.maxZoom = maxZoom; this.clazz = clazz; this.osmId = null; + this.neId = -1; this.area = 0; }