Indirect lists of mvt_feature through pointers for faster sorting

This commit is contained in:
Erica Fischer
2025-02-12 11:32:28 -08:00
parent 9d00c92ff2
commit 355cc31d5b
9 changed files with 52 additions and 48 deletions
+26 -22
View File
@@ -1674,7 +1674,7 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
}
}
outlayer.features.push_back(std::move(outfeature));
outlayer.features.push_back(std::make_shared<mvt_feature>(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<mvt_feature> &a, const std::shared_ptr<mvt_feature> &b) {
return a->seq < b->seq;
}
} preservecmp;
struct index_event {
@@ -1825,39 +1828,39 @@ mvt_tile assign_to_bins(mvt_tile &features,
std::map<unsigned long long, std::pair<size_t, size_t>> 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<size_t> 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<size_t> 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<source_tile> 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;
+3 -3
View File
@@ -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++;
}
}
+6 -6
View File
@@ -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<mvt_feature>(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<unsigned> sorted_tags = layers[i].features[f].tags;
std::vector<unsigned> 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<uint32_t> geometry;
@@ -426,7 +426,7 @@ std::string mvt_tile::encode() {
int cmd = -1;
int length = 0;
std::vector<mvt_geometry> &geom = layers[i].features[f].geometry;
std::vector<mvt_geometry> &geom = layers[i].features[f]->geometry;
for (size_t g = 0; g < geom.size(); g++) {
int op = geom[g].op;
+1 -1
View File
@@ -204,7 +204,7 @@ struct std::hash<mvt_value> {
struct mvt_layer {
int version = 0;
std::string name = "";
std::vector<mvt_feature> features{};
std::vector<std::shared_ptr<mvt_feature>> features{};
std::vector<std::string> keys{};
std::vector<mvt_value> values{};
long long extent = 0;
+6 -6
View File
@@ -119,17 +119,17 @@ std::vector<mvt_layer> 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
+1 -1
View File
@@ -398,7 +398,7 @@ std::vector<mvt_layer> 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<mvt_feature>(feature));
}
json_free(j);
+6 -6
View File
@@ -243,9 +243,9 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<st
// scaling up is safe while scaling down requires geometry cleaning.
for (size_t i = 0; i < outlayer.features.size(); i++) {
for (size_t j = 0; j < outlayer.features[i].geometry.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;
for (size_t j = 0; j < outlayer.features[i]->geometry.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<st
join_keys.resize(layer.features.size());
for (size_t f = 0; f < layer.features.size(); f++) {
mvt_feature &feat = layer.features[f];
mvt_feature &feat = *layer.features[f];
join_keys[f].type = mvt_no_such_key;
for (size_t t = 0; t + 1 < feat.tags.size(); t += 2) {
@@ -289,7 +289,7 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<st
bool features_added_to_layer = false;
for (size_t f = 0; f < layer.features.size(); f++) {
mvt_feature &feat = layer.features[f];
mvt_feature &feat = *layer.features[f];
std::set<std::string> 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<st
features_added++;
features_added_to_layer = true;
outlayer.features.push_back(outfeature);
outlayer.features.push_back(std::make_shared<mvt_feature>(outfeature));
if (z < tilestats->second.minzoom) {
tilestats->second.minzoom = z;
+2 -2
View File
@@ -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<mvt_feature>(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<std::string>());
}
@@ -2575,7 +2575,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *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<mvt_feature>(feature));
layer_features[x] = std::make_shared<serial_feature>();
}
+1 -1
View File
@@ -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<std::string> 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");