Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/geom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,11 @@ struct RectClipper {
bool inside(const Point &p) const {
return p.x() >= x0 && p.x() <= x1 && p.y() >= y0 && p.y() <= y1;
}
// Both end points beyond the same edge: the segment can't reach the box
bool beyondOneEdge(const Point &a, const Point &b) const {
return (a.x() < x0 && b.x() < x0) || (a.x() > x1 && b.x() > x1) ||
(a.y() < y0 && b.y() < y0) || (a.y() > y1 && b.y() > y1);
}
bool strictlyInside(const Point &p) const {
return p.x() > x0 && p.x() < x1 && p.y() > y0 && p.y() < y1;
}
Expand Down Expand Up @@ -888,7 +893,9 @@ RingClip clipRing(const RectClipper &rc, const Ring &ring, std::vector<RectChain
const Point &b = ring[(start + k + 1) % n];
double t0, t1;
Point pa, pb;
const bool hit = rc.clipSegment(a, b, t0, t1, pa, pb) && t1 > t0;
// Most segments of a large polygon lie far from a small tile's box: reject
// those with four comparisons before the clip computation
const bool hit = !rc.beyondOneEdge(a, b) && rc.clipSegment(a, b, t0, t1, pa, pb) && t1 > t0;
if (!hit || (building && t0 > 0)) {
if (building && !finish()) return RingClip::Fail;
if (!hit) continue;
Expand Down
12 changes: 9 additions & 3 deletions src/tile_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,13 @@ Geometry TileDataSource::buildWayGeometry(OutputGeometryType const geomType,
}

MultiPolygon mp;
if (cachedClip == nullptr)
// rect_clip below needs the input as it was before fast_clip. For a large valid
// polygon, keep it rather than load it from the store again for every tile.
std::size_t inputPoints = 0;
if (cachedClip == nullptr && inputKnownValid)
for (auto const &p : uncached) inputPoints += geom::num_points(p);
const bool keepUncached = inputPoints > 1000;
if (cachedClip == nullptr && !keepUncached)
mp = std::move(uncached);
else
geom::assign(mp, input);
Expand All @@ -405,9 +411,9 @@ Geometry TileDataSource::buildWayGeometry(OutputGeometryType const geomType,
// instead, which is much cheaper than the is_valid/intersection/repair
// path below; rect_clip bails out on anything it can't handle.
MultiPolygon original;
if (cachedClip == nullptr) populateMultiPolygon(original, objectID);
if (cachedClip == nullptr && !keepUncached) populateMultiPolygon(original, objectID);
MultiPolygon clipped;
if (rect_clip(cachedClip == nullptr ? original : input, box, clipped) &&
if (rect_clip(cachedClip == nullptr && !keepUncached ? original : input, box, clipped) &&
(multiPolygonDefinitelyValid(clipped) || geom::is_valid(clipped))) {
multiPolygonClipCache.add(bbox, objectID, clipped, true);
return clipped;
Expand Down
Loading