This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sedona.git
The following commit(s) were added to refs/heads/master by this push:
new 995b5b1774 [GH-2396] Making splitting polygon by line robust by
removing the computation of line-polygon intersection (#2598)
995b5b1774 is described below
commit 995b5b177443ca35a91605c427f6e7d099cee897
Author: Kristin Cowalcijk <[email protected]>
AuthorDate: Thu Jan 22 16:21:01 2026 +0800
[GH-2396] Making splitting polygon by line robust by removing the
computation of line-polygon intersection (#2598)
---
.../sedona/common/utils/GeometrySplitter.java | 19 +++++++++-----
.../org/apache/sedona/common/FunctionsTest.java | 30 ++++++++++++++++++++++
2 files changed, 43 insertions(+), 6 deletions(-)
diff --git
a/common/src/main/java/org/apache/sedona/common/utils/GeometrySplitter.java
b/common/src/main/java/org/apache/sedona/common/utils/GeometrySplitter.java
index 7045316fed..89473c5d3c 100644
--- a/common/src/main/java/org/apache/sedona/common/utils/GeometrySplitter.java
+++ b/common/src/main/java/org/apache/sedona/common/utils/GeometrySplitter.java
@@ -262,13 +262,9 @@ public final class GeometrySplitter {
}
private Geometry generateCandidatePolygons(Geometry polygons, Geometry
blade) {
- // restrict the blade to only be within the original polygon to
- // avoid candidate polygons that are impossible
- Geometry bladeWithinPolygons = blade.intersection(polygons);
-
// a union will node all the lines at intersections
// these nodes are required for Polygonizer to work correctly
- Geometry totalLineWork = polygons.getBoundary().union(bladeWithinPolygons);
+ Geometry totalLineWork = polygons.getBoundary().union(blade);
Polygonizer polygonizer = new Polygonizer();
polygonizer.add(totalLineWork);
@@ -281,7 +277,18 @@ public final class GeometrySplitter {
// original geometry to ensure holes in the original geometry are excluded
for (int i = 0; i < polygons.getNumGeometries(); i++) {
Geometry candidateResult = polygons.getGeometryN(i);
- if (candidateResult instanceof Polygon &&
original.contains(candidateResult)) {
+ if (!(candidateResult instanceof Polygon)) {
+ continue;
+ }
+
+ Point pointOnSurface = candidateResult.getInteriorPoint();
+ // getInteriorPoint() may return null for degenerate or empty polygonal
geometries,
+ // so guard against null before using the point.
+ if (pointOnSurface == null) {
+ continue;
+ }
+
+ if (original.covers(pointOnSurface)) {
list.add((Polygon) candidateResult);
}
}
diff --git a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
index c5eac14c39..c4e6325143 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -531,6 +531,36 @@ public class FunctionsTest extends TestBase {
assertNull(actualResult);
}
+ @Test
+ public void splitCircleInto2SemiCircles() throws ParseException {
+ String polygonWkt =
+ "POLYGON ((-117.76405581088967 34.111876749328026, -117.76407506132291
34.11170068822483, "
+ + "-117.76413523652074 34.111531133837936, -117.76423402376724
34.11137460199335, -117.76436762657538 34.11123710803779, "
+ + "-117.76453091060647 34.11112393568514, -117.76471760098879
34.11103943398174, -117.76492052345083 34.11098685019075, "
+ + "-117.76513188000408 34.1109682050154, -117.76534354858369
34.11098421495394, -117.76554739513688 34.11103426476887, "
+ + "-117.76573558617179 34.11111643112786, -117.76590088976099
34.111227556508084, -117.76603695343799 34.11136337052523, "
+ + "-117.76613854831002 34.11151865402651, -117.76620177000793
34.11168743964393, -117.76622418874936 34.111863241103265, "
+ + "-117.76620494274577 34.11203930247842, -117.76614477135817
34.11220885781403, -117.7660459867224 34.11236539113964, "
+ + "-117.76591238492807 34.11250288688306, -117.7657491001595
34.11261606105824, -117.7655624074007 34.11270056434135, "
+ + "-117.76535948128496 34.112753149228745, -117.76514812035703
34.11277179485027, -117.76493644734776 34.112755784639766, "
+ + "-117.76473259698435 34.112705733876126, -117.76454440333869
34.11262356603611, -117.76437909873567 34.11251243886801, "
+ + "-117.76424303579616 34.11237662302835, -117.76414144330062
34.112221337947354, -117.76407822525644 34.11205255123353, "
+ + "-117.76405581088967 34.111876749328026))";
+ String knifeWkt =
+ "LINESTRING (-117.7640751398563 34.111535124121441,
-117.76628486838135 34.112204866513046)";
+
+ Geometry polygon = Constructors.geomFromWKT(polygonWkt, 4326);
+ Geometry knife = Constructors.geomFromWKT(knifeWkt, 4326);
+ Geometry resultPolygon = Functions.split(polygon, knife);
+ assertEquals(2, resultPolygon.getNumGeometries());
+
+ double circleArea = polygon.getArea();
+ for (int i = 0; i < resultPolygon.getNumGeometries(); i++) {
+ double actualArea = resultPolygon.getGeometryN(i).getArea();
+ assertEquals(2.0, circleArea / actualArea, 0.1);
+ }
+ }
+
@Test
public void dimensionGeometry2D() {
Point point = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 2));