mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-03-23 12:25:16 +00:00
Add option for newline-delimited output format to tippecanoe-decode
This commit is contained in:
parent
eaff7b93c5
commit
834ba19277
4
Makefile
4
Makefile
@ -116,8 +116,10 @@ decode-test:
|
||||
mkdir -p tests/muni/decode
|
||||
./tippecanoe -z11 -Z11 -f -o tests/muni/decode/multi.mbtiles tests/muni/*.json
|
||||
./tippecanoe-decode -l subway tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.json.check
|
||||
./tippecanoe-decode -c tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.pipeline.json.check
|
||||
cmp tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles.json
|
||||
rm -f tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles
|
||||
cmp tests/muni/decode/multi.mbtiles.pipeline.json.check tests/muni/decode/multi.mbtiles.pipeline.json
|
||||
rm -f tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles tests/muni/decode/multi.mbtiles.pipeline.json.check
|
||||
|
||||
pbf-test:
|
||||
./tippecanoe-decode tests/pbf/11-328-791.vector.pbf 11 328 791 > tests/pbf/11-328-791.vector.pbf.out
|
||||
|
@ -440,3 +440,4 @@ resolutions.
|
||||
* -z _maxzoom_: Specify the highest zoom level to decode from the tileset
|
||||
* -Z _minzoom_: Specify the lowest zoom level to decode from the tileset
|
||||
* -l _layer_: Decode only layers with the specified names. (Multiple `-l` options can be specified.)
|
||||
* -c: Include each feature's layer and zoom level as part of its `tippecanoe` object rather than as a FeatureCollection wrapper
|
||||
|
140
decode.cpp
140
decode.cpp
@ -21,7 +21,7 @@
|
||||
int minzoom = 0;
|
||||
int maxzoom = 32;
|
||||
|
||||
void handle(std::string message, int z, unsigned x, unsigned y, int describe, std::set<std::string> const &to_decode) {
|
||||
void handle(std::string message, int z, unsigned x, unsigned y, int describe, std::set<std::string> const &to_decode, bool pipeline) {
|
||||
int within = 0;
|
||||
mvt_tile tile;
|
||||
|
||||
@ -35,19 +35,21 @@ void handle(std::string message, int z, unsigned x, unsigned y, int describe, st
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("{ \"type\": \"FeatureCollection\"");
|
||||
if (!pipeline) {
|
||||
printf("{ \"type\": \"FeatureCollection\"");
|
||||
|
||||
if (describe) {
|
||||
printf(", \"properties\": { \"zoom\": %d, \"x\": %d, \"y\": %d }", z, x, y);
|
||||
if (describe) {
|
||||
printf(", \"properties\": { \"zoom\": %d, \"x\": %d, \"y\": %d }", z, x, y);
|
||||
|
||||
if (projection != projections) {
|
||||
printf(", \"crs\": { \"type\": \"name\", \"properties\": { \"name\": ");
|
||||
fprintq(stdout, projection->alias);
|
||||
printf(" } }");
|
||||
if (projection != projections) {
|
||||
printf(", \"crs\": { \"type\": \"name\", \"properties\": { \"name\": ");
|
||||
fprintq(stdout, projection->alias);
|
||||
printf(" } }");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf(", \"features\": [\n");
|
||||
printf(", \"features\": [\n");
|
||||
}
|
||||
|
||||
bool first_layer = true;
|
||||
for (size_t l = 0; l < tile.layers.size(); l++) {
|
||||
@ -57,33 +59,39 @@ void handle(std::string message, int z, unsigned x, unsigned y, int describe, st
|
||||
continue;
|
||||
}
|
||||
|
||||
if (describe) {
|
||||
if (!first_layer) {
|
||||
printf(",\n");
|
||||
if (!pipeline) {
|
||||
if (describe) {
|
||||
if (!first_layer) {
|
||||
printf(",\n");
|
||||
}
|
||||
|
||||
printf("{ \"type\": \"FeatureCollection\"");
|
||||
printf(", \"properties\": { \"layer\": ");
|
||||
fprintq(stdout, layer.name.c_str());
|
||||
printf(", \"version\": %d, \"extent\": %lld", layer.version, layer.extent);
|
||||
printf(" }");
|
||||
printf(", \"features\": [\n");
|
||||
|
||||
first_layer = false;
|
||||
within = 0;
|
||||
}
|
||||
|
||||
printf("{ \"type\": \"FeatureCollection\"");
|
||||
printf(", \"properties\": { \"layer\": ");
|
||||
fprintq(stdout, layer.name.c_str());
|
||||
printf(", \"version\": %d, \"extent\": %lld", layer.version, layer.extent);
|
||||
printf(" }");
|
||||
printf(", \"features\": [\n");
|
||||
|
||||
first_layer = false;
|
||||
within = 0;
|
||||
}
|
||||
|
||||
layer_to_geojson(stdout, layer, z, x, y, true, false, 0, 0, 0);
|
||||
layer_to_geojson(stdout, layer, z, x, y, !pipeline, pipeline, pipeline, 0, 0, 0);
|
||||
|
||||
if (describe) {
|
||||
printf("] }\n");
|
||||
if (!pipeline) {
|
||||
if (describe) {
|
||||
printf("] }\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("] }\n");
|
||||
if (!pipeline) {
|
||||
printf("] }\n");
|
||||
}
|
||||
}
|
||||
|
||||
void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode) {
|
||||
void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> const &to_decode, bool pipeline) {
|
||||
sqlite3 *db;
|
||||
int oz = z;
|
||||
unsigned ox = x, oy = y;
|
||||
@ -98,7 +106,7 @@ 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, 1, to_decode);
|
||||
handle(s, z, x, y, 1, to_decode, pipeline);
|
||||
munmap(map, st.st_size);
|
||||
return;
|
||||
} else {
|
||||
@ -126,32 +134,35 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
}
|
||||
|
||||
if (z < 0) {
|
||||
printf("{ \"type\": \"FeatureCollection\", \"properties\": {\n");
|
||||
|
||||
const char *sql2 = "SELECT name, value from metadata order by name;";
|
||||
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);
|
||||
}
|
||||
|
||||
int within = 0;
|
||||
while (sqlite3_step(stmt2) == SQLITE_ROW) {
|
||||
if (within) {
|
||||
printf(",\n");
|
||||
|
||||
if (!pipeline) {
|
||||
printf("{ \"type\": \"FeatureCollection\", \"properties\": {\n");
|
||||
|
||||
const char *sql2 = "SELECT name, value from metadata order by name;";
|
||||
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);
|
||||
}
|
||||
within = 1;
|
||||
|
||||
const unsigned char *name = sqlite3_column_text(stmt2, 0);
|
||||
const unsigned char *value = sqlite3_column_text(stmt2, 1);
|
||||
while (sqlite3_step(stmt2) == SQLITE_ROW) {
|
||||
if (within) {
|
||||
printf(",\n");
|
||||
}
|
||||
within = 1;
|
||||
|
||||
fprintq(stdout, (char *) name);
|
||||
printf(": ");
|
||||
fprintq(stdout, (char *) value);
|
||||
const unsigned char *name = sqlite3_column_text(stmt2, 0);
|
||||
const unsigned char *value = sqlite3_column_text(stmt2, 1);
|
||||
|
||||
fprintq(stdout, (char *) name);
|
||||
printf(": ");
|
||||
fprintq(stdout, (char *) value);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt2);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt2);
|
||||
|
||||
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) {
|
||||
@ -162,14 +173,18 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
sqlite3_bind_int(stmt, 1, minzoom);
|
||||
sqlite3_bind_int(stmt, 2, maxzoom);
|
||||
|
||||
printf("\n}, \"features\": [\n");
|
||||
if (!pipeline) {
|
||||
printf("\n}, \"features\": [\n");
|
||||
}
|
||||
|
||||
within = 0;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
if (within) {
|
||||
printf(",\n");
|
||||
if (!pipeline) {
|
||||
if (within) {
|
||||
printf(",\n");
|
||||
}
|
||||
within = 1;
|
||||
}
|
||||
within = 1;
|
||||
|
||||
int len = sqlite3_column_bytes(stmt, 0);
|
||||
int tz = sqlite3_column_int(stmt, 1);
|
||||
@ -178,10 +193,12 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
ty = (1LL << tz) - 1 - ty;
|
||||
const char *s = (const char *) sqlite3_column_blob(stmt, 0);
|
||||
|
||||
handle(std::string(s, len), tz, tx, ty, 1, to_decode);
|
||||
handle(std::string(s, len), tz, tx, ty, 1, to_decode, pipeline);
|
||||
}
|
||||
|
||||
printf("] }\n");
|
||||
if (!pipeline) {
|
||||
printf("] }\n");
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
} else {
|
||||
@ -206,7 +223,7 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
|
||||
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, 0, to_decode);
|
||||
handle(std::string(s, len), z, x, y, 0, to_decode, pipeline);
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
@ -234,8 +251,9 @@ int main(int argc, char **argv) {
|
||||
extern char *optarg;
|
||||
int i;
|
||||
std::set<std::string> to_decode;
|
||||
bool pipeline = false;
|
||||
|
||||
while ((i = getopt(argc, argv, "t:Z:z:l:")) != -1) {
|
||||
while ((i = getopt(argc, argv, "t:Z:z:l:c")) != -1) {
|
||||
switch (i) {
|
||||
case 't':
|
||||
set_projection_or_exit(optarg);
|
||||
@ -253,15 +271,19 @@ int main(int argc, char **argv) {
|
||||
to_decode.insert(optarg);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
pipeline = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == optind + 4) {
|
||||
decode(argv[optind], atoi(argv[optind + 1]), atoi(argv[optind + 2]), atoi(argv[optind + 3]), to_decode);
|
||||
decode(argv[optind], atoi(argv[optind + 1]), atoi(argv[optind + 2]), atoi(argv[optind + 3]), to_decode, pipeline);
|
||||
} else if (argc == optind + 1) {
|
||||
decode(argv[optind], -1, -1, -1, to_decode);
|
||||
decode(argv[optind], -1, -1, -1, to_decode, pipeline);
|
||||
} else {
|
||||
usage(argv);
|
||||
}
|
||||
|
@ -162,6 +162,8 @@ which may not be what you want.
|
||||
\-an or \-\-drop\-smallest\-as\-needed: Dynamically drop the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level to keep large tiles under the 500K size limit. This option will not work for point features.
|
||||
.IP \(bu 2
|
||||
\-aL or \-\-grid\-low\-zooms: At all zoom levels below \fImaxzoom\fP, snap all lines and polygons to a stairstep grid instead of allowing diagonals. You will also want to specify a tile resolution, probably \fB\fC\-D8\fR\&. This option provides a way to display continuous parcel, gridded, or binned data at low zooms without overwhelming the tiles with tiny polygons, since features will either get stretched out to the grid unit or lost entirely, depending on how they happened to be aligned in the original data.
|
||||
.IP \(bu 2
|
||||
\-aw or \-\-detect\-longitude\-wraparound: Detect when adjacent points within a feature jump to the other side of the world, and try to fix the geometry.
|
||||
.RE
|
||||
.SS Doing less
|
||||
.RS
|
||||
@ -178,7 +180,7 @@ which may not be what you want.
|
||||
.IP \(bu 2
|
||||
\-pi or \-\-preserve\-input\-order: Preserve the original input order of features as the drawing order instead of ordering geographically. (This is implemented as a restoration of the original order at the end, so that dot\-dropping is still geographic, which means it also undoes \-ao).
|
||||
.IP \(bu 2
|
||||
\-pp or \-\-no\-polygon\-splitting: Don't split complex polygons (over 700 vertices after simplification) into multiple features.
|
||||
\-pp or \-\-no\-polygon\-splitting: This no longer has any effect.
|
||||
.IP \(bu 2
|
||||
\-pc or \-\-no\-clipping: Don't clip features to the size of the tile. If a feature overlaps the tile's bounds or buffer at all, it is included completely. Be careful: this can produce very large tilesets, especially with large polygons.
|
||||
.IP \(bu 2
|
||||
@ -336,9 +338,6 @@ have their probability diffused, so that some of them will be drawn as a square
|
||||
this minimum size and others will not be drawn at all, preserving the total area that
|
||||
all of them should have had together.
|
||||
.PP
|
||||
Any polygons that have over 700 vertices after line simplification will be split into
|
||||
multiple features so they can be rendered efficiently, unless you use \-pp to prevent this.
|
||||
.PP
|
||||
Features in the same tile that share the same type and attributes are coalesced
|
||||
together into a single geometry if you use \fB\fC\-\-coalesce\fR\&. You are strongly encouraged to use \-x to exclude
|
||||
any unnecessary properties to reduce wasted file size.
|
||||
@ -521,4 +520,6 @@ resolutions.
|
||||
\-Z \fIminzoom\fP: Specify the lowest zoom level to decode from the tileset
|
||||
.IP \(bu 2
|
||||
\-l \fIlayer\fP: Decode only layers with the specified names. (Multiple \fB\fC\-l\fR options can be specified.)
|
||||
.IP \(bu 2
|
||||
\-c: Include each feature's layer and zoom level as part of its \fB\fCtippecanoe\fR object rather than as a FeatureCollection wrapper
|
||||
.RE
|
||||
|
@ -51,7 +51,7 @@ void *run_writer(void *a) {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < wa->layers->size(); i++) {
|
||||
layer_to_geojson(fp, (*(wa->layers))[i], wa->z, wa->x, wa->y, false, true, 0, 0, 0);
|
||||
layer_to_geojson(fp, (*(wa->layers))[i], wa->z, wa->x, wa->y, false, true, false, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (fclose(fp) != 0) {
|
||||
|
4858
tests/muni/decode/multi.mbtiles.pipeline.json
Normal file
4858
tests/muni/decode/multi.mbtiles.pipeline.json
Normal file
File diff suppressed because it is too large
Load Diff
2
tile.cpp
2
tile.cpp
@ -1372,7 +1372,7 @@ void *run_prefilter(void *v) {
|
||||
decode_meta(sf.m, sf.keys, sf.values, rpa->stringpool + rpa->pool_off[sf.segment], tmp_layer, tmp_feature);
|
||||
tmp_layer.features.push_back(tmp_feature);
|
||||
|
||||
layer_to_geojson(rpa->prefilter_fp, tmp_layer, 0, 0, 0, false, true, sf.index, sf.seq, sf.extent);
|
||||
layer_to_geojson(rpa->prefilter_fp, tmp_layer, 0, 0, 0, false, true, false, sf.index, sf.seq, sf.extent);
|
||||
}
|
||||
|
||||
if (fclose(rpa->prefilter_fp) != 0) {
|
||||
|
@ -24,7 +24,7 @@ struct lonlat {
|
||||
}
|
||||
};
|
||||
|
||||
void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, unsigned long long index, long long sequence, long long extent) {
|
||||
void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, unsigned long long index, long long sequence, long long extent) {
|
||||
for (size_t f = 0; f < layer.features.size(); f++) {
|
||||
mvt_feature const &feat = layer.features[f];
|
||||
|
||||
@ -38,7 +38,7 @@ void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x,
|
||||
fprintf(fp, ", \"id\": %llu", feat.id);
|
||||
}
|
||||
|
||||
if (name || index != 0 || sequence != 0 || extent != 0) {
|
||||
if (name || zoom || index != 0 || sequence != 0 || extent != 0) {
|
||||
bool need_comma = false;
|
||||
|
||||
fprintf(fp, ", \"tippecanoe\": { ");
|
||||
@ -52,6 +52,15 @@ void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x,
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
if (zoom) {
|
||||
if (need_comma) {
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
fprintf(fp, "\"minzoom\": %u, ", z);
|
||||
fprintf(fp, "\"maxzoom\": %u", z);
|
||||
need_comma = true;
|
||||
}
|
||||
|
||||
if (index != 0) {
|
||||
if (need_comma) {
|
||||
fprintf(fp, ", ");
|
||||
|
@ -1,2 +1,2 @@
|
||||
void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, unsigned long long index, long long sequence, long long extent);
|
||||
void layer_to_geojson(FILE *fp, mvt_layer const &layer, unsigned z, unsigned x, unsigned y, bool comma, bool name, bool zoom, unsigned long long index, long long sequence, long long extent);
|
||||
void fprintq(FILE *f, const char *s);
|
||||
|
Loading…
x
Reference in New Issue
Block a user