[geos-commits] [SCM] GEOS branch 3.13 updated. b84d32ac39294b73d988e12f4320e0d19ff39453

git at osgeo.org git at osgeo.org
Mon Apr 21 10:29:07 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, 3.13 has been updated
       via  b84d32ac39294b73d988e12f4320e0d19ff39453 (commit)
       via  6f3fe122b32d76bdf445ccaeb15941225d2a34be (commit)
      from  071f7ee5c871167633a878e0ac072cbfe0509d34 (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 b84d32ac39294b73d988e12f4320e0d19ff39453
Author: Martin Davis <mtnclimb at gmail.com>
Date:   Mon Apr 21 10:28:43 2025 -0700

    Update NEWS

diff --git a/NEWS.md b/NEWS.md
index 1ddc661ab..84a803e73 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,6 +4,7 @@
 
 - Fixes/Improvements:
   - Fix GeometryCollections in coverageSimplify cause segfault (GH-1250, Paul Ramsey)
+  - Fix OverlayNG coordinate dimemsion handling for EMPTY geometries (GH-1258, Martin Davis)
 
 ## Changes in 3.13.1
 2025-03-03

commit 6f3fe122b32d76bdf445ccaeb15941225d2a34be
Author: Martin Davis <mtnclimb at gmail.com>
Date:   Mon Apr 21 10:23:46 2025 -0700

    Fix OverlayNG coordinate dimemsion handling for EMPTY geometries (#1258)

diff --git a/include/geos/operation/overlayng/InputGeometry.h b/include/geos/operation/overlayng/InputGeometry.h
index 862ac9f0f..3f78107ee 100644
--- a/include/geos/operation/overlayng/InputGeometry.h
+++ b/include/geos/operation/overlayng/InputGeometry.h
@@ -59,6 +59,7 @@ public:
 
     bool isSingle() const;
     int getDimension(uint8_t index) const;
+    uint8_t getCoordinateDimension(uint8_t index) const;
     const Geometry* getGeometry(uint8_t geomIndex) const;
     const Envelope* getEnvelope(uint8_t geomIndex) const;
     bool isEmpty(uint8_t geomIndex) const;
diff --git a/include/geos/operation/overlayng/OverlayUtil.h b/include/geos/operation/overlayng/OverlayUtil.h
index a033c5a71..d885c9638 100644
--- a/include/geos/operation/overlayng/OverlayUtil.h
+++ b/include/geos/operation/overlayng/OverlayUtil.h
@@ -132,13 +132,13 @@ public:
     static bool isEnvDisjoint(const Geometry* a, const Geometry* b, const PrecisionModel* pm);
 
     /**
-    * Creates an empty result geometry of the appropriate dimension,
+    * Creates an empty result geometry of the appropriate dimension and coordinate dimension,
     * based on the given overlay operation and the dimensions of the inputs.
     * The created geometry is an atomic geometry,
     * not a collection (unless the dimension is -1,
     * in which case a GEOMETRYCOLLECTION EMPTY is created.)
     */
-    static std::unique_ptr<Geometry> createEmptyResult(int dim, const GeometryFactory* geomFact);
+    static std::unique_ptr<Geometry> createEmptyResult(int dim, size_t coordDim, const GeometryFactory* geomFact);
 
     /**
     * Computes the dimension of the result of
@@ -155,6 +155,13 @@ public:
     */
     static int resultDimension(int opCode, int dim0, int dim1);
 
+    /**
+     * Computes the coordinate dimension of overlaying two geometries.
+     * This is the smallest of the two coordinate dimensions 
+     * (to avoid having to populate Z and M with unknown values).
+     */
+    static uint8_t resultCoordinateDimension(uint8_t coordDim0, uint8_t coordDim1);
+
     /**
     * Creates an overlay result geometry for homogeneous or mixed components.
     */
diff --git a/src/geom/HeuristicOverlay.cpp b/src/geom/HeuristicOverlay.cpp
index c164e00fb..57f6683de 100644
--- a/src/geom/HeuristicOverlay.cpp
+++ b/src/geom/HeuristicOverlay.cpp
@@ -341,8 +341,14 @@ StructuredCollection::doUnaryUnion(int resultDim) const
     toVector(poly_union.get(), geoms);
 
     if (geoms.size() == 0) {
+        uint8_t resultCoordDim2 = OverlayUtil::resultCoordinateDimension(
+            pts_less_polys_lines->getCoordinateDimension(), 
+            lines_less_polys->getCoordinateDimension());
+        uint8_t resultCoordDim = OverlayUtil::resultCoordinateDimension(
+            resultCoordDim2, 
+            poly_union->getCoordinateDimension());
         return OverlayUtil::createEmptyResult(
-            resultDim, factory);
+            resultDim, resultCoordDim, factory);
     }
     return factory->buildGeometry(geoms.begin(), geoms.end());
 }
diff --git a/src/operation/overlayng/InputGeometry.cpp b/src/operation/overlayng/InputGeometry.cpp
index 794971887..4ddf4470f 100644
--- a/src/operation/overlayng/InputGeometry.cpp
+++ b/src/operation/overlayng/InputGeometry.cpp
@@ -41,6 +41,15 @@ InputGeometry::getDimension(uint8_t index) const
     return geom[index]->getDimension();
 }
 
+/*public*/
+uint8_t
+InputGeometry::getCoordinateDimension(uint8_t index) const
+{
+    if (geom[index] == nullptr)
+        return 0;
+    return geom[index]->getCoordinateDimension();
+}
+
 /*public*/
 const Geometry*
 InputGeometry::getGeometry(uint8_t geomIndex) const
diff --git a/src/operation/overlayng/OverlayNG.cpp b/src/operation/overlayng/OverlayNG.cpp
index 02cfb9311..43f952f15 100644
--- a/src/operation/overlayng/OverlayNG.cpp
+++ b/src/operation/overlayng/OverlayNG.cpp
@@ -357,11 +357,15 @@ OverlayNG::extractResult(int p_opCode, OverlayGraph* graph)
 std::unique_ptr<Geometry>
 OverlayNG::createEmptyResult()
 {
+    uint8_t coordDim = OverlayUtil::resultCoordinateDimension(
+                            inputGeom.getCoordinateDimension(0), 
+                            inputGeom.getCoordinateDimension(1));
     return OverlayUtil::createEmptyResult(
                 OverlayUtil::resultDimension(opCode,
                     inputGeom.getDimension(0),
                     inputGeom.getDimension(1)),
-                geomFact);
+                    coordDim,
+                    geomFact);
 }
 
 
diff --git a/src/operation/overlayng/OverlayPoints.cpp b/src/operation/overlayng/OverlayPoints.cpp
index 6afe7a211..79018f8ac 100644
--- a/src/operation/overlayng/OverlayPoints.cpp
+++ b/src/operation/overlayng/OverlayPoints.cpp
@@ -108,8 +108,12 @@ OverlayPoints::getResult()
             break;
         }
     }
-    if (rsltList.empty())
-        return OverlayUtil::createEmptyResult(0, geometryFactory);
+    if (rsltList.empty()) {
+        uint8_t coordDim = OverlayUtil::resultCoordinateDimension(
+                                            geom0->getCoordinateDimension(), 
+                                            geom1->getCoordinateDimension());
+        return OverlayUtil::createEmptyResult(0, coordDim, geometryFactory);
+    }
 
     return geometryFactory->buildGeometry(std::move(rsltList));
 }
