mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Keep variable-depth tile pyramids consistent when a zoom level has to drop features (#407)
* Only skip polygon cleaning if we are still at very high resolution * Remove collinear points and clean polygons even at high resolution * If we truncated but still have the data and need to drop, revive * Deduplicate by ID even when the duplicate is clipped away * Test that deduplication works across tile boundaries * Write out children of a tile revived after its parent truncated A tile writes the geometry for its children on pass 0 of its zoom level, and the later passes, which are only retries with new thresholds, must not write it again. But a tile whose parent truncated its pyramid is skipped on pass 0, and is only revived on a later pass, once the zoom has had to start dropping features. Gating on pass 0 meant its children were never written at all, so a revived tile was always a dead end: it appeared in the output at ordinary detail with nothing below it, even though its truncated ancestor still held the full-detail geometry. Write the children on whichever pass first tiles the tile instead. The dropping thresholds only ever increase within a zoom, so for a revived tile that is exactly the pass on which the zoom started dropping. Also collect the three thresholds into dropping_features(), since write_tile() and run_thread() have to agree about when truncation is disabled and when a skipped tile comes back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Treat dropping by attribute like the other ways of dropping features --drop-by-attribute-as-needed was added after variable-depth pyramids, and minattribute never made it into the test for whether a zoom level is discarding features. A zoom that was dropping by attribute could still truncate pyramids, so some of its tiles became full-detail leaves while the rest of the zoom had features dropped out of them, and tiles skipped because an ancestor had truncated stayed missing. Unlike the other thresholds, minattribute starts at the infinity on whichever side is being kept rather than at zero, so dropping_features() now takes the direction too. On tests/tl_2022_11_tract at -Z10 -M15000, zoom 11 was dropping by attribute and truncating two pyramids at the same time; now it truncates none of them and the tile that had been skipped under zoom 10's truncation is written out. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Delete the merged tile that the deduplication test leaves behind overzoom-test removes merged-dedup.pbf.json.check but not the merged-dedup.pbf it was decoded from, so the file was left in the working tree after every test run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Document what variable-depth pyramids now do to geometry and to dropping Truncated tiles are no longer left uncleaned: they keep every vertex that isn't collinear with its neighbors, but their polygons are cleaned so that overlapping areas are merged instead of stacked. Say so, and say that dropping features at a zoom level now suppresses truncation for the whole zoom rather than for individual tiles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Start minattribute out at the infinity that excludes nothing dropping_features() reads write_tile_args::minattribute, and the in-class default of 0 decodes as a threshold that has already been chosen. Every path assigns it from zoom_minattribute before anything reads it, so this changes no behavior, but a future one that didn't would silently suppress pyramid truncation rather than fail visibly. -HUGE_VAL is the value that excludes nothing for the ascending order that drop_by_attribute_descending also defaults to, so the two members agree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Regenerate the drop-by-attribute fixture through the test harness The Makefile can't be asked for a target whose name contains an =, since make reads that as a variable assignment, so this fixture was generated by hand into a scratch directory. The output path ends up in the tileset's name, description, and generator_options, and tippecanoe-decode is only passed -x generator, so all three were compared against the harness's .check.mbtiles path and could never match. make test failed on it. Regenerated with the same output path the rule uses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Restore the -z14 -M25000 variable-depth fixture This configuration was dropped rather than regenerated when the -z17 -M10000 fixture was added. It still runs, so it was losing a passing regression test for no stated reason. Regenerated against current behavior. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Encode the = in the drop-by-attribute fixture name as %3d A test output name containing an = can't be asked for on the make command line, because make reads that argument as a variable assignment, so the fixture couldn't be regenerated through its own rule. Add %3d to the punctuation escapes that testargs decodes and use it here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp * Regenerate the man page for the README change The variable-depth pyramid option's description changed, and man/tippecanoe.1 is generated from README.md, so the committed page no longer matched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KewFM6XCt5W9QBZkTZDjCp --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
734bba7c78
commit
63fcac725a
@@ -538,7 +538,6 @@ struct simplification_worker_arg {
|
||||
std::vector<std::shared_ptr<serial_feature>> *features = NULL;
|
||||
int task = 0;
|
||||
int tasks = 0;
|
||||
bool trying_to_stop_early = false;
|
||||
|
||||
drawvec *shared_nodes;
|
||||
node *shared_nodes_map;
|
||||
@@ -673,9 +672,7 @@ static void *simplification_worker(void *v) {
|
||||
|
||||
for (size_t i = a->task; i < (*features).size(); i += a->tasks) {
|
||||
double area = 0;
|
||||
if (!a->trying_to_stop_early) {
|
||||
area = simplify_feature(&*((*features)[i]), *(a->shared_nodes), a->shared_nodes_map, a->nodepos, *(a->shared_nodes_bloom));
|
||||
}
|
||||
area = simplify_feature(&*((*features)[i]), *(a->shared_nodes), a->shared_nodes_map, a->nodepos, *(a->shared_nodes_bloom));
|
||||
|
||||
signed char t = (*features)[i]->t;
|
||||
int z = (*features)[i]->z;
|
||||
@@ -690,20 +687,18 @@ static void *simplification_worker(void *v) {
|
||||
{
|
||||
drawvec before = geom;
|
||||
|
||||
if (!a->trying_to_stop_early) {
|
||||
// we can try scaling up because this is now tile scale
|
||||
coalesce_polygon(geom, true);
|
||||
if (additional[A_DEBUG_POLYGON]) {
|
||||
check_polygon(geom);
|
||||
}
|
||||
// we can try scaling up because this is now tile scale
|
||||
coalesce_polygon(geom, true);
|
||||
if (additional[A_DEBUG_POLYGON]) {
|
||||
check_polygon(geom);
|
||||
}
|
||||
|
||||
if (geom.size() < 3) {
|
||||
if (area > 0) {
|
||||
// area is in world coordinates, calculated before scaling down
|
||||
geom = revive_polygon(before, area, z, out_detail);
|
||||
} else {
|
||||
geom.clear();
|
||||
}
|
||||
if (geom.size() < 3) {
|
||||
if (area > 0) {
|
||||
// area is in world coordinates, calculated before scaling down
|
||||
geom = revive_polygon(before, area, z, out_detail);
|
||||
} else {
|
||||
geom.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -926,8 +921,12 @@ struct write_tile_args {
|
||||
long long minextent_out = 0;
|
||||
unsigned long long mindrop_sequence = 0;
|
||||
unsigned long long mindrop_sequence_out = 0;
|
||||
double minattribute = 0;
|
||||
double minattribute_out = 0;
|
||||
// the infinity that excludes nothing, for the ascending order that
|
||||
// drop_by_attribute_descending also defaults to. dropping_features()
|
||||
// reads these, so they must not start out at a value that looks like
|
||||
// a threshold that has already been chosen.
|
||||
double minattribute = -HUGE_VAL;
|
||||
double minattribute_out = -HUGE_VAL;
|
||||
std::string const *drop_by_attribute_as_needed_attribute = NULL;
|
||||
bool drop_by_attribute_descending = false;
|
||||
size_t tile_size_out = 0;
|
||||
@@ -949,8 +948,26 @@ struct write_tile_args {
|
||||
std::string const *shared_nodes_bloom;
|
||||
std::set<zxy> const *skip_children; // what is being skipped at this zoom
|
||||
std::set<zxy> skip_children_out; // what will be skipped in the next zoom
|
||||
bool first_dropping_pass = false; // is this the first pass of this zoom that is dropping features?
|
||||
};
|
||||
|
||||
// Is this zoom level discarding features to make its tiles fit? The thresholds
|
||||
// start out excluding nothing, and only move inward once some tile in the zoom
|
||||
// fails to fit and the whole zoom is retried with a threshold for discarding
|
||||
// features. For mingap, minextent, and mindrop_sequence that starting point is
|
||||
// zero; for minattribute it is the infinity on whichever side is being kept.
|
||||
//
|
||||
// Pyramid truncation is disabled while this is true, so that every tile in the
|
||||
// zoom is reduced consistently, and tiles that were skipped because an ancestor
|
||||
// truncated its pyramid are revived.
|
||||
static bool dropping_features(unsigned long long mingap, long long minextent, unsigned long long mindrop_sequence, double minattribute, bool drop_by_attribute_descending) {
|
||||
bool dropping_by_attribute = drop_by_attribute_descending
|
||||
? minattribute != HUGE_VAL
|
||||
: minattribute != -HUGE_VAL;
|
||||
|
||||
return mingap != 0 || minextent != 0 || mindrop_sequence != 0 || dropping_by_attribute;
|
||||
}
|
||||
|
||||
// Clips a feature's geometry to the tile bounds at the specified zoom level
|
||||
// with the specified buffer. Returns true if the feature was entirely clipped away
|
||||
// by bounding box alone; otherwise returns false.
|
||||
@@ -1102,7 +1119,7 @@ struct next_feature_state {
|
||||
// This function is called repeatedly from write_tile() to retrieve the next feature
|
||||
// from the input stream. If the stream is at an end, it returns a feature with the
|
||||
// geometry type set to -2.
|
||||
static 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, std::atomic<bool> *within, compressor **geomfile, std::atomic<long long> *geompos, long long start_geompos[], std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, json_object *filter, const char *global_stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool compressed, multiplier_state *multiplier_state, std::shared_ptr<std::string> &tile_stringpool, std::vector<std::string> const &unidecode_data, next_feature_state &next_feature_state, double droprate) {
|
||||
static 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, std::atomic<bool> *within, compressor **geomfile, std::atomic<long long> *geompos, long long start_geompos[], std::atomic<double> *oprogress, double todo, const char *fname, int child_shards, json_object *filter, const char *global_stringpool, long long *pool_off, std::vector<std::vector<std::string>> *layer_unmaps, bool first_time, bool write_children, bool compressed, multiplier_state *multiplier_state, std::shared_ptr<std::string> &tile_stringpool, std::vector<std::string> const &unidecode_data, next_feature_state &next_feature_state, double droprate) {
|
||||
double extra_multiplier_zooms = log(retain_points_multiplier) / log(droprate);
|
||||
|
||||
while (1) {
|
||||
@@ -1191,7 +1208,7 @@ static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *
|
||||
// XXX should continue, but affects test outputs
|
||||
}
|
||||
|
||||
if (first_time && pass == 0) { /* only write out the next zoom once, even if we retry */
|
||||
if (first_time && write_children) { /* only write out the next zoom once, even if we retry */
|
||||
if (sf.tippecanoe_maxzoom == -1 || sf.tippecanoe_maxzoom >= nextzoom) {
|
||||
rewrite(sf, z, nextzoom, maxzoom, tx, ty, buffer, within, geompos, start_geompos, geomfile, fname, child_shards, max_zoom_increment, sf.segment, initial_x, initial_y);
|
||||
}
|
||||
@@ -1356,6 +1373,7 @@ struct run_prefilter_args {
|
||||
json_object *filter = NULL;
|
||||
std::vector<std::string> const *unidecode_data;
|
||||
bool first_time = false;
|
||||
bool write_children = false;
|
||||
bool compressed = false;
|
||||
double droprate = 1;
|
||||
};
|
||||
@@ -1368,7 +1386,7 @@ void *run_prefilter(void *v) {
|
||||
next_feature_state next_feature_state;
|
||||
|
||||
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->start_geompos, rpa->oprogress, rpa->todo, rpa->fname, rpa->child_shards, rpa->filter, rpa->global_stringpool, rpa->pool_off, rpa->layer_unmaps, rpa->first_time, rpa->compressed, &multiplier_state, tile_stringpool, *(rpa->unidecode_data), next_feature_state, rpa->droprate);
|
||||
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->start_geompos, rpa->oprogress, rpa->todo, rpa->fname, rpa->child_shards, rpa->filter, rpa->global_stringpool, rpa->pool_off, rpa->layer_unmaps, rpa->first_time, rpa->write_children, rpa->compressed, &multiplier_state, tile_stringpool, *(rpa->unidecode_data), next_feature_state, rpa->droprate);
|
||||
if (sf.t < 0) {
|
||||
break;
|
||||
}
|
||||
@@ -1644,7 +1662,7 @@ void skip_tile(decompressor *geoms, std::atomic<long long> *geompos_in, bool com
|
||||
}
|
||||
}
|
||||
|
||||
long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, char *global_stringpool, int z, const unsigned tx, const unsigned ty, const int detail, int min_detail, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, compressor **geomfile, std::atomic<long long> *geompos, int minzoom, int maxzoom, double todo, std::atomic<long long> *along, long long alongminus, double gamma, int child_shards, long long *pool_off, unsigned *initial_x, unsigned *initial_y, std::atomic<int> *running, double simplification, std::vector<std::map<std::string, layermap_entry>> *layermaps, std::vector<std::vector<std::string>> *layer_unmaps, size_t tiling_seg, size_t pass, unsigned long long mingap, long long minextent, unsigned long long mindrop_sequence, double minattribute, const char *prefilter, const char *postfilter, json_object *filter, write_tile_args *arg, atomic_strategy *strategy_out, bool compressed_input, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, std::vector<std::string> const &unidecode_data, long long estimated_complexity, std::set<zxy> &skip_children_out) {
|
||||
long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, char *global_stringpool, int z, const unsigned tx, const unsigned ty, const int detail, int min_detail, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, compressor **geomfile, std::atomic<long long> *geompos, int minzoom, int maxzoom, double todo, std::atomic<long long> *along, long long alongminus, double gamma, int child_shards, long long *pool_off, unsigned *initial_x, unsigned *initial_y, std::atomic<int> *running, double simplification, std::vector<std::map<std::string, layermap_entry>> *layermaps, std::vector<std::vector<std::string>> *layer_unmaps, size_t tiling_seg, size_t pass, unsigned long long mingap, long long minextent, unsigned long long mindrop_sequence, double minattribute, const char *prefilter, const char *postfilter, json_object *filter, write_tile_args *arg, atomic_strategy *strategy_out, bool compressed_input, node *shared_nodes_map, size_t nodepos, std::string const &shared_nodes_bloom, std::vector<std::string> const &unidecode_data, long long estimated_complexity, bool write_children, std::set<zxy> &skip_children_out) {
|
||||
double merge_fraction = 1;
|
||||
double mingap_fraction = 1;
|
||||
double minextent_fraction = 1;
|
||||
@@ -1680,7 +1698,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
int first_detail = detail, second_detail = detail - 1;
|
||||
bool trying_to_stop_early = false;
|
||||
bool can_stop_early = true;
|
||||
if (additional[A_VARIABLE_DEPTH_PYRAMID]) {
|
||||
if (additional[A_VARIABLE_DEPTH_PYRAMID] && !dropping_features(mingap, minextent, mindrop_sequence, minattribute, arg->drop_by_attribute_descending)) {
|
||||
// If we are trying to stop early, there is an extra first pass with full+extra detail,
|
||||
// and which loops if everything doesn't fit rather than trying to drop or union features.
|
||||
|
||||
@@ -1825,6 +1843,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
rpa.filter = filter;
|
||||
rpa.unidecode_data = &unidecode_data;
|
||||
rpa.first_time = first_time;
|
||||
rpa.write_children = write_children;
|
||||
rpa.compressed = compressed_input;
|
||||
rpa.droprate = arg->droprate;
|
||||
|
||||
@@ -1858,7 +1877,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
ssize_t which_serial_feature = -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.data(), geomfile, geompos, start_geompos.data(), &oprogress, todo, fname, child_shards, filter, global_stringpool, pool_off, layer_unmaps, first_time, compressed_input, &multiplier_state, tile_stringpool, unidecode_data, next_feature_state, arg->droprate);
|
||||
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.data(), geomfile, geompos, start_geompos.data(), &oprogress, todo, fname, child_shards, filter, global_stringpool, pool_off, layer_unmaps, first_time, write_children, compressed_input, &multiplier_state, tile_stringpool, unidecode_data, next_feature_state, arg->droprate);
|
||||
} else {
|
||||
sf = parse_feature(prefilter_jp, z, tx, ty, layermaps, tiling_seg, layer_unmaps, postfilter != NULL, key_pool);
|
||||
}
|
||||
@@ -2248,6 +2267,12 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
sf.clustered = 0;
|
||||
sf.tile_stringpool = tile_stringpool;
|
||||
|
||||
if (trying_to_stop_early && line_detail == first_detail) {
|
||||
// only remove collinearities;
|
||||
// leave all other vertices for extreme overzooming
|
||||
sf.simplification = 0;
|
||||
}
|
||||
|
||||
if (line_detail == detail && extra_detail >= 0 && z == maxzoom) {
|
||||
sf.extra_detail = extra_detail;
|
||||
// maximum allowed coordinate delta in geometries is 2^31 - 1
|
||||
@@ -2456,7 +2481,6 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
args[i].shared_nodes_map = shared_nodes_map;
|
||||
args[i].nodepos = nodepos;
|
||||
args[i].shared_nodes_bloom = &shared_nodes_bloom;
|
||||
args[i].trying_to_stop_early = trying_to_stop_early;
|
||||
|
||||
if (tasks > 1) {
|
||||
if (thread_create(&pthreads[i], NULL, simplification_worker, &args[i]) != 0) {
|
||||
@@ -2883,7 +2907,6 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
|
||||
|
||||
if (trying_to_stop_early && line_detail == first_detail) {
|
||||
// didn't work, try a lower detail
|
||||
detail_reduced++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3146,12 +3169,41 @@ exit(EXIT_IMPOSSIBLE);
|
||||
long long len;
|
||||
|
||||
struct zxy parent(z - 1, x / 2, y / 2);
|
||||
bool skip = false;
|
||||
|
||||
// Normally a tile writes the geometry for its children on pass 0, and the
|
||||
// later passes of the same zoom, which are only retries with new thresholds,
|
||||
// must not write it again.
|
||||
bool write_children = (arg->pass == 0);
|
||||
|
||||
if (arg->skip_children->count(parent) > 0) {
|
||||
if (dropping_features(arg->mingap, arg->minextent, arg->mindrop_sequence, arg->minattribute, arg->drop_by_attribute_descending)) {
|
||||
// The parent truncated its pyramid here, but the zoom has since had to
|
||||
// start dropping features, so the truncation no longer holds and this
|
||||
// tile has to be written after all. Its geometry is still in the stream.
|
||||
skip = false;
|
||||
|
||||
// It was skipped on every earlier pass of this zoom, so its children
|
||||
// have never been written out. Write them on the first pass that
|
||||
// actually tiles it, rather than on pass 0 as usual. The thresholds
|
||||
// only ever increase within a zoom, so that is exactly the pass on
|
||||
// which this zoom started dropping.
|
||||
write_children = arg->first_dropping_pass;
|
||||
} else {
|
||||
// skip if the parent tile finished at the last zoom level and we aren't trying to drop
|
||||
skip = true;
|
||||
}
|
||||
} else {
|
||||
// do the tile if the parent didn't finish early
|
||||
skip = false;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
skip_tile(&dc, &geompos, arg->compressed);
|
||||
len = 1;
|
||||
} else {
|
||||
arg->wrote_zoom = z;
|
||||
len = write_tile(&dc, &geompos, arg->global_stringpool, z, x, y, z == arg->maxzoom ? arg->full_detail : arg->low_detail, arg->min_detail, arg->outdb, arg->outdir, arg->buffer, arg->fname, arg->geomfile, arg->geompos, arg->minzoom, arg->maxzoom, arg->todo, arg->along, geompos, arg->gamma, arg->child_shards, arg->pool_off, arg->initial_x, arg->initial_y, arg->running, arg->simplification, arg->layermaps, arg->layer_unmaps, arg->tiling_seg, arg->pass, arg->mingap, arg->minextent, arg->mindrop_sequence, arg->minattribute, arg->prefilter, arg->postfilter, arg->filter, arg, arg->strategy, arg->compressed, arg->shared_nodes_map, arg->nodepos, *(arg->shared_nodes_bloom), (*arg->unidecode_data), estimated_complexity, arg->skip_children_out);
|
||||
len = write_tile(&dc, &geompos, arg->global_stringpool, z, x, y, z == arg->maxzoom ? arg->full_detail : arg->low_detail, arg->min_detail, arg->outdb, arg->outdir, arg->buffer, arg->fname, arg->geomfile, arg->geompos, arg->minzoom, arg->maxzoom, arg->todo, arg->along, geompos, arg->gamma, arg->child_shards, arg->pool_off, arg->initial_x, arg->initial_y, arg->running, arg->simplification, arg->layermaps, arg->layer_unmaps, arg->tiling_seg, arg->pass, arg->mingap, arg->minextent, arg->mindrop_sequence, arg->minattribute, arg->prefilter, arg->postfilter, arg->filter, arg, arg->strategy, arg->compressed, arg->shared_nodes_map, arg->nodepos, *(arg->shared_nodes_bloom), (*arg->unidecode_data), estimated_complexity, write_children, arg->skip_children_out);
|
||||
}
|
||||
|
||||
if (pthread_mutex_lock(&var_lock) != 0) {
|
||||
@@ -3335,8 +3387,16 @@ int traverse_zooms(int *geomfd, off_t *geom_size, char *global_stringpool, std::
|
||||
size_t zoom_tile_size = 0;
|
||||
size_t zoom_feature_count = 0;
|
||||
std::set<zxy> skip_children_out;
|
||||
bool was_dropping = false;
|
||||
|
||||
for (size_t pass = 0;; pass++) {
|
||||
// Tiles that were skipped because an ancestor truncated its pyramid are
|
||||
// revived on the pass where this zoom starts dropping features, and that
|
||||
// is the pass on which they have to write out their children.
|
||||
bool is_dropping = dropping_features(zoom_mingap, zoom_minextent, zoom_mindrop_sequence, zoom_minattribute, drop_by_attribute_descending);
|
||||
bool first_dropping_pass = is_dropping && !was_dropping;
|
||||
was_dropping = is_dropping;
|
||||
|
||||
std::vector<pthread_t> pthreads(threads);
|
||||
std::vector<write_tile_args> args;
|
||||
args.resize(threads);
|
||||
@@ -3418,6 +3478,7 @@ int traverse_zooms(int *geomfd, off_t *geom_size, char *global_stringpool, std::
|
||||
args[thread].shared_nodes_bloom = &shared_nodes_bloom;
|
||||
args[thread].skip_children = &skip_children;
|
||||
args[thread].skip_children_out.clear();
|
||||
args[thread].first_dropping_pass = first_dropping_pass;
|
||||
|
||||
if (thread_create(&pthreads[thread], NULL, run_thread, &args[thread]) != 0) {
|
||||
perror("pthread_create");
|
||||
|
||||
Reference in New Issue
Block a user