[geos-commits] [SCM] GEOS branch main updated. 02cbfe81143f6303f234f8a9ce3d9694ddcec381
git at osgeo.org
git at osgeo.org
Tue Jan 6 05:51:20 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 02cbfe81143f6303f234f8a9ce3d9694ddcec381 (commit)
from 158c588566e08fd2f31f8c9e7ae069518e8264c5 (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 02cbfe81143f6303f234f8a9ce3d9694ddcec381
Author: arriopolis <arjan at cwi.nl>
Date: Tue Jan 6 14:50:56 2026 +0100
Improve OverlayNG performance (#1353)
* Incorporated JTS PR 906
* EdgeRing: Add const qualifiers, use std::make_shared
---------
Co-authored-by: arriopolis <arjan_rekenamchine at hotmail.com>
Co-authored-by: Dan Baston <dbaston at gmail.com>
diff --git a/include/geos/geom/Envelope.h b/include/geos/geom/Envelope.h
index 687dbbae1..15d360030 100644
--- a/include/geos/geom/Envelope.h
+++ b/include/geos/geom/Envelope.h
@@ -575,6 +575,19 @@ public:
std::isless(p.y, maxy) && std::isgreater(p.y, miny);
}
+ /** \brief
+ * Tests if an envelope is properly contained in this one.
+ * The envelope is properly contained if it is contained
+ * by this one but not equal to it.
+ *
+ * @param other the envelope to test
+ * @return true if the envelope is properly contained
+ */
+ bool containsProperly(const Envelope& other) const {
+ if (equals(&other)) return false;
+ return covers(other);
+ }
+
/** \brief
* Check if the point p intersects (lies inside) the region of this Envelope.
*
diff --git a/include/geos/operation/overlayng/OverlayEdgeRing.h b/include/geos/operation/overlayng/OverlayEdgeRing.h
index b2509f02c..f0e94445a 100644
--- a/include/geos/operation/overlayng/OverlayEdgeRing.h
+++ b/include/geos/operation/overlayng/OverlayEdgeRing.h
@@ -28,6 +28,7 @@ class PointOnGeometryLocator;
}
namespace geom {
class Coordinate;
+class CoordinateXY;
class CoordinateSequence;
class GeometryFactory;
class LinearRing;
@@ -46,6 +47,7 @@ namespace overlayng { // geos.operation.overlayng
class GEOS_DLL OverlayEdgeRing {
using Coordinate = geos::geom::Coordinate;
+ using CoordinateXY = geos::geom::CoordinateXY;
using CoordinateSequence = geos::geom::CoordinateSequence;
using GeometryFactory = geos::geom::GeometryFactory;
using LinearRing = geos::geom::LinearRing;
@@ -59,23 +61,25 @@ private:
OverlayEdge* startEdge;
std::unique_ptr<LinearRing> ring;
bool m_isHole;
- std::unique_ptr<IndexedPointInAreaLocator> locator;
+ mutable std::unique_ptr<IndexedPointInAreaLocator> locator;
OverlayEdgeRing* shell;
// a list of EdgeRings which are holes in this EdgeRing
std::vector<OverlayEdgeRing*> holes;
// Methods
void computeRingPts(OverlayEdge* start, CoordinateSequence& pts);
- void computeRing(std::unique_ptr<CoordinateSequence> && ringPts, const GeometryFactory* geometryFactory);
+ void computeRing(const std::shared_ptr<CoordinateSequence> & ringPts, const GeometryFactory* geometryFactory);
/**
* Computes the list of coordinates which are contained in this ring.
* The coordinates are computed once only and cached.
* @return an array of the {@link Coordinate}s in this ring
*/
- const CoordinateSequence& getCoordinates();
- PointOnGeometryLocator* getLocator();
+ const CoordinateSequence& getCoordinates() const;
+ PointOnGeometryLocator* getLocator() const;
static void closeRing(CoordinateSequence& pts);
+ bool contains(const OverlayEdgeRing& otherRing) const;
+ bool isPointInOrOut(const OverlayEdgeRing& otherRing) const;
public:
@@ -85,6 +89,8 @@ public:
std::unique_ptr<LinearRing> getRing();
const LinearRing* getRingPtr() const;
+ const geom::Envelope& getEnvelope() const;
+
/**
* Tests whether this ring is a hole.
* @return <code>true</code> if this ring is a hole
@@ -114,9 +120,9 @@ public:
void addHole(OverlayEdgeRing* ring);
- bool isInRing(const Coordinate& pt);
+ geom::Location locate(const CoordinateXY& pt) const;
- const Coordinate& getCoordinate();
+ const Coordinate& getCoordinate() const;
/**
* Computes the {@link Polygon} formed by this ring and any contained holes.
@@ -144,7 +150,7 @@ public:
* @return containing EdgeRing, if there is one
* or null if no containing EdgeRing is found
*/
- OverlayEdgeRing* findEdgeRingContaining(const std::vector<OverlayEdgeRing*>& erList);
+ OverlayEdgeRing* findEdgeRingContaining(const std::vector<OverlayEdgeRing*>& erList) const;
};
diff --git a/include/geos/operation/polygonize/EdgeRing.h b/include/geos/operation/polygonize/EdgeRing.h
index 30f5be286..18646ee5d 100644
--- a/include/geos/operation/polygonize/EdgeRing.h
+++ b/include/geos/operation/polygonize/EdgeRing.h
@@ -64,9 +64,9 @@ private:
DeList deList;
// cache the following data for efficiency
- std::unique_ptr<geom::LinearRing> ring;
- std::unique_ptr<geom::CoordinateSequence> ringPts;
- std::unique_ptr<algorithm::locate::PointOnGeometryLocator> ringLocator;
+ mutable std::unique_ptr<geom::LinearRing> ring;
+ mutable std::shared_ptr<geom::CoordinateSequence> ringPts;
+ mutable std::unique_ptr<algorithm::locate::PointOnGeometryLocator> ringLocator;
std::unique_ptr<std::vector<std::unique_ptr<geom::LinearRing>>> holes;
@@ -84,19 +84,26 @@ private:
*
* @return an array of the Coordinate in this ring
*/
- const geom::CoordinateSequence* getCoordinates();
+ const geom::CoordinateSequence* getCoordinates() const;
+
+ const geom::Envelope& getEnvelope() const {
+ return *getRingInternal()->getEnvelopeInternal();
+ }
static void addEdge(const geom::CoordinateSequence* coords,
bool isForward,
geom::CoordinateSequence* coordList);
- algorithm::locate::PointOnGeometryLocator* getLocator() {
+ algorithm::locate::PointOnGeometryLocator* getLocator() const {
if (ringLocator == nullptr) {
ringLocator.reset(new algorithm::locate::IndexedPointInAreaLocator(*getRingInternal()));
}
return ringLocator.get();
}
+ bool contains(const EdgeRing& otherRing) const;
+ bool isPointInOrOut(const EdgeRing& otherRing) const;
+
public:
/** \brief
* Adds a DirectedEdge which is known to form part of this ring.
@@ -324,7 +331,7 @@ public:
* Ownership of ring is retained by the object.
* Details of problems are written to standard output.
*/
- geom::LinearRing* getRingInternal();
+ const geom::LinearRing* getRingInternal() const;
/** \brief
* Returns this ring as a LinearRing, or null if an Exception
@@ -335,8 +342,8 @@ public:
*/
std::unique_ptr<geom::LinearRing> getRingOwnership();
- bool isInRing(const geom::Coordinate & pt) {
- return geom::Location::EXTERIOR != getLocator()->locate(&pt);
+ geom::Location locate(const geom::CoordinateXY& pt) const {
+ return getLocator()->locate(&pt);
}
};
diff --git a/src/operation/overlayng/OverlayEdgeRing.cpp b/src/operation/overlayng/OverlayEdgeRing.cpp
index f45d46418..b9ac01518 100644
--- a/src/operation/overlayng/OverlayEdgeRing.cpp
+++ b/src/operation/overlayng/OverlayEdgeRing.cpp
@@ -42,9 +42,9 @@ OverlayEdgeRing::OverlayEdgeRing(OverlayEdge* start, const GeometryFactory* geom
, locator(nullptr)
, shell(nullptr)
{
- auto ringPts = detail::make_unique<CoordinateSequence>(0u, start->getCoordinatesRO()->hasZ(), start->getCoordinatesRO()->hasM());
+ auto ringPts = std::make_shared<CoordinateSequence>(0u, start->getCoordinatesRO()->hasZ(), start->getCoordinatesRO()->hasM());
computeRingPts(start, *ringPts);
- computeRing(std::move(ringPts), geometryFactory);
+ computeRing(ringPts, geometryFactory);
}
/*public*/
@@ -60,6 +60,12 @@ OverlayEdgeRing::getRingPtr() const
return ring.get();
}
+const Envelope&
+OverlayEdgeRing::getEnvelope() const
+{
+ return *ring->getEnvelopeInternal();
+}
+
/**
* Tests whether this ring is a hole.
* @return <code>true</code> if this ring is a hole
@@ -149,10 +155,10 @@ OverlayEdgeRing::computeRingPts(OverlayEdge* start, CoordinateSequence& pts)
/*private*/
void
-OverlayEdgeRing::computeRing(std::unique_ptr<CoordinateSequence> && p_ringPts, const GeometryFactory* geometryFactory)
+OverlayEdgeRing::computeRing(const std::shared_ptr<CoordinateSequence> & p_ringPts, const GeometryFactory* geometryFactory)
{
if (ring != nullptr) return; // don't compute more than once
- ring = geometryFactory->createLinearRing(std::move(p_ringPts));
+ ring = geometryFactory->createLinearRing(p_ringPts);
m_isHole = algorithm::Orientation::isCCW(ring->getCoordinatesRO());
}
@@ -164,9 +170,9 @@ OverlayEdgeRing::computeRing(std::unique_ptr<CoordinateSequence> && p_ringPts, c
*/
/*private*/
const CoordinateSequence&
-OverlayEdgeRing::getCoordinates()
+OverlayEdgeRing::getCoordinates() const
{
- return *(detail::down_cast<const CoordinateSequence*>(ring->getCoordinatesRO()));
+ return *ring->getCoordinatesRO();
}
/**
@@ -189,39 +195,23 @@ OverlayEdgeRing::getCoordinates()
*/
/*public*/
OverlayEdgeRing*
-OverlayEdgeRing::findEdgeRingContaining(const std::vector<OverlayEdgeRing*>& erList)
+OverlayEdgeRing::findEdgeRingContaining(const std::vector<OverlayEdgeRing*>& erList) const
{
- const LinearRing* testRing = ring.get();
- const Envelope* testEnv = testRing->getEnvelopeInternal();
-
- OverlayEdgeRing* minRing = nullptr;
- const Envelope* minRingEnv = nullptr;
- for (auto tryEdgeRing: erList) {
- const LinearRing* tryRing = tryEdgeRing->getRingPtr();
- const Envelope* tryShellEnv = tryRing->getEnvelopeInternal();
- // the hole envelope cannot equal the shell envelope
- // (also guards against testing rings against themselves)
- if (tryShellEnv->equals(testEnv)) continue;
-
- // hole must be contained in shell
- if (! tryShellEnv->contains(testEnv)) continue;
-
- const Coordinate& testPt = EdgeRing::ptNotInList(testRing->getCoordinatesRO(), tryRing->getCoordinatesRO());
- bool isContained = tryEdgeRing->isInRing(testPt);
- // check if the new containing ring is smaller than the current minimum ring
- if (isContained) {
- if (minRing == nullptr || minRingEnv->contains(tryShellEnv)) {
- minRing = tryEdgeRing;
- minRingEnv = minRing->getRingPtr()->getEnvelopeInternal();
+ OverlayEdgeRing* minContainingRing = nullptr;
+ for (OverlayEdgeRing* edgeRing : erList) {
+ if (edgeRing->contains(*this)) {
+ if (minContainingRing == nullptr
+ || minContainingRing->getEnvelope().contains(edgeRing->getEnvelope())) {
+ minContainingRing = edgeRing;
}
}
}
- return minRing;
+ return minContainingRing;
}
/*private*/
PointOnGeometryLocator*
-OverlayEdgeRing::getLocator()
+OverlayEdgeRing::getLocator() const
{
if (locator == nullptr) {
locator.reset(new IndexedPointInAreaLocator(*(getRingPtr())));
@@ -230,18 +220,54 @@ OverlayEdgeRing::getLocator()
}
/*public*/
-bool
-OverlayEdgeRing::isInRing(const Coordinate& pt)
+geom::Location
+OverlayEdgeRing::locate(const CoordinateXY& pt) const
{
/**
* Use an indexed point-in-polygon for performance
*/
- return Location::EXTERIOR != getLocator()->locate(&pt);
+ return getLocator()->locate(&pt);
+}
+
+/**
+ * Tests if an edgeRing is properly contained in this ring.
+ * Relies on property that edgeRings never overlap (although they may
+ * touch at single vertices).
+ *
+ * @param ring ring to test
+ * @return true if ring is properly contained
+ */
+bool
+OverlayEdgeRing::contains(const OverlayEdgeRing& otherRing) const {
+ // the test envelope must be properly contained
+ // (guards against testing rings against themselves)
+ const Envelope& env = getEnvelope();
+ const Envelope& testEnv = otherRing.getEnvelope();
+ if (! env.containsProperly(testEnv)) {
+ return false;
+ }
+ return isPointInOrOut(otherRing);
+}
+
+bool
+OverlayEdgeRing::isPointInOrOut(const OverlayEdgeRing& otherRing) const {
+ // in most cases only one or two points will be checked
+ for (const CoordinateXY& pt : otherRing.getCoordinates().items<CoordinateXY>()) {
+ geom::Location loc = locate(pt);
+ if (loc == geom::Location::INTERIOR) {
+ return true;
+ }
+ if (loc == geom::Location::EXTERIOR) {
+ return false;
+ }
+ // pt is on BOUNDARY, so keep checking for a determining location
+ }
+ return false;
}
/*public*/
const Coordinate&
-OverlayEdgeRing::getCoordinate()
+OverlayEdgeRing::getCoordinate() const
{
return ring->getCoordinatesRO()->getAt(0);
}
diff --git a/src/operation/polygonize/EdgeRing.cpp b/src/operation/polygonize/EdgeRing.cpp
index 7bff9c787..4f4252a8d 100644
--- a/src/operation/polygonize/EdgeRing.cpp
+++ b/src/operation/polygonize/EdgeRing.cpp
@@ -51,39 +51,16 @@ namespace polygonize { // geos.operation.polygonize
EdgeRing*
EdgeRing::findEdgeRingContaining(const std::vector<EdgeRing*> & erList)
{
- const LinearRing* testRing = getRingInternal();
- if(! testRing) {
- return nullptr;
- }
- const Envelope* testEnv = testRing->getEnvelopeInternal();
- EdgeRing* minRing = nullptr;
- const Envelope* minRingEnv = nullptr;
-
- for(auto& tryEdgeRing : erList) {
- auto tryRing = tryEdgeRing->getRingInternal();
- auto tryShellEnv = tryRing->getEnvelopeInternal();
- // the hole envelope cannot equal the shell envelope
- // (also guards against testing rings against themselves)
- if (tryShellEnv->equals(testEnv)) {
- continue;
- }
- // hole must be contained in shell
- if (!tryShellEnv->contains(testEnv)) {
- continue;
- }
-
- auto tryCoords = tryRing->getCoordinatesRO();
- const Coordinate& testPt = ptNotInList(testRing->getCoordinatesRO(), tryCoords);
-
- // check if this new containing ring is smaller than the current minimum ring
- if(tryEdgeRing->isInRing(testPt)) {
- if(minRing == nullptr || minRingEnv->contains(tryShellEnv)) {
- minRing = tryEdgeRing;
- minRingEnv = minRing->getRingInternal()->getEnvelopeInternal();
+ EdgeRing* minContainingRing = nullptr;
+ for (auto& edgeRing : erList) {
+ if (edgeRing->contains(*this)) {
+ if (minContainingRing == nullptr
+ || minContainingRing->getEnvelope().contains(edgeRing->getEnvelope())) {
+ minContainingRing = edgeRing;
}
}
}
- return minRing;
+ return minContainingRing;
}
std::vector<PolygonizeDirectedEdge*>
@@ -214,12 +191,40 @@ EdgeRing::computeValid()
is_valid = ring->isValid();
}
+bool
+EdgeRing::contains(const EdgeRing& otherRing) const {
+ // the test envelope must be properly contained
+ // (guards against testing rings against themselves)
+ const Envelope& env = getEnvelope();
+ const Envelope& testEnv = otherRing.getEnvelope();
+ if (! env.containsProperly(testEnv)) {
+ return false;
+ }
+ return isPointInOrOut(otherRing);
+ }
+
+bool
+EdgeRing::isPointInOrOut(const EdgeRing& otherRing) const {
+ // in most cases only one or two points will be checked
+ for (const CoordinateXY& pt : otherRing.getCoordinates()->items<CoordinateXY>()) {
+ geom::Location loc = locate(pt);
+ if (loc == geom::Location::INTERIOR) {
+ return true;
+ }
+ if (loc == geom::Location::EXTERIOR) {
+ return false;
+ }
+ // pt is on BOUNDARY, so keep checking for a determining location
+ }
+ return false;
+}
+
/*private*/
const CoordinateSequence*
-EdgeRing::getCoordinates()
+EdgeRing::getCoordinates() const
{
if(ringPts == nullptr) {
- ringPts = detail::make_unique<CoordinateSequence>(0u, 0u);
+ ringPts = std::make_shared<CoordinateSequence>(0u, 0u);
for(const auto& de : deList) {
auto edge = dynamic_cast<PolygonizeEdge*>(de->getEdge());
addEdge(edge->getLine()->getCoordinatesRO(),
@@ -234,12 +239,12 @@ std::unique_ptr<LineString>
EdgeRing::getLineString()
{
getCoordinates();
- return std::unique_ptr<LineString>(factory->createLineString(*ringPts));
+ return factory->createLineString(ringPts);
}
/*public*/
-LinearRing*
-EdgeRing::getRingInternal()
+const LinearRing*
+EdgeRing::getRingInternal() const
{
if(ring != nullptr) {
return ring.get();
-----------------------------------------------------------------------
Summary of changes:
include/geos/geom/Envelope.h | 13 +++
include/geos/operation/overlayng/OverlayEdgeRing.h | 20 +++--
include/geos/operation/polygonize/EdgeRing.h | 23 ++++--
src/operation/overlayng/OverlayEdgeRing.cpp | 96 ++++++++++++++--------
src/operation/polygonize/EdgeRing.cpp | 75 +++++++++--------
5 files changed, 142 insertions(+), 85 deletions(-)
hooks/post-receive
--
GEOS
More information about the geos-commits
mailing list