diff --git a/geometry.cpp b/geometry.cpp index 3d2cd7be..e176aaa5 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -559,16 +559,16 @@ drawvec close_poly(drawvec &geom) { // @@@ static bool inside(std::pair 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 d, int edge, long long minx, long l static std::pair intersect(std::pair a, std::pair 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((a.first + (double) (b.first - a.first) * (miny - a.second) / (b.second - a.second)), miny); - case 1: // right + case 1: // right return std::pair(maxx, (a.second + (double) (b.second - a.second) * (maxx - a.first) / (b.first - a.first))); - case 2: // bottom + case 2: // bottom return std::pair((a.first + (double) (b.first - a.first) * (maxy - a.second) / (b.second - a.second)), maxy); - case 3: // left + case 3: // left return std::pair(minx, (a.second + (double) (b.second - a.second) * (minx - a.first) / (b.first - a.first))); } @@ -596,7 +596,9 @@ static std::pair intersect(std::pair a, std::pai } // http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm -static std::vector> clip_poly1(std::vector> &geom, long long minx, long long miny, long long maxx, long long maxy) { +static std::vector> clip_poly1(std::vector> &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> out = geom; for (int edge = 0; edge < 4; edge++) { @@ -609,13 +611,60 @@ static std::vector> clip_poly1(std::vector 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> clip_poly1(std::vector 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 chop_polygon(std::vector &geoms) { while (1) { bool again = false; @@ -1364,6 +1421,7 @@ std::vector chop_polygon(std::vector &geoms) { geoms = out; } } +#endif // @@@ #define INSIDE 0 diff --git a/geometry.hpp b/geometry.hpp index 1cff1768..611b4628 100644 --- a/geometry.hpp +++ b/geometry.hpp @@ -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); diff --git a/tile.cpp b/tile.cpp index 42536de9..36121eec 100644 --- a/tile.cpp +++ b/tile.cpp @@ -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 const &exclude_ } } -serial_feature next_feature(decompressor *geoms, std::atomic *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 *along, long long alongminus, int buffer, int *within, compressor **geomfile, std::atomic *geompos, std::atomic *oprogress, double todo, const char *fname, int child_shards, struct json_object *filter, const char *stringpool, long long *pool_off, std::vector> *layer_unmaps, bool first_time, bool compressed) { +serial_feature next_feature(decompressor *geoms, std::atomic *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 *along, long long alongminus, int buffer, int *within, compressor **geomfile, std::atomic *geompos, std::atomic *oprogress, double todo, const char *fname, int child_shards, struct json_object *filter, const char *stringpool, long long *pool_off, std::vector> *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 *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 *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); }