[geos-commits] [SCM] GEOS branch main updated. 347b3fad55b05750e471aafa8ca3c7338ba25ee5

git at osgeo.org git at osgeo.org
Fri Dec 5 15:12:33 PST 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  347b3fad55b05750e471aafa8ca3c7338ba25ee5 (commit)
       via  14376eeb7a53f970fc31a574c941fd1d3a4aed5b (commit)
      from  953e1c3d307d9e9a3e2c95fd7b981c39d3365317 (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 347b3fad55b05750e471aafa8ca3c7338ba25ee5
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Fri Dec 5 15:05:31 2025 -0800

    news

diff --git a/NEWS.md b/NEWS.md
index 716795d7a..43926615a 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -5,6 +5,9 @@
 - New things:
   - 
 
+- Breaking Changes:
+  - BufferOp returns POLYGON EMPTY when fed Inf/Nan coords (GH-1332)
+
 
 ## Changes in 3.14.0
 2025-08-21

commit 14376eeb7a53f970fc31a574c941fd1d3a4aed5b
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Fri Dec 5 14:54:19 2025 -0800

    Return EMPTY when confronted with request to buffer input with NaN/Inf coordinates, references #1332

diff --git a/src/operation/buffer/BufferCurveSetBuilder.cpp b/src/operation/buffer/BufferCurveSetBuilder.cpp
index 7fc39e77c..69e5976e3 100644
--- a/src/operation/buffer/BufferCurveSetBuilder.cpp
+++ b/src/operation/buffer/BufferCurveSetBuilder.cpp
@@ -201,6 +201,10 @@ BufferCurveSetBuilder::addLineString(const LineString* line)
 
     auto coord = operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(line->getCoordinatesRO());
 
+    if (coord->size() == 0) {
+        return;
+    }
+
     /**
      * Rings (closed lines) are generated with a continuous curve,
      * with no end arcs. This produces better quality linework,
@@ -272,21 +276,22 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p)
         return;
     }
 
-    auto shellCoord =
+    auto shellCoords =
             operation::valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(shell->getCoordinatesRO());
 
-    if (shellCoord->isEmpty()) {
-        throw util::GEOSException("Shell empty after removing invalid points");
+    if (shellCoords->isEmpty()) {
+        return;
+        //throw util::GEOSException("Shell empty after removing invalid points");
     }
 
     // don't attempt to buffer a polygon
     // with too few distinct vertices
-    if(distance <= 0.0 && shellCoord->size() < 3) {
+    if(distance <= 0.0 && shellCoords->size() < 3) {
         return;
     }
 
     addPolygonRingSide(
-        shellCoord.get(),
+        shellCoords.get(),
         offsetDistance,
         offsetSide,
         Location::EXTERIOR,
@@ -302,13 +307,17 @@ BufferCurveSetBuilder::addPolygon(const Polygon* p)
             continue;
         }
 
-        auto holeCoord = valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(hole->getCoordinatesRO());
+        auto holeCoords = valid::RepeatedPointRemover::removeRepeatedAndInvalidPoints(hole->getCoordinatesRO());
+
+        //-- skip if no valid coordinates
+        if (holeCoords->isEmpty())
+            continue;
 
         // Holes are topologically labelled opposite to the shell,
         // since the interior of the polygon lies on their opposite
         // side (on the left, if the hole is oriented CCW)
         addPolygonRingSide(
-            holeCoord.get(),
+            holeCoords.get(),
             offsetDistance,
             Position::opposite(offsetSide),
             Location::INTERIOR,
diff --git a/tests/unit/capi/GEOSBufferTest.cpp b/tests/unit/capi/GEOSBufferTest.cpp
index 538dfbf75..702cc8dff 100644
--- a/tests/unit/capi/GEOSBufferTest.cpp
+++ b/tests/unit/capi/GEOSBufferTest.cpp
@@ -436,10 +436,15 @@ void object::test<24>()
     std::string wkb("0106000020E61000000100000001030000000100000005000000000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F000000000000F07F");
     geom1_ = GEOSGeomFromHEX_buf(reinterpret_cast<const unsigned char*>(wkb.c_str()), wkb.size());
     ensure(geom1_ != nullptr);
+
+    expected_ = fromWKT("POLYGON EMPTY");
+    ensure(expected_ != nullptr);
+
     geom2_ = GEOSBuffer(geom1_, 20, 8);
-    ensure(geom2_ == nullptr);
+    ensure_geometry_equals(expected_, geom2_, 0.001);
+
     geom3_ = GEOSBuffer(geom1_, -20, 8);
-    ensure(geom3_ == nullptr);
+    ensure_geometry_equals(expected_, geom3_, 0.001);
 }
 
 
diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp
index 7ac585ccc..3e5bc5d92 100644
--- a/tests/unit/operation/buffer/BufferOpTest.cpp
+++ b/tests/unit/operation/buffer/BufferOpTest.cpp
@@ -63,13 +63,19 @@ struct test_bufferop_data {
         ensure_equals("Area", actualArea, expectedArea, tolerance);
     }
 
-    void checkBufferEmpty(const std::string& wkt, double dist, bool isEmpty)
+    void checkBufferPolygonEmpty(const std::string& wkt, double dist, bool isEmpty)
     {
         std::unique_ptr<Geometry> geom = wktreader.read(wkt);
         std::unique_ptr<Geometry> actual = geom->buffer(dist);
         ensure_equals(actual->isEmpty(), isEmpty);
     }
 
+    void checkBufferPolygonEmpty(const Geometry& geom, double dist, bool isEmpty)
+    {
+        std::unique_ptr<Geometry> actual = geom.buffer(dist);
+        ensure_equals(actual->isEmpty(), isEmpty);
+    }
+
     void checkBuffer(const std::string& wkt, double dist, double tolerance, const std::string& wktExpected)
     {
         std::unique_ptr<Geometry> geom = wktreader.read(wkt);
@@ -421,10 +427,10 @@ void object::test<16>
 ()
 {
     std::string wkt0("POLYGON ((666360.09 429614.71, 666344.4 429597.12, 666358.47 429584.52, 666374.5 429602.33, 666360.09 429614.71))");
-    checkBufferEmpty(wkt0, -9, false);
-    checkBufferEmpty(wkt0, -10, true);
-    checkBufferEmpty(wkt0, -15, true);
-    checkBufferEmpty(wkt0, -18, true);
+    checkBufferPolygonEmpty(wkt0, -9, false);
+    checkBufferPolygonEmpty(wkt0, -10, true);
+    checkBufferPolygonEmpty(wkt0, -15, true);
+    checkBufferPolygonEmpty(wkt0, -18, true);
 }
 
 // Test for https://trac.osgeo.org/geos/ticket/1101 - Non-empty negative buffer of 5-pt convex polygon
@@ -434,10 +440,10 @@ void object::test<17>
 ()
 {
     std::string wkt0("POLYGON ((6 20, 16 20, 21 9, 9 0, 0 10, 6 20))");
-    checkBufferEmpty(wkt0, -8, false);
-    checkBufferEmpty(wkt0, -8.6, true);
-    checkBufferEmpty(wkt0, -9.6, true);
-    checkBufferEmpty(wkt0, -11, true);
+    checkBufferPolygonEmpty(wkt0, -8, false);
+    checkBufferPolygonEmpty(wkt0, -8.6, true);
+    checkBufferPolygonEmpty(wkt0, -9.6, true);
+    checkBufferPolygonEmpty(wkt0, -11, true);
 }
 
 // Test for https://trac.osgeo.org/geos/ticket/1101 - Buffer of Polygon with hole with hole eroded
@@ -662,4 +668,39 @@ void object::test<30>
     ensure(bufGeom->getArea() > 12000);
 }
 
+
+// testInvalidCoordPoint
+template<>
+template<>
+void object::test<31> ()
+{
+    // works for Inf ordinates as well
+    auto geom = wktreader.read("POINT (NaN NaN)");
+    checkBufferPolygonEmpty(*geom, 1, true);
+}
+
+// testInvalidCoordsLine
+template<>
+template<>
+void object::test<32> ()
+{
+    // works for Inf ordinates as well
+    auto geom = wktreader.read("LINESTRING (NaN NaN, NaN NaN)");
+    checkBufferPolygonEmpty(*geom, 1, true);
+}
+
+// testInvalidCoordShell
+template<>
+template<>
+void object::test<33> ()
+{
+    // using Inf ordinates creates a valid ring with equal endpoints
+    // this would be simpler if JTS WKT supported Inf
+    auto geom = wktreader.read("POLYGON ((Inf Inf, Inf Inf, Inf Inf, Inf Inf, Inf Inf))");
+    checkBufferPolygonEmpty(*geom, 1, true);
+}
+
+
+
+
 } // namespace tut

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

Summary of changes:
 NEWS.md                                        |  3 ++
 src/operation/buffer/BufferCurveSetBuilder.cpp | 23 +++++++---
 tests/unit/capi/GEOSBufferTest.cpp             |  9 +++-
 tests/unit/operation/buffer/BufferOpTest.cpp   | 59 ++++++++++++++++++++++----
 4 files changed, 76 insertions(+), 18 deletions(-)


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list