From 9a3b6060ac4167aca376c5fa38d56d443bb82a0d Mon Sep 17 00:00:00 2001 From: tanelk Date: Thu, 14 Mar 2024 22:17:41 +0200 Subject: [PATCH 1/2] Fix vertex-vertex intersection in OverlayArea Signed-off-by: tanelk --- .../jts/operation/overlayarea/OverlayArea.java | 10 +++++----- .../jts/operation/overlayarea/SimpleOverlayArea.java | 8 +++----- .../jts/operation/overlayarea/OverlayAreaTest.java | 3 +-- .../operation/overlayarea/SimpleOverlayAreaTest.java | 3 +-- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java index 8e475ebd52..7781e69c53 100644 --- a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java +++ b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java @@ -268,17 +268,17 @@ private static double areaForIntersection(Coordinate a0, Coordinate a1, Coordina * For accuracy the full edge is used to provide the direction vector. */ Coordinate intPt = li.getIntersection(0); - - boolean isAenteringB = Orientation.COUNTERCLOCKWISE == Orientation.index(a0, a1, b1); - - if ( isAenteringB ) { + + if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b0) ) { return EdgeVector.area2Term(intPt, a0, a1, true) + EdgeVector.area2Term(intPt, b1, b0, false); } - else { + else if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b1) ) { return EdgeVector.area2Term(intPt, a1, a0, false) + EdgeVector.area2Term(intPt, b0, b1, true); } + + return 0.0; } private double areaForInteriorVertices(LinearRing ring) { diff --git a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java index 6d386c8af5..c6f204cf70 100644 --- a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java +++ b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java @@ -116,14 +116,12 @@ private double areaForIntersections(CoordinateSequence ringA, boolean isCCWA, Co * Use full edge to compute direction, for accuracy. */ Coordinate intPt = li.getIntersection(0); - - boolean isAenteringB = Orientation.COUNTERCLOCKWISE == Orientation.index(a0, a1, b1); - - if ( isAenteringB ) { + + if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b0) ) { area += EdgeVector.area2Term(intPt, a0, a1, true); area += EdgeVector.area2Term(intPt, b1, b0, false); } - else { + else if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b1) ) { area += EdgeVector.area2Term(intPt, a1, a0, false); area += EdgeVector.area2Term(intPt, b0, b1, true); } diff --git a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java index 369ee013aa..0d9754bcb3 100644 --- a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java +++ b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java @@ -32,8 +32,7 @@ public void testDisjoint() { "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } - //TODO: fix this bug - public void xtestTouching() { + public void testTouching() { checkIntersectionArea( "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); diff --git a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java index c2ab1813d7..a0ea15c0fe 100644 --- a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java +++ b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java @@ -32,8 +32,7 @@ public void testDisjoint() { "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } - //TODO: fix this bug - public void xtestTouching() { + public void testTouching() { checkIntersectionArea( "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); From b871fd91412bd2d33dd7bfc2d96bd37b29013852 Mon Sep 17 00:00:00 2001 From: tanelk Date: Fri, 15 Mar 2024 10:18:18 +0200 Subject: [PATCH 2/2] Avoid counting outside regions in vertex-vertex and vertex-edge intersections Signed-off-by: tanelk --- .../jts/operation/overlayarea/OverlayArea.java | 10 ++++++++++ .../operation/overlayarea/SimpleOverlayArea.java | 10 ++++++++++ .../operation/overlayarea/OverlayAreaTest.java | 16 ++++++++++++++-- .../overlayarea/SimpleOverlayAreaTest.java | 14 +++++++++++++- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java index 7781e69c53..57033f3f2e 100644 --- a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java +++ b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/OverlayArea.java @@ -270,10 +270,20 @@ private static double areaForIntersection(Coordinate a0, Coordinate a1, Coordina Coordinate intPt = li.getIntersection(0); if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b0) ) { + if (intPt.equals2D(a1)) { + // Intersection at vertex and A0 -> A1 is outside of the intersection area + // Area will be computed by the segment A1 -> A2 + return 0.0; + } return EdgeVector.area2Term(intPt, a0, a1, true) + EdgeVector.area2Term(intPt, b1, b0, false); } else if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b1) ) { + if (intPt.equals2D(a0)) { + // Intersection at vertex and A0 -> A1 is outside of the intersection area + // Area will be computed by the segment A(-1) -> A0 + return 0.0; + } return EdgeVector.area2Term(intPt, a1, a0, false) + EdgeVector.area2Term(intPt, b0, b1, true); } diff --git a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java index c6f204cf70..7007c510d9 100644 --- a/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java +++ b/modules/lab/src/main/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayArea.java @@ -118,10 +118,20 @@ private double areaForIntersections(CoordinateSequence ringA, boolean isCCWA, Co Coordinate intPt = li.getIntersection(0); if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b0) ) { + if (intPt.equals2D(a1)) { + // Intersection at vertex and A0 -> A1 is outside of the intersection area + // Area will be computed by the segment A1 -> A2 + continue; + } area += EdgeVector.area2Term(intPt, a0, a1, true); area += EdgeVector.area2Term(intPt, b1, b0, false); } else if ( Orientation.CLOCKWISE == Orientation.index(a0, a1, b1) ) { + if (intPt.equals2D(a0)) { + // Intersection at vertex and A0 -> A1 is outside of the intersection area + // Area will be computed by the segment A(-1) -> A0 + continue; + } area += EdgeVector.area2Term(intPt, a1, a0, false); area += EdgeVector.area2Term(intPt, b0, b1, true); } diff --git a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java index 0d9754bcb3..250d8654a0 100644 --- a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java +++ b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/OverlayAreaTest.java @@ -31,12 +31,24 @@ public void testDisjoint() { "POLYGON ((10 90, 40 90, 40 60, 10 60, 10 90))", "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } - - public void testTouching() { + + public void testTouchingTwoCollinear() { checkIntersectionArea( "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } + + public void testTouchingOneCollinear() { + checkIntersectionArea( + "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", + "POLYGON ((90 10, 49 10, 50 50, 90 50, 90 10))"); + } + + public void testTouchingNoneCollinear() { + checkIntersectionArea( + "POLYGON ((10 90, 50 90, 50 50, 10 52, 10 90))", + "POLYGON ((90 10, 49 10, 50 50, 90 50, 90 10))"); + } public void testRectangleAContainsB() { checkIntersectionArea( diff --git a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java index a0ea15c0fe..1db355703f 100644 --- a/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java +++ b/modules/lab/src/test/java/org/locationtech/jts/operation/overlayarea/SimpleOverlayAreaTest.java @@ -32,12 +32,24 @@ public void testDisjoint() { "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } - public void testTouching() { + public void testTouchingTwoCollinear() { checkIntersectionArea( "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", "POLYGON ((90 10, 50 10, 50 50, 90 50, 90 10))"); } + public void testTouchingOneCollinear() { + checkIntersectionArea( + "POLYGON ((10 90, 50 90, 50 50, 10 50, 10 90))", + "POLYGON ((90 10, 49 10, 50 50, 90 50, 90 10))"); + } + + public void testTouchingNoneCollinear() { + checkIntersectionArea( + "POLYGON ((10 90, 50 90, 50 50, 10 52, 10 90))", + "POLYGON ((90 10, 49 10, 50 50, 90 50, 90 10))"); + } + public void testRectangleAContainsB() { checkIntersectionArea( "POLYGON ((100 300, 300 300, 300 100, 100 100, 100 300))",