mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Once features can't possibly fit in a tile, stop trying (#9)
* Stop adding features to a tile if it can't possibly work * Add --integer and --fraction options to tippecanoe-decode * Carry the strategies field from tileset metadata through tile-join * Update changelog * Assign different codes to different kinds of error exits
This commit is contained in:
+73
-17
@@ -37,6 +37,7 @@
|
||||
#include <functional>
|
||||
#include "jsonpull/jsonpull.h"
|
||||
#include "milo/dtoa_milo.h"
|
||||
#include "errors.hpp"
|
||||
|
||||
int pk = false;
|
||||
int pC = false;
|
||||
@@ -54,6 +55,7 @@ struct stats {
|
||||
int maxzoom;
|
||||
double midlat, midlon;
|
||||
double minlat, minlon, maxlat, maxlon;
|
||||
std::vector<struct strategy> strategies;
|
||||
};
|
||||
|
||||
void aprintf(std::string *buf, const char *format, ...) {
|
||||
@@ -63,7 +65,7 @@ void aprintf(std::string *buf, const char *format, ...) {
|
||||
va_start(ap, format);
|
||||
if (vasprintf(&tmp, format, ap) < 0) {
|
||||
fprintf(stderr, "memory allocation failure\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_MEMORY);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
@@ -78,7 +80,7 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::map<std::st
|
||||
|
||||
if (!tile.decode(message, was_compressed)) {
|
||||
fprintf(stderr, "Couldn't decompress tile %d/%u/%u\n", z, x, y);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_MVT);
|
||||
}
|
||||
|
||||
for (size_t l = 0; l < tile.layers.size(); l++) {
|
||||
@@ -430,13 +432,13 @@ struct reader *begin_reading(char *fname) {
|
||||
|
||||
if (sqlite3_open(fname, &db) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: %s\n", fname, sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
char *err = NULL;
|
||||
if (sqlite3_exec(db, "PRAGMA integrity_check;", NULL, NULL, &err) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: integrity_check: %s\n", fname, err);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
const char *sql = "SELECT zoom_level, tile_column, tile_row, tile_data from tiles order by zoom_level, tile_column, tile_row;";
|
||||
@@ -444,7 +446,7 @@ struct reader *begin_reading(char *fname) {
|
||||
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: select failed: %s\n", fname, sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
r->db = db;
|
||||
@@ -561,7 +563,7 @@ void handle_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<st
|
||||
for (size_t i = 0; i < CPUS; i++) {
|
||||
if (pthread_create(&pthreads[i], NULL, join_worker, &args[i]) != 0) {
|
||||
perror("pthread_create");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_PTHREAD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,6 +584,54 @@ void handle_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<st
|
||||
}
|
||||
}
|
||||
|
||||
void handle_strategies(const unsigned char *s, std::vector<strategy> *st) {
|
||||
json_pull *jp = json_begin_string((const char *) s);
|
||||
json_object *o = json_read_tree(jp);
|
||||
|
||||
if (o != NULL && o->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < o->value.array.length; i++) {
|
||||
json_object *h = o->value.array.array[i];
|
||||
if (h->type == JSON_HASH) {
|
||||
for (size_t j = 0; j < h->value.object.length; j++) {
|
||||
json_object *k = h->value.object.keys[j];
|
||||
json_object *v = h->value.object.values[j];
|
||||
|
||||
if (k->type != JSON_STRING) {
|
||||
fprintf(stderr, "Key %zu of %zu is not a string: %s\n", j, i, s);
|
||||
} else if (v->type != JSON_NUMBER) {
|
||||
fprintf(stderr, "Value %zu of %zu is not a number: %s\n", j, i, s);
|
||||
} else {
|
||||
if (i <= st->size()) {
|
||||
st->resize(i + 1);
|
||||
}
|
||||
|
||||
if (strcmp(k->value.string.string, "dropped_by_rate") == 0) {
|
||||
(*st)[i].dropped_by_rate += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "dropped_by_gamma") == 0) {
|
||||
(*st)[i].dropped_by_gamma += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "dropped_as_needed") == 0) {
|
||||
(*st)[i].dropped_as_needed += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "coalesced_as_needed") == 0) {
|
||||
(*st)[i].coalesced_as_needed += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "detail_reduced") == 0) {
|
||||
(*st)[i].detail_reduced += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "tiny_polygons") == 0) {
|
||||
(*st)[i].tiny_polygons += v->value.number.number;
|
||||
} else if (strcmp(k->value.string.string, "tile_size_desired") == 0) {
|
||||
(*st)[i].tile_size += v->value.number.number;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Element %zu is not a hash: %s\n", i, s);
|
||||
}
|
||||
}
|
||||
json_free(o);
|
||||
}
|
||||
|
||||
json_end(jp);
|
||||
}
|
||||
|
||||
void handle_vector_layers(json_object *vector_layers, std::map<std::string, layermap_entry> &layermap, std::map<std::string, std::string> &attribute_descriptions) {
|
||||
if (vector_layers != NULL && vector_layers->type == JSON_ARRAY) {
|
||||
for (size_t i = 0; i < vector_layers->value.array.length; i++) {
|
||||
@@ -621,7 +671,7 @@ void handle_vector_layers(json_object *vector_layers, std::map<std::string, laye
|
||||
}
|
||||
}
|
||||
|
||||
void decode(struct reader *readers, std::map<std::string, layermap_entry> &layermap, sqlite3 *outdb, const char *outdir, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, std::set<std::string> &exclude, int ifmatched, std::string &attribution, std::string &description, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, std::string &name, json_object *filter, std::map<std::string, std::string> &attribute_descriptions, std::string &generator_options) {
|
||||
void decode(struct reader *readers, std::map<std::string, layermap_entry> &layermap, sqlite3 *outdb, const char *outdir, struct stats *st, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, std::set<std::string> &exclude, int ifmatched, std::string &attribution, std::string &description, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, std::string &name, json_object *filter, std::map<std::string, std::string> &attribute_descriptions, std::string &generator_options, std::vector<strategy> *strategies) {
|
||||
std::vector<std::map<std::string, layermap_entry>> layermaps;
|
||||
for (size_t i = 0; i < CPUS; i++) {
|
||||
layermaps.push_back(std::map<std::string, layermap_entry>());
|
||||
@@ -840,11 +890,18 @@ void decode(struct reader *readers, std::map<std::string, layermap_entry> &layer
|
||||
}
|
||||
sqlite3_finalize(r->stmt);
|
||||
}
|
||||
if (sqlite3_prepare_v2(db, "SELECT value from metadata where name = 'strategies'", -1, &r->stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_step(r->stmt) == SQLITE_ROW) {
|
||||
const unsigned char *s = sqlite3_column_text(r->stmt, 0);
|
||||
handle_strategies(s, strategies);
|
||||
}
|
||||
sqlite3_finalize(r->stmt);
|
||||
}
|
||||
|
||||
// Closes either real db or temp mirror of metadata.json
|
||||
if (sqlite3_close(db) != SQLITE_OK) {
|
||||
fprintf(stderr, "Could not close database: %s\n", sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_CLOSE);
|
||||
}
|
||||
|
||||
delete r;
|
||||
@@ -853,7 +910,7 @@ void decode(struct reader *readers, std::map<std::string, layermap_entry> &layer
|
||||
|
||||
void usage(char **argv) {
|
||||
fprintf(stderr, "Usage: %s [-f] [-i] [-pk] [-pC] [-c joins.csv] [-X] [-x exclude ...] -o new.mbtiles source.mbtiles ...\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -994,14 +1051,14 @@ int main(int argc, char **argv) {
|
||||
pe = true;
|
||||
} else {
|
||||
fprintf(stderr, "%s: Unknown option for -p%s\n", argv[0], optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (csv != NULL) {
|
||||
fprintf(stderr, "Only one -c for now\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
|
||||
csv = optarg;
|
||||
@@ -1028,7 +1085,7 @@ int main(int argc, char **argv) {
|
||||
char *cp = strchr(optarg, ':');
|
||||
if (cp == NULL || cp == optarg) {
|
||||
fprintf(stderr, "%s: -R requires old:new\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
std::string before = std::string(optarg).substr(0, cp - optarg);
|
||||
std::string after = std::string(cp + 1);
|
||||
@@ -1050,7 +1107,7 @@ int main(int argc, char **argv) {
|
||||
max_tilestats_values = atoi(optarg);
|
||||
} else {
|
||||
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1076,7 +1133,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (minzoom > maxzoom) {
|
||||
fprintf(stderr, "%s: Minimum zoom -Z%d cannot be greater than maxzoom -z%d\n", argv[0], minzoom, maxzoom);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
|
||||
if (out_mbtiles != NULL) {
|
||||
@@ -1117,8 +1174,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
std::map<std::string, std::string> attribute_descriptions;
|
||||
std::string generator_options;
|
||||
std::vector<strategy> strategies;
|
||||
|
||||
decode(readers, layermap, outdb, out_dir, &st, header, mapping, exclude, ifmatched, attribution, description, keep_layers, remove_layers, name, filter, attribute_descriptions, generator_options);
|
||||
decode(readers, layermap, outdb, out_dir, &st, header, mapping, exclude, ifmatched, attribution, description, keep_layers, remove_layers, name, filter, attribute_descriptions, generator_options, &strategies);
|
||||
|
||||
if (set_attribution.size() != 0) {
|
||||
attribution = set_attribution;
|
||||
@@ -1144,8 +1202,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<strategy> strategies;
|
||||
|
||||
mbtiles_write_metadata(outdb, out_dir, name.c_str(), st.minzoom, st.maxzoom, st.minlat, st.minlon, st.maxlat, st.maxlon, st.midlat, st.midlon, 0, attribution.size() != 0 ? attribution.c_str() : NULL, layermap, true, description.c_str(), !pg, attribute_descriptions, "tile-join", generator_options, strategies);
|
||||
|
||||
if (outdb != NULL) {
|
||||
|
||||
Reference in New Issue
Block a user