From 355cc31d5bc992b94000a122c3522d01e1d54a20 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Wed, 12 Feb 2025 11:32:28 -0800 Subject: [PATCH] Indirect lists of mvt_feature through pointers for faster sorting --- clip.cpp | 48 ++++++++++++++++++++++++++---------------------- decode.cpp | 6 +++--- mvt.cpp | 12 ++++++------ mvt.hpp | 2 +- plugin.cpp | 12 ++++++------ read_json.cpp | 2 +- tile-join.cpp | 12 ++++++------ tile.cpp | 4 ++-- write_json.cpp | 2 +- 9 files changed, 52 insertions(+), 48 deletions(-) diff --git a/clip.cpp b/clip.cpp index d8e49317..1bf9738b 100644 --- a/clip.cpp +++ b/clip.cpp @@ -1674,7 +1674,7 @@ static bool feature_out(std::vector const &features, mvt_layer &ou } } - outlayer.features.push_back(std::move(outfeature)); + outlayer.features.push_back(std::make_shared(outfeature)); return true; } @@ -1685,6 +1685,9 @@ static struct preservecmp { bool operator()(const mvt_feature &a, const mvt_feature &b) { return a.seq < b.seq; } + bool operator()(const std::shared_ptr &a, const std::shared_ptr &b) { + return a->seq < b->seq; + } } preservecmp; struct index_event { @@ -1825,39 +1828,39 @@ mvt_tile assign_to_bins(mvt_tile &features, std::map> fid_to_feature; for (size_t i = 0; i < features.layers.size(); i++) { for (size_t j = 0; j < features.layers[i].features.size(); j++) { - if (features.layers[i].features[j].geometry.size() > 0) { - if (features.layers[i].features[j].has_id) { - fid_to_feature.emplace(features.layers[i].features[j].id, std::make_pair(i, j)); + if (features.layers[i].features[j]->geometry.size() > 0) { + if (features.layers[i].features[j]->has_id) { + fid_to_feature.emplace(features.layers[i].features[j]->id, std::make_pair(i, j)); } } } } for (auto &binlayer : bins) { - size_t seq = 0; + size_t seq = 0; for (auto &bin : binlayer.features) { { tile_feature outfeature; - for (auto const &g : bin.geometry) { + for (auto const &g : bin->geometry) { outfeature.geom.emplace_back(g.op, g.x, g.y); } - outfeature.t = bin.type; - outfeature.has_id = bin.has_id; - outfeature.id = bin.id; - outfeature.tags = bin.tags; + outfeature.t = bin->type; + outfeature.has_id = bin->has_id; + outfeature.id = bin->id; + outfeature.tags = bin->tags; outfeature.layer = &binlayer; outfeature.seq = seq++; outfeatures.push_back({std::move(outfeature)}); } - for (size_t k = 0; k < bin.tags.size(); k += 2) { - if (binlayer.keys[bin.tags[k]] == bin_by_id_list) { - std::vector ids = parse_ids_string(binlayer.values[bin.tags[k + 1]]); + for (size_t k = 0; k < bin->tags.size(); k += 2) { + if (binlayer.keys[bin->tags[k]] == bin_by_id_list) { + std::vector ids = parse_ids_string(binlayer.values[bin->tags[k + 1]]); for (auto &id : ids) { auto f = fid_to_feature.find(id); if (f != fid_to_feature.end()) { - mvt_feature &feature = features.layers[f->second.first].features[f->second.second]; + mvt_feature &feature = *features.layers[f->second.first].features[f->second.second]; if (feature.geometry.size() > 0) { tile_feature outfeature; for (auto const &g : feature.geometry) { @@ -1888,7 +1891,7 @@ mvt_tile assign_to_bins(mvt_tile &features, long long xmin, ymin, xmax, ymax; unsigned long long start, end; - get_bbox(bins[i].features[j].geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, bins[i].detail()); + get_bbox(bins[i].features[j]->geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, bins[i].detail()); get_quadkey_bounds(xmin, ymin, xmax, ymax, &start, &end); events.emplace_back(start, index_event::ENTER, i, j, xmin, ymin, xmax, ymax); events.emplace_back(end, index_event::EXIT, i, j, xmin, ymin, xmax, ymax); @@ -1901,8 +1904,8 @@ mvt_tile assign_to_bins(mvt_tile &features, long long xmin, ymin, xmax, ymax; unsigned long long start, end; - if (features.layers[i].features[j].geometry.size() > 0) { - get_bbox(features.layers[i].features[j].geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, features.layers[i].detail()); + if (features.layers[i].features[j]->geometry.size() > 0) { + get_bbox(features.layers[i].features[j]->geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, features.layers[i].detail()); get_quadkey_bounds(xmin, ymin, xmax, ymax, &start, &end); events.emplace_back(start, index_event::CHECK, i, j, xmin, ymin, xmax, ymax); } @@ -1920,7 +1923,7 @@ mvt_tile assign_to_bins(mvt_tile &features, a.xmax = e.xmax; a.ymax = e.ymax; - const mvt_feature &bin = bins[e.layer].features[e.feature]; + const mvt_feature &bin = *bins[e.layer].features[e.feature]; { tile_feature outfeature; @@ -1944,7 +1947,7 @@ mvt_tile assign_to_bins(mvt_tile &features, continue; // only bin by id, not geometrically } - auto const &feature = features.layers[e.layer].features[e.feature]; + auto const &feature = *features.layers[e.layer].features[e.feature]; if (feature.geometry.size() == 0) { // already assigned by ID @@ -1956,7 +1959,7 @@ mvt_tile assign_to_bins(mvt_tile &features, ssize_t which_outfeature = outfeatures.size() - 1; for (auto const &a : active) { - auto const &bin = bins[a.layer].features[a.feature]; + auto const &bin = *bins[a.layer].features[a.feature]; if (bbox_intersects(e.xmin, e.ymin, e.xmax, e.ymax, a.xmin, a.ymin, a.xmax, a.ymax)) { @@ -1999,7 +2002,7 @@ mvt_tile assign_to_bins(mvt_tile &features, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric, key_pool, buffer, true, clipbboxes, z, x, y)) { - mvt_feature &nfeature = outlayer.features.back(); + mvt_feature &nfeature = *outlayer.features.back(); mvt_value val; val.type = mvt_uint; val.numeric_value.uint_value = outfeatures[i].size() - 1; @@ -2071,7 +2074,8 @@ std::string overzoom(std::vector const &tiles, int nz, int nx, int static const std::string retain_points_multiplier_first = "tippecanoe:retain_points_multiplier_first"; static const std::string retain_points_multiplier_sequence = "tippecanoe:retain_points_multiplier_sequence"; - for (auto feature : layer.features) { + for (auto feature_ref : layer.features) { + auto feature = *feature_ref; // this needs to be a copy, because tile-join still needs the original unmutated drawvec geom; int t = feature.type; diff --git a/decode.cpp b/decode.cpp index 534e6219..febdbba9 100644 --- a/decode.cpp +++ b/decode.cpp @@ -60,11 +60,11 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u size_t points = 0, lines = 0, polygons = 0; for (size_t j = 0; j < tile.layers[i].features.size(); j++) { - if (tile.layers[i].features[j].type == mvt_point) { + if (tile.layers[i].features[j]->type == mvt_point) { points++; - } else if (tile.layers[i].features[j].type == mvt_linestring) { + } else if (tile.layers[i].features[j]->type == mvt_linestring) { lines++; - } else if (tile.layers[i].features[j].type == mvt_polygon) { + } else if (tile.layers[i].features[j]->type == mvt_polygon) { polygons++; } } diff --git a/mvt.cpp b/mvt.cpp index 16f9f583..3d31df7d 100644 --- a/mvt.cpp +++ b/mvt.cpp @@ -278,7 +278,7 @@ bool mvt_tile::decode(const std::string &message, bool &was_compressed) { } } - layer.features.push_back(std::move(feature)); + layer.features.push_back(std::make_shared(feature)); break; } @@ -407,16 +407,16 @@ std::string mvt_tile::encode() { std::string feature_string; protozero::pbf_writer feature_writer(feature_string); - feature_writer.add_enum(3, layers[i].features[f].type); + feature_writer.add_enum(3, layers[i].features[f]->type); - std::vector sorted_tags = layers[i].features[f].tags; + std::vector sorted_tags = layers[i].features[f]->tags; for (size_t v = 1; v < sorted_tags.size(); v += 2) { sorted_tags[v] = mapping[sorted_tags[v]]; } feature_writer.add_packed_uint32(2, std::begin(sorted_tags), std::end(sorted_tags)); - if (layers[i].features[f].has_id) { - feature_writer.add_uint64(1, layers[i].features[f].id); + if (layers[i].features[f]->has_id) { + feature_writer.add_uint64(1, layers[i].features[f]->id); } std::vector geometry; @@ -426,7 +426,7 @@ std::string mvt_tile::encode() { int cmd = -1; int length = 0; - std::vector &geom = layers[i].features[f].geometry; + std::vector &geom = layers[i].features[f]->geometry; for (size_t g = 0; g < geom.size(); g++) { int op = geom[g].op; diff --git a/mvt.hpp b/mvt.hpp index 8f24fc68..7e52363c 100644 --- a/mvt.hpp +++ b/mvt.hpp @@ -204,7 +204,7 @@ struct std::hash { struct mvt_layer { int version = 0; std::string name = ""; - std::vector features{}; + std::vector> features{}; std::vector keys{}; std::vector values{}; long long extent = 0; diff --git a/plugin.cpp b/plugin.cpp index cfe06593..b6033111 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -119,17 +119,17 @@ std::vector parse_layers(int fd, int z, unsigned x, unsigned y, std:: } for (auto const &feature : layer.features) { - if (feature.type == mvt_point) { + if (feature->type == mvt_point) { ts->second.points++; - } else if (feature.type == mvt_linestring) { + } else if (feature->type == mvt_linestring) { ts->second.lines++; - } else if (feature.type == mvt_polygon) { + } else if (feature->type == mvt_polygon) { ts->second.polygons++; } - for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) { - const std::string &key = layer.keys[feature.tags[i]]; - const mvt_value &val = layer.values[feature.tags[i + 1]]; + for (size_t i = 0; i + 1 < feature->tags.size(); i += 2) { + const std::string &key = layer.keys[feature->tags[i]]; + const mvt_value &val = layer.values[feature->tags[i + 1]]; // Nulls can be excluded here because this is the postfilter // and it is nearly time to create the vector representation diff --git a/read_json.cpp b/read_json.cpp index 63329acb..88ec04bc 100644 --- a/read_json.cpp +++ b/read_json.cpp @@ -398,7 +398,7 @@ std::vector parse_layers(FILE *fp, int z, unsigned x, unsigned y, int } } - l->second.features.push_back(feature); + l->second.features.push_back(std::make_shared(feature)); } json_free(j); diff --git a/tile-join.cpp b/tile-join.cpp index d9484a28..ee3c6788 100644 --- a/tile-join.cpp +++ b/tile-join.cpp @@ -243,9 +243,9 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::mapgeometry.size(); j++) { + outlayer.features[i]->geometry[j].x = outlayer.features[i]->geometry[j].x * layer.extent / outlayer.extent; + outlayer.features[i]->geometry[j].y = outlayer.features[i]->geometry[j].y * layer.extent / outlayer.extent; } } @@ -261,7 +261,7 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map exclude_attributes; if (filter != NULL && !evaluate(feat, layer, filter, exclude_attributes, z, unidecode_data)) { @@ -520,7 +520,7 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map(outfeature)); if (z < tilestats->second.minzoom) { tilestats->second.minzoom = z; diff --git a/tile.cpp b/tile.cpp index 40ef416c..bf58bdda 100644 --- a/tile.cpp +++ b/tile.cpp @@ -1360,7 +1360,7 @@ void *run_prefilter(void *v) { } decode_meta(sf, tmp_layer, tmp_feature); - tmp_layer.features.push_back(tmp_feature); + tmp_layer.features.push_back(std::make_shared(tmp_feature)); layer_to_geojson(tmp_layer, 0, 0, 0, false, true, false, true, sf.index, sf.seq, sf.extent, true, state, 0, std::set()); } @@ -2575,7 +2575,7 @@ long long write_tile(decompressor *geoms, std::atomic *geompos_in, ch add_tilestats(layer.name, z, layermaps, tiling_seg, layer_unmaps, "tippecanoe_feature_density", sv); } - layer.features.push_back(std::move(feature)); + layer.features.push_back(std::make_shared(feature)); layer_features[x] = std::make_shared(); } diff --git a/write_json.cpp b/write_json.cpp index eae5a2f0..fc11dc56 100644 --- a/write_json.cpp +++ b/write_json.cpp @@ -270,7 +270,7 @@ void write_coords(json_writer &state, lonlat const &ll, double scale) { void layer_to_geojson(mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, bool write_dropped, unsigned long long index, long long sequence, long long extent, bool complain, json_writer &state, double scale, std::set const &include_attr) { for (size_t f = 0; f < layer.features.size(); f++) { - mvt_feature const &feat = layer.features[f]; + mvt_feature const &feat = *layer.features[f]; state.json_write_hash(); state.json_write_string("type");