From git at osgeo.org Mon Nov 10 09:52:51 2025 From: git at osgeo.org (git at osgeo.org) Date: Mon, 10 Nov 2025 09:52:51 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 93472ce0f6a02dd5dfcbf8e41eca4e75e714209f Message-ID: <20251110175251.5CA2C192042@trac.osgeo.org> 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 93472ce0f6a02dd5dfcbf8e41eca4e75e714209f (commit) from b5960c3a08c3ccaffee019529f847dc02371a790 (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 93472ce0f6a02dd5dfcbf8e41eca4e75e714209f Author: Daniel Baston Date: Mon Nov 10 12:52:28 2025 -0500 Buffer: Ensure buffer of single-part returns single-part (#1323) * Buffer: Ensure buffer of single-part returns single-part * Buffer: Move location of fix for #1321 * BufferOp: Add a test case diff --git a/src/operation/buffer/BufferBuilder.cpp b/src/operation/buffer/BufferBuilder.cpp index a5d423e9e..5cc5685d2 100644 --- a/src/operation/buffer/BufferBuilder.cpp +++ b/src/operation/buffer/BufferBuilder.cpp @@ -363,6 +363,25 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, } } +static void +keepLargestArea(std::vector> & polyList) { + size_t maxAreaGeom = 0; + double maxArea = polyList[0]->getArea(); + + for (size_t i = 1; i < polyList.size(); i++) { + if (polyList[i]->getArea() > maxArea) { + maxArea = polyList[i]->getArea(); + maxAreaGeom = i; + } + } + + if (maxAreaGeom > 0) { + polyList[0] = std::move(polyList[maxAreaGeom]); + } + + polyList.resize(1); +} + /*public*/ std::unique_ptr BufferBuilder::buffer(const Geometry* g, double distance) @@ -485,9 +504,18 @@ BufferBuilder::buffer(const Geometry* g, double distance) return createEmptyResultGeometry(); } + // Heuristic to remove artifacts caused by topology robustness problems + // or buffer curve generation anomalies. + // Uses fact that for distance > 0 single-element inputs must create single element buffers. + // This does not hold if distance <= 0; + // distance = 0 can create multipolygon results due to topology collapse, + // and distance < 0 may erode polygons so they are disconnected. + if (distance > 0 && g->getNumGeometries() == 1 && resultPolyList.size() > 1) { + keepLargestArea(resultPolyList); + } + // resultPolyList ownership transferred here resultGeom = geomFact->buildGeometry(std::move(resultPolyList)); - } catch(const util::GEOSException& /* exc */) { diff --git a/src/operation/buffer/BufferOp.cpp b/src/operation/buffer/BufferOp.cpp index 379ca1d4d..0bdbbfdb7 100644 --- a/src/operation/buffer/BufferOp.cpp +++ b/src/operation/buffer/BufferOp.cpp @@ -116,6 +116,7 @@ BufferOp::getResultGeometry(double nDistance) } distance = nDistance; computeGeometry(); + return std::unique_ptr(resultGeometry.release()); } diff --git a/tests/unit/operation/buffer/BufferOpTest.cpp b/tests/unit/operation/buffer/BufferOpTest.cpp index b51914ca8..7ac585ccc 100644 --- a/tests/unit/operation/buffer/BufferOpTest.cpp +++ b/tests/unit/operation/buffer/BufferOpTest.cpp @@ -598,7 +598,7 @@ void object::test<26> } // testElementErodedEx -// Checks that a skinny element polygon is eroded with no internal predicision reduction due to topo exes +// Checks that a skinny element polygon is eroded with no internal precision reduction due to topo exes // see https://github.com/libgeos/geos/issues/1182 template<> template<> @@ -623,4 +623,43 @@ void object::test<28> "MULTIPOLYGON (((24 95.239, 24 96, 24 99, 24.816 99, 24 95.239)), ((3 90, 3 93, 3 96, 3 99, 21 99, 21 96, 21 93, 21 90, 3 90)))"); } +template<> +template<> +void object::test<29> +() +{ + set_test_name("GH-1321"); + // Ensure positive buffer of LineString produces a single-part Polygon + // See https://github.com/libgeos/geos/issues/1321 + + std::string wkt = "LINESTRING(640770.332537465 216785.425146015,640770.356311913 216785.560172686,640770.475488952 216786.226162019,640770.647396495 216787.800152365,640770.658978918 216789.268376902,640770.447752096 216792.399898366,640769.98018796 216795.624688816,640769.110287021 216798.527305023,640767.648768098 216801.891389348,640766.02448565 216804.805892778,640764.74005588 216807.134569434,640763.337363474 216809.560477487,640761.650901703 216812.246990061,640759.955600712 216815.327305019,640758.482499366 216817.868732504,640757.383693167 216819.548488661,640756.238862077 216821.226720821,640754.01503683 216824.434442434,640751.366929134 216828.435255234,640749.204368809 216832.450088865,640747.25516891 216836.227787618,640746.014020829 216838.801219168,640745.393751588 216840.360274284,640744.315976633 216842.854457673,640743.400050801 216844.65704848,640742.582575565 216846.277673322,640741.52491745 216848.478638524,640740.503835408 216850.705816576,640739.787553975 2 16852.270967708,640739.053289307 216853.851968469,640738.173025147 216855.546355058,640737.55488951 216856.568961104,640736.817272035 216857.822910812,640735.910795021 216859.35697228,640734.77510795 216861.236982439,640733.832969266 216862.938074642,640732.814325629 216865.039674844,640731.225095251 216869.012141189,640729.979984761 216871.879095724,640729.445974092 216873.02148841,640729.002794006 216873.679857725,640728.952197105 216873.745389857,640728.676962154 216874.089814544)"; + + auto bufGeom = wktreader.read(wkt)->buffer(100); + + ensure_equals(bufGeom->getGeometryTypeId(), geos::geom::GEOS_POLYGON); + ensure(bufGeom->getArea() > 51000); +} + +template<> +template<> +void object::test<30> +() +{ + set_test_name("sf-2552"); + // Ensure positive buffer of LineString produces a single-part Polygon + // See https://github.com/r-spatial/sf/issues/2552 + + std::string wkt = "LINESTRING (245184.6 6045650, 245193.3 6045649, 245201.7 6045651, 245204.3 6045653)"; + + auto geom = wktreader.read(wkt); + + BufferOp bop(geom.get()); + bop.setEndCapStyle(BufferParameters::CAP_SQUARE); + + auto bufGeom = bop.getResultGeometry(50); + ensure_equals(bufGeom->getGeometryTypeId(), geos::geom::GEOS_POLYGON); + + ensure(bufGeom->getArea() > 12000); +} + } // namespace tut diff --git a/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp b/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp index 73a8a3dd1..83f3e9e45 100644 --- a/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp +++ b/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp @@ -45,7 +45,7 @@ struct test_dpsimp_data { ensure("Simplified geometry is invalid!", simplified->isValid()); GeomPtr exp(wktreader.read(wkt_expected)); - ensure_equals_geometry(exp.get(), simplified.get()); + ensure_equals_geometry(simplified.get(), exp.get()); } void ----------------------------------------------------------------------- Summary of changes: src/operation/buffer/BufferBuilder.cpp | 30 +++++++++++++++- src/operation/buffer/BufferOp.cpp | 1 + tests/unit/operation/buffer/BufferOpTest.cpp | 41 +++++++++++++++++++++- .../unit/simplify/DouglasPeuckerSimplifierTest.cpp | 2 +- 4 files changed, 71 insertions(+), 3 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Sun Nov 16 14:11:26 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 16 Nov 2025 14:11:26 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. e3b518f00ce17fecaed7289323829fc9bb7a1105 Message-ID: <20251116221127.72E4C189C86@trac.osgeo.org> 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 e3b518f00ce17fecaed7289323829fc9bb7a1105 (commit) via 588f656cf4107d7cf34706544be03c9589878d5f (commit) via a1164a680593ef43aaa0bee11578abaac24b5dbd (commit) via b8cb43fc5b175e23496521319742e982192e1638 (commit) via 05ac5c6a2d02a98f4fc566ef86737ba9d324fb12 (commit) from 93472ce0f6a02dd5dfcbf8e41eca4e75e714209f (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 e3b518f00ce17fecaed7289323829fc9bb7a1105 Author: Daniel Baston Date: Wed Nov 12 14:46:37 2025 -0500 BoundaryChainNoder: mark some methods as static diff --git a/include/geos/noding/BoundaryChainNoder.h b/include/geos/noding/BoundaryChainNoder.h index ec98eb9da..a3fc72446 100644 --- a/include/geos/noding/BoundaryChainNoder.h +++ b/include/geos/noding/BoundaryChainNoder.h @@ -170,24 +170,24 @@ private: std::vector> extractChains(std::vector& sections) const; - Coordinate::UnorderedSet findNodePts( - const std::vector>& segStrings) const; + static Coordinate::UnorderedSet findNodePts( + const std::vector>& segStrings); - std::vector> nodeChains( + static std::vector> nodeChains( std::vector> &chains, const Coordinate::UnorderedSet &nodePts); - void nodeChain( + static void nodeChain( std::unique_ptr chain, const Coordinate::UnorderedSet &nodePts, std::vector> &nodedChains); - std::size_t findNodeIndex( + static std::size_t findNodeIndex( const SegmentString* chain, std::size_t start, - const Coordinate::UnorderedSet& nodePts) const; + const Coordinate::UnorderedSet& nodePts); - std::unique_ptr substring( + static std::unique_ptr substring( const SegmentString* segString, std::size_t start, std::size_t end); diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index b8348b24c..35b3a6bfe 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -48,7 +48,7 @@ BoundaryChainNoder::computeNodes(const std::vector& segStrings) /* private */ Coordinate::UnorderedSet -BoundaryChainNoder::findNodePts(const std::vector>& segStrings) const +BoundaryChainNoder::findNodePts(const std::vector>& segStrings) { Coordinate::UnorderedSet interiorVertices; Coordinate::UnorderedSet nodes; @@ -122,7 +122,7 @@ std::size_t BoundaryChainNoder::findNodeIndex( const SegmentString* chain, std::size_t start, - const Coordinate::UnorderedSet& nodePts) const + const Coordinate::UnorderedSet& nodePts) { for (std::size_t i = start + 1; i < chain->size(); i++) { if (nodePts.find(chain->getCoordinate(i)) != nodePts.end()) commit 588f656cf4107d7cf34706544be03c9589878d5f Author: Daniel Baston Date: Wed Nov 12 14:27:02 2025 -0500 BoundaryChainNoder: Add comment diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index f4346d9bb..b8348b24c 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -107,7 +107,10 @@ BoundaryChainNoder::nodeChain( std::unique_ptr BoundaryChainNoder::substring(const SegmentString* segString, std::size_t start, std::size_t end) { - // FIXME: Doesn't this leak "pts" ? + // A BasicSegmentString does not own its CoordinateSequence, so why does this not leak? + // At least in the CoverageUnion case, we end up here from EdgeNodingBuilder::node, where the + // created BasicSegmentStrings are (incorrectly) down-casted to NodedSegmentStrings, and + // the coordinate ownership is transferred to an overlayng::Edge. auto pts = std::make_unique(); pts->add(*segString->getCoordinates(), start, end); return std::make_unique(pts.release(), segString->getData()); commit a1164a680593ef43aaa0bee11578abaac24b5dbd Author: Daniel Baston Date: Wed Nov 12 12:22:44 2025 -0500 Noder::getNodedSubstrings: Return vector of unique_ptr diff --git a/include/geos/coverage/CoverageCleaner.h b/include/geos/coverage/CoverageCleaner.h index 8452a4925..79b0ed855 100644 --- a/include/geos/coverage/CoverageCleaner.h +++ b/include/geos/coverage/CoverageCleaner.h @@ -324,7 +324,7 @@ public: std::vector getMergedGaps(); std::unique_ptr toGeometry( - std::vector& segStrings, + std::vector>& segStrings, const GeometryFactory* geomFact); std::unique_ptr node( diff --git a/include/geos/geomgraph/EdgeNodingValidator.h b/include/geos/geomgraph/EdgeNodingValidator.h index 6f844d1e0..84a506b01 100644 --- a/include/geos/geomgraph/EdgeNodingValidator.h +++ b/include/geos/geomgraph/EdgeNodingValidator.h @@ -54,13 +54,13 @@ namespace geomgraph { // geos.geomgraph class GEOS_DLL EdgeNodingValidator final { private: - std::vector& toSegmentStrings(std::vector& edges); + const std::vector>& toSegmentStrings(std::vector& edges); // Make sure this member is initialized *before* // the NodingValidator, as initialization of // NodingValidator will use toSegmentString(), that // in turn expects this member to be initialized - std::vector segStr; + std::vector> segStr; // Make sure this member is initialized *before* // the NodingValidator, as initialization of diff --git a/include/geos/noding/BoundaryChainNoder.h b/include/geos/noding/BoundaryChainNoder.h index d46007497..ec98eb9da 100644 --- a/include/geos/noding/BoundaryChainNoder.h +++ b/include/geos/noding/BoundaryChainNoder.h @@ -66,8 +66,8 @@ private: SegmentString* segString; std::vector isBoundary; - static SegmentString* createChain( - const SegmentString* segString, + static std::unique_ptr createChain( + const SegmentString *segString, std::size_t startIndex, std::size_t endIndex, bool constructZ, @@ -84,7 +84,7 @@ private: }; void setBoundarySegment(std::size_t index); - void createChains(std::vector& chains, bool constructZ, bool constructM); + void createChains(std::vector> &chains, bool constructZ, bool constructM); }; class Segment { @@ -142,14 +142,14 @@ public: {}; // Noder virtual methods - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; void computeNodes(const std::vector& inputSegStrings) override; private: // Members - std::vector m_chainList; + std::vector> m_chainList; std::vector> m_substrings; bool m_constructZ; bool m_constructM; @@ -168,19 +168,19 @@ private: static void markBoundarySegments(SegmentSet& segSet); - std::vector extractChains(std::vector& sections) const; + std::vector> extractChains(std::vector& sections) const; Coordinate::UnorderedSet findNodePts( - const std::vector& segStrings) const; + const std::vector>& segStrings) const; - std::vector nodeChains( - const std::vector& chains, - const Coordinate::UnorderedSet& nodePts); + std::vector> nodeChains( + std::vector> &chains, + const Coordinate::UnorderedSet &nodePts); void nodeChain( - SegmentString* chain, - const Coordinate::UnorderedSet& nodePts, - std::vector& nodedChains); + std::unique_ptr chain, + const Coordinate::UnorderedSet &nodePts, + std::vector> &nodedChains); std::size_t findNodeIndex( const SegmentString* chain, diff --git a/include/geos/noding/FastNodingValidator.h b/include/geos/noding/FastNodingValidator.h index 6ceadc4a3..f2b004937 100644 --- a/include/geos/noding/FastNodingValidator.h +++ b/include/geos/noding/FastNodingValidator.h @@ -60,13 +60,16 @@ class FastNodingValidator { public: - FastNodingValidator(std::vector& newSegStrings) + FastNodingValidator(const std::vector>& newSegStrings) : li(), // robust... - segStrings(newSegStrings), segInt(), isValidVar(true) { + segStrings.resize(newSegStrings.size()); + for (std::size_t i = 0; i < newSegStrings.size(); ++i) { + segStrings[i] = newSegStrings[i].get(); + } } /** \brief @@ -102,7 +105,7 @@ private: geos::algorithm::LineIntersector li; - std::vector& segStrings; + std::vector segStrings; std::unique_ptr segInt; diff --git a/include/geos/noding/GeometryNoder.h b/include/geos/noding/GeometryNoder.h index 437307fac..ea3b3c347 100644 --- a/include/geos/noding/GeometryNoder.h +++ b/include/geos/noding/GeometryNoder.h @@ -45,6 +45,10 @@ public: std::unique_ptr getNoded(); + // Declare type as noncopyable + GeometryNoder(GeometryNoder const&) = delete; + GeometryNoder& operator=(GeometryNoder const&) = delete; + private: const geom::Geometry& argGeom; @@ -58,10 +62,8 @@ private: std::unique_ptr noder; - std::unique_ptr toGeometry(SegmentString::NonConstVect& noded); + std::unique_ptr toGeometry(std::vector>& noded); - GeometryNoder(GeometryNoder const&); /*= delete*/ - GeometryNoder& operator=(GeometryNoder const&); /*= delete*/ }; } // namespace geos.noding diff --git a/include/geos/noding/IteratedNoder.h b/include/geos/noding/IteratedNoder.h index 6e55ecb8a..1d2bc296a 100644 --- a/include/geos/noding/IteratedNoder.h +++ b/include/geos/noding/IteratedNoder.h @@ -57,7 +57,7 @@ private: const geom::PrecisionModel* pm; algorithm::LineIntersector li; - std::vector nodedSegStrings; + std::vector> nodedSegStrings; int maxIter; /** @@ -96,7 +96,7 @@ public: maxIter = n; } - std::vector + std::vector> getNodedSubstrings() override { return std::move(nodedSegStrings); @@ -113,6 +113,10 @@ public: * @throws TopologyException if the iterated noding fails to converge. */ void computeNodes(const std::vector& inputSegmentStrings) override; // throw(GEOSException); + + // Declare type as noncopyable + IteratedNoder(IteratedNoder const&) = delete; + IteratedNoder& operator=(IteratedNoder const&) = delete; }; } // namespace geos::noding diff --git a/include/geos/noding/MCIndexNoder.h b/include/geos/noding/MCIndexNoder.h index 5a4965710..d2e02453c 100644 --- a/include/geos/noding/MCIndexNoder.h +++ b/include/geos/noding/MCIndexNoder.h @@ -101,7 +101,7 @@ public: return index; } - std::vector getNodedSubstrings() override + std::vector> getNodedSubstrings() override { //assert(nodedSegStrings); // must have called computeNodes before! return NodedSegmentString::getNodedSubstrings(nodedSegStrings); diff --git a/include/geos/noding/NodedSegmentString.h b/include/geos/noding/NodedSegmentString.h index 985b8e722..632ac9493 100644 --- a/include/geos/noding/NodedSegmentString.h +++ b/include/geos/noding/NodedSegmentString.h @@ -62,7 +62,7 @@ public: template static void getNodedSubstrings(II from, II too_far, - SegmentString::NonConstVect* resultEdgelist) + std::vector>& resultEdgelist) { for(II i = from; i != too_far; ++i) { NodedSegmentString* nss = dynamic_cast(*i); @@ -73,16 +73,16 @@ public: template static void - getNodedSubstrings(C* segStrings, - SegmentString::NonConstVect* resultEdgelist) + getNodedSubstrings(const C& segStrings, + std::vector>& resultEdgelist) { - getNodedSubstrings(segStrings->begin(), segStrings->end(), resultEdgelist); + getNodedSubstrings(segStrings.begin(), segStrings.end(), resultEdgelist); } static void getNodedSubstrings(const SegmentString::NonConstVect& segStrings, - SegmentString::NonConstVect* resultEdgeList); + std::vector>& resultEdgeList); - static std::vector getNodedSubstrings( + static std::vector> getNodedSubstrings( const std::vector& segStrings); std::unique_ptr getNodedCoordinates(); @@ -124,7 +124,6 @@ public: std::ostream& print(std::ostream& os) const override; - /** \brief * Add {@link SegmentNode}s for one or both * intersections found for a segment of an edge to the edge diff --git a/include/geos/noding/Noder.h b/include/geos/noding/Noder.h index 03c490160..e41a80e50 100644 --- a/include/geos/noding/Noder.h +++ b/include/geos/noding/Noder.h @@ -16,6 +16,7 @@ #include +#include #include // Forward declarations @@ -50,7 +51,7 @@ public: * * @param segStrings a collection of {@link SegmentString}s to node * The caller remains responsible for releasing the memory - * associated with the container and its elements. + * associated with the SegmentStrings. */ virtual void computeNodes(const std::vector& segStrings) = 0; @@ -62,7 +63,7 @@ public: * Caller is responsible to delete elements of container. * This method may only be called once. */ - virtual std::vector getNodedSubstrings() = 0; + virtual std::vector> getNodedSubstrings() = 0; virtual ~Noder() {} diff --git a/include/geos/noding/NodingValidator.h b/include/geos/noding/NodingValidator.h index 31bdd4e1f..24b24c94b 100644 --- a/include/geos/noding/NodingValidator.h +++ b/include/geos/noding/NodingValidator.h @@ -45,7 +45,7 @@ namespace noding { // geos.noding class GEOS_DLL NodingValidator { private: algorithm::LineIntersector li; - const std::vector& segStrings; + std::vector segStrings; /** * Checks if a segment string contains a segment @@ -93,9 +93,13 @@ private: public: - NodingValidator(const std::vector& newSegStrings): - segStrings(newSegStrings) - {} + NodingValidator(const std::vector>& newSegStrings) + { + segStrings.resize(newSegStrings.size()); + for (size_t i = 0; i < newSegStrings.size(); ++i) { + segStrings[i] = newSegStrings[i].get(); + } + } ~NodingValidator() {} diff --git a/include/geos/noding/ScaledNoder.h b/include/geos/noding/ScaledNoder.h index 2e0d615be..99566d879 100644 --- a/include/geos/noding/ScaledNoder.h +++ b/include/geos/noding/ScaledNoder.h @@ -77,7 +77,7 @@ public: ~ScaledNoder() override; - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; void computeNodes(const std::vector& inputSegStr) override; @@ -104,7 +104,7 @@ private: bool isScaled; - void rescale(std::vector& segStrings) const; + void rescale(std::vector>& segStrings) const; void scale(const std::vector& segStrings) const; diff --git a/include/geos/noding/SegmentExtractingNoder.h b/include/geos/noding/SegmentExtractingNoder.h index 5f4f29d15..71c49e909 100644 --- a/include/geos/noding/SegmentExtractingNoder.h +++ b/include/geos/noding/SegmentExtractingNoder.h @@ -53,15 +53,15 @@ class GEOS_DLL SegmentExtractingNoder : public Noder { private: - std::vector segList; + std::vector> segList; void extractSegments( const std::vector& inputSegs, - std::vector& outputSegs); + std::vector>& outputSegs); void extractSegments( const SegmentString* ss, - std::vector& outputSegs); + std::vector>& outputSegs); public: @@ -77,8 +77,11 @@ public: * @return a Collection of SegmentString representing the * substrings. Caller takes ownership over vector and contents. */ - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; + // Declare type as noncopyable + SegmentExtractingNoder(SegmentExtractingNoder const&) = delete; + SegmentExtractingNoder& operator=(SegmentExtractingNoder const&) = delete; }; diff --git a/include/geos/noding/SegmentNodeList.h b/include/geos/noding/SegmentNodeList.h index d199fde15..6791e9704 100644 --- a/include/geos/noding/SegmentNodeList.h +++ b/include/geos/noding/SegmentNodeList.h @@ -219,10 +219,10 @@ public: * Adds the edges to the input list (this is so a single list * can be used to accumulate all split edges for a Geometry). */ - void addSplitEdges(std::vector& edgeList); + void addSplitEdges(std::vector>& edgeList); void - addSplitEdges(std::vector* edgeList) + addSplitEdges(std::vector>* edgeList) { assert(edgeList); addSplitEdges(*edgeList); diff --git a/include/geos/noding/SegmentString.h b/include/geos/noding/SegmentString.h index af7cee2de..8e08b853b 100644 --- a/include/geos/noding/SegmentString.h +++ b/include/geos/noding/SegmentString.h @@ -171,6 +171,8 @@ public: return seq->front().equals(seq->back()); } + static std::vector toRawPointerVector(const std::vector> & segStrings); + virtual std::ostream& print(std::ostream& os) const; protected: diff --git a/include/geos/noding/SimpleNoder.h b/include/geos/noding/SimpleNoder.h index b2bf4f70c..95468637a 100644 --- a/include/geos/noding/SimpleNoder.h +++ b/include/geos/noding/SimpleNoder.h @@ -58,7 +58,7 @@ public: void computeNodes(const std::vector& inputSegmentStrings) override; - std::vector + std::vector> getNodedSubstrings() override { return NodedSegmentString::getNodedSubstrings(nodedSegStrings); diff --git a/include/geos/noding/SinglePassNoder.h b/include/geos/noding/SinglePassNoder.h index 1c2de5613..b36d94a60 100644 --- a/include/geos/noding/SinglePassNoder.h +++ b/include/geos/noding/SinglePassNoder.h @@ -88,7 +88,7 @@ public: * * @return a Collection of SegmentStrings */ - std::vector getNodedSubstrings() override = 0; + std::vector> getNodedSubstrings() override = 0; }; diff --git a/include/geos/noding/ValidatingNoder.h b/include/geos/noding/ValidatingNoder.h index e6a3af6a2..c8c750ba8 100644 --- a/include/geos/noding/ValidatingNoder.h +++ b/include/geos/noding/ValidatingNoder.h @@ -17,6 +17,7 @@ #include #include +#include #include // for unique_ptr @@ -51,7 +52,7 @@ class GEOS_DLL ValidatingNoder : public Noder { private: - std::vector nodedSS; + std::vector> nodedSS; noding::Noder& noder; @@ -61,11 +62,17 @@ public: : noder(noderArg) {} + ~ValidatingNoder() override; + void computeNodes(const std::vector& segStrings) override; - void validate(); + void validate() const; - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; + + // Declare type as noncopyable + ValidatingNoder(ValidatingNoder const&) = delete; + ValidatingNoder& operator=(ValidatingNoder const&) = delete; }; diff --git a/include/geos/noding/snap/SnappingNoder.h b/include/geos/noding/snap/SnappingNoder.h index 8381f13bd..a143419c5 100644 --- a/include/geos/noding/snap/SnappingNoder.h +++ b/include/geos/noding/snap/SnappingNoder.h @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -71,7 +72,7 @@ private: // Members double snapTolerance; SnappingPointIndex snapIndex; - std::vector nodedResult; + std::vector> nodedResult; // Methods @@ -79,7 +80,7 @@ private: void snapVertices(const std::vector& segStrings, std::vector& nodedStrings); - SegmentString* snapVertices(SegmentString* ss); + std::unique_ptr snapVertices(const SegmentString* ss); std::unique_ptr snap(const geom::CoordinateSequence* cs); @@ -91,7 +92,7 @@ private: * * @return a list of Coordinates for the intersections */ - std::vector snapIntersections(std::vector& inputSS); + std::vector> snapIntersections(std::vector& inputSS); public: @@ -108,7 +109,7 @@ public: /** * @return a Collection of NodedSegmentStrings representing the substrings */ - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; void computeNodes(const std::vector& inputSegStrings) override; diff --git a/include/geos/noding/snapround/MCIndexSnapRounder.h b/include/geos/noding/snapround/MCIndexSnapRounder.h index ba1ad2db7..19a33addd 100644 --- a/include/geos/noding/snapround/MCIndexSnapRounder.h +++ b/include/geos/noding/snapround/MCIndexSnapRounder.h @@ -83,7 +83,7 @@ public: li.setPrecisionModel(&pm); } - std::vector + std::vector> getNodedSubstrings() override { return NodedSegmentString::getNodedSubstrings(nodedSegStrings); diff --git a/include/geos/noding/snapround/SnapRoundingNoder.h b/include/geos/noding/snapround/SnapRoundingNoder.h index 528c63df8..2cd6a251b 100644 --- a/include/geos/noding/snapround/SnapRoundingNoder.h +++ b/include/geos/noding/snapround/SnapRoundingNoder.h @@ -148,7 +148,7 @@ public: /** * @return a Collection of NodedSegmentStrings representing the substrings */ - std::vector getNodedSubstrings() override; + std::vector> getNodedSubstrings() override; /** * Computes the nodes in the snap-rounding line arrangement. diff --git a/include/geos/operation/overlayng/EdgeNodingBuilder.h b/include/geos/operation/overlayng/EdgeNodingBuilder.h index 8130c1aa1..cae8a44e7 100644 --- a/include/geos/operation/overlayng/EdgeNodingBuilder.h +++ b/include/geos/operation/overlayng/EdgeNodingBuilder.h @@ -178,7 +178,7 @@ private: * (and is then discarded). */ std::vector node(const std::vector& segStrings); - std::vector createEdges(std::vector* segStrings); + std::vector createEdges(std::vector> &segStrings); public: @@ -199,18 +199,10 @@ public: , inputHasM(false) {}; - ~EdgeNodingBuilder() - { - for (noding::SegmentString* ss: *inputEdges) { - delete ss; - } - } + ~EdgeNodingBuilder(); void setClipEnvelope(const Envelope* clipEnv); - // returns newly allocated vector and segmentstrings - // std::vector* node(); - /** * Reports whether there are noded edges * for the given input geometry. @@ -236,8 +228,9 @@ public: */ std::vector build(const Geometry* geom0, const Geometry* geom1); - - + // Declare type as noncopyable + EdgeNodingBuilder(const EdgeNodingBuilder& other) = delete; + EdgeNodingBuilder& operator=(const EdgeNodingBuilder& rhs) = delete; }; diff --git a/src/coverage/CoverageCleaner.cpp b/src/coverage/CoverageCleaner.cpp index 88e30c872..940dcd444 100644 --- a/src/coverage/CoverageCleaner.cpp +++ b/src/coverage/CoverageCleaner.cpp @@ -384,11 +384,11 @@ CoverageCleaner::polygonize(const Geometry* cleanEdges) /* public static */ std::unique_ptr CoverageCleaner::toGeometry( - std::vector& segStrings, + std::vector>& segStrings, const GeometryFactory* geomFact) { std::vector> lines; - for (SegmentString* ss : segStrings) { + for (auto& ss : segStrings) { auto cs = ss->getCoordinates()->clone(); std::unique_ptr line = geomFact->createLineString(std::move(cs)); lines.emplace_back(line.release()); @@ -426,9 +426,6 @@ CoverageCleaner::node(std::vector& p_coverage, double p_snapDis } auto result = toGeometry(nodedSegStrings, geomFactory); - for (SegmentString* ss : nodedSegStrings) { - delete ss; - } return result; } diff --git a/src/geomgraph/EdgeNodingValidator.cpp b/src/geomgraph/EdgeNodingValidator.cpp index 97b9a7d99..eab396e81 100644 --- a/src/geomgraph/EdgeNodingValidator.cpp +++ b/src/geomgraph/EdgeNodingValidator.cpp @@ -30,14 +30,14 @@ using namespace geos::geom; namespace geos { namespace geomgraph { // geos.geomgraph -std::vector& +const std::vector>& EdgeNodingValidator::toSegmentStrings(std::vector& edges) { // convert Edges to SegmentStrings for(std::size_t i = 0, n = edges.size(); i < n; ++i) { Edge* e = edges[i]; auto cs = e->getCoordinates()->clone(); - segStr.push_back(new BasicSegmentString(cs.get(), e)); + segStr.push_back(std::make_unique(cs.get(), e)); newCoordSeq.push_back(cs.release()); } return segStr; @@ -45,13 +45,6 @@ EdgeNodingValidator::toSegmentStrings(std::vector& edges) EdgeNodingValidator::~EdgeNodingValidator() { - for(SegmentString::NonConstVect::iterator - i = segStr.begin(), e = segStr.end(); - i != e; - ++i) { - delete *i; - } - for(std::size_t i = 0, n = newCoordSeq.size(); i < n; ++i) { delete newCoordSeq[i]; } diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index 8a7637c08..f4346d9bb 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -48,11 +48,11 @@ BoundaryChainNoder::computeNodes(const std::vector& segStrings) /* private */ Coordinate::UnorderedSet -BoundaryChainNoder::findNodePts(const std::vector& segStrings) const +BoundaryChainNoder::findNodePts(const std::vector>& segStrings) const { Coordinate::UnorderedSet interiorVertices; Coordinate::UnorderedSet nodes; - for (const SegmentString* ss : segStrings) { + for (const auto& ss : segStrings) { //-- endpoints are nodes nodes.insert(ss->getCoordinate(0)); nodes.insert(ss->getCoordinate(ss->size() - 1)); @@ -70,14 +70,14 @@ BoundaryChainNoder::findNodePts(const std::vector& segStrings) c } /* private */ -std::vector +std::vector> BoundaryChainNoder::nodeChains( - const std::vector& chains, + std::vector>& chains, const Coordinate::UnorderedSet& nodePts) { - std::vector nodedChains; - for (SegmentString* chain : chains) { - nodeChain(chain, nodePts, nodedChains); + std::vector> nodedChains; + for (auto& chain : chains) { + nodeChain(std::move(chain), nodePts, nodedChains); } return nodedChains; } @@ -86,25 +86,21 @@ BoundaryChainNoder::nodeChains( /* private */ void BoundaryChainNoder::nodeChain( - SegmentString* chain, + std::unique_ptr chain, const Coordinate::UnorderedSet& nodePts, - std::vector& nodedChains) + std::vector>& nodedChains) { std::size_t start = 0; while (start < chain->size() - 1) { - std::size_t end = findNodeIndex(chain, start, nodePts); + std::size_t end = findNodeIndex(chain.get(), start, nodePts); //-- if no interior nodes found, keep original chain if (start == 0 && end == chain->size() - 1) { - nodedChains.push_back(chain); + nodedChains.emplace_back(std::move(chain)); return; } - nodedChains.push_back(substring(chain, start, end).release()); + nodedChains.push_back(substring(chain.get(), start, end)); start = end; } - // We replaced this SegmentString with substrings, - // and we are discarding the containing vector later - // so get rid of this chain now - delete chain; } /* private static */ @@ -134,7 +130,7 @@ BoundaryChainNoder::findNodeIndex( /* public */ -std::vector +std::vector> BoundaryChainNoder::getNodedSubstrings() { return std::move(m_chainList); @@ -201,10 +197,10 @@ BoundaryChainNoder::markBoundarySegments(SegmentSet& segSet) } /* private */ -std::vector +std::vector> BoundaryChainNoder::extractChains(std::vector& boundaryChains) const { - std::vector chains; + std::vector> chains; for (BoundaryChainMap& chainMap : boundaryChains) { chainMap.createChains(chains, m_constructZ, m_constructM); } @@ -225,7 +221,7 @@ BoundaryChainNoder::BoundaryChainMap::setBoundarySegment(std::size_t index) /* public */ void BoundaryChainNoder::BoundaryChainMap::createChains( - std::vector& chains, + std::vector>& chains, bool constructZ, bool constructM) { @@ -235,16 +231,16 @@ BoundaryChainNoder::BoundaryChainMap::createChains( if (startIndex >= segString->size() - 1) break; endIndex = findChainEnd(startIndex); - SegmentString* ss = createChain(segString, startIndex, endIndex, constructZ, constructM); - chains.push_back(ss); + auto ss = createChain(segString, startIndex, endIndex, constructZ, constructM); + chains.push_back(std::move(ss)); } } /* private static */ -SegmentString* +std::unique_ptr BoundaryChainNoder::BoundaryChainMap::createChain( - const SegmentString* segString, + const SegmentString *segString, std::size_t startIndex, std::size_t endIndex, bool constructZ, @@ -255,7 +251,7 @@ BoundaryChainNoder::BoundaryChainMap::createChain( pts->reserve(npts); pts->add(*segString->getCoordinates(), startIndex, endIndex); - return new NodedSegmentString(pts.release(), constructZ, constructM, segString->getData()); + return std::make_unique(pts.release(), constructZ, constructM, segString->getData()); } /* private */ diff --git a/src/noding/GeometryNoder.cpp b/src/noding/GeometryNoder.cpp index b552e7f47..5ec79d1f7 100644 --- a/src/noding/GeometryNoder.cpp +++ b/src/noding/GeometryNoder.cpp @@ -97,7 +97,7 @@ GeometryNoder::GeometryNoder(const geom::Geometry& g) /* private */ std::unique_ptr -GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges) +GeometryNoder::toGeometry(std::vector>& nodedEdges) { const geom::GeometryFactory* geomFact = argGeom.getFactory(); @@ -130,7 +130,7 @@ GeometryNoder::getNoded() extractSegmentStrings(argGeom, p_lineList); Noder& p_noder = getNoder(); - std::vector nodedEdges; + std::vector> nodedEdges; try { p_noder.computeNodes(p_lineList); @@ -145,10 +145,6 @@ GeometryNoder::getNoded() std::unique_ptr noded = toGeometry(nodedEdges); - for(auto* elem : nodedEdges) { - delete elem; - } - for(auto* elem : p_lineList) { delete elem; } diff --git a/src/noding/IteratedNoder.cpp b/src/noding/IteratedNoder.cpp index 62e893287..c88b76387 100644 --- a/src/noding/IteratedNoder.cpp +++ b/src/noding/IteratedNoder.cpp @@ -47,9 +47,6 @@ IteratedNoder::node(const std::vector& segStrings, noder.setSegmentIntersector(&si); noder.computeNodes(segStrings); auto updatedSegStrings = noder.getNodedSubstrings(); - for (SegmentString* ss : nodedSegStrings) { - delete ss; - } nodedSegStrings = std::move(updatedSegStrings); numInteriorIntersections = si.numInteriorIntersections; @@ -65,14 +62,18 @@ IteratedNoder::computeNodes(const std::vector& segStrings) int numInteriorIntersections; int nodingIterationCount = 0; int lastNodesCreated = -1; - //std::vector* lastStrings = nullptr; CoordinateXY intersectionPoint = CoordinateXY::getNull(); - const std::vector* toNode = &segStrings; - do { + bool firstPass = true; + do { // NOTE: will change this.nodedSegStrings - node(*toNode, numInteriorIntersections, intersectionPoint); - toNode = &nodedSegStrings; + if (firstPass) { + node(segStrings, numInteriorIntersections, intersectionPoint); + firstPass = false; + } else { + auto nodingInput = SegmentString::toRawPointerVector(nodedSegStrings); + node(nodingInput, numInteriorIntersections, intersectionPoint); + } nodingIterationCount++; int nodesCreated = numInteriorIntersections; @@ -85,11 +86,6 @@ IteratedNoder::computeNodes(const std::vector& segStrings) && nodesCreated >= lastNodesCreated && nodingIterationCount > maxIter) { - // Delete noded strings from previous iteration - for (SegmentString* ss : nodedSegStrings) { - delete ss; - } - std::stringstream s; s << "Iterated noding failed to converge after " << nodingIterationCount << " iterations (near " << diff --git a/src/noding/NodedSegmentString.cpp b/src/noding/NodedSegmentString.cpp index 4d5fe71e8..4074d7342 100644 --- a/src/noding/NodedSegmentString.cpp +++ b/src/noding/NodedSegmentString.cpp @@ -43,16 +43,13 @@ NodedSegmentString::getNodeList() /* public static */ void NodedSegmentString::getNodedSubstrings( - const SegmentString::NonConstVect& segStrings, - SegmentString::NonConstVect* resultEdgeList) + const std::vector& segStrings, + std::vector>& resultEdgeList) { - assert(resultEdgeList); - for(SegmentString::NonConstVect::const_iterator - i = segStrings.begin(), iEnd = segStrings.end(); - i != iEnd; ++i) { - NodedSegmentString* ss = dynamic_cast(*i); - assert(ss); - ss->getNodeList().addSplitEdges(resultEdgeList); + for(SegmentString* ss : segStrings) { + NodedSegmentString* nss = dynamic_cast(ss); + assert(nss); + nss->getNodeList().addSplitEdges(resultEdgeList); } } @@ -64,12 +61,12 @@ NodedSegmentString::getNodedCoordinates() { /* public static */ -std::vector +std::vector> NodedSegmentString::getNodedSubstrings( const std::vector& segStrings) { - std::vector resultEdgelist; - getNodedSubstrings(segStrings, &resultEdgelist); + std::vector> resultEdgelist; + getNodedSubstrings(segStrings, resultEdgelist); return resultEdgelist; } diff --git a/src/noding/ScaledNoder.cpp b/src/noding/ScaledNoder.cpp index 71158db89..02192cac2 100644 --- a/src/noding/ScaledNoder.cpp +++ b/src/noding/ScaledNoder.cpp @@ -135,17 +135,11 @@ private: /*private*/ void -ScaledNoder::rescale(SegmentString::NonConstVect& segStrings) const +ScaledNoder::rescale(std::vector>& segStrings) const { ReScaler rescaler(*this); - for(SegmentString::NonConstVect::const_iterator - i0 = segStrings.begin(), i0End = segStrings.end(); - i0 != i0End; ++i0) { - - SegmentString* ss = *i0; - + for(auto& ss : segStrings) { ss->getCoordinates()->apply_rw(&rescaler); - } } @@ -188,10 +182,10 @@ ScaledNoder::~ScaledNoder() /*public*/ -SegmentString::NonConstVect +std::vector> ScaledNoder::getNodedSubstrings() { - SegmentString::NonConstVect splitSS = noder.getNodedSubstrings(); + auto splitSS = noder.getNodedSubstrings(); #if GEOS_DEBUG > 1 sqlPrint("nodedSegStr", *splitSS); diff --git a/src/noding/SegmentExtractingNoder.cpp b/src/noding/SegmentExtractingNoder.cpp index e63ce5718..0bfb095bf 100644 --- a/src/noding/SegmentExtractingNoder.cpp +++ b/src/noding/SegmentExtractingNoder.cpp @@ -39,7 +39,7 @@ SegmentExtractingNoder::computeNodes( void SegmentExtractingNoder::extractSegments( const std::vector& inputSegs, - std::vector& outputSegs) + std::vector>& outputSegs) { for (SegmentString* ss : inputSegs) { extractSegments(ss, outputSegs); @@ -52,7 +52,7 @@ SegmentExtractingNoder::extractSegments( void SegmentExtractingNoder::extractSegments( const SegmentString* ss, - std::vector& outputSegs) + std::vector>& outputSegs) { const CoordinateSequence* ss_seq = ss->getCoordinates(); @@ -65,12 +65,12 @@ SegmentExtractingNoder::extractSegments( cs->reserve(2); cs->add(*ss_seq, i, i + 1); std::unique_ptr seg(new NodedSegmentString(cs.release(), constructZ, constructM, ss->getData())); - outputSegs.push_back(seg.release()); + outputSegs.push_back(std::move(seg)); } } -std::vector +std::vector> SegmentExtractingNoder::getNodedSubstrings() { return std::move(segList); diff --git a/src/noding/SegmentNodeList.cpp b/src/noding/SegmentNodeList.cpp index 962f4a7c3..5fa6dd7dc 100644 --- a/src/noding/SegmentNodeList.cpp +++ b/src/noding/SegmentNodeList.cpp @@ -164,7 +164,7 @@ SegmentNodeList::findCollapseIndex(const SegmentNode& ei0, const SegmentNode& ei /* public */ void -SegmentNodeList::addSplitEdges(std::vector& edgeList) +SegmentNodeList::addSplitEdges(std::vector>& edgeList) { // testingOnly @@ -193,7 +193,7 @@ SegmentNodeList::addSplitEdges(std::vector& edgeList) } std::unique_ptr newEdge = createSplitEdge(eiPrev, ei); - edgeList.push_back(newEdge.release()); + edgeList.push_back(std::move(newEdge)); #if GEOS_DEBUG testingSplitEdges.push_back(edgeList.back()); #endif diff --git a/src/noding/SegmentString.cpp b/src/noding/SegmentString.cpp index 7531bfd75..b5a56c70f 100644 --- a/src/noding/SegmentString.cpp +++ b/src/noding/SegmentString.cpp @@ -53,6 +53,15 @@ SegmentString::print(std::ostream& os) const return os; } +std::vector +SegmentString::toRawPointerVector(const std::vector> & segStrings) { + std::vector ret(segStrings.size()); + for (std::size_t i = 0; i < segStrings.size(); i++) { + ret[i] = segStrings[i].get(); + } + return ret; +} + } // namespace geos.noding } // namespace geos diff --git a/src/noding/ValidatingNoder.cpp b/src/noding/ValidatingNoder.cpp index 322f9fbb3..001a8c2a2 100644 --- a/src/noding/ValidatingNoder.cpp +++ b/src/noding/ValidatingNoder.cpp @@ -14,7 +14,6 @@ #include #include -#include #include @@ -24,6 +23,7 @@ namespace geos { namespace noding { // geos.noding +ValidatingNoder::~ValidatingNoder() = default; void ValidatingNoder::computeNodes(const std::vector& segStrings) @@ -34,22 +34,18 @@ ValidatingNoder::computeNodes(const std::vector& segStrings) } void -ValidatingNoder::validate() +ValidatingNoder::validate() const { FastNodingValidator nv(nodedSS); try { nv.checkValid(); } catch (const std::exception &) { - for (SegmentString* ss: nodedSS) { - delete ss; - } - throw; } } -std::vector +std::vector> ValidatingNoder::getNodedSubstrings() { return std::move(nodedSS); diff --git a/src/noding/snap/SnappingNoder.cpp b/src/noding/snap/SnappingNoder.cpp index 701170474..614aeac7e 100644 --- a/src/noding/snap/SnappingNoder.cpp +++ b/src/noding/snap/SnappingNoder.cpp @@ -62,7 +62,7 @@ SnappingNoder::snapVertices(const std::vector& segStrings, std:: seedSnapIndex(segStrings); for (SegmentString* ss: segStrings) { - nodedStrings.push_back(snapVertices(ss)); + nodedStrings.push_back(snapVertices(ss).release()); } //sw->stop(); @@ -94,12 +94,12 @@ SnappingNoder::seedSnapIndex(const std::vector& segStrings) } /*private*/ -SegmentString* -SnappingNoder::snapVertices(SegmentString* ss) +std::unique_ptr +SnappingNoder::snapVertices(const SegmentString* ss) { auto snapCoords = snap(ss->getCoordinates()); // FIXME remove hardcoded hasZ, hasM and derive from input - return new NodedSegmentString(snapCoords.release(), false, false, ss->getData()); + return std::make_unique(snapCoords.release(), false, false, ss->getData()); } @@ -120,7 +120,7 @@ SnappingNoder::snap(const CoordinateSequence* cs) /*private*/ -std::vector +std::vector> SnappingNoder::snapIntersections(std::vector& inputSS) { SnappingIntersectionAdder intAdder(snapTolerance, snapIndex); @@ -134,7 +134,7 @@ SnappingNoder::snapIntersections(std::vector& inputSS) } /*public*/ -std::vector +std::vector> SnappingNoder::getNodedSubstrings() { return std::move(nodedResult); diff --git a/src/noding/snapround/SnapRoundingNoder.cpp b/src/noding/snapround/SnapRoundingNoder.cpp index cfaa18be0..30d7b7be5 100644 --- a/src/noding/snapround/SnapRoundingNoder.cpp +++ b/src/noding/snapround/SnapRoundingNoder.cpp @@ -36,10 +36,10 @@ namespace snapround { // geos.noding.snapround /*public*/ -std::vector +std::vector> SnapRoundingNoder::getNodedSubstrings() { - std::vector nssResult = NodedSegmentString::getNodedSubstrings(snappedResult); + auto nssResult = NodedSegmentString::getNodedSubstrings(snappedResult); // Intermediate SegmentStrings are no longer needed for (auto nss: snappedResult) diff --git a/src/operation/buffer/BufferBuilder.cpp b/src/operation/buffer/BufferBuilder.cpp index c2926b40e..1bdf09493 100644 --- a/src/operation/buffer/BufferBuilder.cpp +++ b/src/operation/buffer/BufferBuilder.cpp @@ -202,16 +202,14 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, Noder* noder = getNoder(precisionModel); noder->computeNodes(curveList); - std::vector nodedEdges = noder->getNodedSubstrings(); + auto nodedEdges = noder->getNodedSubstrings(); // Create a geometry out of the noded substrings. std::vector> singleSidedNodedEdges; singleSidedNodedEdges.reserve(nodedEdges.size()); - for(std::size_t i = 0, n = nodedEdges.size(); i < n; ++i) { - SegmentString* ss = nodedEdges[i]; - + for(auto& ss : nodedEdges) { auto tmp = geomFact->createLineString(ss->getCoordinates()->clone()); - delete ss; + ss.reset(); singleSidedNodedEdges.push_back(std::move(tmp)); } @@ -654,8 +652,7 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, noder->computeNodes(bufferSegStrList); - SegmentString::NonConstVect nodedSegStrings = \ - noder->getNodedSubstrings(); + auto nodedSegStrings = noder->getNodedSubstrings(); #if JTS_DEBUG std::cerr << "after noding: " @@ -666,15 +663,11 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, #endif - for(SegmentString::NonConstVect::iterator - i = nodedSegStrings.begin(), e = nodedSegStrings.end(); - i != e; - ++i) { - SegmentString* segStr = *i; + for(auto& segStr : nodedSegStrings) { const Label* oldLabel = static_cast(segStr->getData()); auto cs = operation::valid::RepeatedPointRemover::removeRepeatedPoints(segStr->getCoordinates()); - delete segStr; + segStr.reset(); if(cs->size() < 2) { // don't insert collapsed edges // we need to take care of the memory here as cs is a new sequence diff --git a/src/operation/overlayng/EdgeNodingBuilder.cpp b/src/operation/overlayng/EdgeNodingBuilder.cpp index c75c2057a..0800e8fcf 100644 --- a/src/operation/overlayng/EdgeNodingBuilder.cpp +++ b/src/operation/overlayng/EdgeNodingBuilder.cpp @@ -42,6 +42,13 @@ using geos::noding::SegmentString; using geos::noding::NodedSegmentString; +EdgeNodingBuilder::~EdgeNodingBuilder() +{ + for (SegmentString* ss: *inputEdges) { + delete ss; + } +} + /*private*/ Noder* EdgeNodingBuilder::getNoder() @@ -121,23 +128,18 @@ EdgeNodingBuilder::node(const std::vector& segStrings) auto nodedSS = noder->getNodedSubstrings(); - nodedEdges = createEdges(&nodedSS); - - // Clean up now that all the info is transferred to Edges - for (SegmentString* ss : nodedSS) { - delete ss; - } + nodedEdges = createEdges(nodedSS); return nodedEdges; } /*private*/ std::vector -EdgeNodingBuilder::createEdges(std::vector* segStrings) +EdgeNodingBuilder::createEdges(std::vector>& segStrings) { std::vector createdEdges; - for (SegmentString* ss : *segStrings) { + for (auto& ss : segStrings) { const CoordinateSequence* pts = ss->getCoordinates(); // don't create edges from collapsed lines @@ -148,7 +150,7 @@ EdgeNodingBuilder::createEdges(std::vector* segStrings) // Record that a non-collapsed edge exists for the parent geometry hasEdges[info->getIndex()] = true; // Allocate the new Edge locally in a std::deque - NodedSegmentString* nss = detail::down_cast(ss); + NodedSegmentString* nss = detail::down_cast(ss.get()); edgeQue.emplace_back(nss->releaseCoordinates(), info); Edge* newEdge = &(edgeQue.back()); createdEdges.push_back(newEdge); diff --git a/tests/unit/noding/NodedSegmentStringTest.cpp b/tests/unit/noding/NodedSegmentStringTest.cpp index 35100878f..26f8cc904 100644 --- a/tests/unit/noding/NodedSegmentStringTest.cpp +++ b/tests/unit/noding/NodedSegmentStringTest.cpp @@ -46,10 +46,10 @@ struct test_nodedsegmentstring_data { } std::unique_ptr - toLines(SegmentString::NonConstVect& ss, const GeometryFactory* gf) + toLines(std::vector>& ss, const GeometryFactory* gf) { std::vector> lines; - for (auto s: ss) + for (auto& s: ss) { std::unique_ptr cs = s->getCoordinates()->clone(); lines.push_back(gf->createLineString(std::move(cs))); @@ -72,13 +72,9 @@ struct test_nodedsegmentstring_data { nss.addIntersection(node->getAt(i), segmentIndex.at(i)); } - SegmentString::NonConstVect nodedSS; + std::vector> nodedSS; nss.getNodeList().addSplitEdges(nodedSS); std::unique_ptr result = toLines(nodedSS, line->getFactory()); - //System.out.println(result); - for (auto ss: nodedSS) { - delete ss; - } std::unique_ptr expected = r.read(wktExpected); ensure_equals_geometry(expected.get(), result.get()); } diff --git a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp index 4490dd95a..d9d569a69 100644 --- a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp +++ b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp @@ -137,11 +137,10 @@ void object::test<1> ensure_equals(nodable.size(), 1u); noder.computeNodes(nodable); - SegStrVct noded(noder.getNodedSubstrings()); + auto noded = noder.getNodedSubstrings(); ensure_equals("1e-5", noded.size(), 178u); - freeSegmentStrings(noded); freeSegmentStrings(nodable); } diff --git a/tests/unit/util/NodingTestUtil.cpp b/tests/unit/util/NodingTestUtil.cpp index 5fef421af..edb0b8072 100644 --- a/tests/unit/util/NodingTestUtil.cpp +++ b/tests/unit/util/NodingTestUtil.cpp @@ -92,19 +92,14 @@ NodingTestUtil::nodeValidated(const Geometry* geom1, const Geometry* geom2, Node // which creates new NodedSegmentString and new pts member, so complete // new copy of data. Can be disposed of after geometries are constructed // std::vector* nodedList = noderValid.getNodedSubstrings(); - std::vector nodedList = noderValid.getNodedSubstrings(); + auto nodedList = noderValid.getNodedSubstrings(); // Dispose of ssList for (auto ss: ssList) { delete ss; } - std::unique_ptr lineGeom = toLines(nodedList, geom1->getFactory()); - - // Dispose of nodedList - for (auto nss: nodedList) { - delete nss; - } + std::unique_ptr lineGeom = toLines(SegmentString::toRawPointerVector(nodedList), geom1->getFactory()); return lineGeom; } commit b8cb43fc5b175e23496521319742e982192e1638 Author: Daniel Baston Date: Tue Nov 11 18:59:07 2025 -0500 Noder: Accept std::vector as reference, return as value diff --git a/include/geos/noding/BoundaryChainNoder.h b/include/geos/noding/BoundaryChainNoder.h index 075168a7e..d46007497 100644 --- a/include/geos/noding/BoundaryChainNoder.h +++ b/include/geos/noding/BoundaryChainNoder.h @@ -142,8 +142,8 @@ public: {}; // Noder virtual methods - std::vector* getNodedSubstrings() const override; - void computeNodes(std::vector* inputSegStrings) override; + std::vector getNodedSubstrings() override; + void computeNodes(const std::vector& inputSegStrings) override; private: @@ -155,7 +155,7 @@ private: bool m_constructM; // Methods - void addSegments(std::vector* segStrings, + void addSegments(const std::vector& segStrings, SegmentSet& segSet, std::vector& includedSegs); diff --git a/include/geos/noding/IteratedNoder.h b/include/geos/noding/IteratedNoder.h index 3e82c8aa1..6e55ecb8a 100644 --- a/include/geos/noding/IteratedNoder.h +++ b/include/geos/noding/IteratedNoder.h @@ -57,14 +57,14 @@ private: const geom::PrecisionModel* pm; algorithm::LineIntersector li; - std::vector* nodedSegStrings; + std::vector nodedSegStrings; int maxIter; /** * Node the input segment strings once * and create the split edges between the nodes */ - void node(std::vector* segStrings, + void node(const std::vector& segStrings, int& numInteriorIntersections, geom::CoordinateXY& intersectionPoint); @@ -96,10 +96,10 @@ public: maxIter = n; } - std::vector* - getNodedSubstrings() const override + std::vector + getNodedSubstrings() override { - return nodedSegStrings; + return std::move(nodedSegStrings); } @@ -112,7 +112,7 @@ public: * @param inputSegmentStrings a collection of SegmentStrings to be noded * @throws TopologyException if the iterated noding fails to converge. */ - void computeNodes(std::vector* inputSegmentStrings) override; // throw(GEOSException); + void computeNodes(const std::vector& inputSegmentStrings) override; // throw(GEOSException); }; } // namespace geos::noding diff --git a/include/geos/noding/MCIndexNoder.h b/include/geos/noding/MCIndexNoder.h index cf810abd4..5a4965710 100644 --- a/include/geos/noding/MCIndexNoder.h +++ b/include/geos/noding/MCIndexNoder.h @@ -67,7 +67,7 @@ class GEOS_DLL MCIndexNoder : public SinglePassNoder { private: std::vector monoChains; index::strtree::TemplateSTRtree index; - std::vector* nodedSegStrings; + std::vector nodedSegStrings; // statistics int nOverlaps; double overlapTolerance; @@ -81,7 +81,6 @@ public: MCIndexNoder(SegmentIntersector* nSegInt = nullptr, double p_overlapTolerance = 0.0) : SinglePassNoder(nSegInt) - , nodedSegStrings(nullptr) , nOverlaps(0) , overlapTolerance(p_overlapTolerance) , indexBuilt(false) @@ -102,13 +101,13 @@ public: return index; } - std::vector* getNodedSubstrings() const override + std::vector getNodedSubstrings() override { - assert(nodedSegStrings); // must have called computeNodes before! - return NodedSegmentString::getNodedSubstrings(*nodedSegStrings); + //assert(nodedSegStrings); // must have called computeNodes before! + return NodedSegmentString::getNodedSubstrings(nodedSegStrings); } - void computeNodes(std::vector* inputSegmentStrings) override; + void computeNodes(const std::vector& inputSegmentStrings) override; class SegmentOverlapAction : public index::chain::MonotoneChainOverlapAction { public: diff --git a/include/geos/noding/NodedSegmentString.h b/include/geos/noding/NodedSegmentString.h index 18f6f18d3..985b8e722 100644 --- a/include/geos/noding/NodedSegmentString.h +++ b/include/geos/noding/NodedSegmentString.h @@ -82,9 +82,8 @@ public: static void getNodedSubstrings(const SegmentString::NonConstVect& segStrings, SegmentString::NonConstVect* resultEdgeList); - /// Returns allocated object - static SegmentString::NonConstVect* getNodedSubstrings( - const SegmentString::NonConstVect& segStrings); + static std::vector getNodedSubstrings( + const std::vector& segStrings); std::unique_ptr getNodedCoordinates(); diff --git a/include/geos/noding/Noder.h b/include/geos/noding/Noder.h index 768be8b02..03c490160 100644 --- a/include/geos/noding/Noder.h +++ b/include/geos/noding/Noder.h @@ -17,7 +17,6 @@ #include #include -#include // Forward declarations namespace geos { @@ -40,8 +39,6 @@ namespace noding { // geos.noding * * Last port: noding/Noder.java rev. 1.8 (JTS-1.7) * - * TODO: this was really an interface, we should avoid making it a Base class - * */ class GEOS_DLL Noder { public: @@ -55,17 +52,17 @@ public: * The caller remains responsible for releasing the memory * associated with the container and its elements. */ - virtual void computeNodes(std::vector* segStrings) = 0; + virtual void computeNodes(const std::vector& segStrings) = 0; /** \brief * Returns a collection of fully noded [SegmentStrings](@ref SegmentString). * The SegmentStrings have the same context as their parent. * - * @return a newly allocated std::vector of newly allocated - * SegmentStrings (copies of input, if needs be). - * Caller is responsible to delete container and elements. + * @return a std::vector of SegmentStrings (copies of input, if needs be). + * Caller is responsible to delete elements of container. + * This method may only be called once. */ - virtual std::vector* getNodedSubstrings() const = 0; + virtual std::vector getNodedSubstrings() = 0; virtual ~Noder() {} diff --git a/include/geos/noding/ScaledNoder.h b/include/geos/noding/ScaledNoder.h index 6ca44c680..2e0d615be 100644 --- a/include/geos/noding/ScaledNoder.h +++ b/include/geos/noding/ScaledNoder.h @@ -77,9 +77,9 @@ public: ~ScaledNoder() override; - std::vector* getNodedSubstrings() const override; + std::vector getNodedSubstrings() override; - void computeNodes(std::vector* inputSegStr) override; + void computeNodes(const std::vector& inputSegStr) override; //void filter(Coordinate& c); @@ -106,7 +106,7 @@ private: void rescale(std::vector& segStrings) const; - void scale(std::vector& segStrings) const; + void scale(const std::vector& segStrings) const; class Scaler; diff --git a/include/geos/noding/SegmentExtractingNoder.h b/include/geos/noding/SegmentExtractingNoder.h index 6a7277166..5f4f29d15 100644 --- a/include/geos/noding/SegmentExtractingNoder.h +++ b/include/geos/noding/SegmentExtractingNoder.h @@ -53,7 +53,7 @@ class GEOS_DLL SegmentExtractingNoder : public Noder { private: - std::vector* segList; + std::vector segList; void extractSegments( const std::vector& inputSegs, @@ -69,16 +69,15 @@ public: /** * Creates a new segment-extracting noder. */ - SegmentExtractingNoder() : segList(nullptr) - {}; + SegmentExtractingNoder() = default; - void computeNodes(std::vector* segStrings) override; + void computeNodes(const std::vector& segStrings) override; /** * @return a Collection of SegmentString representing the * substrings. Caller takes ownership over vector and contents. */ - std::vector* getNodedSubstrings() const override; + std::vector getNodedSubstrings() override; }; diff --git a/include/geos/noding/SimpleNoder.h b/include/geos/noding/SimpleNoder.h index bbe6b5420..b2bf4f70c 100644 --- a/include/geos/noding/SimpleNoder.h +++ b/include/geos/noding/SimpleNoder.h @@ -47,7 +47,7 @@ namespace noding { // geos.noding */ class GEOS_DLL SimpleNoder: public SinglePassNoder { private: - std::vector* nodedSegStrings; + std::vector nodedSegStrings; virtual void computeIntersects(SegmentString* e0, SegmentString* e1); public: @@ -56,12 +56,12 @@ public: SinglePassNoder(nSegInt) {} - void computeNodes(std::vector* inputSegmentStrings) override; + void computeNodes(const std::vector& inputSegmentStrings) override; - std::vector* - getNodedSubstrings() const override + std::vector + getNodedSubstrings() override { - return NodedSegmentString::getNodedSubstrings(*nodedSegStrings); + return NodedSegmentString::getNodedSubstrings(nodedSegStrings); } }; diff --git a/include/geos/noding/SinglePassNoder.h b/include/geos/noding/SinglePassNoder.h index 412c19b0f..1c2de5613 100644 --- a/include/geos/noding/SinglePassNoder.h +++ b/include/geos/noding/SinglePassNoder.h @@ -79,7 +79,7 @@ public: * * @param segStrings a collection of {@link SegmentString}s to node */ - void computeNodes(std::vector* segStrings) override = 0; + void computeNodes(const std::vector& segStrings) override = 0; /** \brief * Returns a Collection of fully noded {@link SegmentString}s. @@ -88,7 +88,7 @@ public: * * @return a Collection of SegmentStrings */ - std::vector* getNodedSubstrings() const override = 0; + std::vector getNodedSubstrings() override = 0; }; diff --git a/include/geos/noding/ValidatingNoder.h b/include/geos/noding/ValidatingNoder.h index ce45c74cf..e6a3af6a2 100644 --- a/include/geos/noding/ValidatingNoder.h +++ b/include/geos/noding/ValidatingNoder.h @@ -51,7 +51,7 @@ class GEOS_DLL ValidatingNoder : public Noder { private: - std::vector* nodedSS; + std::vector nodedSS; noding::Noder& noder; @@ -61,11 +61,11 @@ public: : noder(noderArg) {} - void computeNodes(std::vector* segStrings) override; + void computeNodes(const std::vector& segStrings) override; void validate(); - std::vector* getNodedSubstrings() const override; + std::vector getNodedSubstrings() override; }; diff --git a/include/geos/noding/snap/SnappingNoder.h b/include/geos/noding/snap/SnappingNoder.h index 40f057a44..8381f13bd 100644 --- a/include/geos/noding/snap/SnappingNoder.h +++ b/include/geos/noding/snap/SnappingNoder.h @@ -71,13 +71,13 @@ private: // Members double snapTolerance; SnappingPointIndex snapIndex; - std::vector* nodedResult; + std::vector nodedResult; // Methods - void seedSnapIndex(std::vector& segStrings); + void seedSnapIndex(const std::vector& segStrings); - void snapVertices(std::vector& segStrings, std::vector& nodedStrings); + void snapVertices(const std::vector& segStrings, std::vector& nodedStrings); SegmentString* snapVertices(SegmentString* ss); @@ -91,7 +91,7 @@ private: * * @return a list of Coordinates for the intersections */ - std::unique_ptr> snapIntersections(std::vector& inputSS); + std::vector snapIntersections(std::vector& inputSS); public: @@ -108,9 +108,9 @@ public: /** * @return a Collection of NodedSegmentStrings representing the substrings */ - std::vector* getNodedSubstrings() const override; + std::vector getNodedSubstrings() override; - void computeNodes(std::vector* inputSegStrings) override; + void computeNodes(const std::vector& inputSegStrings) override; }; diff --git a/include/geos/noding/snapround/MCIndexSnapRounder.h b/include/geos/noding/snapround/MCIndexSnapRounder.h index 70305f1d5..ba1ad2db7 100644 --- a/include/geos/noding/snapround/MCIndexSnapRounder.h +++ b/include/geos/noding/snapround/MCIndexSnapRounder.h @@ -83,13 +83,13 @@ public: li.setPrecisionModel(&pm); } - std::vector* - getNodedSubstrings() const override + std::vector + getNodedSubstrings() override { - return NodedSegmentString::getNodedSubstrings(*nodedSegStrings); + return NodedSegmentString::getNodedSubstrings(nodedSegStrings); } - void computeNodes(std::vector* segStrings) override; + void computeNodes(const std::vector& segStrings) override; /** * Computes nodes introduced as a result of @@ -99,7 +99,7 @@ public: * NOTE: they *must* be instances of NodedSegmentString, or * an assertion will fail. */ - void computeVertexSnaps(std::vector& edges); + void computeVertexSnaps(const std::vector& edges); private: @@ -110,11 +110,11 @@ private: double scaleFactor; - std::vector* nodedSegStrings; + std::vector nodedSegStrings; std::unique_ptr pointSnapper; - void snapRound(MCIndexNoder& noder, std::vector* segStrings); + void snapRound(MCIndexNoder& noder, const std::vector& segStrings); /** @@ -125,7 +125,7 @@ private: * */ void findInteriorIntersections(MCIndexNoder& noder, - std::vector* segStrings, + const std::vector& segStrings, std::vector& intersections); /** diff --git a/include/geos/noding/snapround/SnapRoundingNoder.h b/include/geos/noding/snapround/SnapRoundingNoder.h index 78dc8c708..528c63df8 100644 --- a/include/geos/noding/snapround/SnapRoundingNoder.h +++ b/include/geos/noding/snapround/SnapRoundingNoder.h @@ -83,7 +83,7 @@ private: std::vector snappedResult; // Methods - void snapRound(std::vector& inputSegStrings, std::vector& resultNodedSegments); + void snapRound(const std::vector& inputSegStrings, std::vector& resultNodedSegments); /** * Creates HotPixels for each vertex in the input segStrings. @@ -92,14 +92,14 @@ private: * if they interact with other segments (or they are already * created as intersection nodes). */ - void addVertexPixels(std::vector& segStrings); + void addVertexPixels(const std::vector& segStrings); /** * Detects interior intersections in the collection of {@link SegmentString}s, * and adds nodes for them to the segment strings. * Also creates HotPixel nodes for the intersection points. */ - void addIntersectionPixels(std::vector& segStrings); + void addIntersectionPixels(const std::vector& segStrings); /** * Gets a list of the rounded coordinates. @@ -148,13 +148,13 @@ public: /** * @return a Collection of NodedSegmentStrings representing the substrings */ - std::vector* getNodedSubstrings() const override; + std::vector getNodedSubstrings() override; /** * Computes the nodes in the snap-rounding line arrangement. * The nodes are added to the {@link NodedSegmentString}s provided as the input. */ - void computeNodes(std::vector* inputSegStrings) override; //override + void computeNodes(const std::vector& inputSegStrings) override; //override }; diff --git a/include/geos/operation/overlayng/EdgeNodingBuilder.h b/include/geos/operation/overlayng/EdgeNodingBuilder.h index 9d2195b35..8130c1aa1 100644 --- a/include/geos/operation/overlayng/EdgeNodingBuilder.h +++ b/include/geos/operation/overlayng/EdgeNodingBuilder.h @@ -177,7 +177,7 @@ private: * which is used to provide source topology info to the constructed Edges * (and is then discarded). */ - std::vector node(std::vector* segStrings); + std::vector node(const std::vector& segStrings); std::vector createEdges(std::vector* segStrings); diff --git a/src/coverage/CoverageCleaner.cpp b/src/coverage/CoverageCleaner.cpp index 80c044eb9..88e30c872 100644 --- a/src/coverage/CoverageCleaner.cpp +++ b/src/coverage/CoverageCleaner.cpp @@ -419,14 +419,14 @@ CoverageCleaner::node(std::vector& p_coverage, double p_snapDis } SnappingNoder noder(p_snapDistance); - noder.computeNodes(&segs); - std::unique_ptr> nodedSegStrings(noder.getNodedSubstrings()); + noder.computeNodes(segs); + auto nodedSegStrings= noder.getNodedSubstrings(); for (auto* ss : segs) { delete ss; } - auto result = toGeometry(*nodedSegStrings, geomFactory); - for (SegmentString* ss : *nodedSegStrings) { + auto result = toGeometry(nodedSegStrings, geomFactory); + for (SegmentString* ss : nodedSegStrings) { delete ss; } diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index 6f07bd9e2..8a7637c08 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -29,11 +29,11 @@ namespace noding { // geos::noding /* public */ void -BoundaryChainNoder::computeNodes(std::vector* segStrings) +BoundaryChainNoder::computeNodes(const std::vector& segStrings) { SegmentSet boundarySegSet; std::vector boundaryChains; - boundaryChains.reserve(segStrings->size()); + boundaryChains.reserve(segStrings.size()); addSegments(segStrings, boundarySegSet, boundaryChains); markBoundarySegments(boundarySegSet); m_chainList = extractChains(boundaryChains); @@ -134,20 +134,20 @@ BoundaryChainNoder::findNodeIndex( /* public */ -std::vector* -BoundaryChainNoder::getNodedSubstrings() const +std::vector +BoundaryChainNoder::getNodedSubstrings() { - return new std::vector(std::move(m_chainList)); + return std::move(m_chainList); } /* private */ void BoundaryChainNoder::addSegments( - std::vector* segStrings, + const std::vector& segStrings, SegmentSet& segSet, std::vector& boundaryChains) { - for (SegmentString* ss : *segStrings) { + for (SegmentString* ss : segStrings) { m_constructZ |= ss->getCoordinates()->hasZ(); m_constructM |= ss->getCoordinates()->hasM(); diff --git a/src/noding/FastNodingValidator.cpp b/src/noding/FastNodingValidator.cpp index 425cde083..ba5a7caad 100644 --- a/src/noding/FastNodingValidator.cpp +++ b/src/noding/FastNodingValidator.cpp @@ -37,7 +37,7 @@ FastNodingValidator::checkInteriorIntersections() segInt.reset(new NodingIntersectionFinder(li)); MCIndexNoder noder; noder.setSegmentIntersector(segInt.get()); - noder.computeNodes(&segStrings); + noder.computeNodes(segStrings); if(segInt->hasIntersection()) { isValidVar = false; return; diff --git a/src/noding/GeometryNoder.cpp b/src/noding/GeometryNoder.cpp index 71ad91ea9..b552e7f47 100644 --- a/src/noding/GeometryNoder.cpp +++ b/src/noding/GeometryNoder.cpp @@ -123,17 +123,17 @@ GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges) std::unique_ptr GeometryNoder::getNoded() { - SegmentString::NonConstVect p_lineList; if (argGeom.isEmpty()) return argGeom.clone(); + std::vector p_lineList; extractSegmentStrings(argGeom, p_lineList); Noder& p_noder = getNoder(); - SegmentString::NonConstVect* nodedEdges = nullptr; + std::vector nodedEdges; try { - p_noder.computeNodes(&p_lineList); + p_noder.computeNodes(p_lineList); nodedEdges = p_noder.getNodedSubstrings(); } catch(const std::exception&) { @@ -143,12 +143,11 @@ GeometryNoder::getNoded() throw; } - std::unique_ptr noded = toGeometry(*nodedEdges); + std::unique_ptr noded = toGeometry(nodedEdges); - for(auto* elem : (*nodedEdges)) { + for(auto* elem : nodedEdges) { delete elem; } - delete nodedEdges; for(auto* elem : p_lineList) { delete elem; diff --git a/src/noding/IteratedNoder.cpp b/src/noding/IteratedNoder.cpp index e2ac4f2af..62e893287 100644 --- a/src/noding/IteratedNoder.cpp +++ b/src/noding/IteratedNoder.cpp @@ -38,7 +38,7 @@ namespace noding { // geos.noding /* private */ void -IteratedNoder::node(std::vector* segStrings, +IteratedNoder::node(const std::vector& segStrings, int& numInteriorIntersections, CoordinateXY& intersectionPoint) { @@ -46,7 +46,11 @@ IteratedNoder::node(std::vector* segStrings, MCIndexNoder noder; noder.setSegmentIntersector(&si); noder.computeNodes(segStrings); - nodedSegStrings = noder.getNodedSubstrings(); + auto updatedSegStrings = noder.getNodedSubstrings(); + for (SegmentString* ss : nodedSegStrings) { + delete ss; + } + nodedSegStrings = std::move(updatedSegStrings); numInteriorIntersections = si.numInteriorIntersections; if (si.hasProperInteriorIntersection()) { @@ -56,28 +60,19 @@ IteratedNoder::node(std::vector* segStrings, /* public */ void -IteratedNoder::computeNodes(SegmentString::NonConstVect* segStrings) -// throw(GEOSException); +IteratedNoder::computeNodes(const std::vector& segStrings) { int numInteriorIntersections; - nodedSegStrings = segStrings; int nodingIterationCount = 0; int lastNodesCreated = -1; - std::vector* lastStrings = nullptr; + //std::vector* lastStrings = nullptr; CoordinateXY intersectionPoint = CoordinateXY::getNull(); + const std::vector* toNode = &segStrings; do { // NOTE: will change this.nodedSegStrings - node(nodedSegStrings, numInteriorIntersections, intersectionPoint); - - // Delete noded strings from previous iteration - if(lastStrings) { - for(auto& s : *lastStrings) { - delete s; - } - delete lastStrings; - } - lastStrings = nodedSegStrings; + node(*toNode, numInteriorIntersections, intersectionPoint); + toNode = &nodedSegStrings; nodingIterationCount++; int nodesCreated = numInteriorIntersections; @@ -86,17 +81,13 @@ IteratedNoder::computeNodes(SegmentString::NonConstVect* segStrings) * Fail if the number of nodes created is not declining. * However, allow a few iterations at least before doing this */ - //cerr<<"# nodes created: "< 0 && nodesCreated >= lastNodesCreated && nodingIterationCount > maxIter) { // Delete noded strings from previous iteration - if(lastStrings) { - for(auto& s : *lastStrings) { - delete s; - } - delete lastStrings; + for (SegmentString* ss : nodedSegStrings) { + delete ss; } std::stringstream s; diff --git a/src/noding/MCIndexNoder.cpp b/src/noding/MCIndexNoder.cpp index 6cdd9a45b..556738ff4 100644 --- a/src/noding/MCIndexNoder.cpp +++ b/src/noding/MCIndexNoder.cpp @@ -40,12 +40,11 @@ namespace noding { // geos.noding /*public*/ void -MCIndexNoder::computeNodes(SegmentString::NonConstVect* inputSegStrings) +MCIndexNoder::computeNodes(const std::vector& inputSegStrings) { nodedSegStrings = inputSegStrings; - assert(nodedSegStrings); - for (const auto& s : *nodedSegStrings) { + for (const auto& s : nodedSegStrings) { add(s); } diff --git a/src/noding/NodedSegmentString.cpp b/src/noding/NodedSegmentString.cpp index b2ca546a3..4d5fe71e8 100644 --- a/src/noding/NodedSegmentString.cpp +++ b/src/noding/NodedSegmentString.cpp @@ -64,13 +64,12 @@ NodedSegmentString::getNodedCoordinates() { /* public static */ -SegmentString::NonConstVect* +std::vector NodedSegmentString::getNodedSubstrings( - const SegmentString::NonConstVect& segStrings) + const std::vector& segStrings) { - SegmentString::NonConstVect* resultEdgelist = \ - new SegmentString::NonConstVect(); - getNodedSubstrings(segStrings, resultEdgelist); + std::vector resultEdgelist; + getNodedSubstrings(segStrings, &resultEdgelist); return resultEdgelist; } diff --git a/src/noding/ScaledNoder.cpp b/src/noding/ScaledNoder.cpp index f345362e9..71158db89 100644 --- a/src/noding/ScaledNoder.cpp +++ b/src/noding/ScaledNoder.cpp @@ -152,7 +152,7 @@ ScaledNoder::rescale(SegmentString::NonConstVect& segStrings) const /*private*/ void -ScaledNoder::scale(SegmentString::NonConstVect& segStrings) const +ScaledNoder::scale(const SegmentString::NonConstVect& segStrings) const { Scaler scaler(*this); for(std::size_t i = 0; i < segStrings.size(); i++) { @@ -170,7 +170,7 @@ ScaledNoder::scale(SegmentString::NonConstVect& segStrings) const // FIXME remove hardcoded hasZ, hasM and derive from input if (rpt.hasRepeatedPoint(cs)) { auto cs2 = operation::valid::RepeatedPointRemover::removeRepeatedPoints(cs); - segStrings[i] = new NodedSegmentString(cs2.release(), true, false, ss->getData()); + const_cast&>(segStrings)[i] = new NodedSegmentString(cs2.release(), true, false, ss->getData()); delete ss; } } @@ -188,17 +188,17 @@ ScaledNoder::~ScaledNoder() /*public*/ -SegmentString::NonConstVect* -ScaledNoder::getNodedSubstrings() const +SegmentString::NonConstVect +ScaledNoder::getNodedSubstrings() { - SegmentString::NonConstVect* splitSS = noder.getNodedSubstrings(); + SegmentString::NonConstVect splitSS = noder.getNodedSubstrings(); #if GEOS_DEBUG > 1 sqlPrint("nodedSegStr", *splitSS); #endif if(isScaled) { - rescale(*splitSS); + rescale(splitSS); } #if GEOS_DEBUG > 1 @@ -211,7 +211,7 @@ ScaledNoder::getNodedSubstrings() const /*public*/ void -ScaledNoder::computeNodes(SegmentString::NonConstVect* inputSegStr) +ScaledNoder::computeNodes(const SegmentString::NonConstVect& inputSegStr) { #if GEOS_DEBUG > 1 @@ -219,7 +219,7 @@ ScaledNoder::computeNodes(SegmentString::NonConstVect* inputSegStr) #endif if(isScaled) { - scale(*inputSegStr); + scale(inputSegStr); } #if GEOS_DEBUG > 1 diff --git a/src/noding/SegmentExtractingNoder.cpp b/src/noding/SegmentExtractingNoder.cpp index de0548b1d..e63ce5718 100644 --- a/src/noding/SegmentExtractingNoder.cpp +++ b/src/noding/SegmentExtractingNoder.cpp @@ -29,10 +29,9 @@ namespace noding { // geos.noding /* public */ void SegmentExtractingNoder::computeNodes( - std::vector* segStrings) + const std::vector& segStrings) { - segList = new std::vector; - extractSegments(*segStrings, *segList); + extractSegments(segStrings, segList); } @@ -71,10 +70,10 @@ SegmentExtractingNoder::extractSegments( } -std::vector* -SegmentExtractingNoder::getNodedSubstrings() const +std::vector +SegmentExtractingNoder::getNodedSubstrings() { - return segList; + return std::move(segList); } diff --git a/src/noding/SimpleNoder.cpp b/src/noding/SimpleNoder.cpp index d4a6dd0f6..8f5ea1d9e 100644 --- a/src/noding/SimpleNoder.cpp +++ b/src/noding/SimpleNoder.cpp @@ -45,12 +45,12 @@ SimpleNoder::computeIntersects(SegmentString* e0, SegmentString* e1) /*public*/ void -SimpleNoder::computeNodes(SegmentString::NonConstVect* inputSegmentStrings) +SimpleNoder::computeNodes(const std::vector& inputSegmentStrings) { nodedSegStrings = inputSegmentStrings; - for (SegmentString* edge0: *inputSegmentStrings) { - for (SegmentString* edge1: *inputSegmentStrings) { + for (SegmentString* edge0: inputSegmentStrings) { + for (SegmentString* edge1: inputSegmentStrings) { computeIntersects(edge0, edge1); } } diff --git a/src/noding/ValidatingNoder.cpp b/src/noding/ValidatingNoder.cpp index 171878a18..322f9fbb3 100644 --- a/src/noding/ValidatingNoder.cpp +++ b/src/noding/ValidatingNoder.cpp @@ -26,7 +26,7 @@ namespace noding { // geos.noding void -ValidatingNoder::computeNodes(std::vector* segStrings) +ValidatingNoder::computeNodes(const std::vector& segStrings) { noder.computeNodes(segStrings); nodedSS = noder.getNodedSubstrings(); @@ -36,24 +36,23 @@ ValidatingNoder::computeNodes(std::vector* segStrings) void ValidatingNoder::validate() { - FastNodingValidator nv(*nodedSS); + FastNodingValidator nv(nodedSS); try { nv.checkValid(); } catch (const std::exception &) { - for (SegmentString* ss: *nodedSS) { + for (SegmentString* ss: nodedSS) { delete ss; } - delete nodedSS; - nodedSS = nullptr; + throw; } } -std::vector* -ValidatingNoder::getNodedSubstrings() const +std::vector +ValidatingNoder::getNodedSubstrings() { - return nodedSS; + return std::move(nodedSS); } diff --git a/src/noding/snap/SnappingNoder.cpp b/src/noding/snap/SnappingNoder.cpp index 616bec84b..701170474 100644 --- a/src/noding/snap/SnappingNoder.cpp +++ b/src/noding/snap/SnappingNoder.cpp @@ -40,21 +40,21 @@ namespace snap { // geos.noding.snap /*public*/ void -SnappingNoder::computeNodes(std::vector* inputSegStrings) +SnappingNoder::computeNodes(const std::vector& inputSegStrings) { std::vector snappedSS; - snapVertices(*inputSegStrings, snappedSS); + snapVertices(inputSegStrings, snappedSS); auto result = snapIntersections(snappedSS); for (SegmentString* ss: snappedSS) { delete ss; } - nodedResult = result.release(); + nodedResult = std::move(result); } /*private*/ void -SnappingNoder::snapVertices(std::vector& segStrings, std::vector& nodedStrings) +SnappingNoder::snapVertices(const std::vector& segStrings, std::vector& nodedStrings) { //geos::util::Profiler* profiler = geos::util::Profiler::instance(); //auto sw = profiler->get(std::string("SnappingNoder::snapVertices")); @@ -72,7 +72,7 @@ SnappingNoder::snapVertices(std::vector& segStrings, std::vector /*private*/ void -SnappingNoder::seedSnapIndex(std::vector& segStrings) +SnappingNoder::seedSnapIndex(const std::vector& segStrings) { double PHI_INV = (std::sqrt(5.0) - 1.0) / 2.0; @@ -120,7 +120,7 @@ SnappingNoder::snap(const CoordinateSequence* cs) /*private*/ -std::unique_ptr> +std::vector SnappingNoder::snapIntersections(std::vector& inputSS) { SnappingIntersectionAdder intAdder(snapTolerance, snapIndex); @@ -129,16 +129,15 @@ SnappingNoder::snapIntersections(std::vector& inputSS) * possible snapped intersections are found */ MCIndexNoder noder(&intAdder, 2 * snapTolerance); - noder.computeNodes(&inputSS); - std::unique_ptr> result(noder.getNodedSubstrings()); - return result; + noder.computeNodes(inputSS); + return noder.getNodedSubstrings(); } /*public*/ -std::vector* -SnappingNoder::getNodedSubstrings() const +std::vector +SnappingNoder::getNodedSubstrings() { - return nodedResult; + return std::move(nodedResult); } diff --git a/src/noding/snapround/MCIndexSnapRounder.cpp b/src/noding/snapround/MCIndexSnapRounder.cpp index eb81819b9..d76152ffb 100644 --- a/src/noding/snapround/MCIndexSnapRounder.cpp +++ b/src/noding/snapround/MCIndexSnapRounder.cpp @@ -37,7 +37,7 @@ namespace snapround { // geos.noding.snapround /*private*/ void MCIndexSnapRounder::findInteriorIntersections(MCIndexNoder& noder, - NodedSegmentString::NonConstVect* segStrings, + const NodedSegmentString::NonConstVect& segStrings, std::vector& intersections) { IntersectionFinderAdder intFinderAdder(li, intersections); @@ -73,12 +73,11 @@ MCIndexSnapRounder::computeVertexSnaps(NodedSegmentString* e) /*public*/ void -MCIndexSnapRounder::computeVertexSnaps(SegmentString::NonConstVect& edges) +MCIndexSnapRounder::computeVertexSnaps(const SegmentString::NonConstVect& edges) { - SegmentString::NonConstVect::iterator i = edges.begin(), e = edges.end(); - for(; i != e; ++i) { + for(SegmentString* ss : edges) { NodedSegmentString* edge0 = - dynamic_cast(*i); + dynamic_cast(ss); assert(edge0); computeVertexSnaps(edge0); } @@ -87,18 +86,18 @@ MCIndexSnapRounder::computeVertexSnaps(SegmentString::NonConstVect& edges) /*private*/ void MCIndexSnapRounder::snapRound(MCIndexNoder& noder, - SegmentString::NonConstVect* segStrings) + const SegmentString::NonConstVect& segStrings) { std::vector intersections; findInteriorIntersections(noder, segStrings, intersections); computeIntersectionSnaps(intersections); - computeVertexSnaps(*segStrings); + computeVertexSnaps(segStrings); } /*public*/ void -MCIndexSnapRounder::computeNodes(SegmentString::NonConstVect* inputSegmentStrings) +MCIndexSnapRounder::computeNodes(const std::vector& inputSegmentStrings) { nodedSegStrings = inputSegmentStrings; MCIndexNoder noder; @@ -116,11 +115,9 @@ void MCIndexSnapRounder::checkCorrectness( SegmentString::NonConstVect& inputSegmentStrings) { - std::unique_ptr resultSegStrings( - NodedSegmentString::getNodedSubstrings(inputSegmentStrings) - ); + auto resultSegStrings = NodedSegmentString::getNodedSubstrings(inputSegmentStrings); - NodingValidator nv(*resultSegStrings); + NodingValidator nv(resultSegStrings); try { nv.checkValid(); } diff --git a/src/noding/snapround/SnapRoundingNoder.cpp b/src/noding/snapround/SnapRoundingNoder.cpp index 3817cd729..cfaa18be0 100644 --- a/src/noding/snapround/SnapRoundingNoder.cpp +++ b/src/noding/snapround/SnapRoundingNoder.cpp @@ -36,10 +36,10 @@ namespace snapround { // geos.noding.snapround /*public*/ -std::vector* -SnapRoundingNoder::getNodedSubstrings() const +std::vector +SnapRoundingNoder::getNodedSubstrings() { - std::vector* nssResult = NodedSegmentString::getNodedSubstrings(snappedResult); + std::vector nssResult = NodedSegmentString::getNodedSubstrings(snappedResult); // Intermediate SegmentStrings are no longer needed for (auto nss: snappedResult) @@ -50,15 +50,14 @@ SnapRoundingNoder::getNodedSubstrings() const /*public*/ void -SnapRoundingNoder::computeNodes(std::vector* inputSegStrings) +SnapRoundingNoder::computeNodes(const std::vector& inputSegStrings) { - snapRound(*inputSegStrings, snappedResult); - return; + snapRound(inputSegStrings, snappedResult); } /*private*/ void -SnapRoundingNoder::snapRound(std::vector& inputSegStrings, std::vector& resultNodedSegments) +SnapRoundingNoder::snapRound(const std::vector& inputSegStrings, std::vector& resultNodedSegments) { /** * Determine hot pixels for intersections and vertices. @@ -75,19 +74,19 @@ SnapRoundingNoder::snapRound(std::vector& inputSegStrings, std:: /*private*/ void -SnapRoundingNoder::addIntersectionPixels(std::vector& segStrings) +SnapRoundingNoder::addIntersectionPixels(const std::vector& segStrings) { double tolerance = 1.0 / pm->getScale() / INTERSECTION_NEARNESS_FACTOR; SnapRoundingIntersectionAdder intAdder(tolerance); MCIndexNoder noder(&intAdder, tolerance); - noder.computeNodes(&segStrings); + noder.computeNodes(segStrings); const auto& intPts = intAdder.getIntersections(); pixelIndex.addNodes(&intPts); } /*private void*/ void -SnapRoundingNoder::addVertexPixels(std::vector& segStrings) +SnapRoundingNoder::addVertexPixels(const std::vector& segStrings) { for (SegmentString* nss : segStrings) { const CoordinateSequence* pts = nss->getCoordinates(); diff --git a/src/operation/buffer/BufferBuilder.cpp b/src/operation/buffer/BufferBuilder.cpp index 5cc5685d2..c2926b40e 100644 --- a/src/operation/buffer/BufferBuilder.cpp +++ b/src/operation/buffer/BufferBuilder.cpp @@ -200,15 +200,15 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, // Node these SegmentStrings. Noder* noder = getNoder(precisionModel); - noder->computeNodes(&curveList); + noder->computeNodes(curveList); - SegmentString::NonConstVect* nodedEdges = noder->getNodedSubstrings(); + std::vector nodedEdges = noder->getNodedSubstrings(); // Create a geometry out of the noded substrings. std::vector> singleSidedNodedEdges; - singleSidedNodedEdges.reserve(nodedEdges->size()); - for(std::size_t i = 0, n = nodedEdges->size(); i < n; ++i) { - SegmentString* ss = (*nodedEdges)[i]; + singleSidedNodedEdges.reserve(nodedEdges.size()); + for(std::size_t i = 0, n = nodedEdges.size(); i < n; ++i) { + SegmentString* ss = nodedEdges[i]; auto tmp = geomFact->createLineString(ss->getCoordinates()->clone()); delete ss; @@ -216,8 +216,6 @@ BufferBuilder::bufferLineSingleSided(const Geometry* g, double distance, singleSidedNodedEdges.push_back(std::move(tmp)); } - delete nodedEdges; - for(std::size_t i = 0, n = curveList.size(); i < n; ++i) { delete curveList[i]; } @@ -654,9 +652,9 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, ) << std::endl; #endif - noder->computeNodes(&bufferSegStrList); + noder->computeNodes(bufferSegStrList); - SegmentString::NonConstVect* nodedSegStrings = \ + SegmentString::NonConstVect nodedSegStrings = \ noder->getNodedSubstrings(); #if JTS_DEBUG @@ -669,7 +667,7 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, for(SegmentString::NonConstVect::iterator - i = nodedSegStrings->begin(), e = nodedSegStrings->end(); + i = nodedSegStrings.begin(), e = nodedSegStrings.end(); i != e; ++i) { SegmentString* segStr = *i; @@ -690,8 +688,6 @@ BufferBuilder::computeNodedEdges(SegmentString::NonConstVect& bufferSegStrList, insertUniqueEdge(edge); } - delete nodedSegStrings; - if(noder != workingNoder) { delete noder; } diff --git a/src/operation/overlayng/EdgeNodingBuilder.cpp b/src/operation/overlayng/EdgeNodingBuilder.cpp index 569633462..c75c2057a 100644 --- a/src/operation/overlayng/EdgeNodingBuilder.cpp +++ b/src/operation/overlayng/EdgeNodingBuilder.cpp @@ -101,7 +101,7 @@ EdgeNodingBuilder::build(const Geometry* geom0, const Geometry* geom1) add(geom0, 0); add(geom1, 1); - std::vector nodedEdges = node(inputEdges.get()); + std::vector nodedEdges = node(*inputEdges); /** * Merge the noded edges to eliminate duplicates. @@ -112,19 +112,19 @@ EdgeNodingBuilder::build(const Geometry* geom0, const Geometry* geom1) /*private*/ std::vector -EdgeNodingBuilder::node(std::vector* segStrings) +EdgeNodingBuilder::node(const std::vector& segStrings) { std::vector nodedEdges; Noder* noder = getNoder(); noder->computeNodes(segStrings); - std::unique_ptr> nodedSS(noder->getNodedSubstrings()); + auto nodedSS = noder->getNodedSubstrings(); - nodedEdges = createEdges(nodedSS.get()); + nodedEdges = createEdges(&nodedSS); // Clean up now that all the info is transferred to Edges - for (SegmentString* ss : *nodedSS) { + for (SegmentString* ss : nodedSS) { delete ss; } diff --git a/src/operation/valid/IsSimpleOp.cpp b/src/operation/valid/IsSimpleOp.cpp index 065cd18d8..2a5d136f8 100644 --- a/src/operation/valid/IsSimpleOp.cpp +++ b/src/operation/valid/IsSimpleOp.cpp @@ -216,7 +216,7 @@ IsSimpleOp::isSimpleLinearGeometry(const Geometry& geom) NonSimpleIntersectionFinder segInt(isClosedEndpointsInInterior, isFindAllLocations, nonSimplePts); MCIndexNoder noder; noder.setSegmentIntersector(&segInt); - noder.computeNodes(&segStringsBare); + noder.computeNodes(segStringsBare); if (segInt.hasIntersection()) { return false; } diff --git a/src/operation/valid/PolygonTopologyAnalyzer.cpp b/src/operation/valid/PolygonTopologyAnalyzer.cpp index c2b9d0a39..121d4f5ce 100644 --- a/src/operation/valid/PolygonTopologyAnalyzer.cpp +++ b/src/operation/valid/PolygonTopologyAnalyzer.cpp @@ -54,7 +54,7 @@ PolygonTopologyAnalyzer::PolygonTopologyAnalyzer(const Geometry* geom, bool p_is // Code copied in from analyzeIntersections() noding::MCIndexNoder noder; noder.setSegmentIntersector(&segInt); - noder.computeNodes(&segStrings); + noder.computeNodes(segStrings); if (segInt.hasDoubleTouch()) { disconnectionPt = segInt.getDoubleTouchLocation(); } diff --git a/src/triangulate/polygon/PolygonNoder.cpp b/src/triangulate/polygon/PolygonNoder.cpp index 8e6a70ad9..08462469e 100644 --- a/src/triangulate/polygon/PolygonNoder.cpp +++ b/src/triangulate/polygon/PolygonNoder.cpp @@ -130,7 +130,7 @@ PolygonNoder::node() for (auto& nss : nodedRings) { bareNodedRings.push_back(nss.get()); } - noder.computeNodes(&bareNodedRings); + noder.computeNodes(bareNodedRings); } /* public */ diff --git a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp index 11d760c55..4490dd95a 100644 --- a/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp +++ b/tests/unit/noding/snapround/MCIndexSnapRounderTest.cpp @@ -136,12 +136,12 @@ void object::test<1> MCIndexSnapRounder noder(pm); ensure_equals(nodable.size(), 1u); - noder.computeNodes(&nodable); - std::unique_ptr noded(noder.getNodedSubstrings()); + noder.computeNodes(nodable); + SegStrVct noded(noder.getNodedSubstrings()); - ensure_equals("1e-5", noded->size(), 178u); + ensure_equals("1e-5", noded.size(), 178u); - freeSegmentStrings(*noded); + freeSegmentStrings(noded); freeSegmentStrings(nodable); } diff --git a/tests/unit/util/NodingTestUtil.cpp b/tests/unit/util/NodingTestUtil.cpp index 21fa5e59a..5fef421af 100644 --- a/tests/unit/util/NodingTestUtil.cpp +++ b/tests/unit/util/NodingTestUtil.cpp @@ -26,11 +26,11 @@ namespace geos { /*private static*/ std::unique_ptr -NodingTestUtil::toLines(const std::vector* nodedList, const GeometryFactory* geomFact) +NodingTestUtil::toLines(const std::vector& nodedList, const GeometryFactory* geomFact) { std::vector> lines; - for (auto nss : *nodedList) { + for (auto nss : nodedList) { CoordinateSequence* pts = nss->getCoordinates(); // pts is owned by nss, so we make a copy to build the line // on top of. Lines are 100% self-contained and own all their parts. @@ -86,13 +86,13 @@ NodingTestUtil::nodeValidated(const Geometry* geom1, const Geometry* geom2, Node ValidatingNoder noderValid(*noder); // computeNotes might alter ssList, but ssList still // holds all memory - noderValid.computeNodes(&ssList); + noderValid.computeNodes(ssList); // getNodedSubstrings calls NodedSegmentString::getNodedSubStrings() // which creates new NodedSegmentString and new pts member, so complete // new copy of data. Can be disposed of after geometries are constructed // std::vector* nodedList = noderValid.getNodedSubstrings(); - std::vector* nodedList = noderValid.getNodedSubstrings(); + std::vector nodedList = noderValid.getNodedSubstrings(); // Dispose of ssList for (auto ss: ssList) { @@ -102,10 +102,9 @@ NodingTestUtil::nodeValidated(const Geometry* geom1, const Geometry* geom2, Node std::unique_ptr lineGeom = toLines(nodedList, geom1->getFactory()); // Dispose of nodedList - for (auto nss: *nodedList) { + for (auto nss: nodedList) { delete nss; } - delete nodedList; return lineGeom; } diff --git a/tests/unit/util/NodingTestUtil.h b/tests/unit/util/NodingTestUtil.h index 228c99272..1db170e4a 100644 --- a/tests/unit/util/NodingTestUtil.h +++ b/tests/unit/util/NodingTestUtil.h @@ -38,7 +38,7 @@ class NodingTestUtil { // Methods static std::unique_ptr - toLines(const std::vector* nodedList, const geom::GeometryFactory* geomFact); + toLines(const std::vector& nodedList, const geom::GeometryFactory* geomFact); static std::vector toSegmentStrings(std::vector& lines); commit 05ac5c6a2d02a98f4fc566ef86737ba9d324fb12 Author: Daniel Baston Date: Tue Nov 11 18:21:09 2025 -0500 BoundaryChainNoder: Remove some heap allocations diff --git a/include/geos/noding/BoundaryChainNoder.h b/include/geos/noding/BoundaryChainNoder.h index c0a494603..075168a7e 100644 --- a/include/geos/noding/BoundaryChainNoder.h +++ b/include/geos/noding/BoundaryChainNoder.h @@ -137,8 +137,7 @@ public: using SegmentSet = std::unordered_set; BoundaryChainNoder() - : m_chainList(nullptr) - , m_constructZ(false) + : m_constructZ(false) , m_constructM(false) {}; @@ -150,7 +149,7 @@ public: private: // Members - std::vector* m_chainList; + std::vector m_chainList; std::vector> m_substrings; bool m_constructZ; bool m_constructM; @@ -169,26 +168,26 @@ private: static void markBoundarySegments(SegmentSet& segSet); - std::vector* extractChains(std::vector& sections) const; + std::vector extractChains(std::vector& sections) const; Coordinate::UnorderedSet findNodePts( - const std::vector* segStrings) const; + const std::vector& segStrings) const; - std::vector* nodeChains( - const std::vector* chains, + std::vector nodeChains( + const std::vector& chains, const Coordinate::UnorderedSet& nodePts); void nodeChain( SegmentString* chain, const Coordinate::UnorderedSet& nodePts, - std::vector* nodedChains); + std::vector& nodedChains); std::size_t findNodeIndex( const SegmentString* chain, std::size_t start, const Coordinate::UnorderedSet& nodePts) const; - noding::BasicSegmentString* substring( + std::unique_ptr substring( const SegmentString* segString, std::size_t start, std::size_t end); diff --git a/src/noding/BoundaryChainNoder.cpp b/src/noding/BoundaryChainNoder.cpp index 93642fc7e..6f07bd9e2 100644 --- a/src/noding/BoundaryChainNoder.cpp +++ b/src/noding/BoundaryChainNoder.cpp @@ -40,21 +40,19 @@ BoundaryChainNoder::computeNodes(std::vector* segStrings) Coordinate::UnorderedSet nodePts = findNodePts(m_chainList); if (!nodePts.empty()) { - std::vector* tmplist = nodeChains(m_chainList, nodePts); // At this point we have copied all the SegmentString* - // we want to keep, so t container needs to go away and be replaced - delete m_chainList; - m_chainList = tmplist; + // we want to keep, so the container needs to go away and be replaced + m_chainList = nodeChains(m_chainList, nodePts); } } /* private */ Coordinate::UnorderedSet -BoundaryChainNoder::findNodePts(const std::vector* segStrings) const +BoundaryChainNoder::findNodePts(const std::vector& segStrings) const { Coordinate::UnorderedSet interiorVertices; Coordinate::UnorderedSet nodes; - for (const SegmentString* ss : *segStrings) { + for (const SegmentString* ss : segStrings) { //-- endpoints are nodes nodes.insert(ss->getCoordinate(0)); nodes.insert(ss->getCoordinate(ss->size() - 1)); @@ -72,13 +70,13 @@ BoundaryChainNoder::findNodePts(const std::vector* segStrings) c } /* private */ -std::vector* +std::vector BoundaryChainNoder::nodeChains( - const std::vector* chains, + const std::vector& chains, const Coordinate::UnorderedSet& nodePts) { - std::vector* nodedChains = new std::vector(); - for (SegmentString* chain : *chains) { + std::vector nodedChains; + for (SegmentString* chain : chains) { nodeChain(chain, nodePts, nodedChains); } return nodedChains; @@ -90,17 +88,17 @@ void BoundaryChainNoder::nodeChain( SegmentString* chain, const Coordinate::UnorderedSet& nodePts, - std::vector* nodedChains) + std::vector& nodedChains) { std::size_t start = 0; while (start < chain->size() - 1) { std::size_t end = findNodeIndex(chain, start, nodePts); //-- if no interior nodes found, keep original chain if (start == 0 && end == chain->size() - 1) { - nodedChains->push_back(chain); + nodedChains.push_back(chain); return; } - nodedChains->push_back(substring(chain, start, end)); + nodedChains.push_back(substring(chain, start, end).release()); start = end; } // We replaced this SegmentString with substrings, @@ -110,16 +108,13 @@ BoundaryChainNoder::nodeChain( } /* private static */ -BasicSegmentString* +std::unique_ptr BoundaryChainNoder::substring(const SegmentString* segString, std::size_t start, std::size_t end) { - // m_substrings.emplace_back(new CoordinateSequence()); - // CoordinateSequence* pts = m_substrings.back().get(); - CoordinateSequence* pts = new CoordinateSequence(); - for (std::size_t i = start; i < end + 1; i++) { - pts->add(segString->getCoordinate(i)); - } - return new BasicSegmentString(pts, segString->getData()); + // FIXME: Doesn't this leak "pts" ? + auto pts = std::make_unique(); + pts->add(*segString->getCoordinates(), start, end); + return std::make_unique(pts.release(), segString->getData()); } @@ -142,7 +137,7 @@ BoundaryChainNoder::findNodeIndex( std::vector* BoundaryChainNoder::getNodedSubstrings() const { - return m_chainList; + return new std::vector(std::move(m_chainList)); } /* private */ @@ -206,12 +201,12 @@ BoundaryChainNoder::markBoundarySegments(SegmentSet& segSet) } /* private */ -std::vector* +std::vector BoundaryChainNoder::extractChains(std::vector& boundaryChains) const { - std::vector* chains = new std::vector(); + std::vector chains; for (BoundaryChainMap& chainMap : boundaryChains) { - chainMap.createChains(*chains, m_constructZ, m_constructM); + chainMap.createChains(chains, m_constructZ, m_constructM); } return chains; } ----------------------------------------------------------------------- Summary of changes: include/geos/coverage/CoverageCleaner.h | 2 +- include/geos/geomgraph/EdgeNodingValidator.h | 4 +- include/geos/noding/BoundaryChainNoder.h | 43 ++++++----- include/geos/noding/FastNodingValidator.h | 9 ++- include/geos/noding/GeometryNoder.h | 8 ++- include/geos/noding/IteratedNoder.h | 16 +++-- include/geos/noding/MCIndexNoder.h | 11 ++- include/geos/noding/NodedSegmentString.h | 16 ++--- include/geos/noding/Noder.h | 16 ++--- include/geos/noding/NodingValidator.h | 12 ++-- include/geos/noding/ScaledNoder.h | 8 +-- include/geos/noding/SegmentExtractingNoder.h | 16 +++-- include/geos/noding/SegmentNodeList.h | 4 +- include/geos/noding/SegmentString.h | 2 + include/geos/noding/SimpleNoder.h | 10 +-- include/geos/noding/SinglePassNoder.h | 4 +- include/geos/noding/ValidatingNoder.h | 15 ++-- include/geos/noding/snap/SnappingNoder.h | 15 ++-- include/geos/noding/snapround/MCIndexSnapRounder.h | 16 ++--- include/geos/noding/snapround/SnapRoundingNoder.h | 10 +-- .../geos/operation/overlayng/EdgeNodingBuilder.h | 19 ++--- src/coverage/CoverageCleaner.cpp | 13 ++-- src/geomgraph/EdgeNodingValidator.cpp | 11 +-- src/noding/BoundaryChainNoder.cpp | 84 ++++++++++------------ src/noding/FastNodingValidator.cpp | 2 +- src/noding/GeometryNoder.cpp | 15 ++-- src/noding/IteratedNoder.cpp | 37 ++++------ src/noding/MCIndexNoder.cpp | 5 +- src/noding/NodedSegmentString.cpp | 22 +++--- src/noding/ScaledNoder.cpp | 26 +++---- src/noding/SegmentExtractingNoder.cpp | 17 +++-- src/noding/SegmentNodeList.cpp | 4 +- src/noding/SegmentString.cpp | 9 +++ src/noding/SimpleNoder.cpp | 6 +- src/noding/ValidatingNoder.cpp | 19 ++--- src/noding/snap/SnappingNoder.cpp | 31 ++++---- src/noding/snapround/MCIndexSnapRounder.cpp | 21 +++--- src/noding/snapround/SnapRoundingNoder.cpp | 19 +++-- src/operation/buffer/BufferBuilder.cpp | 29 +++----- src/operation/overlayng/EdgeNodingBuilder.cpp | 26 +++---- src/operation/valid/IsSimpleOp.cpp | 2 +- src/operation/valid/PolygonTopologyAnalyzer.cpp | 2 +- src/triangulate/polygon/PolygonNoder.cpp | 2 +- tests/unit/noding/NodedSegmentStringTest.cpp | 10 +-- .../noding/snapround/MCIndexSnapRounderTest.cpp | 7 +- tests/unit/util/NodingTestUtil.cpp | 16 ++--- tests/unit/util/NodingTestUtil.h | 2 +- 47 files changed, 319 insertions(+), 374 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Sun Nov 16 15:31:52 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 16 Nov 2025 15:31:52 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 26e1cddea7b6d24d1b6c836a76bb9232888b432d Message-ID: <20251116233152.8C4CA189F1F@trac.osgeo.org> 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 26e1cddea7b6d24d1b6c836a76bb9232888b432d (commit) from e3b518f00ce17fecaed7289323829fc9bb7a1105 (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 26e1cddea7b6d24d1b6c836a76bb9232888b432d Author: Mike Taves Date: Mon Nov 17 12:31:17 2025 +1300 geosop: add removeRepeatedPointsgit operation diff --git a/util/geosop/GeometryOp.cpp b/util/geosop/GeometryOp.cpp index 4838ab3eb..376d444b6 100644 --- a/util/geosop/GeometryOp.cpp +++ b/util/geosop/GeometryOp.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -281,6 +282,13 @@ std::vector opRegistry { return new Result( geos::operation::valid::MakeValid().build( &geom ) ); }); }}, +{"removeRepeatedPoints", [](std::string name) { return GeometryOp::create(name, + catValid, + "remove repeated points from a geometry within a distance", + [](const Geometry& geom, double d) { + return new Result( operation::valid::RepeatedPointRemover::removeRepeatedPoints( &geom, d) ); + }); +}}, //============= category: Construction ================== ----------------------------------------------------------------------- Summary of changes: util/geosop/GeometryOp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) hooks/post-receive -- GEOS From git at osgeo.org Sun Nov 16 16:46:26 2025 From: git at osgeo.org (git at osgeo.org) Date: Sun, 16 Nov 2025 16:46:26 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. afe4d0595b2203605f6cdccd7742a9665caab6e3 Message-ID: <20251117004626.5873D189F3C@trac.osgeo.org> 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 afe4d0595b2203605f6cdccd7742a9665caab6e3 (commit) from 26e1cddea7b6d24d1b6c836a76bb9232888b432d (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 afe4d0595b2203605f6cdccd7742a9665caab6e3 Author: Daniel Baston Date: Sun Nov 16 19:46:04 2025 -0500 DouglasPeuckerLineSimplifier: preserve M values (#1317) Resolves https://github.com/libgeos/geos/issues/1315 diff --git a/capi/geos_c.h.in b/capi/geos_c.h.in index b5d5ada78..7c80f7016 100644 --- a/capi/geos_c.h.in +++ b/capi/geos_c.h.in @@ -5207,6 +5207,7 @@ extern GEOSGeometry GEOS_DLL *GEOSReverse(const GEOSGeometry* g); * to the coordinate sequences of the input geometry. * Removes "unnecessary" vertices, vertices * that are co-linear within the tolerance distance. +* Z and M values on the retained coordinates will be preserved. * \param g The input geometry * \param tolerance The tolerance to apply. Larger tolerance leads to simpler output. * \return The simplified geometry diff --git a/src/simplify/DouglasPeuckerLineSimplifier.cpp b/src/simplify/DouglasPeuckerLineSimplifier.cpp index 49e040e0b..ff436e578 100644 --- a/src/simplify/DouglasPeuckerLineSimplifier.cpp +++ b/src/simplify/DouglasPeuckerLineSimplifier.cpp @@ -75,7 +75,7 @@ DouglasPeuckerLineSimplifier::setPreserveClosedEndpoint(bool preserve) std::unique_ptr DouglasPeuckerLineSimplifier::simplify() { - auto coordList = detail::make_unique(); + auto coordList = detail::make_unique(0, pts.hasZ(), pts.hasM()); // empty coordlist is the simplest, won't simplify further if(pts.isEmpty()) { @@ -85,9 +85,18 @@ DouglasPeuckerLineSimplifier::simplify() usePt = std::vector(pts.size(), true); simplifySection(0, pts.size() - 1); - for(std::size_t i = 0, n = pts.size(); i < n; ++i) { - if(usePt[i]) { - coordList->add(pts[i]); + // Add continuous ranges of retained points from pts to coordList + std::size_t from = 0; + while (from < pts.size() && !usePt[from]) { + from++; + } + for(std::size_t to = from + 1; to <= pts.size(); to++) { + if (to == pts.size() || !usePt[to]) { + coordList->add(pts, from, to - 1); + while (to < pts.size() && !usePt[to]) { + to++; + } + from = to; } } @@ -96,8 +105,7 @@ DouglasPeuckerLineSimplifier::simplify() if (simplifyRing && coordList->size() > geom::LinearRing::MINIMUM_VALID_SIZE) { geom::LineSegment seg(coordList->getAt(coordList->size() - 2), coordList->getAt(1)); if (seg.distance(coordList->getAt(0)) <= distanceTolerance) { - auto ret = detail::make_unique(); - ret->reserve(coordList->size() - 1); + auto ret = detail::make_unique(0, pts.hasZ(), pts.hasM()); ret->add(*coordList, 1, coordList->size() - 2); ret->closeRing(); coordList = std::move(ret); diff --git a/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp b/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp index 83f3e9e45..ee3257a90 100644 --- a/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp +++ b/tests/unit/simplify/DouglasPeuckerSimplifierTest.cpp @@ -45,7 +45,7 @@ struct test_dpsimp_data { ensure("Simplified geometry is invalid!", simplified->isValid()); GeomPtr exp(wktreader.read(wkt_expected)); - ensure_equals_geometry(simplified.get(), exp.get()); + ensure_equals_exact_geometry_xyzm(simplified.get(), exp.get(), 0); } void @@ -297,7 +297,7 @@ void object::test<16>() { checkDP("POLYGON ((1 0, 2 0, 2 2, 0 2, 0 0, 1 0))", 0, - "POLYGON (( 0 0, 2 0, 2 2, 0 2, 0 0))"); + "POLYGON ((2 0, 2 2, 0 2, 0 0, 2 0))"); } // Test that start point of a closed LineString is not changed @@ -318,7 +318,7 @@ void object::test<18>() checkDP( "POLYGON ((42 42, 0 42, 0 100, 42 100, 100 42, 42 42))", 1, - "POLYGON ((100 42, 0 42, 0 100, 42 100, 100 42))" + "POLYGON ((0 42, 0 100, 42 100, 100 42, 0 42))" ); } @@ -349,4 +349,37 @@ void object::test<20>() } } +template<> +template<> +void object::test<21>() +{ + set_test_name("Z values are preserved"); + + checkDP("POLYGON Z ((20 220 5, 40 220 10, 60 220 15, 80 220 20, 100 220 25, 120 220 30, 140 220 35, 140 180 40, 100 180 45, 60 180 50, 20 180 55, 20 220 5))", + 10.0, + "POLYGON Z ((20 220 5, 140 220 35, 140 180 40, 20 180 55, 20 220 5))"); +} + +template<> +template<> +void object::test<22>() +{ + set_test_name("M values are preserved"); + + checkDP("POLYGON M ((20 220 5, 40 220 10, 60 220 15, 80 220 20, 100 220 25, 120 220 30, 140 220 35, 140 180 40, 100 180 45, 60 180 50, 20 180 55, 20 220 5))", + 10.0, + "POLYGON M ((20 220 5, 140 220 35, 140 180 40, 20 180 55, 20 220 5))"); +} + +template<> +template<> +void object::test<23>() +{ + set_test_name("Z/M values preserved when removing polygon start point"); + + checkDP("POLYGON ZM ((1 0 5 7, 2 0 10 9, 2 2 15 11, 0 2 20 13, 0 0 25 15, 1 0 5 7))", + 0, + "POLYGON ZM ((2 0 10 9, 2 2 15 11, 0 2 20 13, 0 0 25 15, 2 0 10 9))"); +} + } // namespace tut ----------------------------------------------------------------------- Summary of changes: capi/geos_c.h.in | 1 + src/simplify/DouglasPeuckerLineSimplifier.cpp | 20 +++++++---- .../unit/simplify/DouglasPeuckerSimplifierTest.cpp | 39 ++++++++++++++++++++-- 3 files changed, 51 insertions(+), 9 deletions(-) hooks/post-receive -- GEOS From git at osgeo.org Mon Nov 17 05:24:06 2025 From: git at osgeo.org (git at osgeo.org) Date: Mon, 17 Nov 2025 05:24:06 -0800 (PST) Subject: [geos-commits] [SCM] GEOS branch main updated. 640d3758eeafc859e7484ca7ab7e6d76fc48719d Message-ID: <20251117132406.8BFD818BEE8@trac.osgeo.org> 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 640d3758eeafc859e7484ca7ab7e6d76fc48719d (commit) via 174866213c52f91d24cda3cfdb32dea6e4a4684e (commit) via b0b52d238eee1b70388404e1401f7d3d7d90bc02 (commit) from afe4d0595b2203605f6cdccd7742a9665caab6e3 (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 640d3758eeafc859e7484ca7ab7e6d76fc48719d Author: Daniel Baston Date: Wed Oct 22 10:30:37 2025 -0400 Densifier: preserve and interpolate M values diff --git a/src/geom/util/Densifier.cpp b/src/geom/util/Densifier.cpp index 9f4e27967..a344757b4 100644 --- a/src/geom/util/Densifier.cpp +++ b/src/geom/util/Densifier.cpp @@ -108,16 +108,13 @@ Densifier::Densifier(const Geometry* geom): std::unique_ptr Densifier::densifyPoints(const CoordinateSequence& pts, double distanceTolerance, const PrecisionModel* precModel) { - geom::LineSegment seg; - auto coordList = detail::make_unique(); + auto coordList = detail::make_unique(0, pts.hasZ(), pts.hasM()); - auto items = pts.items(); - for(auto it = items.cbegin(), itEnd = items.cend() - 1; it < itEnd; ++it) { - seg.p0 = *it; - seg.p1 = *(it + 1); - coordList->add(seg.p0, false); - const double len = seg.getLength(); - const double densifiedSegCountDbl = ceil(len / distanceTolerance); + pts.forEachSegment([&coordList, distanceTolerance, precModel](const auto& p0, const auto& p1) { + coordList->add(p0, false); + + const double len = p0.distance(p1); + const double densifiedSegCountDbl = std::ceil(len / distanceTolerance); if(densifiedSegCountDbl > std::numeric_limits::max()) { throw geos::util::GEOSException( "Tolerance is too small compared to geometry length"); @@ -128,18 +125,20 @@ Densifier::densifyPoints(const CoordinateSequence& pts, double distanceTolerance double densifiedSegLen = len / densifiedSegCount; for(int j = 1; j < densifiedSegCount; j++) { double segFract = (j * densifiedSegLen) / len; - Coordinate p; - seg.pointAlong(segFract, p); + auto p = LineSegment::pointAlong(segFract, p0, p1); precModel->makePrecise(p); coordList->add(p, false); } } else { // no densification required; insert the last coordinate and continue - coordList->add(seg.p1, false); + coordList->add(p1, false); } - } - coordList->add(pts[pts.size() - 1], false); + + }); + pts.applyAt(pts.size() - 1, [&coordList](const auto& pt) { + coordList->add(pt, false); + }); return coordList; } diff --git a/tests/unit/capi/GEOSDensifyTest.cpp b/tests/unit/capi/GEOSDensifyTest.cpp index 721e91dc2..752441ddb 100644 --- a/tests/unit/capi/GEOSDensifyTest.cpp +++ b/tests/unit/capi/GEOSDensifyTest.cpp @@ -169,6 +169,7 @@ void object::test<10>() result_ = GEOSDensify(input_, 0.1); ensure("curved geometries not supported", result_ == nullptr); } + // Densify a LINESTRING Z, check that Z gets interpolated template <> template <> @@ -205,4 +206,17 @@ void object::test<13>() ); } +template <> +template <> +void object::test<14>() +{ + set_test_name("M values are interpolated"); + + testDensify( + "LINESTRING M (0 0 0, 0 6 2)", + "LINESTRING M (0 0 0, 0 3 1, 0 6 2)", + 3.0 + ); +} + } // namespace tut commit 174866213c52f91d24cda3cfdb32dea6e4a4684e Author: Daniel Baston Date: Wed Oct 22 10:30:29 2025 -0400 CoordinateSequence: add forEachSegment method diff --git a/include/geos/geom/CoordinateSequence.h b/include/geos/geom/CoordinateSequence.h index 2d952f137..5e0a7776b 100644 --- a/include/geos/geom/CoordinateSequence.h +++ b/include/geos/geom/CoordinateSequence.h @@ -710,6 +710,16 @@ public: } } + template + void forEachSegment(F&& fun) const { + switch(getCoordinateType()) { + case CoordinateType::XY: forEachSegmentImpl(std::move(fun)); break; + case CoordinateType::XYZ: forEachSegmentImpl(std::move(fun)); break; + case CoordinateType::XYM: forEachSegmentImpl(std::move(fun)); break; + case CoordinateType::XYZM: forEachSegmentImpl(std::move(fun)); break; + } + } + template void forEach(std::size_t from, std::size_t to, F&& fun) const { @@ -797,6 +807,24 @@ private: orig = c; } + template + void forEachSegmentImpl(F&& fun) const { + auto p0it = items().cbegin(); + const auto end = items().end(); + + if (p0it == end) { + return; + } + + auto p1it = std::next(p0it); + + while (p1it != end) { + fun(*p0it, *p1it); + ++p0it; + ++p1it; + } + } + void make_space(std::size_t pos, std::size_t n) { m_vect.insert(std::next(m_vect.begin(), static_cast(pos * stride())), m_stride * n, diff --git a/tests/unit/geom/CoordinateSequenceTest.cpp b/tests/unit/geom/CoordinateSequenceTest.cpp index 4786c20c8..e2a94fb41 100644 --- a/tests/unit/geom/CoordinateSequenceTest.cpp +++ b/tests/unit/geom/CoordinateSequenceTest.cpp @@ -1536,4 +1536,48 @@ void object::test<56> ensure_equals_xyz(seq1.getAt(3), Coordinate{10, 11, DoubleNotANumber}); } +template<> +template<> +void object::test<57>() +{ + set_test_name("CoordinateSequence::forEachSegment called on empty CoordinateSequence"); + + CoordinateSequence empty; + empty.forEachSegment([](const auto&, const auto&) { + fail(); + }); +} + +template<> +template<> +void object::test<58>() +{ + set_test_name("CoordinateSequence::forEachSegment called on single-point CoordinateSequence"); + + CoordinateSequence seq; + seq.add(CoordinateXY{3, 6}); + seq.forEachSegment([](const auto&, const auto&) { + fail(); + }); +} + +template<> +template<> +void object::test<59>() +{ + set_test_name("CoordinateSequence::forEachSegment basic test"); + + CoordinateSequence seq; + seq.add(CoordinateXY{0, 0}); + seq.add(CoordinateXY{3, 0}); + seq.add(CoordinateXY{3, 5}); + + double length = 0; + seq.forEachSegment([&length](const auto& p0, const auto& p1) { + length += p0.distance(p1); + }); + + ensure_equals(length, 8); +} + } // namespace tut commit b0b52d238eee1b70388404e1401f7d3d7d90bc02 Author: Daniel Baston Date: Wed Oct 22 10:30:12 2025 -0400 LineSegment: Add static pointAlong interpolation methods diff --git a/include/geos/geom/LineSegment.h b/include/geos/geom/LineSegment.h index aea0fefd8..f6ef755ac 100644 --- a/include/geos/geom/LineSegment.h +++ b/include/geos/geom/LineSegment.h @@ -326,6 +326,34 @@ public: p0.z + segmentLengthFraction * (p1.z - p0.z)); }; + static CoordinateXY pointAlong(double segmentLengthFraction, const CoordinateXY& p0, const CoordinateXY& p1) + { + return { p0.x + segmentLengthFraction * (p1.x - p0.x), + p0.y + segmentLengthFraction * (p1.y - p0.y) }; + } + + static Coordinate pointAlong(double segmentLengthFraction, const Coordinate& p0, const Coordinate& p1) + { + return { p0.x + segmentLengthFraction * (p1.x - p0.x), + p0.y + segmentLengthFraction * (p1.y - p0.y), + p0.z + segmentLengthFraction * (p1.z - p0.z) }; + } + + static CoordinateXYM pointAlong(double segmentLengthFraction, const CoordinateXYM& p0, const CoordinateXYM& p1) + { + return { p0.x + segmentLengthFraction * (p1.x - p0.x), + p0.y + segmentLengthFraction * (p1.y - p0.y), + p0.m + segmentLengthFraction * (p1.m - p0.m) }; + } + + static CoordinateXYZM pointAlong(double segmentLengthFraction, const CoordinateXYZM& p0, const CoordinateXYZM& p1) + { + return { p0.x + segmentLengthFraction * (p1.x - p0.x), + p0.y + segmentLengthFraction * (p1.y - p0.y), + p0.z + segmentLengthFraction * (p1.z - p0.z), + p0.m + segmentLengthFraction * (p1.m - p0.m) }; + } + /** \brief * Computes the {@link Coordinate} that lies a given * fraction along the line defined by this segment and offset from ----------------------------------------------------------------------- Summary of changes: include/geos/geom/CoordinateSequence.h | 28 +++++++++++++++++++ include/geos/geom/LineSegment.h | 28 +++++++++++++++++++ src/geom/util/Densifier.cpp | 29 ++++++++++---------- tests/unit/capi/GEOSDensifyTest.cpp | 14 ++++++++++ tests/unit/geom/CoordinateSequenceTest.cpp | 44 ++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 15 deletions(-) hooks/post-receive -- GEOS