[geos-commits] [SCM] GEOS branch main updated. a0f13d86655ad3f96c6f58a11161737eb5381d79
git at osgeo.org
git at osgeo.org
Mon Apr 21 10:24:09 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 a0f13d86655ad3f96c6f58a11161737eb5381d79 (commit)
from c54b93af6fead743fce357b939c84b50ba6fe84e (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 a0f13d86655ad3f96c6f58a11161737eb5381d79
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 a1ecff0e4..e1ff981e2 100644
--- a/include/geos/operation/overlayng/InputGeometry.h
+++ b/include/geos/operation/overlayng/InputGeometry.h
@@ -61,6 +61,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 9c18e5917..6bff9c358 100644
--- a/include/geos/operation/overlayng/OverlayUtil.h
+++ b/include/geos/operation/overlayng/OverlayUtil.h
@@ -138,13 +138,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
@@ -161,6 +161,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 95580ce7a..dd350aa07 100644
--- a/src/operation/overlayng/InputGeometry.cpp
+++ b/src/operation/overlayng/InputGeometry.cpp
@@ -46,6 +46,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 66fbfbb74..1919d96ad 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:
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 +++++++++++++++++++++
8 files changed, 256 insertions(+), 10 deletions(-)
create mode 100644 tests/unit/operation/overlayng/OverlayNGEmptyCoordDimTest.cpp
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list