[geos-commits] [SCM] GEOS branch 3.12 updated. 86039e06d249dbae6b53a9ff6480b7a36d24cc06

git at osgeo.org git at osgeo.org
Mon Apr 21 10:37:14 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.12 has been updated
       via  86039e06d249dbae6b53a9ff6480b7a36d24cc06 (commit)
       via  5f05f9bb954986e2640d141b96a064d3c109638c (commit)
      from  0293c1e898082f43102ab1011d49e7ddc8f2c9ce (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 86039e06d249dbae6b53a9ff6480b7a36d24cc06
Author: Martin Davis <mtnclimb at gmail.com>
Date:   Mon Apr 21 10:36:52 2025 -0700

    Update NEWS

diff --git a/NEWS.md b/NEWS.md
index 56060dee0..17e9c0760 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,7 +2,7 @@
 2025-xx-xx
 
 - Fixes:
-  - 
+  - Fix OverlayNG coordinate dimemsion handling for EMPTY geometries (GH-1258, Martin Davis)
 
 
 ## Changes in 3.12.3

commit 5f05f9bb954986e2640d141b96a064d3c109638c
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 9d30dca34..54098f1f0 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 c1c37799c..39943febc 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                                            |   2 +-
 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(+), 11 deletions(-)
 create mode 100644 tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp


hooks/post-receive
-- 
GEOS


More information about the geos-commits mailing list