[geos-commits] [SCM] GEOS branch main updated. 3b391278f7844f16968e9397dd507c95589ac647
git at osgeo.org
git at osgeo.org
Fri Jan 16 08:18:43 PST 2026
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 3b391278f7844f16968e9397dd507c95589ac647 (commit)
via 49209692ccda59d4f650001ba7a7f8752d54b98b (commit)
via c28e77e9502c7496f90e1402dae6420312a69203 (commit)
from 9563c1805e90523fce74530e8fa3ff4d5e873d35 (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 3b391278f7844f16968e9397dd507c95589ac647
Author: Daniel Baston <dbaston at gmail.com>
Date: Mon Jan 12 10:21:06 2026 -0500
LineMerger: Retain M values
Resolves https://github.com/libgeos/geos/issues/1359
diff --git a/src/operation/linemerge/EdgeString.cpp b/src/operation/linemerge/EdgeString.cpp
index 7c10a2a2e..88abfadee 100644
--- a/src/operation/linemerge/EdgeString.cpp
+++ b/src/operation/linemerge/EdgeString.cpp
@@ -27,7 +27,6 @@
#include <geos/util.h>
#include <vector>
-#include <cassert>
using namespace geos::geom;
@@ -60,9 +59,23 @@ EdgeString::getCoordinates() const
{
int forwardDirectedEdges = 0;
int reverseDirectedEdges = 0;
- auto coordinates = detail::make_unique<CoordinateSequence>();
- for(std::size_t i = 0, e = directedEdges.size(); i < e; ++i) {
- LineMergeDirectedEdge* directedEdge = directedEdges[i];
+
+ bool resultHasZ = false;
+ bool resultHasM = false;
+
+ for (const LineMergeDirectedEdge* directedEdge : directedEdges) {
+ const LineMergeEdge* lme = detail::down_cast<LineMergeEdge*>(directedEdge->getEdge());
+
+ resultHasZ |= lme->getLine()->hasZ();
+ resultHasM |= lme->getLine()->hasM();
+ }
+
+ auto coordinates = std::make_unique<CoordinateSequence>(0, resultHasZ, resultHasM);
+
+ bool lastPointMissingZ = false;
+ bool lastPointMissingM = false;
+
+ for (const LineMergeDirectedEdge* directedEdge : directedEdges) {
if(directedEdge->getEdgeDirection()) {
forwardDirectedEdges++;
}
@@ -70,15 +83,30 @@ EdgeString::getCoordinates() const
reverseDirectedEdges++;
}
- LineMergeEdge* lme = detail::down_cast<LineMergeEdge*>(directedEdge->getEdge());
+ const LineMergeEdge* lme = detail::down_cast<LineMergeEdge*>(directedEdge->getEdge());
+ const CoordinateSequence* seq = lme->getLine()->getCoordinatesRO();
- coordinates->add(*lme->getLine()->getCoordinatesRO(),
+ if (lastPointMissingZ && seq->hasZ()) {
+ const double z = directedEdge->getEdgeDirection() ? seq->getZ(0) : seq->getZ(seq->getSize() - 1);
+ coordinates->setZ(coordinates->getSize() - 1, z);
+ }
+ if (lastPointMissingM && seq->hasM()) {
+ const double m = directedEdge->getEdgeDirection() ? seq->getM(0) : seq->getM(seq->getSize() - 1);
+ coordinates->setM(coordinates->getSize() - 1, m);
+ }
+
+ coordinates->add(*seq,
false,
directedEdge->getEdgeDirection());
+
+ lastPointMissingZ = resultHasZ && !seq->hasZ();
+ lastPointMissingM = resultHasM && !seq->hasM();
}
+
if(reverseDirectedEdges > forwardDirectedEdges) {
coordinates->reverse();
}
+
return coordinates;
}
diff --git a/tests/unit/operation/linemerge/LineMergerTest.cpp b/tests/unit/operation/linemerge/LineMergerTest.cpp
index 1fea1cd7b..e99ad4280 100644
--- a/tests/unit/operation/linemerge/LineMergerTest.cpp
+++ b/tests/unit/operation/linemerge/LineMergerTest.cpp
@@ -17,6 +17,8 @@
#include <string>
#include <vector>
+#include "utility.h"
+
namespace tut {
//
// Test Group
@@ -492,5 +494,34 @@ void object::test<19>
ensure_equals(geom->getLength(), merged[0]->getLength());
}
+template<>
+template<>
+void object::test<20>
+()
+{
+ std::vector<std::string> wkts{
+ "LINESTRING Z (0 0 0, 1 2 3, 2 4 6)",
+ "LINESTRING M (10 9 8, 2 4 7)",
+ "LINESTRING Z (10 9 2, 11 12 15)"
+ };
+ std::vector<std::unique_ptr<Geometry>> geoms;
+
+ LineMerger lm;
+
+ for (const auto& wkt : wkts) {
+ auto geom = wktreader.read(wkt);
+ lm.add(geom.get());
+ geoms.push_back(std::move(geom));
+ }
+
+ auto merged = lm.getMergedLineStrings();
+
+ ensure_equals(merged.size(), 1u);
+
+ auto expected = wktreader.read("LINESTRING ZM (0 0 0 NaN, 1 2 3 NaN, 2 4 6 7, 10 9 2 8, 11 12 15 NaN)");
+
+ ensure_equals_exact_geometry_xyzm(merged.front().get(), expected.get(), 0.0);
+}
+
} // namespace tut
commit 49209692ccda59d4f650001ba7a7f8752d54b98b
Author: Daniel Baston <dbaston at gmail.com>
Date: Mon Jan 12 10:20:50 2026 -0500
geos_unit: Improve assert failure message in ensure_equals_xyzm
diff --git a/tests/unit/utility.h b/tests/unit/utility.h
index 562a95dc8..c86dbce56 100644
--- a/tests/unit/utility.h
+++ b/tests/unit/utility.h
@@ -428,8 +428,8 @@ ensure_equals_exact_xyzm(const geos::geom::CoordinateSequence* seq1,
seq2->getAt(i, c2);
ensure("xy not in tolerance", c1.distance(c2) <= tol);
- ensure_same("z not same", c1.z, c2.z);
- ensure_same("z not same", c1.m, c2.m);
+ ensure_same(("index " + std::to_string(i) + "/" + std::to_string(seq1->getSize() - 1) + " z not same").c_str(), c1.z, c2.z);
+ ensure_same(("index " + std::to_string(i) + "/" + std::to_string(seq1->getSize() - 1) + " m not same").c_str(), c1.m, c2.m);
}
}
commit c28e77e9502c7496f90e1402dae6420312a69203
Author: Daniel Baston <dbaston at gmail.com>
Date: Mon Jan 12 10:20:23 2026 -0500
CoordinateSequence: Add Z/M accessors
diff --git a/include/geos/geom/CoordinateSequence.h b/include/geos/geom/CoordinateSequence.h
index 5e0a7776b..e4a1c5553 100644
--- a/include/geos/geom/CoordinateSequence.h
+++ b/include/geos/geom/CoordinateSequence.h
@@ -337,6 +337,80 @@ public:
return m_vect[index * stride() + 1];
}
+ /**
+ * Returns ordinate Z of the specified coordinate.
+ *
+ * @param index
+ * @return the value of the Z ordinate in the index'th coordinate, or NaN if the
+ * CoordinateSequence does not store Z values
+ */
+ double getZ(std::size_t index) const
+ {
+ return getOrdinate(index, Z);
+ }
+
+ /**
+ * Returns ordinate M of the specified coordinate.
+ *
+ * @param index
+ * @return the value of the M ordinate in the index'th coordinate, or NaN if the
+ * CoordinateSequence does not store M values
+ */
+ double getM(std::size_t index) const
+ {
+ return getOrdinate(index, M);
+ }
+
+ /**
+ * Set the X value of the specified coordinate.
+ *
+ * @param index
+ * @param x the new X value
+ */
+ void setX(std::size_t index, double x)
+ {
+ m_vect[index * stride()] = x;
+ }
+
+ /**
+ * Set the Y value of the specified coordinate.
+ *
+ * @param index
+ * @param y the new Y value
+ */
+ void setY(std::size_t index, double y)
+ {
+ m_vect[index * stride() + 1] = y;
+ }
+
+ /**
+ * Set the Z value of the specified coordinate.
+ *
+ * Has no effect if the CoordinateSequence does not store Z values.
+ *
+ * @param index
+ * @param z the new Z value
+ */
+ void setZ(std::size_t index, double z)
+ {
+ if (hasZ())
+ setOrdinate(index, Z, z);
+ }
+
+ /**
+ * Set the M value of the specified coordinate.
+ *
+ * Has no effect if the CoordinateSequence does not store M values.
+ *
+ * @param index
+ * @param m the new M value
+ */
+ void setM(std::size_t index, double m)
+ {
+ if (hasM())
+ setOrdinate(index, M, m);
+ }
+
/// Return last Coordinate in the sequence
template<typename T=Coordinate>
const T& back() const
diff --git a/tests/unit/geom/CoordinateSequenceTest.cpp b/tests/unit/geom/CoordinateSequenceTest.cpp
index e2a94fb41..a0c86888e 100644
--- a/tests/unit/geom/CoordinateSequenceTest.cpp
+++ b/tests/unit/geom/CoordinateSequenceTest.cpp
@@ -1580,4 +1580,41 @@ void object::test<59>()
ensure_equals(length, 8);
}
+template<>
+template<>
+void object::test<60>()
+{
+ set_test_name("Z/M accessors on XY sequence");
+
+ CoordinateSequence seq(0, false, false);
+ seq.add(CoordinateXY{0, 0});
+ seq.add(CoordinateXY{3, 0});
+
+ seq.setZ(0, 500);
+ seq.setM(0, 501);
+
+ ensure(std::isnan(seq.getZ(0)));
+ ensure(std::isnan(seq.getM(0)));
+}
+
+template<>
+template<>
+void object::test<61>()
+{
+ set_test_name("Z/M accessors on XYZM sequence");
+
+ CoordinateSequence seq(0, true, true);
+ seq.add(CoordinateXY{0, 0});
+ seq.add(CoordinateXY{3, 0});
+
+ seq.setZ(0, 500);
+ seq.setM(0, 501);
+
+ ensure_equals(seq.getZ(0), 500);
+ ensure_equals(seq.getM(0), 501);
+
+ ensure(std::isnan(seq.getZ(1)));
+ ensure(std::isnan(seq.getM(1)));
+}
+
} // namespace tut
-----------------------------------------------------------------------
Summary of changes:
include/geos/geom/CoordinateSequence.h | 74 +++++++++++++++++++++++
src/operation/linemerge/EdgeString.cpp | 40 ++++++++++--
tests/unit/geom/CoordinateSequenceTest.cpp | 37 ++++++++++++
tests/unit/operation/linemerge/LineMergerTest.cpp | 31 ++++++++++
tests/unit/utility.h | 4 +-
5 files changed, 178 insertions(+), 8 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list