mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-06 18:35:41 +02:00
Fix the check for continuous polygons
This commit is contained in:
+22
-6
@@ -1427,7 +1427,7 @@ drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigne
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_continous_poly(drawvec const &geom, size_t i, size_t j, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
|
bool is_continuous_ring(drawvec const &geom, size_t i, size_t j, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
// j - 1 to avoid double-counting the duplicate last node
|
// j - 1 to avoid double-counting the duplicate last node
|
||||||
@@ -1435,6 +1435,7 @@ bool is_continous_poly(drawvec const &geom, size_t i, size_t j, int z, int tx, i
|
|||||||
if (is_shared_node(geom[i], z, tx, ty, shared_nodes_map, nodepos)) {
|
if (is_shared_node(geom[i], z, tx, ty, shared_nodes_map, nodepos)) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
|
// every ring will have three shared nodes; the fourth indicates a shared vertex
|
||||||
if (count >= 4) {
|
if (count >= 4) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1444,7 +1445,26 @@ bool is_continous_poly(drawvec const &geom, size_t i, size_t j, int z, int tx, i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawvec buffer_poly(drawvec const &geom, double buffer, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
|
bool is_continuous_poly(drawvec const &geom, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos) {
|
||||||
|
for (size_t i = 0; i < geom.size(); i++) {
|
||||||
|
if (geom[i].op == VT_MOVETO) {
|
||||||
|
size_t j;
|
||||||
|
for (j = i + 1; j < geom.size(); j++) {
|
||||||
|
if (geom[j].op != VT_LINETO) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_continuous_ring(geom, i, j, z, tx, ty, shared_nodes_map, nodepos)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawvec buffer_poly(drawvec const &geom, double buffer) {
|
||||||
drawvec out = geom;
|
drawvec out = geom;
|
||||||
|
|
||||||
if (buffer != 0) {
|
if (buffer != 0) {
|
||||||
@@ -1457,7 +1477,6 @@ drawvec buffer_poly(drawvec const &geom, double buffer, int z, int tx, int ty, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_continous_poly(geom, i, j, z, tx, ty, shared_nodes_map, nodepos)) {
|
|
||||||
for (size_t k = i; k < j - 1; k++) {
|
for (size_t k = i; k < j - 1; k++) {
|
||||||
draw p0 = geom[(k + 0 - i) % (j - i - 1) + i];
|
draw p0 = geom[(k + 0 - i) % (j - i - 1) + i];
|
||||||
draw p1 = geom[(k + 1 - i) % (j - i - 1) + i];
|
draw p1 = geom[(k + 1 - i) % (j - i - 1) + i];
|
||||||
@@ -1479,9 +1498,6 @@ drawvec buffer_poly(drawvec const &geom, double buffer, int z, int tx, int ty, s
|
|||||||
|
|
||||||
out[j - 1].x = out[i].x;
|
out[j - 1].x = out[i].x;
|
||||||
out[j - 1].y = out[i].y;
|
out[j - 1].y = out[i].y;
|
||||||
} else {
|
|
||||||
printf("skipping continuous ring %zu to %zu\n", i, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = j - 1;
|
i = j - 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -104,6 +104,7 @@ std::string overzoom(mvt_tile tile, int oz, int ox, int oy, int nz, int nx, int
|
|||||||
std::string overzoom(std::string s, int oz, int ox, int oy, int nz, int nx, int ny,
|
std::string overzoom(std::string s, int oz, int ox, int oy, int nz, int nx, int ny,
|
||||||
int detail, int buffer, std::set<std::string> const &keep, bool do_compress);
|
int detail, int buffer, std::set<std::string> const &keep, bool do_compress);
|
||||||
|
|
||||||
drawvec buffer_poly(drawvec const &geom, double buffer, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos);
|
drawvec buffer_poly(drawvec const &geom, double buffer);
|
||||||
|
bool is_continuous_poly(drawvec const &geom, int z, int tx, int ty, struct node *shared_nodes_map, size_t nodepos);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ std::string serialize_feature(serial_feature *sf, long long wx, long long wy) {
|
|||||||
serialize_int(s, sf->segment);
|
serialize_int(s, sf->segment);
|
||||||
|
|
||||||
write_geometry(sf->geometry, s, wx, wy);
|
write_geometry(sf->geometry, s, wx, wy);
|
||||||
|
serialize_byte(s, sf->continuous);
|
||||||
|
|
||||||
if (sf->index != 0) {
|
if (sf->index != 0) {
|
||||||
serialize_ulong_long(s, sf->index);
|
serialize_ulong_long(s, sf->index);
|
||||||
@@ -276,8 +277,10 @@ serial_feature deserialize_feature(std::string &geoms, unsigned z, unsigned tx,
|
|||||||
sf.index = 0;
|
sf.index = 0;
|
||||||
sf.label_point = 0;
|
sf.label_point = 0;
|
||||||
sf.extent = 0;
|
sf.extent = 0;
|
||||||
|
sf.continuous = -1; // unknown
|
||||||
|
|
||||||
sf.geometry = decode_geometry(&cp, z, tx, ty, sf.bbox, initial_x[sf.segment], initial_y[sf.segment]);
|
sf.geometry = decode_geometry(&cp, z, tx, ty, sf.bbox, initial_x[sf.segment], initial_y[sf.segment]);
|
||||||
|
deserialize_byte(&cp, &sf.continuous);
|
||||||
|
|
||||||
if (sf.layer & (1 << FLAG_INDEX)) {
|
if (sf.layer & (1 << FLAG_INDEX)) {
|
||||||
deserialize_ulong_long(&cp, &sf.index);
|
deserialize_ulong_long(&cp, &sf.index);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ struct serial_feature {
|
|||||||
|
|
||||||
signed char t = 0;
|
signed char t = 0;
|
||||||
signed char feature_minzoom = 0;
|
signed char feature_minzoom = 0;
|
||||||
|
signed char continuous = -1; // is this a continuous polygon?
|
||||||
|
|
||||||
bool has_id = false;
|
bool has_id = false;
|
||||||
unsigned long long id = 0;
|
unsigned long long id = 0;
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ struct ordercmp {
|
|||||||
}
|
}
|
||||||
} ordercmp;
|
} ordercmp;
|
||||||
|
|
||||||
void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, unsigned tx, unsigned ty, int buffer, int *within, std::atomic<long long> *geompos, compressor **geomfile, const char *fname, signed char t, int layer, signed char feature_minzoom, int child_shards, int max_zoom_increment, long long seq, int tippecanoe_minzoom, int tippecanoe_maxzoom, int segment, unsigned *initial_x, unsigned *initial_y, std::vector<long long> &metakeys, std::vector<long long> &metavals, bool has_id, unsigned long long id, unsigned long long index, unsigned long long label_point, long long extent) {
|
void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, unsigned tx, unsigned ty, int buffer, int *within, std::atomic<long long> *geompos, compressor **geomfile, const char *fname, signed char t, int layer, signed char feature_minzoom, int child_shards, int max_zoom_increment, long long seq, int tippecanoe_minzoom, int tippecanoe_maxzoom, int segment, unsigned *initial_x, unsigned *initial_y, std::vector<long long> &metakeys, std::vector<long long> &metavals, bool has_id, unsigned long long id, unsigned long long index, unsigned long long label_point, long long extent, signed char continuous) {
|
||||||
if (geom.size() > 0 && (nextzoom <= maxzoom || additional[A_EXTEND_ZOOMS] || extend_zooms_max > 0)) {
|
if (geom.size() > 0 && (nextzoom <= maxzoom || additional[A_EXTEND_ZOOMS] || extend_zooms_max > 0)) {
|
||||||
int xo, yo;
|
int xo, yo;
|
||||||
int span = 1 << (nextzoom - z);
|
int span = 1 << (nextzoom - z);
|
||||||
@@ -424,6 +424,7 @@ void rewrite(drawvec &geom, int z, int nextzoom, int maxzoom, long long *bbox, u
|
|||||||
sf.label_point = label_point;
|
sf.label_point = label_point;
|
||||||
sf.extent = extent;
|
sf.extent = extent;
|
||||||
sf.feature_minzoom = feature_minzoom;
|
sf.feature_minzoom = feature_minzoom;
|
||||||
|
sf.continuous = continuous;
|
||||||
|
|
||||||
for (size_t i = 0; i < metakeys.size(); i++) {
|
for (size_t i = 0; i < metakeys.size(); i++) {
|
||||||
sf.keys.push_back(metakeys[i]);
|
sf.keys.push_back(metakeys[i]);
|
||||||
@@ -474,6 +475,7 @@ struct partial {
|
|||||||
long long clustered = 0;
|
long long clustered = 0;
|
||||||
std::set<std::string> need_tilestats;
|
std::set<std::string> need_tilestats;
|
||||||
std::map<std::string, accum_state> attribute_accum_state;
|
std::map<std::string, accum_state> attribute_accum_state;
|
||||||
|
int continuous;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct partial_arg {
|
struct partial_arg {
|
||||||
@@ -613,8 +615,8 @@ void *partial_feature_worker(void *v) {
|
|||||||
|
|
||||||
drawvec geom = (*partials)[i].geoms[0];
|
drawvec geom = (*partials)[i].geoms[0];
|
||||||
|
|
||||||
if (additional[A_BUFFER_POLYGONS_OUTWARD] && t == VT_POLYGON) {
|
if (additional[A_BUFFER_POLYGONS_OUTWARD] && t == VT_POLYGON && !((*partials)[i].continuous)) {
|
||||||
geom = buffer_poly(geom, (1LL << (32 - z - out_detail)) * sqrt(2), z, (*partials)[i].tx, (*partials)[i].ty, a->shared_nodes_map, a->nodepos);
|
geom = buffer_poly(geom, (1LL << (32 - z - out_detail)) * sqrt(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
to_tile_scale(geom, z, out_detail);
|
to_tile_scale(geom, z, out_detail);
|
||||||
@@ -1461,7 +1463,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, struct node *shared_nodes_map, size_t nodepos) {
|
||||||
while (1) {
|
while (1) {
|
||||||
serial_feature sf;
|
serial_feature sf;
|
||||||
std::string s;
|
std::string s;
|
||||||
@@ -1512,9 +1514,21 @@ serial_feature next_feature(decompressor *geoms, std::atomic<long long> *geompos
|
|||||||
(*unclipped_features)++;
|
(*unclipped_features)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sf.t == VT_POLYGON && sf.continuous < 0) {
|
||||||
|
// figure out whether the polygon is continuous the first time it is examined,
|
||||||
|
// since we don't have access to all of the shared nodes to determine this
|
||||||
|
// when the feature is first being ingested
|
||||||
|
|
||||||
|
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
|
||||||
|
sf.continuous = is_continuous_poly(sf.geometry, z, tx, ty, shared_nodes_map, nodepos);
|
||||||
|
} else {
|
||||||
|
sf.continuous = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (first_time && pass == 0) { /* only write out the next zoom once, even if we retry */
|
if (first_time && pass == 0) { /* only write out the next zoom once, even if we retry */
|
||||||
if (sf.tippecanoe_maxzoom == -1 || sf.tippecanoe_maxzoom >= nextzoom) {
|
if (sf.tippecanoe_maxzoom == -1 || sf.tippecanoe_maxzoom >= nextzoom) {
|
||||||
rewrite(sf.geometry, z, nextzoom, maxzoom, sf.bbox, tx, ty, buffer, within, geompos, geomfile, fname, sf.t, sf.layer, sf.feature_minzoom, child_shards, max_zoom_increment, sf.seq, sf.tippecanoe_minzoom, sf.tippecanoe_maxzoom, sf.segment, initial_x, initial_y, sf.keys, sf.values, sf.has_id, sf.id, sf.index, sf.label_point, sf.extent);
|
rewrite(sf.geometry, z, nextzoom, maxzoom, sf.bbox, tx, ty, buffer, within, geompos, geomfile, fname, sf.t, sf.layer, sf.feature_minzoom, child_shards, max_zoom_increment, sf.seq, sf.tippecanoe_minzoom, sf.tippecanoe_maxzoom, sf.segment, initial_x, initial_y, sf.keys, sf.values, sf.has_id, sf.id, sf.index, sf.label_point, sf.extent, sf.continuous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1646,6 +1660,8 @@ struct run_prefilter_args {
|
|||||||
struct json_object *filter = NULL;
|
struct json_object *filter = NULL;
|
||||||
bool first_time = false;
|
bool first_time = false;
|
||||||
bool compressed = false;
|
bool compressed = false;
|
||||||
|
struct node *shared_nodes_map;
|
||||||
|
size_t nodepos;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *run_prefilter(void *v) {
|
void *run_prefilter(void *v) {
|
||||||
@@ -1653,7 +1669,7 @@ void *run_prefilter(void *v) {
|
|||||||
json_writer state(rpa->prefilter_fp);
|
json_writer state(rpa->prefilter_fp);
|
||||||
|
|
||||||
while (1) {
|
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);
|
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, rpa->shared_nodes_map, rpa->nodepos);
|
||||||
if (sf.t < 0) {
|
if (sf.t < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2047,6 +2063,8 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
|||||||
rpa.filter = filter;
|
rpa.filter = filter;
|
||||||
rpa.first_time = first_time;
|
rpa.first_time = first_time;
|
||||||
rpa.compressed = compressed_input;
|
rpa.compressed = compressed_input;
|
||||||
|
rpa.shared_nodes_map = shared_nodes_map;
|
||||||
|
rpa.nodepos = nodepos;
|
||||||
|
|
||||||
if (pthread_create(&prefilter_writer, NULL, run_prefilter, &rpa) != 0) {
|
if (pthread_create(&prefilter_writer, NULL, run_prefilter, &rpa) != 0) {
|
||||||
perror("pthread_create (prefilter writer)");
|
perror("pthread_create (prefilter writer)");
|
||||||
@@ -2066,7 +2084,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
|||||||
ssize_t which_partial = -1;
|
ssize_t which_partial = -1;
|
||||||
|
|
||||||
if (prefilter == NULL) {
|
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_map, nodepos);
|
||||||
} else {
|
} else {
|
||||||
sf = parse_feature(prefilter_jp, z, tx, ty, layermaps, tiling_seg, layer_unmaps, postfilter != NULL);
|
sf = parse_feature(prefilter_jp, z, tx, ty, layermaps, tiling_seg, layer_unmaps, postfilter != NULL);
|
||||||
}
|
}
|
||||||
@@ -2271,6 +2289,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
|||||||
p.renamed = -1;
|
p.renamed = -1;
|
||||||
p.extent = sf.extent;
|
p.extent = sf.extent;
|
||||||
p.clustered = 0;
|
p.clustered = 0;
|
||||||
|
p.continuous = sf.continuous;
|
||||||
|
|
||||||
if (line_detail == detail && extra_detail >= 0 && z == maxzoom) {
|
if (line_detail == detail && extra_detail >= 0 && z == maxzoom) {
|
||||||
p.extra_detail = extra_detail;
|
p.extra_detail = extra_detail;
|
||||||
|
|||||||
Reference in New Issue
Block a user