diff --git a/src/main/java/com/onthegomap/flatmap/geo/GeoUtils.java b/src/main/java/com/onthegomap/flatmap/geo/GeoUtils.java index 4ddd5ea4..56c85d0b 100644 --- a/src/main/java/com/onthegomap/flatmap/geo/GeoUtils.java +++ b/src/main/java/com/onthegomap/flatmap/geo/GeoUtils.java @@ -11,10 +11,11 @@ import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.MultiPoint; import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.TopologyException; +import org.locationtech.jts.geom.PrecisionModel; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.locationtech.jts.geom.util.GeometryTransformer; import org.locationtech.jts.io.WKBReader; +import org.locationtech.jts.precision.GeometryPrecisionReducer; public class GeoUtils { @@ -196,19 +197,24 @@ public class GeoUtils { return JTS_FACTORY.createMultiLineString(lineStrings.toArray(EMPTY_LINE_STRING_ARRAY)); } - public static Geometry fixPolygon(Geometry geom, int maxAttempts) throws GeometryException { + public static Geometry snapAndFixPolygon(Geometry geom, PrecisionModel tilePrecision) throws GeometryException { try { - int attempts; - for (attempts = 0; attempts < maxAttempts && !geom.isValid(); attempts++) { + return GeometryPrecisionReducer.reduce(geom, tilePrecision); + } catch (IllegalArgumentException e) { + // precision reduction fails if geometry is invalid, so attempt + // to fix it then try again + geom = geom.buffer(0); + try { + return GeometryPrecisionReducer.reduce(geom, tilePrecision); + } catch (IllegalArgumentException e2) { + // give it one last try, just in case geom = geom.buffer(0); + try { + return GeometryPrecisionReducer.reduce(geom, tilePrecision); + } catch (IllegalArgumentException e3) { + throw new GeometryException("Error reducing precision"); + } } - - if (attempts == maxAttempts) { - throw new GeometryException("Geometry still invalid after 2 buffers"); - } - return geom; - } catch (TopologyException e) { - throw new GeometryException("Unable to fix polygon: " + e); } } diff --git a/src/main/java/com/onthegomap/flatmap/render/FeatureRenderer.java b/src/main/java/com/onthegomap/flatmap/render/FeatureRenderer.java index 8b6ff97a..aff906bc 100644 --- a/src/main/java/com/onthegomap/flatmap/render/FeatureRenderer.java +++ b/src/main/java/com/onthegomap/flatmap/render/FeatureRenderer.java @@ -26,7 +26,6 @@ import org.locationtech.jts.geom.Polygonal; import org.locationtech.jts.geom.PrecisionModel; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.locationtech.jts.geom.util.AffineTransformation; -import org.locationtech.jts.precision.GeometryPrecisionReducer; import org.locationtech.jts.simplify.DouglasPeuckerSimplifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -172,17 +171,11 @@ public class FeatureRenderer { Geometry geom; if (feature.area()) { geom = CoordinateSequenceExtractor.reassemblePolygons(geoms); - geom = GeoUtils.fixPolygon(geom, 2); + geom = GeoUtils.snapAndFixPolygon(geom, tilePrecision); } else { geom = CoordinateSequenceExtractor.reassembleLineStrings(geoms); } - try { - geom = GeometryPrecisionReducer.reduce(geom, tilePrecision); - } catch (IllegalArgumentException e) { - throw new GeometryException("Error reducing precision"); - } - if (!geom.isEmpty()) { // JTS utilities "fix" the geometry to be clockwise outer/CCW inner if (feature.area()) {