[geos-commits] [SCM] GEOS branch main updated. d5977ebb4e29d6d970a3f784836a46796526f1fa
git at osgeo.org
git at osgeo.org
Wed Mar 11 07:38:01 PDT 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 d5977ebb4e29d6d970a3f784836a46796526f1fa (commit)
from 78c951c95dad8b6ff46b6f0d8b194ea93d3ad261 (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 d5977ebb4e29d6d970a3f784836a46796526f1fa
Author: Daniel Baston <dbaston at gmail.com>
Date: Wed Mar 11 10:37:39 2026 -0400
Curved types: support getBoundary (#1394)
diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in
index 21a85501f..12d30c9f4 100644
--- a/capi/geos_c.h.in
+++ b/capi/geos_c.h.in
@@ -4733,6 +4733,8 @@ extern GEOSGeometry GEOS_DLL *GEOSEnvelope(const GEOSGeometry* g);
*
* Z and M values in the input coordinates are preserved.
*
+* Curved geometry types are supported as of GEOS 3.15.
+*
* \param g The input geometry
* \return A newly allocated geometry of the boundary. NULL on exception.
* Caller is responsible for freeing with GEOSGeom_destroy().
diff --git a/include/geos/geom/CompoundCurve.h b/include/geos/geom/CompoundCurve.h
index 211a4aaa4..c685be18c 100644
--- a/include/geos/geom/CompoundCurve.h
+++ b/include/geos/geom/CompoundCurve.h
@@ -56,6 +56,8 @@ public:
/// Returns the nth section of the CompoundCurve
const SimpleCurve* getCurveN(std::size_t) const override;
+ std::unique_ptr<Point> getEndPoint() const override;
+
const Envelope* getEnvelopeInternal() const override
{
return &envelope;
@@ -72,6 +74,8 @@ public:
std::size_t getNumPoints() const override;
+ std::unique_ptr<Point> getStartPoint() const override;
+
bool hasCurvedComponents() const override;
bool hasM() const override;
diff --git a/include/geos/geom/Curve.h b/include/geos/geom/Curve.h
index 352dff661..d07a9d375 100644
--- a/include/geos/geom/Curve.h
+++ b/include/geos/geom/Curve.h
@@ -52,6 +52,18 @@ public:
return Dimension::L; // line
}
+ /// \brief
+ /// Return the end point of the Curve
+ /// or NULL if this is an EMPTY Curve.
+ ///
+ virtual std::unique_ptr<Point> getEndPoint() const = 0;
+
+ /// \brief
+ /// Return the start point of the Curve
+ /// or NULL if this is an EMPTY Curve.
+ ///
+ virtual std::unique_ptr<Point> getStartPoint() const = 0;
+
/// Returns true if the first and last coordinate in the Curve are the same
virtual bool isClosed() const = 0;
diff --git a/include/geos/geom/SimpleCurve.h b/include/geos/geom/SimpleCurve.h
index acfc8fc7e..9d0538058 100644
--- a/include/geos/geom/SimpleCurve.h
+++ b/include/geos/geom/SimpleCurve.h
@@ -70,7 +70,7 @@ public:
/// Return the end point of the LineString
/// or NULL if this is an EMPTY LineString.
///
- virtual std::unique_ptr<Point> getEndPoint() const;
+ std::unique_ptr<Point> getEndPoint() const override;
const Envelope* getEnvelopeInternal() const override
{
@@ -87,7 +87,7 @@ public:
/// Return the start point of the LineString
/// or NULL if this is an EMPTY LineString.
///
- virtual std::unique_ptr<Point> getStartPoint() const;
+ std::unique_ptr<Point> getStartPoint() const override;
bool hasM() const override;
diff --git a/include/geos/operation/BoundaryOp.h b/include/geos/operation/BoundaryOp.h
index 4a5902763..7b204f030 100644
--- a/include/geos/operation/BoundaryOp.h
+++ b/include/geos/operation/BoundaryOp.h
@@ -24,8 +24,11 @@
namespace geos {
namespace geom {
+class Curve;
class LineString;
+class MultiCurve;
class MultiLineString;
+class GeometryCollection;
}
}
@@ -108,11 +111,11 @@ private:
const geom::GeometryFactory& m_geomFact;
const algorithm::BoundaryNodeRule& m_bnRule;
- std::unique_ptr<geom::Geometry> boundaryMultiLineString(const geom::MultiLineString& mLine);
+ std::unique_ptr<geom::Geometry> boundaryMultiCurve(const geom::GeometryCollection& mLine);
- std::unique_ptr<geom::CoordinateSequence> computeBoundaryCoordinates(const geom::MultiLineString& mLine);
+ std::unique_ptr<geom::CoordinateSequence> computeBoundaryCoordinates(const geom::GeometryCollection& mLine) const;
- std::unique_ptr<geom::Geometry> boundaryLineString(const geom::LineString& line);
+ std::unique_ptr<geom::Geometry> boundaryCurve(const geom::Curve& line) const;
};
}
diff --git a/src/geom/CompoundCurve.cpp b/src/geom/CompoundCurve.cpp
index 9c01111b6..8897109c3 100644
--- a/src/geom/CompoundCurve.cpp
+++ b/src/geom/CompoundCurve.cpp
@@ -202,6 +202,18 @@ CompoundCurve::getCurveN(std::size_t i) const
return curves[i].get();
}
+std::unique_ptr<Point>
+CompoundCurve::getEndPoint() const
+{
+ for (std::size_t i = curves.size(); i != 0; i--) {
+ if (!curves[i-1]->isEmpty()) {
+ return curves[i-1]->getEndPoint();
+ }
+ }
+
+ return nullptr;
+}
+
std::string
CompoundCurve::getGeometryType() const
{
@@ -240,6 +252,18 @@ CompoundCurve::getNumPoints() const
return n;
}
+std::unique_ptr<Point>
+CompoundCurve::getStartPoint() const
+{
+ for (const auto& curve : curves) {
+ if (!curve->isEmpty()) {
+ return curve->getStartPoint();
+ }
+ }
+
+ return nullptr;
+}
+
bool
CompoundCurve::hasZ() const
{
diff --git a/src/geom/CurvePolygon.cpp b/src/geom/CurvePolygon.cpp
index c5213602c..7c181a13a 100644
--- a/src/geom/CurvePolygon.cpp
+++ b/src/geom/CurvePolygon.cpp
@@ -16,6 +16,10 @@
#include <geos/geom/Curve.h>
#include <geos/geom/CurvePolygon.h>
#include <geos/geom/CoordinateSequence.h>
+#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/LineString.h>
+#include <geos/geom/MultiCurve.h>
+#include <geos/geom/SimpleCurve.h>
#include <geos/util/UnsupportedOperationException.h>
namespace geos {
@@ -43,9 +47,37 @@ namespace geom {
return GEOS_CURVEPOLYGON;
}
+ static std::unique_ptr<Geometry>
+ getRingForBoundary(const Geometry* ring)
+ {
+ // Convert LinearRing -> LineString
+ if (ring->getGeometryTypeId() == GEOS_LINEARRING) {
+ return ring->getFactory()->createLineString(*static_cast<const LineString*>(ring));
+ }
+ return ring->clone();
+ }
+
std::unique_ptr<Geometry>
CurvePolygon::getBoundary() const {
- throw util::UnsupportedOperationException();
+
+ const GeometryFactory* gf = getFactory();
+
+ if(isEmpty()) {
+ return gf->createMultiCurve();
+ }
+
+ if(holes.empty()) {
+ return getRingForBoundary(shell.get());
+ }
+
+ std::vector<std::unique_ptr<Geometry>> rings(holes.size() + 1);
+
+ rings[0] = getRingForBoundary(shell.get());
+ for(std::size_t i = 0; i < holes.size(); ++i) {
+ rings[i + 1] = getRingForBoundary(holes[i].get());
+ }
+
+ return getFactory()->createMultiCurve(std::move(rings));
}
void
diff --git a/src/operation/BoundaryOp.cpp b/src/operation/BoundaryOp.cpp
index c0c452c45..1cc02ff80 100644
--- a/src/operation/BoundaryOp.cpp
+++ b/src/operation/BoundaryOp.cpp
@@ -20,16 +20,22 @@
#include <geos/algorithm/BoundaryNodeRule.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
+#include <geos/geom/CompoundCurve.h>
+#include <geos/geom/Curve.h>
#include <geos/geom/LineString.h>
+#include <geos/geom/MultiCurve.h>
#include <geos/geom/MultiLineString.h>
+#include <geos/geom/SimpleCurve.h>
#include <geos/util.h>
#include <map>
using geos::geom::Coordinate;
using geos::geom::CoordinateSequence;
+using geos::geom::Curve;
using geos::geom::Dimension;
using geos::geom::Geometry;
using geos::geom::LineString;
+using geos::geom::MultiCurve;
using geos::geom::MultiLineString;
using geos::geom::Point;
using geos::algorithm::BoundaryNodeRule;
@@ -52,14 +58,16 @@ BoundaryOp::BoundaryOp(const geom::Geometry& geom, const algorithm::BoundaryNode
std::unique_ptr<geom::Geometry>
BoundaryOp::getBoundary()
{
- util::ensureNoCurvedComponents(m_geom);
-
- if (auto ls = dynamic_cast<const LineString*>(&m_geom)) {
- return boundaryLineString(*ls);
+ if (auto ls = dynamic_cast<const Curve*>(&m_geom)) {
+ return boundaryCurve(*ls);
}
if (auto mls = dynamic_cast<const MultiLineString*>(&m_geom)) {
- return boundaryMultiLineString(*mls);
+ return boundaryMultiCurve(*mls);
+ }
+
+ if (auto mc = dynamic_cast<const MultiCurve*>(&m_geom)) {
+ return boundaryMultiCurve(*mc);
}
return m_geom.getBoundary();
@@ -104,7 +112,7 @@ BoundaryOp::hasBoundary(const geom::Geometry& geom, const algorithm::BoundaryNod
}
std::unique_ptr<Geometry>
-BoundaryOp::boundaryLineString(const geom::LineString& line)
+BoundaryOp::boundaryCurve(const geom::Curve& line) const
{
if (m_geom.isEmpty()) {
return m_geomFact.createMultiPoint();
@@ -112,7 +120,7 @@ BoundaryOp::boundaryLineString(const geom::LineString& line)
if (line.isClosed()) {
// check whether endpoints of valence 2 are on the boundary or not
- bool closedEndpointOnBoundary = m_bnRule.isInBoundary(2);
+ const bool closedEndpointOnBoundary = m_bnRule.isInBoundary(2);
if (closedEndpointOnBoundary) {
return line.getStartPoint();
}
@@ -129,7 +137,7 @@ BoundaryOp::boundaryLineString(const geom::LineString& line)
}
std::unique_ptr<Geometry>
-BoundaryOp::boundaryMultiLineString(const geom::MultiLineString& mLine)
+BoundaryOp::boundaryMultiCurve(const geom::GeometryCollection& mLine)
{
if (m_geom.isEmpty()) {
return m_geomFact.createMultiPoint();
@@ -143,29 +151,68 @@ BoundaryOp::boundaryMultiLineString(const geom::MultiLineString& mLine)
return m_geomFact.createPoint(c);
});
}
+
// this handles 0 points case as well
return std::unique_ptr<Geometry>(m_geomFact.createMultiPoint(*bdyPts));
}
-std::unique_ptr<CoordinateSequence>
-BoundaryOp::computeBoundaryCoordinates(const geom::MultiLineString& mLine)
+static const CoordinateSequence*
+getFirstSequence(const Curve& curve)
{
+ if (curve.getGeometryTypeId() == geom::GEOS_COMPOUNDCURVE) {
+ const auto& cc = static_cast<const geom::CompoundCurve&>(curve);
+ for (std::size_t i = 0; i < cc.getNumCurves(); i++) {
+ if (!cc.getCurveN(i)->isEmpty()) {
+ return cc.getCurveN(i)->getCoordinatesRO();
+ }
+ }
+
+ return nullptr;
+ }
+
+ return static_cast<const geom::SimpleCurve&>(curve).getCoordinatesRO();
+}
+
+static const CoordinateSequence*
+getLastSequence(const Curve& curve)
+{
+ if (curve.getGeometryTypeId() == geom::GEOS_COMPOUNDCURVE) {
+ const auto& cc = static_cast<const geom::CompoundCurve&>(curve);
+ for (std::size_t i = cc.getNumCurves(); i != 0; i--) {
+ if (!cc.getCurveN(i-1)->isEmpty()) {
+ return cc.getCurveN(i-1)->getCoordinatesRO();
+ }
+ }
+
+ return nullptr;
+ }
+
+ return static_cast<const geom::SimpleCurve&>(curve).getCoordinatesRO();
+}
+
+std::unique_ptr<CoordinateSequence>
+BoundaryOp::computeBoundaryCoordinates(const geom::GeometryCollection& mLine) const
+{
+ assert(mLine.getGeometryTypeId() == geom::GEOS_MULTILINESTRING || mLine.getGeometryTypeId() == geom::GEOS_MULTICURVE);
+
auto bdyPts = detail::make_unique<CoordinateSequence>(0, mLine.hasZ(), mLine.hasM());
std::map<geom::CoordinateXYZM, int> endpointMap;
for (std::size_t i = 0; i < mLine.getNumGeometries(); i++) {
- const LineString* line = mLine.getGeometryN(i);
+ const Curve* line = detail::down_cast<const Curve*>(mLine.getGeometryN(i));
if (line->getNumPoints() == 0) {
continue;
}
- const CoordinateSequence& pts = *line->getCoordinatesRO();
-
geom::CoordinateXYZM start;
geom::CoordinateXYZM end;
- pts.getAt(0, start);
- pts.getAt(pts.size() - 1, end);
+
+ const geom::CoordinateSequence* firstPts = getFirstSequence(*line);
+ const geom::CoordinateSequence* lastPts = getLastSequence(*line);
+
+ firstPts->getAt(0, start);
+ lastPts->getAt(lastPts->size() - 1, end);
endpointMap[start]++;
endpointMap[end]++;
diff --git a/tests/unit/capi/GEOSBoundaryTest.cpp b/tests/unit/capi/GEOSBoundaryTest.cpp
index 17f4af46e..ce36d6e40 100644
--- a/tests/unit/capi/GEOSBoundaryTest.cpp
+++ b/tests/unit/capi/GEOSBoundaryTest.cpp
@@ -34,11 +34,16 @@ template<>
template<>
void object::test<2>()
{
+ set_test_name("curved inputs");
+
input_ = fromWKT("CIRCULARSTRING (0 0, 1 1, 2 0)");
ensure(input_ != nullptr);
result_ = GEOSBoundary(input_);
- ensure(result_ == nullptr);
+ ensure(result_);
+
+ expected_ = fromWKT("MULTIPOINT (0 0, 2 0)");
+ ensure_geometry_equals_identical(result_, expected_);
}
template<>
diff --git a/tests/unit/geom/CircularStringTest.cpp b/tests/unit/geom/CircularStringTest.cpp
index 045c61739..8204468c8 100644
--- a/tests/unit/geom/CircularStringTest.cpp
+++ b/tests/unit/geom/CircularStringTest.cpp
@@ -148,9 +148,10 @@ void object::test<3>()
ensure_THROW(cs_->getCentroid(), geos::util::UnsupportedOperationException);
- //auto expected_boundary = wktreader_.read("MULTIPOINT ((0 0), (1 1), (2 0), (3 -1), (4 0))");
- //ensure("getBoundary", cs_->getBoundary()->equalsIdentical(expected_boundary.get()));
- ensure_THROW(cs_->getBoundary(), geos::util::UnsupportedOperationException);
+ {
+ auto expected_boundary = wktreader_.read("MULTIPOINT ((0 0), (4 0))");
+ ensure("getBoundary", cs_->getBoundary()->equalsIdentical(expected_boundary.get()));
+ }
ensure("clone", cs_->equalsIdentical(cs_->clone().get()));
diff --git a/tests/unit/geom/CompoundCurveTest.cpp b/tests/unit/geom/CompoundCurveTest.cpp
index 165c67338..499fd3699 100644
--- a/tests/unit/geom/CompoundCurveTest.cpp
+++ b/tests/unit/geom/CompoundCurveTest.cpp
@@ -6,6 +6,7 @@
#include <geos/geom/CoordinateFilter.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/CompoundCurve.h>
+#include <geos/geom/Point.h>
#include <geos/geom/CircularString.h>
#include <geos/geom/IntersectionMatrix.h>
#include <geos/io/WKTReader.h>
@@ -54,6 +55,8 @@ template<>
template<>
void object::test<1>()
{
+ set_test_name("empty CompoundCurve");
+
auto cc = factory_->createCompoundCurve();
ensure("isEmpty", cc->isEmpty());
@@ -68,6 +71,9 @@ void object::test<1>()
ensure_equals("getArea", cc->getArea(), 0);
ensure_equals("getLength", cc->getLength(), 0);
+
+ ensure("getStartPoint", cc->getStartPoint() == nullptr);
+ ensure("getEndPoint", cc->getEndPoint() == nullptr);
}
// Basic Geometry API
@@ -77,7 +83,7 @@ void object::test<2>()
{
// Geometry type functions
ensure_equals("getGeometryType", cc_->getGeometryType(), "CompoundCurve");
- ensure_equals("getGeometryTypdId", cc_->getGeometryTypeId(), geos::geom::GEOS_COMPOUNDCURVE);
+ ensure_equals("getGeometryTypeId", cc_->getGeometryTypeId(), geos::geom::GEOS_COMPOUNDCURVE);
ensure("isCollection", !cc_->isCollection());
// Geometry size functions
@@ -110,6 +116,11 @@ void object::test<2>()
// Coordinate access functions
ensure("getCoordinates", cc_->getCoordinates()->getSize() == 5u);
ensure_equals("getCoordinate", *cc_->getCoordinate(), CoordinateXY(0, 0));
+ ensure_equals_geometry(static_cast<Geometry*>(cc_->getStartPoint().get()), wktreader_.read("POINT (0 0)").get());
+ ensure_equals_geometry(static_cast<Geometry*>(cc_->getEndPoint().get()), wktreader_.read("POINT (2 2)").get());
+
+ ensure_equals_geometry(cc_->getStartPoint().get(), factory_->createPoint(CoordinateXY{0, 0}).get());
+ ensure_equals_geometry(cc_->getEndPoint().get(), factory_->createPoint(CoordinateXY{2, 2}).get());
}
// Operations
@@ -154,7 +165,15 @@ void object::test<3>()
ensure_THROW(cc_->convexHull(), geos::util::UnsupportedOperationException);
ensure_THROW(cc_->buffer(1), geos::util::UnsupportedOperationException);
ensure_THROW(cc_->getCentroid(), geos::util::UnsupportedOperationException);
- ensure_THROW(cc_->getBoundary(), geos::util::UnsupportedOperationException);
+
+ {
+ CoordinateSequence seq(2, false, false);
+ seq.setAt(CoordinateXY{0, 0}, 0);
+ seq.setAt(CoordinateXY{2, 2}, 1);
+ std::unique_ptr<Geometry> mp = factory_->createMultiPoint(seq);
+
+ ensure_equals_geometry(cc_->getBoundary().get(), mp.get());
+ }
ensure("clone", cc_->equalsIdentical(cc_->clone().get()));
diff --git a/tests/unit/geom/CurvePolygonTest.cpp b/tests/unit/geom/CurvePolygonTest.cpp
index ebddf3328..ff638685c 100644
--- a/tests/unit/geom/CurvePolygonTest.cpp
+++ b/tests/unit/geom/CurvePolygonTest.cpp
@@ -1,3 +1,4 @@
+#include <geos_c.h>
#include <tut/tut.hpp>
#include <tut/tut_macros.hpp>
@@ -8,6 +9,8 @@
#include <geos/geom/IntersectionMatrix.h>
#include <geos/io/WKTReader.h>
+#include "utility.h"
+
using geos::geom::CoordinateXY;
using geos::geom::CurvePolygon;
@@ -64,6 +67,8 @@ template<>
template<>
void object::test<1>()
{
+ set_test_name("empty CurvePolygon");
+
auto cp = factory_->createCurvePolygon(false, false);
ensure("isEmpty", cp->isEmpty());
@@ -77,6 +82,12 @@ void object::test<1>()
ensure_equals("getArea", cp->getArea(), 0.0);
ensure_equals("getLength", cp->getLength(), 0.0);
+
+ {
+ auto boundary = cp->getBoundary();
+ ensure(boundary->isEmpty());
+ ensure_equals(boundary->getGeometryTypeId(), geos::geom::GeometryTypeId::GEOS_MULTICURVE);
+ }
}
// Basic Geometry API
@@ -170,7 +181,11 @@ void object::test<3>()
ensure_THROW(cp_->convexHull(), geos::util::UnsupportedOperationException);
ensure_THROW(cp_->buffer(1), geos::util::UnsupportedOperationException);
ensure_THROW(cp_->getCentroid(), geos::util::UnsupportedOperationException);
- ensure_THROW(cp_->getBoundary(), geos::util::UnsupportedOperationException);
+ {
+ auto boundary = cp_->getBoundary();
+ ensure_equals(boundary->getGeometryTypeId(), geos::geom::GEOS_MULTICURVE);
+ ensure_equals(cp_->getLength(), boundary->getLength());
+ }
ensure("clone", cp_->equalsIdentical(cp_->clone().get()));
diff --git a/tests/unit/geom/MultiCurveTest.cpp b/tests/unit/geom/MultiCurveTest.cpp
index 09c79fd12..1ca766cf1 100644
--- a/tests/unit/geom/MultiCurveTest.cpp
+++ b/tests/unit/geom/MultiCurveTest.cpp
@@ -8,6 +8,8 @@
#include <geos/geom/MultiCurve.h>
#include <geos/io/WKTReader.h>
+#include "utility.h"
+
using geos::geom::CoordinateXY;
namespace tut {
@@ -166,7 +168,10 @@ void object::test<3>()
ensure_THROW(mc_->convexHull(), geos::util::UnsupportedOperationException);
ensure_THROW(mc_->buffer(1), geos::util::UnsupportedOperationException);
ensure_THROW(mc_->getCentroid(), geos::util::UnsupportedOperationException);
- ensure_THROW(mc_->getBoundary(), geos::util::UnsupportedOperationException);
+ {
+ auto expected_boundary = wktreader_.read("MULTIPOINT ((8 9), (10 11))");
+ ensure_equals_geometry(mc_->getBoundary().get(), expected_boundary.get());
+ }
ensure("clone", mc_->equalsIdentical(mc_->clone().get()));
diff --git a/tests/unit/geom/MultiSurfaceTest.cpp b/tests/unit/geom/MultiSurfaceTest.cpp
index 58c6ae524..9d422c961 100644
--- a/tests/unit/geom/MultiSurfaceTest.cpp
+++ b/tests/unit/geom/MultiSurfaceTest.cpp
@@ -9,6 +9,8 @@
#include <geos/io/WKTReader.h>
#include <geos/util/UnsupportedOperationException.h>
+#include "utility.h"
+
using geos::geom::CoordinateXY;
namespace tut {
@@ -155,7 +157,10 @@ void object::test<3>()
ensure_THROW(ms_->convexHull(), geos::util::UnsupportedOperationException);
ensure_THROW(ms_->buffer(1), geos::util::UnsupportedOperationException);
ensure_THROW(ms_->getCentroid(), geos::util::UnsupportedOperationException);
- ensure_THROW(ms_->getBoundary(), geos::util::UnsupportedOperationException);
+ {
+ auto expected_boundary = wktreader_.read("MULTICURVE ((0 0, 1 0, 1 1, 0 1, 0 0), CIRCULARSTRING (10 10, 11 11, 12 10, 11 9, 10 10))");
+ ensure_equals_exact_geometry(ms_->getBoundary().get(), expected_boundary.get(), 0);
+ }
ensure("clone", ms_->equalsIdentical(ms_->clone().get()));
diff --git a/tests/unit/operation/BoundaryOpTest.cpp b/tests/unit/operation/BoundaryOpTest.cpp
index de392dbff..8ae1de80a 100644
--- a/tests/unit/operation/BoundaryOpTest.cpp
+++ b/tests/unit/operation/BoundaryOpTest.cpp
@@ -8,6 +8,8 @@
#include <string>
#include <memory>
+#include "utility.h"
+
using namespace geos::algorithm;
using namespace geos::geom;
using geos::operation::BoundaryOp;
@@ -28,7 +30,7 @@ struct test_boundaryop_data {
BoundaryOp op(*g, bnRule);
auto boundary = op.getBoundary();
- ensure(boundary->equals(expected.get()));
+ ensure_equals_geometry(boundary.get(), expected.get());
}
void checkHasBoundary(const std::string& wkt)
@@ -105,7 +107,7 @@ void object::test<3>()
"POINT (10 10)" );
}
-// testMultiLinestd::stringWithRingTouchAtEndpoint
+// testMultiLineStringWithRingTouchAtEndpoint
template<>
template<>
void object::test<4>()
@@ -156,7 +158,7 @@ void object::test<8>()
checkHasBoundary( "LINESTRING (100 100, 20 20, 200 20, 100 100)", false);
}
-// testHasBoundaryMultiLinestd::stringClosed
+// testHasBoundaryMultiLineStringClosed
template<>
template<>
void object::test<9>()
@@ -164,7 +166,7 @@ void object::test<9>()
checkHasBoundary( "MULTILINESTRING ((0 0, 0 1), (0 1, 1 1, 1 0, 0 0))", false);
}
-// testHasBoundaryMultiLinestd::stringOpen
+// testHasBoundaryMultiLineStringOpen
template<>
template<>
void object::test<10>()
@@ -188,4 +190,102 @@ void object::test<12>()
checkHasBoundary( "POLYGON EMPTY", false);
}
+template<>
+template<>
+void object::test<13>()
+{
+ set_test_name("closed CircularString has no boundary");
+
+ checkHasBoundary( "CIRCULARSTRING (-5 0, 0 5, 5 0, 0 -5, -5 0)", false);
+}
+
+template<>
+template<>
+void object::test<14>()
+{
+ set_test_name("non-closed CircularString has a boundary");
+
+ checkHasBoundary( "CIRCULARSTRING (-5 0, 0 5, 5 0)");
+}
+
+template<>
+template<>
+void object::test<15>()
+{
+ set_test_name("closed CompoundCurve has no boundary");
+
+ checkHasBoundary( "COMPOUNDCURVE (CIRCULARSTRING(-5 0, 0 5, 5 0), (5 0, -5 0))", false);
+}
+
+template<>
+template<>
+void object::test<16>()
+{
+ set_test_name("non-closed CompoundCurve has a boundary");
+
+ checkHasBoundary( "COMPOUNDCURVE (CIRCULARSTRING(-5 0, 0 5, 5 0), (5 0, 0 0))");
+}
+
+template<>
+template<>
+void object::test<17>()
+{
+ set_test_name("closed MultiCurve has no boundary");
+
+ checkHasBoundary( "MULTICURVE ((-5 0, 5 0), CIRCULARSTRING (-5 0, 0 5, 5 0))", false);
+}
+
+
+template<>
+template<>
+void object::test<18>()
+{
+ set_test_name("non-closed MultiCurve has a boundary");
+
+ checkHasBoundary( "MULTICURVE ((0 0, 5 0), CIRCULARSTRING (-5 0, 0 5, 5 0))");
+}
+
+template<>
+template<>
+void object::test<19>()
+{
+ set_test_name("boundary of closed CircularString");
+
+ std::string a = "CIRCULARSTRING (-5 0, 0 5, 5 0, 0 -5, -5 0)";
+ // rings are simple under all rules
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryRuleMod2(),
+ "MULTIPOINT EMPTY");
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryEndPoint(),
+ "POINT (-5 0)" );
+}
+
+template<>
+template<>
+void object::test<20>()
+{
+ set_test_name("boundary of closed CompoundCurve");
+
+ std::string a = "COMPOUNDCURVE(CIRCULARSTRING (-5 0, 0 5, 5 0), (5 0, -5 0))";
+ // rings are simple under all rules
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryRuleMod2(),
+ "MULTIPOINT EMPTY");
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryEndPoint(),
+ "POINT (-5 0)" );
+}
+
+template<>
+template<>
+void object::test<21>()
+{
+ set_test_name("boundary of MultiCurve");
+
+ std::string a = "MULTICURVE ((100 100, 20 20), CIRCULARSTRING (20 20, 110 0, 200 20), (200 20, 100 100), (100 200, 100 100))";
+ // under Mod-2, the ring has no boundary, so the line intersects the interior ==> not simple
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryRuleMod2(),
+ "MULTIPOINT ((100 100), (100 200))" );
+ // under Endpoint, the ring has a boundary point, so the line does NOT intersect the interior ==> simple
+ runBoundaryTest(a, BoundaryNodeRule::getBoundaryEndPoint(),
+ "MULTIPOINT ((100 100), (100 200), (20 20), (200 20))" );
+}
+
}
diff --git a/tests/unit/utility.h b/tests/unit/utility.h
index 0a15532ed..ba456c34c 100644
--- a/tests/unit/utility.h
+++ b/tests/unit/utility.h
@@ -534,11 +534,11 @@ ensure_equals_exact_geometry(const geos::geom::Geometry *lhs_in,
assert(nullptr != lhs_in);
assert(nullptr != rhs_in);
- using geos::geom::Point;
- using geos::geom::LineString;
- using geos::geom::Polygon;
using geos::geom::CoordinateSequence;
using geos::geom::GeometryCollection;
+ using geos::geom::Point;
+ using geos::geom::Polygon;
+ using geos::geom::SimpleCurve;
ensure_equals("type id do not match",
lhs_in->getGeometryTypeId(), rhs_in->getGeometryTypeId());
@@ -547,8 +547,8 @@ ensure_equals_exact_geometry(const geos::geom::Geometry *lhs_in,
const Point *gpt2 = static_cast<const Point *>(rhs_in);
return ensure_equals_dims( gpt1->getCoordinatesRO(), gpt2->getCoordinatesRO(), 2, tolerance);
}
- else if (const LineString* gln1 = dynamic_cast<const LineString *>(lhs_in)) {
- const LineString *gln2 = static_cast<const LineString *>(rhs_in);
+ else if (const SimpleCurve* gln1 = dynamic_cast<const SimpleCurve *>(lhs_in)) {
+ const SimpleCurve *gln2 = static_cast<const SimpleCurve *>(rhs_in);
return ensure_equals_dims( gln1->getCoordinatesRO(), gln2->getCoordinatesRO(), 2, tolerance);
}
else if (const GeometryCollection* gc1 = dynamic_cast<const GeometryCollection *>(lhs_in)) {
-----------------------------------------------------------------------
Summary of changes:
capi/geos_c.h.in | 2 +
include/geos/geom/CompoundCurve.h | 4 ++
include/geos/geom/Curve.h | 12 ++++
include/geos/geom/SimpleCurve.h | 4 +-
include/geos/operation/BoundaryOp.h | 9 ++-
src/geom/CompoundCurve.cpp | 24 +++++++
src/geom/CurvePolygon.cpp | 34 +++++++++-
src/operation/BoundaryOp.cpp | 75 +++++++++++++++++-----
tests/unit/capi/GEOSBoundaryTest.cpp | 7 ++-
tests/unit/geom/CircularStringTest.cpp | 7 ++-
tests/unit/geom/CompoundCurveTest.cpp | 23 ++++++-
tests/unit/geom/CurvePolygonTest.cpp | 17 ++++-
tests/unit/geom/MultiCurveTest.cpp | 7 ++-
tests/unit/geom/MultiSurfaceTest.cpp | 7 ++-
tests/unit/operation/BoundaryOpTest.cpp | 108 ++++++++++++++++++++++++++++++--
tests/unit/utility.h | 10 +--
16 files changed, 312 insertions(+), 38 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list