Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do less work when assigning bins by ID #321

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 139 additions & 110 deletions clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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 {
Expand Down Expand Up @@ -1810,90 +1813,54 @@ mvt_tile assign_to_bins(mvt_tile &features,
std::set<std::string> exclude,
std::vector<std::string> exclude_prefix,
int buffer, std::vector<clipbbox> const &clipbboxes) {
std::vector<index_event> events;
key_pool key_pool;

if (bins.size() == 0) {
return mvt_tile();
}

// Index bins
for (size_t i = 0; i < bins.size(); i++) {
for (size_t j = 0; j < bins[i].features.size(); j++) {
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_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);
}
}

std::map<unsigned long long, std::pair<size_t, size_t>> fid_to_feature;

// Index points
for (size_t i = 0; i < features.layers.size(); i++) {
for (size_t j = 0; j < features.layers[i].features.size(); j++) {
long long xmin, ymin, xmax, ymax;
unsigned long long start, end;

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));
}

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);
}
}
}

std::sort(events.begin(), events.end());
std::set<active_bin> active;

mvt_layer outlayer;
outlayer.extent = bins[0].extent;
outlayer.version = 2;
outlayer.name = features.layers[0].name;

std::vector<std::vector<tile_feature>> outfeatures;

for (auto &e : events) {
if (e.kind == index_event::ENTER) {
active_bin a(e.layer, e.feature);
a.xmin = e.xmin;
a.ymin = e.ymin;
a.xmax = e.xmax;
a.ymax = e.ymax;
if (bin_by_id_list.size() > 0) {
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));
}
}
}
}

const mvt_feature &bin = bins[e.layer].features[e.feature];
for (auto &binlayer : bins) {
size_t seq = 0;
for (auto &bin : binlayer.features) {
{
tile_feature outfeature;
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.layer = &binlayer;
outfeature.seq = seq++;

{
tile_feature outfeature;
for (auto const &g : bin.geometry) {
outfeature.geom.emplace_back(g.op, g.x, g.y);
outfeatures.push_back({std::move(outfeature)});
}
outfeature.t = bin.type;
outfeature.has_id = bin.has_id;
outfeature.id = bin.id;
outfeature.tags = bin.tags;
outfeature.layer = &bins[e.layer];
outfeature.seq = e.feature;

a.outfeature = outfeatures.size();
outfeatures.push_back({std::move(outfeature)});
}

if (bin_by_id_list.size() > 0) {
for (size_t k = 0; k < bin.tags.size(); k += 2) {
if (bins[e.layer].keys[bin.tags[k]] == bin_by_id_list) {
std::vector<size_t> ids = parse_ids_string(bins[e.layer].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) {
Expand All @@ -1904,8 +1871,8 @@ mvt_tile assign_to_bins(mvt_tile &features,
outfeature.has_id = feature.has_id;
outfeature.id = feature.id;
outfeature.tags = feature.tags;
outfeature.layer = &features.layers[e.layer];
outfeature.seq = e.feature;
outfeature.layer = &features.layers[f->second.first];
outfeature.seq = f->second.second;
outfeatures.back().push_back(std::move(outfeature));
}
}
Expand All @@ -1914,67 +1881,128 @@ mvt_tile assign_to_bins(mvt_tile &features,
}
}
}
}
} else {
std::vector<index_event> events;

active.insert(std::move(a));
} else if (e.kind == index_event::CHECK) {
if (bin_by_id_list.size() > 0) {
continue; // only bin by id, not geometrically
// Index bins
for (size_t i = 0; i < bins.size(); i++) {
for (size_t j = 0; j < bins[i].features.size(); j++) {
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_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);
}
}

auto const &feature = features.layers[e.layer].features[e.feature];
// Index points
for (size_t i = 0; i < features.layers.size(); i++) {
for (size_t j = 0; j < features.layers[i].features.size(); j++) {
long long xmin, ymin, xmax, ymax;
unsigned long long start, end;

if (feature.geometry.size() == 0) {
// already assigned by ID
continue;
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);
}
}
}

// if we can't find a real match,
// assign points to the most nearby bin
ssize_t which_outfeature = outfeatures.size() - 1;
std::sort(events.begin(), events.end());
std::set<active_bin> active;

for (auto const &a : active) {
auto const &bin = bins[a.layer].features[a.feature];
for (auto &e : events) {
if (e.kind == index_event::ENTER) {
active_bin a(e.layer, e.feature);
a.xmin = e.xmin;
a.ymin = e.ymin;
a.xmax = e.xmax;
a.ymax = e.ymax;

if (bbox_intersects(e.xmin, e.ymin, e.xmax, e.ymax,
a.xmin, a.ymin, a.xmax, a.ymax)) {
if (pnpoly_mp(bin.geometry, feature.geometry[0].x, feature.geometry[0].y)) {
which_outfeature = a.outfeature;
break;
const mvt_feature &bin = *bins[e.layer].features[e.feature];

{
tile_feature outfeature;
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.layer = &bins[e.layer];
outfeature.seq = e.feature;

a.outfeature = outfeatures.size();
outfeatures.push_back({std::move(outfeature)});
}
}

if (which_outfeature >= 0) {
tile_feature outfeature;
for (auto const &g : feature.geometry) {
outfeature.geom.emplace_back(g.op, g.x, g.y);
}
outfeature.t = feature.type;
outfeature.has_id = feature.has_id;
outfeature.id = feature.id;
outfeature.tags = feature.tags;
outfeature.layer = &features.layers[e.layer];
outfeature.seq = e.feature;
outfeatures[which_outfeature].push_back(std::move(outfeature));
}
} else /* EXIT */ {
auto const &found = active.find({e.layer, e.feature});
if (found != active.end()) {
active.erase(found);
} else {
fprintf(stderr, "event mismatch: can't happen\n");
exit(EXIT_IMPOSSIBLE);
active.insert(std::move(a));
} else if (e.kind == index_event::CHECK) {
if (bin_by_id_list.size() > 0) {
continue; // only bin by id, not geometrically
}

auto const &feature = *features.layers[e.layer].features[e.feature];

if (feature.geometry.size() == 0) {
// already assigned by ID
continue;
}

// if we can't find a real match,
// assign points to the most nearby bin
ssize_t which_outfeature = outfeatures.size() - 1;

for (auto const &a : active) {
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)) {
if (pnpoly_mp(bin.geometry, feature.geometry[0].x, feature.geometry[0].y)) {
which_outfeature = a.outfeature;
break;
}
}
}

if (which_outfeature >= 0) {
tile_feature outfeature;
for (auto const &g : feature.geometry) {
outfeature.geom.emplace_back(g.op, g.x, g.y);
}
outfeature.t = feature.type;
outfeature.has_id = feature.has_id;
outfeature.id = feature.id;
outfeature.tags = feature.tags;
outfeature.layer = &features.layers[e.layer];
outfeature.seq = e.feature;
outfeatures[which_outfeature].push_back(std::move(outfeature));
}
} else /* EXIT */ {
auto const &found = active.find({e.layer, e.feature});
if (found != active.end()) {
active.erase(found);
} else {
fprintf(stderr, "event mismatch: can't happen\n");
exit(EXIT_IMPOSSIBLE);
}
}
}
}

key_pool key_pool;
for (size_t i = 0; i < outfeatures.size(); i++) {
if (outfeatures[i].size() > 1) {
if (feature_out(outfeatures[i], outlayer,
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;
Expand Down Expand Up @@ -2046,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;

Expand Down
6 changes: 3 additions & 3 deletions decode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}
}
Expand Down
12 changes: 6 additions & 6 deletions mvt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion mvt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading