mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-01-22 12:28:03 +00:00
Bring back the old simple polygon clipping algorithm
This commit is contained in:
parent
32111af79d
commit
f43d18eb73
157
geometry.cc
157
geometry.cc
@ -341,6 +341,163 @@ drawvec close_poly(drawvec &geom) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool inside(draw d, int edge, long long area, long long buffer) {
|
||||||
|
long long clip_buffer = buffer * area / 256;
|
||||||
|
|
||||||
|
switch (edge) {
|
||||||
|
case 0: // top
|
||||||
|
return d.y > -clip_buffer;
|
||||||
|
|
||||||
|
case 1: // right
|
||||||
|
return d.x < area + clip_buffer;
|
||||||
|
|
||||||
|
case 2: // bottom
|
||||||
|
return d.y < area + clip_buffer;
|
||||||
|
|
||||||
|
case 3: // left
|
||||||
|
return d.x > -clip_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "internal error inside\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||||
|
static draw get_line_intersection(draw p0, draw p1, draw p2, draw p3) {
|
||||||
|
double s1_x = p1.x - p0.x;
|
||||||
|
double s1_y = p1.y - p0.y;
|
||||||
|
double s2_x = p3.x - p2.x;
|
||||||
|
double s2_y = p3.y - p2.y;
|
||||||
|
|
||||||
|
double t;
|
||||||
|
// s = (-s1_y * (p0.x - p2.x) + s1_x * (p0.y - p2.y)) / (-s2_x * s1_y + s1_x * s2_y);
|
||||||
|
t = (s2_x * (p0.y - p2.y) - s2_y * (p0.x - p2.x)) / (-s2_x * s1_y + s1_x * s2_y);
|
||||||
|
|
||||||
|
return draw(VT_LINETO, p0.x + (t * s1_x), p0.y + (t * s1_y));
|
||||||
|
}
|
||||||
|
|
||||||
|
static draw intersect(draw a, draw b, int edge, long long area, long long buffer) {
|
||||||
|
long long clip_buffer = buffer * area / 256;
|
||||||
|
|
||||||
|
switch (edge) {
|
||||||
|
case 0: // top
|
||||||
|
return get_line_intersection(a, b, draw(VT_MOVETO, -clip_buffer, -clip_buffer), draw(VT_MOVETO, area + clip_buffer, -clip_buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // right
|
||||||
|
return get_line_intersection(a, b, draw(VT_MOVETO, area + clip_buffer, -clip_buffer), draw(VT_MOVETO, area + clip_buffer, area + clip_buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // bottom
|
||||||
|
return get_line_intersection(a, b, draw(VT_MOVETO, area + clip_buffer, area + clip_buffer), draw(VT_MOVETO, -clip_buffer, area + clip_buffer));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // left
|
||||||
|
return get_line_intersection(a, b, draw(VT_MOVETO, -clip_buffer, area + clip_buffer), draw(VT_MOVETO, -clip_buffer, -clip_buffer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "internal error intersecting\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
|
||||||
|
static drawvec clip_poly1(drawvec &geom, int z, int detail, int buffer) {
|
||||||
|
drawvec out = geom;
|
||||||
|
|
||||||
|
long long area = 0xFFFFFFFF;
|
||||||
|
if (z != 0) {
|
||||||
|
area = 1LL << (32 - z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int edge = 0; edge < 4; edge++) {
|
||||||
|
if (out.size() > 0) {
|
||||||
|
drawvec in = out;
|
||||||
|
out.resize(0);
|
||||||
|
|
||||||
|
draw S = in[in.size() - 1];
|
||||||
|
|
||||||
|
for (unsigned e = 0; e < in.size(); e++) {
|
||||||
|
draw E = in[e];
|
||||||
|
|
||||||
|
if (inside(E, edge, area, buffer)) {
|
||||||
|
if (!inside(S, edge, area, buffer)) {
|
||||||
|
out.push_back(intersect(S, E, edge, area, buffer));
|
||||||
|
}
|
||||||
|
out.push_back(E);
|
||||||
|
} else if (inside(S, edge, area, buffer)) {
|
||||||
|
out.push_back(intersect(S, E, edge, area, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
S = E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.size() > 0) {
|
||||||
|
// If the polygon begins and ends outside the edge,
|
||||||
|
// the starting and ending points will be left as the
|
||||||
|
// places where it intersects the edge. Need to add
|
||||||
|
// another point to close the loop.
|
||||||
|
|
||||||
|
if (out[0].x != out[out.size() - 1].x || out[0].y != out[out.size() - 1].y) {
|
||||||
|
out.push_back(out[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.size() < 3) {
|
||||||
|
fprintf(stderr, "Polygon degenerated to a line segment\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
out[0].op = VT_MOVETO;
|
||||||
|
for (unsigned i = 1; i < out.size(); i++) {
|
||||||
|
out[i].op = VT_LINETO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawvec simple_clip_poly(drawvec &geom, int z, int detail, int buffer) {
|
||||||
|
if (z == 0) {
|
||||||
|
return geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawvec out;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < geom.size(); i++) {
|
||||||
|
if (geom[i].op == VT_MOVETO) {
|
||||||
|
unsigned j;
|
||||||
|
for (j = i + 1; j < geom.size(); j++) {
|
||||||
|
if (geom[j].op != VT_LINETO) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawvec tmp;
|
||||||
|
for (unsigned k = i; k < j; k++) {
|
||||||
|
tmp.push_back(geom[k]);
|
||||||
|
}
|
||||||
|
tmp = clip_poly1(tmp, z, detail, buffer);
|
||||||
|
if (tmp.size() > 0) {
|
||||||
|
if (tmp[0].x != tmp[tmp.size() - 1].x || tmp[0].y != tmp[tmp.size() - 1].y) {
|
||||||
|
fprintf(stderr, "Internal error: Polygon ring not closed\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned k = 0; k < tmp.size(); k++) {
|
||||||
|
out.push_back(tmp[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = j - 1;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unexpected operation in polygon %d\n", (int) geom[i].op);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double *accum_area) {
|
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double *accum_area) {
|
||||||
drawvec out;
|
drawvec out;
|
||||||
long long pixel = (1 << (32 - detail - z)) * 2;
|
long long pixel = (1 << (32 - detail - z)) * 2;
|
||||||
|
@ -21,6 +21,7 @@ void to_tile_scale(drawvec &geom, int z, int detail);
|
|||||||
drawvec remove_noop(drawvec geom, int type, int shift);
|
drawvec remove_noop(drawvec geom, int type, int shift);
|
||||||
drawvec clip_point(drawvec &geom, int z, int detail, long long buffer);
|
drawvec clip_point(drawvec &geom, int z, int detail, long long buffer);
|
||||||
drawvec clean_or_clip_poly(drawvec &geom, int z, int detail, int buffer, bool clip);
|
drawvec clean_or_clip_poly(drawvec &geom, int z, int detail, int buffer, bool clip);
|
||||||
|
drawvec simple_clip_poly(drawvec &geom, int z, int detail, int buffer);
|
||||||
drawvec close_poly(drawvec &geom);
|
drawvec close_poly(drawvec &geom);
|
||||||
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double *accum_area);
|
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double *accum_area);
|
||||||
drawvec clip_lines(drawvec &geom, int z, int detail, long long buffer);
|
drawvec clip_lines(drawvec &geom, int z, int detail, long long buffer);
|
||||||
|
Loading…
Reference in New Issue
Block a user