mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-05 01:45:41 +02:00
Maybe right now?
This commit is contained in:
+105
-16
@@ -276,8 +276,8 @@ bool intersect(std::vector<segment> &segs, size_t s1, size_t s2) {
|
|||||||
// at an endpoint in s1, so it doesn't need to be changed
|
// at an endpoint in s1, so it doesn't need to be changed
|
||||||
} else {
|
} else {
|
||||||
// printf("introduce %f,%f in %f,%f to %f,%f (s1 %zu %zu)\n", x, y, segs[s1].first.x, segs[s1].first.y, segs[s1].second.x, segs[s1].second.y, s1, s2);
|
// printf("introduce %f,%f in %f,%f to %f,%f (s1 %zu %zu)\n", x, y, segs[s1].first.x, segs[s1].first.y, segs[s1].second.x, segs[s1].second.y, s1, s2);
|
||||||
segs.push_back(std::make_pair(point(x, y), segs[s1].second));
|
segs.push_back(std::make_pair(point(std::round(x), std::round(y)), segs[s1].second));
|
||||||
segs[s1] = std::make_pair(segs[s1].first, point(x, y));
|
segs[s1] = std::make_pair(segs[s1].first, point(std::round(x), std::round(y)));
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,8 +287,8 @@ bool intersect(std::vector<segment> &segs, size_t s1, size_t s2) {
|
|||||||
} else {
|
} else {
|
||||||
// printf("introduce %f,%f in %f,%f to %f,%f (s2 %zu %zu)\n", x, y, segs[s2].first.x, segs[s2].first.y, segs[s2].second.x, segs[s2].second.y, s1, s2);
|
// printf("introduce %f,%f in %f,%f to %f,%f (s2 %zu %zu)\n", x, y, segs[s2].first.x, segs[s2].first.y, segs[s2].second.x, segs[s2].second.y, s1, s2);
|
||||||
// printf("introduce %lld,%lld in %lld,%lld to %lld,%lld (s2)\n", std::llround(x), std::llround(y), std::llround(segs[s2].first.x), std::llround(segs[s2].first.y), std::llround(segs[s2].second.x), std::llround(segs[s2].second.y));
|
// printf("introduce %lld,%lld in %lld,%lld to %lld,%lld (s2)\n", std::llround(x), std::llround(y), std::llround(segs[s2].first.x), std::llround(segs[s2].first.y), std::llround(segs[s2].second.x), std::llround(segs[s2].second.y));
|
||||||
segs.push_back(std::make_pair(point(x, y), segs[s2].second));
|
segs.push_back(std::make_pair(point(std::round(x), std::round(y)), segs[s2].second));
|
||||||
segs[s2] = std::make_pair(segs[s2].first, point(x, y));
|
segs[s2] = std::make_pair(segs[s2].first, point(std::round(x), std::round(y)));
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
} else if (intersections == SAME_SLOPE) {
|
} else if (intersections == SAME_SLOPE) {
|
||||||
@@ -416,10 +416,27 @@ struct ring_area {
|
|||||||
drawvec geom;
|
drawvec geom;
|
||||||
double area;
|
double area;
|
||||||
std::vector<size_t> children;
|
std::vector<size_t> children;
|
||||||
|
long long ear_x;
|
||||||
|
long long ear_y;
|
||||||
|
|
||||||
ring_area(drawvec geom_, double area_) {
|
ring_area(drawvec geom_, double area_) {
|
||||||
geom = geom_;
|
geom = geom_;
|
||||||
area = area_;
|
area = area_;
|
||||||
|
|
||||||
|
// search polygon ears to find an interior point
|
||||||
|
for (size_t i = 0; i + 2 < geom.size(); i++) {
|
||||||
|
long long x = (geom[i].x + geom[i + 1].x + geom[i + 2].x) / 3;
|
||||||
|
long long y = (geom[i].y + geom[i + 1].y + geom[i + 2].y) / 3;
|
||||||
|
|
||||||
|
if (pnpoly(geom, 0, geom.size(), x, y)) {
|
||||||
|
ear_x = x;
|
||||||
|
ear_y = y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Couldn't find an interior point\n");
|
||||||
|
exit(EXIT_IMPOSSIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(ring_area const &s) const {
|
bool operator<(ring_area const &s) const {
|
||||||
@@ -432,6 +449,8 @@ struct ring_area {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int SCALE = 3;
|
||||||
|
|
||||||
std::vector<ring_area> reassemble(std::vector<segment> const &segs) {
|
std::vector<ring_area> reassemble(std::vector<segment> const &segs) {
|
||||||
std::multimap<point, segment> connections;
|
std::multimap<point, segment> connections;
|
||||||
std::vector<ring_area> ret;
|
std::vector<ring_area> ret;
|
||||||
@@ -590,12 +609,12 @@ std::vector<ring_area> reassemble(std::vector<segment> const &segs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// these coordinates are doubled, so that `encloses` can always find
|
// these coordinates are doubled, so that `encloses` can always find
|
||||||
// an integer point at the center of an edge
|
// an interior point in each ring
|
||||||
drawvec out;
|
drawvec out;
|
||||||
for (size_t i = 0; i < ring.size(); i++) {
|
for (size_t i = 0; i < ring.size(); i++) {
|
||||||
out.emplace_back(i == 0 ? VT_MOVETO : VT_LINETO, std::round(ring[i].x) * 2, std::round(ring[i].y) * 2);
|
out.emplace_back(i == 0 ? VT_MOVETO : VT_LINETO, std::round(ring[i].x) * SCALE, std::round(ring[i].y) * SCALE);
|
||||||
}
|
}
|
||||||
out.emplace_back(VT_LINETO, std::round(ring[0].x) * 2, std::round(ring[0].y) * 2);
|
out.emplace_back(VT_LINETO, std::round(ring[0].x) * SCALE, std::round(ring[0].y) * SCALE);
|
||||||
if (out[0] != out[out.size() - 1]) {
|
if (out[0] != out[out.size() - 1]) {
|
||||||
fprintf(stderr, "Ring not closed???\n");
|
fprintf(stderr, "Ring not closed???\n");
|
||||||
exit(EXIT_IMPOSSIBLE);
|
exit(EXIT_IMPOSSIBLE);
|
||||||
@@ -621,15 +640,41 @@ bool encloses(ring_area const &parent, ring_area const &child) {
|
|||||||
exit(EXIT_IMPOSSIBLE);
|
exit(EXIT_IMPOSSIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the edges of the child polygon are supposedly entirely contained within the parent
|
bool a = pnpoly(parent.geom, 0, parent.geom.size(), child.ear_x, child.ear_y);
|
||||||
// (although the vertices may not be), so check the middle of an edge.
|
|
||||||
long long x = (child.geom[0].x + child.geom[1].x) / 2;
|
|
||||||
long long y = (child.geom[0].y + child.geom[1].y) / 2;
|
|
||||||
|
|
||||||
return pnpoly(parent.geom, 0, parent.geom.size(), x, y);
|
#if 0
|
||||||
|
if (a != b) {
|
||||||
|
fprintf(stderr, "inconsistent pnpoly at %lld,%lld (%d) vs %lld,%lld (%d)\n", x, y, a, x2, y2, b);
|
||||||
|
|
||||||
|
printf("0 setlinewidth ");
|
||||||
|
for (auto const &g : parent.geom) {
|
||||||
|
printf("%lld %lld %s ", g.x, g.y, g.op == VT_MOVETO ? "moveto" : "lineto");
|
||||||
|
}
|
||||||
|
printf("stroke\n");
|
||||||
|
for (auto const &g : parent.geom) {
|
||||||
|
printf("%lld %lld .05 0 360 arc fill ", g.x, g.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const &g : child.geom) {
|
||||||
|
printf("%f %f %s ", g.x + 0.25, g.y + 0.25, g.op == VT_MOVETO ? "moveto" : "lineto");
|
||||||
|
}
|
||||||
|
printf("stroke\n");
|
||||||
|
|
||||||
|
printf("%lld %lld .5 0 360 arc fill\n", x, y);
|
||||||
|
printf("%lld %lld .5 0 360 arc fill\n", x2, y2);
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void flatten_rings(std::vector<ring_area> &rings, size_t i, drawvec &out, ssize_t winding, ssize_t parent) {
|
void flatten_rings(std::vector<ring_area> &rings, size_t i, drawvec &out, ssize_t winding, ssize_t parent) {
|
||||||
|
if (rings[i].geom.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// only the transition from winding order 0 to 1 or from 1 to 0
|
// only the transition from winding order 0 to 1 or from 1 to 0
|
||||||
// is actually represented in the geometry.
|
// is actually represented in the geometry.
|
||||||
//
|
//
|
||||||
@@ -638,7 +683,7 @@ void flatten_rings(std::vector<ring_area> &rings, size_t i, drawvec &out, ssize_
|
|||||||
if ((winding == 0 && rings[i].area > 0) ||
|
if ((winding == 0 && rings[i].area > 0) ||
|
||||||
(winding == 1 && rings[i].area < 0)) {
|
(winding == 1 && rings[i].area < 0)) {
|
||||||
for (auto const &g : rings[i].geom) {
|
for (auto const &g : rings[i].geom) {
|
||||||
out.emplace_back(g.op, g.x / 2, g.y / 2);
|
out.emplace_back(g.op, g.x / SCALE, g.y / SCALE);
|
||||||
}
|
}
|
||||||
if (rings[i].geom.size() > 0 && rings[i].geom[0] != rings[i].geom[rings[i].geom.size() - 1]) {
|
if (rings[i].geom.size() > 0 && rings[i].geom[0] != rings[i].geom[rings[i].geom.size() - 1]) {
|
||||||
fprintf(stderr, "Ring not closed\n");
|
fprintf(stderr, "Ring not closed\n");
|
||||||
@@ -655,6 +700,12 @@ void flatten_rings(std::vector<ring_area> &rings, size_t i, drawvec &out, ssize_
|
|||||||
winding--;
|
winding--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "ring %zu contains rings:", i);
|
||||||
|
for (size_t j = 0; j < rings[i].children.size(); j++) {
|
||||||
|
fprintf(stderr, " %zu", rings[i].children[j]);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
for (size_t j = 0; j < rings[i].children.size(); j++) {
|
for (size_t j = 0; j < rings[i].children.size(); j++) {
|
||||||
flatten_rings(rings, rings[i].children[j], out, winding, i);
|
flatten_rings(rings, rings[i].children[j], out, winding, i);
|
||||||
}
|
}
|
||||||
@@ -706,8 +757,28 @@ drawvec clean_polygon(drawvec const &geom, int z, int detail) {
|
|||||||
for (size_t i = 0; i < rings.size(); i++) { // from largest to smallest abs area
|
for (size_t i = 0; i < rings.size(); i++) { // from largest to smallest abs area
|
||||||
for (ssize_t j = i - 1; j >= 0; j--) { // from smallest to largest abs area of already examined
|
for (ssize_t j = i - 1; j >= 0; j--) { // from smallest to largest abs area of already examined
|
||||||
if (encloses(rings[j], rings[i])) {
|
if (encloses(rings[j], rings[i])) {
|
||||||
printf("ring %zd (%f) encloses ring %zu (%f)\n", j, rings[j].area, i, rings[i].area);
|
if (rings[i].area < 0 && rings[j].area > 0) {
|
||||||
rings[j].children.push_back(i);
|
// inner ring inside an outer ring;
|
||||||
|
// attribute it to the outer ring
|
||||||
|
rings[j].children.push_back(i);
|
||||||
|
#if 0
|
||||||
|
fprintf(stderr, "inner within outer: ring %zd (%f) encloses ring %zu (%f) %s\n", j, rings[j].area, i, rings[i].area,
|
||||||
|
signbit(rings[j].area) == signbit(rings[i].area) ? "!!!!" : "");
|
||||||
|
#endif
|
||||||
|
} else if (rings[i].area < 0 && rings[j].area < 0) {
|
||||||
|
fprintf(stderr, "inner within inner: ring %zd (%f) encloses ring %zu (%f) %s\n", j, rings[j].area, i, rings[i].area,
|
||||||
|
signbit(rings[j].area) == signbit(rings[i].area) ? "!!!!" : "");
|
||||||
|
rings[i].geom.clear();
|
||||||
|
} else if (rings[i].area > 0 && rings[j].area > 0) {
|
||||||
|
fprintf(stderr, "outer within outer: ring %zd (%f) encloses ring %zu (%f) %s\n", j, rings[j].area, i, rings[i].area,
|
||||||
|
signbit(rings[j].area) == signbit(rings[i].area) ? "!!!!" : "");
|
||||||
|
rings[i].geom.clear();
|
||||||
|
} else {
|
||||||
|
// outer ring within an inner ring;
|
||||||
|
// this is OK, but it is treated as a new outer ring in the tile,
|
||||||
|
// not output in a hierarchy
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -715,9 +786,27 @@ drawvec clean_polygon(drawvec const &geom, int z, int detail) {
|
|||||||
|
|
||||||
drawvec ret;
|
drawvec ret;
|
||||||
for (size_t i = 0; i < rings.size(); i++) {
|
for (size_t i = 0; i < rings.size(); i++) {
|
||||||
flatten_rings(rings, i, ret, 0, -1);
|
for (auto const &g : rings[i].geom) {
|
||||||
|
ret.emplace_back(g.op, g.x / SCALE, g.y / SCALE);
|
||||||
|
}
|
||||||
|
for (auto child : rings[i].children) {
|
||||||
|
for (auto const &g : rings[child].geom) {
|
||||||
|
ret.emplace_back(g.op, g.x / SCALE, g.y / SCALE);
|
||||||
|
}
|
||||||
|
rings[child].geom.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (size_t i = 0; i < rings.size(); i++) {
|
||||||
|
if (get_area(rings[i].geom, 0, rings[i].geom.size()) > 0) {
|
||||||
|
for (auto const &g : rings[i].geom) {
|
||||||
|
ret.emplace_back(g.op, g.x / SCALE, g.y / SCALE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// remove collinear points?
|
// remove collinear points?
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
Reference in New Issue
Block a user