Work in progress on binning features in overzoom (#258)

* Factoring out tilestats management from GeoJSON file reading

* Move code around so overzoom can link against parse_layers

* Read the file of bins

* Plumb the bins through to overzoom()

* Some zip code bins to test with

* (Currently non-functional) test of binning

* Starting to spell out the bin matching loop

* Can't flatten points, so don't flatten bins either

* More fleshing out bin traversal

* Bounding box of tile-relative mvt geometry

* Smallest enclosing tile from bbox

* Most of the bin scan

* Add point in polygon check. It crashes.

* Find the matching bins

* GDAL-style bounding boxes have eaten my brain

* Make some features to bin into

* Increment a count as features are found to be within the bins

* Fix longitude wraparound in overzoom bins

* Fix the tests

* Push off attribute copying until after bin assignment

* Carry sum of numeric attributes into the bins

* Also add mean, min, and max

* Add --calculate-feature-index since I keep needing it for testing

* Add an option to accumulate sum/mean/max/min/count of all numeric attrs

* Don't bake in tippecanoe:mean, since we redo it from sum and count

* Forgot to update this test fixture after removing tiled mean

* Update version and changelog
This commit is contained in:
Erica Fischer
2024-09-05 12:06:51 -07:00
committed by GitHub
parent f3b575ead4
commit 5b18eea673
27 changed files with 1305 additions and 410 deletions
+84 -1
View File
@@ -1398,10 +1398,76 @@ void promote_attribute(std::string const &key, serial_feature &p) {
}
}
void promote_attribute_prefix(std::string const &key, std::string const &prefixed_key, serial_feature &p) {
if (p.need_tilestats.count(prefixed_key) == 0) {
p.need_tilestats.insert(prefixed_key);
}
// does the prefixed attribute already exist as a full key?
ssize_t found_as = -1;
for (size_t i = 0; i < p.full_keys.size(); i++) {
if (prefixed_key == p.full_keys[i]) {
// yes, so we're done
return;
}
if (key == p.full_keys[i]) {
found_as = i;
}
}
// or did we find the source as a full key? then copy it
if (found_as >= 0) {
p.full_keys.push_back(prefixed_key);
p.full_values.push_back(p.full_values[found_as]);
return;
}
// does the prefix attribute exist as a reference key?
found_as = -1;
for (size_t i = 0; i < p.keys.size(); i++) {
if (strcmp(prefixed_key.c_str(), p.stringpool + p.keys[i] + 1) == 0) {
// yes, so promote it to a full key
serial_val sv;
sv.s = p.stringpool + p.values[i] + 1;
sv.type = p.stringpool[p.values[i]];
p.full_keys.push_back(prefixed_key);
p.full_values.push_back(std::move(sv));
p.keys.erase(p.keys.begin() + i);
p.values.erase(p.values.begin() + i);
return;
} else if (strcmp(key.c_str(), p.stringpool + p.keys[i] + 1) == 0) {
found_as = i;
}
}
// or did we find the source as a reference key? then copy it
if (found_as >= 0) {
serial_val sv;
sv.s = p.stringpool + p.values[found_as] + 1;
sv.type = p.stringpool[p.values[found_as]];
p.full_keys.push_back(prefixed_key);
p.full_values.push_back(std::move(sv));
return;
}
}
std::map<std::string, attribute_op> numeric_operations = {
{"sum", op_sum},
{"min", op_min},
{"max", op_max},
{"count", op_count},
};
// accumulate attribute values from sf onto p
void preserve_attributes(std::unordered_map<std::string, attribute_op> const *attribute_accum, const serial_feature &sf, serial_feature &p) {
for (size_t i = 0; i < sf.keys.size(); i++) {
std::string key = sf.stringpool + sf.keys[i] + 1;
int type = sf.stringpool[sf.values[i]];
auto f = attribute_accum->find(key);
if (f != attribute_accum->end()) {
@@ -1411,17 +1477,34 @@ void preserve_attributes(std::unordered_map<std::string, attribute_op> const *at
promote_attribute(key, p);
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, p.attribute_accum_state);
} else if (type == mvt_double && additional[A_ACCUMULATE_NUMERIC]) {
for (auto const &operation : numeric_operations) {
serial_val sv;
sv.type = sf.stringpool[sf.values[i]];
sv.s = sf.stringpool + sf.values[i] + 1;
std::string prefixed_key = "tippecanoe:" + operation.first + ":" + key;
promote_attribute_prefix(key, prefixed_key, p);
preserve_attribute(operation.second, prefixed_key, sv, p.full_keys, p.full_values, p.attribute_accum_state);
}
}
}
for (size_t i = 0; i < sf.full_keys.size(); i++) {
const std::string &key = sf.full_keys[i];
int type = sf.full_values[i].type;
auto f = attribute_accum->find(key);
if (f != attribute_accum->end()) {
const serial_val &sv = sf.full_values[i];
promote_attribute(key, p);
promote_attribute(key, p); // promotes it in the target feature
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, p.attribute_accum_state);
} else if (type == mvt_double && additional[A_ACCUMULATE_NUMERIC]) {
for (auto const &operation : numeric_operations) {
std::string prefixed_key = "tippecanoe:" + operation.first + ":" + key;
promote_attribute_prefix(key, prefixed_key, p);
preserve_attribute(operation.second, prefixed_key, sf.full_values[i], p.full_keys, p.full_values, p.attribute_accum_state);
}
}
}
}