diff --git a/main.cpp b/main.cpp index 04de935..b12b559 100644 --- a/main.cpp +++ b/main.cpp @@ -997,7 +997,7 @@ void choose_first_zoom(long long *file_bbox, std::vector &readers } } -int read_input(std::vector &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set *exclude, std::set *include, int exclude_all, json_object *filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, std::map const *attribute_types, const char *pgm, std::map const *attribute_accum) { +int read_input(std::vector &sources, char *fname, int maxzoom, int minzoom, int basezoom, double basezoom_marker_width, sqlite3 *outdb, const char *outdir, std::set *exclude, std::set *include, int exclude_all, json_object *filter, double droprate, int buffer, const char *tmpdir, double gamma, int read_parallel, int forcetable, const char *attribution, bool uses_gamma, long long *file_bbox, const char *prefilter, const char *postfilter, const char *description, bool guess_maxzoom, std::map const *attribute_types, const char *pgm, std::map const *attribute_accum) { int ret = EXIT_SUCCESS; std::vector readers; @@ -2211,35 +2211,33 @@ void set_attribute_type(std::map &attribute_types, const char attribute_types.insert(std::pair(name, t)); } -void set_attribute_accum(std::map &attribute_accum, const char *arg) { +void set_attribute_accum(std::map &attribute_accum, const char *arg) { const char *s = strchr(arg, ':'); if (s == NULL) { - fprintf(stderr, "-E%s option must be in the form -Tname:method\n", arg); + fprintf(stderr, "-E%s option must be in the form -Ename:method\n", arg); exit(EXIT_FAILURE); } std::string name = std::string(arg, s - arg); std::string type = std::string(s + 1); - int t = -1; + attribute_op t; if (type == "sum") { - t = 1; + t = op_sum; } else if (type == "product") { - t = 2; + t = op_product; } else if (type == "mean") { - t = 3; - } else if (type == "geom_mean") { - t = 4; - } else if (type == "stddev") { - t = 5; + t = op_mean; } else if (type == "concat") { - t = mvt_bool; + t = op_concat; + } else if (type == "comma") { + t = op_comma; } else { - fprintf(stderr, "Attribute method (%s) must be sum, product, mean, geom_mean, stddev, or concat\n", type.c_str()); + fprintf(stderr, "Attribute method (%s) must be sum, product, mean, concat, or comma\n", type.c_str()); exit(EXIT_FAILURE); } - attribute_accum.insert(std::pair(name, t)); + attribute_accum.insert(std::pair(name, t)); } int main(int argc, char **argv) { @@ -2277,7 +2275,7 @@ int main(int argc, char **argv) { std::set exclude, include; std::map attribute_types; - std::map attribute_accum; + std::map attribute_accum; int exclude_all = 0; int read_parallel = 0; int files_open_at_start; diff --git a/tile.cpp b/tile.cpp index 669e76a..843d1ea 100644 --- a/tile.cpp +++ b/tile.cpp @@ -37,6 +37,7 @@ #include "options.hpp" #include "main.hpp" #include "write_json.hpp" +#include "milo/dtoa_milo.h" extern "C" { #include "jsonpull/jsonpull.h" @@ -1175,7 +1176,7 @@ struct write_tile_args { double fraction_out = 0; const char *prefilter = NULL; const char *postfilter = NULL; - std::map const *attribute_accum = NULL; + std::map const *attribute_accum = NULL; bool still_dropping = false; int wrote_zoom = 0; size_t tiling_seg = 0; @@ -1426,7 +1427,12 @@ void add_tilestats(std::string const &layername, int z, std::vectorsecond.file_keys, key, attrib); } -void preserve_attribute(std::map const *attribute_accum, std::map &attribute_accum_state, serial_feature &sf, char *stringpool, std::string &key, serial_val &val, partial &p) { +struct accum_state { + double sum = 0; + double count = 0; +}; + +void preserve_attribute(attribute_op op, std::map &attribute_accum_state, serial_feature &sf, char *stringpool, std::string &key, serial_val &val, partial &p) { if (p.need_tilestats.count(key) == 0) { p.need_tilestats.insert(key); } @@ -1453,13 +1459,32 @@ void preserve_attribute(std::map const *attribute_accum, std:: for (size_t i = 0; i < p.full_keys.size(); i++) { if (key == p.full_keys[i]) { - p.full_values[i].s += val.s; - break; + switch (op) { + case op_sum: + p.full_values[i].s = milo::dtoa_milo(atof(p.full_values[i].s.c_str()) + atof(val.s.c_str())); + p.full_values[i].type = mvt_double; + break; + + case op_product: + p.full_values[i].s = milo::dtoa_milo(atof(p.full_values[i].s.c_str()) * atof(val.s.c_str())); + p.full_values[i].type = mvt_double; + break; + + case op_concat: + p.full_values[i].s += val.s; + p.full_values[i].type = mvt_string; + break; + + case op_comma: + p.full_values[i].s += std::string(",") + val.s; + p.full_values[i].type = mvt_string; + break; + } } } } -void preserve_attributes(std::map const *attribute_accum, std::map &attribute_accum_state, serial_feature &sf, char *stringpool, partial &p) { +void preserve_attributes(std::map const *attribute_accum, std::map &attribute_accum_state, serial_feature &sf, char *stringpool, partial &p) { for (size_t i = 0; i < sf.m; i++) { std::string key = stringpool + sf.keys[i] + 1; @@ -1467,16 +1492,18 @@ void preserve_attributes(std::map const *attribute_accum, std: sv.type = stringpool[sf.values[i]]; sv.s = stringpool + sf.values[i] + 1; - if (attribute_accum->count(key) != 0) { - preserve_attribute(attribute_accum, attribute_accum_state, sf, stringpool, key, sv, p); + auto f = attribute_accum->find(key); + if (f != attribute_accum->end()) { + preserve_attribute(f->second, attribute_accum_state, sf, stringpool, key, sv, p); } } for (size_t i = 0; i < sf.full_keys.size(); i++) { std::string key = sf.full_keys[i]; serial_val sv = sf.full_values[i]; - if (attribute_accum->count(key) != 0) { - preserve_attribute(attribute_accum, attribute_accum_state, sf, stringpool, key, sv, p); + auto f = attribute_accum->find(key); + if (f != attribute_accum->end()) { + preserve_attribute(f->second, attribute_accum_state, sf, stringpool, key, sv, p); } } } @@ -1544,7 +1571,7 @@ long long write_tile(FILE *geoms, long long *geompos_in, char *metabase, char *s std::map> layers; std::vector indices; std::vector extents; - std::map attribute_accum_state; + std::map attribute_accum_state; double coalesced_area = 0; int within[child_shards]; @@ -2355,7 +2382,7 @@ void *run_thread(void *vargs) { return NULL; } -int traverse_zooms(int *geomfd, off_t *geom_size, char *metabase, char *stringpool, unsigned *midx, unsigned *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, std::vector> &layermaps, const char *prefilter, const char *postfilter, std::map const *attribute_accum) { +int traverse_zooms(int *geomfd, off_t *geom_size, char *metabase, char *stringpool, unsigned *midx, unsigned *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, std::vector> &layermaps, const char *prefilter, const char *postfilter, std::map const *attribute_accum) { // The existing layermaps are one table per input thread. // We need to add another one per *tiling* thread so that it can be // safely changed during tiling. diff --git a/tile.hpp b/tile.hpp index 33a4faa..ba8e4b6 100644 --- a/tile.hpp +++ b/tile.hpp @@ -7,9 +7,17 @@ #include #include "mbtiles.hpp" +enum attribute_op { + op_sum, + op_product, + op_mean, + op_concat, + op_comma, +}; + long long write_tile(char **geom, char *metabase, char *stringpool, unsigned *file_bbox, int z, unsigned x, unsigned y, int detail, int min_detail, int basezoom, sqlite3 *outdb, const char *outdir, double droprate, int buffer, const char *fname, FILE **geomfile, int file_minzoom, int file_maxzoom, double todo, char *geomstart, long long along, double gamma, int nlayers); -int traverse_zooms(int *geomfd, off_t *geom_size, char *metabase, char *stringpool, unsigned *midx, unsigned *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, std::vector > &layermap, const char *prefilter, const char *postfilter, std::map const *attribute_accum); +int traverse_zooms(int *geomfd, off_t *geom_size, char *metabase, char *stringpool, unsigned *midx, unsigned *midy, int &maxzoom, int minzoom, sqlite3 *outdb, const char *outdir, int buffer, const char *fname, const char *tmpdir, double gamma, int full_detail, int low_detail, int min_detail, long long *meta_off, long long *pool_off, unsigned *initial_x, unsigned *initial_y, double simplification, std::vector > &layermap, const char *prefilter, const char *postfilter, std::map const *attribute_accum); int manage_gap(unsigned long long index, unsigned long long *previndex, double scale, double gamma, double *gap);