mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-04 17:35:42 +02:00
Only accept longitude corrections that give rings the right winding
This commit is contained in:
+35
-12
@@ -313,11 +313,12 @@ serial_feature deserialize_feature(std::string &geoms, unsigned z, unsigned tx,
|
|||||||
return sf;
|
return sf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long long scale_geometry(struct serialization_state *sst, long long *bbox, drawvec &geom) {
|
static long long scale_geometry(struct serialization_state *sst, long long *bbox, drawvec &geom, int t) {
|
||||||
double scale = 1.0 / (1 << geometry_scale);
|
double scale = 1.0 / (1 << geometry_scale);
|
||||||
|
|
||||||
if (additional[A_DETECT_WRAPAROUND]) {
|
if (additional[A_DETECT_WRAPAROUND]) {
|
||||||
drawvec out;
|
drawvec out;
|
||||||
|
bool outer = true; // first ring is expected to be outer
|
||||||
|
|
||||||
for (size_t i = 0; i < geom.size(); i++) {
|
for (size_t i = 0; i < geom.size(); i++) {
|
||||||
if (geom[i].op == VT_MOVETO) {
|
if (geom[i].op == VT_MOVETO) {
|
||||||
@@ -333,6 +334,7 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
|
|||||||
bool balanced = true;
|
bool balanced = true;
|
||||||
|
|
||||||
drawvec ring;
|
drawvec ring;
|
||||||
|
bool changed = false;
|
||||||
for (size_t k = i; k < j; k++) {
|
for (size_t k = i; k < j; k++) {
|
||||||
draw op = geom[k];
|
draw op = geom[k];
|
||||||
op.x += offset;
|
op.x += offset;
|
||||||
@@ -349,6 +351,7 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
|
|||||||
|
|
||||||
offset -= 1LL << 32;
|
offset -= 1LL << 32;
|
||||||
op.x -= 1LL << 32;
|
op.x -= 1LL << 32;
|
||||||
|
changed = true;
|
||||||
} else if (prev_x - op.x > (1LL << 31) && prev_x - op.x != (1LL << 32)) {
|
} else if (prev_x - op.x > (1LL << 31) && prev_x - op.x != (1LL << 32)) {
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
// already shifted right, but seems to need another shift right
|
// already shifted right, but seems to need another shift right
|
||||||
@@ -358,22 +361,40 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
|
|||||||
|
|
||||||
offset += 1LL << 32;
|
offset += 1LL << 32;
|
||||||
op.x += 1LL << 32;
|
op.x += 1LL << 32;
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ring.push_back(op);
|
ring.push_back(op);
|
||||||
prev_x = op.x;
|
prev_x = op.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a polygon, in which the first and last
|
if (changed && balanced) {
|
||||||
// points of each ring are supposed to be identical,
|
// If this is a polygon, in which the first and last
|
||||||
// make sure the antimeridian wraparound detection
|
// points of each ring are supposed to be identical,
|
||||||
// preserves that expectation. If it doesn't, it means
|
// make sure the antimeridian wraparound detection
|
||||||
// we have detected something wrongly.
|
// preserves that expectation. If it doesn't, it means
|
||||||
if (geom[j - 1] == geom[i]) {
|
// we have detected something wrongly.
|
||||||
if (offset != 0) {
|
if (geom[j - 1] == geom[i]) {
|
||||||
// first and last points are supposed to be the same
|
if (offset != 0) {
|
||||||
// but there is an unresolved antimeridian shift
|
// first and last points are supposed to be the same
|
||||||
balanced = false;
|
// but there is an unresolved antimeridian shift
|
||||||
|
balanced = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t == VT_POLYGON) {
|
||||||
|
// don't accept longitude corrections that would give
|
||||||
|
// a ring a winding counter to what the geojson structure
|
||||||
|
// says the winding should be
|
||||||
|
|
||||||
|
double area_after = get_area(ring, 0, ring.size());
|
||||||
|
if ((outer && area_after < 0) ||
|
||||||
|
(!outer && area_after > 0)) {
|
||||||
|
// wraparound detection gave a ring a winding different from
|
||||||
|
// what its position in the GeoJSON structure indicates that
|
||||||
|
// it should have.
|
||||||
|
balanced = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +412,10 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
i = j - 1;
|
i = j - 1;
|
||||||
|
outer = false;
|
||||||
} else if (geom[i].op == VT_CLOSEPATH) {
|
} else if (geom[i].op == VT_CLOSEPATH) {
|
||||||
out.push_back(geom[i]);
|
out.push_back(geom[i]);
|
||||||
|
outer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +543,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
|
|||||||
// try to remind myself that the geometry in this function is in SCALED COORDINATES
|
// try to remind myself that the geometry in this function is in SCALED COORDINATES
|
||||||
drawvec scaled_geometry = sf.geometry;
|
drawvec scaled_geometry = sf.geometry;
|
||||||
sf.geometry.clear();
|
sf.geometry.clear();
|
||||||
scale_geometry(sst, sf.bbox, scaled_geometry);
|
scale_geometry(sst, sf.bbox, scaled_geometry, sf.t);
|
||||||
|
|
||||||
// This has to happen after scaling so that the wraparound detection has happened first.
|
// This has to happen after scaling so that the wraparound detection has happened first.
|
||||||
// Otherwise the inner/outer calculation will be confused by bad geometries.
|
// Otherwise the inner/outer calculation will be confused by bad geometries.
|
||||||
|
|||||||
Reference in New Issue
Block a user