Let tile-join and tippecanoe-overzoom write MLT tiles too

Both tools could read MapLibre Tiles but only ever wrote Mapbox Vector
Tiles, so there was no way to convert a tileset into MLT, or to keep a
tileset in MLT once it had been through either of them.

Give them the same --output-format, --pretessellate, and
--no-mlt-feature-sort options that tippecanoe has. tile-join writes the
chosen format to mbtiles files, PMTiles archives, and tile directories,
naming directory tiles and the tileset metadata format accordingly, and
tippecanoe-overzoom writes it to its output tile. Either tool will read
whichever format its sources are in regardless of what it is writing.

The output format selection and the MLT encoder options now live in
mlt.cpp, shared by all three tools rather than defined in main.cpp for
tippecanoe alone, along with encode_tile() for encoding a tile in the
selected format. overzoom() takes the format as a parameter, since
tile-join uses it internally to rescale tiles that will be re-encoded
afterward, and those intermediate tiles should stay MVT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LxhELiLtpUFwrPSWwTYdHG
This commit is contained in:
Claude
2026-08-06 17:34:02 +00:00
parent 2410727242
commit 13f1c3b6e4
14 changed files with 248 additions and 44 deletions
+3
View File
@@ -45,6 +45,9 @@ tests/**/*.geobuf
tests/mlt/dir-out/
tests/mlt/roundtrip-dir/
tests/mlt/overzoom.pbf
tests/mlt/join-out-dir/
tests/mlt/mvt-source-dir/
tests/mlt/overzoom-out.mlt
mlt-build/
+27 -4
View File
@@ -87,16 +87,16 @@ tippecanoe-enumerate: enumerate.o
tippecanoe-decode: decode.o projection.o mvt.o mlt_decode.o write_json.o text.o jsonpull/jsonpull.o dirtiles.o pmtiles_file.o $(MLT_DECODE_LIBS)
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3
tile-join: tile-join.o platform.o projection.o mbtiles.o mvt.o mlt_decode.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o pmtiles_file.o clip.o attribute.o thread.o read_json.o clipper2/src/clipper.engine.o $(MLT_DECODE_LIBS)
tile-join: tile-join.o platform.o projection.o mbtiles.o mvt.o mlt.o mlt_decode.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o pmtiles_file.o clip.o attribute.o thread.o read_json.o clipper2/src/clipper.engine.o $(MLT_LIBS)
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o geojson-loop.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
unit: unit.o text.o sort.o mvt.o mlt_decode.o projection.o clip.o attribute.o jsonpull/jsonpull.o evaluator.o read_json.o clipper2/src/clipper.engine.o $(MLT_DECODE_LIBS)
unit: unit.o text.o sort.o mvt.o mlt.o mlt_decode.o projection.o clip.o attribute.o jsonpull/jsonpull.o evaluator.o read_json.o clipper2/src/clipper.engine.o $(MLT_LIBS)
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
tippecanoe-overzoom: overzoom.o mvt.o mlt_decode.o clip.o evaluator.o jsonpull/jsonpull.o text.o attribute.o read_json.o projection.o read_json.o clipper2/src/clipper.engine.o $(MLT_DECODE_LIBS)
tippecanoe-overzoom: overzoom.o mvt.o mlt.o mlt_decode.o clip.o evaluator.o jsonpull/jsonpull.o text.o attribute.o read_json.o projection.o read_json.o clipper2/src/clipper.engine.o $(MLT_LIBS)
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
-include $(wildcard *.d)
@@ -119,7 +119,7 @@ indent:
TESTS = $(wildcard tests/*/out/*.json)
SPACE = $(NULL) $(NULL)
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test pmtiles-test decode-pmtiles-test overzoom-test flatgeobuf-test mlt-test mlt-decode-test
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test pmtiles-test decode-pmtiles-test overzoom-test flatgeobuf-test mlt-test mlt-decode-test mlt-output-test
./unit
suffixes = json json.gz
@@ -650,6 +650,29 @@ mlt-decode-test: tippecanoe tippecanoe-decode tile-join tippecanoe-overzoom
rm -f tests/mlt/roundtrip-dir.json.check tests/mlt/overzoom.pbf tests/mlt/overzoom.json.check
rm -rf tests/mlt/roundtrip-dir
mlt-output-test: tippecanoe tippecanoe-decode tile-join tippecanoe-overzoom
./tippecanoe -q -z5 -f -o tests/mlt/mvt-source.mbtiles tests/mlt/roundtrip.geojson
# tile-join writes MLT tiles to an mbtiles file, whatever the sources are encoded in
./tile-join -f --output-format=mlt -o tests/mlt/join-out.mbtiles tests/mlt/mvt-source.mbtiles
./tippecanoe-decode -x generator -x generator_options tests/mlt/join-out.mbtiles > tests/mlt/join-out.mbtiles.json.check
cmp tests/mlt/join-out.mbtiles.json.check tests/mlt/join-out.mbtiles.json
# tile-join writes MLT tiles to a tile directory
rm -rf tests/mlt/join-out-dir
./tile-join -f --output-format=mlt -e tests/mlt/join-out-dir tests/mlt/mvt-source.mbtiles
@test $$(find tests/mlt/join-out-dir -name '*.mlt' | wc -l) -gt 0 || (echo "FAIL: No .mlt files in tile-join directory output" && exit 1)
@test $$(find tests/mlt/join-out-dir -name '*.pbf' | wc -l) -eq 0 || (echo "FAIL: .pbf files in tile-join MLT directory output" && exit 1)
# tippecanoe-overzoom writes MLT tiles
rm -rf tests/mlt/mvt-source-dir
./tippecanoe -q -z5 -f -e tests/mlt/mvt-source-dir tests/mlt/roundtrip.geojson
# The same features come out whichever direction the formats are converted in,
# so this is compared against the standard for overzooming an MLT tile to MVT
./tippecanoe-overzoom --output-format=mlt -o tests/mlt/overzoom-out.mlt tests/mlt/mvt-source-dir/2/0/1.pbf 2/0/1 4/2/6
./tippecanoe-decode tests/mlt/overzoom-out.mlt 4 2 6 > tests/mlt/overzoom-out.json.check
cmp tests/mlt/overzoom-out.json.check tests/mlt/overzoom.json
rm -f tests/mlt/mvt-source.mbtiles tests/mlt/join-out.mbtiles tests/mlt/join-out.mbtiles.json.check
rm -f tests/mlt/overzoom-out.mlt tests/mlt/overzoom-out.json.check
rm -rf tests/mlt/join-out-dir tests/mlt/mvt-source-dir
# Use this target to regenerate the standards that the tests are compared against
# after making a change that legitimately changes their output
+10 -3
View File
@@ -777,8 +777,8 @@ mbtiles output. If they define the same layers or the same tiles, the layers
or tiles are merged.
Sources may contain either Mapbox Vector Tiles or MapLibre Tiles, in any combination,
since the encoding is detected from the tile data. The output is always written as
Mapbox Vector Tiles.
since the encoding is detected from the tile data. The output is written as Mapbox
Vector Tiles unless `--output-format=mlt` is specified.
The options are:
@@ -829,6 +829,9 @@ The options are:
* `-pk` or `--no-tile-size-limit`: Don't skip tiles larger than 500K.
* `-pC` or `--no-tile-compression`: Don't compress the vector tile data.
* `--output-format=`*format*: Set the tile encoding format. Supported values: `mvt` (default, Mapbox Vector Tiles) or `mlt` ([MapLibre Tiles](https://github.com/maplibre/maplibre-tile-spec)). Applies regardless of what the sources are encoded in.
* `--pretessellate`: When using `--output-format=mlt`, pre-triangulate polygon geometries. Only applies to layers where all features are polygons.
* `--no-mlt-feature-sort`: When using `--output-format=mlt`, disable within-tile spatial sorting of features by Hilbert curve index. Sorting is on by default.
* `-pg` or `--no-tile-stats`: Don't generate the `tilestats` row in the tileset metadata. Uploads without [tilestats](https://github.com/mapbox/mapbox-geostats) will take longer to process.
* `--tile-stats-attributes-limit=`*count*: Include `tilestats` information about at most *count* attributes instead of the default 1000.
* `--tile-stats-sample-values-limit=`*count*: Calculate `tilestats` attribute statistics based on *count* values instead of the default 1000.
@@ -1015,7 +1018,8 @@ reads tile `inz/inx/iny` of `in.mvt.gz`, tile `in2z/in2x/in2y` of `in2.mvt.gz`,
and produces tile `outz/outx/outy` of `out.mvt.gz` from them.
The input tiles may be either Mapbox Vector Tiles or MapLibre Tiles, since the encoding
is detected from the tile data. The output tile is always a Mapbox Vector Tile.
is detected from the tile data. The output tile is a Mapbox Vector Tile unless
`--output-format=mlt` is specified.
### Options
@@ -1026,3 +1030,6 @@ is detected from the tile data. The output tile is always a Mapbox Vector Tile.
* `-m`: If a tile was created with the `--retain-points-multiplier` option, thin the tile back down to its normal feature count during overzooming. The first feature from each cluster will be retained, unless `-j` is used to specify a filter, in which case the first matching filter from each cluster will be retained instead.
* `--preserve-input-order`: Restore a set of filtered features to its original input order
* `--accumulate-attribute`: Behaves as in `tippecanoe` to sum attributes from the features of a multiplier cluster that are not included in the final output. The attributes from features that are filtered away with `-j` are *not* accumulated onto the output feature.
* `--output-format=`*format*: Set the tile encoding format. Supported values: `mvt` (default, Mapbox Vector Tiles) or `mlt` ([MapLibre Tiles](https://github.com/maplibre/maplibre-tile-spec)). Applies regardless of what the input tiles are encoded in.
* `--pretessellate`: When using `--output-format=mlt`, pre-triangulate polygon geometries. Only applies to layers where all features are polygons.
* `--no-mlt-feature-sort`: When using `--output-format=mlt`, disable within-tile spatial sorting of features by Hilbert curve index. Sorting is on by default.
+7 -4
View File
@@ -10,6 +10,7 @@
#include "errors.hpp"
#include "compression.hpp"
#include "mvt.hpp"
#include "mlt.hpp"
#include "evaluator.hpp"
#include "serial.hpp"
#include "attribute.hpp"
@@ -1228,7 +1229,8 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
std::vector<mvt_layer> const &unused2, std::string const &unused3,
std::string const &unused, size_t feature_limit,
std::vector<clipbbox> const &unused4,
bool deduplicate_by_id) {
bool deduplicate_by_id,
int tile_format) {
std::vector<source_tile> decoded;
for (auto const &t : tiles) {
@@ -1254,7 +1256,7 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
decoded.push_back(out);
}
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, unused2, unused3, unused, feature_limit, unused4, deduplicate_by_id);
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, unused2, unused3, unused, feature_limit, unused4, deduplicate_by_id, tile_format);
}
// like a minimal serial_feature, but with mvt_feature-style attributes
@@ -1464,7 +1466,8 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
std::vector<mvt_layer> const &unused2, std::string const &unused3,
std::string const &unused, size_t feature_limit,
std::vector<clipbbox> const &unused4,
bool deduplicate_by_id) {
bool deduplicate_by_id,
int tile_format) {
mvt_tile outtile;
key_pool key_pool;
@@ -1737,7 +1740,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
}
if (outtile.layers.size() > 0) {
std::string pbf = outtile.encode();
std::string pbf = encode_tile(outtile, tile_format);
std::string compressed;
if (do_compress) {
+4 -2
View File
@@ -148,7 +148,8 @@ 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, size_t feature_limit,
std::vector<clipbbox> const &clipbboxes,
bool deduplicate_by_id);
bool deduplicate_by_id,
int tile_format = OUTPUT_MVT);
std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int ny,
int detail, int buffer,
@@ -164,7 +165,8 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
std::string const &accumulate_numeric, size_t feature_limit,
std::vector<clipbbox> const &clipbboxes,
bool deduplicate_by_id);
bool deduplicate_by_id,
int tile_format = OUTPUT_MVT);
draw center_of_mass_mp(const drawvec &dv);
+3 -12
View File
@@ -50,6 +50,7 @@
#include "projection.hpp"
#include "memfile.hpp"
#include "main.hpp"
#include "mlt.hpp"
#include "geojson.hpp"
#include "geobuf.hpp"
#include "flatgeobuf.hpp"
@@ -104,9 +105,6 @@ bool drop_by_attribute_descending = false;
std::vector<order_field> order_by;
bool order_reverse;
bool order_by_size = false;
int output_format = OUTPUT_MVT;
bool mlt_sort_features = true;
bool mlt_pretessellate = false;
int prevent[256];
int additional[256];
@@ -2827,7 +2825,7 @@ std::pair<int, metadata> read_input(std::vector<source> &sources, char *fname, i
ai->second.maxzoom = maxzoom;
}
const char *tile_format = (output_format == OUTPUT_MLT) ? "mlt" : "pbf";
const char *tile_format = tile_format_name(output_format);
metadata m = make_metadata(fname, minzoom, maxzoom, minlat, minlon, maxlat, maxlon, minlat2, minlon2, maxlat2, maxlon2, midlat, midlon, attribution, merged_lm, tile_format, description, !prevent[P_TILE_STATS], attribute_descriptions, "tippecanoe", commandline, strategies, basezoom, droprate, retain_points_multiplier);
if (outdb != NULL) {
mbtiles_write_metadata(outdb, m, forcetable);
@@ -3335,14 +3333,7 @@ int main(int argc, char **argv) {
} else if (strcmp(opt, "maximum-string-attribute-length") == 0) {
maximum_string_attribute_length = atoll_require(optarg, "Maximum string attribute length");
} else if (strcmp(opt, "output-format") == 0) {
if (strcmp(optarg, "mvt") == 0 || strcmp(optarg, "pbf") == 0) {
output_format = OUTPUT_MVT;
} else if (strcmp(optarg, "mlt") == 0) {
output_format = OUTPUT_MLT;
} else {
fprintf(stderr, "%s: --output-format must be 'mvt' or 'mlt'\n", argv[0]);
exit(EXIT_ARGS);
}
set_output_format(argv, optarg);
} else if (strcmp(opt, "pretessellate") == 0) {
mlt_pretessellate = true;
} else if (strcmp(opt, "no-mlt-feature-sort") == 0) {
-7
View File
@@ -76,11 +76,4 @@ bool progress_time();
#define MAX_ZOOM 24
#define OUTPUT_MVT 0
#define OUTPUT_MLT 1
extern int output_format;
extern bool mlt_sort_features;
extern bool mlt_pretessellate;
#endif
+34
View File
@@ -1,9 +1,12 @@
#include "mlt.hpp"
#include "errors.hpp"
#include <mlt/encoder.hpp>
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <map>
#include <optional>
#include <string>
@@ -11,6 +14,37 @@
using Vertex = mlt::Encoder::Vertex;
int output_format = OUTPUT_MVT;
bool mlt_sort_features = true;
bool mlt_pretessellate = false;
void set_output_format(char **argv, const char *format) {
if (strcmp(format, "mvt") == 0 || strcmp(format, "pbf") == 0) {
output_format = OUTPUT_MVT;
} else if (strcmp(format, "mlt") == 0) {
output_format = OUTPUT_MLT;
} else {
fprintf(stderr, "%s: --output-format must be 'mvt' or 'mlt'\n", argv[0]);
exit(EXIT_ARGS);
}
}
const char *tile_format_name(int format) {
return (format == OUTPUT_MLT) ? "mlt" : "pbf";
}
const char *tile_format_extension(int format) {
return (format == OUTPUT_MLT) ? ".mlt" : ".pbf";
}
std::string encode_tile(mvt_tile &tile, int format) {
if (format == OUTPUT_MLT) {
return encode_as_mlt(tile, mlt_sort_features, mlt_pretessellate);
} else {
return tile.encode();
}
}
// An MLT property column has a single type for the whole layer, while MVT
// values each carry their own type, so a type that can hold every value of
// an attribute has to be chosen before the layer can be converted.
+20
View File
@@ -4,6 +4,26 @@
#include <string>
#include "mvt.hpp"
// The tile format to write, and the MLT encoder options to write it with,
// as selected on the command line.
extern int output_format;
extern bool mlt_sort_features;
extern bool mlt_pretessellate;
// Set output_format from an --output-format argument, complaining and
// exiting if it names a format we can't write.
void set_output_format(char **argv, const char *format);
// What this tile format is called in tileset metadata
const char *tile_format_name(int format);
// What tiles of this format are named in a tile directory
const char *tile_format_extension(int format);
// Encode a tile in the specified format, using whichever MLT encoder
// options were selected on the command line
std::string encode_tile(mvt_tile &tile, int format);
std::string encode_as_mlt(const mvt_tile &tile, bool sort_features, bool pretessellate);
// Does this (already decompressed) tile look like MapLibre Tile rather than
+4
View File
@@ -17,6 +17,10 @@
struct mvt_value;
struct mvt_layer;
// Which of the two vector tile encodings a tile is written in
#define OUTPUT_MVT 0
#define OUTPUT_MLT 1
enum mvt_operation {
mvt_moveto = 1,
mvt_lineto = 2,
+17 -1
View File
@@ -5,6 +5,7 @@
#include <set>
#include "errors.hpp"
#include "mvt.hpp"
#include "mlt.hpp"
#include "geometry.hpp"
#include "evaluator.hpp"
#include "attribute.hpp"
@@ -85,6 +86,9 @@ int main(int argc, char **argv) {
{"source-tile", required_argument, 0, 't'},
{"no-tile-compression", no_argument, 0, 'd' & 0x1F},
{"deduplicate-by-id", no_argument, 0, 'i' & 0x1F},
{"output-format", required_argument, 0, 'f' & 0x1F},
{"pretessellate", no_argument, 0, 'p' & 0x1F},
{"no-mlt-feature-sort", no_argument, 0, 'r' & 0x1F},
{0, 0, 0, 0},
};
@@ -172,6 +176,18 @@ int main(int argc, char **argv) {
break;
}
case 'f' & 0x1F:
set_output_format(argv, optarg);
break;
case 'p' & 0x1F:
mlt_pretessellate = true;
break;
case 'r' & 0x1F:
mlt_sort_features = false;
break;
default:
fprintf(stderr, "Unrecognized flag -%c\n", i);
usage(argv);
@@ -264,7 +280,7 @@ int main(int argc, char **argv) {
its.push_back(std::move(t));
}
out = overzoom(its, nz, nx, ny, detail, buffer, keep, exclude, exclude_prefix, do_compress, NULL, demultiply, json_filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, std::vector<mvt_layer>(), "", "", SIZE_MAX, std::vector<clipbbox>(), deduplicate_by_id);
out = overzoom(its, nz, nx, ny, detail, buffer, keep, exclude, exclude_prefix, do_compress, NULL, demultiply, json_filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, std::vector<mvt_layer>(), "", "", SIZE_MAX, std::vector<clipbbox>(), deduplicate_by_id, output_format);
}
FILE *f = fopen(outfile, "wb");
+104
View File
@@ -0,0 +1,104 @@
{ "type": "FeatureCollection", "properties": {
"antimeridian_adjusted_bounds": "-122.915039,37.160317,-122.343750,37.961523",
"bounds": "-122.915039,37.160317,-122.343750,37.961523",
"center": "-122.350000,37.200000,5",
"description": "tests/mlt/mvt-source.mbtiles",
"format": "mlt",
"json": "{\"vector_layers\":[{\"id\":\"roundtrip\",\"description\":\"\",\"minzoom\":0,\"maxzoom\":5,\"fields\":{\"active\":\"Boolean\",\"count\":\"Number\",\"kind\":\"String\",\"name\":\"String\",\"nested\":\"String\",\"ratio\":\"Number\",\"unicode\":\"String\"}}],\"tilestats\":{\"layerCount\":1,\"layers\":[{\"layer\":\"roundtrip\",\"count\":33,\"geometry\":\"LineString\",\"attributeCount\":7,\"attributes\":[{\"attribute\":\"active\",\"count\":2,\"type\":\"boolean\",\"values\":[false,true]},{\"attribute\":\"count\",\"count\":6,\"type\":\"number\",\"values\":[-200,100,300,4000000000,500,600],\"min\":-200,\"max\":4000000000},{\"attribute\":\"kind\",\"count\":3,\"type\":\"string\",\"values\":[\"line\",\"point\",\"polygon\"]},{\"attribute\":\"name\",\"count\":7,\"type\":\"string\",\"values\":[\"line\",\"multiline\",\"multipoint\",\"multipolygon\",\"no id\",\"point\",\"polygon with hole\"]},{\"attribute\":\"nested\",\"count\":1,\"type\":\"string\",\"values\":[\"{\\\"a\\\":1,\\\"b\\\":\\\"two\\\"}\"]},{\"attribute\":\"ratio\",\"count\":5,\"type\":\"number\",\"values\":[-0.25,0.125,1.5,2,3.25],\"min\":-0.25,\"max\":3.25},{\"attribute\":\"unicode\",\"count\":1,\"type\":\"string\",\"values\":[\"påíñtß 堤防\"]}]}]}}",
"maxzoom": "5",
"minzoom": "0",
"name": "tests/mlt/mvt-source.mbtiles",
"strategies": "[{\"dropped_by_rate\":2,\"tiny_polygons\":1},{\"dropped_by_rate\":2},{\"dropped_by_rate\":2},{\"dropped_by_rate\":2},{\"dropped_by_rate\":1}]",
"type": "overlay",
"version": "2"
}, "features": [
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.519531, 37.926868 ], [ -122.431641, 37.857507 ], [ -122.519531, 37.926868 ] ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.695312, 37.579413 ], [ -122.607422, 37.649034 ] ], [ [ -122.519531, 37.579413 ], [ -122.431641, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.607422, 37.718590 ], [ -122.431641, 37.718590 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.431641, 37.579413 ], [ -122.431641, 37.370157 ], [ -122.783203, 37.370157 ], [ -122.783203, 37.579413 ], [ -122.431641, 37.579413 ] ], [ [ -122.519531, 37.439974 ], [ -122.519531, 37.509726 ], [ -122.695312, 37.509726 ], [ -122.519531, 37.439974 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.343750, 37.300275 ], [ -122.343750, 37.160317 ], [ -122.519531, 37.160317 ], [ -122.519531, 37.300275 ], [ -122.343750, 37.300275 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.519531, 37.892196 ], [ -122.431641, 37.857507 ], [ -122.563477, 37.961523 ] ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.695312, 37.614231 ], [ -122.607422, 37.649034 ] ], [ [ -122.519531, 37.614231 ], [ -122.387695, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.607422, 37.683820 ], [ -122.519531, 37.753344 ], [ -122.387695, 37.683820 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.387695, 37.544577 ], [ -122.387695, 37.405074 ], [ -122.783203, 37.405074 ], [ -122.783203, 37.544577 ], [ -122.387695, 37.544577 ] ], [ [ -122.695312, 37.439974 ], [ -122.519531, 37.439974 ], [ -122.519531, 37.509726 ], [ -122.695312, 37.509726 ], [ -122.695312, 37.439974 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.695312, 37.300275 ], [ -122.695312, 37.195331 ], [ -122.915039, 37.195331 ], [ -122.915039, 37.300275 ], [ -122.695312, 37.300275 ] ] ], [ [ [ -122.387695, 37.300275 ], [ -122.387695, 37.195331 ], [ -122.607422, 37.195331 ], [ -122.607422, 37.300275 ], [ -122.387695, 37.300275 ] ], [ [ -122.563477, 37.230328 ], [ -122.431641, 37.230328 ], [ -122.431641, 37.265310 ], [ -122.563477, 37.265310 ], [ -122.563477, 37.230328 ] ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.497559, 37.892196 ], [ -122.453613, 37.857507 ], [ -122.541504, 37.944198 ] ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.695312, 37.596824 ], [ -122.607422, 37.649034 ] ], [ [ -122.497559, 37.596824 ], [ -122.387695, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.607422, 37.701207 ], [ -122.497559, 37.753344 ], [ -122.387695, 37.701207 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.387695, 37.544577 ], [ -122.387695, 37.405074 ], [ -122.805176, 37.405074 ], [ -122.805176, 37.544577 ], [ -122.387695, 37.544577 ] ], [ [ -122.695312, 37.457418 ], [ -122.497559, 37.457418 ], [ -122.497559, 37.492294 ], [ -122.695312, 37.492294 ], [ -122.695312, 37.457418 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.695312, 37.300275 ], [ -122.695312, 37.195331 ], [ -122.893066, 37.195331 ], [ -122.893066, 37.300275 ], [ -122.695312, 37.300275 ] ] ], [ [ [ -122.387695, 37.300275 ], [ -122.387695, 37.195331 ], [ -122.607422, 37.195331 ], [ -122.607422, 37.300275 ], [ -122.387695, 37.300275 ] ], [ [ -122.541504, 37.212832 ], [ -122.453613, 37.212832 ], [ -122.453613, 37.282795 ], [ -122.541504, 37.282795 ], [ -122.541504, 37.212832 ] ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 1, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.497559, 37.900865 ], [ -122.453613, 37.848833 ], [ -122.552490, 37.952861 ] ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.695312, 37.596824 ], [ -122.596436, 37.649034 ] ], [ [ -122.497559, 37.596824 ], [ -122.398682, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.596436, 37.701207 ], [ -122.497559, 37.744657 ], [ -122.398682, 37.701207 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.398682, 37.544577 ], [ -122.398682, 37.396346 ], [ -122.794189, 37.396346 ], [ -122.794189, 37.544577 ], [ -122.398682, 37.544577 ] ], [ [ -122.695312, 37.448697 ], [ -122.497559, 37.448697 ], [ -122.497559, 37.501010 ], [ -122.695312, 37.501010 ], [ -122.695312, 37.448697 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.695312, 37.300275 ], [ -122.695312, 37.195331 ], [ -122.904053, 37.195331 ], [ -122.904053, 37.300275 ], [ -122.695312, 37.300275 ] ] ], [ [ [ -122.398682, 37.300275 ], [ -122.398682, 37.195331 ], [ -122.596436, 37.195331 ], [ -122.596436, 37.300275 ], [ -122.398682, 37.300275 ] ], [ [ -122.552490, 37.221580 ], [ -122.453613, 37.221580 ], [ -122.453613, 37.282795 ], [ -122.552490, 37.282795 ], [ -122.552490, 37.221580 ] ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 2, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.497559, 37.900865 ], [ -122.448120, 37.848833 ], [ -122.546997, 37.948529 ] ] } }
,
{ "type": "Feature", "properties": { "kind": "point", "name": "no id", "unicode": "påíñtß 堤防" }, "geometry": { "type": "Point", "coordinates": [ -122.349243, 37.749001 ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.700806, 37.596824 ], [ -122.596436, 37.649034 ] ], [ [ -122.497559, 37.596824 ], [ -122.398682, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.596436, 37.696861 ], [ -122.497559, 37.749001 ], [ -122.398682, 37.696861 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.398682, 37.548933 ], [ -122.398682, 37.400710 ], [ -122.799683, 37.400710 ], [ -122.799683, 37.548933 ], [ -122.398682, 37.548933 ] ], [ [ -122.700806, 37.448697 ], [ -122.497559, 37.448697 ], [ -122.497559, 37.501010 ], [ -122.700806, 37.501010 ], [ -122.700806, 37.448697 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.700806, 37.300275 ], [ -122.700806, 37.199706 ], [ -122.898560, 37.199706 ], [ -122.898560, 37.300275 ], [ -122.700806, 37.300275 ] ] ], [ [ [ -122.398682, 37.300275 ], [ -122.398682, 37.199706 ], [ -122.596436, 37.199706 ], [ -122.596436, 37.300275 ], [ -122.398682, 37.300275 ] ], [ [ -122.546997, 37.217206 ], [ -122.448120, 37.217206 ], [ -122.448120, 37.278424 ], [ -122.546997, 37.278424 ], [ -122.546997, 37.217206 ] ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 5, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "roundtrip", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "id": 2, "properties": { "active": false, "count": -200, "kind": "point", "name": "multipoint", "ratio": -0.25 }, "geometry": { "type": "MultiPoint", "coordinates": [ [ -122.500305, 37.900865 ], [ -122.450867, 37.851001 ], [ -122.549744, 37.950695 ] ] } }
,
{ "type": "Feature", "id": 1, "properties": { "active": true, "count": 100, "kind": "point", "name": "point", "nested": "{\"a\":1,\"b\":\"two\"}", "ratio": 1.5 }, "geometry": { "type": "Point", "coordinates": [ -122.398682, 37.798933 ] } }
,
{ "type": "Feature", "properties": { "kind": "point", "name": "no id", "unicode": "påíñtß 堤防" }, "geometry": { "type": "Point", "coordinates": [ -122.349243, 37.749001 ] } }
,
{ "type": "Feature", "id": 4, "properties": { "count": 4000000000, "kind": "line", "name": "multiline", "ratio": 0.125 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -122.700806, 37.599000 ], [ -122.599182, 37.649034 ] ], [ [ -122.500305, 37.599000 ], [ -122.398682, 37.649034 ] ] ] } }
,
{ "type": "Feature", "id": 3, "properties": { "count": 300, "kind": "line", "name": "line", "ratio": 2 }, "geometry": { "type": "LineString", "coordinates": [ [ -122.599182, 37.699034 ], [ -122.500305, 37.749001 ], [ -122.398682, 37.699034 ] ] } }
,
{ "type": "Feature", "id": 5, "properties": { "active": true, "count": 500, "kind": "polygon", "name": "polygon with hole", "ratio": 3.25 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -122.398682, 37.548933 ], [ -122.398682, 37.400710 ], [ -122.799683, 37.400710 ], [ -122.799683, 37.548933 ], [ -122.398682, 37.548933 ] ], [ [ -122.700806, 37.450877 ], [ -122.500305, 37.450877 ], [ -122.500305, 37.501010 ], [ -122.700806, 37.501010 ], [ -122.700806, 37.450877 ] ] ] } }
,
{ "type": "Feature", "id": 6, "properties": { "count": 600, "kind": "polygon", "name": "multipolygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -122.700806, 37.300275 ], [ -122.700806, 37.199706 ], [ -122.901306, 37.199706 ], [ -122.901306, 37.300275 ], [ -122.700806, 37.300275 ] ] ], [ [ [ -122.398682, 37.300275 ], [ -122.398682, 37.199706 ], [ -122.599182, 37.199706 ], [ -122.599182, 37.300275 ], [ -122.398682, 37.300275 ] ], [ [ -122.549744, 37.219393 ], [ -122.450867, 37.219393 ], [ -122.450867, 37.280609 ], [ -122.549744, 37.280609 ], [ -122.549744, 37.219393 ] ] ] ] } }
] }
] }
] }
+13 -3
View File
@@ -24,6 +24,7 @@
#include <math.h>
#include <pthread.h>
#include "mvt.hpp"
#include "mlt.hpp"
#include "projection.hpp"
#include "mbtiles.hpp"
#include "geometry.hpp"
@@ -871,7 +872,7 @@ void *join_worker(void *v) {
}
if (anything) {
std::string pbf = outtile.encode();
std::string pbf = encode_tile(outtile, output_format);
std::string compressed;
if (!pC) {
@@ -958,7 +959,7 @@ void dispatch_tasks(std::map<zxy, std::vector<std::string>> &tasks, std::vector<
if (outdb != NULL) {
mbtiles_write_tile(outdb, ai->first.z, ai->first.x, ai->first.y, ai->second.data(), ai->second.size());
} else if (outdir != NULL) {
dir_write_tile(outdir, ai->first.z, ai->first.x, ai->first.y, ai->second);
dir_write_tile(outdir, ai->first.z, ai->first.x, ai->first.y, ai->second, tile_format_extension(output_format));
}
}
}
@@ -1335,6 +1336,9 @@ int main(int argc, char **argv) {
{"tile-stats-sample-values-limit", required_argument, 0, '~'},
{"tile-stats-values-limit", required_argument, 0, '~'},
{"unidecode-data", required_argument, 0, '~'},
{"output-format", required_argument, 0, '~'},
{"pretessellate", no_argument, 0, '~'},
{"no-mlt-feature-sort", no_argument, 0, '~'},
{0, 0, 0, 0},
};
@@ -1515,6 +1519,12 @@ int main(int argc, char **argv) {
exclude_all_tile_attributes = true;
} else if (strcmp(opt, "exclude-all-tile-geometries") == 0) {
exclude_all_tile_geometries = true;
} else if (strcmp(opt, "output-format") == 0) {
set_output_format(argv, optarg);
} else if (strcmp(opt, "pretessellate") == 0) {
mlt_pretessellate = true;
} else if (strcmp(opt, "no-mlt-feature-sort") == 0) {
mlt_sort_features = false;
} else {
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
exit(EXIT_ARGS);
@@ -1636,7 +1646,7 @@ int main(int argc, char **argv) {
st.maxlon2 = st.maxlon;
}
metadata m = make_metadata(name.c_str(), st.minzoom, st.maxzoom, st.minlat, st.minlon, st.maxlat, st.maxlon, st.minlat2, st.minlon2, st.maxlat2, st.maxlon2, st.midlat, st.midlon, attribution.size() != 0 ? attribution.c_str() : NULL, layermap, "pbf", description.c_str(), !pg, attribute_descriptions, "tile-join", generator_options, strategies, st.maxzoom, 2.5, 1);
metadata m = make_metadata(name.c_str(), st.minzoom, st.maxzoom, st.minlat, st.minlon, st.maxlat, st.maxlon, st.minlat2, st.minlon2, st.maxlat2, st.maxlon2, st.midlat, st.midlon, attribution.size() != 0 ? attribution.c_str() : NULL, layermap, tile_format_name(output_format), description.c_str(), !pg, attribute_descriptions, "tile-join", generator_options, strategies, st.maxzoom, 2.5, 1);
if (outdb != NULL) {
mbtiles_write_metadata(outdb, m, true);
+2 -8
View File
@@ -2854,12 +2854,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
}
std::string compressed;
std::string pbf;
if (output_format == OUTPUT_MLT) {
pbf = encode_as_mlt(tile, mlt_sort_features, mlt_pretessellate);
} else {
pbf = tile.encode();
}
std::string pbf = encode_tile(tile, output_format);
tile.layers.clear();
@@ -3034,8 +3029,7 @@ long long write_tile(decompressor *geoms, std::atomic<long long> *geompos_in, ch
if (outdb != NULL) {
mbtiles_write_tile(outdb, z, tx, ty, compressed.data(), compressed.size());
} else if (outdir != NULL) {
const char *tile_ext = (output_format == OUTPUT_MLT) ? ".mlt" : ".pbf";
dir_write_tile(outdir, z, tx, ty, compressed, tile_ext);
dir_write_tile(outdir, z, tx, ty, compressed, tile_format_extension(output_format));
}
if (pthread_mutex_unlock(&db_lock) != 0) {