From cca35b08a203abc3356e29eee5a610177253b469 Mon Sep 17 00:00:00 2001 From: arimu1 <19286898+arimu1@users.noreply.github.com> Date: Sat, 26 Sep 2026 10:47:20 +0700 Subject: [PATCH] fix(jts): align GEOMETRYCOLLECTION with MULTIPOLYGON WKT parse JtsMultiShapeBuilder re-wrapped homogeneous children via makeShapeFromGeometry, which re-validated geometries that multi* builders already accept via makeShape. Return a lone child unchanged and use makeShape for homogeneous Multi* merges. Fixes #232 Signed-off-by: arimu1 <19286898+arimu1@users.noreply.github.com> --- .../spatial4j/shape/jts/JtsShapeFactory.java | 11 ++++++++++- .../spatial4j/io/JtsWktShapeParserTest.java | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/locationtech/spatial4j/shape/jts/JtsShapeFactory.java b/src/main/java/org/locationtech/spatial4j/shape/jts/JtsShapeFactory.java index f162051dc..50edd6839 100755 --- a/src/main/java/org/locationtech/spatial4j/shape/jts/JtsShapeFactory.java +++ b/src/main/java/org/locationtech/spatial4j/shape/jts/JtsShapeFactory.java @@ -443,7 +443,16 @@ public Shape build() { last = s.getClass(); } - return makeShapeFromGeometry(geometryFactory.buildGeometry(geoms)); + if (shapes.size() == 1) { + return shapes.get(0); + } + + Geometry combined = geometryFactory.buildGeometry(geoms); + // Homogeneous collections become Multi* types; match multi* builders (no re-validate). + if (combined.getClass().equals(GeometryCollection.class)) { + return makeShapeFromGeometry(combined); + } + return makeShape(combined); } } diff --git a/src/test/java/org/locationtech/spatial4j/io/JtsWktShapeParserTest.java b/src/test/java/org/locationtech/spatial4j/io/JtsWktShapeParserTest.java index 429d26e92..c755c66a1 100644 --- a/src/test/java/org/locationtech/spatial4j/io/JtsWktShapeParserTest.java +++ b/src/test/java/org/locationtech/spatial4j/io/JtsWktShapeParserTest.java @@ -138,6 +138,17 @@ public void testLineStringDateline() throws ParseException { assertEquals(30, s.getBoundingBox().getWidth(), 0.0 ); } + @Test + public void selfIntersectingMultiPolygonSameInGeometryCollection() throws ParseException { + WKTReader geoReader = (WKTReader) JtsSpatialContext.GEO.getFormats().getWktReader(); + String multi = + "MULTIPOLYGON (((5 5, 10 5, 10 10, 5 5)), ((6 6, 10 5, 10 10, 6 6)))"; + String collection = + "GEOMETRYCOLLECTION ( MULTIPOLYGON (((5 5, 10 5, 10 10, 5 5)), ((6 6, 10 5, 10 10, 6 6))) )"; + geoReader.parse(multi); + geoReader.parse(collection); + } + @Test public void testWrapTopologyException() throws Exception { //test that we can catch ParseException without having to detect TopologyException too