Performance optimizations for binning (#283)

* Add an all-mvt_value attribute accumulation path

* Only bin by ID, not geometrically

* A little cleanup; changelog and version; test

* Remove accidental double-conversion

* Replace duplicated code with template

* Update changelog
This commit is contained in:
Erica Fischer
2024-11-01 15:27:13 -07:00
committed by GitHub
parent 120b8f4e41
commit b3b89e1e07
9 changed files with 105 additions and 68 deletions
+6
View File
@@ -1,3 +1,9 @@
# 2.66.0
* Only bin by ID, not by geometry, if --bin-by-id-list is specified
* Do attribute accumulation in overzoom in mvt_value instead of converting to serial_val
* Fix bool values read from flatgeobuf sources (#289)
# 2.65.0
* Improve spatial distribution of --retain-points-multiplier features
+30 -33
View File
@@ -88,36 +88,33 @@ void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribut
set_attribute_accum(attribute_accum, name, type);
}
void preserve_attribute(attribute_op const &op, std::string const &key, serial_val const &val, std::vector<std::string> &full_keys, std::vector<serial_val> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state) {
template <class T>
static void preserve_attribute1(attribute_op const &op, std::string const &key, T const &val, std::vector<std::string> &full_keys, std::vector<T> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state) {
for (size_t i = 0; i < full_keys.size(); i++) {
if (key == full_keys[i]) {
switch (op) {
case op_sum:
full_values[i].s = milo::dtoa_milo(atof(full_values[i].s.c_str()) + atof(val.s.c_str()));
full_values[i].type = mvt_double;
full_values[i] = (full_values[i].to_double() + val.to_double());
return;
case op_product:
full_values[i].s = milo::dtoa_milo(atof(full_values[i].s.c_str()) * atof(val.s.c_str()));
full_values[i].type = mvt_double;
full_values[i] = (full_values[i].to_double() * val.to_double());
return;
case op_max: {
double existing = atof(full_values[i].s.c_str());
double maybe = atof(val.s.c_str());
double existing = full_values[i].to_double();
double maybe = val.to_double();
if (maybe > existing) {
full_values[i].s = val.s.c_str();
full_values[i].type = mvt_double;
full_values[i] = val;
}
return;
}
case op_min: {
double existing = atof(full_values[i].s.c_str());
double maybe = atof(val.s.c_str());
double existing = full_values[i].to_double();
double maybe = val.to_double();
if (maybe < existing) {
full_values[i].s = val.s.c_str();
full_values[i].type = mvt_double;
full_values[i] = val;
}
return;
}
@@ -126,30 +123,26 @@ void preserve_attribute(attribute_op const &op, std::string const &key, serial_v
auto state = attribute_accum_state.find(key);
if (state == attribute_accum_state.end()) {
accum_state s;
s.sum = atof(full_values[i].s.c_str()) + atof(val.s.c_str());
s.sum = full_values[i].to_double() + val.to_double();
s.count = 2;
attribute_accum_state.insert(std::pair<std::string, accum_state>(key, s));
full_values[i].s = milo::dtoa_milo(s.sum / s.count);
full_values[i].type = mvt_double;
full_values[i] = (s.sum / s.count);
} else {
state->second.sum += atof(val.s.c_str());
state->second.sum += val.to_double();
state->second.count += 1;
full_values[i].s = milo::dtoa_milo(state->second.sum / state->second.count);
full_values[i].type = mvt_double;
full_values[i] = (state->second.sum / state->second.count);
}
return;
}
case op_concat:
full_values[i].s += val.s;
full_values[i].type = mvt_string;
full_values[i].set_string_value(full_values[i].get_string_value() + val.get_string_value());
return;
case op_comma:
full_values[i].s += std::string(",") + val.s;
full_values[i].type = mvt_string;
full_values[i].set_string_value(full_values[i].get_string_value() + "," + val.get_string_value());
return;
case op_count: {
@@ -159,12 +152,10 @@ void preserve_attribute(attribute_op const &op, std::string const &key, serial_v
s.count = 2;
attribute_accum_state.insert(std::pair<std::string, accum_state>(key, s));
full_values[i].type = mvt_double;
full_values[i].s = std::to_string(s.count);
full_values[i] = (s.count);
} else { // already present, incrementing
state->second.count += 1;
full_values[i].type = mvt_double;
full_values[i].s = std::to_string(state->second.count);
full_values[i] = (state->second.count);
}
return;
}
@@ -174,13 +165,12 @@ void preserve_attribute(attribute_op const &op, std::string const &key, serial_v
// not found, so we are making a new value
serial_val sv;
T v;
switch (op) {
case op_sum:
case op_max:
case op_min:
sv.s = val.s;
sv.type = mvt_double;
v = val;
break;
case op_count: {
@@ -190,12 +180,11 @@ void preserve_attribute(attribute_op const &op, std::string const &key, serial_v
s.count = 1;
attribute_accum_state.insert(std::pair<std::string, accum_state>(key, s));
sv.s = std::to_string(s.count);
v = (s.count);
} else { // already present, incrementing
fprintf(stderr, "preserve_attribute: can't happen (count)\n");
exit(EXIT_IMPOSSIBLE);
}
sv.type = mvt_double;
break;
}
@@ -205,5 +194,13 @@ void preserve_attribute(attribute_op const &op, std::string const &key, serial_v
}
full_keys.push_back(key);
full_values.push_back(sv);
full_values.push_back(v);
}
void preserve_attribute(attribute_op const &op, std::string const &key, mvt_value const &val, std::vector<std::string> &full_keys, std::vector<mvt_value> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state) {
preserve_attribute1(op, key, val, full_keys, full_values, attribute_accum_state);
}
void preserve_attribute(attribute_op const &op, std::string const &key, serial_val const &val, std::vector<std::string> &full_keys, std::vector<serial_val> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state) {
preserve_attribute1(op, key, val, full_keys, full_values, attribute_accum_state);
}
+5 -1
View File
@@ -4,6 +4,8 @@
#include <vector>
#include <unordered_map>
#include <map>
#include "mvt.hpp"
#include "milo/dtoa_milo.h"
enum attribute_op {
op_sum,
@@ -25,7 +27,9 @@ struct serial_val;
void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribute_accum, std::string name, std::string type);
void set_attribute_accum(std::unordered_map<std::string, attribute_op> &attribute_accum, const char *arg, char **argv);
void preserve_attribute(attribute_op const &op, const std::string &key, serial_val const &val, std::vector<std::string> &full_keys, std::vector<serial_val> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state);
void preserve_attribute(attribute_op const &op, std::string const &key, serial_val const &val, std::vector<std::string> &full_keys, std::vector<serial_val> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state);
void preserve_attribute(attribute_op const &op, std::string const &key, mvt_value const &val, std::vector<std::string> &full_keys, std::vector<mvt_value> &full_values, std::unordered_map<std::string, accum_state> &attribute_accum_state);
extern std::map<std::string, attribute_op> numeric_operations;
+25 -28
View File
@@ -1165,7 +1165,7 @@ static void add_mean(mvt_feature &feature, mvt_layer &layer, std::string const &
// 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::string> &full_keys, // keys of feature being accumulated onto
std::vector<serial_val> &full_values, // values of features 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
@@ -1218,16 +1218,13 @@ static void preserve_numeric(const std::string &key, const mvt_value &val, /
if (op.second == op_count) {
if (starting_from_accumulation) {
// copy our count
full_values.push_back(mvt_value_to_serial_val(val));
full_values.push_back(val);
} else {
// new count of 1
serial_val sv;
sv.type = mvt_double;
sv.s = "1";
full_values.push_back(sv);
full_values.push_back(mvt_value(1));
}
} else {
full_values.push_back(mvt_value_to_serial_val(val));
full_values.push_back(val);
}
} else {
// exists unprefixed, so copy it, and then accumulate on our value
@@ -1235,19 +1232,18 @@ static void preserve_numeric(const std::string &key, const mvt_value &val, /
full_keys.push_back(prefixed);
if (op.second == op_count) {
serial_val sv;
sv.type = mvt_double;
mvt_value v;
if (starting_from_accumulation) {
// sum our count onto the existing 1
sv.s = std::to_string(1 + mvt_value_to_long_long(val));
v = mvt_value(1 + mvt_value_to_long_long(val));
} else {
// sum our 1 onto the existing 1
sv.s = "2";
v = mvt_value(2);
}
full_values.push_back(sv);
full_values.push_back(v);
} else {
full_values.push_back(full_values[out_attr->second]);
preserve_attribute(op.second, prefixed, mvt_value_to_serial_val(val), full_keys, full_values, attribute_accum_state);
preserve_attribute(op.second, prefixed, val, full_keys, full_values, attribute_accum_state);
}
}
} else {
@@ -1255,12 +1251,12 @@ static void preserve_numeric(const std::string &key, const mvt_value &val, /
if (op.second == op_count) {
if (starting_from_accumulation) {
// sum our count onto the existing count
full_values[prefixed_attr->second].s = std::to_string(atoll(full_values[prefixed_attr->second].s.c_str()) + mvt_value_to_long_long(val));
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].s = std::to_string(atoll(full_values[prefixed_attr->second].s.c_str()) + 1);
full_values[prefixed_attr->second] = mvt_value(mvt_value_to_long_long(full_values[prefixed_attr->second]) + 1);
}
} else {
preserve_attribute(op.second, prefixed, mvt_value_to_serial_val(val), full_keys, full_values, attribute_accum_state);
preserve_attribute(op.second, prefixed, val, full_keys, full_values, attribute_accum_state);
}
}
}
@@ -1293,7 +1289,6 @@ static void 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::shared_ptr<std::string> const &tile_stringpool,
std::string const &accumulate_numeric) {
// Add geometry to output feature
@@ -1315,13 +1310,13 @@ static void feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
if (attribute_accum.size() > 0 || accumulate_numeric.size() > 0) {
// convert the attributes of the output feature
// from mvt_value to serial_val so they can have
// from layer references to a vector so they can have
// attributes from the other features of the
// multiplier cluster accumulated onto them
std::unordered_map<std::string, accum_state> attribute_accum_state;
std::vector<std::string> full_keys;
std::vector<serial_val> full_values;
std::vector<mvt_value> full_values;
std::map<std::string, size_t> numeric_out_field;
for (size_t i = 0; i + 1 < features[0].tags.size(); i += 2) {
@@ -1330,12 +1325,12 @@ static void feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
if (f != attribute_accum.end()) {
// this attribute has an accumulator, so convert it
full_keys.push_back(features[0].layer->keys[features[0].tags[i]]);
full_values.push_back(mvt_value_to_serial_val(features[0].layer->values[features[0].tags[i + 1]]));
full_values.push_back(features[0].layer->values[features[0].tags[i + 1]]);
} else if (accumulate_numeric.size() > 0 && features[0].layer->values[features[0].tags[i + 1]].is_numeric()) {
// convert numeric for accumulation
numeric_out_field.emplace(key, full_keys.size());
full_keys.push_back(key);
full_values.push_back(mvt_value_to_serial_val(features[0].layer->values[features[0].tags[i + 1]]));
full_values.push_back(features[0].layer->values[features[0].tags[i + 1]]);
} else {
// otherwise just tag it directly onto the output feature
if (should_keep(features[0].layer->keys[features[0].tags[i]], keep, exclude, exclude_prefix)) {
@@ -1361,7 +1356,7 @@ static void feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
auto f = attribute_accum.find(key);
if (f != attribute_accum.end()) {
serial_val val = mvt_value_to_serial_val(features[i].layer->values[features[i].tags[j + 1]]);
mvt_value val = features[i].layer->values[features[i].tags[j + 1]];
preserve_attribute(f->second, key, val, full_keys, full_values, attribute_accum_state);
} else if (accumulate_numeric.size() > 0) {
const mvt_value &val = features[i].layer->values[features[i].tags[j + 1]];
@@ -1379,7 +1374,7 @@ static void feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
for (size_t i = 0; i < full_keys.size(); i++) {
if (should_keep(full_keys[i], keep, exclude, exclude_prefix)) {
outlayer.tag(outfeature, full_keys[i], stringified_to_mvt_value(full_values[i].type, full_values[i].s.c_str(), tile_stringpool));
outlayer.tag(outfeature, full_keys[i], full_values[i]);
}
}
@@ -1570,7 +1565,6 @@ mvt_tile assign_to_bins(mvt_tile &features,
outlayer.name = features.layers[0].name;
std::vector<std::vector<tile_feature>> outfeatures;
std::shared_ptr<std::string> tile_stringpool = std::make_shared<std::string>();
for (auto &e : events) {
if (e.kind == index_event::ENTER) {
@@ -1629,6 +1623,10 @@ mvt_tile assign_to_bins(mvt_tile &features,
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) {
@@ -1680,7 +1678,7 @@ mvt_tile assign_to_bins(mvt_tile &features,
if (outfeatures[i].size() > 1) {
feature_out(outfeatures[i], outlayer,
keep, exclude, exclude_prefix, attribute_accum,
tile_stringpool, accumulate_numeric);
accumulate_numeric);
mvt_feature &nfeature = outlayer.features.back();
mvt_value val;
val.type = mvt_uint;
@@ -1715,7 +1713,6 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
std::string const &accumulate_numeric) {
mvt_tile outtile;
std::shared_ptr<std::string> tile_stringpool = std::make_shared<std::string>();
for (auto const &tile : tiles) {
for (auto const &layer : tile.tile.layers) {
@@ -1840,7 +1837,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, tile_stringpool, accumulate_numeric);
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric);
pending_tile_features.clear();
}
}
@@ -1897,7 +1894,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, tile_stringpool, accumulate_numeric);
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric);
pending_tile_features.clear();
}
+17 -2
View File
@@ -76,6 +76,9 @@ enum mvt_value_type {
mvt_no_such_key,
};
struct mvt_value;
double mvt_value_to_double(mvt_value const &v);
struct mvt_value {
mvt_value_type type;
std::shared_ptr<std::string> s;
@@ -95,7 +98,11 @@ struct mvt_value {
} numeric_value;
std::string get_string_value() const {
return std::string(*s, numeric_value.string_value.off, numeric_value.string_value.len);
if (type == mvt_string) {
return std::string(*s, numeric_value.string_value.off, numeric_value.string_value.len);
} else {
return toString();
}
}
std::string_view get_string_view() const {
@@ -126,6 +133,10 @@ struct mvt_value {
type == mvt_sint;
}
double to_double() const {
return mvt_value_to_double(*this);
}
bool operator<(const mvt_value &o) const;
bool operator==(const mvt_value &o) const;
std::string toString() const;
@@ -134,6 +145,11 @@ struct mvt_value {
this->type = mvt_double;
this->numeric_value.double_value = 0;
}
mvt_value(double v) {
this->type = mvt_double;
this->numeric_value.double_value = v;
}
};
template <>
@@ -201,7 +217,6 @@ int dezig(unsigned n);
mvt_value stringified_to_mvt_value(int type, const char *s, std::shared_ptr<std::string> const &tile_stringpool);
long long mvt_value_to_long_long(mvt_value const &v);
double mvt_value_to_double(mvt_value const &v);
bool is_integer(const char *s, long long *v);
bool is_unsigned_integer(const char *s, unsigned long long *v);
+20
View File
@@ -49,6 +49,26 @@ struct serial_val {
serial_val(int t, const std::string &val)
: type(t), s(val) {
}
// These functions for interface compatibility with mvt_value:
serial_val(double val) {
type = mvt_double;
s = milo::dtoa_milo(val);
}
double to_double() const {
return atof(s.c_str());
}
std::string get_string_value() const {
return s;
}
void set_string_value(std::string const &val) {
type = mvt_string;
s = val;
}
};
struct serial_feature {
@@ -3,7 +3,5 @@
{ "type": "Feature", "properties": { "bin-ids": "236,237,510,514", "ZCTA5CE10": "94129", "GEOID10": "94129", "CLASSFP10": "B5", "MTFCC10": "G6350", "FUNCSTAT10": "S", "ALAND10": 5968455, "AWATER10": 14697, "INTPTLAT10": "+37.7973402", "INTPTLON10": "-122.4644664", "tippecanoe:count": 4 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.477818, 37.811005 ], [ -122.476444, 37.810869 ], [ -122.476101, 37.809648 ], [ -122.474728, 37.809241 ], [ -122.472668, 37.808970 ], [ -122.470608, 37.808563 ], [ -122.469234, 37.807750 ], [ -122.468719, 37.807071 ], [ -122.468376, 37.806800 ], [ -122.468204, 37.806936 ], [ -122.468204, 37.806665 ], [ -122.466660, 37.805851 ], [ -122.463570, 37.804901 ], [ -122.461681, 37.804901 ], [ -122.458420, 37.805444 ], [ -122.454472, 37.806529 ], [ -122.452412, 37.806258 ], [ -122.448120, 37.806936 ], [ -122.448120, 37.806393 ], [ -122.448463, 37.806122 ], [ -122.448292, 37.804766 ], [ -122.451553, 37.803409 ], [ -122.450180, 37.802867 ], [ -122.450008, 37.802460 ], [ -122.447605, 37.800697 ], [ -122.447262, 37.798527 ], [ -122.448120, 37.798255 ], [ -122.448292, 37.797848 ], [ -122.447948, 37.797441 ], [ -122.448635, 37.797441 ], [ -122.448635, 37.797034 ], [ -122.447948, 37.796899 ], [ -122.447948, 37.796492 ], [ -122.448978, 37.796356 ], [ -122.447433, 37.795814 ], [ -122.447433, 37.795542 ], [ -122.447777, 37.795407 ], [ -122.448635, 37.795542 ], [ -122.448978, 37.795000 ], [ -122.448635, 37.794728 ], [ -122.447948, 37.793101 ], [ -122.448463, 37.792829 ], [ -122.448635, 37.791880 ], [ -122.470951, 37.787267 ], [ -122.473354, 37.787132 ], [ -122.475586, 37.786725 ], [ -122.479877, 37.786860 ], [ -122.483826, 37.787674 ], [ -122.484512, 37.789167 ], [ -122.483997, 37.789709 ], [ -122.484341, 37.790116 ], [ -122.484341, 37.789709 ], [ -122.485027, 37.789574 ], [ -122.485886, 37.790795 ], [ -122.483654, 37.794050 ], [ -122.482109, 37.798527 ], [ -122.481766, 37.798527 ], [ -122.481937, 37.798798 ], [ -122.481594, 37.798798 ], [ -122.481766, 37.798933 ], [ -122.480221, 37.801375 ], [ -122.479877, 37.802867 ], [ -122.478676, 37.805444 ], [ -122.478333, 37.808156 ], [ -122.477818, 37.808428 ], [ -122.477989, 37.810598 ], [ -122.477646, 37.810598 ], [ -122.477818, 37.811005 ] ], [ [ -122.452583, 37.803274 ], [ -122.452412, 37.803138 ], [ -122.450008, 37.802460 ], [ -122.451210, 37.803138 ], [ -122.452583, 37.803274 ] ] ], [ [ [ -122.466145, 37.806393 ], [ -122.465973, 37.806258 ], [ -122.466660, 37.805851 ], [ -122.466145, 37.806393 ] ] ], [ [ [ -122.469921, 37.809377 ], [ -122.469406, 37.809106 ], [ -122.470093, 37.809241 ], [ -122.469921, 37.809377 ] ] ] ] } }
,
{ "type": "Feature", "properties": { "bin-ids": "529,531", "ZCTA5CE10": "94123", "GEOID10": "94123", "CLASSFP10": "B5", "MTFCC10": "G6350", "FUNCSTAT10": "S", "ALAND10": 2646572, "AWATER10": 218721, "INTPTLAT10": "+37.8009336", "INTPTLON10": "-122.4383664", "tippecanoe:count": 2 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.443142, 37.809784 ], [ -122.439537, 37.808835 ], [ -122.440910, 37.806936 ], [ -122.435760, 37.807614 ], [ -122.435589, 37.807207 ], [ -122.435589, 37.806936 ], [ -122.433014, 37.807343 ], [ -122.433014, 37.807071 ], [ -122.434387, 37.806936 ], [ -122.434044, 37.806800 ], [ -122.433014, 37.806936 ], [ -122.432842, 37.806800 ], [ -122.434044, 37.806665 ], [ -122.434044, 37.806393 ], [ -122.433872, 37.806122 ], [ -122.433872, 37.805851 ], [ -122.433701, 37.805580 ], [ -122.432671, 37.805715 ], [ -122.432327, 37.805986 ], [ -122.431641, 37.803274 ], [ -122.425289, 37.804088 ], [ -122.424946, 37.803138 ], [ -122.426491, 37.803003 ], [ -122.426319, 37.802053 ], [ -122.424774, 37.802324 ], [ -122.424603, 37.801239 ], [ -122.426147, 37.801104 ], [ -122.425976, 37.800154 ], [ -122.424431, 37.800426 ], [ -122.423744, 37.796628 ], [ -122.433529, 37.795407 ], [ -122.433357, 37.794457 ], [ -122.434902, 37.794322 ], [ -122.435074, 37.795271 ], [ -122.436790, 37.795000 ], [ -122.436619, 37.794050 ], [ -122.440739, 37.793508 ], [ -122.440910, 37.794457 ], [ -122.441769, 37.794322 ], [ -122.441597, 37.793372 ], [ -122.446404, 37.792829 ], [ -122.446232, 37.791880 ], [ -122.447605, 37.791744 ], [ -122.448635, 37.794728 ], [ -122.448978, 37.795000 ], [ -122.448635, 37.795542 ], [ -122.447777, 37.795407 ], [ -122.447433, 37.795542 ], [ -122.447433, 37.795814 ], [ -122.448978, 37.796356 ], [ -122.447948, 37.796492 ], [ -122.447948, 37.796899 ], [ -122.448635, 37.797034 ], [ -122.448635, 37.797441 ], [ -122.447948, 37.797441 ], [ -122.448292, 37.797848 ], [ -122.448120, 37.798255 ], [ -122.447262, 37.798527 ], [ -122.447605, 37.800697 ], [ -122.450008, 37.802460 ], [ -122.450180, 37.802867 ], [ -122.451553, 37.803409 ], [ -122.448292, 37.804766 ], [ -122.448463, 37.806122 ], [ -122.448120, 37.806393 ], [ -122.448120, 37.806936 ], [ -122.448635, 37.808563 ], [ -122.443142, 37.809784 ] ] ], [ [ [ -122.432842, 37.805986 ], [ -122.432842, 37.805851 ], [ -122.433872, 37.805851 ], [ -122.432842, 37.805986 ] ] ], [ [ [ -122.433529, 37.807614 ], [ -122.433529, 37.807478 ], [ -122.435589, 37.807207 ], [ -122.433529, 37.807614 ] ] ], [ [ [ -122.452583, 37.803274 ], [ -122.451210, 37.803138 ], [ -122.450008, 37.802460 ], [ -122.452583, 37.803274 ] ] ], [ [ [ -122.432842, 37.806393 ], [ -122.432842, 37.806122 ], [ -122.433872, 37.806122 ], [ -122.432842, 37.806393 ] ] ], [ [ [ -122.432842, 37.806665 ], [ -122.432842, 37.806529 ], [ -122.434044, 37.806393 ], [ -122.432842, 37.806665 ] ] ], [ [ [ -122.433701, 37.808156 ], [ -122.433701, 37.807885 ], [ -122.433872, 37.807885 ], [ -122.433701, 37.808156 ] ] ] ] } }
,
{ "type": "Feature", "properties": { "ZCTA5CE10": "94107", "GEOID10": "94107", "CLASSFP10": "B5", "MTFCC10": "G6350", "FUNCSTAT10": "S", "ALAND10": 4647665, "AWATER10": 227634, "INTPTLAT10": "+37.7604596", "INTPTLON10": "-122.3997237", "tippecanoe:count": 5 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.385120, 37.791337 ], [ -122.381687, 37.783469 ], [ -122.384777, 37.782790 ], [ -122.384777, 37.782519 ], [ -122.387867, 37.782248 ], [ -122.387695, 37.781841 ], [ -122.385635, 37.781976 ], [ -122.385464, 37.781841 ], [ -122.384777, 37.781841 ], [ -122.385464, 37.781705 ], [ -122.385464, 37.781569 ], [ -122.387695, 37.781434 ], [ -122.387524, 37.781027 ], [ -122.384777, 37.781298 ], [ -122.384777, 37.781027 ], [ -122.387524, 37.780891 ], [ -122.387524, 37.780484 ], [ -122.387524, 37.780077 ], [ -122.387524, 37.779670 ], [ -122.387352, 37.779263 ], [ -122.387352, 37.778992 ], [ -122.384777, 37.779127 ], [ -122.384777, 37.778992 ], [ -122.387352, 37.778856 ], [ -122.387352, 37.778585 ], [ -122.387352, 37.778313 ], [ -122.387695, 37.778313 ], [ -122.387695, 37.778177 ], [ -122.390442, 37.777092 ], [ -122.390442, 37.776956 ], [ -122.390270, 37.776685 ], [ -122.392502, 37.775192 ], [ -122.394218, 37.776414 ], [ -122.396450, 37.774650 ], [ -122.396107, 37.774514 ], [ -122.397480, 37.773429 ], [ -122.397823, 37.772343 ], [ -122.398510, 37.772886 ], [ -122.400742, 37.771122 ], [ -122.396622, 37.767865 ], [ -122.393875, 37.766101 ], [ -122.393703, 37.764065 ], [ -122.387867, 37.764337 ], [ -122.387524, 37.760537 ], [ -122.386665, 37.760673 ], [ -122.386322, 37.758094 ], [ -122.385464, 37.758094 ], [ -122.384777, 37.757687 ], [ -122.381344, 37.757959 ], [ -122.381344, 37.756466 ], [ -122.381172, 37.755923 ], [ -122.380829, 37.755516 ], [ -122.380829, 37.755244 ], [ -122.384090, 37.754973 ], [ -122.384090, 37.754701 ], [ -122.383404, 37.754701 ], [ -122.382889, 37.754430 ], [ -122.381516, 37.754566 ], [ -122.380142, 37.754566 ], [ -122.379971, 37.753344 ], [ -122.386837, 37.752937 ], [ -122.386494, 37.750358 ], [ -122.393188, 37.749951 ], [ -122.393188, 37.751444 ], [ -122.395248, 37.751308 ], [ -122.395248, 37.749815 ], [ -122.403831, 37.749408 ], [ -122.402973, 37.752801 ], [ -122.403316, 37.756194 ], [ -122.403831, 37.757144 ], [ -122.406063, 37.759180 ], [ -122.406578, 37.760673 ], [ -122.405376, 37.763116 ], [ -122.405033, 37.764608 ], [ -122.401600, 37.764880 ], [ -122.401428, 37.763523 ], [ -122.400570, 37.763658 ], [ -122.400742, 37.766237 ], [ -122.399712, 37.766237 ], [ -122.399712, 37.766644 ], [ -122.400742, 37.767458 ], [ -122.401772, 37.767458 ], [ -122.402115, 37.769901 ], [ -122.403488, 37.769765 ], [ -122.403831, 37.770036 ], [ -122.399368, 37.773564 ], [ -122.402458, 37.776007 ], [ -122.401943, 37.776414 ], [ -122.403145, 37.777363 ], [ -122.403660, 37.776956 ], [ -122.405548, 37.778449 ], [ -122.395592, 37.786318 ], [ -122.394047, 37.785232 ], [ -122.394218, 37.785097 ], [ -122.393360, 37.784961 ], [ -122.391815, 37.785504 ], [ -122.391472, 37.785639 ], [ -122.391472, 37.785097 ], [ -122.392330, 37.784283 ], [ -122.392159, 37.784147 ], [ -122.388554, 37.786996 ], [ -122.387695, 37.787132 ], [ -122.387867, 37.788760 ], [ -122.386322, 37.790252 ], [ -122.385464, 37.790523 ], [ -122.385635, 37.790930 ], [ -122.385120, 37.791337 ] ] ], [ [ [ -122.384777, 37.779941 ], [ -122.384777, 37.779670 ], [ -122.387524, 37.779670 ], [ -122.384777, 37.779941 ] ] ], [ [ [ -122.384777, 37.780348 ], [ -122.384777, 37.780077 ], [ -122.387524, 37.780077 ], [ -122.384777, 37.780348 ] ] ], [ [ [ -122.384777, 37.780755 ], [ -122.384777, 37.780484 ], [ -122.387524, 37.780484 ], [ -122.384777, 37.780755 ] ] ], [ [ [ -122.384777, 37.779534 ], [ -122.384777, 37.779263 ], [ -122.387352, 37.779263 ], [ -122.384777, 37.779534 ] ] ], [ [ [ -122.385120, 37.778856 ], [ -122.385120, 37.778585 ], [ -122.387352, 37.778585 ], [ -122.385120, 37.778856 ] ] ] ] } }
] }
] }
+1 -1
View File
@@ -1,6 +1,6 @@
#ifndef VERSION_HPP
#define VERSION_HPP
#define VERSION "v2.65.0"
#define VERSION "v2.66.0"
#endif