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:
+45
-27
@@ -22,6 +22,7 @@
|
||||
#include "write_json.hpp"
|
||||
#include "jsonpull/jsonpull.h"
|
||||
#include "dirtiles.hpp"
|
||||
#include "errors.hpp"
|
||||
|
||||
int minzoom = 0;
|
||||
int maxzoom = 32;
|
||||
@@ -85,18 +86,18 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u
|
||||
state.json_write_newline();
|
||||
}
|
||||
|
||||
void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline, bool stats, json_writer &state) {
|
||||
void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline, bool stats, json_writer &state, int coordinate_mode) {
|
||||
mvt_tile tile;
|
||||
bool was_compressed;
|
||||
|
||||
try {
|
||||
if (!tile.decode(message, was_compressed)) {
|
||||
fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", z, x, y);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_MVT);
|
||||
}
|
||||
} catch (std::exception const &e) {
|
||||
fprintf(stderr, "PBF decoding error in tile %d/%u/%u\n", z, x, y);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_PROTOBUF);
|
||||
}
|
||||
|
||||
if (stats) {
|
||||
@@ -159,7 +160,7 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
|
||||
|
||||
if (layer.extent <= 0) {
|
||||
fprintf(stderr, "Impossible layer extent %lld in mbtiles\n", layer.extent);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_IMPOSSIBLE);
|
||||
}
|
||||
|
||||
if (to_decode.size() != 0 && !to_decode.count(layer.name)) {
|
||||
@@ -202,10 +203,16 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
|
||||
// X and Y are unsigned, so no need to check <0
|
||||
if (x > (1ULL << z) || y > (1ULL << z)) {
|
||||
fprintf(stderr, "Impossible tile %d/%u/%u\n", z, x, y);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_IMPOSSIBLE);
|
||||
}
|
||||
|
||||
layer_to_geojson(layer, z, x, y, !pipeline, pipeline, pipeline, false, 0, 0, 0, !force, state);
|
||||
double scale = 0;
|
||||
if (coordinate_mode == 1) { // fraction
|
||||
scale = layer.extent;
|
||||
} else if (coordinate_mode == 2) { // integer
|
||||
scale = 1;
|
||||
}
|
||||
layer_to_geojson(layer, z, x, y, !pipeline, pipeline, pipeline, false, 0, 0, 0, !force, state, scale);
|
||||
|
||||
if (!pipeline) {
|
||||
if (true) {
|
||||
@@ -223,7 +230,7 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
|
||||
}
|
||||
}
|
||||
|
||||
void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline, bool stats, std::set<std::string> const &exclude_meta) {
|
||||
void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline, bool stats, std::set<std::string> const &exclude_meta, int coordinate_mode) {
|
||||
sqlite3 *db = NULL;
|
||||
bool isdir = false;
|
||||
int oz = z;
|
||||
@@ -240,12 +247,12 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
if (strcmp(map, "SQLite format 3") != 0) {
|
||||
if (z >= 0) {
|
||||
std::string s = std::string(map, st.st_size);
|
||||
handle(s, z, x, y, to_decode, pipeline, stats, state);
|
||||
handle(s, z, x, y, to_decode, pipeline, stats, state, coordinate_mode);
|
||||
munmap(map, st.st_size);
|
||||
return;
|
||||
} else {
|
||||
fprintf(stderr, "Must specify zoom/x/y to decode a single pbf file\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,7 +263,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
}
|
||||
if (close(fd) != 0) {
|
||||
perror("close");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_CLOSE);
|
||||
}
|
||||
} else {
|
||||
perror(fname);
|
||||
@@ -272,13 +279,13 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
} else {
|
||||
if (sqlite3_open(fname, &db) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: %s\n", fname, sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_OPEN);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +306,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
sqlite3_stmt *stmt2;
|
||||
if (sqlite3_prepare_v2(db, sql2, -1, &stmt2, NULL) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: select failed: %s\n", fname, sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
while (sqlite3_step(stmt2) == SQLITE_ROW) {
|
||||
@@ -308,7 +315,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
|
||||
if (name == NULL || value == NULL) {
|
||||
fprintf(stderr, "Corrupt mbtiles file: null metadata\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
if (exclude_meta.count((char *) name) == 0) {
|
||||
@@ -361,7 +368,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
FILE *f = fopen(fn.c_str(), "rb");
|
||||
if (f == NULL) {
|
||||
perror(fn.c_str());
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_OPEN);
|
||||
}
|
||||
|
||||
std::string s;
|
||||
@@ -372,14 +379,14 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
handle(s, tiles[i].z, tiles[i].x, tiles[i].y, to_decode, pipeline, stats, state);
|
||||
handle(s, tiles[i].z, tiles[i].x, tiles[i].y, to_decode, pipeline, stats, state, coordinate_mode);
|
||||
}
|
||||
} else {
|
||||
const char *sql = "SELECT tile_data, zoom_level, tile_column, tile_row from tiles where zoom_level between ? and ? order by zoom_level, tile_column, tile_row;";
|
||||
sqlite3_stmt *stmt;
|
||||
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);
|
||||
}
|
||||
|
||||
sqlite3_bind_int(stmt, 1, minzoom);
|
||||
@@ -407,7 +414,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
|
||||
if (tz < 0 || tz >= 32) {
|
||||
fprintf(stderr, "Impossible zoom level %d in mbtiles\n", tz);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_IMPOSSIBLE);
|
||||
}
|
||||
|
||||
ty = (1LL << tz) - 1 - ty;
|
||||
@@ -415,10 +422,10 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
|
||||
if (s == NULL) {
|
||||
fprintf(stderr, "Corrupt mbtiles file: null entry in tiles table\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
handle(std::string(s, len), tz, tx, ty, to_decode, pipeline, stats, state);
|
||||
handle(std::string(s, len), tz, tx, ty, to_decode, pipeline, stats, state, coordinate_mode);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -443,7 +450,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
sqlite3_stmt *stmt;
|
||||
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);
|
||||
}
|
||||
|
||||
sqlite3_bind_int(stmt, 1, z);
|
||||
@@ -456,14 +463,14 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
|
||||
if (s == NULL) {
|
||||
fprintf(stderr, "Corrupt mbtiles file: null entry in tiles table\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_SQLITE);
|
||||
}
|
||||
|
||||
if (z != oz) {
|
||||
fprintf(stderr, "%s: Warning: using tile %d/%u/%u instead of %d/%u/%u\n", fname, z, x, y, oz, ox, oy);
|
||||
}
|
||||
|
||||
handle(std::string(s, len), z, x, y, to_decode, pipeline, stats, state);
|
||||
handle(std::string(s, len), z, x, y, to_decode, pipeline, stats, state, coordinate_mode);
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
@@ -477,13 +484,13 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
|
||||
if (sqlite3_close(db) != SQLITE_OK) {
|
||||
fprintf(stderr, "%s: could not close database: %s\n", fname, sqlite3_errmsg(db));
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
void usage(char **argv) {
|
||||
fprintf(stderr, "Usage: %s [-s projection] [-Z minzoom] [-z maxzoom] [-l layer ...] file.mbtiles [zoom x y]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_ARGS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -494,9 +501,12 @@ int main(int argc, char **argv) {
|
||||
bool pipeline = false;
|
||||
bool stats = false;
|
||||
std::set<std::string> exclude_meta;
|
||||
int coordinate_mode = 0;
|
||||
|
||||
struct option long_options[] = {
|
||||
{"projection", required_argument, 0, 's'},
|
||||
{"fractional-coordinates", no_argument, 0, 'F'},
|
||||
{"integer-coordinates", no_argument, 0, 'I'},
|
||||
{"maximum-zoom", required_argument, 0, 'z'},
|
||||
{"minimum-zoom", required_argument, 0, 'Z'},
|
||||
{"layer", required_argument, 0, 'l'},
|
||||
@@ -527,6 +537,14 @@ int main(int argc, char **argv) {
|
||||
set_projection_or_exit(optarg);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
coordinate_mode = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
coordinate_mode = 2;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
maxzoom = atoi(optarg);
|
||||
break;
|
||||
@@ -561,9 +579,9 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
if (argc == optind + 4) {
|
||||
decode(argv[optind], atoi(argv[optind + 1]), atoi(argv[optind + 2]), atoi(argv[optind + 3]), to_decode, pipeline, stats, exclude_meta);
|
||||
decode(argv[optind], atoi(argv[optind + 1]), atoi(argv[optind + 2]), atoi(argv[optind + 3]), to_decode, pipeline, stats, exclude_meta, coordinate_mode);
|
||||
} else if (argc == optind + 1) {
|
||||
decode(argv[optind], -1, -1, -1, to_decode, pipeline, stats, exclude_meta);
|
||||
decode(argv[optind], -1, -1, -1, to_decode, pipeline, stats, exclude_meta, coordinate_mode);
|
||||
} else {
|
||||
usage(argv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user