diff --git a/src/operation/overlayng/OverlayUtil.cpp b/src/operation/overlayng/OverlayUtil.cpp
index 94e6387dc..0f77d1da8 100644
--- a/src/operation/overlayng/OverlayUtil.cpp
+++ b/src/operation/overlayng/OverlayUtil.cpp
@@ -173,18 +173,18 @@ OverlayUtil::isDisjoint(const Envelope* envA, const Envelope* envB, const Precis
 
 /*public static*/
 std::unique_ptr<Geometry>
-OverlayUtil::createEmptyResult(int dim, const GeometryFactory* geomFact)
+OverlayUtil::createEmptyResult(int dim, size_t coordDim, const GeometryFactory* geomFact)
 {
     std::unique_ptr<Geometry> result(nullptr);
     switch (dim) {
     case 0:
-        result = geomFact->createPoint();
+        result = geomFact->createPoint(coordDim);
         break;
     case 1:
-        result = geomFact->createLineString();
+        result = geomFact->createLineString(coordDim);
         break;
     case 2:
-        result = geomFact->createPolygon();
+        result = geomFact->createPolygon(coordDim);
         break;
     case -1:
         result = geomFact->createGeometryCollection();
@@ -224,6 +224,22 @@ OverlayUtil::resultDimension(int opCode, int dim0, int dim1)
     return resultDimension;
 }
 
+/* public static */
+uint8_t
+OverlayUtil::resultCoordinateDimension(uint8_t coordDim0, uint8_t coordDim1)
+{
+    uint8_t resultCoordDim = 4;
+    //-- handle cases where only one geometry provided
+    if (coordDim0 >= 2 && coordDim0 < resultCoordDim) {
+        resultCoordDim = coordDim0;
+    }
+    if (coordDim1 >= 2 && coordDim1 < resultCoordDim) {
+        resultCoordDim = coordDim1;
+    }
+    //-- return value must be 2, 3 or 4
+    return resultCoordDim;
+}
+
 /* public static */
 bool
 OverlayUtil::isResultAreaConsistent(
diff --git a/tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp b/tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp
new file mode 100644
index 000000000..d35cf32a5
--- /dev/null
+++ b/tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp
@@ -0,0 +1,199 @@
+//
+// Test Suite for geos::operation::overlayng::OverlayNG coordinate dimension handling
+// for EMPTY geometries
+
+#include <tut/tut.hpp>
+#include <utility.h>
+
+// geos
+#include <geos/operation/overlayng/OverlayNG.h>
+
+// std
+#include <memory>
+
+using namespace geos::geom;
+using namespace geos::operation::overlayng;
+using geos::io::WKTReader;
+using geos::io::WKTWriter;
+
+namespace tut {
+//
+// Test Group
+//
+
+// Common data used by all tests
+struct test_overlayngcemptyoorddim_data {
+
+    WKTReader r;
+    WKTWriter w;
+
+    void
+    testOverlay(const std::string& a, const std::string& b, int opCode, const std::string& expected)
+    {
+        std::unique_ptr<Geometry> geom_a = r.read(a);
+        std::unique_ptr<Geometry> geom_b = r.read(b);
+        std::unique_ptr<Geometry> geom_expected = r.read(expected);
+        std::unique_ptr<Geometry> geom_result = OverlayNG::overlay(geom_a.get(), geom_b.get(), opCode);
+        // std::string wkt_result = w.write(geom_result.get());
+        // std::cout << std::endl << wkt_result << std::endl;
+        ensure_equals_geometry(geom_expected.get(), geom_result.get());
+        ensure_equals(  "Coordinate dimension: ", 
+                        (int) geom_result.get()->getCoordinateDimension(),
+                        (int) geom_expected.get()->getCoordinateDimension()
+                    );
+    }
+
+};
+
+typedef test_group<test_overlayngcemptyoorddim_data> group;
+typedef group::object object;
+
+group test_overlayngcoorddim_group("geos::operation::overlayng::OverlayNGEmptyCoordDim");
+
+//
+// Test Cases
+//
+
+//--------- POINT / POINT
+
+// test ZM dim for empty POINT union
+template<>
+template<>
+void object::test<1> ()
+{
+    testOverlay("POINT ZM EMPTY", "POINT ZM EMPTY", 
+                OverlayNG::UNION, "POINT ZM EMPTY");
+}
+
+// test ZM dim for empty POINT intersection
+template<>
+template<>
+void object::test<2> ()
+{
+    testOverlay("POINT ZM EMPTY", "POINT ZM EMPTY", 
+        OverlayNG::INTERSECTION, "POINT ZM EMPTY");
+}
+
+// test mixed ZM and XY dim for empty POINT union
+template<>
+template<>
+void object::test<3> ()
+{
+    testOverlay("POINT ZM EMPTY", "POINT EMPTY", 
+        OverlayNG::UNION, "POINT EMPTY");
+}
+
+// test mixed ZM and Z dim for empty POINT union
+template<>
+template<>
+void object::test<4> ()
+{
+    testOverlay("POINT ZM EMPTY", "POINT Z EMPTY", 
+        OverlayNG::UNION, "POINT Z EMPTY");
+}
+
+//--------- LINESTRING / POINT
+
+template<>
+template<>
+void object::test<5> ()
+{
+    testOverlay("POINT ZM EMPTY", "LINESTRING ZM EMPTY", 
+        OverlayNG::UNION, "LINESTRING ZM EMPTY");    
+}
+
+template<>
+template<>
+void object::test<6> ()
+{
+    testOverlay("POINT ZM EMPTY", "LINESTRING Z EMPTY", 
+        OverlayNG::UNION, "LINESTRING Z EMPTY");
+}
+
+template<>
+template<>
+void object::test<7> ()
+{
+    testOverlay("POINT ZM EMPTY", "LINESTRING EMPTY", 
+        OverlayNG::UNION, "LINESTRING EMPTY");
+}
+
+//-- ensure coord dim is lowest of either operand
+template<>
+template<>
+void object::test<8> ()
+{
+    testOverlay("POINT EMPTY", "LINESTRING ZM EMPTY", 
+        OverlayNG::UNION, "LINESTRING EMPTY");
+}
+
+//--------- LINESTRING / LINESTRING
+
+// test ZM dim for empty LINESTRING union
+template<>
+template<>
+void object::test<9> ()
+{
+    testOverlay("LINESTRING ZM EMPTY", "LINESTRING ZM EMPTY", 
+        OverlayNG::UNION, "LINESTRING ZM EMPTY");
+}
+
+// test mixed ZM and XY dim for empty LINESTRING union
+template<>
+template<>
+void object::test<10> ()
+{
+    testOverlay("LINESTRING ZM EMPTY", "LINESTRING Z EMPTY", 
+        OverlayNG::UNION, "LINESTRING Z EMPTY");
+}
+
+// test mixed ZM and Z dim for empty LINESTRING union
+template<>
+template<>
+void object::test<11> ()
+{
+    testOverlay("LINESTRING ZM EMPTY", "LINESTRING EMPTY", 
+        OverlayNG::UNION, "LINESTRING EMPTY");
+}
+
+//--------- GEOMETRYCOLLECTION
+
+//-- coord dim of GC (ZM) EMPTY is always 2
+template<>
+template<>
+void object::test<12> ()
+{
+    testOverlay("GEOMETRYCOLLECTION ZM EMPTY", 
+                "POINT ZM EMPTY", 
+                OverlayNG::UNION, "POINT EMPTY");
+}
+
+//-- coord dim of GC containing EMPTYs is lowest coord dim of elements
+template<>
+template<>
+void object::test<13> ()
+{
+    testOverlay("GEOMETRYCOLLECTION (POINT ZM EMPTY)", 
+        "GEOMETRYCOLLECTION (POINT ZM EMPTY, LINESTRING ZM EMPTY)", 
+        OverlayNG::UNION, "LINESTRING ZM EMPTY");
+}
+
+template<>
+template<>
+void object::test<14> ()
+{
+    testOverlay("GEOMETRYCOLLECTION (POINT Z EMPTY)", 
+        "GEOMETRYCOLLECTION (POINT ZM EMPTY, LINESTRING ZM EMPTY)", 
+        OverlayNG::UNION, "LINESTRING Z EMPTY");
+}
+
+template<>
+template<>
+void object::test<15> ()
+{
+    testOverlay("GEOMETRYCOLLECTION (POINT EMPTY)", 
+        "GEOMETRYCOLLECTION (POINT ZM EMPTY, LINESTRING ZM EMPTY)", 
+        OverlayNG::UNION, "LINESTRING EMPTY");
+}
+
+} // namespace tut

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

Summary of changes:
 NEWS.md                                            |   1 +
 include/geos/operation/overlayng/InputGeometry.h   |   1 +
 include/geos/operation/overlayng/OverlayUtil.h     |  11 +-
 src/geom/HeuristicOverlay.cpp                      |   8 +-
 src/operation/overlayng/InputGeometry.cpp          |   9 +
 src/operation/overlayng/OverlayNG.cpp              |   6 +-
 src/operation/overlayng/OverlayPoints.cpp          |   8 +-
 src/operation/overlayng/OverlayUtil.cpp            |  24 ++-
 .../overlayng/OverlayNGEmptyCoordDimTest.cpp       | 199 +++++++++++++++++++++
 9 files changed, 257 insertions(+), 10 deletions(-)
 create mode 100644 tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list