From 035c1a75099ad32f85c28d8ab6c985694ca43cb1 Mon Sep 17 00:00:00 2001 From: Wouter van Kleunen Date: Sat, 1 May 2021 11:19:27 +0000 Subject: [PATCH] Prune polygon to area within tile bounding box --- src/output_object.cpp | 80 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/src/output_object.cpp b/src/output_object.cpp index 2e7669ea..a9962e12 100644 --- a/src/output_object.cpp +++ b/src/output_object.cpp @@ -80,9 +80,9 @@ Geometry buildWayGeometry(OSMStore &osmStore, OutputObject const &oo, const Tile case OutputGeometryType::LINESTRING: { + MultiLinestring out; auto const &ls = osmStore.retrieve(oo.handle); - MultiLinestring out; if(ls.empty()) return out; @@ -95,6 +95,7 @@ Geometry buildWayGeometry(OSMStore &osmStore, OutputObject const &oo, const Tile out.push_back(std::move(current_ls)); current_ls.clear(); } + geom::append(current_ls, ls[i]); } @@ -109,23 +110,72 @@ Geometry buildWayGeometry(OSMStore &osmStore, OutputObject const &oo, const Tile auto const &mp = osmStore.retrieve(oo.handle); Polygon clippingPolygon; - geom::convert(bbox.clippingBox, clippingPolygon); - if (!geom::intersects(mp, clippingPolygon)) { return MultiPolygon(); } - if (geom::within(mp, clippingPolygon)) { - MultiPolygon out; - boost::geometry::assign(out, mp); - return out; - } - try { - MultiPolygon out; - geom::intersection(mp, clippingPolygon, out); - return out; - } catch (geom::overlay_invalid_input_exception &err) { - std::cout << "Couldn't clip polygon (self-intersection)" << std::endl; - return MultiPolygon(); // blank + MultiPolygon out; + for(auto const &p: mp) { + Polygon newp; + if(geom::within(p.outer, clippingPolygon)) { + boost::geometry::assign(newp, p); + out.push_back(newp); + continue; + } + + for(auto const &inner: p.inners) { + if(!inner.empty()) { + Ring ring; + geom::append(ring, inner[0]); + for(std::size_t i = 1; i < inner.size(); ++i) { + if(geom::within(inner[i], bbox.clippingBox)) { + geom::append(ring, inner[i]); + continue; + } + + std::size_t next_i = (i + 1) % inner.size(); + Linestring ls({ ring.back(), inner[next_i] }); + + if(!geom::within(ls, inner) || geom::intersects(ls, bbox.clippingBox)) { + geom::append(ring, inner[i]); + } + } + + if(ring.size() >= 3) { + newp.inners().resize(newp.inners().size() + 1); + boost::geometry::assign(newp.inners().back(), ring); + } + } + } + + Ring outer_ring; + geom::append(outer_ring, p.outer[0]); + for(std::size_t i = 1; i < p.outer.size(); ++i) { + if(geom::within(p.outer[i], bbox.clippingBox)) { + geom::append(outer_ring, p.outer[i]); + continue; + } + + std::size_t next_i = (i + 1) % p.outer.size(); + Linestring ls({ outer_ring.back(), p.outer[next_i] }); + if(!geom::within(ls, p.outer)) { + geom::append(outer_ring, p.outer[i]); + continue; + } + + bool intersects = geom::intersects(ls, bbox.clippingBox); + for(auto const &inner: newp.inners()) { + intersects |= geom::intersects(ls, inner); + } + + if(intersects) { + geom::append(outer_ring, p.outer[i]); + } + } + + boost::geometry::assign(newp.outer(), outer_ring); + out.push_back(newp); } + + return out; } default: