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
1 change: 1 addition & 0 deletions include/coordinates_geom.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class TileBbox {
std::pair<int,int> scaleLatpLon(double latp, double lon) const;
void scaleRing(Ring &dst, Ring const &src) const;
Ring scaleRing(Ring const &src) const;
void scaleRingNoBacktrack(Ring &dst, Ring const &src) const;
void scaleGeometry(MultiPolygon &dst, MultiPolygon const &src) const;
MultiPolygon scaleGeometry(MultiPolygon const &src) const;
std::pair<double, double> floorLatpLon(double latp, double lon) const;
Expand Down
29 changes: 27 additions & 2 deletions src/coordinates_geom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ void TileBbox::scaleRing(Ring &points, Ring const &src) const {
}
}

// Scaling that only drops points repeating their immediate predecessor. Used as
// a fallback for rings that scaleRing() collapses below 4 points: its
// backtracking window is positional, so a duplicated FIRST vertex shifts every
// later vertex by one, the closing vertex then matches that duplicate at j==4,
// and resize() truncates the whole ring. Without the backtracking there is
// nothing to mis-align, and the ring survives with its shape intact.
void TileBbox::scaleRingNoBacktrack(Ring &points, Ring const &src) const {
points.clear();
points.reserve(src.size());
for(auto const &i: src) {
auto scaled = scaleLatpLon(i.y(), i.x());
if (!points.empty() &&
points.back().x()==scaled.first && points.back().y()==scaled.second)
continue;
points.push_back(Point(scaled.first,scaled.second));
}
}

Ring TileBbox::scaleRing(Ring const &src) const {
Ring points;
scaleRing(points, src);
Expand All @@ -66,8 +84,15 @@ void TileBbox::scaleGeometry(MultiPolygon &dst, MultiPolygon const &src) const {

// Copy the outer ring
scaleRing(p.outer(), poly.outer());
if (p.outer().size()<4)
continue;
if (p.outer().size()<4) {
// A collapsed outer ring means the whole feature disappears from the
// tile, at any size - so before giving up, retry without the
// backtracking that can truncate a ring to two points. Every ring that
// already survives is left untouched.
scaleRingNoBacktrack(p.outer(), poly.outer());
if (p.outer().size()<4)
continue;
}

// Copy the inner rings
if (p.inners().size() < poly.inners().size())
Expand Down
Loading