mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Track nodes added at tile edges during clipping
This commit is contained in:
+77
-19
@@ -559,16 +559,16 @@ drawvec close_poly(drawvec &geom) {
|
||||
// @@@
|
||||
static bool inside(std::pair<double, double> d, int edge, long long minx, long long miny, long long maxx, long long maxy) {
|
||||
switch (edge) {
|
||||
case 0: // top
|
||||
case 0: // top
|
||||
return d.second > miny;
|
||||
|
||||
case 1: // right
|
||||
case 1: // right
|
||||
return d.first < maxx;
|
||||
|
||||
case 2: // bottom
|
||||
case 2: // bottom
|
||||
return d.second < maxy;
|
||||
|
||||
case 3: // left
|
||||
case 3: // left
|
||||
return d.first > minx;
|
||||
}
|
||||
|
||||
@@ -578,16 +578,16 @@ static bool inside(std::pair<double, double> d, int edge, long long minx, long l
|
||||
|
||||
static std::pair<double, double> intersect(std::pair<double, double> a, std::pair<double, double> b, int edge, long long minx, long long miny, long long maxx, long long maxy) {
|
||||
switch (edge) {
|
||||
case 0: // top
|
||||
case 0: // top
|
||||
return std::pair<double, double>((a.first + (double) (b.first - a.first) * (miny - a.second) / (b.second - a.second)), miny);
|
||||
|
||||
case 1: // right
|
||||
case 1: // right
|
||||
return std::pair<double, double>(maxx, (a.second + (double) (b.second - a.second) * (maxx - a.first) / (b.first - a.first)));
|
||||
|
||||
case 2: // bottom
|
||||
case 2: // bottom
|
||||
return std::pair<double, double>((a.first + (double) (b.first - a.first) * (maxy - a.second) / (b.second - a.second)), maxy);
|
||||
|
||||
case 3: // left
|
||||
case 3: // left
|
||||
return std::pair<double, double>(minx, (a.second + (double) (b.second - a.second) * (minx - a.first) / (b.first - a.first)));
|
||||
}
|
||||
|
||||
@@ -596,7 +596,9 @@ static std::pair<double, double> intersect(std::pair<double, double> a, std::pai
|
||||
}
|
||||
|
||||
// http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
|
||||
static std::vector<std::pair<double, double>> clip_poly1(std::vector<std::pair<double, double>> &geom, long long minx, long long miny, long long maxx, long long maxy) {
|
||||
static std::vector<std::pair<double, double>> clip_poly1(std::vector<std::pair<double, double>> &geom,
|
||||
long long minx, long long miny, long long maxx, long long maxy,
|
||||
long long ax, long long ay, long long bx, long long by, drawvec &edge_nodes) {
|
||||
std::vector<std::pair<double, double>> out = geom;
|
||||
|
||||
for (int edge = 0; edge < 4; edge++) {
|
||||
@@ -609,13 +611,60 @@ static std::vector<std::pair<double, double>> clip_poly1(std::vector<std::pair<d
|
||||
for (size_t e = 0; e < in.size(); e++) {
|
||||
std::pair<double, double> E = in[e];
|
||||
|
||||
if (inside(E, edge, minx, miny, maxx, maxy)) {
|
||||
if (!inside(S, edge, minx, miny, maxx, maxy)) {
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy));
|
||||
if (!inside(S, edge, minx, miny, maxx, maxy)) {
|
||||
// was outside the buffer
|
||||
|
||||
if (!inside(E, edge, minx, miny, maxx, maxy)) {
|
||||
// still outside the buffer
|
||||
} else if (!inside(E, edge, ax, ay, bx, by)) {
|
||||
// outside the tile but inside the buffer
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy)); // on buffer edge
|
||||
out.push_back(E);
|
||||
} else {
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy)); // on buffer edge
|
||||
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
|
||||
out.push_back(intersect(S, E, edge, ax, ay, bx, by)); // on tile boundary
|
||||
edge_nodes.push_back(draw(VT_MOVETO, std::round(out.back().first), std::round(out.back().second)));
|
||||
}
|
||||
out.push_back(E);
|
||||
}
|
||||
} else if (!inside(S, edge, ax, ay, bx, by)) {
|
||||
// was inside the buffer but outside the tile edge
|
||||
|
||||
if (!inside(E, edge, minx, miny, maxx, maxy)) {
|
||||
// now outside the buffer
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy)); // on buffer edge
|
||||
} else if (!inside(E, edge, ax, ay, bx, by)) {
|
||||
// still outside the tile edge but inside the buffer
|
||||
out.push_back(E);
|
||||
} else {
|
||||
// now inside the tile
|
||||
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
|
||||
out.push_back(intersect(S, E, edge, ax, ay, bx, by)); // on tile boundary
|
||||
edge_nodes.push_back(draw(VT_MOVETO, std::round(out.back().first), std::round(out.back().second)));
|
||||
}
|
||||
out.push_back(E);
|
||||
}
|
||||
} else {
|
||||
// was inside the tile
|
||||
|
||||
if (!inside(E, edge, minx, miny, maxx, maxy)) {
|
||||
// now outside the buffer
|
||||
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
|
||||
out.push_back(intersect(S, E, edge, ax, ay, bx, by)); // on tile boundary
|
||||
}
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy)); // on buffer edge
|
||||
} else if (!inside(E, edge, ax, ay, bx, by)) {
|
||||
// now inside the buffer but outside the tile edge
|
||||
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
|
||||
out.push_back(intersect(S, E, edge, ax, ay, bx, by)); // on tile boundary
|
||||
edge_nodes.push_back(draw(VT_MOVETO, std::round(out.back().first), std::round(out.back().second)));
|
||||
}
|
||||
out.push_back(E);
|
||||
} else {
|
||||
// still inside the tile
|
||||
out.push_back(E);
|
||||
}
|
||||
out.push_back(E);
|
||||
} else if (inside(S, edge, minx, miny, maxx, maxy)) {
|
||||
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy));
|
||||
}
|
||||
|
||||
S = E;
|
||||
@@ -643,7 +692,8 @@ static std::vector<std::pair<double, double>> clip_poly1(std::vector<std::pair<d
|
||||
return out;
|
||||
}
|
||||
|
||||
drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
|
||||
drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy,
|
||||
long long ax, long long ay, long long bx, long long by, drawvec &shared_nodes) {
|
||||
drawvec out;
|
||||
|
||||
for (size_t i = 0; i < geom.size(); i++) {
|
||||
@@ -661,7 +711,7 @@ drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long lon
|
||||
double y = geom[k].y;
|
||||
tmp.emplace_back(x, y);
|
||||
}
|
||||
tmp = clip_poly1(tmp, minx, miny, maxx, maxy);
|
||||
tmp = clip_poly1(tmp, minx, miny, maxx, maxy, ax, ay, bx, by, shared_nodes);
|
||||
if (tmp.size() > 0) {
|
||||
if (tmp[0].first != tmp[tmp.size() - 1].first || tmp[0].second != tmp[tmp.size() - 1].second) {
|
||||
fprintf(stderr, "Internal error: Polygon ring not closed\n");
|
||||
@@ -686,11 +736,17 @@ drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long lon
|
||||
return out;
|
||||
}
|
||||
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer) {
|
||||
drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
|
||||
drawvec dv;
|
||||
return simple_clip_poly(geom, minx, miny, maxx, maxy, minx, miny, maxx, maxy, dv);
|
||||
}
|
||||
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &shared_nodes) {
|
||||
long long area = 1LL << (32 - z);
|
||||
long long clip_buffer = buffer * area / 256;
|
||||
|
||||
return simple_clip_poly(geom, -clip_buffer, -clip_buffer, area + clip_buffer, area + clip_buffer);
|
||||
return simple_clip_poly(geom, -clip_buffer, -clip_buffer, area + clip_buffer, area + clip_buffer,
|
||||
0, 0, area, area, shared_nodes);
|
||||
}
|
||||
// @@@
|
||||
|
||||
@@ -1286,6 +1342,7 @@ drawvec fix_polygon(drawvec &geom) {
|
||||
return out;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::vector<drawvec> chop_polygon(std::vector<drawvec> &geoms) {
|
||||
while (1) {
|
||||
bool again = false;
|
||||
@@ -1364,6 +1421,7 @@ std::vector<drawvec> chop_polygon(std::vector<drawvec> &geoms) {
|
||||
geoms = out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// @@@
|
||||
#define INSIDE 0
|
||||
|
||||
+3
-1
@@ -66,7 +66,7 @@ drawvec from_tile_scale(drawvec const &geom, int z, int detail);
|
||||
drawvec remove_noop(drawvec geom, int type, int shift);
|
||||
drawvec clip_point(drawvec &geom, int z, long long buffer);
|
||||
drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip);
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer);
|
||||
drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &shared_nodes);
|
||||
drawvec close_poly(drawvec &geom);
|
||||
drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *still_needs_simplification, bool *reduced_away, double *accum_area, serial_feature *this_feature, serial_feature *tiny_feature);
|
||||
int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax);
|
||||
@@ -85,6 +85,8 @@ drawvec polygon_to_anchor(const drawvec &geom);
|
||||
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned long long label_point);
|
||||
|
||||
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
|
||||
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2,
|
||||
long long ax, long long ay, long long bx, long long by, drawvec &shared_nodes);
|
||||
drawvec clip_lines(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
|
||||
drawvec clip_point(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
|
||||
void visvalingam(drawvec &ls, size_t start, size_t end, double threshold, size_t retain);
|
||||
|
||||
@@ -1343,7 +1343,7 @@ struct write_tile_args {
|
||||
bool compressed;
|
||||
};
|
||||
|
||||
bool clip_to_tile(serial_feature &sf, int z, long long buffer) {
|
||||
bool clip_to_tile(serial_feature &sf, int z, long long buffer, drawvec &shared_nodes) {
|
||||
int quick = quick_check(sf.bbox, z, buffer);
|
||||
|
||||
if (z == 0) {
|
||||
@@ -1389,7 +1389,7 @@ bool clip_to_tile(serial_feature &sf, int z, long long buffer) {
|
||||
clipped = clip_lines(sf.geometry, z, buffer);
|
||||
}
|
||||
if (sf.t == VT_POLYGON) {
|
||||
clipped = simple_clip_poly(sf.geometry, z, buffer);
|
||||
clipped = simple_clip_poly(sf.geometry, z, buffer, shared_nodes);
|
||||
}
|
||||
if (sf.t == VT_POINT) {
|
||||
clipped = clip_point(sf.geometry, z, buffer);
|
||||
@@ -1438,7 +1438,7 @@ void remove_attributes(serial_feature &sf, std::set<std::string> const &exclude_
|
||||
}
|
||||
}
|
||||
|
||||
serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos_in, int z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y, long long *original_features, long long *unclipped_features, int nextzoom, int maxzoom, int minzoom, int max_zoom_increment, size_t pass, std::atomic<long long> *along, long long alongminus, int buffer, int *within, compressor **geomfile, std::atomic<long long> *geompos, std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, struct json_object *filter, const char *stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool compressed) {
|
||||
serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos_in, int z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y, long long *original_features, long long *unclipped_features, int nextzoom, int maxzoom, int minzoom, int max_zoom_increment, size_t pass, std::atomic<long long> *along, long long alongminus, int buffer, int *within, compressor **geomfile, std::atomic<long long> *geompos, std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, struct json_object *filter, const char *stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool compressed, drawvec &shared_nodes) {
|
||||
while (1) {
|
||||
serial_feature sf;
|
||||
std::string s;
|
||||
@@ -1481,7 +1481,7 @@ serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos
|
||||
|
||||
(*original_features)++;
|
||||
|
||||
if (clip_to_tile(sf, z, buffer)) {
|
||||
if (clip_to_tile(sf, z, buffer, shared_nodes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1630,7 +1630,8 @@ void *run_prefilter(void *v) {
|
||||
json_writer state(rpa->prefilter_fp);
|
||||
|
||||
while (1) {
|
||||
serial_feature sf = next_feature(rpa->geoms, rpa->geompos_in, rpa->z, rpa->tx, rpa->ty, rpa->initial_x, rpa->initial_y, rpa->original_features, rpa->unclipped_features, rpa->nextzoom, rpa->maxzoom, rpa->minzoom, rpa->max_zoom_increment, rpa->pass, rpa->along, rpa->alongminus, rpa->buffer, rpa->within, rpa->geomfile, rpa->geompos, rpa->oprogress, rpa->todo, rpa->fname, rpa->child_shards, rpa->filter, rpa->stringpool, rpa->pool_off, rpa->layer_unmaps, rpa->first_time, rpa->compressed);
|
||||
drawvec dv; // don't have a way to track tile-edge nodes through prefilter
|
||||
serial_feature sf = next_feature(rpa->geoms, rpa->geompos_in, rpa->z, rpa->tx, rpa->ty, rpa->initial_x, rpa->initial_y, rpa->original_features, rpa->unclipped_features, rpa->nextzoom, rpa->maxzoom, rpa->minzoom, rpa->max_zoom_increment, rpa->pass, rpa->along, rpa->alongminus, rpa->buffer, rpa->within, rpa->geomfile, rpa->geompos, rpa->oprogress, rpa->todo, rpa->fname, rpa->child_shards, rpa->filter, rpa->stringpool, rpa->pool_off, rpa->layer_unmaps, rpa->first_time, rpa->compressed, dv);
|
||||
if (sf.t < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -2043,7 +2044,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
ssize_t which_partial = -1;
|
||||
|
||||
if (prefilter == NULL) {
|
||||
sf = next_feature(geoms, geompos_in, z, tx, ty, initial_x, initial_y, &original_features, &unclipped_features, nextzoom, maxzoom, minzoom, max_zoom_increment, pass, along, alongminus, buffer, within, geomfile, geompos, &oprogress, todo, fname, child_shards, filter, stringpool, pool_off, layer_unmaps, first_time, compressed_input);
|
||||
sf = next_feature(geoms, geompos_in, z, tx, ty, initial_x, initial_y, &original_features, &unclipped_features, nextzoom, maxzoom, minzoom, max_zoom_increment, pass, along, alongminus, buffer, within, geomfile, geompos, &oprogress, todo, fname, child_shards, filter, stringpool, pool_off, layer_unmaps, first_time, compressed_input, shared_nodes);
|
||||
} else {
|
||||
sf = parse_feature(prefilter_jp, z, tx, ty, layermaps, tiling_seg, layer_unmaps, postfilter != NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user