Merge branch 'h3-index' into faster-bin-assign

This commit is contained in:
Erica Fischer
2025-03-28 13:23:28 -07:00
9 changed files with 10020 additions and 19 deletions
+2 -4
View File
@@ -944,12 +944,10 @@ drawvec polygon_to_anchor(const drawvec &geom) {
return drawvec();
}
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned long long label_point) {
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned wx, unsigned wy) {
drawvec out;
// anchor point in world coordinates
unsigned wx, wy;
decode_index(label_point, &wx, &wy);
// wx,wy is anchor point in world coordinates
// upper left of tile in world coordinates
long long tx1 = 0, ty1 = 0;
+1 -1
View File
@@ -89,7 +89,7 @@ void check_polygon(drawvec &geom);
double get_area(const drawvec &geom, size_t i, size_t j);
double get_mp_area(drawvec &geom);
drawvec polygon_to_anchor(const drawvec &geom);
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned long long label_point);
drawvec checkerboard_anchors(drawvec const &geom, int tx, int ty, int z, unsigned label_x, unsigned label_y);
drawvec simple_clip_poly(drawvec &geom, int z, int buffer, drawvec &shared_nodes, bool prevent_simplify_shared_nodes);
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2, bool prevent_simplify_shared_nodes);
+22
View File
@@ -94,11 +94,13 @@ unsigned int drop_denser = 0;
std::map<std::string, serial_val> set_attributes;
unsigned long long preserve_point_density_threshold = 0;
unsigned long long preserve_multiplier_density_threshold = 0;
std::vector<int> preserve_multiplier_density_bits_by_zoom;
long long extend_zooms_max = 0;
int retain_points_multiplier = 1;
std::vector<std::string> unidecode_data;
size_t maximum_string_attribute_length = 0;
std::string accumulate_numeric;
std::string use_h3_index;
std::vector<order_field> order_by;
bool order_reverse;
@@ -2498,6 +2500,7 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
long long ip;
for (ip = 0; ip < indices; ip++) {
unsigned xx, yy;
// XXX this will behave oddly if the index is actually H3
decode_index(map[ip].ix, &xx, &yy);
long long nprogress = 100 * ip / indices;
@@ -3087,6 +3090,7 @@ int main(int argc, char **argv) {
{"cluster-maxzoom", required_argument, 0, 'k'},
{"preserve-point-density-threshold", required_argument, 0, '~'},
{"preserve-multiplier-density-threshold", required_argument, 0, '~'},
{"preserve-multiplier-density-bits-by-zoom", required_argument, 0, '~'},
{"Dropping or merging a fraction of features to keep under tile size limits", 0, 0, 0},
{"drop-densest-as-needed", no_argument, &additional[A_DROP_DENSEST_AS_NEEDED], 1},
@@ -3129,6 +3133,7 @@ int main(int argc, char **argv) {
{"coalesce", no_argument, &additional[A_COALESCE], 1},
{"reverse", no_argument, &additional[A_REVERSE], 1},
{"hilbert", no_argument, &additional[A_HILBERT], 1},
{"use-h3-index", required_argument, 0, '~'},
{"order-by", required_argument, 0, '~'},
{"order-descending-by", required_argument, 0, '~'},
{"order-smallest-first", no_argument, 0, '~'},
@@ -3270,6 +3275,8 @@ int main(int argc, char **argv) {
fprintf(stderr, "%s: --extra-detail can be at most 30\n", argv[0]);
exit(EXIT_ARGS);
}
} else if (strcmp(opt, "use-h3-index") == 0) {
use_h3_index = optarg;
} else if (strcmp(opt, "order-by") == 0) {
order_by.push_back(order_field(optarg, false));
} else if (strcmp(opt, "order-descending-by") == 0) {
@@ -3301,6 +3308,21 @@ int main(int argc, char **argv) {
preserve_point_density_threshold = atoll_require(optarg, "Preserve point density threshold");
} else if (strcmp(opt, "preserve-multiplier-density-threshold") == 0) {
preserve_multiplier_density_threshold = atoll_require(optarg, "Preserve multiplier density threshold");
} else if (strcmp(opt, "preserve-multiplier-density-bits-by-zoom") == 0) {
const char *cp = optarg;
while (*cp != '\0') {
if (!isdigit(*cp)) {
fprintf(stderr, "%s: unexpected multiplier density bits by zoom %s\n", argv[0], cp);
exit(EXIT_ARGS);
}
preserve_multiplier_density_bits_by_zoom.push_back(atoi(cp));
while (isdigit(*cp)) {
cp++;
}
if (*cp == ',') {
cp++;
}
}
} else if (strcmp(opt, "extend-zooms-if-still-dropping-maximum") == 0) {
extend_zooms_max = atoll_require(optarg, "Maximum number by which to extend zooms");
} else if (strcmp(opt, "retain-points-multiplier") == 0) {
+2
View File
@@ -53,7 +53,9 @@ extern long long extend_zooms_max;
extern int retain_points_multiplier;
extern size_t maximum_string_attribute_length;
extern std::string accumulate_numeric;
extern std::string use_h3_index;
extern unsigned long long preserve_multiplier_density_threshold;
extern std::vector<int> preserve_multiplier_density_bits_by_zoom;
struct order_field {
std::string name;
+31 -6
View File
@@ -186,7 +186,7 @@ std::string serialize_feature(serial_feature *sf, long long wx, long long wy) {
long long layer = 0;
layer |= sf->layer << FLAG_LAYER;
layer |= (sf->label_point != 0) << FLAG_LABEL_POINT;
layer |= ((sf->label_x | sf->label_y) != 0) << FLAG_LABEL_POINT;
layer |= (sf->index != 0) << FLAG_INDEX;
layer |= (sf->extent != 0) << FLAG_EXTENT;
layer |= sf->has_id << FLAG_ID;
@@ -211,10 +211,13 @@ std::string serialize_feature(serial_feature *sf, long long wx, long long wy) {
if (sf->index != 0) {
serialize_ulong_long(s, sf->index);
serialize_uint(s, sf->wx);
serialize_uint(s, sf->wy);
serialize_ulong_long(s, sf->gap);
}
if (sf->label_point != 0) {
serialize_ulong_long(s, sf->label_point);
if ((sf->label_x | sf->label_y) != 0) {
serialize_uint(s, sf->label_x);
serialize_uint(s, sf->label_y);
}
if (sf->extent != 0) {
serialize_long_long(s, sf->extent);
@@ -261,17 +264,21 @@ serial_feature deserialize_feature(std::string const &geoms, unsigned z, unsigne
sf.index = 0;
sf.gap = 0;
sf.label_point = 0;
sf.label_x = 0;
sf.label_y = 0;
sf.extent = 0;
sf.geometry = decode_geometry(&cp, z, tx, ty, sf.bbox, initial_x[sf.segment], initial_y[sf.segment]);
if (sf.layer & (1 << FLAG_INDEX)) {
deserialize_ulong_long(&cp, &sf.index);
deserialize_uint(&cp, &sf.wx);
deserialize_uint(&cp, &sf.wy);
deserialize_ulong_long(&cp, &sf.gap);
}
if (sf.layer & (1 << FLAG_LABEL_POINT)) {
deserialize_ulong_long(&cp, &sf.label_point);
deserialize_uint(&cp, &sf.label_x);
deserialize_uint(&cp, &sf.label_y);
}
if (sf.layer & (1 << FLAG_EXTENT)) {
deserialize_long_long(&cp, &sf.extent);
@@ -714,6 +721,19 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf, std::
}
bbox_index = encode_index(midx, midy);
if (use_h3_index.size() > 0) {
for (size_t i = 0; i < sf.full_keys.size(); i++) {
if (*(sf.full_keys[i]) == use_h3_index) {
unsigned long long h3_index = atoll(sf.full_values[i].s.c_str());
// the top 52 bits of the feature index are the H3 index;
// the bottom 12 bits are retained from what otherwise would have been the index.
bbox_index = ((h3_index & ((1LL << 52) - 1)) << 12) | (bbox_index & ((1 << 12) - 1));
break;
}
}
}
if (additional[A_CALCULATE_INDEX]) {
sf.full_keys.push_back(key_pool.pool("tippecanoe:index"));
@@ -728,7 +748,8 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf, std::
if (dv.size() > 0) {
dv[0].x = SHIFT_LEFT(dv[0].x) & ((1LL << 32) - 1);
dv[0].y = SHIFT_LEFT(dv[0].y) & ((1LL << 32) - 1);
sf.label_point = encode_index(dv[0].x, dv[0].y);
sf.label_x = dv[0].x;
sf.label_y = dv[0].y;
}
}
@@ -748,8 +769,12 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf, std::
preserve_multiplier_density_threshold > 0 ||
cluster_distance != 0) {
sf.index = bbox_index;
sf.wx = midx;
sf.wy = midy;
} else {
sf.index = 0;
sf.wx = 0;
sf.wy = 0;
}
if (sst->layermap->count(layername) == 0) {
+6 -1
View File
@@ -58,6 +58,10 @@ struct serial_val {
s = milo::dtoa_milo(val);
}
std::string toString() const {
return s;
}
double to_double() const {
return atof(s.c_str());
}
@@ -118,8 +122,9 @@ struct serial_feature {
drawvec geometry = drawvec();
unsigned long long index = 0;
unsigned wx = 0, wy = 0;
unsigned long long gap = 0; // filled in during z0. square of planar distance
unsigned long long label_point = 0;
unsigned label_x = 0, label_y = 0;
long long extent = 0;
// These fields are not directly serialized, but are used
File diff suppressed because it is too large Load Diff
+17 -7
View File
@@ -377,7 +377,7 @@ struct ordercmp {
static std::vector<std::vector<std::shared_ptr<serial_feature>>> assemble_multiplier_clusters(std::vector<std::shared_ptr<serial_feature>> const &features) {
std::vector<std::vector<std::shared_ptr<serial_feature>>> clusters;
if (retain_points_multiplier == 1) {
if (!(retain_points_multiplier > 1 || preserve_multiplier_density_threshold != 0 || preserve_multiplier_density_bits_by_zoom.size() > 0)) {
for (auto const &feature : features) {
std::vector<std::shared_ptr<serial_feature>> cluster;
cluster.push_back(std::move(feature));
@@ -714,7 +714,7 @@ static void *simplification_worker(void *v) {
if (t == VT_POLYGON && additional[A_GENERATE_POLYGON_LABEL_POINTS]) {
t = (*features)[i]->t = VT_POINT;
geom = checkerboard_anchors(from_tile_scale(geom, z, out_detail), (*features)[i]->tx, (*features)[i]->ty, z, (*features)[i]->label_point);
geom = checkerboard_anchors(from_tile_scale(geom, z, out_detail), (*features)[i]->tx, (*features)[i]->ty, z, (*features)[i]->label_x, (*features)[i]->label_y);
to_tile_scale(geom, z, out_detail);
}
@@ -1059,6 +1059,7 @@ static bool skip_next_feature(decompressor *geoms, std::atomic<long long> *geomp
struct next_feature_state {
unsigned long long previndex = 0;
unsigned prevx = 0, prevy = 0;
unsigned long long prev_not_dropped_index = 0;
};
@@ -1128,9 +1129,11 @@ static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *
long long ox = (1LL << (32 - z)) * tx;
long long oy = (1LL << (32 - z)) * ty;
unsigned wx1, wy1;
decode_index(next_feature_state.previndex, &wx1, &wy1);
unsigned wx1 = next_feature_state.prevx;
unsigned wy1 = next_feature_state.prevy;
// find the furthest distance of a vertex in this feature
// from the representative point of the previous feature
for (auto const &g : sf.geometry) {
long long dx = (long long) wx1 - (g.x + ox);
long long dy = (long long) wy1 - (g.y + oy);
@@ -1143,6 +1146,8 @@ static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *
}
}
next_feature_state.previndex = sf.index;
next_feature_state.prevx = sf.wx;
next_feature_state.prevy = sf.wy;
if (clip_to_tile(sf, z, buffer)) {
continue;
@@ -1250,6 +1255,11 @@ static serial_feature next_feature(decompressor *geoms, std::atomic<long long> *
} else if (preserve_multiplier_density_threshold > 0 &&
sf.index - next_feature_state.prev_not_dropped_index > ((1LL << (32 - z)) / preserve_multiplier_density_threshold) * ((1LL << (32 - z)) / preserve_multiplier_density_threshold)) {
sf.dropped = FEATURE_ADDED_FOR_MULTIPLIER_DENSITY;
} else if (preserve_multiplier_density_bits_by_zoom.size() > 0 &&
(size_t) z < preserve_multiplier_density_bits_by_zoom.size() &&
(sf.index >> (64 - preserve_multiplier_density_bits_by_zoom[z])) !=
(next_feature_state.prev_not_dropped_index >> (64 - preserve_multiplier_density_bits_by_zoom[z]))) {
sf.dropped = FEATURE_ADDED_FOR_MULTIPLIER_DENSITY;
} else {
sf.dropped = FEATURE_DROPPED;
}
@@ -2143,7 +2153,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
sf.dropped = FEATURE_KEPT;
}
if (sf.dropped == FEATURE_KEPT && retain_points_multiplier > 1) {
if (sf.dropped == FEATURE_KEPT && (retain_points_multiplier > 1 || preserve_multiplier_density_threshold != 0 || preserve_multiplier_density_bits_by_zoom.size() > 0)) {
sf.full_keys.push_back(key_pool.pool("tippecanoe:retain_points_multiplier_first"));
sf.full_values.emplace_back(mvt_bool, "true");
}
@@ -2293,7 +2303,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
std::string const &layername = kv.first;
std::vector<std::shared_ptr<serial_feature>> &features = kv.second.features;
if (retain_points_multiplier > 1) {
if ((retain_points_multiplier > 1 || preserve_multiplier_density_threshold != 0 || preserve_multiplier_density_bits_by_zoom.size() > 0)) {
// mapping from input sequence to current sequence within this tile
std::vector<std::pair<size_t, size_t>> feature_sequences;
@@ -2820,7 +2830,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
}
if (skipped > 0 || too_many_bytes || too_many_features) {
fprintf(stderr, "Can't happen: writing tile even though we skipped\n");
fprintf(stderr, "Can't happen: writing tile even though we skipped (%zu %d %d)\n", skipped, too_many_bytes, too_many_features);
exit(EXIT_IMPOSSIBLE);
}