mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Remove undocumented command-line options (#361)
* Remove --accumulate-numeric-attributes * Remove join-sqlite, etc. * Remove --accumulate-numeric-attributes from overzoom * Remove --assign-to-bins and --bin-by-id-list * Remove --clip-polygon and --clip-bounding-box * Remove FSL expressions * Update version and changelog
This commit is contained in:
@@ -1214,47 +1214,6 @@ bool pnpoly_mp(drawvec const &geom, long long x, long long y) {
|
||||
return found;
|
||||
}
|
||||
|
||||
clipbbox parse_clip_poly(std::string arg) {
|
||||
json_pull *jp = json_begin_string(arg.c_str());
|
||||
json_object *j = json_read_tree(jp);
|
||||
if (j == NULL) {
|
||||
fprintf(stderr, "Expected JSON object, not %s\n", arg.c_str());
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
if (j->type != JSON_HASH) {
|
||||
fprintf(stderr, "Expected JSON geometry object, not %s\n", arg.c_str());
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
|
||||
std::pair<int, drawvec> parsed_geometry = parse_geometry(j, jp, j, 0, 0, 0, 1LL << 32, false, false);
|
||||
json_end(jp);
|
||||
|
||||
clipbbox out;
|
||||
out.minx = LLONG_MAX;
|
||||
out.miny = LLONG_MAX;
|
||||
out.maxx = LLONG_MIN;
|
||||
out.maxy = LLONG_MIN;
|
||||
for (auto const &d : parsed_geometry.second) {
|
||||
if (d.op == VT_MOVETO || d.op == VT_LINETO) {
|
||||
if (d.x < out.minx) {
|
||||
out.minx = d.x;
|
||||
}
|
||||
if (d.y < out.miny) {
|
||||
out.miny = d.y;
|
||||
}
|
||||
if (d.x > out.maxx) {
|
||||
out.maxx = d.x;
|
||||
}
|
||||
if (d.y > out.maxy) {
|
||||
out.maxy = d.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.dv = std::move(parsed_geometry.second);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int ny,
|
||||
int detail_or_unspecified, int buffer,
|
||||
std::set<std::string> const &keep,
|
||||
@@ -1266,9 +1225,9 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
|
||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||
std::vector<std::string> const &unidecode_data, double simplification,
|
||||
double tiny_polygon_size,
|
||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
||||
std::string const &accumulate_numeric, size_t feature_limit,
|
||||
std::vector<clipbbox> const &clipbboxes,
|
||||
std::vector<mvt_layer> const &unused2, std::string const &unused3,
|
||||
std::string const &unused, size_t feature_limit,
|
||||
std::vector<clipbbox> const &unused4,
|
||||
bool deduplicate_by_id) {
|
||||
std::vector<source_tile> decoded;
|
||||
|
||||
@@ -1295,7 +1254,7 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
|
||||
decoded.push_back(out);
|
||||
}
|
||||
|
||||
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, bins, bin_by_id_list, accumulate_numeric, feature_limit, clipbboxes, deduplicate_by_id);
|
||||
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, unused2, unused3, unused, feature_limit, unused4, deduplicate_by_id);
|
||||
}
|
||||
|
||||
// like a minimal serial_feature, but with mvt_feature-style attributes
|
||||
@@ -1330,152 +1289,6 @@ static bool should_keep(std::string const &key,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_mean(mvt_feature &feature, mvt_layer &layer, std::string const &accumulate_numeric,
|
||||
std::set<std::string> const &keep, std::set<std::string> const &exclude,
|
||||
std::vector<std::string> const &exclude_prefix) {
|
||||
std::string accumulate_numeric_colon = accumulate_numeric + ":";
|
||||
|
||||
std::unordered_map<std::string, size_t> attributes;
|
||||
for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) {
|
||||
std::string const &key = layer.keys[feature.tags[i]];
|
||||
if (starts_with(key, accumulate_numeric_colon)) {
|
||||
attributes.emplace(key, i);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) {
|
||||
std::string accumulate_numeric_sum_colon = accumulate_numeric + ":sum:";
|
||||
|
||||
std::string const &key = layer.keys[feature.tags[i]];
|
||||
if (starts_with(key, accumulate_numeric_sum_colon)) {
|
||||
std::string trunc = key.substr(accumulate_numeric_sum_colon.size());
|
||||
auto const f = attributes.find(accumulate_numeric + ":count:" + trunc);
|
||||
if (f != attributes.end()) {
|
||||
mvt_value const &sum = layer.values[feature.tags[i + 1]];
|
||||
mvt_value const &count = layer.values[feature.tags[f->second + 1]];
|
||||
double count_val = mvt_value_to_double(count);
|
||||
if (count_val <= 0) {
|
||||
fprintf(stderr, "can't happen: count is %s (type %d)\n", count.toString().c_str(), count.type);
|
||||
exit(EXIT_IMPOSSIBLE);
|
||||
}
|
||||
mvt_value mean;
|
||||
mean.type = mvt_double;
|
||||
mean.numeric_value.double_value = mvt_value_to_double(sum) / count_val;
|
||||
|
||||
if (should_keep(key, keep, exclude, exclude_prefix)) {
|
||||
layer.tag(feature, accumulate_numeric + ":mean:" + trunc, mean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// accumulate :sum:, :min:, :max:, and :count: versions of the specified attribute
|
||||
static void preserve_numeric(const std::string &key, const mvt_value &val, // numeric attribute being accumulated
|
||||
std::vector<std::shared_ptr<std::string>> &full_keys, // keys of feature being accumulated onto
|
||||
std::vector<mvt_value> &full_values, // values of features being accumulated onto
|
||||
const std::string &accumulate_numeric, // prefix of accumulations
|
||||
std::set<std::string> &keys, // key presence in the source feature
|
||||
std::map<std::string, size_t> &numeric_out_field, // key index in the output feature
|
||||
key_pool &key_pool,
|
||||
std::set<std::string> const &keep, std::set<std::string> const &exclude,
|
||||
std::vector<std::string> const &exclude_prefix) {
|
||||
// If this is a numeric attribute, but there is also a prefix:sum (etc.) for the
|
||||
// same attribute, we want to use that one instead of this one.
|
||||
|
||||
for (auto const &op : numeric_operations) {
|
||||
std::string compound_key = accumulate_numeric + ":" + op.first + ":" + key;
|
||||
auto compound_found = keys.find(compound_key);
|
||||
if (compound_found != keys.end()) {
|
||||
// found, so skip this one
|
||||
} else {
|
||||
// not found, so accumulate this one
|
||||
|
||||
// if this is already prefixed, strip off the prefix
|
||||
// if it is the right one, and skip the attribute if
|
||||
// it is the wrong one.
|
||||
|
||||
std::string outkey = key;
|
||||
bool starting_from_accumulation;
|
||||
|
||||
if (starts_with(outkey, accumulate_numeric + ":")) {
|
||||
std::string prefix = accumulate_numeric + ":" + op.first + ":";
|
||||
if (starts_with(outkey, prefix)) {
|
||||
outkey = outkey.substr(prefix.size());
|
||||
starting_from_accumulation = true; // from a subaccumulation
|
||||
} else {
|
||||
continue; // to next operation
|
||||
}
|
||||
} else {
|
||||
starting_from_accumulation = false; // from a plain value
|
||||
}
|
||||
// and then put it back on for the output field
|
||||
std::string prefixed = accumulate_numeric + ":" + op.first + ":" + outkey;
|
||||
|
||||
if (!should_keep(prefixed, keep, exclude, exclude_prefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does it exist in the output feature already?
|
||||
|
||||
auto prefixed_attr = numeric_out_field.find(prefixed);
|
||||
if (prefixed_attr == numeric_out_field.end()) {
|
||||
// No? Does it exist unprefixed in the output feature already?
|
||||
|
||||
auto out_attr = numeric_out_field.find(outkey);
|
||||
if (out_attr == numeric_out_field.end()) {
|
||||
// not present at all, so copy our value to the prefixed output
|
||||
numeric_out_field.emplace(prefixed, full_keys.size());
|
||||
full_keys.push_back(key_pool.pool(prefixed));
|
||||
|
||||
if (op.second == op_count) {
|
||||
if (starting_from_accumulation) {
|
||||
// copy our count
|
||||
full_values.push_back(val);
|
||||
} else {
|
||||
// new count of 1
|
||||
full_values.push_back(mvt_value(1));
|
||||
}
|
||||
} else {
|
||||
full_values.push_back(val);
|
||||
}
|
||||
} else {
|
||||
// exists unprefixed, so copy it, and then accumulate on our value
|
||||
numeric_out_field.emplace(prefixed, full_keys.size());
|
||||
full_keys.push_back(key_pool.pool(prefixed));
|
||||
|
||||
if (op.second == op_count) {
|
||||
mvt_value v;
|
||||
if (starting_from_accumulation) {
|
||||
// sum our count onto the existing 1
|
||||
v = mvt_value(1 + mvt_value_to_long_long(val));
|
||||
} else {
|
||||
// sum our 1 onto the existing 1
|
||||
v = mvt_value(2);
|
||||
}
|
||||
full_values.push_back(v);
|
||||
} else {
|
||||
full_values.push_back(full_values[out_attr->second]);
|
||||
preserve_attribute(op.second, prefixed, val, full_keys, full_values, key_pool);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// exists, so accumulate on our value
|
||||
if (op.second == op_count) {
|
||||
if (starting_from_accumulation) {
|
||||
// sum our count onto the existing count
|
||||
full_values[prefixed_attr->second] = mvt_value(mvt_value_to_long_long(full_values[prefixed_attr->second]) + mvt_value_to_long_long(val));
|
||||
} else {
|
||||
full_values[prefixed_attr->second] = mvt_value(mvt_value_to_long_long(full_values[prefixed_attr->second]) + 1);
|
||||
}
|
||||
} else {
|
||||
preserve_attribute(op.second, prefixed, val, full_keys, full_values, key_pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_closepath_from_mvt(drawvec &geom) {
|
||||
// mvt geometries close polygons with a mvt_closepath operation
|
||||
// tippecanoe-internal geometries close polygons with a lineto to the initial point
|
||||
@@ -1497,9 +1310,9 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
std::set<std::string> const &exclude,
|
||||
std::vector<std::string> const &exclude_prefix,
|
||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||
std::string const &accumulate_numeric,
|
||||
std::string const &,
|
||||
key_pool &key_pool, int buffer, bool include_nonaggregate,
|
||||
std::vector<clipbbox> const &clipbboxes, int nz, int nx, int ny,
|
||||
std::vector<clipbbox> const &, int, int, int,
|
||||
std::set<unsigned long long> *deduplicate_ids) {
|
||||
// Add geometry to output feature
|
||||
|
||||
@@ -1507,7 +1320,7 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
int t = features[0].t;
|
||||
|
||||
bool fix_polygons = false;
|
||||
if ((buffer >= 0 || clipbboxes.size() > 0) && t == VT_POLYGON) {
|
||||
if ((buffer >= 0) && t == VT_POLYGON) {
|
||||
fix_polygons = true;
|
||||
}
|
||||
|
||||
@@ -1528,48 +1341,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
geom = remove_noop(geom, t, 0);
|
||||
}
|
||||
|
||||
if (clipbboxes.size() != 0) {
|
||||
// bounding box is in world coordinates at world scale
|
||||
// feature is in local coordinates at tile scale
|
||||
|
||||
long long dx = (long long) nx << (32 - nz);
|
||||
long long dy = (long long) ny << (32 - nz);
|
||||
double scale = (double) outlayer.extent / (1LL << (32 - nz));
|
||||
|
||||
for (auto const &c_world : clipbboxes) {
|
||||
clipbbox c = c_world;
|
||||
|
||||
c.minx = std::llround((c_world.minx - dx) * scale);
|
||||
c.miny = std::llround((c_world.miny - dy) * scale);
|
||||
c.maxx = std::llround((c_world.maxx - dx) * scale);
|
||||
c.maxy = std::llround((c_world.maxy - dy) * scale);
|
||||
|
||||
for (auto &p : c.dv) {
|
||||
p.x = std::llround((p.x - dx) * scale);
|
||||
p.y = std::llround((p.y - dy) * scale);
|
||||
}
|
||||
|
||||
if (t == VT_POLYGON) {
|
||||
geom = simple_clip_poly(geom, c.minx, c.miny, c.maxx, c.maxy, false);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_poly_poly(geom, c.dv);
|
||||
}
|
||||
} else if (t == VT_LINE) {
|
||||
geom = clip_lines(geom, c.minx, c.miny, c.maxx, c.maxy);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_lines_poly(geom, c.dv);
|
||||
}
|
||||
} else if (t == VT_POINT) {
|
||||
geom = clip_point(geom, c.minx, c.miny, c.maxx, c.maxy);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_point_poly(geom, c.dv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geom = remove_noop(geom, t, 0);
|
||||
}
|
||||
|
||||
if (fix_polygons) {
|
||||
geom = clean_or_clip_poly(geom, 0, 0, false, false);
|
||||
geom = close_poly(geom);
|
||||
@@ -1599,7 +1370,7 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
|
||||
outfeature.seq = features[0].seq;
|
||||
|
||||
if (attribute_accum.size() > 0 || accumulate_numeric.size() > 0) {
|
||||
if (attribute_accum.size() > 0) {
|
||||
// convert the attributes of the output feature
|
||||
// from layer references to a vector so they can have
|
||||
// attributes from the other features of the
|
||||
@@ -1617,11 +1388,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
// this attribute has an accumulator, so convert it
|
||||
full_keys.push_back(key_pool.pool(f.layer->keys[f.tags[i]]));
|
||||
full_values.push_back(f.layer->values[f.tags[i + 1]]);
|
||||
} else if (accumulate_numeric.size() > 0 && f.layer->values[f.tags[i + 1]].is_numeric()) {
|
||||
// convert numeric for accumulation
|
||||
numeric_out_field.emplace(key, full_keys.size());
|
||||
full_keys.push_back(key_pool.pool(key));
|
||||
full_values.push_back(f.layer->values[f.tags[i + 1]]);
|
||||
} else if (include_nonaggregate) {
|
||||
// otherwise just tag it directly onto the output feature
|
||||
outlayer.tag(outfeature, f.layer->keys[f.tags[i]], f.layer->values[f.tags[i + 1]]);
|
||||
@@ -1650,14 +1416,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
if (found != attribute_accum.end()) {
|
||||
mvt_value val = features[i].layer->values[features[i].tags[j + 1]];
|
||||
preserve_attribute(found->second, key, val, full_keys, full_values, key_pool);
|
||||
} else if (accumulate_numeric.size() > 0) {
|
||||
const mvt_value &val = features[i].layer->values[features[i].tags[j + 1]];
|
||||
if (val.is_numeric()) {
|
||||
preserve_numeric(key, val, full_keys, full_values,
|
||||
accumulate_numeric,
|
||||
keys, numeric_out_field, key_pool,
|
||||
keep, exclude, exclude_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1671,10 +1429,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
||||
outlayer.tag(outfeature, *full_keys[i], full_values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (accumulate_numeric.size() > 0) {
|
||||
add_mean(outfeature, outlayer, accumulate_numeric, keep, exclude, exclude_prefix);
|
||||
}
|
||||
} else if (include_nonaggregate) {
|
||||
for (size_t i = 0; i + 1 < features[0].tags.size(); i += 2) {
|
||||
if (should_keep(features[0].layer->keys[features[0].tags[i]], keep, exclude, exclude_prefix)) {
|
||||
@@ -1696,316 +1450,6 @@ static struct preservecmp {
|
||||
}
|
||||
} preservecmp;
|
||||
|
||||
struct index_event {
|
||||
unsigned long long where;
|
||||
enum index_event_kind {
|
||||
ENTER = 0, // new bin in is now active
|
||||
CHECK, // point needs to be checked against active bins
|
||||
EXIT // bin has ceased to be active
|
||||
} kind;
|
||||
size_t layer;
|
||||
size_t feature;
|
||||
long long xmin, ymin, xmax, ymax;
|
||||
|
||||
index_event(unsigned long long where_, index_event_kind kind_, size_t layer_, size_t feature_,
|
||||
long long xmin_, long long ymin_, long long xmax_, long long ymax_)
|
||||
: where(where_), kind(kind_), layer(layer_), feature(feature_), xmin(xmin_), ymin(ymin_), xmax(xmax_), ymax(ymax_) {
|
||||
}
|
||||
|
||||
bool operator<(const index_event &ie) const {
|
||||
if (where < ie.where) {
|
||||
return true;
|
||||
} else if (where == ie.where) {
|
||||
if (kind < ie.kind) {
|
||||
return true;
|
||||
} else if (kind == ie.kind) {
|
||||
if (layer < ie.layer) {
|
||||
return true;
|
||||
} else if (layer == ie.layer) {
|
||||
if (feature < ie.feature) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct active_bin {
|
||||
size_t layer;
|
||||
size_t feature;
|
||||
|
||||
active_bin(size_t layer_, size_t feature_)
|
||||
: layer(layer_), feature(feature_) {
|
||||
}
|
||||
|
||||
bool operator<(const active_bin &o) const {
|
||||
if (layer < o.layer) {
|
||||
return true;
|
||||
} else if (layer == o.layer) {
|
||||
if (feature < o.feature) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t outfeature;
|
||||
long long xmin, ymin, xmax, ymax;
|
||||
size_t counter = 0;
|
||||
};
|
||||
|
||||
void get_quadkey_bounds(long long xmin, long long ymin, long long xmax, long long ymax,
|
||||
unsigned long long *start, unsigned long long *end) {
|
||||
if (xmin < 0 || ymin < 0 || xmax >= 1LL << 32 || ymax >= 1LL << 32) {
|
||||
*start = 0;
|
||||
*end = ULLONG_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
*start = encode_quadkey(xmin, ymin);
|
||||
*end = encode_quadkey(xmax, ymax);
|
||||
|
||||
for (ssize_t i = 62; i >= 0; i -= 2) {
|
||||
if ((*start & (3LL << i)) != (*end & (3LL << i))) {
|
||||
for (; i >= 0; i -= 2) {
|
||||
*start &= ~(3LL << i);
|
||||
*end |= 3LL << i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool bbox_intersects(long long x1min, long long y1min, long long x1max, long long y1max,
|
||||
long long x2min, long long y2min, long long x2max, long long y2max) {
|
||||
if (x1max < x2min) {
|
||||
return false;
|
||||
}
|
||||
if (x2max < x1min) {
|
||||
return false;
|
||||
}
|
||||
if (y1max < y2min) {
|
||||
return false;
|
||||
}
|
||||
if (y2max < y1min) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<size_t> parse_ids_string(mvt_value const &v) {
|
||||
std::vector<size_t> out;
|
||||
std::string s = v.toString();
|
||||
|
||||
for (size_t i = 0; i < s.size(); i++) {
|
||||
if (i == 0 || s[i - 1] == ',') {
|
||||
out.push_back(atoll(s.c_str() + i));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
mvt_tile assign_to_bins(mvt_tile &features,
|
||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
||||
int z, int x, int y,
|
||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||
std::string const &accumulate_numeric,
|
||||
std::set<std::string> keep,
|
||||
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;
|
||||
|
||||
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 (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 (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];
|
||||
if (feature.geometry.size() > 0) {
|
||||
tile_feature outfeature;
|
||||
for (auto const &g : feature.geometry) {
|
||||
outfeature.geom.emplace_back(g.op, g.x, g.y);
|
||||
}
|
||||
feature.geometry.clear();
|
||||
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.back().push_back(std::move(outfeature));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, NULL)) {
|
||||
mvt_feature &nfeature = outlayer.features.back();
|
||||
mvt_value val;
|
||||
val.type = mvt_uint;
|
||||
val.numeric_value.uint_value = outfeatures[i].size() - 1;
|
||||
|
||||
std::string attrname;
|
||||
if (accumulate_numeric.size() == 0) {
|
||||
attrname = "tippecanoe:count";
|
||||
} else {
|
||||
attrname = accumulate_numeric + ":count";
|
||||
}
|
||||
if (should_keep(attrname, keep, exclude, exclude_prefix)) {
|
||||
outlayer.tag(nfeature, attrname, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mvt_tile ret;
|
||||
ret.layers.push_back(outlayer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int ny,
|
||||
int detail_or_unspecified, int buffer,
|
||||
std::set<std::string> const &keep,
|
||||
@@ -2017,9 +1461,9 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||
std::vector<std::string> const &unidecode_data, double simplification,
|
||||
double tiny_polygon_size,
|
||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
||||
std::string const &accumulate_numeric, size_t feature_limit,
|
||||
std::vector<clipbbox> const &clipbboxes,
|
||||
std::vector<mvt_layer> const &unused2, std::string const &unused3,
|
||||
std::string const &unused, size_t feature_limit,
|
||||
std::vector<clipbbox> const &unused4,
|
||||
bool deduplicate_by_id) {
|
||||
mvt_tile outtile;
|
||||
key_pool key_pool;
|
||||
@@ -2093,30 +1537,6 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
}
|
||||
}
|
||||
|
||||
// Clip to user-specified bounding boxes.
|
||||
// Bounding box clip first, to reduce complexity of the full clip.
|
||||
// But don't clip here if we are binning, because we need to bin points in the buffer
|
||||
if (bins.size() == 0) {
|
||||
for (auto &c : clipbboxes) {
|
||||
if (t == VT_POLYGON) {
|
||||
geom = simple_clip_poly(geom, c.minx, c.miny, c.maxx, c.maxy, false);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_poly_poly(geom, c.dv);
|
||||
}
|
||||
} else if (t == VT_LINE) {
|
||||
geom = clip_lines(geom, c.minx, c.miny, c.maxx, c.maxy);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_lines_poly(geom, c.dv);
|
||||
}
|
||||
} else if (t == VT_POINT) {
|
||||
geom = clip_point(geom, c.minx, c.miny, c.maxx, c.maxy);
|
||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
||||
geom = clip_point_poly(geom, c.dv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now offset from world coordinates to output tile coordinates,
|
||||
// but retain world scale, because that is what tippecanoe zoom-oriented clipping expects
|
||||
|
||||
@@ -2126,8 +1546,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
g.y -= ny * outtilesize;
|
||||
}
|
||||
|
||||
// Don't clip here if we are binning, because we need to bin points in the buffer
|
||||
if (bins.size() == 0) {
|
||||
{
|
||||
// Clip to output tile
|
||||
|
||||
long long xmin = LLONG_MAX;
|
||||
@@ -2190,7 +1609,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
|
||||
if (flush_multiplier_cluster) {
|
||||
if (pending_tile_features.size() > 0) {
|
||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric, key_pool, -1, bins.size() == 0, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, unused, key_pool, -1, true, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||
if (outlayer->features.size() >= feature_limit) {
|
||||
break;
|
||||
}
|
||||
@@ -2262,7 +1681,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
}
|
||||
|
||||
if (pending_tile_features.size() > 0) {
|
||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric, key_pool, -1, bins.size() == 0, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, unused, key_pool, -1, true, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||
pending_tile_features.clear();
|
||||
if (outlayer->features.size() >= feature_limit) {
|
||||
break;
|
||||
@@ -2301,8 +1720,8 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
nz + 1, nx * 2 + x, ny * 2 + y,
|
||||
detail_or_unspecified, buffer, keep, exclude, exclude_prefix, false, NULL,
|
||||
demultiply, filter, preserve_input_order, attribute_accum, unidecode_data,
|
||||
simplification, tiny_polygon_size, bins, bin_by_id_list, accumulate_numeric,
|
||||
1, clipbboxes, deduplicate_by_id);
|
||||
simplification, tiny_polygon_size, unused2, unused3, unused,
|
||||
1, unused4, deduplicate_by_id);
|
||||
if (child.size() > 0) {
|
||||
next_overzoomed_tiles->emplace_back(nx * 2 + x, ny * 2 + y);
|
||||
}
|
||||
@@ -2311,12 +1730,6 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
||||
}
|
||||
}
|
||||
|
||||
if (bins.size() > 0) {
|
||||
outtile = assign_to_bins(outtile, bins, bin_by_id_list, nz, nx, ny,
|
||||
attribute_accum, accumulate_numeric,
|
||||
keep, exclude, exclude_prefix, buffer, clipbboxes);
|
||||
}
|
||||
|
||||
for (ssize_t i = outtile.layers.size() - 1; i >= 0; i--) {
|
||||
if (outtile.layers[i].features.size() == 0) {
|
||||
outtile.layers.erase(outtile.layers.begin() + i);
|
||||
|
||||
Reference in New Issue
Block a user