[geos-commits] [SCM] GEOS branch main updated. cc9b437c994a0e68b4d04b233e0e10eb015e1390

git at osgeo.org git at osgeo.org
Mon May 26 13:36:30 PDT 2025


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GEOS".

The branch, main has been updated
       via  cc9b437c994a0e68b4d04b233e0e10eb015e1390 (commit)
      from  31399d845873fa03caee5141f7c355cbd0660c83 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit cc9b437c994a0e68b4d04b233e0e10eb015e1390
Author: Martin Davis <mtnclimb at gmail.com>
Date:   Mon May 26 13:36:05 2025 -0700

    Fix DepthSegment comparison logic (#1266)

diff --git a/src/operation/buffer/SubgraphDepthLocater.cpp b/src/operation/buffer/SubgraphDepthLocater.cpp
index 4fc9d578a..2941c020a 100644
--- a/src/operation/buffer/SubgraphDepthLocater.cpp
+++ b/src/operation/buffer/SubgraphDepthLocater.cpp
@@ -70,8 +70,35 @@ public:
     }
 
     /**
-     * Defines a comparison operation on DepthSegments
-     * which orders them left to right
+     * Compares a point to a segment for left/right position, 
+     * as long as the point lies within the segment Y extent.
+     * Otherwise the point is not comparable.
+     * If the point is not comparable or it lies on the segment
+     * returns 0.
+     */
+    int 
+    comparePointInYExtent(const Coordinate& p, const LineSegment& seg) const
+    {
+        //-- if point is comparable to segment
+        if (p.y >= seg.minY() && p.y <= seg.maxY()) {
+          //-- flip sign, since orientation and order relation are opposite
+          int orient = seg.orientationIndex(p);
+          switch (orient) {
+          case Orientation::LEFT: return -1;
+          case Orientation::RIGHT: return 1;
+          }
+          //-- collinear, so indeterminate
+        }
+        //-- not computable
+        return 0;
+    }
+
+    /**
+     * A comparison operation which orders segments left to right
+     * along some horizontal line.
+     * If segments don't touch the same line, 
+     * or touch at the same point,
+     * they are compared in their Y extent.
      *
      * <pre>
      * DS1 < DS2   if   DS1.seg is left of DS2.seg
@@ -84,47 +111,62 @@ public:
     int
     compareTo(const DepthSegment& other) const
     {
+      
         /**
-         * If segment envelopes do not overlap, then
-         * can use standard segment lexicographic ordering.
+         * If segments are disjoint in X, X values provides ordering.
+         * This is the most common case.
          */
-        if (upwardSeg.minX() >= other.upwardSeg.maxX()
-            || upwardSeg.maxX() <= other.upwardSeg.minX()
-            || upwardSeg.minY() >= other.upwardSeg.maxY()
-            || upwardSeg.maxY() <= other.upwardSeg.minY()) {
-            return upwardSeg.compareTo(other.upwardSeg);
-        };
-
+        if (upwardSeg.minX() > other.upwardSeg.maxX())
+            return 1;
+        if (upwardSeg.maxX() < other.upwardSeg.minX())
+            return -1;
         /**
-         * Otherwise if envelopes overlap, use relative segment orientation.
-         *
-         * Collinear segments should be evaluated by previous logic
+         * The segments Y ranges should intersect since they lie on same stabbing line.
+         * But check for this and provide a result based on Y ordering
          */
-        int orientIndex = upwardSeg.orientationIndex(&(other.upwardSeg));
-
-        /*
-         * If comparison between this and other is indeterminate,
-         * try the opposite call order.
-         * orientationIndex value is 1 if this is left of other,
-         * so have to flip sign to get proper comparison value of
-         * -1 if this is leftmost
+        if (upwardSeg.minY() > other.upwardSeg.maxY())
+            return 1;
+        if (upwardSeg.maxY() < other.upwardSeg.minY())
+            return -1;
+        
+        /**
+         * Check if some segment point is left or right
+         * of the other segment in its Y extent.
          */
-        if(orientIndex == 0) {
-            orientIndex = -1 * other.upwardSeg.orientationIndex(&upwardSeg);
+        int comp00 = comparePointInYExtent(upwardSeg.p0, other.upwardSeg);
+        if (comp00 != 0) return comp00;
+        int comp01 = comparePointInYExtent(upwardSeg.p1, other.upwardSeg);
+        if (comp01 != 0) return comp01;
+        //-- negate orientation for other/this checks
+        int comp10 = -comparePointInYExtent(other.upwardSeg.p0, upwardSeg);
+        if (comp10 != 0) return comp10;
+        int comp11 = -comparePointInYExtent(other.upwardSeg.p1, upwardSeg);
+        if (comp11 != 0) return comp11;
+        
+        /**
+         * If point checks in Y range are indeterminate,
+         * segments touch at a point
+         * and lie above and below that point, or are horizontal.
+         * Order according to their Y values.
+         * (The ordering in this case doesn't matter, it just has to be consistent)
+         */
+        if (upwardSeg.maxY() > other.upwardSeg.maxY())
+            return 1;
+        if (upwardSeg.maxY() < other.upwardSeg.maxY())
+            return -1;
+        
+        /**
+         * If both are horizontal order by X
+         */
+        if (upwardSeg.isHorizontal() && other.upwardSeg.isHorizontal()) {
+            if (upwardSeg.minX() < other.upwardSeg.minX())
+                return -1;
+            if (upwardSeg.minX() > other.upwardSeg.minX())
+                return 1;
         }
-
-        // if orientation is determinate, return it
-        if(orientIndex != 0) {
-            return orientIndex;
-        }
-
-        /**
-         * If segment envelopes overlap and they are collinear,
-         * since segments do not cross they must be equal.
-         */
+        
         // assert: segments are equal
-        return 0;
-    }
+        return 0;    }
 };
 
 struct DepthSegmentLessThan {
diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp
index 520256585..b51914ca8 100644
--- a/tests/unit/operation/buffer/BufferOpTest.cpp
+++ b/tests/unit/operation/buffer/BufferOpTest.cpp
@@ -610,4 +610,17 @@ void object::test<27>
 "POLYGON ((48267.2218198241 -49049.37231112561, 44430.1 -55696.500291383236, 44430.1 -55107.58561879013, 44506.96594366424 -54974.50014155032, 44507.05088958367 -54974.309530288774, 44507.09442572395 -54974.10543945913, 44507.09465615313 -54973.896756903174, 44507.05157083636 -54973.69257042533, 44506.96704607295 -54973.50177203271, 44430.1 -54839.73314639927, 44430.1 -51569.2, 44430.08071956347 -51569.00457958696, 44430.02362172434 -51568.81669475566, 44429.93090822513 -51568.64359050924, 44429.80615417933 -51568.49194189856, 42172.42282165639 -49317.178566110095, 48267.2218198241 -49049.37231112561))");    
 }
 
+// testBufferByZeroKeepsAllElements
+// Test a buffer-by-zero case which revealed a bug in the DeptSegment comparator.
+// See https://github.com/locationtech/jts/issues/1131
+template<>
+template<>
+void object::test<28>
+()
+{
+    std::string wkt = "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))";
+    checkBuffer(wkt, 0, 0.01,
+"MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))");    
+}
+
 } // namespace tut

-----------------------------------------------------------------------

Summary of changes:
 src/operation/buffer/SubgraphDepthLocater.cpp | 112 ++++++++++++++++++--------
 tests/unit/operation/buffer/BufferOpTest.cpp  |  13 +++
 2 files changed, 90 insertions(+), 35 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list