From fd35ea9c6f430c34fec2e2e98efaa84707699798 Mon Sep 17 00:00:00 2001 From: arriopolis Date: Fri, 16 Jan 2026 12:18:08 -0800 Subject: [PATCH 1/3] added a spatial index to the overlayng polygonbuilder --- src/operation/overlayng/PolygonBuilder.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/operation/overlayng/PolygonBuilder.cpp b/src/operation/overlayng/PolygonBuilder.cpp index abdb4a0fb8..4e032c976c 100644 --- a/src/operation/overlayng/PolygonBuilder.cpp +++ b/src/operation/overlayng/PolygonBuilder.cpp @@ -168,11 +168,20 @@ PolygonBuilder::assignHoles(OverlayEdgeRing* shell, const std::vector& shells, const std::vector & freeHoles) const { - // TODO: use a spatial index to improve performance + // build spacial index + index::strtree::TemplateSTRtree index; + for (auto& shell : shells) { + index.insert(*shell->getRingPtr()->getEnvelopeInternal(), shell); + } + for (OverlayEdgeRing* hole : freeHoles) { // only place this hole if it doesn't yet have a shell if (hole->getShell() == nullptr) { - OverlayEdgeRing* shell = hole->findEdgeRingContaining(shells); + // get list of overlapping shells + std::vector shellListOverlaps; + index.query(*hole->getRingPtr()->getEnvelopeInternal(), shellListOverlaps); + + OverlayEdgeRing* shell = hole->findEdgeRingContaining(shellListOverlaps); // only when building a polygon-valid result if (isEnforcePolygonal && shell == nullptr) { throw util::TopologyException("unable to assign free hole to a shell", hole->getCoordinate()); From 50c7d5abdb17eb6adf61174428085fabb8bc314d Mon Sep 17 00:00:00 2001 From: arriopolis Date: Fri, 16 Jan 2026 12:38:04 -0800 Subject: [PATCH 2/3] Updated spelling. --- src/operation/overlayng/PolygonBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/overlayng/PolygonBuilder.cpp b/src/operation/overlayng/PolygonBuilder.cpp index 4e032c976c..ccc3e0c449 100644 --- a/src/operation/overlayng/PolygonBuilder.cpp +++ b/src/operation/overlayng/PolygonBuilder.cpp @@ -168,7 +168,7 @@ PolygonBuilder::assignHoles(OverlayEdgeRing* shell, const std::vector& shells, const std::vector & freeHoles) const { - // build spacial index + // build spatial index index::strtree::TemplateSTRtree index; for (auto& shell : shells) { index.insert(*shell->getRingPtr()->getEnvelopeInternal(), shell); From a57121315cfcf8a98071859b52a9051c7f9ed301 Mon Sep 17 00:00:00 2001 From: arriopolis Date: Fri, 16 Jan 2026 21:03:32 -0800 Subject: [PATCH 3/3] reuse spatial filter result vector --- src/operation/overlayng/PolygonBuilder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/operation/overlayng/PolygonBuilder.cpp b/src/operation/overlayng/PolygonBuilder.cpp index ccc3e0c449..8cc88d306f 100644 --- a/src/operation/overlayng/PolygonBuilder.cpp +++ b/src/operation/overlayng/PolygonBuilder.cpp @@ -174,11 +174,12 @@ PolygonBuilder::placeFreeHoles(const std::vector& shells, cons index.insert(*shell->getRingPtr()->getEnvelopeInternal(), shell); } + std::vector shellListOverlaps; for (OverlayEdgeRing* hole : freeHoles) { // only place this hole if it doesn't yet have a shell if (hole->getShell() == nullptr) { // get list of overlapping shells - std::vector shellListOverlaps; + shellListOverlaps.clear(); index.query(*hole->getRingPtr()->getEnvelopeInternal(), shellListOverlaps); OverlayEdgeRing* shell = hole->findEdgeRingContaining(shellListOverlaps);