From 79d190c90be5d74ce22b87fd51beff75a2781443 Mon Sep 17 00:00:00 2001 From: geoneutrino <48556918+geoneutrino@users.noreply.github.com> Date: Sat, 29 Aug 2026 15:45:27 +0200 Subject: [PATCH] Skip empty multipolygons in union_many() boost::geometry::envelope() of an empty multipolygon returns Boost's inverse initialisation box (min = +DBL_MAX, max = -DBL_MAX). Inserting that box into the R-tree trips the Boost.Geometry indexable validity check, aborting the run: boost/geometry/index/rtree.hpp:1661: Assertion `is_valid(...) && "Indexable is invalid"' failed. Clipping a polygon against a tile can legitimately produce an empty result, so ProcessObjects() can hand union_many() a vector whose entries are empty. An empty multipolygon cannot intersect anything and contributes nothing to the union, so skip it before the R-tree query and insert. Builds that define NDEBUG do not abort, but store the invalid box in the R-tree, which makes subsequent intersects() queries unreliable for that tile. The result is silently wrong output rather than a crash, so this affects release builds too. Reproduced on a planet dump at z13 in z6/0/14 (north-west Alaska, bbox -180,67.5,-172,71.5). --- src/geom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/geom.cpp b/src/geom.cpp index be063c3f..5d135e72 100644 --- a/src/geom.cpp +++ b/src/geom.cpp @@ -250,6 +250,7 @@ void union_many(std::vector &to_unify) { // whose bboxes intersect (transitivity is handled by union-find) bgi::rtree> rtree; for (size_t i = 0; i < to_unify.size(); i++) { + if (boost::geometry::is_empty(to_unify[i])) continue; for (auto const &v : rtree | bgi::adaptors::queried(bgi::intersects(boxes[i]))) { size_t ri = find(i), rj = find(v.second); if (ri != rj) parent[ri] = rj;