Compare commits

..

1 Commits

286 changed files with 29854 additions and 123023 deletions

11
.gitignore vendored
View File

@ -34,19 +34,10 @@ tippecanoe
tile-join
tippecanoe-decode
tippecanoe-enumerate
tippecanoe-json-tool
unit
# Tests
tests/**/*.mbtiles
tests/**/*.check
tests/**/*.geobuf
# Vim
*.swp
# Mac
# Mac
.DS_Store
# Nodejs
node_modules

View File

@ -43,7 +43,7 @@ matrix:
# debug+leak+address-sanitizer build
- os: linux
compiler: clang
env: CLANG_VERSION='3.8.0' BUILDTYPE=Debug ASAN_OPTIONS=detect_leaks=1 CC="clang-3.8" CXX="clang++-3.8" CXXFLAGS="-fsanitize=address,undefined" CFLAGS="-fsanitize=address,undefined" LDFLAGS="-fsanitize=address,undefined" FEWER=true
env: CLANG_VERSION='3.8.0' BUILDTYPE=Debug ASAN_OPTIONS=detect_leaks=1 CC="clang-3.8" CXX="clang++-3.8" CXXFLAGS="-fsanitize=address" CFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" FEWER=true
addons:
apt:
sources: ['ubuntu-toolchain-r-test' ]
@ -52,13 +52,6 @@ matrix:
- os: linux
compiler: clang
env: CLANG_VERSION='3.8.0' BUILDTYPE=Debug CC="clang-3.8" CXX="clang++-3.8" CXXFLAGS="--coverage" CFLAGS="--coverage" LDFLAGS="--coverage"
after_script:
- mason install llvm-cov 3.9.1
- mason link llvm-cov 3.9.1
- which llvm-cov
- curl -S -f https://codecov.io/bash -o codecov
- chmod +x codecov
- ./codecov -x "llvm-cov gcov" -Z
addons:
apt:
sources: ['ubuntu-toolchain-r-test' ]
@ -108,3 +101,8 @@ script:
BUILDTYPE=${BUILDTYPE} make fewer-tests; else
BUILDTYPE=${BUILDTYPE} make test geobuf-test;
fi
- if [ -n "${COVERAGE}" ]; then
/usr/bin/llvm-cov-3.5 -lp *.o;
pip install --user cpp-coveralls;
~/.local/bin/coveralls --no-gcov -i ./ --exclude clipper;
fi

View File

@ -1,253 +1,8 @@
## 1.36.0
* Update Wagyu to version 0.5.0
## 1.35.0
* Fix calculation of mean when accumulating attributes in clusters
## 1.34.6
* Fix crash when there are null entries in the metadata table
## 1.34.5
* Fix line numbers in GeoJSON feature parsing error messages
## 1.34.4
* Be careful to avoid undefined behavior from shifting negative numbers
## 1.34.3
* Add an option to keep intersection nodes from being simplified away
## 1.34.2
* Be more consistent about when longitudes beyond 180 are allowed.
Now if the entire feature is beyond 180, it will still appear.
## 1.34.1
* Don't run shell filters if the current zoom is below the minzoom
* Fix -Z and -z for tile directories in tile-join and tippecanoe-decode
* Return a successful error status for --help and --version
## 1.34.0
* Record the command line options in the tileset metadata
## 1.33.0
* MultiLineStrings were previously ignored in Geobuf input
## 1.32.12
* Accept .mvt as well as .pbf in directories of tiles
* Allow tippecanoe-decode and tile-join of directories with no metadata
## 1.32.11
* Don't let attribute exclusion apply to the attribute that has been specified
to become the feature ID
## 1.32.10
* Fix a bug that disallowed a per-feature minzoom of 0
## 1.32.9
* Limit tile detail to 30 and buffer size to 127 to prevent coordinate
delta overflow in vector tiles.
## 1.32.8
* Better error message if the output tileset already exists
## 1.32.7
* Point features may now be coalesced into MultiPoint features with --coalesce.
* Add --hilbert option to put features in Hilbert Curve sequence
## 1.32.6
* Make it an error, not a warning, to have missing coordinates for a point
## 1.32.5
* Use less memory on lines and polygons that are too small for the tile
* Fix coordinate rounding problem that was causing --grid-low-zooms grids
to be lost at low zooms if the original polygons were not aligned to
tile boundaries
## 1.32.4
* Ignore leading zeroes when converting string attributes to feature IDs
## 1.32.3
* Add an option to convert stringified number feature IDs to numbers
* Add an option to use a specified feature attribute as the feature ID
## 1.32.2
* Warn in tile-join if tilesets being joined have inconsistent maxzooms
## 1.32.1
* Fix null pointer crash when reading filter output that does not
tag features with their extent
* Add `--clip-bounding-box` option to clip input geometry
## 1.32.0
* Fix a bug that allowed coalescing of features with mismatched attributes
if they had been passed through a shell prefilter
## 1.31.7
* Create the output tile directory even if there are no valid features
## 1.31.6
* Issue an error message in tile-join if minzoom is greater than maxzoom
## 1.31.5
* Add options to change the tilestats limits
## 1.31.4
* Keep tile-join from generating a tileset name longer than 255 characters
## 1.31.3
* Fix the missing filename in JSON parsing warning messages
## 1.31.2
## 1.27.6
* Don't accept anything inside another JSON object's properties as a
feature or geometry of its own.
## 1.31.1
* Add --exclude-all to tile-join
## 1.31.0
* Upgrade Wagyu to version 0.4.3
## 1.30.6
* Take cluster distance into account when guessing a maxzoom
## 1.30.4
* Features within the z0 tile buffer of the antimeridian (not only
those that cross it) are duplicated on both sides.
## 1.30.3
* Add an option to automatically assign ids to features
## 1.30.2
* Don't guess a higher maxzoom than is allowed for manual selection
## 1.30.1
* Ensure that per-feature minzoom and maxzoom are integers
* Report compression errors in tippecanoe-decode
* Add the ability to specify the file format with -L{"format":"…"}
* Add an option to treat empty CSV columns as nulls, not empty strings
## 1.30.0
* Add a filter extension to allow filtering individual attributes
## 1.29.3
* Include a generator field in tileset metadata with the Tippecanoe version
## 1.29.2
* Be careful to remove null attributes from prefilter/postfilter output
## 1.29.1
* Add --use-source-polygon-winding and --reverse-source-polygon-winding
## 1.29.0
* Add the option to specify layer file, name, and description as JSON
* Add the option to specify the description for attributes in the
tileset metadata
* In CSV input, a trailing comma now counts as a trailing empty field
* In tippecanoe-json-tool, an empty CSV field is now an empty string,
not null (for consistency with tile-join)
## 1.28.1
* Explicitly check for infinite and not-a-number input coordinates
## 1.28.0
* Directly support gzipped GeoJSON as input files
## 1.27.16
* Fix thread safety issues related to the out-of-disk-space checker
## 1.27.15
* --extend-zooms-if-still-dropping now also extends zooms if features
are dropped by --force-feature-limit
## 1.27.14
* Use an exit status of 100 if some zoom levels were successfully
written but not all zoom levels could be tiled.
## 1.27.13
* Allow filtering features by zoom level in conditional expressions
* Lines in CSV input with empty geometry columns will be ignored
## 1.27.12
* Check integrity of sqlite3 file before decoding or tile-joining
## 1.27.11
* Always include tile and layer in tippecanoe-decode, fixing corrupt JSON.
* Clean up writing of JSON in general.
## 1.27.10
* Add --progress-interval setting to reduce progress indicator frequency
## 1.27.9
* Make clusters look better by averaging locations of clustered points
## 1.27.8
* Add --accumulate-attribute to keep attributes of dropped, coalesced,
or clustered features
* Make sure numeric command line arguments are actually numbers
* Don't coalesce features whose non-string-pool attributes don't match
## 1.27.7
* Add an option to produce only a single tile
* Retain non-ASCII characters in layernames generated from filenames
* Remember to close input files after reading them
* Add --coalesce-fraction-as-needed and --coalesce-densest-as-needed
* Report distances in both feet and meters
## 1.27.6
* Fix opportunities for integer overflow and out-of-bounds references
## 1.27.5
* Add --cluster-densest-as-needed to cluster features

View File

@ -1,5 +1,5 @@
# Start from ubuntu
FROM ubuntu:16.04
FROM ubuntu:17.04
# Update repos and install dependencies
RUN apt-get update \

262
Makefile
View File

@ -47,19 +47,19 @@ C = $(wildcard *.c) $(wildcard *.cpp)
INCLUDES = -I/usr/local/include -I.
LIBS = -L/usr/local/lib
tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o projection.o memfile.o mvt.o serial.o main.o text.o dirtiles.o plugin.o read_json.o write_json.o geobuf.o evaluator.o geocsv.o csv.o geojson-loop.o
tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o projection.o memfile.o mvt.o serial.o main.o text.o dirtiles.o plugin.o read_json.o write_json.o geobuf.o evaluator.o geocsv.o csv.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
tippecanoe-enumerate: enumerate.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lsqlite3
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CFLAGS) -o $@ $^ $(LDFLAGS) -lsqlite3
tippecanoe-decode: decode.o projection.o mvt.o write_json.o text.o jsonpull/jsonpull.o dirtiles.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3
tile-join: tile-join.o projection.o pool.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o write_json.o
tile-join: tile-join.o projection.o pool.o mbtiles.o mvt.o memfile.o dirtiles.o jsonpull/jsonpull.o text.o evaluator.o csv.o
$(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
tippecanoe-json-tool: jsontool.o jsonpull/jsonpull.o csv.o text.o
$(CXX) $(PG) $(LIBS) $(FINAL_FLAGS) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) -lm -lz -lsqlite3 -lpthread
unit: unit.o text.o
@ -74,7 +74,7 @@ unit: unit.o text.o
$(CXX) -MMD $(PG) $(INCLUDES) $(FINAL_FLAGS) $(CXXFLAGS) -c -o $@ $<
clean:
rm -f ./tippecanoe ./tippecanoe-* ./tile-join ./unit *.o *.d */*.o */*.d tests/**/*.mbtiles tests/**/*.check
rm -f ./tippecanoe ./tippecanoe-* ./tile-join ./unit *.o *.d */*.o */*.d
indent:
clang-format -i -style="{BasedOnStyle: Google, IndentWidth: 8, UseTab: Always, AllowShortIfStatementsOnASingleLine: false, ColumnLimit: 0, ContinuationIndentWidth: 8, SpaceAfterCStyleCast: true, IndentCaseLabels: false, AllowShortBlocksOnASingleLine: false, AllowShortFunctionsOnASingleLine: false, SortIncludes: false}" $(C) $(H)
@ -82,22 +82,18 @@ 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
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
./unit
suffixes = json json.gz
# Work around Makefile and filename punctuation limits: _ for space, @ for :, % for /
%.json.check:
./tippecanoe -q -a@ -f -o $@.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json.check,%,$(word 4,$(subst /, ,$@)))))) $(foreach suffix,$(suffixes),$(sort $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.$(suffix)))) < /dev/null
./tippecanoe-decode -x generator $@.mbtiles > $@.out
./tippecanoe -aD -f -o $@.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json.check,%,$(word 4,$(subst /, ,$@)))))) $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.json) < /dev/null
./tippecanoe-decode $@.mbtiles > $@.out
cmp $@.out $(patsubst %.check,%,$@)
rm $@.out $@.mbtiles
# Don't test overflow with geobuf, because it fails (https://github.com/mapbox/geobuf/issues/87)
# Don't test stringids with geobuf, because it fails
nogeobuf = tests/overflow/out/-z0.json $(wildcard tests/stringid/out/*.json)
geobuf-test: tippecanoe-json-tool $(addsuffix .checkbuf,$(filter-out $(nogeobuf),$(TESTS)))
geobuf-test: tippecanoe-json-tool $(addsuffix .checkbuf,$(filter-out tests/overflow/out/-z0.json,$(TESTS)))
# For quicker address sanitizer build, hope that regular JSON parsing is tested enough by parallel and join tests
fewer-tests: tippecanoe tippecanoe-decode geobuf-test raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit
@ -105,9 +101,8 @@ fewer-tests: tippecanoe tippecanoe-decode geobuf-test raw-tiles-test parallel-te
# XXX Use proper makefile rules instead of a for loop
%.json.checkbuf:
for i in $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.json); do ./tippecanoe-json-tool -w $$i | ./node_modules/geobuf/bin/json2geobuf > $$i.geobuf; done
for i in $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.json.gz); do gzip -dc $$i | ./tippecanoe-json-tool -w | ./node_modules/geobuf/bin/json2geobuf > $$i.geobuf; done
./tippecanoe -q -a@ -f -o $@.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json.checkbuf,%,$(word 4,$(subst /, ,$@)))))) $(foreach suffix,$(suffixes),$(addsuffix .geobuf,$(sort $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.$(suffix))))) < /dev/null
./tippecanoe-decode -x generator $@.mbtiles | sed 's/checkbuf/check/g' | sed 's/\.geobuf//g' > $@.out
./tippecanoe -aD -f -o $@.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json.checkbuf,%,$(word 4,$(subst /, ,$@)))))) $(addsuffix .geobuf,$(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.json)) < /dev/null
./tippecanoe-decode $@.mbtiles | sed 's/checkbuf/check/g' > $@.out
cmp $@.out $(patsubst %.checkbuf,%,$@)
rm $@.out $@.mbtiles
@ -119,18 +114,18 @@ parallel-test:
perl -e 'for ($$i = 0; $$i < 20; $$i++) { $$lon = rand(360) - 180; $$lat = rand(180) - 90; $$v = rand(1); print "{ \"type\": \"Feature\", \"properties\": { }, \"tippecanoe\": { \"layer\": \"$$v\" }, \"geometry\": { \"type\": \"Point\", \"coordinates\": [ $$lon, $$lat ] } }\n"; }' > tests/parallel/in4.json
echo -n "" > tests/parallel/empty1.json
echo "" > tests/parallel/empty2.json
./tippecanoe -q -z5 -f -pi -l test -n test -o tests/parallel/linear-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
./tippecanoe -q -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
cat tests/parallel/in[1234].json | ./tippecanoe -q -z5 -f -pi -l test -n test -o tests/parallel/linear-pipe.mbtiles
cat tests/parallel/in[1234].json | ./tippecanoe -q -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipe.mbtiles
cat tests/parallel/in[1234].json | sed 's/^/@/' | tr '@' '\036' | ./tippecanoe -q -z5 -f -pi -l test -n test -o tests/parallel/implicit-pipe.mbtiles
./tippecanoe -q -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipes.mbtiles <(cat tests/parallel/in1.json) <(cat tests/parallel/empty1.json) <(cat tests/parallel/empty2.json) <(cat tests/parallel/in2.json) /dev/null <(cat tests/parallel/in3.json) <(cat tests/parallel/in4.json)
./tippecanoe-decode -x generator -x generator_options tests/parallel/linear-file.mbtiles > tests/parallel/linear-file.json
./tippecanoe-decode -x generator -x generator_options tests/parallel/parallel-file.mbtiles > tests/parallel/parallel-file.json
./tippecanoe-decode -x generator -x generator_options tests/parallel/linear-pipe.mbtiles > tests/parallel/linear-pipe.json
./tippecanoe-decode -x generator -x generator_options tests/parallel/parallel-pipe.mbtiles > tests/parallel/parallel-pipe.json
./tippecanoe-decode -x generator -x generator_options tests/parallel/implicit-pipe.mbtiles > tests/parallel/implicit-pipe.json
./tippecanoe-decode -x generator -x generator_options tests/parallel/parallel-pipes.mbtiles > tests/parallel/parallel-pipes.json
./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-file.mbtiles tests/parallel/in[1234].json tests/parallel/empty[12].json
cat tests/parallel/in[1234].json | ./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/linear-pipe.mbtiles
cat tests/parallel/in[1234].json | ./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipe.mbtiles
cat tests/parallel/in[1234].json | sed 's/^/@/' | tr '@' '\036' | ./tippecanoe -z5 -f -pi -l test -n test -o tests/parallel/implicit-pipe.mbtiles
./tippecanoe -z5 -f -pi -l test -n test -P -o tests/parallel/parallel-pipes.mbtiles <(cat tests/parallel/in1.json) <(cat tests/parallel/empty1.json) <(cat tests/parallel/empty2.json) <(cat tests/parallel/in2.json) /dev/null <(cat tests/parallel/in3.json) <(cat tests/parallel/in4.json)
./tippecanoe-decode tests/parallel/linear-file.mbtiles > tests/parallel/linear-file.json
./tippecanoe-decode tests/parallel/parallel-file.mbtiles > tests/parallel/parallel-file.json
./tippecanoe-decode tests/parallel/linear-pipe.mbtiles > tests/parallel/linear-pipe.json
./tippecanoe-decode tests/parallel/parallel-pipe.mbtiles > tests/parallel/parallel-pipe.json
./tippecanoe-decode tests/parallel/implicit-pipe.mbtiles > tests/parallel/implicit-pipe.json
./tippecanoe-decode tests/parallel/parallel-pipes.mbtiles > tests/parallel/parallel-pipes.json
cmp tests/parallel/linear-file.json tests/parallel/parallel-file.json
cmp tests/parallel/linear-file.json tests/parallel/linear-pipe.json
cmp tests/parallel/linear-file.json tests/parallel/parallel-pipe.json
@ -138,203 +133,138 @@ parallel-test:
cmp tests/parallel/linear-file.json tests/parallel/parallel-pipes.json
rm tests/parallel/*.mbtiles tests/parallel/*.json
raw-tiles-test:
./tippecanoe -q -f -e tests/raw-tiles/raw-tiles -r1 -pC tests/raw-tiles/hackspots.geojson
./tippecanoe-decode -x generator tests/raw-tiles/raw-tiles > tests/raw-tiles/raw-tiles.json.check
cmp tests/raw-tiles/raw-tiles.json.check tests/raw-tiles/raw-tiles.json
# Test that -z and -Z work in tippecanoe-decode
./tippecanoe-decode -x generator -Z6 -z7 tests/raw-tiles/raw-tiles > tests/raw-tiles/raw-tiles-z67.json.check
cmp tests/raw-tiles/raw-tiles-z67.json.check tests/raw-tiles/raw-tiles-z67.json
# Test that -z and -Z work in tile-join
./tile-join -q -f -Z6 -z7 -e tests/raw-tiles/raw-tiles-z67 tests/raw-tiles/raw-tiles
./tippecanoe-decode -x generator tests/raw-tiles/raw-tiles-z67 > tests/raw-tiles/raw-tiles-z67-join.json.check
cmp tests/raw-tiles/raw-tiles-z67-join.json.check tests/raw-tiles/raw-tiles-z67-join.json
rm -rf tests/raw-tiles/raw-tiles tests/raw-tiles/raw-tiles-z67 tests/raw-tiles/raw-tiles.json.check raw-tiles-z67.json.check tests/raw-tiles/raw-tiles-z67-join.json.check
# Test that metadata.json is created even if all features are clipped away
./tippecanoe -q -f -e tests/raw-tiles/nothing tests/raw-tiles/nothing.geojson
./tippecanoe-decode -x generator tests/raw-tiles/nothing > tests/raw-tiles/nothing.json.check
cmp tests/raw-tiles/nothing.json.check tests/raw-tiles/nothing.json
rm -r tests/raw-tiles/nothing tests/raw-tiles/nothing.json.check
raw-tiles-test:
./tippecanoe -f -e tests/raw-tiles/raw-tiles tests/raw-tiles/hackspots.geojson -pC
diff -x '*.DS_Store' -rq tests/raw-tiles/raw-tiles tests/raw-tiles/compare
rm -rf tests/raw-tiles/raw-tiles
decode-test:
mkdir -p tests/muni/decode
./tippecanoe -q -z11 -Z11 -f -o tests/muni/decode/multi.mbtiles tests/muni/*.json
./tippecanoe-decode -x generator -l subway tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.json.check
./tippecanoe-decode -x generator -c tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.pipeline.json.check
./tippecanoe-decode -x generator tests/muni/decode/multi.mbtiles 11 327 791 > tests/muni/decode/multi.mbtiles.onetile.json.check
./tippecanoe-decode -x generator --stats tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.stats.json.check
./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
./tippecanoe-decode --stats tests/muni/decode/multi.mbtiles > tests/muni/decode/multi.mbtiles.stats.json.check
cmp tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles.json
cmp tests/muni/decode/multi.mbtiles.pipeline.json.check tests/muni/decode/multi.mbtiles.pipeline.json
cmp tests/muni/decode/multi.mbtiles.onetile.json.check tests/muni/decode/multi.mbtiles.onetile.json
cmp tests/muni/decode/multi.mbtiles.stats.json.check tests/muni/decode/multi.mbtiles.stats.json
rm -f tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles tests/muni/decode/multi.mbtiles.pipeline.json.check tests/muni/decode/multi.mbtiles.stats.json.check tests/muni/decode/multi.mbtiles.onetile.json.check
rm -f tests/muni/decode/multi.mbtiles.json.check tests/muni/decode/multi.mbtiles tests/muni/decode/multi.mbtiles.pipeline.json.check tests/muni/decode/multi.mbtiles.stats.json.check
pbf-test:
./tippecanoe-decode -x generator tests/pbf/11-328-791.vector.pbf 11 328 791 > tests/pbf/11-328-791.vector.pbf.out
./tippecanoe-decode tests/pbf/11-328-791.vector.pbf 11 328 791 > tests/pbf/11-328-791.vector.pbf.out
cmp tests/pbf/11-328-791.json tests/pbf/11-328-791.vector.pbf.out
rm tests/pbf/11-328-791.vector.pbf.out
./tippecanoe-decode -x generator -s EPSG:3857 tests/pbf/11-328-791.vector.pbf 11 328 791 > tests/pbf/11-328-791.3857.vector.pbf.out
./tippecanoe-decode -s EPSG:3857 tests/pbf/11-328-791.vector.pbf 11 328 791 > tests/pbf/11-328-791.3857.vector.pbf.out
cmp tests/pbf/11-328-791.3857.json tests/pbf/11-328-791.3857.vector.pbf.out
rm tests/pbf/11-328-791.3857.vector.pbf.out
enumerate-test:
./tippecanoe -q -z5 -f -o tests/ne_110m_admin_0_countries/out/enum.mbtiles tests/ne_110m_admin_0_countries/in.json.gz
./tippecanoe -z5 -f -o tests/ne_110m_admin_0_countries/out/enum.mbtiles tests/ne_110m_admin_0_countries/in.json
./tippecanoe-enumerate tests/ne_110m_admin_0_countries/out/enum.mbtiles > tests/ne_110m_admin_0_countries/out/enum.check
cmp tests/ne_110m_admin_0_countries/out/enum tests/ne_110m_admin_0_countries/out/enum.check
rm tests/ne_110m_admin_0_countries/out/enum.mbtiles tests/ne_110m_admin_0_countries/out/enum.check
join-test: tile-join
./tippecanoe -q -f -z12 -o tests/join-population/tabblock_06001420.mbtiles -YALAND10:'Land area' -L'{"file": "tests/join-population/tabblock_06001420.json", "description": "population"}'
./tippecanoe -q -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur tests/join-population/macarthur.json
./tile-join -q -f -Z6 -z9 -o tests/join-population/macarthur-6-9.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode -x generator tests/join-population/macarthur-6-9.mbtiles > tests/join-population/macarthur-6-9.mbtiles.json.check
join-test:
./tippecanoe -f -z12 -o tests/join-population/tabblock_06001420.mbtiles tests/join-population/tabblock_06001420.json
./tippecanoe -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur tests/join-population/macarthur.json
./tile-join -f -Z6 -z9 -o tests/join-population/macarthur-6-9.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode tests/join-population/macarthur-6-9.mbtiles > tests/join-population/macarthur-6-9.mbtiles.json.check
cmp tests/join-population/macarthur-6-9.mbtiles.json.check tests/join-population/macarthur-6-9.mbtiles.json
./tile-join -q -f -Z6 -z9 -X -o tests/join-population/macarthur-6-9-exclude.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode -x generator tests/join-population/macarthur-6-9-exclude.mbtiles > tests/join-population/macarthur-6-9-exclude.mbtiles.json.check
cmp tests/join-population/macarthur-6-9-exclude.mbtiles.json.check tests/join-population/macarthur-6-9-exclude.mbtiles.json
rm -f tests/join-population/macarthur-6-9.mbtiles.json.check tests/join-population/macarthur-6-9.mbtiles tests/join-population/macarthur-6-9-exclude.mbtiles.json.check tests/join-population/macarthur-6-9-exclude.mbtiles
./tippecanoe -q -f -d10 -D10 -Z9 -z11 -o tests/join-population/macarthur2.mbtiles -l macarthur tests/join-population/macarthur2.json
rm -f tests/join-population/macarthur-6-9.mbtiles.json.check tests/join-population/macarthur-6-9.mbtiles
./tippecanoe -f -d10 -D10 -Z9 -z11 -o tests/join-population/macarthur2.mbtiles -l macarthur tests/join-population/macarthur2.json
./tile-join --quiet --force -o tests/join-population/joined.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join --quiet --force -o tests/join-population/joined-null.mbtiles --empty-csv-columns-are-null -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join --quiet --force --no-tile-stats -o tests/join-population/joined-no-tile-stats.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join -q -f -i -o tests/join-population/joined-i.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join -q -f -o tests/join-population/merged.mbtiles tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tile-join -q -f -c tests/join-population/windows.csv -o tests/join-population/windows.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode -x generator --maximum-zoom=11 --minimum-zoom=4 tests/join-population/joined.mbtiles > tests/join-population/joined.mbtiles.json.check
./tippecanoe-decode -x generator --maximum-zoom=11 --minimum-zoom=4 tests/join-population/joined-null.mbtiles > tests/join-population/joined-null.mbtiles.json.check
./tippecanoe-decode -x generator --maximum-zoom=11 --minimum-zoom=4 tests/join-population/joined-no-tile-stats.mbtiles > tests/join-population/joined-no-tile-stats.mbtiles.json.check
./tippecanoe-decode -x generator tests/join-population/joined-i.mbtiles > tests/join-population/joined-i.mbtiles.json.check
./tippecanoe-decode -x generator tests/join-population/merged.mbtiles > tests/join-population/merged.mbtiles.json.check
./tippecanoe-decode -x generator tests/join-population/windows.mbtiles > tests/join-population/windows.mbtiles.json.check
./tile-join -f -i -o tests/join-population/joined-i.mbtiles -x GEOID10 -c tests/join-population/population.csv tests/join-population/tabblock_06001420.mbtiles
./tile-join -f -o tests/join-population/merged.mbtiles tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tile-join -f -c tests/join-population/windows.csv -o tests/join-population/windows.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode --maximum-zoom=11 --minimum-zoom=4 tests/join-population/joined.mbtiles > tests/join-population/joined.mbtiles.json.check
./tippecanoe-decode --maximum-zoom=11 --minimum-zoom=4 tests/join-population/joined-no-tile-stats.mbtiles > tests/join-population/joined-no-tile-stats.mbtiles.json.check
./tippecanoe-decode tests/join-population/joined-i.mbtiles > tests/join-population/joined-i.mbtiles.json.check
./tippecanoe-decode tests/join-population/merged.mbtiles > tests/join-population/merged.mbtiles.json.check
./tippecanoe-decode tests/join-population/windows.mbtiles > tests/join-population/windows.mbtiles.json.check
cmp tests/join-population/joined.mbtiles.json.check tests/join-population/joined.mbtiles.json
cmp tests/join-population/joined-null.mbtiles.json.check tests/join-population/joined-null.mbtiles.json
cmp tests/join-population/joined-no-tile-stats.mbtiles.json.check tests/join-population/joined-no-tile-stats.mbtiles.json
cmp tests/join-population/joined-i.mbtiles.json.check tests/join-population/joined-i.mbtiles.json
cmp tests/join-population/merged.mbtiles.json.check tests/join-population/merged.mbtiles.json
cmp tests/join-population/windows.mbtiles.json.check tests/join-population/windows.mbtiles.json
rm -f tests/join-population/joined-null.mbtiles tests/join-population/joined-null.mbtiles.json.check
./tile-join -q -f -l macarthur -n "macarthur name" -N "macarthur description" -A "macarthur's attribution" -o tests/join-population/just-macarthur.mbtiles tests/join-population/merged.mbtiles
./tile-join -q -f -L macarthur -o tests/join-population/no-macarthur.mbtiles tests/join-population/merged.mbtiles
./tippecanoe-decode -x generator tests/join-population/just-macarthur.mbtiles > tests/join-population/just-macarthur.mbtiles.json.check
./tippecanoe-decode -x generator tests/join-population/no-macarthur.mbtiles > tests/join-population/no-macarthur.mbtiles.json.check
./tile-join -f -l macarthur -n "macarthur name" -N "macarthur description" -A "macarthur attribution" -o tests/join-population/just-macarthur.mbtiles tests/join-population/merged.mbtiles
./tile-join -f -L macarthur -o tests/join-population/no-macarthur.mbtiles tests/join-population/merged.mbtiles
./tippecanoe-decode tests/join-population/just-macarthur.mbtiles > tests/join-population/just-macarthur.mbtiles.json.check
./tippecanoe-decode tests/join-population/no-macarthur.mbtiles > tests/join-population/no-macarthur.mbtiles.json.check
cmp tests/join-population/just-macarthur.mbtiles.json.check tests/join-population/just-macarthur.mbtiles.json
cmp tests/join-population/no-macarthur.mbtiles.json.check tests/join-population/no-macarthur.mbtiles.json
./tile-join -q --no-tile-compression -f -e tests/join-population/raw-merged-folder tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tippecanoe-decode -x generator tests/join-population/raw-merged-folder > tests/join-population/raw-merged-folder.json.check
cmp tests/join-population/raw-merged-folder.json.check tests/join-population/raw-merged-folder.json
rm -f tests/join-population/raw-merged-folder.json.check
./tippecanoe -q -z12 -f -e tests/join-population/tabblock_06001420-folder -YALAND10:'Land area' -L'{"file": "tests/join-population/tabblock_06001420.json", "description": "population"}'
./tippecanoe -q -Z5 -z10 -f -e tests/join-population/macarthur-folder -l macarthur tests/join-population/macarthur.json
./tippecanoe -q -d10 -D10 -Z9 -z11 -f -e tests/join-population/macarthur2-folder -l macarthur tests/join-population/macarthur2.json
./tile-join -q -f -o tests/join-population/merged-folder.mbtiles tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder
./tippecanoe-decode -x generator tests/join-population/merged-folder.mbtiles > tests/join-population/merged-folder.mbtiles.json.check
cmp tests/join-population/no-macarthur.mbtiles.json.check tests/join-population/no-macarthur.mbtiles.json
./tile-join --no-tile-compression -f -e tests/join-population/raw-merged-folder tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
diff -x '*.DS_Store' -rq tests/join-population/raw-merged-folder tests/join-population/raw-merged-folder-compare
./tippecanoe -z12 -f -e tests/join-population/tabblock_06001420-folder tests/join-population/tabblock_06001420.json
./tippecanoe -Z5 -z10 -f -e tests/join-population/macarthur-folder -l macarthur tests/join-population/macarthur.json
./tippecanoe -d10 -D10 -Z9 -z11 -f -e tests/join-population/macarthur2-folder -l macarthur tests/join-population/macarthur2.json
./tile-join -f -o tests/join-population/merged-folder.mbtiles tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder
./tippecanoe-decode tests/join-population/merged-folder.mbtiles > tests/join-population/merged-folder.mbtiles.json.check
cmp tests/join-population/merged-folder.mbtiles.json.check tests/join-population/merged-folder.mbtiles.json
./tile-join -q -n "merged name" -N "merged description" -f -e tests/join-population/merged-mbtiles-to-folder tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tile-join -q -n "merged name" -N "merged description" -f -e tests/join-population/merged-folders-to-folder tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder
./tippecanoe-decode -x generator -x generator_options tests/join-population/merged-mbtiles-to-folder > tests/join-population/merged-mbtiles-to-folder.json.check
./tippecanoe-decode -x generator -x generator_options tests/join-population/merged-folders-to-folder > tests/join-population/merged-folders-to-folder.json.check
cmp tests/join-population/merged-mbtiles-to-folder.json.check tests/join-population/merged-folders-to-folder.json.check
rm -f tests/join-population/merged-mbtiles-to-folder.json.check tests/join-population/merged-folders-to-folder.json.check
./tile-join -q -f -c tests/join-population/windows.csv -o tests/join-population/windows-merged.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -q -c tests/join-population/windows.csv -f -e tests/join-population/windows-merged-folder tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -q -f -o tests/join-population/windows-merged2.mbtiles tests/join-population/windows-merged-folder
./tippecanoe-decode -x generator -x generator_options tests/join-population/windows-merged.mbtiles > tests/join-population/windows-merged.mbtiles.json.check
./tippecanoe-decode -x generator -x generator_options tests/join-population/windows-merged2.mbtiles > tests/join-population/windows-merged2.mbtiles.json.check
./tile-join -n "merged name" -N "merged description" -f -e tests/join-population/merged-mbtiles-to-folder tests/join-population/tabblock_06001420.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tile-join -n "merged name" -N "merged description" -f -e tests/join-population/merged-folders-to-folder tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder
diff -x '*.DS_Store' -rq tests/join-population/merged-mbtiles-to-folder tests/join-population/merged-folders-to-folder
./tile-join -f -c tests/join-population/windows.csv -o tests/join-population/windows-merged.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -c tests/join-population/windows.csv -f -e tests/join-population/windows-merged-folder tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -f -o tests/join-population/windows-merged2.mbtiles tests/join-population/windows-merged-folder
./tippecanoe-decode tests/join-population/windows-merged.mbtiles > tests/join-population/windows-merged.mbtiles.json.check
./tippecanoe-decode tests/join-population/windows-merged2.mbtiles > tests/join-population/windows-merged2.mbtiles.json.check
cmp tests/join-population/windows-merged.mbtiles.json.check tests/join-population/windows-merged2.mbtiles.json.check
./tile-join -q -f -o tests/join-population/macarthur-and-macarthur2-merged.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -q -f -e tests/join-population/macarthur-and-macarthur2-folder tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -q -f -o tests/join-population/macarthur-and-macarthur2-merged2.mbtiles tests/join-population/macarthur-and-macarthur2-folder
./tippecanoe-decode -x generator -x generator_options tests/join-population/macarthur-and-macarthur2-merged.mbtiles > tests/join-population/macarthur-and-macarthur2-merged.mbtiles.json.check
./tippecanoe-decode -x generator -x generator_options tests/join-population/macarthur-and-macarthur2-merged2.mbtiles > tests/join-population/macarthur-and-macarthur2-merged2.mbtiles.json.check
./tile-join -f -o tests/join-population/macarthur-and-macarthur2-merged.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -f -e tests/join-population/macarthur-and-macarthur2-folder tests/join-population/macarthur.mbtiles tests/join-population/macarthur2-folder
./tile-join -f -o tests/join-population/macarthur-and-macarthur2-merged2.mbtiles tests/join-population/macarthur-and-macarthur2-folder
./tippecanoe-decode tests/join-population/macarthur-and-macarthur2-merged.mbtiles > tests/join-population/macarthur-and-macarthur2-merged.mbtiles.json.check
./tippecanoe-decode tests/join-population/macarthur-and-macarthur2-merged2.mbtiles > tests/join-population/macarthur-and-macarthur2-merged2.mbtiles.json.check
cmp tests/join-population/macarthur-and-macarthur2-merged.mbtiles.json.check tests/join-population/macarthur-and-macarthur2-merged2.mbtiles.json.check
rm tests/join-population/tabblock_06001420.mbtiles tests/join-population/joined.mbtiles tests/join-population/joined-i.mbtiles tests/join-population/joined.mbtiles.json.check tests/join-population/joined-i.mbtiles.json.check tests/join-population/macarthur.mbtiles tests/join-population/merged.mbtiles tests/join-population/merged.mbtiles.json.check tests/join-population/merged-folder.mbtiles tests/join-population/macarthur2.mbtiles tests/join-population/windows.mbtiles tests/join-population/windows-merged.mbtiles tests/join-population/windows-merged2.mbtiles tests/join-population/windows.mbtiles.json.check tests/join-population/just-macarthur.mbtiles tests/join-population/no-macarthur.mbtiles tests/join-population/just-macarthur.mbtiles.json.check tests/join-population/no-macarthur.mbtiles.json.check tests/join-population/merged-folder.mbtiles.json.check tests/join-population/windows-merged.mbtiles.json.check tests/join-population/windows-merged2.mbtiles.json.check tests/join-population/macarthur-and-macarthur2-merged.mbtiles tests/join-population/macarthur-and-macarthur2-merged2.mbtiles tests/join-population/macarthur-and-macarthur2-merged.mbtiles.json.check tests/join-population/macarthur-and-macarthur2-merged2.mbtiles.json.check
rm -rf tests/join-population/raw-merged-folder tests/join-population/tabblock_06001420-folder tests/join-population/macarthur-folder tests/join-population/macarthur2-folder tests/join-population/merged-mbtiles-to-folder tests/join-population/merged-folders-to-folder tests/join-population/windows-merged-folder tests/join-population/macarthur-and-macarthur2-folder
# Test renaming of layers
./tippecanoe -q -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur1 tests/join-population/macarthur.json
./tippecanoe -q -f -Z5 -z10 -o tests/join-population/macarthur2.mbtiles -l macarthur2 tests/join-population/macarthur2.json
./tile-join -q -R macarthur1:one --rename-layer=macarthur2:two -f -o tests/join-population/renamed.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tippecanoe-decode -x generator tests/join-population/renamed.mbtiles > tests/join-population/renamed.mbtiles.json.check
./tippecanoe -f -Z5 -z10 -o tests/join-population/macarthur.mbtiles -l macarthur1 tests/join-population/macarthur.json
./tippecanoe -f -Z5 -z10 -o tests/join-population/macarthur2.mbtiles -l macarthur2 tests/join-population/macarthur2.json
./tile-join -R macarthur1:one --rename-layer=macarthur2:two -f -o tests/join-population/renamed.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
./tippecanoe-decode tests/join-population/renamed.mbtiles > tests/join-population/renamed.mbtiles.json.check
cmp tests/join-population/renamed.mbtiles.json.check tests/join-population/renamed.mbtiles.json
rm -f tests/join-population/renamed.mbtiles.json.check tests/join-population/renamed.mbtiles.json.check tests/join-population/macarthur.mbtiles tests/join-population/macarthur2.mbtiles
# Make sure the concatenated name isn't too long
./tippecanoe -q -f -z0 -n 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json
./tile-join -f -o tests/join-population/concat.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles
./tippecanoe-decode -x generator tests/join-population/concat.mbtiles > tests/join-population/concat.mbtiles.json.check
cmp tests/join-population/concat.mbtiles.json.check tests/join-population/concat.mbtiles.json
rm tests/join-population/concat.mbtiles.json.check tests/join-population/concat.mbtiles tests/join-population/macarthur.mbtiles
join-filter-test:
# Comes out different from the direct tippecanoe run because null attributes are lost
./tippecanoe -q -z0 -f -o tests/feature-filter/out/all.mbtiles tests/feature-filter/in.json
./tile-join -q -J tests/feature-filter/filter -f -o tests/feature-filter/out/filtered.mbtiles tests/feature-filter/out/all.mbtiles
./tippecanoe-decode -x generator tests/feature-filter/out/filtered.mbtiles > tests/feature-filter/out/filtered.json.check
./tippecanoe -z0 -f -o tests/feature-filter/out/all.mbtiles tests/feature-filter/in.json
./tile-join -J tests/feature-filter/filter -f -o tests/feature-filter/out/filtered.mbtiles tests/feature-filter/out/all.mbtiles
./tippecanoe-decode tests/feature-filter/out/filtered.mbtiles > tests/feature-filter/out/filtered.json.check
cmp tests/feature-filter/out/filtered.json.check tests/feature-filter/out/filtered.json.standard
rm -f tests/feature-filter/out/filtered.json.check tests/feature-filter/out/filtered.mbtiles tests/feature-filter/out/all.mbtiles
# Test zoom level filtering
./tippecanoe -q -r1 -z8 -f -o tests/feature-filter/out/places.mbtiles tests/ne_110m_populated_places/in.json
./tile-join -q -J tests/feature-filter/places-filter -f -o tests/feature-filter/out/places-filter.mbtiles tests/feature-filter/out/places.mbtiles
./tippecanoe-decode -x generator tests/feature-filter/out/places-filter.mbtiles > tests/feature-filter/out/places-filter.mbtiles.json.check
cmp tests/feature-filter/out/places-filter.mbtiles.json.check tests/feature-filter/out/places-filter.mbtiles.json.standard
rm -f tests/feature-filter/out/places.mbtiles tests/feature-filter/out/places-filter.mbtiles tests/feature-filter/out/places-filter.mbtiles.json.check
json-tool-test: tippecanoe-json-tool
./tippecanoe-json-tool -e GEOID10 tests/join-population/tabblock_06001420.json | sort > tests/join-population/tabblock_06001420.json.sort
./tippecanoe-json-tool -c tests/join-population/population.csv tests/join-population/tabblock_06001420.json.sort > tests/join-population/tabblock_06001420.json.sort.joined
./tippecanoe-json-tool --empty-csv-columns-are-null -c tests/join-population/population.csv tests/join-population/tabblock_06001420.json.sort > tests/join-population/tabblock_06001420-null.json.sort.joined
cmp tests/join-population/tabblock_06001420.json.sort.joined tests/join-population/tabblock_06001420.json.sort.joined.standard
cmp tests/join-population/tabblock_06001420-null.json.sort.joined tests/join-population/tabblock_06001420-null.json.sort.joined.standard
rm -f tests/join-population/tabblock_06001420.json.sort tests/join-population/tabblock_06001420.json.sort.joined
rm -f tests/join-population/tabblock_06001420-null.json.sort.joined
allow-existing-test:
# Make a tileset
./tippecanoe -q -Z0 -z0 -f -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -Z0 -z0 -f -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
# Writing to existing should fail
if ./tippecanoe -q -Z1 -z1 -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json; then exit 1; else exit 0; fi
if ./tippecanoe -Z1 -z1 -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json; then exit 1; else exit 0; fi
# Replace existing
./tippecanoe -q -Z8 -z9 -f -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -q -Z10 -z11 -F -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe-decode -x generator -x generator_options tests/allow-existing/both.mbtiles > tests/allow-existing/both.mbtiles.json.check
./tippecanoe -Z8 -z9 -f -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -Z10 -z11 -F -o tests/allow-existing/both.mbtiles tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe-decode tests/allow-existing/both.mbtiles > tests/allow-existing/both.mbtiles.json.check
cmp tests/allow-existing/both.mbtiles.json.check tests/allow-existing/both.mbtiles.json
# Make a tileset
./tippecanoe -q -Z0 -z0 -f -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -Z0 -z0 -f -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
# Writing to existing should fail
if ./tippecanoe -q -Z1 -z1 -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json; then exit 1; else exit 0; fi
if ./tippecanoe -Z1 -z1 -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json; then exit 1; else exit 0; fi
# Replace existing
./tippecanoe -q -Z8 -z9 -f -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -q -Z10 -z11 -F -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe-decode -x generator -x generator_options tests/allow-existing/both.dir | sed 's/both\.dir/both.mbtiles/g' > tests/allow-existing/both.dir.json.check
./tippecanoe -Z8 -z9 -f -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe -Z10 -z11 -F -e tests/allow-existing/both.dir tests/coalesce-tract/tl_2010_06001_tract10.json
./tippecanoe-decode tests/allow-existing/both.dir | sed 's/both\.dir/both.mbtiles/g' > tests/allow-existing/both.dir.json.check
cmp tests/allow-existing/both.dir.json.check tests/allow-existing/both.mbtiles.json
rm -r tests/allow-existing/both.dir.json.check tests/allow-existing/both.dir tests/allow-existing/both.mbtiles.json.check tests/allow-existing/both.mbtiles
csv-test:
# Reading from named CSV
./tippecanoe -q -zg -f -o tests/csv/out.mbtiles tests/csv/ne_110m_populated_places_simple.csv
./tippecanoe-decode -x generator -x generator_options tests/csv/out.mbtiles > tests/csv/out.mbtiles.json.check
./tippecanoe -zg -f -o tests/csv/out.mbtiles tests/csv/ne_110m_populated_places_simple.csv
./tippecanoe-decode tests/csv/out.mbtiles > tests/csv/out.mbtiles.json.check
cmp tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles.json
rm -f tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles
# Reading from named CSV, with nulls
./tippecanoe -q --empty-csv-columns-are-null -zg -f -o tests/csv/out-null.mbtiles tests/csv/ne_110m_populated_places_simple.csv
./tippecanoe-decode -x generator tests/csv/out-null.mbtiles > tests/csv/out-null.mbtiles.json.check
cmp tests/csv/out-null.mbtiles.json.check tests/csv/out-null.mbtiles.json
rm -f tests/csv/out-null.mbtiles.json.check tests/csv/out-null.mbtiles
# Same, but specifying csv with -L format
./tippecanoe -q -zg -f -o tests/csv/out.mbtiles -L'{"file":"", "format":"csv", "layer":"ne_110m_populated_places_simple"}' < tests/csv/ne_110m_populated_places_simple.csv
./tippecanoe-decode -x generator -x generator_options tests/csv/out.mbtiles > tests/csv/out.mbtiles.json.check
cmp tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles.json
rm -f tests/csv/out.mbtiles.json.check tests/csv/out.mbtiles
layer-json-test:
# GeoJSON with description and named layer
./tippecanoe -q -z0 -r1 -yNAME -f -o tests/layer-json/out.mbtiles -L'{"file":"tests/ne_110m_populated_places/in.json", "description":"World cities", "layer":"places"}'
./tippecanoe-decode -x generator -x generator_options tests/layer-json/out.mbtiles > tests/layer-json/out.mbtiles.json.check
cmp tests/layer-json/out.mbtiles.json.check tests/layer-json/out.mbtiles.json
rm -f tests/layer-json/out.mbtiles.json.check tests/layer-json/out.mbtiles
# Same, but reading from the standard input
./tippecanoe -q -z0 -r1 -yNAME -f -o tests/layer-json/out.mbtiles -L'{"file":"", "description":"World cities", "layer":"places"}' < tests/ne_110m_populated_places/in.json
./tippecanoe-decode -x generator -x generator_options tests/layer-json/out.mbtiles > tests/layer-json/out.mbtiles.json.check
cmp tests/layer-json/out.mbtiles.json.check tests/layer-json/out.mbtiles.json
rm -f tests/layer-json/out.mbtiles.json.check tests/layer-json/out.mbtiles
# Use this target to regenerate the standards that the tests are compared against
# after making a change that legitimately changes their output
@ -342,7 +272,7 @@ layer-json-test:
prep-test: $(TESTS)
tests/%.json: Makefile tippecanoe tippecanoe-decode
./tippecanoe -q -a@ -f -o $@.check.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json,%,$(word 4,$(subst /, ,$@)))))) $(foreach suffix,$(suffixes),$(sort $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.$(suffix))))
./tippecanoe-decode -x generator $@.check.mbtiles > $@
./tippecanoe -f -o $@.check.mbtiles $(subst @,:,$(subst %,/,$(subst _, ,$(patsubst %.json,%,$(word 4,$(subst /, ,$@)))))) $(wildcard $(subst $(SPACE),/,$(wordlist 1,2,$(subst /, ,$@)))/*.json)
./tippecanoe-decode $@.check.mbtiles > $@
cmp $(patsubst %.check,%,$@) $@
rm $@.check.mbtiles

333
README.md
View File

@ -1,30 +1,11 @@
tippecanoe
==========
**Note**: there is an active fork of this project over at https://github.com/felt/tippecanoe
Builds [vector tilesets](https://www.mapbox.com/developers/vector-tiles/) from large (or small) collections of [GeoJSON](http://geojson.org/), [Geobuf](https://github.com/mapbox/geobuf), or [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) features,
[like these](MADE_WITH.md).
![Mapbox Tippecanoe](https://user-images.githubusercontent.com/1951835/36568734-ede27ec0-17df-11e8-8c22-ffaaebb8daf4.JPG)
[![Build Status](https://travis-ci.org/mapbox/tippecanoe.svg)](https://travis-ci.org/mapbox/tippecanoe)
[![Coverage Status](https://codecov.io/gh/mapbox/tippecanoe/branch/master/graph/badge.svg)](https://codecov.io/gh/mapbox/tippecanoe)
### :zap: Mapbox has a new service for creating vector tilesets! :zap:
[Mapbox Tiling Service (MTS)](https://docs.mapbox.com/mapbox-tiling-service/overview/) is a hosted, data processing service that allows you to integrate custom datasets of any scale into your maps faster, cheaper, and with more flexibility and control than previously possible.
MTS is the same service we use internally to create our global, daily updating basemap product Mapbox Streets, which serves over 650 million monthly active users and customers such as Facebook, Snap, the Weather Channel, Tableau, and Shopify.
MTS creates and updates data using distributed and parallelized processing, meaning data is processed much more quickly than is possible with a standard, single server setup with comparable tools. For example, a global basemap at 30cm precision (max zoom of 16) can be processed in under 2 hours with MTS, whereas a comparable workload would take multiple days to process on a single server.
Customers like AllTrails, Plume Labs, and Ookla have noted that MTS helps them:
- build applications faster by focusing more on app development, not infrastructure
- build more compelling user experiences that drive better user engagement
- get updated data to their users faster—in some cases up to 90% faster than previous tools
Learn more about [MTS](https://blog.mapbox.com/introducing-mapbox-tiling-service-df1df636c7cf).
[![Coverage Status](https://coveralls.io/repos/mapbox/tippecanoe/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapbox/tippecanoe?branch=master)
Intent
------
@ -52,28 +33,15 @@ Installation
The easiest way to install tippecanoe on OSX is with [Homebrew](http://brew.sh/):
```sh
```js
$ brew install tippecanoe
```
On Ubuntu it will usually be easiest to build from the source repository:
```sh
$ git clone https://github.com/mapbox/tippecanoe.git
$ cd tippecanoe
$ make -j
$ make install
```
See [Development](#development) below for how to upgrade your
C++ compiler or install prerequisite packages if you get
compiler errors.
Usage
-----
```sh
$ tippecanoe -o file.mbtiles [options] [file.json file.json.gz file.geobuf ...]
$ tippecanoe -o file.mbtiles [options] [file.json file.geobuf ...]
```
If no files are specified, it reads GeoJSON from the standard input.
@ -90,7 +58,7 @@ Try this first
If you aren't sure what options to use, try this:
```sh
$ tippecanoe -zg -o out.mbtiles --drop-densest-as-needed in.geojson
$ tippecanoe -o out.mbtiles -zg --drop-densest-as-needed in.geojson
```
The `-zg` option will make Tippecanoe choose a maximum zoom level that should be
@ -118,170 +86,6 @@ with a custom layer name and description, and leaving out the `LINEARID` and `RT
$ cat tiger/tl_2014_*_roads.json | tippecanoe -o tiger.mbtiles -l roads -n "All TIGER roads, one zoom" -z12 -Z12 -d14 -x LINEARID -x RTTYP
```
Cookbook
--------
### Linear features (world railroads), visible at all zoom levels
```
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_railroads.zip
unzip ne_10m_railroads.zip
ogr2ogr -f GeoJSON ne_10m_railroads.geojson ne_10m_railroads.shp
tippecanoe -zg -o ne_10m_railroads.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping ne_10m_railroads.geojson
```
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--drop-densest-as-needed`: If the tiles are too big at low zoom levels, drop the least-visible features to allow tiles to be created with those features that remain
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Discontinuous polygon features (buildings of Rhode Island), visible at all zoom levels
```
curl -L -O https://usbuildingdata.blob.core.windows.net/usbuildings-v1-1/RhodeIsland.zip
unzip RhodeIsland.zip
tippecanoe -zg -o RhodeIsland.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping RhodeIsland.geojson
```
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--drop-densest-as-needed`: If the tiles are too big at low or medium zoom levels, drop the least-visible features to allow tiles to be created with those features that remain
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Continuous polygon features (states and provinces), visible at all zoom levels
```
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip -o ne_10m_admin_1_states_provinces.zip
ogr2ogr -f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe -zg -o ne_10m_admin_1_states_provinces.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping ne_10m_admin_1_states_provinces.geojson
```
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--coalesce-densest-as-needed`: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Large point dataset (GPS bus locations), for visualization at all zoom levels
```
curl -L -O ftp://avl-data.sfmta.com/avl_data/avl_raw/sfmtaAVLRawData01012013.csv
sed 's/PREDICTABLE.*/PREDICTABLE/' sfmtaAVLRawData01012013.csv > sfmta.csv
tippecanoe -zg -o sfmta.mbtiles --drop-densest-as-needed --extend-zooms-if-still-dropping sfmta.csv
```
(The `sed` line is to clean the corrupt CSV header, which contains the wrong number of fields.)
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--drop-densest-as-needed`: If the tiles are too big at low or medium zoom levels, drop the least-visible features to allow tiles to be created with those features that remain
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Clustered points (world cities), summing the clustered population, visible at all zoom levels
```
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip
unzip -o ne_10m_populated_places.zip
ogr2ogr -f GeoJSON ne_10m_populated_places.geojson ne_10m_populated_places.shp
tippecanoe -zg -o ne_10m_populated_places.mbtiles -r1 --cluster-distance=10 --accumulate-attribute=POP_MAX:sum ne_10m_populated_places.geojson
```
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `-r1`: Do not automatically drop a fraction of points at low zoom levels, since clustering will be used instead
* `--cluster-distance=10`: Cluster together features that are closer than about 10 pixels from each other
* `--accumulate-attribute=POP_MAX:sum`: Sum the `POP_MAX` (population) attribute in features that are clustered together. Other attributes will be arbitrarily taken from the first feature in the cluster.
### Show countries at low zoom levels but states at higher zoom levels
```
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
unzip ne_10m_admin_0_countries.zip
ogr2ogr -f GeoJSON ne_10m_admin_0_countries.geojson ne_10m_admin_0_countries.shp
curl -L -O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip -o ne_10m_admin_1_states_provinces.zip
ogr2ogr -f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe -z3 -o countries-z3.mbtiles --coalesce-densest-as-needed ne_10m_admin_0_countries.geojson
tippecanoe -zg -Z4 -o states-Z4.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping ne_10m_admin_1_states_provinces.geojson
tile-join -o states-countries.mbtiles countries-z3.mbtiles states-Z4.mbtiles
```
Countries:
* `-z3`: Only generate zoom levels 0 through 3
* `--coalesce-densest-as-needed`: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
States and Provinces:
* `-Z4`: Only generate zoom levels 4 and beyond
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--coalesce-densest-as-needed`: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Represent multiple sources (Illinois and Indiana counties) as separate layers
```
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr -f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr -f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe -zg -o counties-separate.mbtiles --coalesce-densest-as-needed --extend-zooms-if-still-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
```
* `-zg`: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
* `--coalesce-densest-as-needed`: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
* `--extend-zooms-if-still-dropping`: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
### Merge multiple sources (Illinois and Indiana counties) into the same layer
```
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr -f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr -f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe -zg -o counties-merged.mbtiles -l counties --coalesce-densest-as-needed --extend-zooms-if-still-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
```
As above, but
* `-l counties`: Specify the layer name instead of letting it be derived from the source file names
### Selectively remove and replace features (Census tracts) to update a tileset
```
# Retrieve and tile California 2000 Census tracts
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2000/tl_2010_06_tract00.zip
unzip tl_2010_06_tract00.zip
ogr2ogr -f GeoJSON tl_2010_06_tract00.shp.json tl_2010_06_tract00.shp
tippecanoe -z11 -o tracts.mbtiles -l tracts tl_2010_06_tract00.shp.json
# Create a copy of the tileset, minus Alameda County (FIPS code 001)
tile-join -j '{"*":["none",["==","COUNTYFP00","001"]]}' -f -o tracts-filtered.mbtiles tracts.mbtiles
# Retrieve and tile Alameda County Census tracts for 2010
curl -L -O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2010/tl_2010_06001_tract10.zip
unzip tl_2010_06001_tract10.zip
ogr2ogr -f GeoJSON tl_2010_06001_tract10.shp.json tl_2010_06001_tract10.shp
tippecanoe -z11 -o tracts-added.mbtiles -l tracts tl_2010_06001_tract10.shp.json
# Merge the filtered tileset and the tileset of new tracts into a final tileset
tile-join -o tracts-final.mbtiles tracts-filtered.mbtiles tracts-added.mbtiles
```
The `-z11` option explicitly specifies the maxzoom, to make sure both the old and new tilesets have the same zoom range.
The `-j` option to `tile-join` specifies a filter, so that only the desired features will be copied to the new tileset.
This filter excludes (using `none`) any features whose FIPS code (`COUNTYFP00`) is the code for Alameda County (`001`).
Options
-------
@ -323,17 +127,11 @@ If your input is formatted as newline-delimited GeoJSON, use `-P` to make input
### Input files and layer names
* _name_`.json` or _name_`.geojson`: Read the named GeoJSON input file into a layer called _name_.
* _name_`.json.gz` or _name_`.geojson.gz`: Read the named gzipped GeoJSON input file into a layer called _name_.
* _name_`.geobuf`: Read the named Geobuf input file into a layer called _name_.
* _name_`.csv`: Read the named CSV input file into a layer called _name_.
* `-l` _name_ or `--layer=`_name_: Use the specified layer name instead of deriving a name from the input filename or output tileset. If there are multiple input files
specified, the files are all merged into the single named layer, even if they try to specify individual names with `-L`.
* `-L` _name_`:`_file.json_ or `--named-layer=`_name_`:`_file.json_: Specify layer names for individual files. If your shell supports it, you can use a subshell redirect like `-L` _name_`:<(cat dir/*.json)` to specify a layer name for the output of streamed input.
* `-L{`_layer-json_`}` or `--named-layer={`_layer-json_`}`: Specify an input file and layer options by a JSON object. The JSON object must contain a `"file"` key to specify the filename to read from. (If the `"file"` key is an empty string, it means to read from the standard input stream.) It may also contain a `"layer"` field to specify the name of the layer, and/or a `"description"` field to specify the layer's description in the tileset metadata, and/or a `"format"` field to specify `csv` or `geobuf` file format if it is not obvious from the `name`. Example:
```
tippecanoe -z5 -o world.mbtiles -L'{"file":"ne_10m_admin_0_countries.json", "layer":"countries", "description":"Natural Earth countries"}'
```
CSV input files currently support only Point geometries, from columns named `latitude`, `longitude`, `lat`, `lon`, `long`, `lng`, `x`, or `y`.
@ -364,39 +162,6 @@ Parallel processing will also be automatic if the input file is in Geobuf format
* `-ae` or `--extend-zooms-if-still-dropping`: Increase the maxzoom if features are still being dropped at that zoom level.
The detail and simplification options that ordinarily apply only to the maximum zoom level will apply both to the originally
specified maximum zoom and to any levels added beyond that.
* `-R` _zoom_`/`_x_`/`_y_ or `--one-tile=`_zoom_`/`_x_`/`_y_: Set the minzoom and maxzoom to _zoom_ and produce only
the single specified tile at that zoom level.
If you know the precision to which you want your data to be represented,
or the map scale of a corresponding printed map,
this table shows the approximate precision and scale corresponding to various
`-z` options if you use the default `-d` detail of 12:
zoom level | precision (ft) | precision (m) | map scale
---------- | -------------- | ------------- | ---------
`-z0` | 32000 ft | 10000 m | 1:320,000,000
`-z1` | 16000 ft | 5000 m | 1:160,000,000
`-z2` | 8000 ft | 2500 m | 1:80,000,000
`-z3` | 4000 ft | 1250 m | 1:40,000,000
`-z4` | 2000 ft | 600 m | 1:20,000,000
`-z5` | 1000 ft | 300 m | 1:10,000,000
`-z6` | 500 ft | 150 m | 1:5,000,000
`-z7` | 250 ft | 80 m | 1:2,500,000
`-z8` | 125 ft | 40 m | 1:1,250,000
`-z9` | 64 ft | 20 m | 1:640,000
`-z10` | 32 ft | 10 m | 1:320,000
`-z11` | 16 ft | 5 m | 1:160,000
`-z12` | 8 ft | 2 m | 1:80,000
`-z13` | 4 ft | 1 m | 1:40,000
`-z14` | 2 ft | 0.5 m | 1:20,000
`-z15` | 1 ft | 0.25 m | 1:10,000
`-z16` | 6 in | 15 cm | 1:5000
`-z17` | 3 in | 8 cm | 1:2500
`-z18` | 1.5 in | 4 cm | 1:1250
`-z19` | 0.8 in | 2 cm | 1:600
`-z20` | 0.4 in | 1 cm | 1:300
`-z21` | 0.2 in | 0.5 cm | 1:150
`-z22` | 0.1 in | 0.25 cm | 1:75
### Tile resolution
@ -410,29 +175,15 @@ resolution is obtained than by using a smaller _maxzoom_ or _detail_.
### Filtering feature attributes
* `-x` _name_ or `--exclude=`_name_: Exclude the named attributes from all features. You can specify multiple `-x` options to exclude several attributes. (Don't comma-separate names within a single `-x`.)
* `-y` _name_ or `--include=`_name_: Include the named attributes in all features, excluding all those not explicitly named. You can specify multiple `-y` options to explicitly include several attributes. (Don't comma-separate names within a single `-y`.)
* `-X` or `--exclude-all`: Exclude all attributes and encode only geometries
### Modifying feature attributes
* `-x` _name_ or `--exclude=`_name_: Exclude the named properties from all features
* `-y` _name_ or `--include=`_name_: Include the named properties in all features, excluding all those not explicitly named
* `-X` or `--exclude-all`: Exclude all properties and encode only geometries
* `-T`_attribute_`:`_type_ or `--attribute-type=`_attribute_`:`_type_: Coerce the named feature _attribute_ to be of the specified _type_.
The _type_ may be `string`, `float`, `int`, or `bool`.
If the type is `bool`, then original attributes of `0` (or, if numeric, `0.0`, etc.), `false`, `null`, or the empty string become `false`, and otherwise become `true`.
If the type is `float` or `int` and the original attribute was non-numeric, it becomes `0`.
If the type is `int` and the original attribute was floating-point, it is rounded to the nearest integer.
* `-Y`_attribute_`:`_description_ or `--attribute-description=`_attribute_`:`_description_: Set the `description` for the specified attribute in the tileset metadata to _description_ instead of the usual `String`, `Number`, or `Boolean`.
* `-E`_attribute_`:`_operation_ or `--accumulate-attribute=`_attribute_`:`_operation_: Preserve the named _attribute_ from features
that are dropped, coalesced-as-needed, or clustered. The _operation_ may be
`sum`, `product`, `mean`, `max`, `min`, `concat`, or `comma`
to specify how the named _attribute_ is accumulated onto the attribute of the same name in a feature that does survive.
* `-pe` or `--empty-csv-columns-are-null`: Treat empty CSV columns as nulls rather than as empty strings.
* `-aI` or `--convert-stringified-ids-to-numbers`: If a feature ID is the string representation of a number, convert it to a plain number to use as the feature ID.
* `--use-attribute-for-id=`*name*: Use the attribute with the specified *name* as if it were specified as the feature ID. (If this attribute is a stringified number, you must also use `-aI` to convert it to a number.)
### Filtering features by attributes
* `-j` *filter* or `--feature-filter`=*filter*: Check features against a per-layer filter (as defined in the [Mapbox GL Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/#other-filter)) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer `"*"` apply to all layers. The special variable `$zoom` refers to the current zoom level.
* `-j` *filter* or `--feature-filter`=*filter*: Check features against a per-layer filter (as defined in the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-filter)) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer `"*"` apply to all layers.
* `-J` *filter-file* or `--feature-filter-file`=*filter-file*: Like `-j`, but read the filter from a file.
Example: to find the Natural Earth countries with low `scalerank` but high `LABELRANK`:
@ -441,23 +192,6 @@ Example: to find the Natural Earth countries with low `scalerank` but high `LABE
tippecanoe -z5 -o filtered.mbtiles -j '{ "ne_10m_admin_0_countries": [ "all", [ "<", "scalerank", 3 ], [ ">", "LABELRANK", 5 ] ] }' ne_10m_admin_0_countries.geojson
```
Example: to retain only major TIGER roads at low zoom levels:
```
tippecanoe -o roads.mbtiles -j '{ "*": [ "any", [ ">=", "$zoom", 11 ], [ "in", "MTFCC", "S1100", "S1200" ] ] }' tl_2015_06001_roads.json
```
Tippecanoe also accepts expressions of the form `[ "attribute-filter", name, expression ]`, to filter individual feature attributes
instead of entire features. For example, you can exclude the road names at low zoom levels by doing
```
tippecanoe -o roads.mbtiles -j '{ "*": [ "attribute-filter", "FULLNAME", [ ">=", "$zoom", 9 ] ] }' tl_2015_06001_roads.json
```
An `attribute-filter` expression itself is always considered to evaluate to `true` (in other words, to retain the feature instead
of dropping it). If you want to use multiple `attribute-filter` expressions, or to use other expressions to remove features from
the same layer, enclose them in an `all` expression so they will all be evaluated.
### Dropping a fixed fraction of features by zoom level
* `-r` _rate_ or `--drop-rate=`_rate_: Rate at which dots are dropped at zoom levels below basezoom (default 2.5).
@ -470,18 +204,16 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
compensate for the larger marker, or `-Bf`*number* to allow at most *number* features in the densest tile.
* `-al` or `--drop-lines`: Let "dot" dropping at lower zooms apply to lines too
* `-ap` or `--drop-polygons`: Let "dot" dropping at lower zooms apply to polygons too
* `-K` _distance_ or `--cluster-distance=`_distance_: Cluster points (as with `--cluster-densest-as-needed`, but without the experimental discovery process) that are approximately within _distance_ of each other. The units are tile coordinates within a nominally 256-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 10 are probably appropriate for typical marker sizes. See `--cluster-densest-as-needed` below for behavior.
* `-K` _distance_ or `--cluster-distance=`_distance_: Cluster points (as with `--cluster-densest-as-needed`, but without the experimental discovery process) that are approximately within _distance_ of each other. The units are tile coordinates within a nominally 256-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 20 are probably appropriate for typical marker sizes.
### Dropping a fraction of features to keep under tile size limits
* `-as` or `--drop-densest-as-needed`: If a tile is too large, try to reduce it to under 500K by increasing the minimum spacing between features. The discovered spacing applies to the entire zoom level.
* `-ad` or `--drop-fraction-as-needed`: Dynamically drop some fraction of features from each zoom level to keep large tiles under the 500K size limit. (This is like `-pd` but applies to the entire zoom level, not to each tile.)
* `-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.
* `-aN` or `--coalesce-smallest-as-needed`: Dynamically combine the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level into other nearby features to keep large tiles under the 500K size limit. This option will not work for point features, and will probably not help very much with LineStrings. It is mostly intended for polygons, to maintain the full original area covered by polygons while still reducing the feature count somehow. The attributes of the small polygons are *not* preserved into the combined features (except through `--accumulate-attribute`), only their geometry. Furthermore, the polygons to which nested polygons are coalesced may not necessarily be the immediately enclosing features.
* `-aD` or `--coalesce-densest-as-needed`: Dynamically combine the densest features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)
* `-aS` or `--coalesce-fraction-as-needed`: Dynamically combine a fraction of features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)
* `-aN` or `--coalesce-smallest-as-needed`: Dynamically combine the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level into other nearby features to keep large tiles under the 500K size limit. This option will not work for point features, and will probably not help very much with LineStrings. It is mostly intended for polygons, to maintain the full original area covered by polygons while still reducing the feature count somehow. The attributes of the small polygons are *not* preserved into the combined features, only their geometry.
* `-pd` or `--force-feature-limit`: Dynamically drop some fraction of features from large tiles to keep them under the 500K size limit. It will probably look ugly at the tile boundaries. (This is like `-ad` but applies to each tile individually, not to the entire zoom level.) You probably don't want to use this.
* `-aC` or `--cluster-densest-as-needed`: If a tile is too large, try to reduce its size by increasing the minimum spacing between features, and leaving one placeholder feature from each group. The remaining feature will be given a `"clustered": true` attribute to indicate that it represents a cluster, a `"point_count"` attribute to indicate the number of features that were clustered into it, and a `"sqrt_point_count"` attribute to indicate the relative width of a feature to represent the cluster. If the features being clustered are points, the representative feature will be located at the average of the original points' locations; otherwise, one of the original features will be left as the representative.
* `-aC` or `--cluster-densest-as-needed`: If a tile is too large, try to reduce its size by increasing the minimum spacing between features, and leaving one placeholder feature from each group. The remaining feature will be given a `"cluster": true` attribute to indicate that it represents a cluster and a `"point_count"` attribute to indicate the number of features that were clustered into it.
### Dropping tightly overlapping features
@ -494,7 +226,6 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
the line or polygon within one tile unit of its proper location. You can probably go up to about 10 without too much visible difference.
* `-ps` or `--no-line-simplification`: Don't simplify lines and polygons
* `-pS` or `--simplify-only-low-zooms`: Don't simplify lines and polygons at maxzoom (but do simplify at lower zooms)
* `-pn` or `--no-simplification-of-shared-nodes`: Don't simplify away nodes that appear in more than one feature or are used multiple times within the same feature, so that the intersection node will not be lost from intersecting roads. (This will not be effective if you also use `--coalesce` or `--detect-shared-borders`.)
* `-pt` or `--no-tiny-polygon-reduction`: Don't combine the area of very small polygons into small squares that represent their combined area.
### Attempts to improve shared polygon boundaries
@ -511,22 +242,17 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
### Reordering features within each tile
* `-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`).
* `-ac` or `--coalesce`: Coalesce consecutive features that have the same attributes. This can be useful if you have lots of small polygons with identical attributes and you would like to merge them together.
* `-ao` or `--reorder`: Reorder features to put ones with the same attributes in sequence (instead of ones that are approximately spatially adjacent), to try to get them to coalesce. You probably want to use this if you use `--coalesce`.
* `-ao` or `--reorder`: Reorder features to put ones with the same properties in sequence, to try to get them to coalesce. You probably want to use this if you use `--coalesce`.
* `-ac` or `--coalesce`: Coalesce adjacent line and polygon features that have the same properties. This can be useful if you have lots of small polygons with identical attributes and you would like to merge them together.
* `-ar` or `--reverse`: Try reversing the directions of lines to make them coalesce and compress better. You probably don't want to use this.
* `-ah` or `--hilbert`: Put features in Hilbert Curve order instead of the usual Z-Order. This improves the odds that spatially adjacent features will be sequentially adjacent, and should improve density calculations and spatial coalescing. It should be the default eventually.
### Adding calculated attributes
* `-ag` or `--calculate-feature-density`: Add a new attribute, `tippecanoe_feature_density`, to each feature, to record how densely features are spaced in that area of the tile. You can use this attribute in the style to produce a glowing effect where points are densely packed. It can range from 0 in the sparsest areas to 255 in the densest.
* `-ai` or `--generate-ids`: Add an `id` (a feature ID, not an attribute named `id`) to each feature that does not already have one. There is currently no guarantee that the `id` added will be stable between runs or that it will not conflict with manually-assigned feature IDs. Future versions of Tippecanoe may change the mechanism for allocating IDs.
### Trying to correct bad source geometry
* `-aw` or `--detect-longitude-wraparound`: Detect when consecutive points within a feature jump to the other side of the world, and try to fix the geometry.
* `-pw` or `--use-source-polygon-winding`: Instead of respecting GeoJSON polygon ring order, use the original polygon winding in the source data to distinguish inner (clockwise) and outer (counterclockwise) polygon rings.
* `-pW` or `--reverse-source-polygon-winding`: Instead of respecting GeoJSON polygon ring order, use the opposite of the original polygon winding in the source data to distinguish inner (counterclockwise) and outer (clockwise) polygon rings.
* `--clip-bounding-box=`*minlon*`,`*minlat*`,`*maxlon*`,`*maxlat*: Clip all features to the specified bounding box.
* `-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.
### Setting or disabling tile size limits
@ -534,11 +260,8 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
* `-O` _features_ or `--maximum-tile-features=`_features_: Use the specified number of _features_ as the maximum in a tile instead of 200,000.
* `-pf` or `--no-feature-limit`: Don't limit tiles to 200,000 features
* `-pk` or `--no-tile-size-limit`: Don't limit tiles to 500K bytes
* `-pC` or `--no-tile-compression`: Don't compress the PBF vector tile data. If you are getting "Unimplemented type 3" error messages from a renderer, it is probably because it expects uncompressed tiles using this option rather than the normal gzip-compressed tiles.
* `-pC` or `--no-tile-compression`: Don't compress the PBF vector tile data.
* `-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.
* `--tile-stats-values-limit=`*count*: Report *count* unique attribute values in `tilestats` instead of the default 100.
### Temporary storage
@ -549,7 +272,6 @@ the same layer, enclose them in an `all` expression so they will all be evaluate
* `-q` or `--quiet`: Work quietly instead of reporting progress or warning messages
* `-Q` or `--no-progress-indicator`: Don't report progress, but still give warnings
* `-U` _seconds_ or `--progress-interval=`_seconds_: Don't report progress more often than the specified number of _seconds_.
* `-v` or `--version`: Report Tippecanoe's version number
### Filters
@ -571,7 +293,7 @@ The postfilter receives the features at tile resolution, after simplification, c
The layer name is provided as part of the `tippecanoe` element of the feature and must be passed through
to keep the feature in its correct layer. In the case of the prefilter, the `tippecanoe` element may also
contain `index`, `sequence`, `extent`, and `dropped`, elements, which must be passed through for internal operations like
contain `index`, `sequence`, and `extent` elements, which must be passed through for internal operations like
`--drop-densest-as-needed`, `--drop-smallest-as-needed`, and `--preserve-input-order` to work.
#### Examples:
@ -643,12 +365,6 @@ the filename or name specified using `--layer`, like this:
}
```
If your source GeoJSON only has `minzoom`, `maxzoom` and/or `layer` within `properties` you can use [ndjson-cli](https://github.com/mbostock/ndjson-cli/blob/master/README.md) to move them into the required `tippecanoe` object by piping the GeoJSON like this:
```sh
ndjson-map 'd.tippecanoe = { minzoom: d.properties.minzoom, maxzoom: d.properties.maxzoom, layer: d.properties.layer }, delete d.properties.minzoom, delete d.properties.maxzoom, delete d.properties.layer, d'
```
Geometric simplifications
-------------------------
@ -677,7 +393,7 @@ all of them should have had together.
Features in the same tile that share the same type and attributes are coalesced
together into a single geometry if you use `--coalesce`. You are strongly encouraged to use -x to exclude
any unnecessary attributes to reduce wasted file size.
any unnecessary properties to reduce wasted file size.
If a tile is larger than 500K, it will try encoding that tile at progressively
lower resolutions before failing if it still doesn't fit.
@ -786,11 +502,9 @@ The options are:
### Filtering features and feature attributes
* `-x` *key* or `--exclude=`*key*: Remove attributes of type *key* from the output. You can use this to remove the field you are matching against if you no longer need it after joining, or to remove any other attributes you don't want.
* `-X` or `--exclude-all`: Remove all attributes from the output.
* `-i` or `--if-matched`: Only include features that matched the CSV.
* `-j` *filter* or `--feature-filter`=*filter*: Check features against a per-layer filter (as defined in the [Mapbox GL Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/#other-filter)) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer `"*"` apply to all layers.
* `-j` *filter* or `--feature-filter`=*filter*: Check features against a per-layer filter (as defined in the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-filter)) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer `"*"` apply to all layers.
* `-J` *filter-file* or `--feature-filter-file`=*filter-file*: Like `-j`, but read the filter from a file.
* `-pe` or `--empty-csv-columns-are-null`: Treat empty CSV columns as nulls rather than as empty strings.
### Setting or disabling tile size limits
@ -809,7 +523,7 @@ Example
Imagine you have a tileset of census blocks:
```sh
curl -L -O http://www2.census.gov/geo/tiger/TIGER2010/TABBLOCK/2010/tl_2010_06001_tabblock10.zip
curl -O http://www2.census.gov/geo/tiger/TIGER2010/TABBLOCK/2010/tl_2010_06001_tabblock10.zip
unzip tl_2010_06001_tabblock10.zip
ogr2ogr -f GeoJSON tl_2010_06001_tabblock10.json tl_2010_06001_tabblock10.shp
./tippecanoe -o tl_2010_06001_tabblock10.mbtiles tl_2010_06001_tabblock10.json
@ -818,7 +532,7 @@ ogr2ogr -f GeoJSON tl_2010_06001_tabblock10.json tl_2010_06001_tabblock10.shp
and a CSV of their populations:
```sh
curl -L -O http://www2.census.gov/census_2010/01-Redistricting_File--PL_94-171/California/ca2010.pl.zip
curl -O http://www2.census.gov/census_2010/01-Redistricting_File--PL_94-171/California/ca2010.pl.zip
unzip -p ca2010.pl.zip cageo2010.pl |
awk 'BEGIN {
print "GEOID10,population"
@ -873,7 +587,7 @@ or on an individual tile:
tippecanoe-decode file.mbtiles zoom x y
tippecanoe-decode file.vector.pbf zoom x y
Unless you use `-c`, the output is a set of nested FeatureCollections identifying each
If you decode an entire file, you get a nested `FeatureCollection` identifying each
tile and layer separately. Note that the same features generally appear at all zooms,
so the output for the file will have many copies of the same features at different
resolutions.
@ -915,8 +629,7 @@ something better.
* `-e` *attribute* or `--extract=`*attribute*: Extract the named attribute as a prefix to each feature.
The formatting makes excessive use of `\u` quoting so that it follows JSON string rules but will still
be sorted correctly by tools that just do ASCII comparisons.
* `-c` *file.csv* or `--csv=`*file.csv*: Join attributes from the named sorted CSV file, using its first column as the join key. Geometries will be passed through even if they do not match the CSV; CSV lines that do not match a geometry will be discarded.
* `-pe` or `--empty-csv-columns-are-null`: Treat empty CSV columns as nulls rather than as empty strings.
* `-c` *file.csv* or `--csv=`*file.csv*: Join properties from the named sorted CSV file, using its first column as the join key. Geometries will be passed through even if they do not match the CSV; CSV lines that do not match a geometry will be discarded.
### Example
@ -945,7 +658,7 @@ Sort GeoJSON block geometry so it is ordered by block ID. If you don't do this,
$ tippecanoe-json-tool -e GEOID10 tl_2010_18157_tabblock10.json | LC_ALL=C sort > tl_2010_18157_tabblock10.sort.json
```
Join block geometries to employment attributes:
Join block geometries to employment properties:
```
$ tippecanoe-json-tool -c in_wac_S000_JT00_2015.csv tl_2010_18157_tabblock10.sort.json > blocks-wac.json

View File

@ -1,7 +0,0 @@
ignore:
- "test"
- "mapbox"
coverage:
status:
patch: off

View File

@ -27,11 +27,6 @@ std::vector<std::string> csv_split(const char *s) {
while (*s && isspace(*s)) {
s++;
}
if (*s == '\0' || *s == '\r' || *s == '\n') {
ret.push_back(std::string(""));
break;
}
}
}

View File

@ -27,31 +27,17 @@ int minzoom = 0;
int maxzoom = 32;
bool force = false;
void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, unsigned y, json_writer &state) {
state.json_write_hash();
state.json_write_string("zoom");
state.json_write_signed(z);
state.json_write_string("x");
state.json_write_unsigned(x);
state.json_write_string("y");
state.json_write_unsigned(y);
state.json_write_string("bytes");
state.json_write_unsigned(size);
state.json_write_string("compressed");
state.json_write_bool(compressed);
state.json_write_string("layers");
state.json_write_hash();
void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, unsigned y) {
printf("{ \"zoom\": %d, \"x\": %u, \"y\": %u, \"bytes\": %zu, \"compressed\": %s", z, x, y, size, compressed ? "true" : "false");
printf(", \"layers\": { ");
for (size_t i = 0; i < tile.layers.size(); i++) {
state.json_write_string(tile.layers[i].name);
if (i != 0) {
printf(", ");
}
fprintq(stdout, tile.layers[i].name.c_str());
size_t points = 0, lines = 0, polygons = 0;
int points = 0, lines = 0, polygons = 0;
for (size_t j = 0; j < tile.layers[i].features.size(); j++) {
if (tile.layers[i].features[j].type == mvt_point) {
points++;
@ -62,30 +48,13 @@ void do_stats(mvt_tile &tile, size_t size, bool compressed, int z, unsigned x, u
}
}
state.json_write_hash();
state.json_write_string("points");
state.json_write_unsigned(points);
state.json_write_string("lines");
state.json_write_unsigned(lines);
state.json_write_string("polygons");
state.json_write_unsigned(polygons);
state.json_write_string("extent");
state.json_write_signed(tile.layers[i].extent);
state.json_end_hash();
printf(": { \"points\": %d, \"lines\": %d, \"polygons\": %d, \"extent\": %lld }", points, lines, polygons, tile.layers[i].extent);
}
state.json_end_hash();
state.json_end_hash();
state.json_write_newline();
printf(" } }\n");
}
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, int describe, std::set<std::string> const &to_decode, bool pipeline, bool stats) {
mvt_tile tile;
bool was_compressed;
@ -94,63 +63,34 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
fprintf(stderr, "Couldn't parse tile %d/%u/%u\n", z, x, y);
exit(EXIT_FAILURE);
}
} catch (std::exception const &e) {
} catch (protozero::unknown_pbf_wire_type_exception e) {
fprintf(stderr, "PBF decoding error in tile %d/%u/%u\n", z, x, y);
exit(EXIT_FAILURE);
}
if (stats) {
do_stats(tile, message.size(), was_compressed, z, x, y, state);
do_stats(tile, message.size(), was_compressed, z, x, y);
return;
}
if (!pipeline) {
state.json_write_hash();
state.json_write_string("type");
state.json_write_string("FeatureCollection");
if (true) {
state.json_write_string("properties");
state.json_write_hash();
state.json_write_string("zoom");
state.json_write_signed(z);
state.json_write_string("x");
state.json_write_signed(x);
state.json_write_string("y");
state.json_write_signed(y);
printf("{ \"type\": \"FeatureCollection\"");
if (describe) {
printf(", \"properties\": { \"zoom\": %d, \"x\": %d, \"y\": %d", z, x, y);
if (!was_compressed) {
state.json_write_string("compressed");
state.json_write_bool(false);
printf(", \"compressed\": false");
}
state.json_end_hash();
printf(" }");
if (projection != projections) {
state.json_write_string("crs");
state.json_write_hash();
state.json_write_string("type");
state.json_write_string("name");
state.json_write_string("properties");
state.json_write_hash();
state.json_write_string("name");
state.json_write_string(projection->alias);
state.json_end_hash();
state.json_end_hash();
printf(", \"crs\": { \"type\": \"name\", \"properties\": { \"name\": ");
fprintq(stdout, projection->alias);
printf(" } }");
}
}
state.json_write_string("features");
state.json_write_array();
state.json_write_newline();
printf(", \"features\": [\n");
}
bool first_layer = true;
@ -167,34 +107,18 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
}
if (!pipeline) {
if (true) {
if (describe) {
if (!first_layer) {
state.json_comma_newline();
printf(",\n");
}
state.json_write_hash();
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");
state.json_write_string("type");
state.json_write_string("FeatureCollection");
state.json_write_string("properties");
state.json_write_hash();
state.json_write_string("layer");
state.json_write_string(layer.name);
state.json_write_string("version");
state.json_write_signed(layer.version);
state.json_write_string("extent");
state.json_write_signed(layer.extent);
state.json_end_hash();
state.json_write_string("features");
state.json_write_array();
state.json_write_newline();
first_layer = false;
}
}
@ -205,30 +129,25 @@ void handle(std::string message, int z, unsigned x, unsigned y, std::set<std::st
exit(EXIT_FAILURE);
}
layer_to_geojson(layer, z, x, y, !pipeline, pipeline, pipeline, false, 0, 0, 0, !force, state);
layer_to_geojson(stdout, layer, z, x, y, !pipeline, pipeline, pipeline, 0, 0, 0, !force);
if (!pipeline) {
if (true) {
state.json_end_array();
state.json_end_hash();
state.json_write_newline();
if (describe) {
printf("] }\n");
}
}
}
if (!pipeline) {
state.json_end_array();
state.json_end_hash();
state.json_write_newline();
printf("] }\n");
}
}
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) {
sqlite3 *db = NULL;
bool isdir = false;
int oz = z;
unsigned ox = x, oy = y;
json_writer state(stdout);
int fd = open(fname, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
@ -240,7 +159,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, to_decode, pipeline, stats, state);
handle(s, z, x, y, 1, to_decode, pipeline, stats);
munmap(map, st.st_size);
return;
} else {
@ -268,32 +187,19 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
isdir = true;
db = dirmeta2tmp(fname);
tiles = enumerate_dirtiles(fname, minzoom, maxzoom);
tiles = enumerate_dirtiles(fname);
} else {
if (sqlite3_open(fname, &db) != SQLITE_OK) {
fprintf(stderr, "%s: %s\n", fname, sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
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);
}
}
if (z < 0) {
int within = 0;
if (!pipeline && !stats) {
state.json_write_hash();
state.json_write_string("type");
state.json_write_string("FeatureCollection");
state.json_write_string("properties");
state.json_write_hash();
state.json_write_newline();
printf("{ \"type\": \"FeatureCollection\", \"properties\": {\n");
const char *sql2 = "SELECT name, value from metadata order by name;";
sqlite3_stmt *stmt2;
@ -303,6 +209,11 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
}
while (sqlite3_step(stmt2) == SQLITE_ROW) {
if (within) {
printf(",\n");
}
within = 1;
const unsigned char *name = sqlite3_column_text(stmt2, 0);
const unsigned char *value = sqlite3_column_text(stmt2, 1);
@ -311,34 +222,20 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
exit(EXIT_FAILURE);
}
if (exclude_meta.count((char *) name) == 0) {
if (within) {
state.json_comma_newline();
}
within = 1;
state.json_write_string((char *) name);
state.json_write_string((char *) value);
}
fprintq(stdout, (char *) name);
printf(": ");
fprintq(stdout, (char *) value);
}
state.json_write_newline();
state.wantnl = false; // XXX
sqlite3_finalize(stmt2);
}
if (stats) {
state.json_write_array();
state.json_write_newline();
printf("[\n");
}
if (!pipeline && !stats) {
state.json_end_hash();
state.json_write_string("features");
state.json_write_array();
state.json_write_newline();
printf("\n}, \"features\": [\n");
}
if (isdir) {
@ -346,13 +243,13 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
for (size_t i = 0; i < tiles.size(); i++) {
if (!pipeline && !stats) {
if (within) {
state.json_comma_newline();
printf(",\n");
}
within = 1;
}
if (stats) {
if (within) {
state.json_comma_newline();
printf(",\n");
}
within = 1;
}
@ -372,7 +269,7 @@ 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, 1, to_decode, pipeline, stats);
}
} 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;";
@ -389,13 +286,13 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
while (sqlite3_step(stmt) == SQLITE_ROW) {
if (!pipeline && !stats) {
if (within) {
state.json_comma_newline();
printf(",\n");
}
within = 1;
}
if (stats) {
if (within) {
state.json_comma_newline();
printf(",\n");
}
within = 1;
}
@ -413,28 +310,17 @@ 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);
if (s == NULL) {
fprintf(stderr, "Corrupt mbtiles file: null entry in tiles table\n");
exit(EXIT_FAILURE);
}
handle(std::string(s, len), tz, tx, ty, to_decode, pipeline, stats, state);
handle(std::string(s, len), tz, tx, ty, 1, to_decode, pipeline, stats);
}
sqlite3_finalize(stmt);
}
if (!pipeline && !stats) {
state.json_end_array();
state.json_end_hash();
state.json_write_newline();
printf("] }\n");
}
if (stats) {
state.json_end_array();
state.json_write_newline();
}
if (pipeline) {
state.json_write_newline();
printf("]\n");
}
} else {
int handled = 0;
@ -454,16 +340,11 @@ void decode(char *fname, int z, unsigned x, unsigned y, std::set<std::string> co
int len = sqlite3_column_bytes(stmt, 0);
const char *s = (const char *) sqlite3_column_blob(stmt, 0);
if (s == NULL) {
fprintf(stderr, "Corrupt mbtiles file: null entry in tiles table\n");
exit(EXIT_FAILURE);
}
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, 0, to_decode, pipeline, stats);
handled = 1;
}
@ -493,7 +374,6 @@ int main(int argc, char **argv) {
std::set<std::string> to_decode;
bool pipeline = false;
bool stats = false;
std::set<std::string> exclude_meta;
struct option long_options[] = {
{"projection", required_argument, 0, 's'},
@ -503,7 +383,6 @@ int main(int argc, char **argv) {
{"tag-layer-and-zoom", no_argument, 0, 'c'},
{"stats", no_argument, 0, 'S'},
{"force", no_argument, 0, 'f'},
{"exclude-metadata-row", required_argument, 0, 'x'},
{0, 0, 0, 0},
};
@ -551,19 +430,15 @@ int main(int argc, char **argv) {
force = true;
break;
case 'x':
exclude_meta.insert(optarg);
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, pipeline, stats, exclude_meta);
decode(argv[optind], atoi(argv[optind + 1]), atoi(argv[optind + 2]), atoi(argv[optind + 3]), to_decode, pipeline, stats);
} 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);
} else {
usage(argv);
}

View File

@ -7,7 +7,6 @@
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include "jsonpull/jsonpull.h"
@ -60,20 +59,18 @@ static bool pbfname(const char *s) {
s++;
}
return strcmp(s, ".pbf") == 0 || strcmp(s, ".mvt") == 0;
return strcmp(s, ".pbf") == 0;
}
void check_dir(const char *dir, char **argv, bool force, bool forcetable) {
void check_dir(const char *dir, bool force, bool forcetable) {
struct stat st;
mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
std::string meta = std::string(dir) + "/" + "metadata.json";
if (force) {
unlink(meta.c_str()); // error OK since it may not exist;
} else {
if (stat(meta.c_str(), &st) == 0) {
fprintf(stderr, "%s: Tileset \"%s\" already exists. You can use --force if you want to delete the old tileset.\n", argv[0], dir);
fprintf(stderr, "%s: %s: file exists\n", argv[0], meta.c_str());
fprintf(stderr, "%s: file exists\n", meta.c_str());
if (!forcetable) {
exit(EXIT_FAILURE);
}
@ -85,7 +82,7 @@ void check_dir(const char *dir, char **argv, bool force, bool forcetable) {
return;
}
std::vector<zxy> tiles = enumerate_dirtiles(dir, INT_MIN, INT_MAX);
std::vector<zxy> tiles = enumerate_dirtiles(dir);
for (size_t i = 0; i < tiles.size(); i++) {
std::string fn = std::string(dir) + "/" + tiles[i].path();
@ -102,14 +99,14 @@ void check_dir(const char *dir, char **argv, bool force, bool forcetable) {
}
}
std::vector<zxy> enumerate_dirtiles(const char *fname, int minzoom, int maxzoom) {
std::vector<zxy> enumerate_dirtiles(const char *fname) {
std::vector<zxy> tiles;
DIR *d1 = opendir(fname);
if (d1 != NULL) {
struct dirent *dp;
while ((dp = readdir(d1)) != NULL) {
if (numeric(dp->d_name) && atoi(dp->d_name) >= minzoom && atoi(dp->d_name) <= maxzoom) {
if (numeric(dp->d_name)) {
std::string z = std::string(fname) + "/" + dp->d_name;
int tz = atoi(dp->d_name);
@ -135,12 +132,7 @@ std::vector<zxy> enumerate_dirtiles(const char *fname, int minzoom, int maxzoom)
while ((dp3 = readdir(d3)) != NULL) {
if (pbfname(dp3->d_name)) {
int ty = atoi(dp3->d_name);
zxy tile(tz, tx, ty);
if (strstr(dp3->d_name, ".mvt") != NULL) {
tile.extension = ".mvt";
}
tiles.push_back(tile);
tiles.push_back(zxy(tz, tx, ty));
}
}
@ -160,52 +152,48 @@ std::vector<zxy> enumerate_dirtiles(const char *fname, int minzoom, int maxzoom)
}
sqlite3 *dirmeta2tmp(const char *fname) {
sqlite3 *db;
char *err = NULL;
sqlite3 *db;
char *err = NULL;
if (sqlite3_open("", &db) != SQLITE_OK) {
fprintf(stderr, "Temporary db: %s\n", sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
if (sqlite3_exec(db, "CREATE TABLE metadata (name text, value text);", NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "Create metadata table: %s\n", err);
exit(EXIT_FAILURE);
}
if (sqlite3_open("", &db) != SQLITE_OK) {
fprintf(stderr, "Temporary db: %s\n", sqlite3_errmsg(db));
exit(EXIT_FAILURE);
}
if (sqlite3_exec(db, "CREATE TABLE metadata (name text, value text);", NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "Create metadata table: %s\n", err);
exit(EXIT_FAILURE);
}
std::string name = fname;
name += "/metadata.json";
std::string name = fname;
name += "/metadata.json";
FILE *f = fopen(name.c_str(), "r");
if (f == NULL) {
perror(name.c_str());
} else {
json_pull *jp = json_begin_file(f);
json_object *o = json_read_tree(jp);
if (o == NULL) {
fprintf(stderr, "%s: metadata parsing error: %s\n", name.c_str(), jp->error);
exit(EXIT_FAILURE);
}
FILE *f = fopen(name.c_str(), "r");
if (f == NULL) {
perror(name.c_str());
exit(EXIT_FAILURE);
}
if (o->type != JSON_HASH) {
fprintf(stderr, "%s: bad metadata format\n", name.c_str());
exit(EXIT_FAILURE);
}
json_pull *jp = json_begin_file(f);
json_object *o = json_read_tree(jp);
for (size_t i = 0; i < o->length; i++) {
if (o->keys[i]->type != JSON_STRING || o->values[i]->type != JSON_STRING) {
fprintf(stderr, "%s: non-string in metadata\n", name.c_str());
}
if (o->type != JSON_HASH) {
fprintf(stderr, "%s: bad metadata format\n", name.c_str());
exit(EXIT_FAILURE);
}
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->keys[i]->string, o->values[i]->string);
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", o->keys[i]->string, err);
}
sqlite3_free(sql);
}
for (size_t i = 0; i < o->length; i++) {
if (o->keys[i]->type != JSON_STRING || o->values[i]->type != JSON_STRING) {
fprintf(stderr, "%s: non-string in metadata\n", name.c_str());
}
json_end(jp);
fclose(f);
}
char *sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES (%Q, %Q);", o->keys[i]->string, o->values[i]->string);
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set %s in metadata: %s\n", o->keys[i]->string, err);
}
sqlite3_free(sql);
}
return db;
json_end(jp);
fclose(f);
return db;
}

View File

@ -1,19 +1,17 @@
#include <string>
#include <vector>
#include <sys/stat.h>
#ifndef DIRTILES_HPP
#define DIRTILES_HPP
void dir_write_tile(const char *outdir, int z, int tx, int ty, std::string const &pbf);
void check_dir(const char *d, char **argv, bool force, bool forcetable);
void check_dir(const char *d, bool force, bool forcetable);
struct zxy {
long long z;
long long x;
long long y;
std::string extension = ".pbf";
zxy(int _z, int _x, int _y)
: z(_z), x(_x), y(_y) {
@ -38,11 +36,11 @@ struct zxy {
}
std::string path() {
return std::to_string(z) + "/" + std::to_string(x) + "/" + std::to_string(y) + extension;
return std::to_string(z) + "/" + std::to_string(x) + "/" + std::to_string(y) + ".pbf";
}
};
std::vector<zxy> enumerate_dirtiles(const char *fname, int minzoom, int maxzoom);
std::vector<zxy> enumerate_dirtiles(const char *fname);
sqlite3 *dirmeta2tmp(const char *fname);
std::string dir_read_tile(std::string pbfPath, struct zxy tile);

View File

@ -11,12 +11,6 @@ void enumerate(char *fname) {
exit(EXIT_FAILURE);
}
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);
}
const char *sql = "SELECT zoom_level, tile_column, tile_row from tiles order by zoom_level, tile_column, tile_row;";
sqlite3_stmt *stmt;

View File

@ -69,7 +69,7 @@ int compare(mvt_value one, json_object *two, bool &fail) {
exit(EXIT_FAILURE);
}
bool eval(std::map<std::string, mvt_value> const &feature, json_object *f, std::set<std::string> &exclude_attributes) {
bool eval(std::map<std::string, mvt_value> const &feature, json_object *f) {
if (f == NULL || f->type != JSON_ARRAY) {
fprintf(stderr, "Filter is not an array: %s\n", json_stringify(f));
exit(EXIT_FAILURE);
@ -191,7 +191,7 @@ bool eval(std::map<std::string, mvt_value> const &feature, json_object *f, std::
}
for (size_t i = 1; i < f->length; i++) {
bool out = eval(feature, f->array[i], exclude_attributes);
bool out = eval(feature, f->array[i]);
if (strcmp(f->array[0]->string, "all") == 0) {
v = v && out;
@ -269,30 +269,11 @@ bool eval(std::map<std::string, mvt_value> const &feature, json_object *f, std::
}
}
if (strcmp(f->array[0]->string, "attribute-filter") == 0) {
if (f->length != 3) {
fprintf(stderr, "Wrong number of array elements in filter: %s\n", json_stringify(f));
exit(EXIT_FAILURE);
}
if (f->array[1]->type != JSON_STRING) {
fprintf(stderr, "\"attribute-filter\" key is not a string: %s\n", json_stringify(f));
exit(EXIT_FAILURE);
}
bool ok = eval(feature, f->array[2], exclude_attributes);
if (!ok) {
exclude_attributes.insert(f->array[1]->string);
}
return true;
}
fprintf(stderr, "Unknown filter %s\n", json_stringify(f));
exit(EXIT_FAILURE);
}
bool evaluate(std::map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter, std::set<std::string> &exclude_attributes) {
bool evaluate(std::map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter) {
if (filter == NULL || filter->type != JSON_HASH) {
fprintf(stderr, "Error: filter is not a hash: %s\n", json_stringify(filter));
exit(EXIT_FAILURE);
@ -303,12 +284,12 @@ bool evaluate(std::map<std::string, mvt_value> const &feature, std::string const
f = json_hash_get(filter, layer.c_str());
if (ok && f != NULL) {
ok = eval(feature, f, exclude_attributes);
ok = eval(feature, f);
}
f = json_hash_get(filter, "*");
if (ok && f != NULL) {
ok = eval(feature, f, exclude_attributes);
ok = eval(feature, f);
}
return ok;

View File

@ -3,11 +3,10 @@
#include <map>
#include <string>
#include <set>
#include "jsonpull/jsonpull.h"
#include "mvt.hpp"
bool evaluate(std::map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter, std::set<std::string> &exclude_attributes);
bool evaluate(std::map<std::string, mvt_value> const &feature, std::string const &layer, json_object *filter);
json_object *parse_filter(const char *s);
json_object *read_filter(const char *fname);

View File

@ -13,7 +13,6 @@
#include "protozero/pbf_writer.hpp"
#include "milo/dtoa_milo.h"
#include "jsonpull/jsonpull.h"
#include "text.hpp"
#define POINT 0
#define MULTIPOINT 1
@ -254,8 +253,6 @@ std::vector<drawvec_type> readGeometry(protozero::pbf_reader &pbf, size_t dim, d
dv.dv = readLine(coords, dim, e, false);
} else if (type == POLYGON) {
dv.dv = readMultiLine(coords, lengths, dim, e, true);
} else if (type == MULTILINESTRING) {
dv.dv = readMultiLine(coords, lengths, dim, e, false);
} else if (type == MULTIPOLYGON) {
dv.dv = readMultiPolygon(coords, lengths, dim, e);
} else {
@ -390,6 +387,7 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
sf.t = dv[i].type;
sf.full_keys = full_keys;
sf.full_values = full_values;
sf.m = sf.full_values.size();
auto tip = other.find("tippecanoe");
if (tip != other.end()) {
@ -400,13 +398,13 @@ void readFeature(protozero::pbf_reader &pbf, size_t dim, double e, std::vector<s
json_object *min = json_hash_get(o, "minzoom");
if (min != NULL && (min->type == JSON_STRING || min->type == JSON_NUMBER)) {
sf.has_tippecanoe_minzoom = true;
sf.tippecanoe_minzoom = integer_zoom(sst->fname, min->string);
sf.tippecanoe_minzoom = atoi(min->string);
}
json_object *max = json_hash_get(o, "maxzoom");
if (max != NULL && (max->type == JSON_STRING || max->type == JSON_NUMBER)) {
sf.has_tippecanoe_maxzoom = true;
sf.tippecanoe_maxzoom = integer_zoom(sst->fname, max->string);
sf.tippecanoe_maxzoom = atoi(max->string);
}
json_object *tlayer = json_hash_get(o, "layer");
@ -478,9 +476,7 @@ void runQueue() {
}
}
// Lack of atomicity is OK, since we are single-threaded again here
long long was = *((*(feature_queue[0].sst))[CPUS - 1].layer_seq);
*((*(feature_queue[0].sst))[0].layer_seq) = was;
*((*(feature_queue[0].sst))[0].layer_seq) = *((*(feature_queue[0].sst))[CPUS - 1].layer_seq);
feature_queue.clear();
}
@ -514,6 +510,7 @@ void outBareGeometry(drawvec const &dv, int type, struct serialization_state *ss
sf.seq = (*sst->layer_seq);
sf.geometry = dv;
sf.t = type;
sf.m = 0;
serialize_feature(sst, sf);
}

View File

@ -8,19 +8,12 @@
#include "text.hpp"
#include "csv.hpp"
#include "milo/dtoa_milo.h"
#include "options.hpp"
void parse_geocsv(std::vector<struct serialization_state> &sst, std::string fname, int layer, std::string layername) {
FILE *f;
if (fname.size() == 0) {
f = stdin;
} else {
f = fopen(fname.c_str(), "r");
if (f == NULL) {
perror(fname.c_str());
exit(EXIT_FAILURE);
}
FILE *f = fopen(fname.c_str(), "r");
if (f == NULL) {
perror(fname.c_str());
exit(EXIT_FAILURE);
}
std::string s;
@ -68,18 +61,10 @@ void parse_geocsv(std::vector<struct serialization_state> &sst, std::string fnam
std::vector<std::string> line = csv_split(s.c_str());
if (line.size() != header.size()) {
fprintf(stderr, "%s:%zu: Mismatched column count: %zu in line, %zu in header\n", fname.c_str(), seq + 1, line.size(), header.size());
fprintf(stderr, "%s:%zu: Mismatched column count: %zu in line, %zu in header\n", fname.c_str(), seq, line.size(), header.size());
exit(EXIT_FAILURE);
}
if (line[loncol].empty() || line[latcol].empty()) {
static int warned = 0;
if (!warned) {
fprintf(stderr, "%s:%zu: null geometry (additional not reported)\n", fname.c_str(), seq + 1);
warned = 1;
}
continue;
}
double lon = atof(line[loncol].c_str());
double lat = atof(line[latcol].c_str());
@ -98,9 +83,6 @@ void parse_geocsv(std::vector<struct serialization_state> &sst, std::string fnam
serial_val sv;
if (is_number(line[i])) {
sv.type = mvt_double;
} else if (line[i].size() == 0 && prevent[P_EMPTY_CSV_COLUMNS]) {
sv.type = mvt_null;
line[i] = "null";
} else {
sv.type = mvt_string;
}
@ -126,14 +108,13 @@ void parse_geocsv(std::vector<struct serialization_state> &sst, std::string fnam
sf.t = 1; // POINT
sf.full_keys = full_keys;
sf.full_values = full_values;
sf.m = sf.full_values.size();
serialize_feature(&sst[0], sf);
}
if (fname.size() != 0) {
if (fclose(f) != 0) {
perror("fclose");
exit(EXIT_FAILURE);
}
if (fclose(f) != 0) {
perror("fclose");
exit(EXIT_FAILURE);
}
}

View File

@ -1,184 +0,0 @@
#ifdef MTRACE
#include <mcheck.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include "geojson-loop.hpp"
#include "jsonpull/jsonpull.h"
// XXX duplicated
#define GEOM_TYPES 6
static const char *geometry_names[GEOM_TYPES] = {
"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon",
};
// XXX duplicated
static void json_context(json_object *j) {
char *s = json_stringify(j);
if (strlen(s) >= 500) {
sprintf(s + 497, "...");
}
fprintf(stderr, "In JSON object %s\n", s);
free(s); // stringify
}
void parse_json(json_feature_action *jfa, json_pull *jp) {
long long found_hashes = 0;
long long found_features = 0;
long long found_geometries = 0;
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
fprintf(stderr, "%s:%d: %s\n", jfa->fname.c_str(), jp->line, jp->error);
if (jp->root != NULL) {
json_context(jp->root);
}
}
json_free(jp->root);
break;
}
if (j->type == JSON_HASH) {
found_hashes++;
if (found_hashes == 50 && found_features == 0 && found_geometries == 0) {
fprintf(stderr, "%s:%d: Warning: not finding any GeoJSON features or geometries in input yet after 50 objects.\n", jfa->fname.c_str(), jp->line);
}
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
continue;
}
if (found_features == 0) {
int i;
int is_geometry = 0;
for (i = 0; i < GEOM_TYPES; i++) {
if (strcmp(type->string, geometry_names[i]) == 0) {
is_geometry = 1;
break;
}
}
if (is_geometry) {
if (j->parent != NULL) {
if (j->parent->type == JSON_ARRAY && j->parent->parent != NULL) {
if (j->parent->parent->type == JSON_HASH) {
json_object *geometries = json_hash_get(j->parent->parent, "geometries");
if (geometries != NULL) {
// Parent of Parent must be a GeometryCollection
is_geometry = 0;
}
}
} else if (j->parent->type == JSON_HASH) {
json_object *geometry = json_hash_get(j->parent, "geometry");
if (geometry != NULL) {
// Parent must be a Feature
is_geometry = 0;
}
}
}
}
if (is_geometry) {
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
// Ancestor is the value corresponding to a properties key
is_geometry = 0;
break;
}
}
jo = jo->parent;
}
}
if (is_geometry) {
if (found_features != 0 && found_geometries == 0) {
fprintf(stderr, "%s:%d: Warning: found a mixture of features and bare geometries\n", jfa->fname.c_str(), jp->line);
}
found_geometries++;
jfa->add_feature(j, false, NULL, NULL, NULL, j);
json_free(j);
continue;
}
}
if (strcmp(type->string, "Feature") != 0) {
if (strcmp(type->string, "FeatureCollection") == 0) {
jfa->check_crs(j);
json_free(j);
}
continue;
}
if (found_features == 0 && found_geometries != 0) {
fprintf(stderr, "%s:%d: Warning: found a mixture of features and bare geometries\n", jfa->fname.c_str(), jp->line);
}
found_features++;
json_object *geometry = json_hash_get(j, "geometry");
if (geometry == NULL) {
fprintf(stderr, "%s:%d: feature with no geometry\n", jfa->fname.c_str(), jp->line);
json_context(j);
json_free(j);
continue;
}
json_object *properties = json_hash_get(j, "properties");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "%s:%d: feature without properties hash\n", jfa->fname.c_str(), jp->line);
json_context(j);
json_free(j);
continue;
}
bool is_feature = true;
{
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
// Ancestor is the value corresponding to a properties key
is_feature = false;
break;
}
}
jo = jo->parent;
}
}
if (!is_feature) {
continue;
}
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
json_object *id = json_hash_get(j, "id");
json_object *geometries = json_hash_get(geometry, "geometries");
if (geometries != NULL && geometries->type == JSON_ARRAY) {
jfa->add_feature(geometries, true, properties, id, tippecanoe, j);
} else {
jfa->add_feature(geometry, false, properties, id, tippecanoe, j);
}
json_free(j);
/* XXX check for any non-features in the outer object */
}
}

View File

@ -1,11 +0,0 @@
#include <string>
#include "jsonpull/jsonpull.h"
struct json_feature_action {
std::string fname;
virtual int add_feature(json_object *geometry, bool geometrycollection, json_object *properties, json_object *id, json_object *tippecanoe, json_object *feature) = 0;
virtual void check_crs(json_object *j) = 0;
};
void parse_json(json_feature_action *action, json_pull *jp);

View File

@ -37,7 +37,6 @@
#include "text.hpp"
#include "read_json.hpp"
#include "mvt.hpp"
#include "geojson-loop.hpp"
int serialize_geojson_feature(struct serialization_state *sst, json_object *geometry, json_object *properties, json_object *id, int layer, json_object *tippecanoe, json_object *feature, std::string layername) {
json_object *geometry_type = json_hash_get(geometry, "type");
@ -83,13 +82,19 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
if (tippecanoe != NULL) {
json_object *min = json_hash_get(tippecanoe, "minzoom");
if (min != NULL && (min->type == JSON_STRING || min->type == JSON_NUMBER)) {
tippecanoe_minzoom = integer_zoom(sst->fname, min->string);
if (min != NULL && min->type == JSON_NUMBER) {
tippecanoe_minzoom = min->number;
}
if (min != NULL && min->type == JSON_STRING) {
tippecanoe_minzoom = atoi(min->string);
}
json_object *max = json_hash_get(tippecanoe, "maxzoom");
if (max != NULL && (max->type == JSON_STRING || max->type == JSON_NUMBER)) {
tippecanoe_maxzoom = integer_zoom(sst->fname, max->string);
if (max != NULL && max->type == JSON_NUMBER) {
tippecanoe_maxzoom = max->number;
}
if (max != NULL && max->type == JSON_STRING) {
tippecanoe_maxzoom = atoi(max->string);
}
json_object *ln = json_hash_get(tippecanoe, "layer");
@ -113,13 +118,6 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->string);
warned_frac = true;
}
} else if (std::to_string(id_value) != id->string) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->string);
warned = true;
}
} else {
has_id = true;
}
@ -132,41 +130,13 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
}
}
} else {
bool converted = false;
static bool warned_nan = false;
if (additional[A_CONVERT_NUMERIC_IDS] && id->type == JSON_STRING) {
char *err = NULL;
id_value = strtoull(id->string, &err, 10);
if (err != NULL && *err != '\0') {
static bool warned_frac = false;
if (!warned_frac) {
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", id->string);
warned_frac = true;
}
} else if (std::to_string(id_value) != id->string) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", id->string);
warned = true;
}
} else {
has_id = true;
converted = true;
}
}
if (!converted) {
static bool warned_nan = false;
if (!warned_nan) {
char *s = json_stringify(id);
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", s);
free(s); // stringify
warned_nan = true;
}
if (!warned_nan) {
char *s = json_stringify(id);
fprintf(stderr, "Warning: Can't represent non-numeric feature ID %s\n", s);
free(s); // stringify
warned_nan = true;
}
}
}
@ -223,6 +193,7 @@ int serialize_geojson_feature(struct serialization_state *sst, json_object *geom
sf.has_tippecanoe_maxzoom = (tippecanoe_maxzoom != -1);
sf.tippecanoe_maxzoom = tippecanoe_maxzoom;
sf.geometry = dv;
sf.m = m;
sf.feature_minzoom = 0; // Will be filled in during index merging
sf.seq = *(sst->layer_seq);
@ -251,7 +222,7 @@ void check_crs(json_object *j, const char *reading) {
json_object *properties = json_hash_get(crs, "properties");
if (properties != NULL) {
json_object *name = json_hash_get(properties, "name");
if (name != NULL && name->type == JSON_STRING) {
if (name->type == JSON_STRING) {
if (strcmp(name->string, projection->alias) != 0) {
if (!quiet) {
fprintf(stderr, "%s: Warning: GeoJSON specified projection \"%s\", not the expected \"%s\".\n", reading, name->string, projection->alias);
@ -263,37 +234,159 @@ void check_crs(json_object *j, const char *reading) {
}
}
struct json_serialize_action : json_feature_action {
serialization_state *sst;
int layer;
std::string layername;
int add_feature(json_object *geometry, bool geometrycollection, json_object *properties, json_object *id, json_object *tippecanoe, json_object *feature) {
sst->line = geometry->parser->line;
if (geometrycollection) {
int ret = 1;
for (size_t g = 0; g < geometry->length; g++) {
ret &= serialize_geojson_feature(sst, geometry->array[g], properties, id, layer, tippecanoe, feature, layername);
}
return ret;
} else {
return serialize_geojson_feature(sst, geometry, properties, id, layer, tippecanoe, feature, layername);
}
}
void check_crs(json_object *j) {
::check_crs(j, fname.c_str());
}
};
void parse_json(struct serialization_state *sst, json_pull *jp, int layer, std::string layername) {
json_serialize_action jsa;
jsa.fname = sst->fname;
jsa.sst = sst;
jsa.layer = layer;
jsa.layername = layername;
long long found_hashes = 0;
long long found_features = 0;
long long found_geometries = 0;
parse_json(&jsa, jp);
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
fprintf(stderr, "%s:%d: %s\n", sst->fname, jp->line, jp->error);
if (jp->root != NULL) {
json_context(jp->root);
}
}
json_free(jp->root);
break;
}
if (j->type == JSON_HASH) {
found_hashes++;
if (found_hashes == 50 && found_features == 0 && found_geometries == 0) {
fprintf(stderr, "%s:%d: Warning: not finding any GeoJSON features or geometries in input yet after 50 objects.\n", sst->fname, jp->line);
}
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
continue;
}
if (found_features == 0) {
int i;
int is_geometry = 0;
for (i = 0; i < GEOM_TYPES; i++) {
if (strcmp(type->string, geometry_names[i]) == 0) {
is_geometry = 1;
break;
}
}
if (is_geometry) {
if (j->parent != NULL) {
if (j->parent->type == JSON_ARRAY && j->parent->parent != NULL) {
if (j->parent->parent->type == JSON_HASH) {
json_object *geometries = json_hash_get(j->parent->parent, "geometries");
if (geometries != NULL) {
// Parent of Parent must be a GeometryCollection
is_geometry = 0;
}
}
} else if (j->parent->type == JSON_HASH) {
json_object *geometry = json_hash_get(j->parent, "geometry");
if (geometry != NULL) {
// Parent must be a Feature
is_geometry = 0;
}
}
}
}
if (is_geometry) {
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
// Ancestor is the value corresponding to a properties key
is_geometry = 0;
break;
}
}
jo = jo->parent;
}
}
if (is_geometry) {
if (found_features != 0 && found_geometries == 0) {
fprintf(stderr, "%s:%d: Warning: found a mixture of features and bare geometries\n", sst->fname, jp->line);
}
found_geometries++;
serialize_geojson_feature(sst, j, NULL, NULL, layer, NULL, j, layername);
json_free(j);
continue;
}
}
if (strcmp(type->string, "Feature") != 0) {
if (strcmp(type->string, "FeatureCollection") == 0) {
check_crs(j, sst->fname);
json_free(j);
}
continue;
}
if (found_features == 0 && found_geometries != 0) {
fprintf(stderr, "%s:%d: Warning: found a mixture of features and bare geometries\n", sst->fname, jp->line);
}
found_features++;
json_object *geometry = json_hash_get(j, "geometry");
if (geometry == NULL) {
fprintf(stderr, "%s:%d: feature with no geometry\n", sst->fname, jp->line);
json_context(j);
json_free(j);
continue;
}
json_object *properties = json_hash_get(j, "properties");
if (properties == NULL || (properties->type != JSON_HASH && properties->type != JSON_NULL)) {
fprintf(stderr, "%s:%d: feature without properties hash\n", sst->fname, jp->line);
json_context(j);
json_free(j);
continue;
}
bool is_feature = true;
{
json_object *jo = j;
while (jo != NULL) {
if (jo->parent != NULL && jo->parent->type == JSON_HASH) {
if (json_hash_get(jo->parent, "properties") == jo) {
// Ancestor is the value corresponding to a properties key
is_feature = false;
break;
}
}
jo = jo->parent;
}
}
if (!is_feature) {
continue;
}
json_object *tippecanoe = json_hash_get(j, "tippecanoe");
json_object *id = json_hash_get(j, "id");
json_object *geometries = json_hash_get(geometry, "geometries");
if (geometries != NULL) {
size_t g;
for (g = 0; g < geometries->length; g++) {
serialize_geojson_feature(sst, geometries->array[g], properties, id, layer, tippecanoe, j, layername);
}
} else {
serialize_geojson_feature(sst, geometry, properties, id, layer, tippecanoe, j, layername);
}
json_free(j);
/* XXX check for any non-features in the outer object */
}
}
void *run_parse_json(void *v) {

View File

@ -19,12 +19,11 @@
#include "projection.hpp"
#include "serial.hpp"
#include "main.hpp"
#include "options.hpp"
static int pnpoly(drawvec &vert, size_t start, size_t nvert, long long testx, long long testy);
static int clip(double *x0, double *y0, double *x1, double *y1, double xmin, double ymin, double xmax, double ymax);
drawvec decode_geometry(FILE *meta, std::atomic<long long> *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y) {
drawvec decode_geometry(FILE *meta, long long *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y) {
drawvec out;
bbox[0] = LLONG_MAX;
@ -270,7 +269,7 @@ drawvec clean_or_clip_poly(drawvec &geom, int z, int buffer, bool clip) {
mapbox::geometry::multi_polygon<long long> result;
try {
wagyu.execute(mapbox::geometry::wagyu::clip_type_union, result, mapbox::geometry::wagyu::fill_type_positive, mapbox::geometry::wagyu::fill_type_positive);
} catch (std::runtime_error &e) {
} catch (std::runtime_error e) {
FILE *f = fopen("/tmp/wagyu.log", "w");
fprintf(f, "%s\n", e.what());
fprintf(stderr, "%s\n", e.what());
@ -595,20 +594,16 @@ drawvec reduce_tiny_poly(drawvec &geom, int z, int detail, bool *reduced, double
}
drawvec clip_point(drawvec &geom, int z, long long buffer) {
drawvec out;
long long min = 0;
long long area = 1LL << (32 - z);
min -= buffer * area / 256;
area += buffer * area / 256;
return clip_point(geom, min, min, area, area);
}
drawvec clip_point(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
drawvec out;
for (size_t i = 0; i < geom.size(); i++) {
if (geom[i].x >= minx && geom[i].y >= miny && geom[i].x <= maxx && geom[i].y <= maxy) {
if (geom[i].x >= min && geom[i].y >= min && geom[i].x <= area && geom[i].y <= area) {
out.push_back(geom[i]);
}
}
@ -650,17 +645,13 @@ bool point_within_tile(long long x, long long y, int z) {
}
drawvec clip_lines(drawvec &geom, int z, long long buffer) {
drawvec out;
long long min = 0;
long long area = 1LL << (32 - z);
min -= buffer * area / 256;
area += buffer * area / 256;
return clip_lines(geom, min, min, area, area);
}
drawvec clip_lines(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
drawvec out;
for (size_t i = 0; i < geom.size(); i++) {
if (i > 0 && (geom[i - 1].op == VT_MOVETO || geom[i - 1].op == VT_LINETO) && geom[i].op == VT_LINETO) {
double x1 = geom[i - 1].x;
@ -669,7 +660,7 @@ drawvec clip_lines(drawvec &geom, long long minx, long long miny, long long maxx
double x2 = geom[i - 0].x;
double y2 = geom[i - 0].y;
int c = clip(&x1, &y1, &x2, &y2, minx, miny, maxx, maxy);
int c = clip(&x1, &y1, &x2, &y2, min, min, area, area);
if (c > 1) { // clipped
out.push_back(draw(VT_MOVETO, x1, y1));
@ -802,7 +793,7 @@ drawvec impose_tile_boundaries(drawvec &geom, long long extent) {
return out;
}
drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds, double simplification, size_t retain, drawvec const &shared_nodes) {
drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds, double simplification, size_t retain) {
int res = 1 << (32 - detail - z);
long long area = 1LL << (32 - z);
@ -814,13 +805,6 @@ drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds,
} else {
geom[i].necessary = 1;
}
if (prevent[P_SIMPLIFY_SHARED_NODES]) {
auto pt = std::lower_bound(shared_nodes.begin(), shared_nodes.end(), geom[i]);
if (pt != shared_nodes.end() && *pt == geom[i]) {
geom[i].necessary = true;
}
}
}
if (mark_tile_bounds) {
@ -881,8 +865,8 @@ drawvec reorder_lines(drawvec &geom) {
// instead of down and to the right
// so that it will coalesce better
unsigned long long l1 = encode_index(geom[0].x, geom[0].y);
unsigned long long l2 = encode_index(geom[geom.size() - 1].x, geom[geom.size() - 1].y);
unsigned long long l1 = encode(geom[0].x, geom[0].y);
unsigned long long l2 = encode(geom[geom.size() - 1].x, geom[geom.size() - 1].y);
if (l1 > l2) {
drawvec out;
@ -928,21 +912,8 @@ drawvec fix_polygon(drawvec &geom) {
// Reverse ring if winding order doesn't match
// inner/outer expectation
bool reverse_ring = false;
if (prevent[P_USE_SOURCE_POLYGON_WINDING]) {
// GeoJSON winding is reversed from vector winding
reverse_ring = true;
} else if (prevent[P_REVERSE_SOURCE_POLYGON_WINDING]) {
// GeoJSON winding is reversed from vector winding
reverse_ring = false;
} else {
double area = get_area(ring, 0, ring.size());
if ((area > 0) != outer) {
reverse_ring = true;
}
}
if (reverse_ring) {
double area = get_area(ring, 0, ring.size());
if ((area > 0) != outer) {
drawvec tmp;
for (int a = ring.size() - 1; a >= 0; a--) {
tmp.push_back(ring[a]);
@ -1142,14 +1113,14 @@ drawvec stairstep(drawvec &geom, int z, int detail) {
double scale = 1 << (32 - detail - z);
for (size_t i = 0; i < geom.size(); i++) {
geom[i].x = std::floor(geom[i].x / scale);
geom[i].y = std::floor(geom[i].y / scale);
geom[i].x = std::round(geom[i].x / scale);
geom[i].y = std::round(geom[i].y / scale);
}
for (size_t i = 0; i < geom.size(); i++) {
if (geom[i].op == VT_MOVETO) {
out.push_back(geom[i]);
} else if (out.size() > 0) {
} else {
long long x0 = out[out.size() - 1].x;
long long y0 = out[out.size() - 1].y;
long long x1 = geom[i].x;
@ -1209,9 +1180,6 @@ drawvec stairstep(drawvec &geom, int z, int detail) {
}
// out.push_back(draw(VT_LINETO, xx, yy));
} else {
fprintf(stderr, "Can't happen: stairstepping lineto with no moveto\n");
exit(EXIT_FAILURE);
}
}

View File

@ -2,7 +2,6 @@
#define GEOMETRY_HPP
#include <vector>
#include <atomic>
#include <sqlite3.h>
#define VT_POINT 1
@ -56,7 +55,7 @@ struct draw {
typedef std::vector<draw> drawvec;
drawvec decode_geometry(FILE *meta, std::atomic<long long> *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y);
drawvec decode_geometry(FILE *meta, long long *geompos, int z, unsigned tx, unsigned ty, long long *bbox, unsigned initial_x, unsigned initial_y);
void to_tile_scale(drawvec &geom, int z, int detail);
drawvec remove_noop(drawvec geom, int type, int shift);
drawvec clip_point(drawvec &geom, int z, long long buffer);
@ -68,7 +67,7 @@ drawvec clip_lines(drawvec &geom, int z, long long buffer);
drawvec stairstep(drawvec &geom, int z, int detail);
bool point_within_tile(long long x, long long y, int z);
int quick_check(long long *bbox, int z, long long buffer);
drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds, double simplification, size_t retain, drawvec const &shared_nodes);
drawvec simplify_lines(drawvec &geom, int z, int detail, bool mark_tile_bounds, double simplification, size_t retain);
drawvec reorder_lines(drawvec &geom);
drawvec fix_polygon(drawvec &geom);
std::vector<drawvec> chop_polygon(std::vector<drawvec> &geoms);
@ -76,8 +75,4 @@ void check_polygon(drawvec &geom);
double get_area(drawvec &geom, size_t i, size_t j);
double get_mp_area(drawvec &geom);
drawvec simple_clip_poly(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
drawvec clip_lines(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
drawvec clip_point(drawvec &geom, long long x1, long long y1, long long x2, long long y2);
#endif

View File

@ -10,7 +10,6 @@
#include "jsonpull/jsonpull.h"
#include "csv.hpp"
#include "text.hpp"
#include "geojson-loop.hpp"
int fail = EXIT_SUCCESS;
bool wrap = false;
@ -19,7 +18,6 @@ const char *extract = NULL;
FILE *csvfile = NULL;
std::vector<std::string> header;
std::vector<std::string> fields;
int pe = false;
std::string buffered;
int buffered_type = -1;
@ -111,7 +109,7 @@ std::string sort_quote(const char *s) {
for (size_t i = 0; i < utf32.size(); i++) {
if (utf32[i] < 0xD800) {
char buf[8];
char buf[7];
sprintf(buf, "\\u%04lu", utf32[i]);
ret.append(std::string(buf));
} else {
@ -320,11 +318,7 @@ void join_csv(json_object *j) {
} else if (is_number(v)) {
attr_type = JSON_NUMBER;
}
} else if (pe) {
attr_type = JSON_NULL;
}
if (attr_type != JSON_NULL) {
// This knows more about the structure of JSON objects than it ought to
json_object *ko = (json_object *) malloc(sizeof(json_object));
@ -363,35 +357,70 @@ void join_csv(json_object *j) {
}
}
struct json_join_action : json_feature_action {
int add_feature(json_object *geometry, bool, json_object *, json_object *, json_object *, json_object *feature) {
if (feature != geometry) { // a real feature, not a bare geometry
if (csvfile != NULL) {
join_csv(feature);
}
char *s = json_stringify(feature);
out(s, 1, json_hash_get(feature, "properties"));
free(s);
} else {
char *s = json_stringify(geometry);
out(s, 2, NULL);
free(s);
}
return 1;
}
void check_crs(json_object *) {
}
};
void process(FILE *fp, const char *fname) {
json_pull *jp = json_begin_file(fp);
json_join_action jja;
jja.fname = fname;
parse_json(&jja, jp);
while (1) {
json_object *j = json_read(jp);
if (j == NULL) {
if (jp->error != NULL) {
fprintf(stderr, "%s:%d: %s\n", fname, jp->line, jp->error);
}
json_free(jp->root);
break;
}
json_object *type = json_hash_get(j, "type");
if (type == NULL || type->type != JSON_STRING) {
continue;
}
if (strcmp(type->string, "Feature") == 0) {
if (csvfile != NULL) {
join_csv(j);
}
char *s = json_stringify(j);
out(s, 1, json_hash_get(j, "properties"));
free(s);
json_free(j);
} else if (strcmp(type->string, "Point") == 0 ||
strcmp(type->string, "MultiPoint") == 0 ||
strcmp(type->string, "LineString") == 0 ||
strcmp(type->string, "MultiLineString") == 0 ||
strcmp(type->string, "MultiPolygon") == 0) {
int is_geometry = 1;
if (j->parent != NULL) {
if (j->parent->type == JSON_ARRAY && j->parent->parent != NULL) {
if (j->parent->parent->type == JSON_HASH) {
json_object *geometries = json_hash_get(j->parent->parent, "geometries");
if (geometries != NULL) {
// Parent of Parent must be a GeometryCollection
is_geometry = 0;
}
}
} else if (j->parent->type == JSON_HASH) {
json_object *geometry = json_hash_get(j->parent, "geometry");
if (geometry != NULL) {
// Parent must be a Feature
is_geometry = 0;
}
}
}
if (is_geometry) {
char *s = json_stringify(j);
out(s, 2, NULL);
free(s);
json_free(j);
}
} else if (strcmp(type->string, "FeatureCollection") == 0) {
json_free(j);
}
}
json_end(jp);
}
@ -402,8 +431,6 @@ int main(int argc, char **argv) {
{"wrap", no_argument, 0, 'w'},
{"extract", required_argument, 0, 'e'},
{"csv", required_argument, 0, 'c'},
{"empty-csv-columns-are-null", no_argument, &pe, 1},
{"prevent", required_argument, 0, 'p'},
{0, 0, 0, 0},
};
@ -424,9 +451,6 @@ int main(int argc, char **argv) {
while ((i = getopt_long(argc, argv, getopt_str.c_str(), long_options, NULL)) != -1) {
switch (i) {
case 0:
break;
case 'w':
wrap = true;
break;
@ -439,15 +463,6 @@ int main(int argc, char **argv) {
csv = optarg;
break;
case 'p':
if (strcmp(optarg, "e") == 0) {
pe = true;
} else {
fprintf(stderr, "%s: Unknown option for -p%s\n", argv[0], optarg);
exit(EXIT_FAILURE);
}
break;
default:
fprintf(stderr, "Unexpected option -%c\n", i);
exit(EXIT_FAILURE);

765
main.cpp

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,6 @@
#define MAIN_HPP
#include <stddef.h>
#include <atomic>
#include <string>
struct index {
long long start = 0;
@ -19,27 +17,11 @@ struct index {
}
};
struct clipbbox {
double lon1;
double lat1;
double lon2;
double lat2;
long long minx;
long long miny;
long long maxx;
long long maxy;
};
extern std::vector<clipbbox> clipbboxes;
void checkdisk(std::vector<struct reader> *r);
extern int geometry_scale;
extern int quiet;
extern int quiet_progress;
extern double progress_interval;
extern std::atomic<double> last_progress;
extern size_t CPUS;
extern size_t TEMP_FILES;
@ -47,11 +29,9 @@ extern size_t TEMP_FILES;
extern size_t max_tile_size;
extern size_t max_tile_features;
extern int cluster_distance;
extern std::string attribute_for_id;
int mkstemp_cloexec(char *name);
FILE *fopen_oflag(const char *name, const char *mode, int oflag);
bool progress_time();
#define MAX_ZOOM 24

View File

@ -3,10 +3,8 @@
Builds vector tilesets \[la]https://www.mapbox.com/developers/vector-tiles/\[ra] from large (or small) collections of GeoJSON \[la]http://geojson.org/\[ra], Geobuf \[la]https://github.com/mapbox/geobuf\[ra], or CSV \[la]https://en.wikipedia.org/wiki/Comma-separated_values\[ra] features,
like these \[la]MADE_WITH.md\[ra]\&.
.PP
[Mapbox Tippecanoe](\[la]https://user-images.githubusercontent.com/1951835/36568734-ede27ec0-17df-11e8-8c22-ffaaebb8daf4.JPG\[ra])
.PP
[Build Status](https://travis\-ci.org/mapbox/tippecanoe.svg) \[la]https://travis-ci.org/mapbox/tippecanoe\[ra]
[Coverage Status](https://codecov.io/gh/mapbox/tippecanoe/branch/master/graph/badge.svg) \[la]https://codecov.io/gh/mapbox/tippecanoe\[ra]
[Coverage Status](https://coveralls.io/repos/mapbox/tippecanoe/badge.svg?branch=master&service=github) \[la]https://coveralls.io/github/mapbox/tippecanoe?branch=master\[ra]
.SH Intent
.PP
The goal of Tippecanoe is to enable making a scale\-independent view of your data,
@ -35,26 +33,11 @@ The easiest way to install tippecanoe on OSX is with Homebrew \[la]http://brew.s
$ brew install tippecanoe
.fi
.RE
.PP
On Ubuntu it will usually be easiest to build from the source repository:
.PP
.RS
.nf
$ git clone https://github.com/mapbox/tippecanoe.git
$ cd tippecanoe
$ make \-j
$ make install
.fi
.RE
.PP
See Development \[la]#development\[ra] below for how to upgrade your
C++ compiler or install prerequisite packages if you get
compiler errors.
.SH Usage
.PP
.RS
.nf
$ tippecanoe \-o file.mbtiles [options] [file.json file.json.gz file.geobuf ...]
$ tippecanoe \-o file.mbtiles [options] [file.json file.geobuf ...]
.fi
.RE
.PP
@ -101,212 +84,6 @@ with a custom layer name and description, and leaving out the \fB\fCLINEARID\fR
$ cat tiger/tl_2014_*_roads.json | tippecanoe \-o tiger.mbtiles \-l roads \-n "All TIGER roads, one zoom" \-z12 \-Z12 \-d14 \-x LINEARID \-x RTTYP
.fi
.RE
.SH Cookbook
.SS Linear features (world railroads), visible at all zoom levels
.PP
.RS
.nf
curl \-L \-O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_railroads.zip
unzip ne_10m_railroads.zip
ogr2ogr \-f GeoJSON ne_10m_railroads.geojson ne_10m_railroads.shp
tippecanoe \-zg \-o ne_10m_railroads.mbtiles \-\-drop\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping ne_10m_railroads.geojson
.fi
.RE
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-drop\-densest\-as\-needed\fR: If the tiles are too big at low zoom levels, drop the least\-visible features to allow tiles to be created with those features that remain
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Discontinuous polygon features (buildings of Rhode Island), visible at all zoom levels
.PP
.RS
.nf
curl \-L \-O https://usbuildingdata.blob.core.windows.net/usbuildings\-v1\-1/RhodeIsland.zip
unzip RhodeIsland.zip
tippecanoe \-zg \-o RhodeIsland.mbtiles \-\-drop\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping RhodeIsland.geojson
.fi
.RE
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-drop\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, drop the least\-visible features to allow tiles to be created with those features that remain
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Continuous polygon features (states and provinces), visible at all zoom levels
.PP
.RS
.nf
curl \-L \-O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip \-o ne_10m_admin_1_states_provinces.zip
ogr2ogr \-f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe \-zg \-o ne_10m_admin_1_states_provinces.mbtiles \-\-coalesce\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping ne_10m_admin_1_states_provinces.geojson
.fi
.RE
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-coalesce\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Large point dataset (GPS bus locations), for visualization at all zoom levels
.PP
.RS
.nf
curl \-L \-O ftp://avl\-data.sfmta.com/avl_data/avl_raw/sfmtaAVLRawData01012013.csv
sed 's/PREDICTABLE.*/PREDICTABLE/' sfmtaAVLRawData01012013.csv > sfmta.csv
tippecanoe \-zg \-o sfmta.mbtiles \-\-drop\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping sfmta.csv
.fi
.RE
.PP
(The \fB\fCsed\fR line is to clean the corrupt CSV header, which contains the wrong number of fields.)
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-drop\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, drop the least\-visible features to allow tiles to be created with those features that remain
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Clustered points (world cities), summing the clustered population, visible at all zoom levels
.PP
.RS
.nf
curl \-L \-O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip
unzip \-o ne_10m_populated_places.zip
ogr2ogr \-f GeoJSON ne_10m_populated_places.geojson ne_10m_populated_places.shp
tippecanoe \-zg \-o ne_10m_populated_places.mbtiles \-r1 \-\-cluster\-distance=10 \-\-accumulate\-attribute=POP_MAX:sum ne_10m_populated_places.geojson
.fi
.RE
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-r1\fR: Do not automatically drop a fraction of points at low zoom levels, since clustering will be used instead
.IP \(bu 2
\fB\fC\-\-cluster\-distance=10\fR: Cluster together features that are closer than about 10 pixels from each other
.IP \(bu 2
\fB\fC\-\-accumulate\-attribute=POP_MAX:sum\fR: Sum the \fB\fCPOP_MAX\fR (population) attribute in features that are clustered together. Other attributes will be arbitrarily taken from the first feature in the cluster.
.RE
.SS Show countries at low zoom levels but states at higher zoom levels
.PP
.RS
.nf
curl \-L \-O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
unzip ne_10m_admin_0_countries.zip
ogr2ogr \-f GeoJSON ne_10m_admin_0_countries.geojson ne_10m_admin_0_countries.shp
curl \-L \-O https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip \-o ne_10m_admin_1_states_provinces.zip
ogr2ogr \-f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp
tippecanoe \-z3 \-o countries\-z3.mbtiles \-\-coalesce\-densest\-as\-needed ne_10m_admin_0_countries.geojson
tippecanoe \-zg \-Z4 \-o states\-Z4.mbtiles \-\-coalesce\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping ne_10m_admin_1_states_provinces.geojson
tile\-join \-o states\-countries.mbtiles countries\-z3.mbtiles states\-Z4.mbtiles
.fi
.RE
.PP
Countries:
.RS
.IP \(bu 2
\fB\fC\-z3\fR: Only generate zoom levels 0 through 3
.IP \(bu 2
\fB\fC\-\-coalesce\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
.RE
.PP
States and Provinces:
.RS
.IP \(bu 2
\fB\fC\-Z4\fR: Only generate zoom levels 4 and beyond
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-coalesce\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Represent multiple sources (Illinois and Indiana counties) as separate layers
.PP
.RS
.nf
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr \-f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr \-f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe \-zg \-o counties\-separate.mbtiles \-\-coalesce\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
.fi
.RE
.RS
.IP \(bu 2
\fB\fC\-zg\fR: Automatically choose a maxzoom that should be sufficient to clearly distinguish the features and the detail within each feature
.IP \(bu 2
\fB\fC\-\-coalesce\-densest\-as\-needed\fR: If the tiles are too big at low or medium zoom levels, merge as many features together as are necessary to allow tiles to be created with those features that are still distinguished
.IP \(bu 2
\fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: If even the tiles at high zoom levels are too big, keep adding zoom levels until one is reached that can represent all the features
.RE
.SS Merge multiple sources (Illinois and Indiana counties) into the same layer
.PP
.RS
.nf
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_17_county10.zip
unzip tl_2010_17_county10.zip
ogr2ogr \-f GeoJSON tl_2010_17_county10.geojson tl_2010_17_county10.shp
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/COUNTY/2010/tl_2010_18_county10.zip
unzip tl_2010_18_county10.zip
ogr2ogr \-f GeoJSON tl_2010_18_county10.geojson tl_2010_18_county10.shp
tippecanoe \-zg \-o counties\-merged.mbtiles \-l counties \-\-coalesce\-densest\-as\-needed \-\-extend\-zooms\-if\-still\-dropping tl_2010_17_county10.geojson tl_2010_18_county10.geojson
.fi
.RE
.PP
As above, but
.RS
.IP \(bu 2
\fB\fC\-l counties\fR: Specify the layer name instead of letting it be derived from the source file names
.RE
.SS Selectively remove and replace features (Census tracts) to update a tileset
.PP
.RS
.nf
# Retrieve and tile California 2000 Census tracts
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2000/tl_2010_06_tract00.zip
unzip tl_2010_06_tract00.zip
ogr2ogr \-f GeoJSON tl_2010_06_tract00.shp.json tl_2010_06_tract00.shp
tippecanoe \-z11 \-o tracts.mbtiles \-l tracts tl_2010_06_tract00.shp.json
# Create a copy of the tileset, minus Alameda County (FIPS code 001)
tile\-join \-j '{"*":["none",["==","COUNTYFP00","001"]]}' \-f \-o tracts\-filtered.mbtiles tracts.mbtiles
# Retrieve and tile Alameda County Census tracts for 2010
curl \-L \-O https://www2.census.gov/geo/tiger/TIGER2010/TRACT/2010/tl_2010_06001_tract10.zip
unzip tl_2010_06001_tract10.zip
ogr2ogr \-f GeoJSON tl_2010_06001_tract10.shp.json tl_2010_06001_tract10.shp
tippecanoe \-z11 \-o tracts\-added.mbtiles \-l tracts tl_2010_06001_tract10.shp.json
# Merge the filtered tileset and the tileset of new tracts into a final tileset
tile\-join \-o tracts\-final.mbtiles tracts\-filtered.mbtiles tracts\-added.mbtiles
.fi
.RE
.PP
The \fB\fC\-z11\fR option explicitly specifies the maxzoom, to make sure both the old and new tilesets have the same zoom range.
.PP
The \fB\fC\-j\fR option to \fB\fCtile\-join\fR specifies a filter, so that only the desired features will be copied to the new tileset.
This filter excludes (using \fB\fCnone\fR) any features whose FIPS code (\fB\fCCOUNTYFP00\fR) is the code for Alameda County (\fB\fC001\fR).
.SH Options
.PP
There are a lot of options. A lot of the time you won't want to use any of them
@ -355,8 +132,6 @@ or if metadata fields can't be set. You probably don't want to use this.
.IP \(bu 2
\fIname\fP\fB\fC\&.json\fR or \fIname\fP\fB\fC\&.geojson\fR: Read the named GeoJSON input file into a layer called \fIname\fP\&.
.IP \(bu 2
\fIname\fP\fB\fC\&.json.gz\fR or \fIname\fP\fB\fC\&.geojson.gz\fR: Read the named gzipped GeoJSON input file into a layer called \fIname\fP\&.
.IP \(bu 2
\fIname\fP\fB\fC\&.geobuf\fR: Read the named Geobuf input file into a layer called \fIname\fP\&.
.IP \(bu 2
\fIname\fP\fB\fC\&.csv\fR: Read the named CSV input file into a layer called \fIname\fP\&.
@ -365,14 +140,6 @@ or if metadata fields can't be set. You probably don't want to use this.
specified, the files are all merged into the single named layer, even if they try to specify individual names with \fB\fC\-L\fR\&.
.IP \(bu 2
\fB\fC\-L\fR \fIname\fP\fB\fC:\fR\fIfile.json\fP or \fB\fC\-\-named\-layer=\fR\fIname\fP\fB\fC:\fR\fIfile.json\fP: Specify layer names for individual files. If your shell supports it, you can use a subshell redirect like \fB\fC\-L\fR \fIname\fP\fB\fC:<(cat dir/*.json)\fR to specify a layer name for the output of streamed input.
.IP \(bu 2
\fB\fC\-L{\fR\fIlayer\-json\fP\fB\fC}\fR or \fB\fC\-\-named\-layer={\fR\fIlayer\-json\fP\fB\fC}\fR: Specify an input file and layer options by a JSON object. The JSON object must contain a \fB\fC"file"\fR key to specify the filename to read from. (If the \fB\fC"file"\fR key is an empty string, it means to read from the standard input stream.) It may also contain a \fB\fC"layer"\fR field to specify the name of the layer, and/or a \fB\fC"description"\fR field to specify the layer's description in the tileset metadata, and/or a \fB\fC"format"\fR field to specify \fB\fCcsv\fR or \fB\fCgeobuf\fR file format if it is not obvious from the \fB\fCname\fR\&. Example:
.RE
.PP
.RS
.nf
tippecanoe \-z5 \-o world.mbtiles \-L'{"file":"ne_10m_admin_0_countries.json", "layer":"countries", "description":"Natural Earth countries"}'
.fi
.RE
.PP
CSV input files currently support only Point geometries, from columns named \fB\fClatitude\fR, \fB\fClongitude\fR, \fB\fClat\fR, \fB\fClon\fR, \fB\fClong\fR, \fB\fClng\fR, \fB\fCx\fR, or \fB\fCy\fR\&.
@ -409,52 +176,7 @@ Parallel processing will also be automatic if the input file is in Geobuf format
\fB\fC\-ae\fR or \fB\fC\-\-extend\-zooms\-if\-still\-dropping\fR: Increase the maxzoom if features are still being dropped at that zoom level.
The detail and simplification options that ordinarily apply only to the maximum zoom level will apply both to the originally
specified maximum zoom and to any levels added beyond that.
.IP \(bu 2
\fB\fC\-R\fR \fIzoom\fP\fB\fC/\fR\fIx\fP\fB\fC/\fR\fIy\fP or \fB\fC\-\-one\-tile=\fR\fIzoom\fP\fB\fC/\fR\fIx\fP\fB\fC/\fR\fIy\fP: Set the minzoom and maxzoom to \fIzoom\fP and produce only
the single specified tile at that zoom level.
.RE
.PP
If you know the precision to which you want your data to be represented,
this table shows the approximate precision corresponding to various
\fB\fC\-z\fR options if you use the default \fB\fC\-d\fR detail of 12:
.TS
allbox;
cb cb cb
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
l l l
.
zoom level precision (ft) precision (m)
\fB\fC\-z0\fR 32000 ft 10000 m
\fB\fC\-z1\fR 16000 ft 5000 m
\fB\fC\-z2\fR 8000 ft 2500 m
\fB\fC\-z3\fR 4000 ft 1250 m
\fB\fC\-z4\fR 2000 ft 600 m
\fB\fC\-z5\fR 1000 ft 300 m
\fB\fC\-z6\fR 500 ft 150 m
\fB\fC\-z7\fR 250 ft 80 m
\fB\fC\-z8\fR 125 ft 40 m
\fB\fC\-z9\fR 64 ft 20 m
\fB\fC\-z10\fR 32 ft 10 m
\fB\fC\-z11\fR 16 ft 5 m
\fB\fC\-z12\fR 8 ft 2 m
\fB\fC\-z13\fR 4 ft 1 m
\fB\fC\-z14\fR 2 ft 0.5 m
\fB\fC\-z15\fR 1 ft 0.25 m
.TE
.SS Tile resolution
.RS
.IP \(bu 2
@ -471,14 +193,11 @@ resolution is obtained than by using a smaller \fImaxzoom\fP or \fIdetail\fP\&.
.SS Filtering feature attributes
.RS
.IP \(bu 2
\fB\fC\-x\fR \fIname\fP or \fB\fC\-\-exclude=\fR\fIname\fP: Exclude the named attributes from all features. You can specify multiple \fB\fC\-x\fR options to exclude several attributes. (Don't comma\-separate names within a single \fB\fC\-x\fR\&.)
\fB\fC\-x\fR \fIname\fP or \fB\fC\-\-exclude=\fR\fIname\fP: Exclude the named properties from all features
.IP \(bu 2
\fB\fC\-y\fR \fIname\fP or \fB\fC\-\-include=\fR\fIname\fP: Include the named attributes in all features, excluding all those not explicitly named. You can specify multiple \fB\fC\-y\fR options to explicitly include several attributes. (Don't comma\-separate names within a single \fB\fC\-y\fR\&.)
\fB\fC\-y\fR \fIname\fP or \fB\fC\-\-include=\fR\fIname\fP: Include the named properties in all features, excluding all those not explicitly named
.IP \(bu 2
\fB\fC\-X\fR or \fB\fC\-\-exclude\-all\fR: Exclude all attributes and encode only geometries
.RE
.SS Modifying feature attributes
.RS
\fB\fC\-X\fR or \fB\fC\-\-exclude\-all\fR: Exclude all properties and encode only geometries
.IP \(bu 2
\fB\fC\-T\fR\fIattribute\fP\fB\fC:\fR\fItype\fP or \fB\fC\-\-attribute\-type=\fR\fIattribute\fP\fB\fC:\fR\fItype\fP: Coerce the named feature \fIattribute\fP to be of the specified \fItype\fP\&.
The \fItype\fP may be \fB\fCstring\fR, \fB\fCfloat\fR, \fB\fCint\fR, or \fB\fCbool\fR\&.
@ -486,23 +205,7 @@ If the type is \fB\fCbool\fR, then original attributes of \fB\fC0\fR (or, if num
If the type is \fB\fCfloat\fR or \fB\fCint\fR and the original attribute was non\-numeric, it becomes \fB\fC0\fR\&.
If the type is \fB\fCint\fR and the original attribute was floating\-point, it is rounded to the nearest integer.
.IP \(bu 2
\fB\fC\-Y\fR\fIattribute\fP\fB\fC:\fR\fIdescription\fP or \fB\fC\-\-attribute\-description=\fR\fIattribute\fP\fB\fC:\fR\fIdescription\fP: Set the \fB\fCdescription\fR for the specified attribute in the tileset metadata to \fIdescription\fP instead of the usual \fB\fCString\fR, \fB\fCNumber\fR, or \fB\fCBoolean\fR\&.
.IP \(bu 2
\fB\fC\-E\fR\fIattribute\fP\fB\fC:\fR\fIoperation\fP or \fB\fC\-\-accumulate\-attribute=\fR\fIattribute\fP\fB\fC:\fR\fIoperation\fP: Preserve the named \fIattribute\fP from features
that are dropped, coalesced\-as\-needed, or clustered. The \fIoperation\fP may be
\fB\fCsum\fR, \fB\fCproduct\fR, \fB\fCmean\fR, \fB\fCmax\fR, \fB\fCmin\fR, \fB\fCconcat\fR, or \fB\fCcomma\fR
to specify how the named \fIattribute\fP is accumulated onto the attribute of the same name in a feature that does survive.
.IP \(bu 2
\fB\fC\-pe\fR or \fB\fC\-\-empty\-csv\-columns\-are\-null\fR: Treat empty CSV columns as nulls rather than as empty strings.
.IP \(bu 2
\fB\fC\-aI\fR or \fB\fC\-\-convert\-stringified\-ids\-to\-numbers\fR: If a feature ID is the string representation of a number, convert it to a plain number to use as the feature ID.
.IP \(bu 2
\fB\fC\-\-use\-attribute\-for\-id=\fR\fIname\fP: Use the attribute with the specified \fIname\fP as if it were specified as the feature ID. (If this attribute is a stringified number, you must also use \fB\fC\-aI\fR to convert it to a number.)
.RE
.SS Filtering features by attributes
.RS
.IP \(bu 2
\fB\fC\-j\fR \fIfilter\fP or \fB\fC\-\-feature\-filter\fR=\fIfilter\fP: Check features against a per\-layer filter (as defined in the Mapbox GL Style Specification \[la]https://docs.mapbox.com/mapbox-gl-js/style-spec/#other-filter\[ra]) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer \fB\fC"*"\fR apply to all layers. The special variable \fB\fC$zoom\fR refers to the current zoom level.
\fB\fC\-j\fR \fIfilter\fP or \fB\fC\-\-feature\-filter\fR=\fIfilter\fP: Check features against a per\-layer filter (as defined in the Mapbox GL Style Specification \[la]https://www.mapbox.com/mapbox-gl-js/style-spec/#types-filter\[ra]) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer \fB\fC"*"\fR apply to all layers.
.IP \(bu 2
\fB\fC\-J\fR \fIfilter\-file\fP or \fB\fC\-\-feature\-filter\-file\fR=\fIfilter\-file\fP: Like \fB\fC\-j\fR, but read the filter from a file.
.RE
@ -514,27 +217,6 @@ Example: to find the Natural Earth countries with low \fB\fCscalerank\fR but hig
tippecanoe \-z5 \-o filtered.mbtiles \-j '{ "ne_10m_admin_0_countries": [ "all", [ "<", "scalerank", 3 ], [ ">", "LABELRANK", 5 ] ] }' ne_10m_admin_0_countries.geojson
.fi
.RE
.PP
Example: to retain only major TIGER roads at low zoom levels:
.PP
.RS
.nf
tippecanoe \-o roads.mbtiles \-j '{ "*": [ "any", [ ">=", "$zoom", 11 ], [ "in", "MTFCC", "S1100", "S1200" ] ] }' tl_2015_06001_roads.json
.fi
.RE
.PP
Tippecanoe also accepts expressions of the form \fB\fC[ "attribute\-filter", name, expression ]\fR, to filter individual feature attributes
instead of entire features. For example, you can exclude the road names at low zoom levels by doing
.PP
.RS
.nf
tippecanoe \-o roads.mbtiles \-j '{ "*": [ "attribute\-filter", "FULLNAME", [ ">=", "$zoom", 9 ] ] }' tl_2015_06001_roads.json
.fi
.RE
.PP
An \fB\fCattribute\-filter\fR expression itself is always considered to evaluate to \fB\fCtrue\fR (in other words, to retain the feature instead
of dropping it). If you want to use multiple \fB\fCattribute\-filter\fR expressions, or to use other expressions to remove features from
the same layer, enclose them in an \fB\fCall\fR expression so they will all be evaluated.
.SS Dropping a fixed fraction of features by zoom level
.RS
.IP \(bu 2
@ -552,7 +234,7 @@ compensate for the larger marker, or \fB\fC\-Bf\fR\fInumber\fP to allow at most
.IP \(bu 2
\fB\fC\-ap\fR or \fB\fC\-\-drop\-polygons\fR: Let "dot" dropping at lower zooms apply to polygons too
.IP \(bu 2
\fB\fC\-K\fR \fIdistance\fP or \fB\fC\-\-cluster\-distance=\fR\fIdistance\fP: Cluster points (as with \fB\fC\-\-cluster\-densest\-as\-needed\fR, but without the experimental discovery process) that are approximately within \fIdistance\fP of each other. The units are tile coordinates within a nominally 256\-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 10 are probably appropriate for typical marker sizes. See \fB\fC\-\-cluster\-densest\-as\-needed\fR below for behavior.
\fB\fC\-K\fR \fIdistance\fP or \fB\fC\-\-cluster\-distance=\fR\fIdistance\fP: Cluster points (as with \fB\fC\-\-cluster\-densest\-as\-needed\fR, but without the experimental discovery process) that are approximately within \fIdistance\fP of each other. The units are tile coordinates within a nominally 256\-pixel tile, so the maximum value of 255 allows only one feature per tile. Values around 20 are probably appropriate for typical marker sizes.
.RE
.SS Dropping a fraction of features to keep under tile size limits
.RS
@ -563,15 +245,11 @@ compensate for the larger marker, or \fB\fC\-Bf\fR\fInumber\fP to allow at most
.IP \(bu 2
\fB\fC\-an\fR or \fB\fC\-\-drop\-smallest\-as\-needed\fR: 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
\fB\fC\-aN\fR or \fB\fC\-\-coalesce\-smallest\-as\-needed\fR: Dynamically combine the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level into other nearby features to keep large tiles under the 500K size limit. This option will not work for point features, and will probably not help very much with LineStrings. It is mostly intended for polygons, to maintain the full original area covered by polygons while still reducing the feature count somehow. The attributes of the small polygons are \fInot\fP preserved into the combined features (except through \fB\fC\-\-accumulate\-attribute\fR), only their geometry. Furthermore, the polygons to which nested polygons are coalesced may not necessarily be the immediately enclosing features.
.IP \(bu 2
\fB\fC\-aD\fR or \fB\fC\-\-coalesce\-densest\-as\-needed\fR: Dynamically combine the densest features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)
.IP \(bu 2
\fB\fC\-aS\fR or \fB\fC\-\-coalesce\-fraction\-as\-needed\fR: Dynamically combine a fraction of features from each zoom level into other nearby features to keep large tiles under the 500K size limit. (Again, mostly useful for polygons.)
\fB\fC\-aN\fR or \fB\fC\-\-coalesce\-smallest\-as\-needed\fR: Dynamically combine the smallest features (physically smallest: the shortest lines or the smallest polygons) from each zoom level into other nearby features to keep large tiles under the 500K size limit. This option will not work for point features, and will probably not help very much with LineStrings. It is mostly intended for polygons, to maintain the full original area covered by polygons while still reducing the feature count somehow. The attributes of the small polygons are \fInot\fP preserved into the combined features, only their geometry.
.IP \(bu 2
\fB\fC\-pd\fR or \fB\fC\-\-force\-feature\-limit\fR: Dynamically drop some fraction of features from large tiles to keep them under the 500K size limit. It will probably look ugly at the tile boundaries. (This is like \fB\fC\-ad\fR but applies to each tile individually, not to the entire zoom level.) You probably don't want to use this.
.IP \(bu 2
\fB\fC\-aC\fR or \fB\fC\-\-cluster\-densest\-as\-needed\fR: If a tile is too large, try to reduce its size by increasing the minimum spacing between features, and leaving one placeholder feature from each group. The remaining feature will be given a \fB\fC"cluster": true\fR attribute to indicate that it represents a cluster, a \fB\fC"point_count"\fR attribute to indicate the number of features that were clustered into it, and a \fB\fC"sqrt_point_count"\fR attribute to indicate the relative width of a feature to represent the cluster. If the features being clustered are points, the representative feature will be located at the average of the original points' locations; otherwise, one of the original features will be left as the representative.
\fB\fC\-aC\fR or \fB\fC\-\-cluster\-densest\-as\-needed\fR: If a tile is too large, try to reduce its size by increasing the minimum spacing between features, and leaving one placeholder feature from each group. The remaining feature will be given a \fB\fC"cluster": true\fR attribute to indicate that it represents a cluster and a \fB\fC"point_count"\fR attribute to indicate the number of features that were clustered into it.
.RE
.SS Dropping tightly overlapping features
.RS
@ -613,31 +291,21 @@ the line or polygon within one tile unit of its proper location. You can probabl
.IP \(bu 2
\fB\fC\-pi\fR or \fB\fC\-\-preserve\-input\-order\fR: 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 \fB\fC\-ao\fR).
.IP \(bu 2
\fB\fC\-ac\fR or \fB\fC\-\-coalesce\fR: Coalesce consecutive features that have the same attributes. This can be useful if you have lots of small polygons with identical attributes and you would like to merge them together.
\fB\fC\-ao\fR or \fB\fC\-\-reorder\fR: Reorder features to put ones with the same properties in sequence, to try to get them to coalesce. You probably want to use this if you use \fB\fC\-\-coalesce\fR\&.
.IP \(bu 2
\fB\fC\-ao\fR or \fB\fC\-\-reorder\fR: Reorder features to put ones with the same attributes in sequence (instead of ones that are approximately spatially adjacent), to try to get them to coalesce. You probably want to use this if you use \fB\fC\-\-coalesce\fR\&.
\fB\fC\-ac\fR or \fB\fC\-\-coalesce\fR: Coalesce adjacent line and polygon features that have the same properties. This can be useful if you have lots of small polygons with identical attributes and you would like to merge them together.
.IP \(bu 2
\fB\fC\-ar\fR or \fB\fC\-\-reverse\fR: Try reversing the directions of lines to make them coalesce and compress better. You probably don't want to use this.
.IP \(bu 2
\fB\fC\-ah\fR or \fB\fC\-\-hilbert\fR: Put features in Hilbert Curve order instead of the usual Z\-Order. This improves the odds that spatially adjacent features will be sequentially adjacent, and should improve density calculations and spatial coalescing. It should be the default eventually.
.RE
.SS Adding calculated attributes
.RS
.IP \(bu 2
\fB\fC\-ag\fR or \fB\fC\-\-calculate\-feature\-density\fR: Add a new attribute, \fB\fCtippecanoe_feature_density\fR, to each feature, to record how densely features are spaced in that area of the tile. You can use this attribute in the style to produce a glowing effect where points are densely packed. It can range from 0 in the sparsest areas to 255 in the densest.
.IP \(bu 2
\fB\fC\-ai\fR or \fB\fC\-\-generate\-ids\fR: Add an \fB\fCid\fR (a feature ID, not an attribute named \fB\fCid\fR) to each feature that does not already have one. There is currently no guarantee that the \fB\fCid\fR added will be stable between runs or that it will not conflict with manually\-assigned feature IDs. Future versions of Tippecanoe may change the mechanism for allocating IDs.
.RE
.SS Trying to correct bad source geometry
.RS
.IP \(bu 2
\fB\fC\-aw\fR or \fB\fC\-\-detect\-longitude\-wraparound\fR: Detect when consecutive points within a feature jump to the other side of the world, and try to fix the geometry.
.IP \(bu 2
\fB\fC\-pw\fR or \fB\fC\-\-use\-source\-polygon\-winding\fR: Instead of respecting GeoJSON polygon ring order, use the original polygon winding in the source data to distinguish inner (clockwise) and outer (counterclockwise) polygon rings.
.IP \(bu 2
\fB\fC\-pW\fR or \fB\fC\-\-reverse\-source\-polygon\-winding\fR: Instead of respecting GeoJSON polygon ring order, use the opposite of the original polygon winding in the source data to distinguish inner (counterclockwise) and outer (clockwise) polygon rings.
.IP \(bu 2
\fB\fC\-\-clip\-bounding\-box=\fR\fIminlon\fP\fB\fC,\fR\fIminlat\fP\fB\fC,\fR\fImaxlon\fP\fB\fC,\fR\fImaxlat\fP: Clip all features to the specified bounding box.
\fB\fC\-aw\fR or \fB\fC\-\-detect\-longitude\-wraparound\fR: Detect when adjacent points within a feature jump to the other side of the world, and try to fix the geometry.
.RE
.SS Setting or disabling tile size limits
.RS
@ -653,12 +321,6 @@ the line or polygon within one tile unit of its proper location. You can probabl
\fB\fC\-pC\fR or \fB\fC\-\-no\-tile\-compression\fR: Don't compress the PBF vector tile data.
.IP \(bu 2
\fB\fC\-pg\fR or \fB\fC\-\-no\-tile\-stats\fR: Don't generate the \fB\fCtilestats\fR row in the tileset metadata. Uploads without tilestats \[la]https://github.com/mapbox/mapbox-geostats\[ra] will take longer to process.
.IP \(bu 2
\fB\fC\-\-tile\-stats\-attributes\-limit=\fR\fIcount\fP: Include \fB\fCtilestats\fR information about at most \fIcount\fP attributes instead of the default 1000.
.IP \(bu 2
\fB\fC\-\-tile\-stats\-sample\-values\-limit=\fR\fIcount\fP: Calculate \fB\fCtilestats\fR attribute statistics based on \fIcount\fP values instead of the default 1000.
.IP \(bu 2
\fB\fC\-\-tile\-stats\-values\-limit=\fR\fIcount\fP: Report \fIcount\fP unique attribute values in \fB\fCtilestats\fR instead of the default 100.
.RE
.SS Temporary storage
.RS
@ -673,8 +335,6 @@ If you don't specify, it will use \fB\fC/tmp\fR\&.
.IP \(bu 2
\fB\fC\-Q\fR or \fB\fC\-\-no\-progress\-indicator\fR: Don't report progress, but still give warnings
.IP \(bu 2
\fB\fC\-U\fR \fIseconds\fP or \fB\fC\-\-progress\-interval=\fR\fIseconds\fP: Don't report progress more often than the specified number of \fIseconds\fP\&.
.IP \(bu 2
\fB\fC\-v\fR or \fB\fC\-\-version\fR: Report Tippecanoe's version number
.RE
.SS Filters
@ -699,7 +359,7 @@ The postfilter receives the features at tile resolution, after simplification, c
.PP
The layer name is provided as part of the \fB\fCtippecanoe\fR element of the feature and must be passed through
to keep the feature in its correct layer. In the case of the prefilter, the \fB\fCtippecanoe\fR element may also
contain \fB\fCindex\fR, \fB\fCsequence\fR, \fB\fCextent\fR, and \fB\fCdropped\fR, elements, which must be passed through for internal operations like
contain \fB\fCindex\fR, \fB\fCsequence\fR, and \fB\fCextent\fR elements, which must be passed through for internal operations like
\fB\fC\-\-drop\-densest\-as\-needed\fR, \fB\fC\-\-drop\-smallest\-as\-needed\fR, and \fB\fC\-\-preserve\-input\-order\fR to work.
.SS Examples:
.RS
@ -781,14 +441,6 @@ the filename or name specified using \fB\fC\-\-layer\fR, like this:
}
.fi
.RE
.PP
If your source GeoJSON only has \fB\fCminzoom\fR, \fB\fCmaxzoom\fR and/or \fB\fClayer\fR within \fB\fCproperties\fR you can use ndjson\-cli \[la]https://github.com/mbostock/ndjson-cli/blob/master/README.md\[ra] to move them into the required \fB\fCtippecanoe\fR object by piping the GeoJSON like this:
.PP
.RS
.nf
ndjson\-map 'd.tippecanoe = { minzoom: d.properties.minzoom, maxzoom: d.properties.maxzoom, layer: d.properties.layer }, delete d.properties.minzoom, delete d.properties.maxzoom, delete d.properties.layer, d'
.fi
.RE
.SH Geometric simplifications
.PP
At every zoom level, line and polygon features are subjected to Douglas\-Peucker
@ -816,7 +468,7 @@ all of them should have had together.
.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 attributes to reduce wasted file size.
any unnecessary properties to reduce wasted file size.
.PP
If a tile is larger than 500K, it will try encoding that tile at progressively
lower resolutions before failing if it still doesn't fit.
@ -944,15 +596,11 @@ The options are:
.IP \(bu 2
\fB\fC\-x\fR \fIkey\fP or \fB\fC\-\-exclude=\fR\fIkey\fP: Remove attributes of type \fIkey\fP from the output. You can use this to remove the field you are matching against if you no longer need it after joining, or to remove any other attributes you don't want.
.IP \(bu 2
\fB\fC\-X\fR or \fB\fC\-\-exclude\-all\fR: Remove all attributes from the output.
.IP \(bu 2
\fB\fC\-i\fR or \fB\fC\-\-if\-matched\fR: Only include features that matched the CSV.
.IP \(bu 2
\fB\fC\-j\fR \fIfilter\fP or \fB\fC\-\-feature\-filter\fR=\fIfilter\fP: Check features against a per\-layer filter (as defined in the Mapbox GL Style Specification \[la]https://docs.mapbox.com/mapbox-gl-js/style-spec/#other-filter\[ra]) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer \fB\fC"*"\fR apply to all layers.
\fB\fC\-j\fR \fIfilter\fP or \fB\fC\-\-feature\-filter\fR=\fIfilter\fP: Check features against a per\-layer filter (as defined in the Mapbox GL Style Specification \[la]https://www.mapbox.com/mapbox-gl-js/style-spec/#types-filter\[ra]) and only include those that match. Any features in layers that have no filter specified will be passed through. Filters for the layer \fB\fC"*"\fR apply to all layers.
.IP \(bu 2
\fB\fC\-J\fR \fIfilter\-file\fP or \fB\fC\-\-feature\-filter\-file\fR=\fIfilter\-file\fP: Like \fB\fC\-j\fR, but read the filter from a file.
.IP \(bu 2
\fB\fC\-pe\fR or \fB\fC\-\-empty\-csv\-columns\-are\-null\fR: Treat empty CSV columns as nulls rather than as empty strings.
.RE
.SS Setting or disabling tile size limits
.RS
@ -1053,7 +701,7 @@ tippecanoe\-decode file.vector.pbf zoom x y
.fi
.RE
.PP
Unless you use \fB\fC\-c\fR, the output is a set of nested FeatureCollections identifying each
If you decode an entire file, you get a nested \fB\fCFeatureCollection\fR identifying each
tile and layer separately. Note that the same features generally appear at all zooms,
so the output for the file will have many copies of the same features at different
resolutions.
@ -1106,9 +754,7 @@ something better.
The formatting makes excessive use of \fB\fC\\u\fR quoting so that it follows JSON string rules but will still
be sorted correctly by tools that just do ASCII comparisons.
.IP \(bu 2
\fB\fC\-c\fR \fIfile.csv\fP or \fB\fC\-\-csv=\fR\fIfile.csv\fP: Join attributes from the named sorted CSV file, using its first column as the join key. Geometries will be passed through even if they do not match the CSV; CSV lines that do not match a geometry will be discarded.
.IP \(bu 2
\fB\fC\-pe\fR or \fB\fC\-\-empty\-csv\-columns\-are\-null\fR: Treat empty CSV columns as nulls rather than as empty strings.
\fB\fC\-c\fR \fIfile.csv\fP or \fB\fC\-\-csv=\fR\fIfile.csv\fP: Join properties from the named sorted CSV file, using its first column as the join key. Geometries will be passed through even if they do not match the CSV; CSV lines that do not match a geometry will be discarded.
.RE
.SS Example
.PP
@ -1143,7 +789,7 @@ $ tippecanoe\-json\-tool \-e GEOID10 tl_2010_18157_tabblock10.json | LC_ALL=C so
.fi
.RE
.PP
Join block geometries to employment attributes:
Join block geometries to employment properties:
.PP
.RS
.nf

View File

@ -1,4 +1,4 @@
Parts of the code in the Wagyu Library are derived from the version of the
Parts of the code in the Wagyu Library are derived from the version of the
Clipper Library by Angus Johnson listed below.
Author : Angus Johnson
@ -6,15 +6,13 @@ Version : 6.4.0
Date : 2 July 2015
Website : http://www.angusj.com
Copyright for portions of the derived code in the Wagyu library are held
by Angus Johnson, 2010-2015. Copyright for the "include/mapbox/geometry/wagyu/almost_equal.hpp"
file is held by Google Inc and its license is listed at the top of that file.
All other copyright for the Wagyu Library are held by Mapbox, 2016. This code
is published in accordance with, and retains the same license as the Clipper
Library by Angus Johnson.
Copyright for portions of the derived code in the Wagyu library are held
by Angus Johnson, 2010-2015. All other copyright for the Wagyu Library are held by
Mapbox, 2016. This code is published in accordance with, and retains the same license
as the Clipper Library by Angus Johnson.
Copyright (c) 2010-2015, Angus Johnson
Copyright (c) 2016-2020, Mapbox
Copyright (c) 2016, Mapbox
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by

View File

@ -19,7 +19,7 @@ namespace geometry {
namespace wagyu {
template <typename T>
using active_bound_list = std::vector<bound_ptr<T>>;
using active_bound_list = std::list<bound_ptr<T>>;
template <typename T>
using active_bound_list_itr = typename active_bound_list<T>::iterator;
@ -61,7 +61,9 @@ std::string output_edges(active_bound_list<T> const& bnds) {
#endif
template <typename T>
bool is_even_odd_fill_type(bound<T> const& bound, fill_type subject_fill_type, fill_type clip_fill_type) {
bool is_even_odd_fill_type(bound<T> const& bound,
fill_type subject_fill_type,
fill_type clip_fill_type) {
if (bound.poly_type == polygon_type_subject) {
return subject_fill_type == fill_type_even_odd;
} else {
@ -70,7 +72,9 @@ bool is_even_odd_fill_type(bound<T> const& bound, fill_type subject_fill_type, f
}
template <typename T>
bool is_even_odd_alt_fill_type(bound<T> const& bound, fill_type subject_fill_type, fill_type clip_fill_type) {
bool is_even_odd_alt_fill_type(bound<T> const& bound,
fill_type subject_fill_type,
fill_type clip_fill_type) {
if (bound.poly_type == polygon_type_subject) {
return clip_fill_type == fill_type_even_odd;
} else {
@ -79,92 +83,107 @@ bool is_even_odd_alt_fill_type(bound<T> const& bound, fill_type subject_fill_typ
}
template <typename T>
struct bound_insert_location {
bound<T> const& bound2;
bound_insert_location(bound<T> const& b) : bound2(b) {
}
bool operator()(bound_ptr<T> const& b) {
auto const& bound1 = *b;
if (values_are_equal(bound2.current_x, bound1.current_x)) {
if (bound2.current_edge->top.y > bound1.current_edge->top.y) {
return less_than(static_cast<double>(bound2.current_edge->top.x),
get_current_x(*(bound1.current_edge), bound2.current_edge->top.y));
} else {
return greater_than(static_cast<double>(bound1.current_edge->top.x),
get_current_x(*(bound2.current_edge), bound1.current_edge->top.y));
}
inline bool bound2_inserts_before_bound1(bound<T> const& bound1, bound<T> const& bound2) {
if (values_are_equal(bound2.current_x, bound1.current_x)) {
if (bound2.current_edge->top.y > bound1.current_edge->top.y) {
return bound2.current_edge->top.x <
get_current_x(*(bound1.current_edge), bound2.current_edge->top.y);
} else {
return bound2.current_x < bound1.current_x;
return bound1.current_edge->top.x >
get_current_x(*(bound2.current_edge), bound1.current_edge->top.y);
}
} else {
return bound2.current_x < bound1.current_x;
}
};
template <typename T>
active_bound_list_itr<T> insert_bound_into_ABL(bound<T>& left, bound<T>& right, active_bound_list<T>& active_bounds) {
auto itr = std::find_if(active_bounds.begin(), active_bounds.end(), bound_insert_location<T>(left));
#ifdef GCC_MISSING_VECTOR_RANGE_INSERT
itr = active_bounds.insert(itr, &right);
return active_bounds.insert(itr, &left);
#else
return active_bounds.insert(itr, { &left, &right });
#endif
}
template <typename T>
inline bool is_maxima(bound<T> const& bnd, T y) {
active_bound_list_itr<T> insert_bound_into_ABL(bound<T>& bnd, active_bound_list<T>& active_bounds) {
auto itr = active_bounds.begin();
while (itr != active_bounds.end() && !bound2_inserts_before_bound1(*(*itr), bnd)) {
++itr;
}
return active_bounds.insert(itr, &bnd);
}
template <typename T>
active_bound_list_itr<T> insert_bound_into_ABL(bound<T>& bnd,
active_bound_list_itr<T> itr,
active_bound_list<T>& active_bounds) {
while (itr != active_bounds.end() && !bound2_inserts_before_bound1(*(*itr), bnd)) {
++itr;
}
return active_bounds.insert(itr, &bnd);
}
template <typename T>
inline bool is_maxima(bound<T>& bnd, T y) {
return bnd.next_edge == bnd.edges.end() && bnd.current_edge->top.y == y;
}
template <typename T>
inline bool is_maxima(active_bound_list_itr<T> const& bnd, T y) {
inline bool is_maxima(active_bound_list_itr<T>& bnd, T y) {
return is_maxima(*(*bnd), y);
}
template <typename T>
inline bool is_intermediate(bound<T> const& bnd, T y) {
inline bool is_intermediate(bound<T>& bnd, T y) {
return bnd.next_edge != bnd.edges.end() && bnd.current_edge->top.y == y;
}
template <typename T>
inline bool is_intermediate(active_bound_list_itr<T> const& bnd, T y) {
inline bool is_intermediate(active_bound_list_itr<T>& bnd, T y) {
return is_intermediate(*(*bnd), y);
}
template <typename T>
inline bool current_edge_is_horizontal(active_bound_list_itr<T> const& bnd) {
inline bool current_edge_is_horizontal(active_bound_list_itr<T>& bnd) {
return is_horizontal(*((*bnd)->current_edge));
}
template <typename T>
inline bool next_edge_is_horizontal(active_bound_list_itr<T> const& bnd) {
inline bool next_edge_is_horizontal(active_bound_list_itr<T>& bnd) {
return is_horizontal(*((*bnd)->next_edge));
}
template <typename T>
void next_edge_in_bound(bound<T>& bnd, scanbeam_list<T>& scanbeam) {
auto& current_edge = bnd.current_edge;
++current_edge;
if (current_edge != bnd.edges.end()) {
++(bnd.next_edge);
bnd.current_x = static_cast<double>(current_edge->bot.x);
if (!is_horizontal<T>(*current_edge)) {
insert_sorted_scanbeam(scanbeam, current_edge->top.y);
inline void swap_positions_in_ABL(active_bound_list_itr<T>& bnd1,
active_bound_list_itr<T>& bnd2,
active_bound_list<T>& active_bounds) {
if (std::next(bnd2) == bnd1) {
active_bounds.splice(bnd2, active_bounds, bnd1);
} else {
active_bounds.splice(bnd1, active_bounds, bnd2);
}
}
template <typename T>
void next_edge_in_bound(active_bound_list_itr<T>& bnd, scanbeam_list<T>& scanbeam) {
++((*bnd)->current_edge);
if ((*bnd)->current_edge != (*bnd)->edges.end()) {
++((*bnd)->next_edge);
(*bnd)->current_x = static_cast<double>((*bnd)->current_edge->bot.x);
if (!current_edge_is_horizontal<T>(bnd)) {
scanbeam.push((*bnd)->current_edge->top.y);
}
}
}
template <typename T>
active_bound_list_itr<T> get_maxima_pair(active_bound_list_itr<T> bnd, active_bound_list<T>& active_bounds) {
bound_ptr<T> maximum = (*bnd)->maximum_bound;
return std::find(active_bounds.begin(), active_bounds.end(), maximum);
active_bound_list_itr<T> get_maxima_pair(active_bound_list_itr<T> bnd,
active_bound_list<T>& active_bounds) {
auto bnd_itr = active_bounds.begin();
while (bnd_itr != active_bounds.end()) {
if (*bnd_itr == (*bnd)->maximum_bound) {
break;
}
++bnd_itr;
}
return bnd_itr;
}
template <typename T>
void set_winding_count(active_bound_list_itr<T> bnd_itr,
void set_winding_count(active_bound_list_itr<T>& bnd_itr,
active_bound_list<T>& active_bounds,
fill_type subject_fill_type,
fill_type clip_fill_type) {
@ -178,7 +197,8 @@ void set_winding_count(active_bound_list_itr<T> bnd_itr,
// find the edge of the same polytype that immediately preceeds 'edge' in
// AEL
while (rev_bnd_itr != active_bounds.rend() && (*rev_bnd_itr)->poly_type != (*bnd_itr)->poly_type) {
while (rev_bnd_itr != active_bounds.rend() &&
(*rev_bnd_itr)->poly_type != (*bnd_itr)->poly_type) {
++rev_bnd_itr;
}
if (rev_bnd_itr == active_bounds.rend()) {
@ -200,7 +220,8 @@ void set_winding_count(active_bound_list_itr<T> bnd_itr,
(*bnd_itr)->winding_count = (*rev_bnd_itr)->winding_count;
} else {
// otherwise continue to 'decrease' WC ...
(*bnd_itr)->winding_count = (*rev_bnd_itr)->winding_count + (*bnd_itr)->winding_delta;
(*bnd_itr)->winding_count =
(*rev_bnd_itr)->winding_count + (*bnd_itr)->winding_delta;
}
} else {
// now outside all polys of same polytype so set own WC ...
@ -214,7 +235,8 @@ void set_winding_count(active_bound_list_itr<T> bnd_itr,
(*bnd_itr)->winding_count = (*rev_bnd_itr)->winding_count;
} else {
// otherwise add to WC ...
(*bnd_itr)->winding_count = (*rev_bnd_itr)->winding_count + (*bnd_itr)->winding_delta;
(*bnd_itr)->winding_count =
(*rev_bnd_itr)->winding_count + (*bnd_itr)->winding_delta;
}
}
(*bnd_itr)->winding_count2 = (*rev_bnd_itr)->winding_count2;
@ -225,7 +247,9 @@ void set_winding_count(active_bound_list_itr<T> bnd_itr,
if (is_even_odd_alt_fill_type(*(*bnd_itr), subject_fill_type, clip_fill_type)) {
// EvenOdd filling ...
while (bnd_itr_forward != bnd_itr) {
(*bnd_itr)->winding_count2 = ((*bnd_itr)->winding_count2 == 0 ? 1 : 0);
if ((*bnd_itr_forward)->winding_delta != 0) {
(*bnd_itr)->winding_count2 = ((*bnd_itr)->winding_count2 == 0 ? 1 : 0);
}
++bnd_itr_forward;
}
} else {
@ -238,7 +262,10 @@ void set_winding_count(active_bound_list_itr<T> bnd_itr,
}
template <typename T>
bool is_contributing(bound<T> const& bnd, clip_type cliptype, fill_type subject_fill_type, fill_type clip_fill_type) {
bool is_contributing(bound<T> const& bnd,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type) {
fill_type pft = subject_fill_type;
fill_type pft2 = clip_fill_type;
if (bnd.poly_type != polygon_type_subject) {
@ -335,20 +362,21 @@ void insert_lm_left_and_right_bound(bound<T>& left_bound,
fill_type clip_fill_type) {
// Both left and right bound
auto lb_abl_itr = insert_bound_into_ABL(left_bound, right_bound, active_bounds);
auto rb_abl_itr = std::next(lb_abl_itr);
auto lb_abl_itr = insert_bound_into_ABL(left_bound, active_bounds);
auto rb_abl_itr = active_bounds.insert(std::next(lb_abl_itr), &right_bound);
set_winding_count(lb_abl_itr, active_bounds, subject_fill_type, clip_fill_type);
(*rb_abl_itr)->winding_count = (*lb_abl_itr)->winding_count;
(*rb_abl_itr)->winding_count2 = (*lb_abl_itr)->winding_count2;
if (is_contributing(left_bound, cliptype, subject_fill_type, clip_fill_type)) {
add_local_minimum_point(*(*lb_abl_itr), *(*rb_abl_itr), active_bounds, (*lb_abl_itr)->current_edge->bot, rings);
add_local_minimum_point(lb_abl_itr, rb_abl_itr, active_bounds,
(*lb_abl_itr)->current_edge->bot, rings);
}
// Add top of edges to scanbeam
insert_sorted_scanbeam(scanbeam, (*lb_abl_itr)->current_edge->top.y);
scanbeam.push((*lb_abl_itr)->current_edge->top.y);
if (!current_edge_is_horizontal<T>(rb_abl_itr)) {
insert_sorted_scanbeam(scanbeam, (*rb_abl_itr)->current_edge->top.y);
scanbeam.push((*rb_abl_itr)->current_edge->top.y);
}
}
@ -366,8 +394,8 @@ void insert_local_minima_into_ABL(T const bot_y,
initialize_lm<T>(current_lm);
auto& left_bound = (*current_lm)->left_bound;
auto& right_bound = (*current_lm)->right_bound;
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
cliptype, subject_fill_type, clip_fill_type);
++current_lm;
}
}
@ -382,15 +410,16 @@ void insert_horizontal_local_minima_into_ABL(T const top_y,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type) {
while (current_lm != minima_sorted.end() && top_y == (*current_lm)->y && (*current_lm)->minimum_has_horizontal) {
while (current_lm != minima_sorted.end() && top_y == (*current_lm)->y &&
(*current_lm)->minimum_has_horizontal) {
initialize_lm<T>(current_lm);
auto& left_bound = (*current_lm)->left_bound;
auto& right_bound = (*current_lm)->right_bound;
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
cliptype, subject_fill_type, clip_fill_type);
++current_lm;
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -1,277 +0,0 @@
// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
//
// The Google C++ Testing Framework (Google Test)
// This template class serves as a compile-time function from size to
// type. It maps a size in bytes to a primitive type with that
// size. e.g.
//
// TypeWithSize<4>::UInt
//
// is typedef-ed to be unsigned int (unsigned integer made up of 4
// bytes).
//
// Such functionality should belong to STL, but I cannot find it
// there.
//
// Google Test uses this class in the implementation of floating-point
// comparison.
//
// For now it only handles UInt (unsigned int) as that's all Google Test
// needs. Other types can be easily added in the future if need
// arises.
namespace mapbox {
namespace geometry {
namespace wagyu {
namespace util {
template <size_t size>
class TypeWithSize {
public:
// This prevents the user from using TypeWithSize<N> with incorrect
// values of N.
typedef void UInt;
};
// The specialization for size 4.
template <>
class TypeWithSize<4> {
public:
// unsigned int has size 4 in both gcc and MSVC.
//
// As base/basictypes.h doesn't compile on Windows, we cannot use
// uint32, uint64, and etc here.
typedef int Int;
typedef unsigned int UInt;
};
// The specialization for size 8.
template <>
class TypeWithSize<8> {
public:
#if GTEST_OS_WINDOWS
typedef __int64 Int;
typedef unsigned __int64 UInt;
#else
typedef long long Int; // NOLINT
typedef unsigned long long UInt; // NOLINT
#endif // GTEST_OS_WINDOWS
};
// This template class represents an IEEE floating-point number
// (either single-precision or double-precision, depending on the
// template parameters).
//
// The purpose of this class is to do more sophisticated number
// comparison. (Due to round-off error, etc, it's very unlikely that
// two floating-points will be equal exactly. Hence a naive
// comparison by the == operation often doesn't work.)
//
// Format of IEEE floating-point:
//
// The most-significant bit being the leftmost, an IEEE
// floating-point looks like
//
// sign_bit exponent_bits fraction_bits
//
// Here, sign_bit is a single bit that designates the sign of the
// number.
//
// For float, there are 8 exponent bits and 23 fraction bits.
//
// For double, there are 11 exponent bits and 52 fraction bits.
//
// More details can be found at
// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
//
// Template parameter:
//
// RawType: the raw floating-point type (either float or double)
template <typename RawType>
class FloatingPoint {
public:
// Defines the unsigned integer type that has the same size as the
// floating point number.
typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
// Constants.
// # of bits in a number.
static const size_t kBitCount = 8 * sizeof(RawType);
// # of fraction bits in a number.
static const size_t kFractionBitCount = std::numeric_limits<RawType>::digits - 1;
// # of exponent bits in a number.
static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
// The mask for the sign bit.
static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
// The mask for the fraction bits.
static const Bits kFractionBitMask = ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
// The mask for the exponent bits.
static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
// How many ULP's (Units in the Last Place) we want to tolerate when
// comparing two numbers. The larger the value, the more error we
// allow. A 0 value means that two numbers must be exactly the same
// to be considered equal.
//
// The maximum error of a single floating-point operation is 0.5
// units in the last place. On Intel CPU's, all floating-point
// calculations are done with 80-bit precision, while double has 64
// bits. Therefore, 4 should be enough for ordinary use.
//
// See the following article for more details on ULP:
// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
static const size_t kMaxUlps = 4;
// Constructs a FloatingPoint from a raw floating-point number.
//
// On an Intel CPU, passing a non-normalized NAN (Not a Number)
// around may change its bits, although the new value is guaranteed
// to be also a NAN. Therefore, don't expect this constructor to
// preserve the bits in x when x is a NAN.
explicit FloatingPoint(const RawType& x) : u_(x) {
}
// Static methods
// Reinterprets a bit pattern as a floating-point number.
//
// This function is needed to test the AlmostEquals() method.
static RawType ReinterpretBits(const Bits bits) {
FloatingPoint fp(0);
fp.u_.bits_ = bits;
return fp.u_.value_;
}
// Returns the floating-point number that represent positive infinity.
static RawType Infinity() {
return ReinterpretBits(kExponentBitMask);
}
// Non-static methods
// Returns the bits that represents this number.
const Bits& bits() const {
return u_.bits_;
}
// Returns the exponent bits of this number.
Bits exponent_bits() const {
return kExponentBitMask & u_.bits_;
}
// Returns the fraction bits of this number.
Bits fraction_bits() const {
return kFractionBitMask & u_.bits_;
}
// Returns the sign bit of this number.
Bits sign_bit() const {
return kSignBitMask & u_.bits_;
}
// Returns true iff this is NAN (not a number).
bool is_nan() const {
// It's a NAN if the exponent bits are all ones and the fraction
// bits are not entirely zeros.
return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
}
// Returns true iff this number is at most kMaxUlps ULP's away from
// rhs. In particular, this function:
//
// - returns false if either number is (or both are) NAN.
// - treats really large numbers as almost equal to infinity.
// - thinks +0.0 and -0.0 are 0 DLP's apart.
bool AlmostEquals(const FloatingPoint& rhs) const {
// The IEEE standard says that any comparison operation involving
// a NAN must return false.
if (is_nan() || rhs.is_nan())
return false;
return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps;
}
private:
// The data type used to store the actual floating-point number.
union FloatingPointUnion {
explicit FloatingPointUnion(RawType val) : value_(val) {
}
RawType value_; // The raw floating-point number.
Bits bits_; // The bits that represent the number.
};
// Converts an integer from the sign-and-magnitude representation to
// the biased representation. More precisely, let N be 2 to the
// power of (kBitCount - 1), an integer x is represented by the
// unsigned number x + N.
//
// For instance,
//
// -N + 1 (the most negative number representable using
// sign-and-magnitude) is represented by 1;
// 0 is represented by N; and
// N - 1 (the biggest number representable using
// sign-and-magnitude) is represented by 2N - 1.
//
// Read http://en.wikipedia.org/wiki/Signed_number_representations
// for more details on signed number representations.
static Bits SignAndMagnitudeToBiased(const Bits& sam) {
if (kSignBitMask & sam) {
// sam represents a negative number.
return ~sam + 1;
} else {
// sam represents a positive number.
return kSignBitMask | sam;
}
}
// Given two numbers in the sign-and-magnitude representation,
// returns the distance between them as an unsigned number.
static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1, const Bits& sam2) {
const Bits biased1 = SignAndMagnitudeToBiased(sam1);
const Bits biased2 = SignAndMagnitudeToBiased(sam2);
return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
}
FloatingPointUnion u_;
};
} // namespace util
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

View File

@ -36,7 +36,6 @@ struct bound {
bound() noexcept
: edges(),
current_edge(edges.end()),
next_edge(edges.end()),
last_point({ 0, 0 }),
ring(nullptr),
maximum_bound(nullptr),
@ -52,7 +51,6 @@ struct bound {
bound(bound<T>&& b) noexcept
: edges(std::move(b.edges)),
current_edge(std::move(b.current_edge)),
next_edge(std::move(b.next_edge)),
last_point(std::move(b.last_point)),
ring(std::move(b.ring)),
maximum_bound(std::move(b.maximum_bound)),
@ -64,15 +62,13 @@ struct bound {
poly_type(std::move(b.poly_type)),
side(std::move(b.side)) {
}
bound(bound<T> const& b) = delete;
bound<T>& operator=(bound<T> const&) = delete;
};
#ifdef DEBUG
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, const bound<T>& bnd) {
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const bound<T>& bnd) {
out << " Bound: " << &bnd << std::endl;
out << " current_x: " << bnd.current_x << std::endl;
out << " last_point: " << bnd.last_point.x << ", " << bnd.last_point.y << std::endl;
@ -94,6 +90,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -1,28 +0,0 @@
#pragma once
namespace mapbox {
namespace geometry {
namespace wagyu {
template <typename It, class Compare, class MethodOnSwap>
void bubble_sort(It begin, It end, Compare c, MethodOnSwap m) {
if (begin == end) {
return;
}
bool modified = false;
auto last = end - 1;
do {
modified = false;
for (auto itr = begin; itr != last; ++itr) {
auto next = std::next(itr);
if (!c(*itr, *next)) {
m(*itr, *next);
std::iter_swap(itr, next);
modified = true;
}
}
} while (modified);
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

View File

@ -25,8 +25,8 @@ bool point_2_is_between_point_1_and_point_3(mapbox::geometry::point<T> const& pt
}
}
template <typename T1, typename T2>
bool build_edge_list(mapbox::geometry::linear_ring<T2> const& path_geometry, edge_list<T1>& edges) {
template <typename T>
bool build_edge_list(mapbox::geometry::linear_ring<T> const& path_geometry, edge_list<T>& edges) {
if (path_geometry.size() < 3) {
return false;
@ -37,8 +37,8 @@ bool build_edge_list(mapbox::geometry::linear_ring<T2> const& path_geometry, edg
auto itr_rev = path_geometry.rbegin();
auto itr = path_geometry.begin();
mapbox::geometry::point<T2> pt1 = *itr_rev;
mapbox::geometry::point<T2> pt2 = *itr;
mapbox::geometry::point<T> pt1 = *itr_rev;
mapbox::geometry::point<T> pt2 = *itr;
// Find next non repeated point going backwards from
// end for pt1
@ -50,10 +50,10 @@ bool build_edge_list(mapbox::geometry::linear_ring<T2> const& path_geometry, edg
pt1 = *itr_rev;
}
++itr;
mapbox::geometry::point<T2> pt3 = *itr;
mapbox::geometry::point<T> pt3 = *itr;
auto itr_last = itr_rev.base();
mapbox::geometry::point<T2> front_pt;
mapbox::geometry::point<T2> back_pt;
mapbox::geometry::point<T> front_pt;
mapbox::geometry::point<T> back_pt;
while (true) {
if (pt3 == pt2) {
// Duplicate point advance itr, but do not
@ -84,12 +84,10 @@ bool build_edge_list(mapbox::geometry::linear_ring<T2> const& path_geometry, edg
edges.pop_back(); // remove previous edge (pt1)
}
if (!edges.empty()) {
auto const& back_top = edges.back().top;
if (static_cast<T1>(back_pt.x) == back_top.x && static_cast<T1>(back_pt.y) == back_top.y) {
auto const& back_bot = edges.back().bot;
pt1 = mapbox::geometry::point<T2>(static_cast<T2>(back_bot.x), static_cast<T2>(back_bot.y));
if (back_pt == edges.back().top) {
pt1 = edges.back().bot;
} else {
pt1 = mapbox::geometry::point<T2>(static_cast<T2>(back_top.x), static_cast<T2>(back_top.y));
pt1 = edges.back().top;
}
back_pt = pt1;
} else {
@ -178,6 +176,6 @@ bool build_edge_list(mapbox::geometry::linear_ring<T2> const& path_geometry, edg
return true;
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -9,18 +9,31 @@ namespace mapbox {
namespace geometry {
namespace wagyu {
template <typename T1, typename T2>
bool add_linear_ring(mapbox::geometry::linear_ring<T2> const& path_geometry,
local_minimum_list<T1>& minima_list,
polygon_type p_type) {
edge_list<T1> new_edges;
template <typename T>
bool add_line_string(mapbox::geometry::line_string<T> const& path_geometry,
local_minimum_list<T>& minima_list) {
bool is_flat = true;
edge_list<T> new_edges;
new_edges.reserve(path_geometry.size());
if (!build_edge_list<T1, T2>(path_geometry, new_edges) || new_edges.empty()) {
if (!build_edge_list(path_geometry, new_edges, is_flat) || new_edges.empty()) {
return false;
}
add_line_to_local_minima_list(new_edges, minima_list, polygon_type_subject);
return true;
}
template <typename T>
bool add_linear_ring(mapbox::geometry::linear_ring<T> const& path_geometry,
local_minimum_list<T>& minima_list,
polygon_type p_type) {
edge_list<T> new_edges;
new_edges.reserve(path_geometry.size());
if (!build_edge_list(path_geometry, new_edges) || new_edges.empty()) {
return false;
}
add_ring_to_local_minima_list(new_edges, minima_list, p_type);
return true;
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -3,26 +3,24 @@
#include <mapbox/geometry/wagyu/ring.hpp>
#include <mapbox/geometry/wagyu/ring_util.hpp>
#include <mapbox/geometry/multi_polygon.hpp>
namespace mapbox {
namespace geometry {
namespace wagyu {
template <typename T1, typename T2>
void push_ring_to_polygon(mapbox::geometry::polygon<T2>& poly, ring_ptr<T1> r, bool reverse_output) {
mapbox::geometry::linear_ring<T2> lr;
lr.reserve(r->size() + 1);
template <typename T>
void push_ring_to_polygon(mapbox::geometry::polygon<T>& poly, ring_ptr<T>& r, bool reverse_output) {
mapbox::geometry::linear_ring<T> lr;
lr.reserve(r->size + 1);
auto firstPt = r->points;
auto ptIt = r->points;
if (reverse_output) {
do {
lr.emplace_back(static_cast<T2>(ptIt->x), static_cast<T2>(ptIt->y));
lr.emplace_back(ptIt->x, ptIt->y);
ptIt = ptIt->next;
} while (ptIt != firstPt);
} else {
do {
lr.emplace_back(static_cast<T2>(ptIt->x), static_cast<T2>(ptIt->y));
lr.emplace_back(ptIt->x, ptIt->y);
ptIt = ptIt->prev;
} while (ptIt != firstPt);
}
@ -30,28 +28,28 @@ void push_ring_to_polygon(mapbox::geometry::polygon<T2>& poly, ring_ptr<T1> r, b
poly.push_back(lr);
}
template <typename T1, typename T2>
void build_result_polygons(mapbox::geometry::multi_polygon<T2>& solution,
ring_vector<T1> const& rings,
template <typename T>
void build_result_polygons(std::vector<mapbox::geometry::polygon<T>>& solution,
ring_list<T>& rings,
bool reverse_output) {
for (auto r : rings) {
if (r == nullptr) {
for (auto& r : rings) {
assert(r->points);
std::size_t cnt = point_count(r->points);
if (cnt < 3) {
continue;
}
assert(r->points);
solution.emplace_back();
push_ring_to_polygon(solution.back(), r, reverse_output);
for (auto c : r->children) {
if (c == nullptr) {
for (auto& c : r->children) {
assert(c->points);
cnt = point_count(c->points);
if (cnt < 3) {
continue;
}
assert(c->points);
push_ring_to_polygon(solution.back(), c, reverse_output);
}
for (auto c : r->children) {
if (c == nullptr) {
continue;
}
for (auto& c : r->children) {
if (!c->children.empty()) {
build_result_polygons(solution, c->children, reverse_output);
}
@ -59,10 +57,12 @@ void build_result_polygons(mapbox::geometry::multi_polygon<T2>& solution,
}
}
template <typename T1, typename T2>
void build_result(mapbox::geometry::multi_polygon<T2>& solution, ring_manager<T1> const& rings, bool reverse_output) {
template <typename T>
void build_result(std::vector<mapbox::geometry::polygon<T>>& solution,
ring_manager<T>& rings,
bool reverse_output) {
build_result_polygons(solution, rings.children, reverse_output);
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -5,22 +5,25 @@
#include <list>
#include <stdexcept>
// GCC 4.8 missing range std::vector::insert (c++11)
#ifdef __GNUC__
#if __GNUC__ == 4 && __GNUC_MINOR__ == 8
#define GCC_MISSING_VECTOR_RANGE_INSERT
#endif
#endif
namespace mapbox {
namespace geometry {
namespace wagyu {
enum clip_type : std::uint8_t { clip_type_intersection = 0, clip_type_union, clip_type_difference, clip_type_x_or };
enum clip_type : std::uint8_t {
clip_type_intersection = 0,
clip_type_union,
clip_type_difference,
clip_type_x_or
};
enum polygon_type : std::uint8_t { polygon_type_subject = 0, polygon_type_clip };
enum fill_type : std::uint8_t { fill_type_even_odd = 0, fill_type_non_zero, fill_type_positive, fill_type_negative };
enum fill_type : std::uint8_t {
fill_type_even_odd = 0,
fill_type_non_zero,
fill_type_positive,
fill_type_negative
};
static double const def_arc_tolerance = 0.25;
@ -45,6 +48,6 @@ enum end_type {
template <typename T>
using maxima_list = std::list<T>;
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -38,15 +38,13 @@ struct edge {
return *this;
}
template <typename T2>
edge(mapbox::geometry::point<T2> const& current, mapbox::geometry::point<T2> const& next_pt) noexcept
: bot(static_cast<T>(current.x), static_cast<T>(current.y)),
top(static_cast<T>(current.x), static_cast<T>(current.y)),
dx(0.0) {
edge(mapbox::geometry::point<T> const& current,
mapbox::geometry::point<T> const& next_pt) noexcept
: bot(current), top(current), dx(0.0) {
if (current.y >= next_pt.y) {
top = mapbox::geometry::point<T>(static_cast<T>(next_pt.x), static_cast<T>(next_pt.y));
top = next_pt;
} else {
bot = mapbox::geometry::point<T>(static_cast<T>(next_pt.x), static_cast<T>(next_pt.y));
bot = next_pt;
}
double dy = static_cast<double>(top.y - bot.y);
if (value_is_zero(dy)) {
@ -68,8 +66,8 @@ using edge_list_itr = typename edge_list<T>::iterator;
template <typename T>
bool slopes_equal(edge<T> const& e1, edge<T> const& e2) {
return static_cast<std::int64_t>(e1.top.y - e1.bot.y) * static_cast<std::int64_t>(e2.top.x - e2.bot.x) ==
static_cast<std::int64_t>(e1.top.x - e1.bot.x) * static_cast<std::int64_t>(e2.top.y - e2.bot.y);
return (e1.top.y - e1.bot.y) * (e2.top.x - e2.bot.x) ==
(e1.top.x - e1.bot.x) * (e2.top.y - e2.bot.y);
}
template <typename T>
@ -82,14 +80,16 @@ inline double get_current_x(edge<T> const& edge, const T current_y) {
if (current_y == edge.top.y) {
return static_cast<double>(edge.top.x);
} else {
return static_cast<double>(edge.bot.x) + edge.dx * static_cast<double>(current_y - edge.bot.y);
return static_cast<double>(edge.bot.x) +
edge.dx * static_cast<double>(current_y - edge.bot.y);
}
}
#ifdef DEBUG
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, const edge<T>& e) {
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const edge<T>& e) {
out << " Edge: " << std::endl;
out << " bot x: " << e.bot.x << " y: " << e.bot.y << std::endl;
out << " top x: " << e.top.x << " y: " << e.top.y << std::endl;
@ -115,6 +115,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <stdexcept>
namespace mapbox {
namespace geometry {
namespace wagyu {
class clipper_exception : public std::exception {
private:
std::string m_descr;
public:
clipper_exception(const char* description) : m_descr(description) {
}
virtual ~clipper_exception() noexcept {
}
virtual const char* what() const noexcept {
return m_descr.c_str();
}
};
}
}
}

View File

@ -1,50 +0,0 @@
#pragma once
/**
* To enable this by the program, define USE_WAGYU_INTERRUPT before including wagyu.hpp
* To request an interruption, call `interrupt_request()`. As soon as Wagyu detects the request
* it will raise an exception (`std::runtime_error`).
*/
#ifdef USE_WAGYU_INTERRUPT
namespace {
thread_local bool WAGYU_INTERRUPT_REQUESTED = false;
}
namespace mapbox {
namespace geometry {
namespace wagyu {
static void interrupt_reset(void) {
WAGYU_INTERRUPT_REQUESTED = false;
}
static void interrupt_request(void) {
WAGYU_INTERRUPT_REQUESTED = true;
}
static void interrupt_check(void) {
if (WAGYU_INTERRUPT_REQUESTED) {
interrupt_reset();
throw std::runtime_error("Wagyu interrupted");
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
#else /* ! USE_WAGYU_INTERRUPT */
namespace mapbox {
namespace geometry {
namespace wagyu {
static void interrupt_check(void) {
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
#endif /* USE_WAGYU_INTERRUPT */

View File

@ -17,22 +17,24 @@ namespace wagyu {
template <typename T>
struct intersect_node {
bound_ptr<T> bound1;
bound_ptr<T> bound2;
active_bound_list_itr<T> bound1;
active_bound_list_itr<T> bound2;
mapbox::geometry::point<double> pt;
intersect_node(intersect_node<T>&& n) noexcept
intersect_node(intersect_node<T>&& n)
: bound1(std::move(n.bound1)), bound2(std::move(n.bound2)), pt(std::move(n.pt)) {
}
intersect_node& operator=(intersect_node<T>&& n) noexcept {
intersect_node& operator=(intersect_node<T>&& n) {
bound1 = std::move(n.bound1);
bound2 = std::move(n.bound2);
pt = std::move(n.pt);
return *this;
}
intersect_node(bound_ptr<T> const& bound1_, bound_ptr<T> const& bound2_, mapbox::geometry::point<double> const& pt_)
intersect_node(active_bound_list_itr<T> const& bound1_,
active_bound_list_itr<T> const& bound2_,
mapbox::geometry::point<double> const& pt_)
: bound1(bound1_), bound2(bound2_), pt(pt_) {
}
};
@ -47,9 +49,9 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
const intersect_node<T>& e) {
out << " point x: " << e.pt.x << " y: " << e.pt.y << std::endl;
out << " bound 1: " << std::endl;
out << *e.bound1 << std::endl;
out << *(*e.bound1) << std::endl;
out << " bound 2: " << std::endl;
out << *e.bound2 << std::endl;
out << *(*e.bound2) << std::endl;
return out;
}
@ -65,6 +67,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -2,14 +2,11 @@
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
#include <mapbox/geometry/wagyu/bound.hpp>
#include <mapbox/geometry/wagyu/bubble_sort.hpp>
#include <mapbox/geometry/wagyu/config.hpp>
#include <mapbox/geometry/wagyu/intersect.hpp>
#include <mapbox/geometry/wagyu/ring_util.hpp>
#include <mapbox/geometry/wagyu/util.hpp>
#include <algorithm>
namespace mapbox {
namespace geometry {
namespace wagyu {
@ -20,8 +17,8 @@ struct intersect_list_sorter {
if (!values_are_equal(node2.pt.y, node1.pt.y)) {
return node2.pt.y < node1.pt.y;
} else {
return (node2.bound1->winding_count2 + node2.bound2->winding_count2) >
(node1.bound1->winding_count2 + node1.bound2->winding_count2);
return ((*node2.bound1)->winding_count2 + (*node2.bound2)->winding_count2) >
((*node1.bound1)->winding_count2 + (*node1.bound2)->winding_count2);
}
}
};
@ -46,7 +43,9 @@ inline void swap_sides(bound<T>& b1, bound<T>& b2) {
}
template <typename T1, typename T2>
bool get_edge_intersection(edge<T1> const& e1, edge<T1> const& e2, mapbox::geometry::point<T2>& pt) {
bool get_edge_intersection(edge<T1> const& e1,
edge<T1> const& e2,
mapbox::geometry::point<T2>& pt) {
T2 p0_x = static_cast<T2>(e1.bot.x);
T2 p0_y = static_cast<T2>(e1.bot.y);
T2 p1_x = static_cast<T2>(e1.top.x);
@ -61,8 +60,9 @@ bool get_edge_intersection(edge<T1> const& e1, edge<T1> const& e2, mapbox::geome
s2_x = p3_x - p2_x;
s2_y = p3_y - p2_y;
T2 s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
T2 t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
T2 s, t;
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0.0 && s <= 1.0 && t >= 0.0 && t <= 1.0) {
pt.x = p0_x + (t * s1_x);
@ -74,89 +74,90 @@ bool get_edge_intersection(edge<T1> const& e1, edge<T1> const& e2, mapbox::geome
// LCOV_EXCL_END
}
template <typename T>
struct intersection_compare {
bool operator()(bound_ptr<T> const& b1, bound_ptr<T> const& b2) {
return !(b1->current_x > b2->current_x && !slopes_equal(*(b1->current_edge), *(b2->current_edge)));
}
};
template <typename T>
struct on_intersection_swap {
intersect_list<T>& intersects;
on_intersection_swap(intersect_list<T>& i) : intersects(i) {
}
void operator()(bound_ptr<T> const& b1, bound_ptr<T> const& b2) {
mapbox::geometry::point<double> pt;
if (!get_edge_intersection<T, double>(*(b1->current_edge), *(b2->current_edge), pt)) {
// LCOV_EXCL_START
throw std::runtime_error("Trying to find intersection of lines that do not intersect");
// LCOV_EXCL_END
}
intersects.emplace_back(b1, b2, pt);
}
};
template <typename T>
void build_intersect_list(active_bound_list<T>& active_bounds, intersect_list<T>& intersects) {
bubble_sort(active_bounds.begin(), active_bounds.end(), intersection_compare<T>(),
on_intersection_swap<T>(intersects));
// bubblesort ...
bool isModified = false;
do {
isModified = false;
auto bnd = active_bounds.begin();
auto bnd_next = std::next(bnd);
while (bnd_next != active_bounds.end()) {
if ((*bnd)->current_x > (*bnd_next)->current_x &&
!slopes_equal(*((*bnd)->current_edge), *((*bnd_next)->current_edge))) {
mapbox::geometry::point<double> pt;
if (!get_edge_intersection<T, double>(*((*bnd)->current_edge),
*((*bnd_next)->current_edge), pt)) {
// LCOV_EXCL_START
throw std::runtime_error(
"Trying to find intersection of lines that do not intersect");
// LCOV_EXCL_END
}
intersects.emplace_back(bnd, bnd_next, pt);
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
bnd_next = std::next(bnd);
isModified = true;
} else {
bnd = bnd_next;
++bnd_next;
}
}
} while (isModified);
}
template <typename T>
void intersect_bounds(bound<T>& b1,
bound<T>& b2,
void intersect_bounds(active_bound_list_itr<T>& b1,
active_bound_list_itr<T>& b2,
mapbox::geometry::point<T> const& pt,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type,
ring_manager<T>& rings,
active_bound_list<T>& active_bounds) {
bool b1Contributing = (b1.ring != nullptr);
bool b2Contributing = (b2.ring != nullptr);
bool b1Contributing = ((*b1)->ring != nullptr);
bool b2Contributing = ((*b2)->ring != nullptr);
// update winding counts...
// assumes that b1 will be to the Right of b2 ABOVE the intersection
if (b1.poly_type == b2.poly_type) {
if (is_even_odd_fill_type(b1, subject_fill_type, clip_fill_type)) {
std::swap(b1.winding_count, b2.winding_count);
if ((*b1)->poly_type == (*b2)->poly_type) {
if (is_even_odd_fill_type(*(*b1), subject_fill_type, clip_fill_type)) {
std::int32_t oldE1winding_count = (*b1)->winding_count;
(*b1)->winding_count = (*b2)->winding_count;
(*b2)->winding_count = oldE1winding_count;
} else {
if (b1.winding_count + b2.winding_delta == 0) {
b1.winding_count = -b1.winding_count;
if ((*b1)->winding_count + (*b2)->winding_delta == 0) {
(*b1)->winding_count = -(*b1)->winding_count;
} else {
b1.winding_count += b2.winding_delta;
(*b1)->winding_count += (*b2)->winding_delta;
}
if (b2.winding_count - b1.winding_delta == 0) {
b2.winding_count = -b2.winding_count;
if ((*b2)->winding_count - (*b1)->winding_delta == 0) {
(*b2)->winding_count = -(*b2)->winding_count;
} else {
b2.winding_count -= b1.winding_delta;
(*b2)->winding_count -= (*b1)->winding_delta;
}
}
} else {
if (!is_even_odd_fill_type(b2, subject_fill_type, clip_fill_type)) {
b1.winding_count2 += b2.winding_delta;
if (!is_even_odd_fill_type(*(*b2), subject_fill_type, clip_fill_type)) {
(*b1)->winding_count2 += (*b2)->winding_delta;
} else {
b1.winding_count2 = (b1.winding_count2 == 0) ? 1 : 0;
(*b1)->winding_count2 = ((*b1)->winding_count2 == 0) ? 1 : 0;
}
if (!is_even_odd_fill_type(b1, subject_fill_type, clip_fill_type)) {
b2.winding_count2 -= b1.winding_delta;
if (!is_even_odd_fill_type(*(*b1), subject_fill_type, clip_fill_type)) {
(*b2)->winding_count2 -= (*b1)->winding_delta;
} else {
b2.winding_count2 = (b2.winding_count2 == 0) ? 1 : 0;
(*b2)->winding_count2 = ((*b2)->winding_count2 == 0) ? 1 : 0;
}
}
fill_type b1FillType, b2FillType, b1FillType2, b2FillType2;
if (b1.poly_type == polygon_type_subject) {
if ((*b1)->poly_type == polygon_type_subject) {
b1FillType = subject_fill_type;
b1FillType2 = clip_fill_type;
} else {
b1FillType = clip_fill_type;
b1FillType2 = subject_fill_type;
}
if (b2.poly_type == polygon_type_subject) {
if ((*b2)->poly_type == polygon_type_subject) {
b2FillType = subject_fill_type;
b2FillType2 = clip_fill_type;
} else {
@ -167,51 +168,51 @@ void intersect_bounds(bound<T>& b1,
std::int32_t b1Wc, b2Wc;
switch (b1FillType) {
case fill_type_positive:
b1Wc = b1.winding_count;
b1Wc = (*b1)->winding_count;
break;
case fill_type_negative:
b1Wc = -b1.winding_count;
b1Wc = -(*b1)->winding_count;
break;
case fill_type_even_odd:
case fill_type_non_zero:
default:
b1Wc = std::abs(static_cast<int>(b1.winding_count));
b1Wc = std::abs(static_cast<int>((*b1)->winding_count));
}
switch (b2FillType) {
case fill_type_positive:
b2Wc = b2.winding_count;
b2Wc = (*b2)->winding_count;
break;
case fill_type_negative:
b2Wc = -b2.winding_count;
b2Wc = -(*b2)->winding_count;
break;
case fill_type_even_odd:
case fill_type_non_zero:
default:
b2Wc = std::abs(static_cast<int>(b2.winding_count));
b2Wc = std::abs(static_cast<int>((*b2)->winding_count));
}
if (b1Contributing && b2Contributing) {
if ((b1Wc != 0 && b1Wc != 1) || (b2Wc != 0 && b2Wc != 1) ||
(b1.poly_type != b2.poly_type && cliptype != clip_type_x_or)) {
((*b1)->poly_type != (*b2)->poly_type && cliptype != clip_type_x_or)) {
add_local_maximum_point(b1, b2, pt, rings, active_bounds);
} else {
add_point(b1, active_bounds, pt, rings);
add_point(b2, active_bounds, pt, rings);
swap_sides(b1, b2);
swap_rings(b1, b2);
swap_sides(*(*b1), *(*b2));
swap_rings(*(*b1), *(*b2));
}
} else if (b1Contributing) {
if (b2Wc == 0 || b2Wc == 1) {
add_point(b1, active_bounds, pt, rings);
b2.last_point = pt;
swap_sides(b1, b2);
swap_rings(b1, b2);
(*b2)->last_point = pt;
swap_sides(*(*b1), *(*b2));
swap_rings(*(*b1), *(*b2));
}
} else if (b2Contributing) {
if (b1Wc == 0 || b1Wc == 1) {
b1.last_point = pt;
(*b1)->last_point = pt;
add_point(b2, active_bounds, pt, rings);
swap_sides(b1, b2);
swap_rings(b1, b2);
swap_sides(*(*b1), *(*b2));
swap_rings(*(*b1), *(*b2));
}
} else if ((b1Wc == 0 || b1Wc == 1) && (b2Wc == 0 || b2Wc == 1)) {
// neither bound is currently contributing ...
@ -219,30 +220,30 @@ void intersect_bounds(bound<T>& b1,
std::int32_t b1Wc2, b2Wc2;
switch (b1FillType2) {
case fill_type_positive:
b1Wc2 = b1.winding_count2;
b1Wc2 = (*b1)->winding_count2;
break;
case fill_type_negative:
b1Wc2 = -b1.winding_count2;
b1Wc2 = -(*b1)->winding_count2;
break;
case fill_type_even_odd:
case fill_type_non_zero:
default:
b1Wc2 = std::abs(static_cast<int>(b1.winding_count2));
b1Wc2 = std::abs(static_cast<int>((*b1)->winding_count2));
}
switch (b2FillType2) {
case fill_type_positive:
b2Wc2 = b2.winding_count2;
b2Wc2 = (*b2)->winding_count2;
break;
case fill_type_negative:
b2Wc2 = -b2.winding_count2;
b2Wc2 = -(*b2)->winding_count2;
break;
case fill_type_even_odd:
case fill_type_non_zero:
default:
b2Wc2 = std::abs(static_cast<int>(b2.winding_count2));
b2Wc2 = std::abs(static_cast<int>((*b2)->winding_count2));
}
if (b1.poly_type != b2.poly_type) {
if ((*b1)->poly_type != (*b2)->poly_type) {
add_local_minimum_point(b1, b2, active_bounds, pt, rings);
} else if (b1Wc == 1 && b2Wc == 1) {
switch (cliptype) {
@ -258,8 +259,8 @@ void intersect_bounds(bound<T>& b1,
}
break;
case clip_type_difference:
if (((b1.poly_type == polygon_type_clip) && (b1Wc2 > 0) && (b2Wc2 > 0)) ||
((b1.poly_type == polygon_type_subject) && (b1Wc2 <= 0) && (b2Wc2 <= 0))) {
if ((((*b1)->poly_type == polygon_type_clip) && (b1Wc2 > 0) && (b2Wc2 > 0)) ||
(((*b1)->poly_type == polygon_type_subject) && (b1Wc2 <= 0) && (b2Wc2 <= 0))) {
add_local_minimum_point(b1, b2, active_bounds, pt, rings);
}
break;
@ -267,29 +268,16 @@ void intersect_bounds(bound<T>& b1,
add_local_minimum_point(b1, b2, active_bounds, pt, rings);
}
} else {
swap_sides(b1, b2);
swap_sides(*(*b1), *(*b2));
}
}
}
template <typename T>
bool bounds_adjacent(intersect_node<T> const& inode, bound_ptr<T> next) {
return (next == inode.bound2) || (next == inode.bound1);
bool bounds_adjacent(intersect_node<T> const& inode) {
return (std::next(inode.bound1) == inode.bound2) || (std::next(inode.bound2) == inode.bound1);
}
template <typename T>
struct find_first_bound {
bound_ptr<T> b1;
bound_ptr<T> b2;
find_first_bound(intersect_node<T> const& inode) : b1(inode.bound1), b2(inode.bound2) {
}
bool operator()(bound_ptr<T> const& b) {
return b == b1 || b == b2;
}
};
template <typename T>
void process_intersect_list(intersect_list<T>& intersects,
clip_type cliptype,
@ -298,18 +286,9 @@ void process_intersect_list(intersect_list<T>& intersects,
ring_manager<T>& rings,
active_bound_list<T>& active_bounds) {
for (auto node_itr = intersects.begin(); node_itr != intersects.end(); ++node_itr) {
auto b1 = std::find_if(active_bounds.begin(), active_bounds.end(), find_first_bound<T>(*node_itr));
auto b2 = std::next(b1);
if (!bounds_adjacent(*node_itr, *b2)) {
if (!bounds_adjacent(*node_itr)) {
auto next_itr = std::next(node_itr);
while (next_itr != intersects.end()) {
auto n1 = std::find_if(active_bounds.begin(), active_bounds.end(), find_first_bound<T>(*next_itr));
auto n2 = std::next(n1);
if (bounds_adjacent(*next_itr, *n2)) {
b1 = n1;
b2 = n2;
break;
}
while (next_itr != intersects.end() && !bounds_adjacent(*next_itr)) {
++next_itr;
}
if (next_itr == intersects.end()) {
@ -318,9 +297,9 @@ void process_intersect_list(intersect_list<T>& intersects,
std::iter_swap(node_itr, next_itr);
}
mapbox::geometry::point<T> pt = round_point<T>(node_itr->pt);
intersect_bounds(*(node_itr->bound1), *(node_itr->bound2), pt, cliptype, subject_fill_type, clip_fill_type,
rings, active_bounds);
std::iter_swap(b1, b2);
intersect_bounds(node_itr->bound1, node_itr->bound2, pt, cliptype, subject_fill_type,
clip_fill_type, rings, active_bounds);
swap_positions_in_ABL(node_itr->bound1, node_itr->bound2, active_bounds);
}
}
@ -352,14 +331,15 @@ void process_intersections(T top_y,
}
// Restore order of active bounds list
std::stable_sort(active_bounds.begin(), active_bounds.end(),
[](bound_ptr<T> const& b1, bound_ptr<T> const& b2) { return b1->pos < b2->pos; });
active_bounds.sort(
[](bound_ptr<T> const& b1, bound_ptr<T> const& b2) { return b1->pos < b2->pos; });
// Sort the intersection list
std::stable_sort(intersects.begin(), intersects.end(), intersect_list_sorter<T>());
process_intersect_list(intersects, cliptype, subject_fill_type, clip_fill_type, rings, active_bounds);
process_intersect_list(intersects, cliptype, subject_fill_type, clip_fill_type, rings,
active_bounds);
}
}
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

View File

@ -45,7 +45,8 @@ using local_minimum_ptr_list_itr = typename local_minimum_ptr_list<T>::iterator;
template <typename T>
struct local_minimum_sorter {
inline bool operator()(local_minimum_ptr<T> const& locMin1, local_minimum_ptr<T> const& locMin2) {
inline bool operator()(local_minimum_ptr<T> const& locMin1,
local_minimum_ptr<T> const& locMin2) {
if (locMin2->y == locMin1->y) {
return locMin2->minimum_has_horizontal != locMin1->minimum_has_horizontal &&
locMin1->minimum_has_horizontal;
@ -112,6 +113,6 @@ std::string output_all_edges(local_minimum_ptr_list<T> const& lms) {
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -1,11 +1,8 @@
#pragma once
#include <mapbox/geometry/wagyu/edge.hpp>
#include <mapbox/geometry/wagyu/interrupt.hpp>
#include <mapbox/geometry/wagyu/local_minimum.hpp>
#include <algorithm>
#ifdef DEBUG
#include <stdexcept>
#endif
@ -43,10 +40,12 @@ void start_list_on_local_maximum(edge_list<T>& edges) {
break;
}
if (!edge_is_horizontal && prev_edge_is_horizontal) {
if (y_decreasing_before_last_horizontal && (edge->top == prev_edge->bot || edge->top == prev_edge->top)) {
if (y_decreasing_before_last_horizontal &&
(edge->top == prev_edge->bot || edge->top == prev_edge->top)) {
break;
}
} else if (!y_decreasing_before_last_horizontal && !prev_edge_is_horizontal && edge_is_horizontal &&
} else if (!y_decreasing_before_last_horizontal && !prev_edge_is_horizontal &&
edge_is_horizontal &&
(prev_edge->top == edge->top || prev_edge->top == edge->bot)) {
y_decreasing_before_last_horizontal = true;
}
@ -83,10 +82,12 @@ bound<T> create_bound_towards_minimum(edge_list<T>& edges) {
break;
}
if (!next_edge_is_horizontal && edge_is_horizontal) {
if (y_increasing_before_last_horizontal && (next_edge->bot == edge->bot || next_edge->bot == edge->top)) {
if (y_increasing_before_last_horizontal &&
(next_edge->bot == edge->bot || next_edge->bot == edge->top)) {
break;
}
} else if (!y_increasing_before_last_horizontal && !edge_is_horizontal && next_edge_is_horizontal &&
} else if (!y_increasing_before_last_horizontal && !edge_is_horizontal &&
next_edge_is_horizontal &&
(edge->bot == next_edge->top || edge->bot == next_edge->bot)) {
y_increasing_before_last_horizontal = true;
}
@ -101,7 +102,7 @@ bound<T> create_bound_towards_minimum(edge_list<T>& edges) {
if (next_edge == edges.end()) {
std::swap(edges, bnd.edges);
} else {
bnd.edges.reserve(static_cast<std::size_t>(std::distance(edges.begin(), next_edge)));
bnd.edges.reserve(std::distance(edges.begin(), next_edge));
std::move(edges.begin(), next_edge, std::back_inserter(bnd.edges));
edges.erase(edges.begin(), next_edge);
}
@ -129,10 +130,12 @@ bound<T> create_bound_towards_maximum(edge_list<T>& edges) {
break;
}
if (!next_edge_is_horizontal && edge_is_horizontal) {
if (y_decreasing_before_last_horizontal && (next_edge->top == edge->bot || next_edge->top == edge->top)) {
if (y_decreasing_before_last_horizontal &&
(next_edge->top == edge->bot || next_edge->top == edge->top)) {
break;
}
} else if (!y_decreasing_before_last_horizontal && !edge_is_horizontal && next_edge_is_horizontal &&
} else if (!y_decreasing_before_last_horizontal && !edge_is_horizontal &&
next_edge_is_horizontal &&
(edge->top == next_edge->top || edge->top == next_edge->bot)) {
y_decreasing_before_last_horizontal = true;
}
@ -144,7 +147,7 @@ bound<T> create_bound_towards_maximum(edge_list<T>& edges) {
if (next_edge == edges.end()) {
std::swap(bnd.edges, edges);
} else {
bnd.edges.reserve(static_cast<std::size_t>(std::distance(edges.begin(), next_edge)));
bnd.edges.reserve(std::distance(edges.begin(), next_edge));
std::move(edges.begin(), next_edge, std::back_inserter(bnd.edges));
edges.erase(edges.begin(), next_edge);
}
@ -191,11 +194,14 @@ void move_horizontals_on_left_to_right(bound<T>& left_bound, bound<T>& right_bou
auto dist = std::distance(left_bound.edges.begin(), edge_itr);
std::move(left_bound.edges.begin(), edge_itr, std::back_inserter(right_bound.edges));
left_bound.edges.erase(left_bound.edges.begin(), edge_itr);
std::rotate(right_bound.edges.begin(), std::prev(right_bound.edges.end(), dist), right_bound.edges.end());
std::rotate(right_bound.edges.begin(), std::prev(right_bound.edges.end(), dist),
right_bound.edges.end());
}
template <typename T>
void add_ring_to_local_minima_list(edge_list<T>& edges, local_minimum_list<T>& minima_list, polygon_type poly_type) {
void add_ring_to_local_minima_list(edge_list<T>& edges,
local_minimum_list<T>& minima_list,
polygon_type poly_type) {
if (edges.empty()) {
return;
@ -207,7 +213,6 @@ void add_ring_to_local_minima_list(edge_list<T>& edges, local_minimum_list<T>& m
bound_ptr<T> first_minimum = nullptr;
bound_ptr<T> last_maximum = nullptr;
while (!edges.empty()) {
interrupt_check(); // Check for interruptions
bool lm_minimum_has_horizontal = false;
auto to_minimum = create_bound_towards_minimum(edges);
if (edges.empty()) {
@ -219,20 +224,22 @@ void add_ring_to_local_minima_list(edge_list<T>& edges, local_minimum_list<T>& m
auto to_max_first_non_horizontal = to_maximum.edges.begin();
auto to_min_first_non_horizontal = to_minimum.edges.begin();
bool minimum_is_left = true;
while (to_max_first_non_horizontal != to_maximum.edges.end() && is_horizontal(*to_max_first_non_horizontal)) {
while (to_max_first_non_horizontal != to_maximum.edges.end() &&
is_horizontal(*to_max_first_non_horizontal)) {
lm_minimum_has_horizontal = true;
++to_max_first_non_horizontal;
}
while (to_min_first_non_horizontal != to_minimum.edges.end() && is_horizontal(*to_min_first_non_horizontal)) {
while (to_min_first_non_horizontal != to_minimum.edges.end() &&
is_horizontal(*to_min_first_non_horizontal)) {
lm_minimum_has_horizontal = true;
++to_min_first_non_horizontal;
}
#ifdef DEBUG
if (to_max_first_non_horizontal == to_maximum.edges.end() ||
to_min_first_non_horizontal == to_minimum.edges.end()) {
throw std::runtime_error("should not have a horizontal only bound for a ring");
}
#endif
if (lm_minimum_has_horizontal) {
if (to_max_first_non_horizontal->bot.x > to_min_first_non_horizontal->bot.x) {
minimum_is_left = true;
@ -309,6 +316,6 @@ void initialize_lm(local_minimum_ptr_list_itr<T>& lm) {
(*lm)->right_bound.ring = nullptr;
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -37,12 +37,18 @@ struct point {
point_ptr<T> next;
point_ptr<T> prev;
point(point<T>&& p)
: ring(std::move(p.ring)),
x(std::move(p.x)),
y(std::move(p.y)),
next(std::move(p.next)),
prev(std::move(p.prev)) {
}
point() : ring(nullptr), x(0), y(0), prev(this), next(this) {
}
point(T x_, T y_) : ring(nullptr), x(x_), y(y_), next(this), prev(this) {
}
point(ring_ptr<T> ring_, mapbox::geometry::point<T> const& pt)
: ring(ring_), x(pt.x), y(pt.y), next(this), prev(this) {
}
@ -54,12 +60,6 @@ struct point {
}
};
template <typename T>
using point_vector = std::vector<point_ptr<T>>;
template <typename T>
using point_vector_itr = typename point_vector<T>::iterator;
template <typename T>
bool operator==(point<T> const& lhs, point<T> const& rhs) {
return lhs.x == rhs.x && lhs.y == rhs.y;
@ -93,7 +93,8 @@ bool operator!=(point<T> const& lhs, mapbox::geometry::point<T> const& rhs) {
#ifdef DEBUG
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, const point<T>& p) {
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const point<T>& p) {
out << " point at: " << p.x << ", " << p.y;
return out;
}
@ -105,6 +106,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
return out;
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -23,7 +23,6 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
fill_type subject_fill_type,
fill_type clip_fill_type) {
auto horizontal_itr_behind = horz_bound;
bool shifted = false;
bool is_maxima_edge = is_maxima(horz_bound, scanline_y);
auto bound_max_pair = active_bounds.end();
if (is_maxima_edge) {
@ -32,35 +31,33 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
auto hp_itr = rings.current_hp_itr;
while (hp_itr != rings.hot_pixels.end() &&
(hp_itr->y > scanline_y || (hp_itr->y == scanline_y && hp_itr->x < (*horz_bound)->current_edge->bot.x))) {
(hp_itr->y > scanline_y ||
(hp_itr->y == scanline_y && hp_itr->x < (*horz_bound)->current_edge->bot.x))) {
++hp_itr;
}
auto bnd = std::next(horz_bound);
while (bnd != active_bounds.end()) {
if (*bnd == nullptr) {
++bnd;
continue;
}
// this code block inserts extra coords into horizontal edges (in output
// polygons) wherever hot pixels touch these horizontal edges. This helps
//'simplifying' polygons (ie if the Simplify property is set).
while (hp_itr != rings.hot_pixels.end() && hp_itr->y == scanline_y &&
hp_itr->x < wround<T>((*bnd)->current_x) && hp_itr->x < (*horz_bound)->current_edge->top.x) {
hp_itr->x < std::llround((*bnd)->current_x) &&
hp_itr->x < (*horz_bound)->current_edge->top.x) {
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
}
++hp_itr;
}
if (greater_than((*bnd)->current_x, static_cast<double>((*horz_bound)->current_edge->top.x))) {
if ((*bnd)->current_x > static_cast<double>((*horz_bound)->current_edge->top.x)) {
break;
}
// Also break if we've got to the end of an intermediate horizontal edge ...
// nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
if (wround<T>((*bnd)->current_x) == (*horz_bound)->current_edge->top.x &&
if (std::llround((*bnd)->current_x) == (*horz_bound)->current_edge->top.x &&
(*horz_bound)->next_edge != (*horz_bound)->edges.end() &&
(*horz_bound)->current_edge->dx < (*horz_bound)->next_edge->dx) {
break;
@ -68,104 +65,113 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
// note: may be done multiple times
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), mapbox::geometry::point<T>(wround<T>((*bnd)->current_x), scanline_y),
rings);
add_point_to_ring(
*(*horz_bound),
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y), rings);
}
// OK, so far we're still in range of the horizontal Edge but make sure
// we're at the last of consec. horizontals when matching with eMaxPair
if (is_maxima_edge && bnd == bound_max_pair) {
if ((*horz_bound)->ring && (*bound_max_pair)->ring) {
add_local_maximum_point(*(*horz_bound), *(*bound_max_pair), (*horz_bound)->current_edge->top, rings,
active_bounds);
if ((*horz_bound)->ring) {
add_local_maximum_point(horz_bound, bound_max_pair,
(*horz_bound)->current_edge->top, rings, active_bounds);
}
*bound_max_pair = nullptr;
*horz_bound = nullptr;
if (!shifted) {
++horizontal_itr_behind;
active_bounds.erase(bound_max_pair);
auto after_horz = active_bounds.erase(horz_bound);
if (horizontal_itr_behind != horz_bound) {
return horizontal_itr_behind;
} else {
return after_horz;
}
return horizontal_itr_behind;
}
intersect_bounds(*(*horz_bound), *(*bnd), mapbox::geometry::point<T>(wround<T>((*bnd)->current_x), scanline_y),
intersect_bounds(horz_bound, bnd,
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y),
cliptype, subject_fill_type, clip_fill_type, rings, active_bounds);
std::iter_swap(horz_bound, bnd);
horz_bound = bnd;
++bnd;
shifted = true;
auto next_bnd = std::next(bnd);
swap_positions_in_ABL(horz_bound, bnd, active_bounds);
if (current_edge_is_horizontal<T>(bnd) && horizontal_itr_behind == horz_bound) {
horizontal_itr_behind = bnd;
}
bnd = next_bnd;
} // end while (bnd != active_bounds.end())
if ((*horz_bound)->ring) {
while (hp_itr != rings.hot_pixels.end() && hp_itr->y == scanline_y &&
hp_itr->x < (*horz_bound)->current_edge->top.x) {
hp_itr->x < std::llround((*horz_bound)->current_edge->top.x)) {
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
++hp_itr;
}
}
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
}
if ((*horz_bound)->next_edge != (*horz_bound)->edges.end()) {
next_edge_in_bound(*(*horz_bound), scanbeam);
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
next_edge_in_bound(horz_bound, scanbeam);
} else {
next_edge_in_bound(horz_bound, scanbeam);
}
if (horizontal_itr_behind != horz_bound) {
return horizontal_itr_behind;
} else {
return std::next(horz_bound);
}
} else {
*horz_bound = nullptr;
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
}
auto after_horz = active_bounds.erase(horz_bound);
if (horizontal_itr_behind != horz_bound) {
return horizontal_itr_behind;
} else {
return after_horz;
}
}
if (!shifted) {
++horizontal_itr_behind;
}
return horizontal_itr_behind;
}
template <typename T>
active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
active_bound_list_itr<T>& horz_bound_fwd,
active_bound_list_itr<T>& horz_bound,
active_bound_list<T>& active_bounds,
ring_manager<T>& rings,
scanbeam_list<T>& scanbeam,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type) {
auto next_bnd_itr = std::next(horz_bound_fwd);
bool is_maxima_edge = is_maxima(horz_bound_fwd, scanline_y);
auto bound_max_pair = active_bounds.rend();
bool is_maxima_edge = is_maxima(horz_bound, scanline_y);
auto bound_max_pair = active_bounds.end();
if (is_maxima_edge) {
bound_max_pair = active_bound_list_rev_itr<T>(get_maxima_pair<T>(horz_bound_fwd, active_bounds));
--bound_max_pair;
bound_max_pair = get_maxima_pair<T>(horz_bound, active_bounds);
}
auto hp_itr_fwd = rings.current_hp_itr;
while (hp_itr_fwd != rings.hot_pixels.end() &&
(hp_itr_fwd->y < scanline_y ||
(hp_itr_fwd->y == scanline_y && hp_itr_fwd->x < (*horz_bound_fwd)->current_edge->top.x))) {
(hp_itr_fwd->y == scanline_y && hp_itr_fwd->x < (*horz_bound)->current_edge->top.x))) {
++hp_itr_fwd;
}
auto hp_itr = hot_pixel_rev_itr<T>(hp_itr_fwd);
auto bnd = active_bound_list_rev_itr<T>(horz_bound_fwd);
auto horz_bound = std::prev(bnd);
auto bnd = active_bound_list_rev_itr<T>(horz_bound);
while (bnd != active_bounds.rend()) {
if (*bnd == nullptr) {
++bnd;
continue;
}
// this code block inserts extra coords into horizontal edges (in output
// polygons) wherever hot pixels touch these horizontal edges.
while (hp_itr != rings.hot_pixels.rend() && hp_itr->y == scanline_y &&
hp_itr->x > wround<T>((*bnd)->current_x) && hp_itr->x > (*horz_bound)->current_edge->top.x) {
hp_itr->x > std::llround((*bnd)->current_x) &&
hp_itr->x > (*horz_bound)->current_edge->top.x) {
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
}
++hp_itr;
}
if (less_than((*bnd)->current_x, static_cast<double>((*horz_bound)->current_edge->top.x))) {
if ((*bnd)->current_x < static_cast<double>((*horz_bound)->current_edge->top.x)) {
break;
}
// Also break if we've got to the end of an intermediate horizontal edge ...
// nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
if (wround<T>((*bnd)->current_x) == (*horz_bound)->current_edge->top.x &&
if (std::llround((*bnd)->current_x) == (*horz_bound)->current_edge->top.x &&
(*horz_bound)->next_edge != (*horz_bound)->edges.end() &&
(*horz_bound)->current_edge->dx < (*horz_bound)->next_edge->dx) {
break;
@ -173,27 +179,32 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
// note: may be done multiple times
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), mapbox::geometry::point<T>(wround<T>((*bnd)->current_x), scanline_y),
rings);
add_point_to_ring(
*(*horz_bound),
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y), rings);
}
auto bnd_forward = --(bnd.base());
// OK, so far we're still in range of the horizontal Edge but make sure
// we're at the last of consec. horizontals when matching with eMaxPair
if (is_maxima_edge && bnd == bound_max_pair) {
if ((*horz_bound)->ring && (*bound_max_pair)->ring) {
add_local_maximum_point(*(*horz_bound), *(*bound_max_pair), (*horz_bound)->current_edge->top, rings,
active_bounds);
if (is_maxima_edge && bnd_forward == bound_max_pair) {
if ((*horz_bound)->ring) {
add_local_maximum_point(horz_bound, bound_max_pair,
(*horz_bound)->current_edge->top, rings, active_bounds);
}
*bound_max_pair = nullptr;
*horz_bound = nullptr;
return next_bnd_itr;
active_bounds.erase(bound_max_pair);
return active_bounds.erase(horz_bound);
}
intersect_bounds(*(*bnd), *(*horz_bound), mapbox::geometry::point<T>(wround<T>((*bnd)->current_x), scanline_y),
intersect_bounds(bnd_forward, horz_bound,
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y),
cliptype, subject_fill_type, clip_fill_type, rings, active_bounds);
std::iter_swap(horz_bound, bnd);
horz_bound = bnd;
++bnd;
swap_positions_in_ABL(horz_bound, bnd_forward, active_bounds);
// Why are we not incrementing the bnd iterator here:
// It is because reverse iterators point to a `base()` iterator that is a forward
// iterator that is one ahead of the reverse bound. This will always be the horizontal
// bound,
// so what the reverse bound points to will have changed.
} // end while (bnd != active_bounds.rend())
if ((*horz_bound)->ring) {
@ -203,16 +214,21 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
++hp_itr;
}
}
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
}
if ((*horz_bound)->next_edge != (*horz_bound)->edges.end()) {
next_edge_in_bound(*(*horz_bound), scanbeam);
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
next_edge_in_bound(horz_bound, scanbeam);
} else {
next_edge_in_bound(horz_bound, scanbeam);
}
return std::next(horz_bound);
} else {
*horz_bound = nullptr;
if ((*horz_bound)->ring) {
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
}
return active_bounds.erase(horz_bound);
}
return next_bnd_itr;
}
template <typename T>
@ -225,11 +241,13 @@ active_bound_list_itr<T> process_horizontal(T scanline_y,
fill_type subject_fill_type,
fill_type clip_fill_type) {
if ((*horz_bound)->current_edge->bot.x < (*horz_bound)->current_edge->top.x) {
return process_horizontal_left_to_right(scanline_y, horz_bound, active_bounds, rings, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
return process_horizontal_left_to_right(scanline_y, horz_bound, active_bounds, rings,
scanbeam, cliptype, subject_fill_type,
clip_fill_type);
} else {
return process_horizontal_right_to_left(scanline_y, horz_bound, active_bounds, rings, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
return process_horizontal_right_to_left(scanline_y, horz_bound, active_bounds, rings,
scanbeam, cliptype, subject_fill_type,
clip_fill_type);
}
}
@ -242,15 +260,14 @@ void process_horizontals(T scanline_y,
fill_type subject_fill_type,
fill_type clip_fill_type) {
for (auto bnd_itr = active_bounds.begin(); bnd_itr != active_bounds.end();) {
if (*bnd_itr != nullptr && current_edge_is_horizontal<T>(bnd_itr)) {
bnd_itr = process_horizontal(scanline_y, bnd_itr, active_bounds, rings, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
if (current_edge_is_horizontal<T>(bnd_itr)) {
bnd_itr = process_horizontal(scanline_y, bnd_itr, active_bounds, rings, scanbeam,
cliptype, subject_fill_type, clip_fill_type);
} else {
++bnd_itr;
}
}
active_bounds.erase(std::remove(active_bounds.begin(), active_bounds.end(), nullptr), active_bounds.end());
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -3,7 +3,6 @@
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
#include <mapbox/geometry/wagyu/config.hpp>
#include <mapbox/geometry/wagyu/edge.hpp>
#include <mapbox/geometry/wagyu/interrupt.hpp>
#include <mapbox/geometry/wagyu/intersect_util.hpp>
#include <mapbox/geometry/wagyu/local_minimum.hpp>
#include <mapbox/geometry/wagyu/local_minimum_util.hpp>
@ -23,35 +22,39 @@ active_bound_list_itr<T> do_maxima(active_bound_list_itr<T>& bnd,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type,
ring_manager<T>& manager,
ring_manager<T>& rings,
active_bound_list<T>& active_bounds) {
if (bndMaxPair == active_bounds.end()) {
if ((*bnd)->ring) {
add_point_to_ring(*(*bnd), (*bnd)->current_edge->top, rings);
}
return active_bounds.erase(bnd);
}
auto bnd_next = std::next(bnd);
auto return_bnd = bnd;
auto return_bnd = bnd_next;
bool skipped = false;
while (bnd_next != active_bounds.end() && bnd_next != bndMaxPair) {
if (*bnd_next == nullptr) {
++bnd_next;
continue;
}
skipped = true;
intersect_bounds(*(*bnd), *(*bnd_next), (*bnd)->current_edge->top, cliptype, subject_fill_type, clip_fill_type,
manager, active_bounds);
std::iter_swap(bnd, bnd_next);
bnd = bnd_next;
++bnd_next;
intersect_bounds(bnd, bnd_next, (*bnd)->current_edge->top, cliptype, subject_fill_type,
clip_fill_type, rings, active_bounds);
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
bnd_next = std::next(bnd);
}
if ((*bnd)->ring && (*bndMaxPair)->ring) {
add_local_maximum_point(*(*bnd), *(*bndMaxPair), (*bnd)->current_edge->top, manager, active_bounds);
} else if ((*bnd)->ring || (*bndMaxPair)->ring) {
if (!(*bnd)->ring && !(*bndMaxPair)->ring) {
active_bounds.erase(bndMaxPair);
} else if ((*bnd)->ring && (*bndMaxPair)->ring) {
add_local_maximum_point(bnd, bndMaxPair, (*bnd)->current_edge->top, rings, active_bounds);
active_bounds.erase(bndMaxPair);
} else {
throw std::runtime_error("DoMaxima error");
}
*bndMaxPair = nullptr;
*bnd = nullptr;
if (!skipped) {
++return_bnd;
auto prev_itr = active_bounds.erase(bnd);
if (skipped) {
return return_bnd;
} else {
return prev_itr;
}
return return_bnd;
}
template <typename T>
@ -60,17 +63,12 @@ void process_edges_at_top_of_scanbeam(T top_y,
scanbeam_list<T>& scanbeam,
local_minimum_ptr_list<T> const& minima_sorted,
local_minimum_ptr_list_itr<T>& current_lm,
ring_manager<T>& manager,
ring_manager<T>& rings,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type) {
for (auto bnd = active_bounds.begin(); bnd != active_bounds.end();) {
interrupt_check(); // Check for interruptions
if (*bnd == nullptr) {
++bnd;
continue;
}
// 1. Process maxima, treating them as if they are "bent" horizontal edges,
// but exclude maxima with horizontal edges.
@ -78,10 +76,12 @@ void process_edges_at_top_of_scanbeam(T top_y,
if (is_maxima_edge) {
auto bnd_max_pair = get_maxima_pair(bnd, active_bounds);
is_maxima_edge = ((bnd_max_pair == active_bounds.end() || !current_edge_is_horizontal<T>(bnd_max_pair)) &&
is_maxima_edge = ((bnd_max_pair == active_bounds.end() ||
!current_edge_is_horizontal<T>(bnd_max_pair)) &&
is_maxima(bnd_max_pair, top_y));
if (is_maxima_edge) {
bnd = do_maxima(bnd, bnd_max_pair, cliptype, subject_fill_type, clip_fill_type, manager, active_bounds);
bnd = do_maxima(bnd, bnd_max_pair, cliptype, subject_fill_type, clip_fill_type,
rings, active_bounds);
continue;
}
}
@ -89,35 +89,37 @@ void process_edges_at_top_of_scanbeam(T top_y,
// 2. Promote horizontal edges.
if (is_intermediate(bnd, top_y) && next_edge_is_horizontal<T>(bnd)) {
if ((*bnd)->ring) {
insert_hot_pixels_in_path(*(*bnd), (*bnd)->current_edge->top, manager, false);
insert_hot_pixels_in_path(*(*bnd), (*bnd)->current_edge->top, rings, false);
}
next_edge_in_bound(*(*bnd), scanbeam);
next_edge_in_bound(bnd, scanbeam);
if ((*bnd)->ring) {
add_point_to_ring(*(*bnd), (*bnd)->current_edge->bot, manager);
add_point_to_ring(*(*bnd), (*bnd)->current_edge->bot, rings);
}
} else {
(*bnd)->current_x = get_current_x(*((*bnd)->current_edge), top_y);
}
++bnd;
}
active_bounds.erase(std::remove(active_bounds.begin(), active_bounds.end(), nullptr), active_bounds.end());
insert_horizontal_local_minima_into_ABL(top_y, minima_sorted, current_lm, active_bounds, manager, scanbeam,
cliptype, subject_fill_type, clip_fill_type);
insert_horizontal_local_minima_into_ABL(top_y, minima_sorted, current_lm, active_bounds, rings,
scanbeam, cliptype, subject_fill_type, clip_fill_type);
process_horizontals(top_y, active_bounds, manager, scanbeam, cliptype, subject_fill_type, clip_fill_type);
process_horizontals(top_y, active_bounds, rings, scanbeam, cliptype, subject_fill_type,
clip_fill_type);
// 4. Promote intermediate vertices
for (auto bnd = active_bounds.begin(); bnd != active_bounds.end(); ++bnd) {
if (is_intermediate(bnd, top_y)) {
if ((*bnd)->ring) {
add_point_to_ring(*(*bnd), (*bnd)->current_edge->top, manager);
add_point_to_ring(*(*bnd), (*bnd)->current_edge->top, rings);
insert_hot_pixels_in_path(*(*bnd), (*bnd)->current_edge->top, rings, false);
}
next_edge_in_bound(*(*bnd), scanbeam);
next_edge_in_bound(bnd, scanbeam);
}
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -18,31 +18,23 @@ mapbox::geometry::point<T> intersect(mapbox::geometry::point<T> a,
switch (edge) {
case 0:
return mapbox::geometry::point<T>(
mapbox::geometry::wagyu::wround<T>(static_cast<double>(a.x) + static_cast<double>(b.x - a.x) *
static_cast<double>(box.min.y - a.y) /
static_cast<double>(b.y - a.y)),
static_cast<T>(a.x + static_cast<double>(b.x - a.x) * (box.min.y - a.y) / (b.y - a.y)),
box.min.y);
case 1:
return mapbox::geometry::point<T>(
box.max.x,
mapbox::geometry::wagyu::wround<T>(static_cast<double>(a.y) + static_cast<double>(b.y - a.y) *
static_cast<double>(box.max.x - a.x) /
static_cast<double>(b.x - a.x)));
static_cast<T>(a.y + static_cast<double>(b.y - a.y) * (box.max.x - a.x) / (b.x - a.x)));
case 2:
return mapbox::geometry::point<T>(
mapbox::geometry::wagyu::wround<T>(static_cast<double>(a.x) + static_cast<double>(b.x - a.x) *
static_cast<double>(box.max.y - a.y) /
static_cast<double>(b.y - a.y)),
static_cast<T>(a.x + static_cast<double>(b.x - a.x) * (box.max.y - a.y) / (b.y - a.y)),
box.max.y);
default: // case 3
return mapbox::geometry::point<T>(
box.min.x,
mapbox::geometry::wagyu::wround<T>(static_cast<double>(a.y) + static_cast<double>(b.y - a.y) *
static_cast<double>(box.min.x - a.x) /
static_cast<double>(b.x - a.x)));
static_cast<T>(a.y + static_cast<double>(b.y - a.y) * (box.min.x - a.x) / (b.x - a.x)));
}
}
@ -65,7 +57,7 @@ bool inside(mapbox::geometry::point<T> p, size_t edge, mapbox::geometry::box<T>
template <typename T>
mapbox::geometry::linear_ring<T> quick_lr_clip(mapbox::geometry::linear_ring<T> const& ring,
mapbox::geometry::box<T> const& b) {
mapbox::geometry::box<T> const& b) {
mapbox::geometry::linear_ring<T> out = ring;
for (size_t edge = 0; edge < 4; edge++) {
@ -101,11 +93,12 @@ mapbox::geometry::linear_ring<T> quick_lr_clip(mapbox::geometry::linear_ring<T>
}
return out;
}
} // namespace quick_clip
}
template <typename T>
mapbox::geometry::multi_polygon<T>
clip(mapbox::geometry::polygon<T> const& poly, mapbox::geometry::box<T> const& b, fill_type subject_fill_type) {
mapbox::geometry::multi_polygon<T> clip(mapbox::geometry::polygon<T> const& poly,
mapbox::geometry::box<T> const& b,
fill_type subject_fill_type) {
mapbox::geometry::multi_polygon<T> result;
wagyu<T> clipper;
for (auto const& lr : poly) {
@ -119,8 +112,9 @@ clip(mapbox::geometry::polygon<T> const& poly, mapbox::geometry::box<T> const& b
}
template <typename T>
mapbox::geometry::multi_polygon<T>
clip(mapbox::geometry::multi_polygon<T> const& mp, mapbox::geometry::box<T> const& b, fill_type subject_fill_type) {
mapbox::geometry::multi_polygon<T> clip(mapbox::geometry::multi_polygon<T> const& mp,
mapbox::geometry::box<T> const& b,
fill_type subject_fill_type) {
mapbox::geometry::multi_polygon<T> result;
wagyu<T> clipper;
for (auto const& poly : mp) {
@ -134,6 +128,6 @@ clip(mapbox::geometry::multi_polygon<T> const& mp, mapbox::geometry::box<T> cons
clipper.execute(clip_type_union, result, subject_fill_type, fill_type_even_odd);
return result;
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -5,7 +5,6 @@
#include <deque>
#include <list>
#include <map>
#include <mapbox/geometry/box.hpp>
#include <mapbox/geometry/wagyu/point.hpp>
#include <set>
#include <sstream>
@ -30,117 +29,35 @@ namespace mapbox {
namespace geometry {
namespace wagyu {
template <typename T>
double area_from_point(point_ptr<T> op, std::size_t& size, mapbox::geometry::box<T>& bbox) {
point_ptr<T> startOp = op;
size = 0;
double a = 0.0;
T min_x = op->x;
T max_x = op->x;
T min_y = op->y;
T max_y = op->y;
do {
++size;
if (op->x > max_x) {
max_x = op->x;
} else if (op->x < min_x) {
min_x = op->x;
}
if (op->y > max_y) {
max_y = op->y;
} else if (op->y < min_y) {
min_y = op->y;
}
a += static_cast<double>(op->prev->x + op->x) * static_cast<double>(op->prev->y - op->y);
op = op->next;
} while (op != startOp);
bbox.min.x = min_x;
bbox.max.x = max_x;
bbox.min.y = min_y;
bbox.max.y = max_y;
return a * 0.5;
}
// NOTE: ring and ring_ptr are forward declared in wagyu/point.hpp
template <typename T>
using ring_vector = std::vector<ring_ptr<T>>;
template <typename T>
using ring_list = std::list<ring_ptr<T>>;
template <typename T>
struct ring {
std::size_t ring_index; // To support unset 0 is undefined and indexes offset by 1
std::size_t size_; // number of points in the ring
double area_; // area of the ring
mapbox::geometry::box<T> bbox; // bounding box of the ring
std::size_t size;
double area;
ring_ptr<T> parent;
ring_vector<T> children;
ring_list<T> children;
point_ptr<T> points;
point_ptr<T> bottom_point;
bool is_hole_;
bool corrected;
ring(ring const&) = delete;
ring& operator=(ring const&) = delete;
ring()
: ring_index(0),
size_(0),
area_(std::numeric_limits<double>::quiet_NaN()),
bbox({ 0, 0 }, { 0, 0 }),
size(0),
area(std::numeric_limits<double>::quiet_NaN()),
parent(nullptr),
children(),
points(nullptr),
bottom_point(nullptr),
is_hole_(false),
corrected(false) {
}
void reset_stats() {
area_ = std::numeric_limits<double>::quiet_NaN();
is_hole_ = false;
bbox.min.x = 0;
bbox.min.y = 0;
bbox.max.x = 0;
bbox.max.y = 0;
size_ = 0;
}
void recalculate_stats() {
if (points != nullptr) {
area_ = area_from_point(points, size_, bbox);
is_hole_ = !(area_ > 0.0);
}
}
void set_stats(double a, std::size_t s, mapbox::geometry::box<T> const& b) {
bbox = b;
area_ = a;
size_ = s;
is_hole_ = !(area_ > 0.0);
}
double area() {
if (std::isnan(area_)) {
recalculate_stats();
}
return area_;
}
bool is_hole() {
if (std::isnan(area_)) {
recalculate_stats();
}
return is_hole_;
}
std::size_t size() {
if (std::isnan(area_)) {
recalculate_stats();
}
return size_;
bottom_point(nullptr) {
}
};
@ -156,8 +73,8 @@ using hot_pixel_rev_itr = typename hot_pixel_vector<T>::reverse_iterator;
template <typename T>
struct ring_manager {
ring_vector<T> children;
point_vector<T> all_points;
ring_list<T> children;
std::vector<point_ptr<T>> all_points;
hot_pixel_vector<T> hot_pixels;
hot_pixel_itr<T> current_hp_itr;
std::deque<point<T>> points;
@ -187,15 +104,16 @@ void preallocate_point_memory(ring_manager<T>& rings, std::size_t size) {
}
template <typename T>
ring_ptr<T> create_new_ring(ring_manager<T>& manager) {
manager.rings.emplace_back();
ring_ptr<T> result = &manager.rings.back();
result->ring_index = manager.index++;
ring_ptr<T> create_new_ring(ring_manager<T>& rings) {
rings.rings.emplace_back();
ring_ptr<T> result = &rings.rings.back();
result->ring_index = rings.index++;
return result;
}
template <typename T>
point_ptr<T> create_new_point(ring_ptr<T> r, mapbox::geometry::point<T> const& pt, ring_manager<T>& rings) {
point_ptr<T>
create_new_point(ring_ptr<T> r, mapbox::geometry::point<T> const& pt, ring_manager<T>& rings) {
point_ptr<T> point;
if (rings.storage.size() < rings.storage.capacity()) {
rings.storage.emplace_back(r, pt);
@ -226,179 +144,79 @@ point_ptr<T> create_new_point(ring_ptr<T> r,
}
template <typename T>
void set_to_children(ring_ptr<T> r, ring_vector<T>& children) {
for (auto& c : children) {
if (c == nullptr) {
c = r;
return;
}
}
children.push_back(r);
}
template <typename T>
void remove_from_children(ring_ptr<T> r, ring_vector<T>& children) {
for (auto& c : children) {
if (c == r) {
c = nullptr;
return;
}
}
}
template <typename T>
void assign_as_child(ring_ptr<T> new_ring, ring_ptr<T> parent, ring_manager<T>& manager) {
// Assigning as a child assumes that this is
// a brand new ring. Therefore it does
// not have any existing relationships
if ((parent == nullptr && new_ring->is_hole()) || (parent != nullptr && new_ring->is_hole() == parent->is_hole())) {
throw std::runtime_error("Trying to assign a child that is the same orientation as the parent");
}
auto& children = parent == nullptr ? manager.children : parent->children;
set_to_children(new_ring, children);
new_ring->parent = parent;
}
template <typename T>
void reassign_as_child(ring_ptr<T> ring, ring_ptr<T> parent, ring_manager<T>& manager) {
// Reassigning a ring assumes it already
// has an existing parent
if ((parent == nullptr && ring->is_hole()) || (parent != nullptr && ring->is_hole() == parent->is_hole())) {
throw std::runtime_error("Trying to re-assign a child that is the same orientation as the parent");
}
// Remove the old child relationship
auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
remove_from_children(ring, old_children);
// Add new child relationship
auto& children = parent == nullptr ? manager.children : parent->children;
set_to_children(ring, children);
ring->parent = parent;
}
template <typename T>
void assign_as_sibling(ring_ptr<T> new_ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
// Assigning as a sibling assumes that this is
// a brand new ring. Therefore it does
// not have any existing relationships
if (new_ring->is_hole() != sibling->is_hole()) {
throw std::runtime_error("Trying to assign to be a sibling that is not the same orientation as the sibling");
}
auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
set_to_children(new_ring, children);
new_ring->parent = sibling->parent;
}
template <typename T>
void reassign_as_sibling(ring_ptr<T> ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
if (ring->parent == sibling->parent) {
void ring1_child_of_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
assert(ring1 != ring2);
if (ring1->parent == ring2) {
return;
}
// Assigning as a sibling assumes that this is
// a brand new ring. Therefore it does
// not have any existing relationships
if (ring->is_hole() != sibling->is_hole()) {
throw std::runtime_error("Trying to assign to be a sibling that is not the same orientation as the sibling");
if (ring1->parent == nullptr) {
manager.children.remove(ring1);
} else {
ring1->parent->children.remove(ring1);
}
// Remove the old child relationship
auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
remove_from_children(ring, old_children);
// Add new relationship
auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
set_to_children(ring, children);
ring->parent = sibling->parent;
if (ring2 == nullptr) {
ring1->parent = nullptr;
manager.children.push_back(ring1);
} else {
ring1->parent = ring2;
ring2->children.push_back(ring1);
}
}
template <typename T>
void ring1_sibling_of_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
assert(ring1 != ring2);
if (ring1->parent == ring2->parent) {
return;
}
if (ring1->parent == nullptr) {
manager.children.remove(ring1);
} else {
ring1->parent->children.remove(ring1);
}
if (ring2->parent == nullptr) {
manager.children.push_back(ring1);
} else {
ring2->parent->children.push_back(ring1);
}
ring1->parent = ring2->parent;
}
template <typename T>
void ring1_replaces_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
assert(ring1 != ring2);
auto& ring1_children = ring1 == nullptr ? manager.children : ring1->children;
if (ring2->parent == nullptr) {
manager.children.remove(ring2);
} else {
ring2->parent->children.remove(ring2);
}
for (auto& c : ring2->children) {
if (c == nullptr) {
continue;
}
c->parent = ring1;
set_to_children(c, ring1_children);
c = nullptr;
}
// Remove the old child relationship
auto& old_children = ring2->parent == nullptr ? manager.children : ring2->parent->children;
remove_from_children(ring2, old_children);
ring2->points = nullptr;
ring2->reset_stats();
if (ring1 == nullptr) {
manager.children.splice(manager.children.end(), ring2->children);
} else {
ring1->children.splice(ring1->children.end(), ring2->children);
}
ring2->parent = nullptr;
}
template <typename T>
void remove_points(point_ptr<T> pt) {
if (pt != nullptr) {
pt->prev->next = nullptr;
while (pt != nullptr) {
point_ptr<T> tmp = pt;
pt = pt->next;
tmp->next = nullptr;
tmp->prev = nullptr;
tmp->ring = nullptr;
void remove_ring(ring_ptr<T> r, ring_manager<T>& manager) {
if (r->parent == nullptr) {
manager.children.remove(r);
for (auto& c : r->children) {
c->parent = nullptr;
}
}
}
template <typename T>
void remove_ring_and_points(ring_ptr<T> r,
ring_manager<T>& manager,
bool remove_children = true,
bool remove_from_parent = true) {
// Removes a ring and any children that might be
// under that ring.
for (auto& c : r->children) {
if (c == nullptr) {
continue;
manager.children.splice(manager.children.end(), r->children);
} else {
r->parent->children.remove(r);
for (auto& c : r->children) {
c->parent = r->parent;
}
if (remove_children) {
remove_ring_and_points(c, manager, true, false);
}
c = nullptr;
r->parent->children.splice(r->parent->children.end(), r->children);
r->parent = nullptr;
}
if (remove_from_parent) {
// Remove the old child relationship
auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
remove_from_children(r, old_children);
}
point_ptr<T> pt = r->points;
if (pt != nullptr) {
pt->prev->next = nullptr;
while (pt != nullptr) {
point_ptr<T> tmp = pt;
pt = pt->next;
tmp->next = nullptr;
tmp->prev = nullptr;
tmp->ring = nullptr;
}
}
r->points = nullptr;
r->reset_stats();
}
template <typename T>
void remove_ring(ring_ptr<T> r, ring_manager<T>& manager, bool remove_children = true, bool remove_from_parent = true) {
// Removes a ring and any children that might be
// under that ring.
for (auto& c : r->children) {
if (c == nullptr) {
continue;
}
if (remove_children) {
remove_ring(c, manager, true, false);
}
c = nullptr;
}
if (remove_from_parent) {
// Remove the old child relationship
auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
remove_from_children(r, old_children);
}
r->points = nullptr;
r->reset_stats();
}
template <typename T>
@ -416,10 +234,6 @@ inline std::size_t ring_depth(ring_ptr<T> r) {
template <typename T>
inline bool ring_is_hole(ring_ptr<T> r) {
// This is different then the "normal" way of determing if
// a ring is a hole or not because it uses the depth of the
// the ring to determine if it is a hole or not. This is only done
// intially when rings are output from Vatti.
return ring_depth(r) & 1;
}
@ -449,6 +263,17 @@ void init(const_point_ptr<T>& node) {
set_prev(node, node);
}
template <typename T>
std::size_t point_count(const const_point_ptr<T>& orig_node) {
std::size_t size = 0;
point_ptr<T> n = orig_node;
do {
n = get_next(n);
++size;
} while (n != orig_node);
return size;
}
template <typename T>
void link_before(point_ptr<T>& node, point_ptr<T>& new_node) {
point_ptr<T> prev_node = get_prev(node);
@ -500,10 +325,33 @@ void reverse_ring(point_ptr<T> pp) {
} while (pp1 != pp);
}
template <typename T>
double area_from_point(point_ptr<T> op, std::size_t& size) {
point_ptr<T> startOp = op;
size = 1;
double a = 0.0;
do {
++size;
a += static_cast<double>(op->prev->x + op->x) * static_cast<double>(op->prev->y - op->y);
op = op->next;
} while (op != startOp);
return a * 0.5;
}
template <typename T>
double area(ring_ptr<T> r) {
assert(r != nullptr);
if (std::isnan(r->area)) {
r->area = area_from_point(r->points, r->size);
}
return r->area;
}
#ifdef DEBUG
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, ring<T>& r) {
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const ring<T>& r) {
out << " ring_index: " << r.ring_index << std::endl;
if (!r.parent) {
// out << " parent_ring ptr: nullptr" << std::endl;
@ -520,7 +368,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
}
auto pt_itr = r.points;
if (pt_itr) {
out << " area: " << r.area() << std::endl;
out << " area: " << r.area << std::endl;
out << " points:" << std::endl;
out << " [[[" << pt_itr->x << "," << pt_itr->y << "],";
pt_itr = pt_itr->next;
@ -536,22 +384,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
return out;
}
template <typename T>
std::string debug_ring_addresses(ring_ptr<T> r) {
std::ostringstream out;
out << "Ring: " << r->ring_index << std::endl;
if (r->points == nullptr) {
out << " Ring has no points" << std::endl;
return out.str();
}
auto pt_itr = r->points;
do {
out << " [" << pt_itr->x << "," << pt_itr->y << "] - " << pt_itr << std::endl;
pt_itr = pt_itr->next;
} while (pt_itr != r->points);
return out.str();
}
template <typename T>
std::string output_as_polygon(ring_ptr<T> r) {
std::ostringstream out;
@ -567,9 +399,6 @@ std::string output_as_polygon(ring_ptr<T> r) {
}
out << "[" << pt_itr->x << "," << pt_itr->y << "]]";
for (auto const& c : r->children) {
if (c == nullptr) {
continue;
}
pt_itr = c->points;
if (pt_itr) {
out << ",[[" << pt_itr->x << "," << pt_itr->y << "],";
@ -590,10 +419,23 @@ std::string output_as_polygon(ring_ptr<T> r) {
}
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, ring_vector<T>& rings) {
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const ring_list<T>& rings) {
out << "START RING LIST" << std::endl;
for (auto& r : rings) {
out << " ring: " << r->ring_index << " - " << r << std::endl;
out << *r;
}
out << "END RING LIST" << std::endl;
return out;
}
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
const ring_vector<T>& rings) {
out << "START RING VECTOR" << std::endl;
for (auto& r : rings) {
if (r == nullptr || !r->points) {
if (!r->points) {
continue;
}
out << " ring: " << r->ring_index << " - " << r << std::endl;
@ -605,7 +447,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
std::deque<ring<T>>& rings) {
const std::deque<ring<T>>& rings) {
out << "START RING VECTOR" << std::endl;
for (auto& r : rings) {
if (!r.points) {
@ -620,7 +462,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
template <class charT, class traits, typename T>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
hot_pixel_vector<T>& hp_vec) {
const hot_pixel_vector<T>& hp_vec) {
out << "Hot Pixels: " << std::endl;
for (auto& hp : hp_vec) {
out << hp << std::endl;
@ -628,6 +470,6 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
return out;
}
#endif
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -15,7 +15,7 @@
// free(strs);
#endif
#include <algorithm>
#include <queue>
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
#include <mapbox/geometry/wagyu/config.hpp>
@ -28,31 +28,55 @@ namespace geometry {
namespace wagyu {
template <typename T>
void set_hole_state(bound<T>& bnd, active_bound_list<T> const& active_bounds, ring_manager<T>& rings) {
auto bnd_itr = std::find(active_bounds.rbegin(), active_bounds.rend(), &bnd);
++bnd_itr;
void set_hole_state(active_bound_list_itr<T>& bnd,
active_bound_list<T>& active_bounds,
ring_manager<T>& rings) {
auto bnd2 = active_bound_list_rev_itr<T>(bnd);
bound_ptr<T> bndTmp = nullptr;
// Find first non line ring to the left of current bound.
while (bnd_itr != active_bounds.rend()) {
if (*bnd_itr == nullptr) {
++bnd_itr;
continue;
}
if ((*bnd_itr)->ring) {
while (bnd2 != active_bounds.rend()) {
if ((*bnd2)->ring && (*bnd2)->winding_delta != 0) {
if (!bndTmp) {
bndTmp = (*bnd_itr);
} else if (bndTmp->ring == (*bnd_itr)->ring) {
bndTmp = (*bnd2);
} else if (bndTmp->ring == (*bnd2)->ring) {
bndTmp = nullptr;
}
}
++bnd_itr;
++bnd2;
}
if (!bndTmp) {
bnd.ring->parent = nullptr;
rings.children.push_back(bnd.ring);
(*bnd)->ring->parent = nullptr;
rings.children.push_back((*bnd)->ring);
} else {
bnd.ring->parent = bndTmp->ring;
bndTmp->ring->children.push_back(bnd.ring);
(*bnd)->ring->parent = bndTmp->ring;
bndTmp->ring->children.push_back((*bnd)->ring);
}
}
template <typename T>
void set_hole_state(active_bound_list_rev_itr<T>& bnd,
active_bound_list<T>& active_bounds,
ring_manager<T>& rings) {
auto bnd2 = std::next(bnd);
bound_ptr<T> bndTmp = nullptr;
// Find first non line ring to the left of current bound.
while (bnd2 != active_bounds.rend()) {
if ((*bnd2)->ring && (*bnd2)->winding_delta != 0) {
if (!bndTmp) {
bndTmp = (*bnd2);
} else if (bndTmp->ring == (*bnd2)->ring) {
bndTmp = nullptr;
}
}
++bnd2;
}
if (!bndTmp) {
(*bnd)->ring->parent = nullptr;
rings.children.push_back((*bnd)->ring);
} else {
(*bnd)->ring->parent = bndTmp->ring;
bndTmp->ring->children.push_back((*bnd)->ring);
}
}
@ -65,7 +89,8 @@ void update_current_hp_itr(T scanline_y, ring_manager<T>& rings) {
template <typename T>
struct hot_pixel_sorter {
inline bool operator()(mapbox::geometry::point<T> const& pt1, mapbox::geometry::point<T> const& pt2) {
inline bool operator()(mapbox::geometry::point<T> const& pt1,
mapbox::geometry::point<T> const& pt2) {
if (pt1.y == pt2.y) {
return pt1.x < pt2.x;
} else {
@ -74,17 +99,18 @@ struct hot_pixel_sorter {
}
};
// Due to the nature of floating point calculations
// and the high likely hood of values around X.5, we
// need to fudge what is X.5 some for our rounding.
const double rounding_offset = 1e-12;
const double rounding_offset_y = 5e-13;
template <typename T>
T round_towards_min(double val) {
// 0.5 rounds to 0
// 0.0 rounds to 0
// -0.5 rounds to -1
double half = std::floor(val) + 0.5;
if (values_are_equal(val, half)) {
return static_cast<T>(std::floor(val));
} else {
return static_cast<T>(std::llround(val));
}
return static_cast<T>(std::ceil(val - 0.5 + rounding_offset));
}
template <typename T>
@ -92,12 +118,7 @@ T round_towards_max(double val) {
// 0.5 rounds to 1
// 0.0 rounds to 0
// -0.5 rounds to 0
double half = std::floor(val) + 0.5;
if (values_are_equal(val, half)) {
return static_cast<T>(std::ceil(val));
} else {
return static_cast<T>(std::llround(val));
}
return static_cast<T>(std::floor(val + 0.5 + rounding_offset));
}
template <typename T>
@ -122,7 +143,8 @@ inline T get_edge_min_x(edge<T> const& edge, const T current_y) {
return edge.bot.x;
} else {
double return_val =
static_cast<double>(edge.bot.x) + edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5);
static_cast<double>(edge.bot.x) +
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
T value = round_towards_min<T>(return_val);
return value;
}
@ -151,7 +173,8 @@ inline T get_edge_max_x(edge<T> const& edge, const T current_y) {
return edge.bot.x;
} else {
double return_val =
static_cast<double>(edge.bot.x) + edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5);
static_cast<double>(edge.bot.x) +
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
T value = round_towards_max<T>(return_val);
return value;
}
@ -273,7 +296,8 @@ void insert_hot_pixels_in_path(bound<T>& bnd,
}
auto first_itr = hot_pixel_rev_itr<T>(itr);
bool add_end_point_itr = (y != end_pt.y || add_end_point);
hot_pixel_set_right_to_left(y, start_x, end_x, bnd, rings, first_itr, last_itr, add_end_point_itr);
hot_pixel_set_right_to_left(y, start_x, end_x, bnd, rings, first_itr, last_itr,
add_end_point_itr);
}
} else {
for (; itr != rings.hot_pixels.end();) {
@ -291,7 +315,8 @@ void insert_hot_pixels_in_path(bound<T>& bnd,
}
auto last_itr = itr;
bool add_end_point_itr = (y != end_pt.y || add_end_point);
hot_pixel_set_left_to_right(y, start_x, end_x, bnd, rings, first_itr, last_itr, add_end_point_itr);
hot_pixel_set_left_to_right(y, start_x, end_x, bnd, rings, first_itr, last_itr,
add_end_point_itr);
}
}
bnd.last_point = end_pt;
@ -303,20 +328,35 @@ void add_to_hot_pixels(mapbox::geometry::point<T> const& pt, ring_manager<T>& ri
}
template <typename T>
void add_first_point(bound<T>& bnd,
void add_first_point(active_bound_list_itr<T>& bnd,
active_bound_list<T>& active_bounds,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
ring_ptr<T> r = create_new_ring(rings);
bnd.ring = r;
(*bnd)->ring = r;
r->points = create_new_point(r, pt, rings);
set_hole_state(bnd, active_bounds, rings);
bnd.last_point = pt;
(*bnd)->last_point = pt;
}
template <typename T>
void add_point_to_ring(bound<T>& bnd, mapbox::geometry::point<T> const& pt, ring_manager<T>& rings) {
void add_first_point(active_bound_list_rev_itr<T>& bnd,
active_bound_list<T>& active_bounds,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
ring_ptr<T> r = create_new_ring(rings);
// no ring currently set!
(*bnd)->ring = r;
r->points = create_new_point(r, pt, rings);
set_hole_state(bnd, active_bounds, rings);
(*bnd)->last_point = pt;
}
template <typename T>
void add_point_to_ring(bound<T>& bnd,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
assert(bnd.ring);
// Handle hot pixels
insert_hot_pixels_in_path(bnd, pt, rings, false);
@ -337,35 +377,64 @@ void add_point_to_ring(bound<T>& bnd, mapbox::geometry::point<T> const& pt, ring
}
template <typename T>
void add_point(bound<T>& bnd,
void add_point(active_bound_list_itr<T>& bnd,
active_bound_list<T>& active_bounds,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
if (bnd.ring == nullptr) {
if (!(*bnd)->ring) {
add_first_point(bnd, active_bounds, pt, rings);
} else {
add_point_to_ring(bnd, pt, rings);
add_point_to_ring(*(*bnd), pt, rings);
}
}
template <typename T>
void add_local_minimum_point(bound<T>& b1,
bound<T>& b2,
void add_point(active_bound_list_rev_itr<T>& bnd,
active_bound_list<T>& active_bounds,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
if (!(*bnd)->ring) {
add_first_point(bnd, active_bounds, pt, rings);
} else {
add_point_to_ring(*(*bnd), pt, rings);
}
}
template <typename T>
void add_local_minimum_point(active_bound_list_itr<T> b1,
active_bound_list_itr<T> b2,
active_bound_list<T>& active_bounds,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings) {
if (is_horizontal(*b2.current_edge) || (b1.current_edge->dx > b2.current_edge->dx)) {
active_bound_list_itr<T> b;
active_bound_list_rev_itr<T> prev_bound;
active_bound_list_rev_itr<T> prev_b1(b1);
active_bound_list_rev_itr<T> prev_b2(b2);
if (is_horizontal(*((*b2)->current_edge)) ||
((*b1)->current_edge->dx > (*b2)->current_edge->dx)) {
add_point(b1, active_bounds, pt, rings);
b2.last_point = pt;
b2.ring = b1.ring;
b1.side = edge_left;
b2.side = edge_right;
(*b2)->last_point = pt;
(*b2)->ring = (*b1)->ring;
(*b1)->side = edge_left;
(*b2)->side = edge_right;
b = b1;
if (prev_b1 != active_bounds.rend() && std::prev(b) == b2) {
prev_bound = prev_b2;
} else {
prev_bound = prev_b1;
}
} else {
add_point(b2, active_bounds, pt, rings);
b1.last_point = pt;
b1.ring = b2.ring;
b1.side = edge_right;
b2.side = edge_left;
(*b1)->last_point = pt;
(*b1)->ring = (*b2)->ring;
(*b1)->side = edge_right;
(*b2)->side = edge_left;
b = b2;
if (prev_b2 != active_bounds.rend() && std::prev(b) == b1) {
prev_bound = prev_b1;
} else {
prev_bound = prev_b2;
}
}
}
@ -374,7 +443,7 @@ inline double get_dx(point<T> const& pt1, point<T> const& pt2) {
if (pt1.y == pt2.y) {
return std::numeric_limits<double>::infinity();
} else {
return static_cast<double>(pt2.x - pt1.x) / static_cast<double>(pt2.y - pt1.y);
return static_cast<double>(pt2.x - pt2.x) / static_cast<double>(pt2.y - pt1.y);
}
}
@ -407,8 +476,7 @@ bool first_is_bottom_point(const_point_ptr<T> btmPt1, const_point_ptr<T> btmPt2)
if (values_are_equal(std::max(dx1p, dx1n), std::max(dx2p, dx2n)) &&
values_are_equal(std::min(dx1p, dx1n), std::min(dx2p, dx2n))) {
std::size_t s = 0;
mapbox::geometry::box<T> bbox({ 0, 0 }, { 0, 0 });
return area_from_point(btmPt1, s, bbox) > 0.0; // if otherwise identical use orientation
return area_from_point(btmPt1, s) > 0.0; // if otherwise identical use orientation
} else {
return (greater_than_or_equal(dx1p, dx2p) && greater_than_or_equal(dx1p, dx2n)) ||
(greater_than_or_equal(dx1n, dx2p) && greater_than_or_equal(dx1n, dx2n));
@ -451,32 +519,32 @@ point_ptr<T> get_bottom_point(point_ptr<T> pp) {
}
template <typename T>
ring_ptr<T> get_lower_most_ring(ring_ptr<T> ring1, ring_ptr<T> ring2) {
ring_ptr<T> get_lower_most_ring(ring_ptr<T> outRec1, ring_ptr<T> outRec2) {
// work out which polygon fragment has the correct hole state ...
if (!ring1->bottom_point) {
ring1->bottom_point = get_bottom_point(ring1->points);
if (!outRec1->bottom_point) {
outRec1->bottom_point = get_bottom_point(outRec1->points);
}
if (!ring2->bottom_point) {
ring2->bottom_point = get_bottom_point(ring2->points);
if (!outRec2->bottom_point) {
outRec2->bottom_point = get_bottom_point(outRec2->points);
}
point_ptr<T> pt1 = ring1->bottom_point;
point_ptr<T> pt2 = ring2->bottom_point;
if (pt1->y > pt2->y) {
return ring1;
} else if (pt1->y < pt2->y) {
return ring2;
} else if (pt1->x < pt2->x) {
return ring1;
} else if (pt1->x > pt2->x) {
return ring2;
} else if (pt1->next == pt1) {
return ring2;
} else if (pt2->next == pt2) {
return ring1;
} else if (first_is_bottom_point(pt1, pt2)) {
return ring1;
point_ptr<T> OutPt1 = outRec1->bottom_point;
point_ptr<T> OutPt2 = outRec2->bottom_point;
if (OutPt1->y > OutPt2->y) {
return outRec1;
} else if (OutPt1->y < OutPt2->y) {
return outRec2;
} else if (OutPt1->x < OutPt2->x) {
return outRec1;
} else if (OutPt1->x > OutPt2->x) {
return outRec2;
} else if (OutPt1->next == OutPt1) {
return outRec2;
} else if (OutPt2->next == OutPt2) {
return outRec1;
} else if (first_is_bottom_point(OutPt1, OutPt2)) {
return outRec1;
} else {
return ring2;
return outRec2;
}
}
@ -501,10 +569,13 @@ void update_points_ring(ring_ptr<T> ring) {
}
template <typename T>
void append_ring(bound<T>& b1, bound<T>& b2, active_bound_list<T>& active_bounds, ring_manager<T>& manager) {
void append_ring(active_bound_list_itr<T>& b1,
active_bound_list_itr<T>& b2,
active_bound_list<T>& active_bounds,
ring_manager<T>& manager) {
// get the start and ends of both output polygons ...
ring_ptr<T> outRec1 = b1.ring;
ring_ptr<T> outRec2 = b2.ring;
ring_ptr<T> outRec1 = (*b1)->ring;
ring_ptr<T> outRec2 = (*b2)->ring;
ring_ptr<T> keep_ring;
bound_ptr<T> keep_bound;
@ -512,24 +583,24 @@ void append_ring(bound<T>& b1, bound<T>& b2, active_bound_list<T>& active_bounds
bound_ptr<T> remove_bound;
if (ring1_child_below_ring2(outRec1, outRec2)) {
keep_ring = outRec2;
keep_bound = &b2;
keep_bound = *b2;
remove_ring = outRec1;
remove_bound = &b1;
remove_bound = *b1;
} else if (ring1_child_below_ring2(outRec2, outRec1)) {
keep_ring = outRec1;
keep_bound = &b1;
keep_bound = *b1;
remove_ring = outRec2;
remove_bound = &b2;
remove_bound = *b2;
} else if (outRec1 == get_lower_most_ring(outRec1, outRec2)) {
keep_ring = outRec1;
keep_bound = &b1;
keep_bound = *b1;
remove_ring = outRec2;
remove_bound = &b2;
remove_bound = *b2;
} else {
keep_ring = outRec2;
keep_bound = &b2;
keep_bound = *b2;
remove_ring = outRec1;
remove_bound = &b1;
remove_bound = *b1;
}
// get the start and ends of both output polygons and
@ -594,9 +665,6 @@ void append_ring(bound<T>& b1, bound<T>& b2, active_bound_list<T>& active_bounds
remove_bound->ring = nullptr;
for (auto& b : active_bounds) {
if (b == nullptr) {
continue;
}
if (b->ring == remove_ring) {
b->ring = keep_ring;
b->side = keep_bound->side;
@ -606,18 +674,18 @@ void append_ring(bound<T>& b1, bound<T>& b2, active_bound_list<T>& active_bounds
}
template <typename T>
void add_local_maximum_point(bound<T>& b1,
bound<T>& b2,
void add_local_maximum_point(active_bound_list_itr<T>& b1,
active_bound_list_itr<T>& b2,
mapbox::geometry::point<T> const& pt,
ring_manager<T>& rings,
active_bound_list<T>& active_bounds) {
insert_hot_pixels_in_path(b2, pt, rings, false);
insert_hot_pixels_in_path(*(*b2), pt, rings, false);
add_point(b1, active_bounds, pt, rings);
if (b1.ring == b2.ring) {
b1.ring = nullptr;
b2.ring = nullptr;
if ((*b1)->ring == (*b2)->ring) {
(*b1)->ring = nullptr;
(*b2)->ring = nullptr;
// I am not certain that order is important here?
} else if (b1.ring->ring_index < b2.ring->ring_index) {
} else if ((*b1)->ring->ring_index < (*b2)->ring->ring_index) {
append_ring(b1, b2, active_bounds, rings);
} else {
append_ring(b2, b1, active_bounds, rings);
@ -637,7 +705,8 @@ point_in_polygon_result point_in_polygon(point<T> const& pt, point_ptr<T> op) {
point_ptr<T> startOp = op;
do {
if (op->next->y == pt.y) {
if ((op->next->x == pt.x) || (op->y == pt.y && ((op->next->x > pt.x) == (op->x < pt.x)))) {
if ((op->next->x == pt.x) ||
(op->y == pt.y && ((op->next->x > pt.x) == (op->x < pt.x)))) {
return point_on_polygon;
}
}
@ -652,8 +721,10 @@ point_in_polygon_result point_in_polygon(point<T> const& pt, point_ptr<T> op) {
result = point_outside_polygon;
}
} else {
double d = static_cast<double>(op->x - pt.x) * static_cast<double>(op->next->y - pt.y) -
static_cast<double>(op->next->x - pt.x) * static_cast<double>(op->y - pt.y);
double d =
static_cast<double>(op->x - pt.x) *
static_cast<double>(op->next->y - pt.y) -
static_cast<double>(op->next->x - pt.x) * static_cast<double>(op->y - pt.y);
if (value_is_zero(d)) {
return point_on_polygon;
}
@ -669,8 +740,10 @@ point_in_polygon_result point_in_polygon(point<T> const& pt, point_ptr<T> op) {
}
} else {
if (op->next->x > pt.x) {
double d = static_cast<double>(op->x - pt.x) * static_cast<double>(op->next->y - pt.y) -
static_cast<double>(op->next->x - pt.x) * static_cast<double>(op->y - pt.y);
double d =
static_cast<double>(op->x - pt.x) *
static_cast<double>(op->next->y - pt.y) -
static_cast<double>(op->next->x - pt.x) * static_cast<double>(op->y - pt.y);
if (value_is_zero(d)) {
return point_on_polygon;
}
@ -692,7 +765,8 @@ point_in_polygon_result point_in_polygon(point<T> const& pt, point_ptr<T> op) {
}
template <typename T>
point_in_polygon_result point_in_polygon(mapbox::geometry::point<double> const& pt, point_ptr<T> op) {
point_in_polygon_result point_in_polygon(mapbox::geometry::point<double> const& pt,
point_ptr<T> op) {
// returns 0 if false, +1 if true, -1 if pt ON polygon boundary
point_in_polygon_result result = point_outside_polygon;
point_ptr<T> startOp = op;
@ -718,11 +792,12 @@ point_in_polygon_result point_in_polygon(mapbox::geometry::point<double> const&
result = point_outside_polygon;
}
} else {
double d = (op_x - pt.x) * (op_next_y - pt.y) - (op_next_x - pt.x) * (op_y - pt.y);
double d =
(op_x - pt.x) * (op_next_y - pt.y) - (op_next_x - pt.x) * (op_y - pt.y);
if (value_is_zero(d)) {
return point_on_polygon;
}
if ((d > 0.0) == (op_next_y > op_y)) {
if ((d > 0.0) == (op_next_y > op->y)) {
// Switch between point outside polygon and point inside
// polygon
if (result == point_outside_polygon) {
@ -734,11 +809,12 @@ point_in_polygon_result point_in_polygon(mapbox::geometry::point<double> const&
}
} else {
if (op_next_x > pt.x) {
double d = (op_x - pt.x) * (op_next_y - pt.y) - (op_next_x - pt.x) * (op_y - pt.y);
double d =
(op_x - pt.x) * (op_next_y - pt.y) - (op_next_x - pt.x) * (op_y - pt.y);
if (value_is_zero(d)) {
return point_on_polygon;
}
if ((d > 0.0) == (op_next_y > op_y)) {
if ((d > 0.0) == (op_next_y > op->y)) {
// Switch between point outside polygon and point inside
// polygon
if (result == point_outside_polygon) {
@ -755,68 +831,47 @@ point_in_polygon_result point_in_polygon(mapbox::geometry::point<double> const&
return result;
}
template <typename T>
bool is_convex(point_ptr<T> edge) {
point_ptr<T> prev = edge->prev;
point_ptr<T> next = edge->next;
T v1x = edge->x - prev->x;
T v1y = edge->y - prev->y;
T v2x = next->x - edge->x;
T v2y = next->y - edge->y;
T cross = v1x * v2y - v2x * v1y;
if (cross < 0 && edge->ring->area() > 0) {
return true;
} else if (cross > 0 && edge->ring->area() < 0) {
return true;
} else {
return false;
}
}
template <typename T>
mapbox::geometry::point<double> centroid_of_points(point_ptr<T> edge) {
point_ptr<T> prev = edge->prev;
point_ptr<T> next = edge->next;
return { static_cast<double>(prev->x + edge->x + next->x) / 3.0,
static_cast<double>(prev->y + edge->y + next->y) / 3.0 };
}
template <typename T>
point_in_polygon_result inside_or_outside_special(point_ptr<T> first_pt, point_ptr<T> other_poly) {
// We are going to loop through all the points
// of the original triangle. The goal is to find a convex edge
// that with its next and previous forms a triangle with its centroid
// that is within the first ring. Then we will check the other polygon
// to see if it is within this polygon.
point_ptr<T> itr = first_pt;
if (value_is_zero(area(first_pt->ring))) {
return point_inside_polygon;
}
if (value_is_zero(area(other_poly->ring))) {
return point_outside_polygon;
}
point_ptr<T> pt = first_pt;
do {
if (is_convex(itr)) {
auto pt = centroid_of_points(itr);
if (point_inside_polygon == point_in_polygon(pt, first_pt)) {
return point_in_polygon(pt, other_poly);
if (*pt == *(pt->prev) || *pt == *(pt->next) || *(pt->next) == *(pt->prev) ||
slopes_equal(*(pt->prev), *pt, *(pt->next))) {
pt = pt->next;
continue;
}
double dx = ((pt->prev->x - pt->x) / 3.0) + ((pt->next->x - pt->x) / 3.0);
double dy = ((pt->prev->y - pt->y) / 3.0) + ((pt->next->y - pt->y) / 3.0);
mapbox::geometry::point<double> offset_pt(pt->x + dx, pt->y + dy);
point_in_polygon_result res = point_in_polygon(offset_pt, pt);
if (res != point_inside_polygon) {
offset_pt.x = pt->x - dx;
offset_pt.y = pt->y - dy;
res = point_in_polygon(offset_pt, pt);
if (res != point_inside_polygon) {
pt = pt->next;
continue;
}
}
itr = itr->next;
} while (itr != first_pt);
throw std::runtime_error("Could not find a point within the polygon to test");
}
template <typename T>
bool box2_contains_box1(mapbox::geometry::box<T> const& box1, mapbox::geometry::box<T> const& box2) {
return (box2.max.x >= box1.max.x && box2.max.y >= box1.max.y && box2.min.x <= box1.min.x &&
box2.min.y <= box1.min.y);
res = point_in_polygon(offset_pt, other_poly);
if (res == point_on_polygon) {
pt = pt->next;
continue;
}
return res;
} while (pt != first_pt);
return point_inside_polygon;
}
template <typename T>
bool poly2_contains_poly1(ring_ptr<T> ring1, ring_ptr<T> ring2) {
if (!box2_contains_box1(ring1->bbox, ring2->bbox)) {
return false;
}
if (std::fabs(ring2->area()) < std::fabs(ring1->area())) {
return false;
}
point_ptr<T> outpt1 = ring1->points->next;
point_ptr<T> outpt2 = ring2->points->next;
point_ptr<T> op = outpt1;
@ -831,6 +886,21 @@ bool poly2_contains_poly1(ring_ptr<T> ring1, ring_ptr<T> ring2) {
point_in_polygon_result res = inside_or_outside_special(outpt1, outpt2);
return res == point_inside_polygon;
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
template <typename T>
void dispose_out_points(point_ptr<T>& pp) {
if (pp == nullptr) {
return;
}
pp->prev->next = nullptr;
while (pp) {
point_ptr<T> tmpPp = pp;
pp = pp->next;
tmpPp->next = tmpPp;
tmpPp->prev = tmpPp;
tmpPp->ring = nullptr;
}
}
}
}
}

View File

@ -1,45 +1,37 @@
#pragma once
#include <queue>
#include <mapbox/geometry/wagyu/config.hpp>
#include <mapbox/geometry/wagyu/local_minimum.hpp>
#include <algorithm>
namespace mapbox {
namespace geometry {
namespace wagyu {
template <typename T>
using scanbeam_list = std::vector<T>;
template <typename T>
void insert_sorted_scanbeam(scanbeam_list<T>& scanbeam, T& t) {
typename scanbeam_list<T>::iterator i = std::lower_bound(scanbeam.begin(), scanbeam.end(), t);
if (i == scanbeam.end() || t < *i) {
scanbeam.insert(i, t);
}
}
using scanbeam_list = std::priority_queue<T>;
template <typename T>
bool pop_from_scanbeam(T& Y, scanbeam_list<T>& scanbeam) {
if (scanbeam.empty()) {
return false;
}
Y = scanbeam.back();
scanbeam.pop_back();
Y = scanbeam.top();
scanbeam.pop();
while (!scanbeam.empty() && Y == scanbeam.top()) {
scanbeam.pop();
} // Pop duplicates.
return true;
}
template <typename T>
void setup_scanbeam(local_minimum_list<T>& minima_list, scanbeam_list<T>& scanbeam) {
scanbeam.reserve(minima_list.size());
for (auto lm = minima_list.begin(); lm != minima_list.end(); ++lm) {
scanbeam.push_back(lm->y);
scanbeam.push(lm->y);
}
std::sort(scanbeam.begin(), scanbeam.end());
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -2,7 +2,6 @@
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
#include <mapbox/geometry/wagyu/bound.hpp>
#include <mapbox/geometry/wagyu/bubble_sort.hpp>
#include <mapbox/geometry/wagyu/config.hpp>
#include <mapbox/geometry/wagyu/edge.hpp>
#include <mapbox/geometry/wagyu/intersect.hpp>
@ -16,110 +15,93 @@ namespace geometry {
namespace wagyu {
template <typename T>
struct hp_intersection_swap {
ring_manager<T>& manager;
hp_intersection_swap(ring_manager<T>& m) : manager(m) {
}
void operator()(bound_ptr<T> const& b1, bound_ptr<T> const& b2) {
mapbox::geometry::point<double> pt;
if (!get_edge_intersection<T, double>(*(b1->current_edge), *(b2->current_edge), pt)) {
// LCOV_EXCL_START
throw std::runtime_error("Trying to find intersection of lines that do not intersect");
// LCOV_EXCL_END
}
add_to_hot_pixels(round_point<T>(pt), manager);
}
};
template <typename T>
void process_hot_pixel_intersections(T top_y, active_bound_list<T>& active_bounds, ring_manager<T>& manager) {
void process_hot_pixel_intersections(T top_y,
active_bound_list<T>& active_bounds,
ring_manager<T>& rings) {
if (active_bounds.empty()) {
return;
}
update_current_x(active_bounds, top_y);
bubble_sort(active_bounds.begin(), active_bounds.end(), intersection_compare<T>(),
hp_intersection_swap<T>(manager));
}
template <typename T>
bool horizontals_at_top_scanbeam(T top_y,
active_bound_list_itr<T>& bnd_curr,
active_bound_list<T>& active_bounds,
ring_manager<T>& manager) {
bool shifted = false;
auto& current_edge = (*bnd_curr)->current_edge;
(*bnd_curr)->current_x = static_cast<double>(current_edge->top.x);
if (current_edge->bot.x < current_edge->top.x) {
// left to right
auto bnd_next = std::next(bnd_curr);
while (bnd_next != active_bounds.end() &&
(*bnd_next == nullptr || (*bnd_next)->current_x < (*bnd_curr)->current_x)) {
if (*bnd_next != nullptr && (*bnd_next)->current_edge->top.y != top_y &&
(*bnd_next)->current_edge->bot.y != top_y) {
mapbox::geometry::point<T> pt(wround<T>((*bnd_next)->current_x), top_y);
add_to_hot_pixels(pt, manager);
}
std::iter_swap(bnd_curr, bnd_next);
++bnd_curr;
++bnd_next;
shifted = true;
}
} else {
// right to left
if (bnd_curr != active_bounds.begin()) {
auto bnd_prev = std::prev(bnd_curr);
while (bnd_curr != active_bounds.begin() &&
(*bnd_prev == nullptr || (*bnd_prev)->current_x > (*bnd_curr)->current_x)) {
if (*bnd_prev != nullptr && (*bnd_prev)->current_edge->top.y != top_y &&
(*bnd_prev)->current_edge->bot.y != top_y) {
mapbox::geometry::point<T> pt(wround<T>((*bnd_prev)->current_x), top_y);
add_to_hot_pixels(pt, manager);
}
std::iter_swap(bnd_curr, bnd_prev);
--bnd_curr;
if (bnd_curr != active_bounds.begin()) {
--bnd_prev;
update_current_x(active_bounds, top_y);
// bubblesort ...
bool isModified;
do {
isModified = false;
auto bnd = active_bounds.begin();
auto bnd_next = std::next(bnd);
while (bnd_next != active_bounds.end()) {
if ((*bnd)->current_x > (*bnd_next)->current_x &&
!slopes_equal(*(*bnd)->current_edge, *(*bnd_next)->current_edge)) {
mapbox::geometry::point<double> pt;
if (!get_edge_intersection<T, double>(*((*bnd)->current_edge),
*((*bnd_next)->current_edge), pt)) {
// LCOV_EXCL_START
throw std::runtime_error("Edges do not intersect!");
// LCOV_EXCL_END
}
add_to_hot_pixels(round_point<T>(pt), rings);
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
bnd_next = std::next(bnd);
isModified = true;
} else {
bnd = bnd_next;
++bnd_next;
}
}
}
return shifted;
} while (isModified);
}
template <typename T>
void process_hot_pixel_edges_at_top_of_scanbeam(T top_y,
scanbeam_list<T>& scanbeam,
active_bound_list<T>& active_bounds,
ring_manager<T>& manager) {
ring_manager<T>& rings) {
for (auto bnd = active_bounds.begin(); bnd != active_bounds.end();) {
if (*bnd == nullptr) {
++bnd;
continue;
}
bound<T>& current_bound = *(*bnd);
auto bnd_curr = bnd;
bool shifted = false;
auto& current_edge = current_bound.current_edge;
while (current_edge != current_bound.edges.end() && current_edge->top.y == top_y) {
add_to_hot_pixels(current_edge->top, manager);
if (is_horizontal(*current_edge)) {
if (horizontals_at_top_scanbeam(top_y, bnd_curr, active_bounds, manager)) {
shifted = true;
auto bnd_2 = std::next(bnd);
while ((*bnd)->current_edge != (*bnd)->edges.end() &&
(*bnd)->current_edge->top.y == top_y) {
add_to_hot_pixels((*bnd)->current_edge->top, rings);
if (current_edge_is_horizontal<T>(bnd)) {
(*bnd)->current_x = static_cast<double>((*bnd)->current_edge->top.x);
if ((*bnd)->current_edge->bot.x < (*bnd)->current_edge->top.x) {
// left to right
auto bnd_next = std::next(bnd);
while (bnd_next != active_bounds.end() &&
(*bnd_next)->current_x < (*bnd)->current_x) {
if (std::llround((*bnd_next)->current_edge->top.y) != top_y &&
std::llround((*bnd_next)->current_edge->bot.y) != top_y) {
mapbox::geometry::point<T> pt(std::llround((*bnd_next)->current_x),
top_y);
add_to_hot_pixels(pt, rings);
}
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
bnd_next = std::next(bnd);
}
} else {
// right to left
if (bnd != active_bounds.begin()) {
auto bnd_prev = std::prev(bnd);
while (bnd != active_bounds.begin() &&
(*bnd_prev)->current_x > (*bnd)->current_x) {
if (std::llround((*bnd_prev)->current_edge->top.y) != top_y &&
std::llround((*bnd_prev)->current_edge->bot.y) != top_y) {
mapbox::geometry::point<T> pt(std::llround((*bnd_prev)->current_x),
top_y);
add_to_hot_pixels(pt, rings);
}
swap_positions_in_ABL(bnd, bnd_prev, active_bounds);
bnd_prev = std::prev(bnd);
}
}
}
}
next_edge_in_bound(current_bound, scanbeam);
next_edge_in_bound(bnd, scanbeam);
}
if (current_edge == current_bound.edges.end()) {
*bnd_curr = nullptr;
}
if (!shifted) {
++bnd;
if ((*bnd)->current_edge == (*bnd)->edges.end()) {
active_bounds.erase(bnd);
}
bnd = bnd_2;
}
active_bounds.erase(std::remove(active_bounds.begin(), active_bounds.end(), nullptr), active_bounds.end());
}
template <typename T>
@ -127,32 +109,30 @@ void insert_local_minima_into_ABL_hot_pixel(T top_y,
local_minimum_ptr_list<T>& minima_sorted,
local_minimum_ptr_list_itr<T>& lm,
active_bound_list<T>& active_bounds,
ring_manager<T>& manager,
ring_manager<T>& rings,
scanbeam_list<T>& scanbeam) {
while (lm != minima_sorted.end() && (*lm)->y == top_y) {
add_to_hot_pixels((*lm)->left_bound.edges.front().bot, manager);
add_to_hot_pixels((*lm)->left_bound.edges.front().bot, rings);
auto& left_bound = (*lm)->left_bound;
auto& right_bound = (*lm)->right_bound;
left_bound.current_edge = left_bound.edges.begin();
left_bound.next_edge = std::next(left_bound.current_edge);
left_bound.current_x = static_cast<double>(left_bound.current_edge->bot.x);
right_bound.current_edge = right_bound.edges.begin();
right_bound.next_edge = std::next(right_bound.current_edge);
right_bound.current_x = static_cast<double>(right_bound.current_edge->bot.x);
auto lb_abl_itr = insert_bound_into_ABL(left_bound, right_bound, active_bounds);
auto lb_abl_itr = insert_bound_into_ABL(left_bound, active_bounds);
if (!current_edge_is_horizontal<T>(lb_abl_itr)) {
insert_sorted_scanbeam(scanbeam, (*lb_abl_itr)->current_edge->top.y);
scanbeam.push((*lb_abl_itr)->current_edge->top.y);
}
auto rb_abl_itr = std::next(lb_abl_itr);
auto& right_bound = (*lm)->right_bound;
right_bound.current_edge = right_bound.edges.begin();
right_bound.current_x = static_cast<double>(right_bound.current_edge->bot.x);
auto rb_abl_itr = insert_bound_into_ABL(right_bound, lb_abl_itr, active_bounds);
if (!current_edge_is_horizontal<T>(rb_abl_itr)) {
insert_sorted_scanbeam(scanbeam, (*rb_abl_itr)->current_edge->top.y);
scanbeam.push((*rb_abl_itr)->current_edge->top.y);
}
++lm;
}
}
template <typename T>
void build_hot_pixels(local_minimum_list<T>& minima_list, ring_manager<T>& manager) {
void build_hot_pixels(local_minimum_list<T>& minima_list, ring_manager<T>& rings) {
active_bound_list<T> active_bounds;
scanbeam_list<T> scanbeam;
T scanline_y = std::numeric_limits<T>::max();
@ -173,19 +153,20 @@ void build_hot_pixels(local_minimum_list<T>& minima_list, ring_manager<T>& manag
reserve += lm.left_bound.edges.size() + 2;
reserve += lm.right_bound.edges.size() + 2;
}
manager.hot_pixels.reserve(reserve);
rings.hot_pixels.reserve(reserve);
while (pop_from_scanbeam(scanline_y, scanbeam) || current_lm != minima_sorted.end()) {
process_hot_pixel_intersections(scanline_y, active_bounds, manager);
process_hot_pixel_intersections(scanline_y, active_bounds, rings);
insert_local_minima_into_ABL_hot_pixel(scanline_y, minima_sorted, current_lm, active_bounds, manager, scanbeam);
insert_local_minima_into_ABL_hot_pixel(scanline_y, minima_sorted, current_lm, active_bounds,
rings, scanbeam);
process_hot_pixel_edges_at_top_of_scanbeam(scanline_y, scanbeam, active_bounds, manager);
process_hot_pixel_edges_at_top_of_scanbeam(scanline_y, scanbeam, active_bounds, rings);
}
preallocate_point_memory(manager, manager.hot_pixels.size());
sort_hot_pixels(manager);
preallocate_point_memory(rings, rings.hot_pixels.size());
sort_hot_pixels(rings);
}
}
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/wagyu/almost_equal.hpp>
#include <mapbox/geometry/wagyu/point.hpp>
namespace mapbox {
@ -31,48 +30,41 @@ double area(mapbox::geometry::linear_ring<T> const& poly) {
return -a * 0.5;
}
inline bool values_are_equal(double x, double y) {
return util::FloatingPoint<double>(x).AlmostEquals(util::FloatingPoint<double>(y));
inline bool value_is_zero(double val) {
return std::fabs(val) < std::numeric_limits<double>::epsilon();
}
inline bool value_is_zero(double val) {
return values_are_equal(val, static_cast<double>(0.0));
inline bool values_are_equal(double x, double y) {
return value_is_zero(x - y);
}
inline bool values_near_equal(double x, double y) {
return std::fabs(x - y) < (5.0 * std::numeric_limits<double>::epsilon());
}
inline bool greater_than_or_equal(double x, double y) {
return x > y || values_are_equal(x, y);
}
inline bool greater_than(double x, double y) {
return (!values_are_equal(x, y) && x > y);
}
inline bool less_than(double x, double y) {
return (!values_are_equal(x, y) && x < y);
}
template <typename T>
bool slopes_equal(mapbox::geometry::point<T> const& pt1,
mapbox::geometry::point<T> const& pt2,
mapbox::geometry::point<T> const& pt3) {
return static_cast<std::int64_t>(pt1.y - pt2.y) * static_cast<std::int64_t>(pt2.x - pt3.x) ==
static_cast<std::int64_t>(pt1.x - pt2.x) * static_cast<std::int64_t>(pt2.y - pt3.y);
return (pt1.y - pt2.y) * (pt2.x - pt3.x) == (pt1.x - pt2.x) * (pt2.y - pt3.y);
}
template <typename T>
bool slopes_equal(mapbox::geometry::wagyu::point<T> const& pt1,
mapbox::geometry::wagyu::point<T> const& pt2,
mapbox::geometry::point<T> const& pt3) {
return static_cast<std::int64_t>(pt1.y - pt2.y) * static_cast<std::int64_t>(pt2.x - pt3.x) ==
static_cast<std::int64_t>(pt1.x - pt2.x) * static_cast<std::int64_t>(pt2.y - pt3.y);
return (pt1.y - pt2.y) * (pt2.x - pt3.x) == (pt1.x - pt2.x) * (pt2.y - pt3.y);
}
template <typename T>
bool slopes_equal(mapbox::geometry::wagyu::point<T> const& pt1,
mapbox::geometry::wagyu::point<T> const& pt2,
mapbox::geometry::wagyu::point<T> const& pt3) {
return static_cast<std::int64_t>(pt1.y - pt2.y) * static_cast<std::int64_t>(pt2.x - pt3.x) ==
static_cast<std::int64_t>(pt1.x - pt2.x) * static_cast<std::int64_t>(pt2.y - pt3.y);
return (pt1.y - pt2.y) * (pt2.x - pt3.x) == (pt1.x - pt2.x) * (pt2.y - pt3.y);
}
template <typename T>
@ -80,19 +72,8 @@ bool slopes_equal(mapbox::geometry::point<T> const& pt1,
mapbox::geometry::point<T> const& pt2,
mapbox::geometry::point<T> const& pt3,
mapbox::geometry::point<T> const& pt4) {
return static_cast<std::int64_t>(pt1.y - pt2.y) * static_cast<std::int64_t>(pt3.x - pt4.x) ==
static_cast<std::int64_t>(pt1.x - pt2.x) * static_cast<std::int64_t>(pt3.y - pt4.y);
return (pt1.y - pt2.y) * (pt3.x - pt4.x) == (pt1.x - pt2.x) * (pt3.y - pt4.y);
}
}
template <typename T>
inline T wround(double value) {
return static_cast<T>(::llround(value));
}
template <>
inline std::int64_t wround<std::int64_t>(double value) {
return ::llround(value);
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

View File

@ -19,11 +19,16 @@ namespace geometry {
namespace wagyu {
template <typename T>
void execute_vatti(local_minimum_list<T>& minima_list,
ring_manager<T>& manager,
bool execute_vatti(local_minimum_list<T>& minima_list,
ring_manager<T>& rings,
clip_type cliptype,
fill_type subject_fill_type,
fill_type clip_fill_type) {
if (minima_list.empty()) {
return false;
}
active_bound_list<T> active_bounds;
scanbeam_list<T> scanbeam;
T scanline_y = std::numeric_limits<T>::max();
@ -38,27 +43,32 @@ void execute_vatti(local_minimum_list<T>& minima_list,
// std::clog << output_all_edges(minima_sorted) << std::endl;
setup_scanbeam(minima_list, scanbeam);
manager.current_hp_itr = manager.hot_pixels.begin();
rings.current_hp_itr = rings.hot_pixels.begin();
while (pop_from_scanbeam(scanline_y, scanbeam) || current_lm != minima_sorted.end()) {
process_intersections(scanline_y, active_bounds, cliptype, subject_fill_type, clip_fill_type, manager);
process_intersections(scanline_y, active_bounds, cliptype, subject_fill_type,
clip_fill_type, rings);
update_current_hp_itr(scanline_y, manager);
update_current_hp_itr(scanline_y, rings);
// First we process bounds that has already been added to the active bound list --
// if the active bound list is empty local minima that are at this scanline_y and
// have a horizontal edge at the local minima will be processed
process_edges_at_top_of_scanbeam(scanline_y, active_bounds, scanbeam, minima_sorted, current_lm, manager,
cliptype, subject_fill_type, clip_fill_type);
process_edges_at_top_of_scanbeam(scanline_y, active_bounds, scanbeam, minima_sorted,
current_lm, rings, cliptype, subject_fill_type,
clip_fill_type);
// Next we will add local minima bounds to the active bounds list that are on the local
// minima queue at
// this current scanline_y
insert_local_minima_into_ABL(scanline_y, minima_sorted, current_lm, active_bounds, manager, scanbeam, cliptype,
subject_fill_type, clip_fill_type);
insert_local_minima_into_ABL(scanline_y, minima_sorted, current_lm, active_bounds, rings,
scanbeam, cliptype, subject_fill_type, clip_fill_type);
}
// std::clog << rings.rings << std::endl;
// std::clog << output_as_polygon(rings.all_rings[0]);
return true;
}
}
}
}
} // namespace wagyu
} // namespace geometry
} // namespace mapbox

View File

@ -10,14 +10,13 @@
#include <mapbox/geometry/wagyu/build_local_minima_list.hpp>
#include <mapbox/geometry/wagyu/build_result.hpp>
#include <mapbox/geometry/wagyu/config.hpp>
#include <mapbox/geometry/wagyu/interrupt.hpp>
#include <mapbox/geometry/wagyu/local_minimum.hpp>
#include <mapbox/geometry/wagyu/snap_rounding.hpp>
#include <mapbox/geometry/wagyu/topology_correction.hpp>
#include <mapbox/geometry/wagyu/vatti.hpp>
#define WAGYU_MAJOR_VERSION 0
#define WAGYU_MINOR_VERSION 5
#define WAGYU_MINOR_VERSION 3
#define WAGYU_PATCH_VERSION 0
#define WAGYU_VERSION (WAGYU_MAJOR_VERSION * 100000) + (WAGYU_MINOR_VERSION * 100) + (WAGYU_PATCH_VERSION)
@ -29,7 +28,9 @@ namespace wagyu {
template <typename T>
class wagyu {
private:
local_minimum_list<T> minima_list;
using value_type = T;
local_minimum_list<value_type> minima_list;
bool reverse_output;
wagyu(wagyu const&) = delete;
@ -43,13 +44,13 @@ public:
clear();
}
template <typename T2>
bool add_ring(mapbox::geometry::linear_ring<T2> const& pg, polygon_type p_type = polygon_type_subject) {
bool add_ring(mapbox::geometry::linear_ring<value_type> const& pg,
polygon_type p_type = polygon_type_subject) {
return add_linear_ring(pg, minima_list, p_type);
}
template <typename T2>
bool add_polygon(mapbox::geometry::polygon<T2> const& ppg, polygon_type p_type = polygon_type_subject) {
bool add_polygon(mapbox::geometry::polygon<value_type> const& ppg,
polygon_type p_type = polygon_type_subject) {
bool result = false;
for (auto const& r : ppg) {
if (add_ring(r, p_type)) {
@ -67,11 +68,11 @@ public:
minima_list.clear();
}
mapbox::geometry::box<T> get_bounds() {
mapbox::geometry::point<T> min = { 0, 0 };
mapbox::geometry::point<T> max = { 0, 0 };
mapbox::geometry::box<value_type> get_bounds() {
mapbox::geometry::point<value_type> min = { 0, 0 };
mapbox::geometry::point<value_type> max = { 0, 0 };
if (minima_list.empty()) {
return mapbox::geometry::box<T>(min, max);
return mapbox::geometry::box<value_type>(min, max);
}
bool first_set = false;
for (auto const& lm : minima_list) {
@ -108,38 +109,29 @@ public:
}
}
}
return mapbox::geometry::box<T>(min, max);
return mapbox::geometry::box<value_type>(min, max);
}
template <typename T2>
bool execute(clip_type cliptype,
mapbox::geometry::multi_polygon<T2>& solution,
mapbox::geometry::multi_polygon<value_type>& solution,
fill_type subject_fill_type,
fill_type clip_fill_type) {
if (minima_list.empty()) {
ring_manager<T> rings;
build_hot_pixels(minima_list, rings);
if (!execute_vatti(minima_list, rings, cliptype, subject_fill_type, clip_fill_type)) {
return false;
}
ring_manager<T> manager;
do_simple_polygons(rings);
interrupt_check(); // Check for interruptions
build_hot_pixels(minima_list, manager);
interrupt_check(); // Check for interruptions
execute_vatti(minima_list, manager, cliptype, subject_fill_type, clip_fill_type);
interrupt_check(); // Check for interruptions
correct_topology(manager);
build_result(solution, manager, reverse_output);
build_result(solution, rings, reverse_output);
return true;
}
};
} // namespace wagyu
} // namespace geometry
} // namespace mapbox
}
}
}

View File

@ -16,12 +16,6 @@
#include "mbtiles.hpp"
#include "text.hpp"
#include "milo/dtoa_milo.h"
#include "write_json.hpp"
#include "version.hpp"
size_t max_tilestats_attributes = 1000;
size_t max_tilestats_sample_values = 1000;
size_t max_tilestats_values = 100;
sqlite3 *mbtiles_open(char *dbname, char **argv, int forcetable) {
sqlite3 *outdb;
@ -45,8 +39,7 @@ sqlite3 *mbtiles_open(char *dbname, char **argv, int forcetable) {
exit(EXIT_FAILURE);
}
if (sqlite3_exec(outdb, "CREATE TABLE metadata (name text, value text);", NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "%s: Tileset \"%s\" already exists. You can use --force if you want to delete the old tileset.\n", argv[0], dbname);
fprintf(stderr, "%s: %s\n", argv[0], err);
fprintf(stderr, "%s: create metadata table: %s\n", argv[0], err);
if (!forcetable) {
exit(EXIT_FAILURE);
}
@ -94,6 +87,38 @@ void mbtiles_write_tile(sqlite3 *outdb, int z, int tx, int ty, const char *data,
}
}
static void quote(std::string &buf, std::string const &s) {
for (size_t i = 0; i < s.size(); i++) {
unsigned char ch = s[i];
if (ch == '\\' || ch == '\"') {
buf.push_back('\\');
buf.push_back(ch);
} else if (ch < ' ') {
char tmp[7];
sprintf(tmp, "\\u%04x", ch);
buf.append(std::string(tmp));
} else {
buf.push_back(ch);
}
}
}
void aprintf(std::string *buf, const char *format, ...) {
va_list ap;
char *tmp;
va_start(ap, format);
if (vasprintf(&tmp, format, ap) < 0) {
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
va_end(ap);
buf->append(tmp, strlen(tmp));
free(tmp);
}
bool type_and_string::operator<(const type_and_string &o) const {
if (string < o.string) {
return true;
@ -114,33 +139,36 @@ bool type_and_string::operator!=(const type_and_string &o) const {
return false;
}
void tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t elements, json_writer &state) {
std::string tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t elements) {
// Consolidate layers/attributes whose names are truncated
std::vector<std::map<std::string, layermap_entry>> lmv;
lmv.push_back(layermap1);
std::map<std::string, layermap_entry> layermap = merge_layermaps(lmv, true);
state.json_write_hash();
std::string out = "{\n";
state.nospace = true;
state.json_write_string("layerCount");
state.json_write_unsigned(layermap.size());
out.append("\t\"layerCount\": ");
out.append(std::to_string(layermap.size()));
out.append(",\n");
state.nospace = true;
state.json_write_string("layers");
state.json_write_array();
out.append("\t\"layers\": [\n");
bool first = true;
for (auto layer : layermap) {
state.nospace = true;
state.json_write_hash();
if (!first) {
out.append(",\n");
}
first = false;
state.nospace = true;
state.json_write_string("layer");
state.json_write_string(layer.first);
out.append("\t\t{\n");
state.nospace = true;
state.json_write_string("count");
state.json_write_unsigned(layer.second.points + layer.second.lines + layer.second.polygons);
out.append("\t\t\t\"layer\": \"");
quote(out, layer.first.c_str());
out.append("\",\n");
out.append("\t\t\t\"count\": ");
out.append(std::to_string(layer.second.points + layer.second.lines + layer.second.polygons));
out.append(",\n");
std::string geomtype = "Polygon";
if (layer.second.points >= layer.second.lines && layer.second.points >= layer.second.polygons) {
@ -149,46 +177,45 @@ void tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t el
geomtype = "LineString";
}
state.nospace = true;
state.json_write_string("geometry");
state.json_write_string(geomtype);
out.append("\t\t\t\"geometry\": \"");
quote(out, geomtype.c_str());
out.append("\",\n");
size_t attrib_count = layer.second.file_keys.size();
if (attrib_count > max_tilestats_attributes) {
attrib_count = max_tilestats_attributes;
if (attrib_count > 1000) {
attrib_count = 1000;
}
state.nospace = true;
state.json_write_string("attributeCount");
state.json_write_unsigned(attrib_count);
out.append("\t\t\t\"attributeCount\": ");
out.append(std::to_string(attrib_count));
out.append(",\n");
state.nospace = true;
state.json_write_string("attributes");
state.nospace = true;
state.json_write_array();
out.append("\t\t\t\"attributes\": [\n");
size_t attrs = 0;
for (auto attribute : layer.second.file_keys) {
if (attrs == elements) {
break;
}
if (attrs != 0) {
out.append(",\n");
}
attrs++;
state.nospace = true;
state.json_write_hash();
out.append("\t\t\t\t{\n");
state.nospace = true;
state.json_write_string("attribute");
state.json_write_string(attribute.first);
out.append("\t\t\t\t\t\"attribute\": \"");
quote(out, attribute.first.c_str());
out.append("\",\n");
size_t val_count = attribute.second.sample_values.size();
if (val_count > max_tilestats_sample_values) {
val_count = max_tilestats_sample_values;
if (val_count > 1000) {
val_count = 1000;
}
state.nospace = true;
state.json_write_string("count");
state.json_write_unsigned(val_count);
out.append("\t\t\t\t\t\"count\": ");
out.append(std::to_string(val_count));
out.append(",\n");
int type = 0;
for (auto s : attribute.second.sample_values) {
@ -207,13 +234,11 @@ void tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t el
type_str = "mixed";
}
state.nospace = true;
state.json_write_string("type");
state.json_write_string(type_str);
out.append("\t\t\t\t\t\"type\": \"");
quote(out, type_str.c_str());
out.append("\",\n");
state.nospace = true;
state.json_write_string("values");
state.json_write_array();
out.append("\t\t\t\t\t\"values\": [\n");
size_t vals = 0;
for (auto value : attribute.second.sample_values) {
@ -221,53 +246,68 @@ void tilestats(std::map<std::string, layermap_entry> const &layermap1, size_t el
break;
}
state.nospace = true;
if (value.type == mvt_double || value.type == mvt_bool) {
if (vals != 0) {
out.append(",\n");
}
vals++;
state.json_write_stringified(value.string);
out.append("\t\t\t\t\t\t");
out.append(value.string);
} else {
std::string trunc = truncate16(value.string, 256);
if (trunc.size() == value.string.size()) {
if (vals != 0) {
out.append(",\n");
}
vals++;
state.json_write_string(value.string);
out.append("\t\t\t\t\t\t\"");
quote(out, value.string.c_str());
out.append("\"");
}
}
}
state.nospace = true;
state.json_end_array();
out.append("\n");
out.append("\t\t\t\t\t]");
if ((type & (1 << mvt_double)) != 0) {
state.nospace = true;
state.json_write_string("min");
state.json_write_number(attribute.second.min);
out.append(",\n");
state.nospace = true;
state.json_write_string("max");
state.json_write_number(attribute.second.max);
out.append("\t\t\t\t\t\"min\": ");
out.append(milo::dtoa_milo(attribute.second.min));
out.append(",\n");
out.append("\t\t\t\t\t\"max\": ");
out.append(milo::dtoa_milo(attribute.second.max));
}
state.nospace = true;
state.json_end_hash();
out.append("\n");
out.append("\t\t\t\t}");
}
state.nospace = true;
state.json_end_array();
state.nospace = true;
state.json_end_hash();
out.append("\n\t\t\t]\n");
out.append("\t\t}");
}
state.nospace = true;
state.json_end_array();
state.nospace = true;
state.json_end_hash();
out.append("\n");
out.append("\t]\n");
out.append("}");
std::string out2;
for (size_t i = 0; i < out.size(); i++) {
if (out[i] != '\t' && out[i] != '\n') {
out2.push_back(out[i]);
}
}
return out2;
}
void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats, std::map<std::string, std::string> const &attribute_descriptions, std::string const &program, std::string const &commandline) {
void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats) {
char *sql, *err;
sqlite3 *db = outdb;
@ -374,37 +414,13 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
}
sqlite3_free(sql);
std::string version = program + " " + VERSION;
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('generator', %Q);", version.c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set version: %s\n", err);
if (!forcetable) {
exit(EXIT_FAILURE);
}
}
sqlite3_free(sql);
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('generator_options', %Q);", commandline.c_str());
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
fprintf(stderr, "set commandline: %s\n", err);
if (!forcetable) {
exit(EXIT_FAILURE);
}
}
sqlite3_free(sql);
if (vector) {
size_t elements = max_tilestats_values;
size_t elements = 100;
std::string buf;
{
json_writer state(&buf);
state.json_write_hash();
state.nospace = true;
state.json_write_string("vector_layers");
state.json_write_array();
buf = "{";
aprintf(&buf, "\"vector_layers\": [ ");
std::vector<std::string> lnames;
for (auto ai = layermap.begin(); ai != layermap.end(); ++ai) {
@ -412,69 +428,52 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
}
for (size_t i = 0; i < lnames.size(); i++) {
if (i != 0) {
aprintf(&buf, ", ");
}
auto fk = layermap.find(lnames[i]);
state.json_write_hash();
state.json_write_string("id");
state.json_write_string(lnames[i]);
state.json_write_string("description");
state.json_write_string(fk->second.description);
state.json_write_string("minzoom");
state.json_write_signed(fk->second.minzoom);
state.json_write_string("maxzoom");
state.json_write_signed(fk->second.maxzoom);
state.json_write_string("fields");
state.json_write_hash();
state.nospace = true;
aprintf(&buf, "{ \"id\": \"");
quote(buf, lnames[i]);
aprintf(&buf, "\", \"description\": \"\", \"minzoom\": %d, \"maxzoom\": %d, \"fields\": {", fk->second.minzoom, fk->second.maxzoom);
bool first = true;
for (auto j = fk->second.file_keys.begin(); j != fk->second.file_keys.end(); ++j) {
if (first) {
first = false;
} else {
aprintf(&buf, ", ");
}
state.json_write_string(j->first);
aprintf(&buf, "\"");
quote(buf, j->first.c_str());
auto f = attribute_descriptions.find(j->first);
if (f == attribute_descriptions.end()) {
int type = 0;
for (auto s : j->second.sample_values) {
type |= (1 << s.type);
}
int type = 0;
for (auto s : j->second.sample_values) {
type |= (1 << s.type);
}
if (type == (1 << mvt_double)) {
state.json_write_string("Number");
} else if (type == (1 << mvt_bool)) {
state.json_write_string("Boolean");
} else if (type == (1 << mvt_string)) {
state.json_write_string("String");
} else {
state.json_write_string("Mixed");
}
if (type == (1 << mvt_double)) {
aprintf(&buf, "\": \"Number\"");
} else if (type == (1 << mvt_bool)) {
aprintf(&buf, "\": \"Boolean\"");
} else if (type == (1 << mvt_string)) {
aprintf(&buf, "\": \"String\"");
} else {
state.json_write_string(f->second);
aprintf(&buf, "\": \"Mixed\"");
}
}
state.nospace = true;
state.json_end_hash();
state.json_end_hash();
aprintf(&buf, "} }");
}
state.json_end_array();
aprintf(&buf, " ]");
if (do_tilestats && elements > 0) {
state.nospace = true;
state.json_write_string("tilestats");
tilestats(layermap, elements, state);
aprintf(&buf, ",\"tilestats\": %s", tilestats(layermap, elements).c_str());
}
state.nospace = true;
state.json_end_hash();
aprintf(&buf, "}");
}
sql = sqlite3_mprintf("INSERT INTO metadata (name, value) VALUES ('json', %Q);", buf.c_str());
@ -500,12 +499,10 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
exit(EXIT_FAILURE);
}
json_writer state(fp);
state.json_write_hash();
state.json_write_newline();
fprintf(fp, "{\n");
sqlite3_stmt *stmt;
bool first = true;
if (sqlite3_prepare_v2(db, "SELECT name, value from metadata;", -1, &stmt, NULL) == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
std::string key, value;
@ -517,16 +514,19 @@ void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fnam
exit(EXIT_FAILURE);
}
state.json_comma_newline();
state.json_write_string(k);
state.json_write_string(v);
quote(key, k);
quote(value, v);
if (!first) {
fprintf(fp, ",\n");
}
fprintf(fp, " \"%s\": \"%s\"", key.c_str(), value.c_str());
first = false;
}
sqlite3_finalize(stmt);
}
state.json_write_newline();
state.json_end_hash();
state.json_write_newline();
fprintf(fp, "\n}\n");
fclose(fp);
}
}
@ -575,7 +575,6 @@ std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::
auto out_entry = out.find(layername);
out_entry->second.minzoom = map->second.minzoom;
out_entry->second.maxzoom = map->second.maxzoom;
out_entry->second.description = map->second.description;
}
auto out_entry = out.find(layername);
@ -600,7 +599,7 @@ std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::
if (pt == fk2->second.sample_values.end() || *pt != val) { // not found
fk2->second.sample_values.insert(pt, val);
if (fk2->second.sample_values.size() > max_tilestats_sample_values) {
if (fk2->second.sample_values.size() > 1000) {
fk2->second.sample_values.pop_back();
}
}
@ -634,10 +633,6 @@ std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::
}
void add_to_file_keys(std::map<std::string, type_and_string_stats> &file_keys, std::string const &attrib, type_and_string const &val) {
if (val.type == mvt_null) {
return;
}
auto fka = file_keys.find(attrib);
if (fka == file_keys.end()) {
file_keys.insert(std::pair<std::string, type_and_string_stats>(attrib, type_and_string_stats()));
@ -664,7 +659,7 @@ void add_to_file_keys(std::map<std::string, type_and_string_stats> &file_keys, s
if (pt == fka->second.sample_values.end() || *pt != val) { // not found
fka->second.sample_values.insert(pt, val);
if (fka->second.sample_values.size() > max_tilestats_sample_values) {
if (fka->second.sample_values.size() > 1000) {
fka->second.sample_values.pop_back();
}
}

View File

@ -5,10 +5,6 @@
#include <map>
#include "mvt.hpp"
extern size_t max_tilestats_attributes;
extern size_t max_tilestats_sample_values;
extern size_t max_tilestats_values;
struct type_and_string {
int type = 0;
std::string string = "";
@ -29,7 +25,6 @@ struct layermap_entry {
std::map<std::string, type_and_string_stats> file_keys{};
int minzoom = 0;
int maxzoom = 0;
std::string description = "";
size_t points = 0;
size_t lines = 0;
@ -45,10 +40,12 @@ sqlite3 *mbtiles_open(char *dbname, char **argv, int forcetable);
void mbtiles_write_tile(sqlite3 *outdb, int z, int tx, int ty, const char *data, int size);
void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats, std::map<std::string, std::string> const &attribute_descriptions, std::string const &program, std::string const &commandline);
void mbtiles_write_metadata(sqlite3 *outdb, const char *outdir, const char *fname, int minzoom, int maxzoom, double minlat, double minlon, double maxlat, double maxlon, double midlat, double midlon, int forcetable, const char *attribution, std::map<std::string, layermap_entry> const &layermap, bool vector, const char *description, bool do_tilestats);
void mbtiles_close(sqlite3 *outdb, const char *pgm);
void aprintf(std::string *buf, const char *format, ...);
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps);
std::map<std::string, layermap_entry> merge_layermaps(std::vector<std::map<std::string, layermap_entry> > const &maps, bool trunc);

View File

@ -1,18 +1,12 @@
#ifndef MEMFILE_HPP
#define MEMFILE_HPP
#include <atomic>
struct memfile {
int fd = 0;
char *map = NULL;
std::atomic<long long> len;
long long len = 0;
long long off = 0;
unsigned long tree = 0;
memfile()
: len(0) {
}
};
struct memfile *memfile_open(int fd);

78
mvt.cpp
View File

@ -34,49 +34,25 @@ int decompress(std::string const &input, std::string &output) {
inflate_s.avail_in = 0;
inflate_s.next_in = Z_NULL;
if (inflateInit2(&inflate_s, 32 + 15) != Z_OK) {
fprintf(stderr, "Decompression error: %s\n", inflate_s.msg);
fprintf(stderr, "error: %s\n", inflate_s.msg);
}
inflate_s.next_in = (Bytef *) input.data();
inflate_s.avail_in = input.size();
inflate_s.next_out = (Bytef *) output.data();
inflate_s.avail_out = output.size();
while (true) {
size_t existing_output = inflate_s.next_out - (Bytef *) output.data();
output.resize(existing_output + 2 * inflate_s.avail_in + 100);
inflate_s.next_out = (Bytef *) output.data() + existing_output;
inflate_s.avail_out = output.size() - existing_output;
int ret = inflate(&inflate_s, 0);
if (ret < 0) {
fprintf(stderr, "Decompression error: ");
if (ret == Z_DATA_ERROR) {
fprintf(stderr, "data error");
}
if (ret == Z_STREAM_ERROR) {
fprintf(stderr, "stream error");
}
if (ret == Z_MEM_ERROR) {
fprintf(stderr, "out of memory");
}
if (ret == Z_BUF_ERROR) {
fprintf(stderr, "no data in buffer");
}
fprintf(stderr, "\n");
size_t length = 0;
do {
output.resize(length + 2 * input.size());
inflate_s.avail_out = 2 * input.size();
inflate_s.next_out = (Bytef *) (output.data() + length);
int ret = inflate(&inflate_s, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) {
fprintf(stderr, "error: %s\n", inflate_s.msg);
return 0;
}
if (ret == Z_STREAM_END) {
break;
}
// ret must be Z_OK or Z_NEED_DICT;
// continue decompresing
}
output.resize(inflate_s.next_out - (Bytef *) output.data());
length += (2 * input.size() - inflate_s.avail_out);
} while (inflate_s.avail_out == 0);
inflateEnd(&inflate_s);
output.resize(length);
return 1;
}
@ -114,9 +90,7 @@ bool mvt_tile::decode(std::string &message, bool &was_compressed) {
if (is_compressed(message)) {
std::string uncompressed;
if (decompress(message, uncompressed) == 0) {
exit(EXIT_FAILURE);
}
decompress(message, uncompressed);
src = uncompressed;
was_compressed = true;
} else {
@ -148,9 +122,6 @@ bool mvt_tile::decode(std::string &message, bool &was_compressed) {
protozero::pbf_reader value_reader(layer_reader.get_message());
mvt_value value;
value.type = mvt_null;
value.numeric_value.null_value = 0;
while (value_reader.next()) {
switch (value_reader.tag()) {
case 1: /* string */
@ -332,12 +303,6 @@ std::string mvt_tile::encode() {
value_writer.add_sint64(6, pbv.numeric_value.sint_value);
} else if (pbv.type == mvt_bool) {
value_writer.add_bool(7, pbv.numeric_value.bool_value);
} else if (pbv.type == mvt_null) {
fprintf(stderr, "Internal error: trying to write null attribute to tile\n");
exit(EXIT_FAILURE);
} else {
fprintf(stderr, "Internal error: trying to write undefined attribute type to tile\n");
exit(EXIT_FAILURE);
}
layer_writer.add_message(4, value_string);
@ -356,7 +321,7 @@ std::string mvt_tile::encode() {
std::vector<uint32_t> geometry;
long long px = 0, py = 0;
int px = 0, py = 0;
int cmd_idx = -1;
int cmd = -1;
int length = 0;
@ -381,13 +346,8 @@ std::string mvt_tile::encode() {
long long wwx = geom[g].x;
long long wwy = geom[g].y;
long long dx = wwx - px;
long long dy = wwy - py;
if (dx < INT_MIN || dx > INT_MAX || dy < INT_MIN || dy > INT_MAX) {
fprintf(stderr, "Internal error: Geometry delta is too big: %lld,%lld\n", dx, dy);
exit(EXIT_FAILURE);
}
int dx = wwx - px;
int dy = wwy - py;
geometry.push_back(protozero::encode_zigzag32(dx));
geometry.push_back(protozero::encode_zigzag32(dy));
@ -428,8 +388,7 @@ bool mvt_value::operator<(const mvt_value &o) const {
(type == mvt_int && numeric_value.int_value < o.numeric_value.int_value) ||
(type == mvt_uint && numeric_value.uint_value < o.numeric_value.uint_value) ||
(type == mvt_sint && numeric_value.sint_value < o.numeric_value.sint_value) ||
(type == mvt_bool && numeric_value.bool_value < o.numeric_value.bool_value) ||
(type == mvt_null && numeric_value.null_value < o.numeric_value.null_value)) {
(type == mvt_bool && numeric_value.bool_value < o.numeric_value.bool_value)) {
return true;
}
}
@ -483,8 +442,6 @@ std::string mvt_value::toString() {
return std::to_string(numeric_value.uint_value);
} else if (type == mvt_bool) {
return numeric_value.bool_value ? "true" : "false";
} else if (type == mvt_null) {
return "null";
} else {
return "unknown";
}
@ -634,7 +591,6 @@ mvt_value stringified_to_mvt_value(int type, const char *s) {
tv.numeric_value.bool_value = (s[0] == 't');
} else if (type == mvt_null) {
tv.type = mvt_null;
tv.numeric_value.null_value = 0;
} else {
tv.type = mvt_string;
tv.string_value = s;

View File

@ -48,7 +48,6 @@ struct mvt_feature {
int /* mvt_geometry_type */ type = 0;
unsigned long long id = 0;
bool has_id = false;
bool dropped = false;
mvt_feature() {
has_id = false;
@ -77,7 +76,6 @@ struct mvt_value {
unsigned long long uint_value;
long long sint_value;
bool bool_value;
int null_value;
} numeric_value;
bool operator<(const mvt_value &o) const;

View File

@ -5,7 +5,7 @@
#define A_REVERSE ((int) 'r')
#define A_REORDER ((int) 'o')
#define A_LINE_DROP ((int) 'l')
#define A_DEBUG_POLYGON ((int) '@')
#define A_DEBUG_POLYGON ((int) 'D')
#define A_POLYGON_DROP ((int) 'p')
#define A_DETECT_SHARED_BORDERS ((int) 'b')
#define A_PREFER_RADIX_SORT ((int) 'R')
@ -15,20 +15,14 @@
#define A_DROP_DENSEST_AS_NEEDED ((int) 's')
#define A_DROP_FRACTION_AS_NEEDED ((int) 'd')
#define A_DROP_SMALLEST_AS_NEEDED ((int) 'n')
#define A_COALESCE_DENSEST_AS_NEEDED ((int) 'S')
#define A_COALESCE_SMALLEST_AS_NEEDED ((int) 'N')
#define A_COALESCE_FRACTION_AS_NEEDED ((int) 'D')
#define A_GRID_LOW_ZOOMS ((int) 'L')
#define A_DETECT_WRAPAROUND ((int) 'w')
#define A_EXTEND_ZOOMS ((int) 'e')
#define A_CLUSTER_DENSEST_AS_NEEDED ((int) 'C')
#define A_GENERATE_IDS ((int) 'i')
#define A_CONVERT_NUMERIC_IDS ((int) 'I')
#define A_HILBERT ((int) 'h')
#define P_SIMPLIFY ((int) 's')
#define P_SIMPLIFY_LOW ((int) 'S')
#define P_SIMPLIFY_SHARED_NODES ((int) 'n')
#define P_FEATURE_LIMIT ((int) 'f')
#define P_KILOBYTE_LIMIT ((int) 'k')
#define P_DYNAMIC_DROP ((int) 'd')
@ -39,9 +33,6 @@
#define P_TINY_POLYGON_REDUCTION ((int) 't')
#define P_TILE_COMPRESSION ((int) 'C')
#define P_TILE_STATS ((int) 'g')
#define P_USE_SOURCE_POLYGON_WINDING ((int) 'w')
#define P_REVERSE_SOURCE_POLYGON_WINDING ((int) 'W')
#define P_EMPTY_CSV_COLUMNS ((int) 'e')
extern int prevent[256];
extern int additional[256];

View File

@ -51,9 +51,8 @@ void *run_writer(void *a) {
exit(EXIT_FAILURE);
}
json_writer state(fp);
for (size_t i = 0; i < wa->layers->size(); i++) {
layer_to_geojson((*(wa->layers))[i], wa->z, wa->x, wa->y, false, true, false, true, 0, 0, 0, true, state);
layer_to_geojson(fp, (*(wa->layers))[i], wa->z, wa->x, wa->y, false, true, false, 0, 0, 0, true);
}
if (fclose(fp) != 0) {
@ -259,11 +258,7 @@ std::vector<mvt_layer> parse_layers(int fd, int z, unsigned x, unsigned y, std::
std::string s;
stringify_value(properties->values[i], tp, s, "Filter output", jp->line, j);
// Nulls can be excluded here because this is the postfilter
// and it is nearly time to create the vector representation
if (tp >= 0 && tp != mvt_null) {
if (tp >= 0) {
mvt_value v = stringified_to_mvt_value(tp, s.c_str());
l->second.tag(feature, std::string(properties->keys[i]->string), v);
@ -397,6 +392,7 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
sf.bbox[0] = sf.bbox[1] = LLONG_MAX;
sf.bbox[2] = sf.bbox[3] = LLONG_MIN;
sf.extent = 0;
sf.m = 0;
sf.metapos = 0;
sf.has_id = false;
@ -419,14 +415,9 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
}
json_object *extent = json_hash_get(tippecanoe, "extent");
if (extent != NULL && extent->type == JSON_NUMBER) {
if (extent != NULL && sequence->type == JSON_NUMBER) {
sf.extent = extent->number;
}
json_object *dropped = json_hash_get(tippecanoe, "dropped");
if (dropped != NULL && dropped->type == JSON_TRUE) {
sf.dropped = true;
}
}
for (size_t i = 0; i < dv.size(); i++) {
@ -497,10 +488,7 @@ serial_feature parse_feature(json_pull *jp, int z, unsigned x, unsigned y, std::
stringify_value(properties->values[i], v.type, v.s, "Filter output", jp->line, j);
// Nulls can be excluded here because the expression evaluation filter
// would have already run before prefiltering
if (v.type >= 0 && v.type != mvt_null) {
if (v.type >= 0) {
sf.full_keys.push_back(std::string(properties->keys[i]->string));
sf.full_values.push_back(v);

View File

@ -2,12 +2,8 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <atomic>
#include "projection.hpp"
unsigned long long (*encode_index)(unsigned int wx, unsigned int wy) = NULL;
void (*decode_index)(unsigned long long index, unsigned *wx, unsigned *wy) = NULL;
struct projection projections[] = {
{"EPSG:4326", lonlat2tile, tile2lonlat, "urn:ogc:def:crs:OGC:1.3:CRS84"},
{"EPSG:3857", epsg3857totile, tiletoepsg3857, "urn:ogc:def:crs:EPSG::3857"},
@ -18,23 +14,6 @@ struct projection *projection = &projections[0];
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
void lonlat2tile(double lon, double lat, int zoom, long long *x, long long *y) {
// Place infinite and NaN coordinates off the edge of the Mercator plane
int lat_class = fpclassify(lat);
int lon_class = fpclassify(lon);
bool bad_lon = false;
if (lat_class == FP_INFINITE || lat_class == FP_NAN) {
lat = 89.9;
}
if (lon_class == FP_INFINITE || lon_class == FP_NAN) {
// Keep these far enough from the plane that they don't get
// moved back into it by 360-degree offsetting
lon = 720;
bad_lon = true;
}
// Must limit latitude somewhere to prevent overflow.
// 89.9 degrees latitude is 0.621 worlds beyond the edge of the flat earth,
// hopefully far enough out that there are few expectations about the shape.
@ -45,10 +24,10 @@ void lonlat2tile(double lon, double lat, int zoom, long long *x, long long *y) {
lat = 89.9;
}
if (lon < -360 && !bad_lon) {
if (lon < -360) {
lon = -360;
}
if (lon > 360 && !bad_lon) {
if (lon > 360) {
lon = 360;
}
@ -70,18 +49,6 @@ void tile2lonlat(long long x, long long y, int zoom, double *lon, double *lat) {
}
void epsg3857totile(double ix, double iy, int zoom, long long *x, long long *y) {
// Place infinite and NaN coordinates off the edge of the Mercator plane
int iy_class = fpclassify(iy);
int ix_class = fpclassify(ix);
if (iy_class == FP_INFINITE || iy_class == FP_NAN) {
iy = 40000000.0;
}
if (ix_class == FP_INFINITE || ix_class == FP_NAN) {
ix = 40000000.0;
}
*x = ix * (1LL << 31) / 6378137.0 / M_PI + (1LL << 31);
*y = ((1LL << 32) - 1) - (iy * (1LL << 31) / 6378137.0 / M_PI + (1LL << 31));
@ -101,60 +68,7 @@ void tiletoepsg3857(long long ix, long long iy, int zoom, double *ox, double *oy
*oy = ((1LL << 32) - 1 - iy - (1LL << 31)) * M_PI * 6378137.0 / (1LL << 31);
}
// https://en.wikipedia.org/wiki/Hilbert_curve
void hilbert_rot(unsigned long long n, unsigned *x, unsigned *y, unsigned long long rx, unsigned long long ry) {
if (ry == 0) {
if (rx == 1) {
*x = n - 1 - *x;
*y = n - 1 - *y;
}
unsigned t = *x;
*x = *y;
*y = t;
}
}
unsigned long long hilbert_xy2d(unsigned long long n, unsigned x, unsigned y) {
unsigned long long d = 0;
unsigned long long rx, ry;
for (unsigned long long s = n / 2; s > 0; s /= 2) {
rx = (x & s) != 0;
ry = (y & s) != 0;
d += s * s * ((3 * rx) ^ ry);
hilbert_rot(s, &x, &y, rx, ry);
}
return d;
}
void hilbert_d2xy(unsigned long long n, unsigned long long d, unsigned *x, unsigned *y) {
unsigned long long rx, ry;
unsigned long long t = d;
*x = *y = 0;
for (unsigned long long s = 1; s < n; s *= 2) {
rx = 1 & (t / 2);
ry = 1 & (t ^ rx);
hilbert_rot(s, x, y, rx, ry);
*x += s * rx;
*y += s * ry;
t /= 4;
}
}
unsigned long long encode_hilbert(unsigned int wx, unsigned int wy) {
return hilbert_xy2d(1LL << 32, wx, wy);
}
void decode_hilbert(unsigned long long index, unsigned *wx, unsigned *wy) {
hilbert_d2xy(1LL << 32, index, wx, wy);
}
unsigned long long encode_quadkey(unsigned int wx, unsigned int wy) {
unsigned long long encode(unsigned int wx, unsigned int wy) {
unsigned long long out = 0;
int i;
@ -169,11 +83,11 @@ unsigned long long encode_quadkey(unsigned int wx, unsigned int wy) {
return out;
}
static std::atomic<unsigned char> decodex[256];
static std::atomic<unsigned char> decodey[256];
static unsigned char decodex[256];
static unsigned char decodey[256];
void decode_quadkey(unsigned long long index, unsigned *wx, unsigned *wy) {
static std::atomic<int> initialized(0);
void decode(unsigned long long index, unsigned *wx, unsigned *wy) {
static int initialized = 0;
if (!initialized) {
for (size_t ix = 0; ix < 256; ix++) {
size_t xx = 0, yy = 0;

View File

@ -5,6 +5,8 @@ void lonlat2tile(double lon, double lat, int zoom, long long *x, long long *y);
void epsg3857totile(double ix, double iy, int zoom, long long *x, long long *y);
void tile2lonlat(long long x, long long y, int zoom, double *lon, double *lat);
void tiletoepsg3857(long long x, long long y, int zoom, double *ox, double *oy);
unsigned long long encode(unsigned int wx, unsigned int wy);
void decode(unsigned long long index, unsigned *wx, unsigned *wy);
void set_projection_or_exit(const char *optarg);
struct projection {
@ -17,13 +19,4 @@ struct projection {
extern struct projection *projection;
extern struct projection projections[];
extern unsigned long long (*encode_index)(unsigned int wx, unsigned int wy);
extern void (*decode_index)(unsigned long long index, unsigned *wx, unsigned *wy);
unsigned long long encode_quadkey(unsigned int wx, unsigned int wy);
void decode_quadkey(unsigned long long index, unsigned *wx, unsigned *wy);
unsigned long long encode_hilbert(unsigned int wx, unsigned int wy);
void decode_hilbert(unsigned long long index, unsigned *wx, unsigned *wy);
#endif

View File

@ -53,7 +53,7 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna
size_t i;
for (i = 0; i < j->length; i++) {
if (within == GEOM_POINT) {
if (i == 0 || mb_geometry[t] == VT_POINT) {
if (i == 0 || mb_geometry[t] == GEOM_MULTIPOINT) {
op = VT_MOVETO;
} else {
op = VT_LINETO;
@ -80,12 +80,12 @@ void parse_geometry(int t, json_object *j, drawvec &out, int op, const char *fna
}
}
draw d(op, x, y);
out.push_back(draw(op, x, y));
} else {
fprintf(stderr, "%s:%d: malformed point\n", fname, line);
json_context(j);
json_context(feature);
exit(EXIT_FAILURE);
}
}

View File

@ -21,11 +21,6 @@
#include "evaluator.hpp"
#include "milo/dtoa_milo.h"
// Offset coordinates to keep them positive
#define COORD_OFFSET (4LL << 32)
#define SHIFT_RIGHT(a) ((((a) + COORD_OFFSET) >> geometry_scale) - (COORD_OFFSET >> geometry_scale))
#define SHIFT_LEFT(a) ((((a) + (COORD_OFFSET >> geometry_scale)) << geometry_scale) - COORD_OFFSET)
size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, const char *fname) {
size_t w = fwrite(ptr, size, nitems, stream);
if (w != nitems) {
@ -35,17 +30,17 @@ size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, c
return w;
}
void serialize_int(FILE *out, int n, std::atomic<long long> *fpos, const char *fname) {
void serialize_int(FILE *out, int n, long long *fpos, const char *fname) {
serialize_long_long(out, n, fpos, fname);
}
void serialize_long_long(FILE *out, long long n, std::atomic<long long> *fpos, const char *fname) {
void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname) {
unsigned long long zigzag = protozero::encode_zigzag64(n);
serialize_ulong_long(out, zigzag, fpos, fname);
}
void serialize_ulong_long(FILE *out, unsigned long long zigzag, std::atomic<long long> *fpos, const char *fname) {
void serialize_ulong_long(FILE *out, unsigned long long zigzag, long long *fpos, const char *fname) {
while (1) {
unsigned char b = zigzag & 0x7F;
if ((zigzag >> 7) != 0) {
@ -67,12 +62,12 @@ void serialize_ulong_long(FILE *out, unsigned long long zigzag, std::atomic<long
}
}
void serialize_byte(FILE *out, signed char n, std::atomic<long long> *fpos, const char *fname) {
void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(signed char), 1, out, fname);
*fpos += sizeof(signed char);
}
void serialize_uint(FILE *out, unsigned n, std::atomic<long long> *fpos, const char *fname) {
void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname) {
fwrite_check(&n, sizeof(unsigned), 1, out, fname);
*fpos += sizeof(unsigned);
}
@ -117,14 +112,14 @@ void deserialize_byte(char **f, signed char *n) {
*f += sizeof(signed char);
}
int deserialize_long_long_io(FILE *f, long long *n, std::atomic<long long> *geompos) {
int deserialize_long_long_io(FILE *f, long long *n, long long *geompos) {
unsigned long long zigzag = 0;
int ret = deserialize_ulong_long_io(f, &zigzag, geompos);
*n = protozero::decode_zigzag64(zigzag);
return ret;
}
int deserialize_ulong_long_io(FILE *f, unsigned long long *zigzag, std::atomic<long long> *geompos) {
int deserialize_ulong_long_io(FILE *f, unsigned long long *zigzag, long long *geompos) {
*zigzag = 0;
int shift = 0;
@ -148,14 +143,14 @@ int deserialize_ulong_long_io(FILE *f, unsigned long long *zigzag, std::atomic<l
return 1;
}
int deserialize_int_io(FILE *f, int *n, std::atomic<long long> *geompos) {
int deserialize_int_io(FILE *f, int *n, long long *geompos) {
long long ll = 0;
int ret = deserialize_long_long_io(f, &ll, geompos);
*n = ll;
return ret;
}
int deserialize_uint_io(FILE *f, unsigned *n, std::atomic<long long> *geompos) {
int deserialize_uint_io(FILE *f, unsigned *n, long long *geompos) {
if (fread(n, sizeof(unsigned), 1, f) != 1) {
return 0;
}
@ -163,7 +158,7 @@ int deserialize_uint_io(FILE *f, unsigned *n, std::atomic<long long> *geompos) {
return 1;
}
int deserialize_byte_io(FILE *f, signed char *n, std::atomic<long long> *geompos) {
int deserialize_byte_io(FILE *f, signed char *n, long long *geompos) {
int c = getc(f);
if (c == EOF) {
return 0;
@ -173,7 +168,7 @@ int deserialize_byte_io(FILE *f, signed char *n, std::atomic<long long> *geompos
return 1;
}
static void write_geometry(drawvec const &dv, std::atomic<long long> *fpos, FILE *out, const char *fname, long long wx, long long wy) {
static void write_geometry(drawvec const &dv, long long *fpos, FILE *out, const char *fname, long long wx, long long wy) {
for (size_t i = 0; i < dv.size(); i++) {
if (dv[i].op == VT_MOVETO || dv[i].op == VT_LINETO) {
serialize_byte(out, dv[i].op, fpos, fname);
@ -187,8 +182,7 @@ static void write_geometry(drawvec const &dv, std::atomic<long long> *fpos, FILE
}
}
// called from generating the next zoom level
void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long> *geompos, const char *fname, long long wx, long long wy, bool include_minzoom) {
void serialize_feature(FILE *geomfile, serial_feature *sf, long long *geompos, const char *fname, long long wx, long long wy, bool include_minzoom) {
serialize_byte(geomfile, sf->t, geompos, fname);
long long layer = 0;
@ -225,15 +219,19 @@ void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long
serialize_long_long(geomfile, sf->extent, geompos, fname);
}
serialize_long_long(geomfile, sf->metapos, geompos, fname);
serialize_int(geomfile, sf->m, geompos, fname);
if (sf->m != 0) {
serialize_long_long(geomfile, sf->metapos, geompos, fname);
}
if (sf->metapos < 0) {
serialize_long_long(geomfile, sf->keys.size(), geompos, fname);
if (sf->metapos < 0 && sf->m != sf->keys.size()) {
fprintf(stderr, "Internal error: feature said to have %lld attributes but only %lld found\n", (long long) sf->m, (long long) sf->keys.size());
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < sf->keys.size(); i++) {
serialize_long_long(geomfile, sf->keys[i], geompos, fname);
serialize_long_long(geomfile, sf->values[i], geompos, fname);
}
for (size_t i = 0; i < sf->keys.size(); i++) {
serialize_long_long(geomfile, sf->keys[i], geompos, fname);
serialize_long_long(geomfile, sf->values[i], geompos, fname);
}
if (include_minzoom) {
@ -241,7 +239,7 @@ void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long
}
}
serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_in, char *metabase, long long *meta_off, unsigned z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y) {
serial_feature deserialize_feature(FILE *geoms, long long *geompos_in, char *metabase, long long *meta_off, unsigned z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y) {
serial_feature sf;
deserialize_byte_io(geoms, &sf.t, geompos_in);
@ -287,14 +285,19 @@ serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_
sf.layer >>= 6;
sf.metapos = 0;
deserialize_long_long_io(geoms, &sf.metapos, geompos_in);
{
int m;
deserialize_int_io(geoms, &m, geompos_in);
sf.m = m;
}
if (sf.m != 0) {
deserialize_long_long_io(geoms, &sf.metapos, geompos_in);
}
if (sf.metapos >= 0) {
char *meta = metabase + sf.metapos + meta_off[sf.segment];
long long count;
deserialize_long_long(&meta, &count);
for (long long i = 0; i < count; i++) {
for (size_t i = 0; i < sf.m; i++) {
long long k, v;
deserialize_long_long(&meta, &k);
deserialize_long_long(&meta, &v);
@ -302,10 +305,7 @@ serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_
sf.values.push_back(v);
}
} else {
long long count;
deserialize_long_long_io(geoms, &count, geompos_in);
for (long long i = 0; i < count; i++) {
for (size_t i = 0; i < sf.m; i++) {
long long k, v;
deserialize_long_long_io(geoms, &k, geompos_in);
deserialize_long_long_io(geoms, &v, geompos_in);
@ -323,7 +323,6 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
long long offset = 0;
long long prev = 0;
bool has_prev = false;
double scale = 1.0 / (1 << geometry_scale);
for (size_t i = 0; i < geom.size(); i++) {
if (geom[i].op == VT_MOVETO || geom[i].op == VT_LINETO) {
@ -360,46 +359,25 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox
}
if (!*(sst->initialized)) {
if (x < 0 || x >= (1LL << 32) || y < 0 || y >= (1LL << 32)) {
if (x < 0 || x >= (1LL << 32) || y < 0 || y >= (1LL < 32)) {
*(sst->initial_x) = 1LL << 31;
*(sst->initial_y) = 1LL << 31;
} else {
*(sst->initial_x) = (((x + COORD_OFFSET) >> geometry_scale) << geometry_scale) - COORD_OFFSET;
*(sst->initial_y) = (((y + COORD_OFFSET) >> geometry_scale) << geometry_scale) - COORD_OFFSET;
*(sst->initial_x) = (x >> geometry_scale) << geometry_scale;
*(sst->initial_y) = (y >> geometry_scale) << geometry_scale;
}
*(sst->initialized) = 1;
}
if (additional[A_GRID_LOW_ZOOMS]) {
// If we are gridding, snap to the maxzoom grid in case the incoming data
// is already supposed to be aligned to tile boundaries (but is not, exactly,
// because of rounding error during projection).
geom[i].x = std::round(x * scale);
geom[i].y = std::round(y * scale);
} else {
geom[i].x = SHIFT_RIGHT(x);
geom[i].y = SHIFT_RIGHT(y);
}
geom[i].x = x >> geometry_scale;
geom[i].y = y >> geometry_scale;
}
}
return geom.size();
}
static std::string strip_zeroes(std::string s) {
// Doesn't do anything special with '-' followed by leading zeros
// since integer IDs must be positive
while (s.size() > 0 && s[0] == '0') {
s.erase(s.begin());
}
return s;
}
// called from frontends
int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
struct reader *r = &(*sst->readers)[sst->segment];
@ -415,57 +393,11 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
sf.geometry = fix_polygon(sf.geometry);
}
for (auto &c : clipbboxes) {
if (sf.t == VT_POLYGON) {
sf.geometry = simple_clip_poly(sf.geometry, SHIFT_RIGHT(c.minx), SHIFT_RIGHT(c.miny), SHIFT_RIGHT(c.maxx), SHIFT_RIGHT(c.maxy));
} else if (sf.t == VT_LINE) {
sf.geometry = clip_lines(sf.geometry, SHIFT_RIGHT(c.minx), SHIFT_RIGHT(c.miny), SHIFT_RIGHT(c.maxx), SHIFT_RIGHT(c.maxy));
sf.geometry = remove_noop(sf.geometry, sf.t, 0);
} else if (sf.t == VT_POINT) {
sf.geometry = clip_point(sf.geometry, SHIFT_RIGHT(c.minx), SHIFT_RIGHT(c.miny), SHIFT_RIGHT(c.maxx), SHIFT_RIGHT(c.maxy));
}
sf.bbox[0] = LLONG_MAX;
sf.bbox[1] = LLONG_MAX;
sf.bbox[2] = LLONG_MIN;
sf.bbox[3] = LLONG_MIN;
for (auto &g : sf.geometry) {
long long x = SHIFT_LEFT(g.x);
long long y = SHIFT_LEFT(g.y);
if (x < sf.bbox[0]) {
sf.bbox[0] = x;
}
if (y < sf.bbox[1]) {
sf.bbox[1] = y;
}
if (x > sf.bbox[2]) {
sf.bbox[2] = x;
}
if (y > sf.bbox[3]) {
sf.bbox[3] = y;
}
}
}
if (sf.geometry.size() == 0) {
// Feature was clipped away
return 1;
}
if (!sf.has_id) {
if (additional[A_GENERATE_IDS]) {
sf.has_id = true;
sf.id = sf.seq + 1;
}
}
if (sst->want_dist) {
std::vector<unsigned long long> locs;
for (size_t i = 0; i < sf.geometry.size(); i++) {
if (sf.geometry[i].op == VT_MOVETO || sf.geometry[i].op == VT_LINETO) {
locs.push_back(encode_index(SHIFT_LEFT(sf.geometry[i].x), SHIFT_LEFT(sf.geometry[i].y)));
locs.push_back(encode(sf.geometry[i].x << geometry_scale, sf.geometry[i].y << geometry_scale));
}
}
std::sort(locs.begin(), locs.end());
@ -500,7 +432,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
inline_meta = false;
if (prevent[P_CLIPPING]) {
static std::atomic<long long> warned(0);
static volatile long long warned = 0;
long long extent = ((sf.bbox[2] - sf.bbox[0]) / ((1LL << (32 - sst->maxzoom)) + 1)) * ((sf.bbox[3] - sf.bbox[1]) / ((1LL << (32 - sst->maxzoom)) + 1));
if (extent > warned) {
fprintf(stderr, "Warning: %s:%d: Large unclipped (-pc) feature may be duplicated across %lld tiles\n", sst->fname, sst->line, extent);
@ -541,11 +473,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
}
}
if (extent <= LLONG_MAX) {
sf.extent = (long long) extent;
} else {
sf.extent = LLONG_MAX;
}
sf.extent = (long long) extent;
if (!prevent[P_INPUT_ORDER]) {
sf.seq = 0;
@ -557,9 +485,9 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
// and then mask to bring it back into the addressable area
long long midx = (sf.bbox[0] / 2 + sf.bbox[2] / 2) & ((1LL << 32) - 1);
long long midy = (sf.bbox[1] / 2 + sf.bbox[3] / 2) & ((1LL << 32) - 1);
bbox_index = encode_index(midx, midy);
bbox_index = encode(midx, midy);
if (additional[A_DROP_DENSEST_AS_NEEDED] || additional[A_COALESCE_DENSEST_AS_NEEDED] || additional[A_CLUSTER_DENSEST_AS_NEEDED] || additional[A_CALCULATE_FEATURE_DENSITY] || additional[A_INCREASE_GAMMA_AS_NEEDED] || sst->uses_gamma || cluster_distance != 0) {
if (additional[A_DROP_DENSEST_AS_NEEDED] || additional[A_CLUSTER_DENSEST_AS_NEEDED] || additional[A_CALCULATE_FEATURE_DENSITY] || additional[A_INCREASE_GAMMA_AS_NEEDED] || sst->uses_gamma || cluster_distance != 0) {
sf.index = bbox_index;
} else {
sf.index = 0;
@ -588,56 +516,65 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
}
for (ssize_t i = (ssize_t) sf.full_keys.size() - 1; i >= 0; i--) {
coerce_value(sf.full_keys[i], sf.full_values[i].type, sf.full_values[i].s, sst->attribute_types);
if (sf.full_keys[i] == attribute_for_id) {
if (sf.full_values[i].type != mvt_double && !additional[A_CONVERT_NUMERIC_IDS]) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: Attribute \"%s\"=\"%s\" as feature ID is not a number\n", sf.full_keys[i].c_str(), sf.full_values[i].s.c_str());
warned = true;
}
} else {
char *err;
long long id_value = strtoull(sf.full_values[i].s.c_str(), &err, 10);
if (err != NULL && *err != '\0') {
static bool warned_frac = false;
if (!warned_frac) {
fprintf(stderr, "Warning: Can't represent non-integer feature ID %s\n", sf.full_values[i].s.c_str());
warned_frac = true;
}
} else if (std::to_string(id_value) != strip_zeroes(sf.full_values[i].s)) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: Can't represent too-large feature ID %s\n", sf.full_values[i].s.c_str());
warned = true;
}
} else {
sf.id = id_value;
sf.has_id = true;
sf.full_keys.erase(sf.full_keys.begin() + i);
sf.full_values.erase(sf.full_values.begin() + i);
continue;
}
}
}
if (sst->exclude_all) {
if (sst->include->count(sf.full_keys[i]) == 0) {
sf.full_keys.erase(sf.full_keys.begin() + i);
sf.full_values.erase(sf.full_values.begin() + i);
sf.m--;
continue;
}
} else if (sst->exclude->count(sf.full_keys[i]) != 0) {
sf.full_keys.erase(sf.full_keys.begin() + i);
sf.full_values.erase(sf.full_values.begin() + i);
sf.m--;
continue;
}
coerce_value(sf.full_keys[i], sf.full_values[i].type, sf.full_values[i].s, sst->attribute_types);
}
if (sst->filter != NULL) {
std::map<std::string, mvt_value> attributes;
for (size_t i = 0; i < sf.full_keys.size(); i++) {
std::string key = sf.full_keys[i];
mvt_value val = stringified_to_mvt_value(sf.full_values[i].type, sf.full_values[i].s.c_str());
attributes.insert(std::pair<std::string, mvt_value>(key, val));
}
if (sf.has_id) {
mvt_value v;
v.type = mvt_uint;
v.numeric_value.uint_value = sf.id;
attributes.insert(std::pair<std::string, mvt_value>("$id", v));
}
mvt_value v;
v.type = mvt_string;
if (sf.t == mvt_point) {
v.string_value = "Point";
} else if (sf.t == mvt_linestring) {
v.string_value = "LineString";
} else if (sf.t == mvt_polygon) {
v.string_value = "Polygon";
}
attributes.insert(std::pair<std::string, mvt_value>("$type", v));
if (!evaluate(attributes, sf.layername, sst->filter)) {
return 0;
}
}
for (ssize_t i = (ssize_t) sf.full_keys.size() - 1; i >= 0; i--) {
if (sf.full_values[i].type == mvt_null) {
sf.full_keys.erase(sf.full_keys.begin() + i);
sf.full_values.erase(sf.full_values.begin() + i);
sf.m--;
}
}
if (!sst->filters) {
@ -659,7 +596,6 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
}
} else {
sf.metapos = r->metapos;
serialize_long_long(r->metafile, sf.full_keys.size(), &r->metapos, sst->fname);
for (size_t i = 0; i < sf.full_keys.size(); i++) {
serialize_long_long(r->metafile, addpool(r->poolfile, r->treefile, sf.full_keys[i].c_str(), mvt_string), &r->metapos, sst->fname);
serialize_long_long(r->metafile, addpool(r->poolfile, r->treefile, sf.full_values[i].s.c_str(), sf.full_values[i].type), &r->metapos, sst->fname);
@ -667,7 +603,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
}
long long geomstart = r->geompos;
serialize_feature(r->geomfile, &sf, &r->geompos, sst->fname, SHIFT_RIGHT(*(sst->initial_x)), SHIFT_RIGHT(*(sst->initial_y)), false);
serialize_feature(r->geomfile, &sf, &r->geompos, sst->fname, *(sst->initial_x) >> geometry_scale, *(sst->initial_y) >> geometry_scale, false);
struct index index;
index.start = geomstart;
@ -693,7 +629,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) {
if (*(sst->progress_seq) % 10000 == 0) {
checkdisk(sst->readers);
if (!quiet && !quiet_progress && progress_time()) {
if (!quiet && !quiet_progress) {
fprintf(stderr, "Read %.2f million features\r", *sst->progress_seq / 1000000.0);
}
}

View File

@ -3,9 +3,7 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <atomic>
#include <sys/stat.h>
#include "geometry.hpp"
#include "mbtiles.hpp"
@ -13,12 +11,12 @@
size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, const char *fname);
void serialize_int(FILE *out, int n, std::atomic<long long> *fpos, const char *fname);
void serialize_long_long(FILE *out, long long n, std::atomic<long long> *fpos, const char *fname);
void serialize_ulong_long(FILE *out, unsigned long long n, std::atomic<long long> *fpos, const char *fname);
void serialize_byte(FILE *out, signed char n, std::atomic<long long> *fpos, const char *fname);
void serialize_uint(FILE *out, unsigned n, std::atomic<long long> *fpos, const char *fname);
void serialize_string(FILE *out, const char *s, std::atomic<long long> *fpos, const char *fname);
void serialize_int(FILE *out, int n, long long *fpos, const char *fname);
void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname);
void serialize_ulong_long(FILE *out, unsigned long long n, long long *fpos, const char *fname);
void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname);
void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname);
void serialize_string(FILE *out, const char *s, long long *fpos, const char *fname);
void deserialize_int(char **f, int *n);
void deserialize_long_long(char **f, long long *n);
@ -26,11 +24,11 @@ void deserialize_ulong_long(char **f, unsigned long long *n);
void deserialize_uint(char **f, unsigned *n);
void deserialize_byte(char **f, signed char *n);
int deserialize_int_io(FILE *f, int *n, std::atomic<long long> *geompos);
int deserialize_long_long_io(FILE *f, long long *n, std::atomic<long long> *geompos);
int deserialize_ulong_long_io(FILE *f, unsigned long long *n, std::atomic<long long> *geompos);
int deserialize_uint_io(FILE *f, unsigned *n, std::atomic<long long> *geompos);
int deserialize_byte_io(FILE *f, signed char *n, std::atomic<long long> *geompos);
int deserialize_int_io(FILE *f, int *n, long long *geompos);
int deserialize_long_long_io(FILE *f, long long *n, long long *geompos);
int deserialize_ulong_long_io(FILE *f, unsigned long long *n, long long *geompos);
int deserialize_uint_io(FILE *f, unsigned *n, long long *geompos);
int deserialize_byte_io(FILE *f, signed char *n, long long *geompos);
struct serial_val {
int type = 0;
@ -58,9 +56,9 @@ struct serial_feature {
unsigned long long index = 0;
long long extent = 0;
size_t m = 0;
std::vector<long long> keys{};
std::vector<long long> values{};
// If >= 0, metadata is external
long long metapos = 0;
// XXX This isn't serialized. Should it be here?
@ -68,11 +66,10 @@ struct serial_feature {
std::vector<std::string> full_keys{};
std::vector<serial_val> full_values{};
std::string layername = "";
bool dropped = false;
};
void serialize_feature(FILE *geomfile, serial_feature *sf, std::atomic<long long> *geompos, const char *fname, long long wx, long long wy, bool include_minzoom);
serial_feature deserialize_feature(FILE *geoms, std::atomic<long long> *geompos_in, char *metabase, long long *meta_off, unsigned z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y);
void serialize_feature(FILE *geomfile, serial_feature *sf, long long *geompos, const char *fname, long long wx, long long wy, bool include_minzoom);
serial_feature deserialize_feature(FILE *geoms, long long *geompos_in, char *metabase, long long *meta_off, unsigned z, unsigned tx, unsigned ty, unsigned *initial_x, unsigned *initial_y);
struct reader {
int metafd = -1;
@ -87,9 +84,9 @@ struct reader {
FILE *geomfile = NULL;
FILE *indexfile = NULL;
std::atomic<long long> metapos;
std::atomic<long long> geompos;
std::atomic<long long> indexpos;
long long metapos = 0;
long long geompos = 0;
long long indexpos = 0;
long long file_bbox[4] = {0, 0, 0, 0};
@ -97,48 +94,14 @@ struct reader {
struct stat metast {};
char *geom_map = NULL;
reader()
: metapos(0), geompos(0), indexpos(0) {
}
reader(reader const &r) {
metafd = r.metafd;
poolfd = r.poolfd;
treefd = r.treefd;
geomfd = r.geomfd;
indexfd = r.indexfd;
metafile = r.metafile;
poolfile = r.poolfile;
treefile = r.treefile;
geomfile = r.geomfile;
indexfile = r.indexfile;
long long p = r.metapos;
metapos = p;
p = r.geompos;
geompos = p;
p = r.indexpos;
indexpos = p;
memcpy(file_bbox, r.file_bbox, sizeof(file_bbox));
geomst = r.geomst;
metast = r.metast;
geom_map = r.geom_map;
}
};
struct serialization_state {
const char *fname = NULL; // source file name
int line = 0; // user-oriented location within source for error reports
std::atomic<long long> *layer_seq = NULL; // sequence within current layer
std::atomic<long long> *progress_seq = NULL; // overall sequence for progress indicator
volatile long long *layer_seq = NULL; // sequence within current layer
volatile long long *progress_seq = NULL; // overall sequence for progress indicator
std::vector<struct reader> *readers = NULL; // array of data for each input thread
int segment = 0; // the current input thread
@ -163,6 +126,7 @@ struct serialization_state {
std::set<std::string> *exclude = NULL;
std::set<std::string> *include = NULL;
int exclude_all = 0;
json_object *filter = NULL;
};
int serialize_feature(struct serialization_state *sst, serial_feature &sf);

View File

@ -1,100 +0,0 @@
{ "type": "Feature", "properties": { "thesum": 1, "themax": 1, "themin": 1, "theproduct": 1, "themean": 1, "theconcat": 1, "thecomma": 1 }, "geometry": { "type": "Point", "coordinates": [ 134.198884,-54.297477 ] } }
{ "type": "Feature", "properties": { "thesum": 2, "themax": 2, "themin": 2, "theproduct": 2, "themean": 2, "theconcat": 2, "thecomma": 2 }, "geometry": { "type": "Point", "coordinates": [ 14.059736,46.728490 ] } }
{ "type": "Feature", "properties": { "thesum": 3, "themax": 3, "themin": 3, "theproduct": 3, "themean": 3, "theconcat": 3, "thecomma": 3 }, "geometry": { "type": "Point", "coordinates": [ -147.369727,84.781281 ] } }
{ "type": "Feature", "properties": { "thesum": 4, "themax": 4, "themin": 4, "theproduct": 4, "themean": 4, "theconcat": 4, "thecomma": 4 }, "geometry": { "type": "Point", "coordinates": [ -66.234387,89.199903 ] } }
{ "type": "Feature", "properties": { "thesum": 5, "themax": 5, "themin": 5, "theproduct": 5, "themean": 5, "theconcat": 5, "thecomma": 5 }, "geometry": { "type": "Point", "coordinates": [ -153.412664,29.072260 ] } }
{ "type": "Feature", "properties": { "thesum": 6, "themax": 6, "themin": 6, "theproduct": 6, "themean": 6, "theconcat": 6, "thecomma": 6 }, "geometry": { "type": "Point", "coordinates": [ 170.262110,-59.450058 ] } }
{ "type": "Feature", "properties": { "thesum": 7, "themax": 7, "themin": 7, "theproduct": 7, "themean": 7, "theconcat": 7, "thecomma": 7 }, "geometry": { "type": "Point", "coordinates": [ 126.605140,8.723849 ] } }
{ "type": "Feature", "properties": { "thesum": 8, "themax": 8, "themin": 8, "theproduct": 8, "themean": 8, "theconcat": 8, "thecomma": 8 }, "geometry": { "type": "Point", "coordinates": [ 161.440413,-40.375296 ] } }
{ "type": "Feature", "properties": { "thesum": 9, "themax": 9, "themin": 9, "theproduct": 9, "themean": 9, "theconcat": 9, "thecomma": 9 }, "geometry": { "type": "Point", "coordinates": [ -168.588146,-52.640848 ] } }
{ "type": "Feature", "properties": { "thesum": 10, "themax": 10, "themin": 10, "theproduct": 10, "themean": 10, "theconcat": 10, "thecomma": 10 }, "geometry": { "type": "Point", "coordinates": [ 87.732615,-76.468219 ] } }
{ "type": "Feature", "properties": { "thesum": 11, "themax": 11, "themin": 11, "theproduct": 11, "themean": 11, "theconcat": 11, "thecomma": 11 }, "geometry": { "type": "Point", "coordinates": [ 30.857236,80.182977 ] } }
{ "type": "Feature", "properties": { "thesum": 12, "themax": 12, "themin": 12, "theproduct": 12, "themean": 12, "theconcat": 12, "thecomma": 12 }, "geometry": { "type": "Point", "coordinates": [ -145.428454,26.334493 ] } }
{ "type": "Feature", "properties": { "thesum": 13, "themax": 13, "themin": 13, "theproduct": 13, "themean": 13, "theconcat": 13, "thecomma": 13 }, "geometry": { "type": "Point", "coordinates": [ -3.709986,47.351847 ] } }
{ "type": "Feature", "properties": { "thesum": 14, "themax": 14, "themin": 14, "theproduct": 14, "themean": 14, "theconcat": 14, "thecomma": 14 }, "geometry": { "type": "Point", "coordinates": [ -145.079976,80.547441 ] } }
{ "type": "Feature", "properties": { "thesum": 15, "themax": 15, "themin": 15, "theproduct": 15, "themean": 15, "theconcat": 15, "thecomma": 15 }, "geometry": { "type": "Point", "coordinates": [ 14.666648,-65.254575 ] } }
{ "type": "Feature", "properties": { "thesum": 16, "themax": 16, "themin": 16, "theproduct": 16, "themean": 16, "theconcat": 16, "thecomma": 16 }, "geometry": { "type": "Point", "coordinates": [ 24.659014,60.295014 ] } }
{ "type": "Feature", "properties": { "thesum": 17, "themax": 17, "themin": 17, "theproduct": 17, "themean": 17, "theconcat": 17, "thecomma": 17 }, "geometry": { "type": "Point", "coordinates": [ 110.427380,38.364152 ] } }
{ "type": "Feature", "properties": { "thesum": 18, "themax": 18, "themin": 18, "theproduct": 18, "themean": 18, "theconcat": 18, "thecomma": 18 }, "geometry": { "type": "Point", "coordinates": [ 6.564431,-44.802836 ] } }
{ "type": "Feature", "properties": { "thesum": 19, "themax": 19, "themin": 19, "theproduct": 19, "themean": 19, "theconcat": 19, "thecomma": 19 }, "geometry": { "type": "Point", "coordinates": [ -25.148684,-41.191936 ] } }
{ "type": "Feature", "properties": { "thesum": 20, "themax": 20, "themin": 20, "theproduct": 20, "themean": 20, "theconcat": 20, "thecomma": 20 }, "geometry": { "type": "Point", "coordinates": [ 94.640674,87.473404 ] } }
{ "type": "Feature", "properties": { "thesum": 21, "themax": 21, "themin": 21, "theproduct": 21, "themean": 21, "theconcat": 21, "thecomma": 21 }, "geometry": { "type": "Point", "coordinates": [ -15.166749,44.154022 ] } }
{ "type": "Feature", "properties": { "thesum": 22, "themax": 22, "themin": 22, "theproduct": 22, "themean": 22, "theconcat": 22, "thecomma": 22 }, "geometry": { "type": "Point", "coordinates": [ -83.839224,-22.324076 ] } }
{ "type": "Feature", "properties": { "thesum": 23, "themax": 23, "themin": 23, "theproduct": 23, "themean": 23, "theconcat": 23, "thecomma": 23 }, "geometry": { "type": "Point", "coordinates": [ -131.431059,-48.656317 ] } }
{ "type": "Feature", "properties": { "thesum": 24, "themax": 24, "themin": 24, "theproduct": 24, "themean": 24, "theconcat": 24, "thecomma": 24 }, "geometry": { "type": "Point", "coordinates": [ 13.458676,-81.541789 ] } }
{ "type": "Feature", "properties": { "thesum": 25, "themax": 25, "themin": 25, "theproduct": 25, "themean": 25, "theconcat": 25, "thecomma": 25 }, "geometry": { "type": "Point", "coordinates": [ 49.375287,54.035848 ] } }
{ "type": "Feature", "properties": { "thesum": 26, "themax": 26, "themin": 26, "theproduct": 26, "themean": 26, "theconcat": 26, "thecomma": 26 }, "geometry": { "type": "Point", "coordinates": [ 44.023761,42.750924 ] } }
{ "type": "Feature", "properties": { "thesum": 27, "themax": 27, "themin": 27, "theproduct": 27, "themean": 27, "theconcat": 27, "thecomma": 27 }, "geometry": { "type": "Point", "coordinates": [ 23.815303,87.689971 ] } }
{ "type": "Feature", "properties": { "thesum": 28, "themax": 28, "themin": 28, "theproduct": 28, "themean": 28, "theconcat": 28, "thecomma": 28 }, "geometry": { "type": "Point", "coordinates": [ -108.418101,69.859222 ] } }
{ "type": "Feature", "properties": { "thesum": 29, "themax": 29, "themin": 29, "theproduct": 29, "themean": 29, "theconcat": 29, "thecomma": 29 }, "geometry": { "type": "Point", "coordinates": [ -162.422461,-72.828993 ] } }
{ "type": "Feature", "properties": { "thesum": 30, "themax": 30, "themin": 30, "theproduct": 30, "themean": 30, "theconcat": 30, "thecomma": 30 }, "geometry": { "type": "Point", "coordinates": [ 41.555960,87.834643 ] } }
{ "type": "Feature", "properties": { "thesum": 31, "themax": 31, "themin": 31, "theproduct": 31, "themean": 31, "theconcat": 31, "thecomma": 31 }, "geometry": { "type": "Point", "coordinates": [ 151.433696,-2.049808 ] } }
{ "type": "Feature", "properties": { "thesum": 32, "themax": 32, "themin": 32, "theproduct": 32, "themean": 32, "theconcat": 32, "thecomma": 32 }, "geometry": { "type": "Point", "coordinates": [ -156.347397,-54.157799 ] } }
{ "type": "Feature", "properties": { "thesum": 33, "themax": 33, "themin": 33, "theproduct": 33, "themean": 33, "theconcat": 33, "thecomma": 33 }, "geometry": { "type": "Point", "coordinates": [ 177.449262,76.384948 ] } }
{ "type": "Feature", "properties": { "thesum": 34, "themax": 34, "themin": 34, "theproduct": 34, "themean": 34, "theconcat": 34, "thecomma": 34 }, "geometry": { "type": "Point", "coordinates": [ 67.516237,89.283900 ] } }
{ "type": "Feature", "properties": { "thesum": 35, "themax": 35, "themin": 35, "theproduct": 35, "themean": 35, "theconcat": 35, "thecomma": 35 }, "geometry": { "type": "Point", "coordinates": [ 57.957991,-82.230182 ] } }
{ "type": "Feature", "properties": { "thesum": 36, "themax": 36, "themin": 36, "theproduct": 36, "themean": 36, "theconcat": 36, "thecomma": 36 }, "geometry": { "type": "Point", "coordinates": [ 152.745823,-78.389341 ] } }
{ "type": "Feature", "properties": { "thesum": 37, "themax": 37, "themin": 37, "theproduct": 37, "themean": 37, "theconcat": 37, "thecomma": 37 }, "geometry": { "type": "Point", "coordinates": [ -79.735349,80.847381 ] } }
{ "type": "Feature", "properties": { "thesum": 38, "themax": 38, "themin": 38, "theproduct": 38, "themean": 38, "theconcat": 38, "thecomma": 38 }, "geometry": { "type": "Point", "coordinates": [ -176.469083,-1.175014 ] } }
{ "type": "Feature", "properties": { "thesum": 39, "themax": 39, "themin": 39, "theproduct": 39, "themean": 39, "theconcat": 39, "thecomma": 39 }, "geometry": { "type": "Point", "coordinates": [ 20.369644,-44.945809 ] } }
{ "type": "Feature", "properties": { "thesum": 40, "themax": 40, "themin": 40, "theproduct": 40, "themean": 40, "theconcat": 40, "thecomma": 40 }, "geometry": { "type": "Point", "coordinates": [ 75.300338,89.728838 ] } }
{ "type": "Feature", "properties": { "thesum": 41, "themax": 41, "themin": 41, "theproduct": 41, "themean": 41, "theconcat": 41, "thecomma": 41 }, "geometry": { "type": "Point", "coordinates": [ -60.903503,-89.434640 ] } }
{ "type": "Feature", "properties": { "thesum": 42, "themax": 42, "themin": 42, "theproduct": 42, "themean": 42, "theconcat": 42, "thecomma": 42 }, "geometry": { "type": "Point", "coordinates": [ -116.214566,-78.600594 ] } }
{ "type": "Feature", "properties": { "thesum": 43, "themax": 43, "themin": 43, "theproduct": 43, "themean": 43, "theconcat": 43, "thecomma": 43 }, "geometry": { "type": "Point", "coordinates": [ -168.143210,-37.381940 ] } }
{ "type": "Feature", "properties": { "thesum": 44, "themax": 44, "themin": 44, "theproduct": 44, "themean": 44, "theconcat": 44, "thecomma": 44 }, "geometry": { "type": "Point", "coordinates": [ 146.600367,-65.112907 ] } }
{ "type": "Feature", "properties": { "thesum": 45, "themax": 45, "themin": 45, "theproduct": 45, "themean": 45, "theconcat": 45, "thecomma": 45 }, "geometry": { "type": "Point", "coordinates": [ -144.960448,89.877412 ] } }
{ "type": "Feature", "properties": { "thesum": 46, "themax": 46, "themin": 46, "theproduct": 46, "themean": 46, "theconcat": 46, "thecomma": 46 }, "geometry": { "type": "Point", "coordinates": [ 37.779538,-9.255682 ] } }
{ "type": "Feature", "properties": { "thesum": 47, "themax": 47, "themin": 47, "theproduct": 47, "themean": 47, "theconcat": 47, "thecomma": 47 }, "geometry": { "type": "Point", "coordinates": [ 141.921366,-86.191382 ] } }
{ "type": "Feature", "properties": { "thesum": 48, "themax": 48, "themin": 48, "theproduct": 48, "themean": 48, "theconcat": 48, "thecomma": 48 }, "geometry": { "type": "Point", "coordinates": [ 3.757458,-46.957098 ] } }
{ "type": "Feature", "properties": { "thesum": 49, "themax": 49, "themin": 49, "theproduct": 49, "themean": 49, "theconcat": 49, "thecomma": 49 }, "geometry": { "type": "Point", "coordinates": [ -178.557808,-17.999930 ] } }
{ "type": "Feature", "properties": { "thesum": 50, "themax": 50, "themin": 50, "theproduct": 50, "themean": 50, "theconcat": 50, "thecomma": 50 }, "geometry": { "type": "Point", "coordinates": [ -94.775598,89.666291 ] } }
{ "type": "Feature", "properties": { "thesum": 51, "themax": 51, "themin": 51, "theproduct": 51, "themean": 51, "theconcat": 51, "thecomma": 51 }, "geometry": { "type": "Point", "coordinates": [ -105.311977,25.819445 ] } }
{ "type": "Feature", "properties": { "thesum": 52, "themax": 52, "themin": 52, "theproduct": 52, "themean": 52, "theconcat": 52, "thecomma": 52 }, "geometry": { "type": "Point", "coordinates": [ 116.462344,-73.172234 ] } }
{ "type": "Feature", "properties": { "thesum": 53, "themax": 53, "themin": 53, "theproduct": 53, "themean": 53, "theconcat": 53, "thecomma": 53 }, "geometry": { "type": "Point", "coordinates": [ -84.902185,62.166503 ] } }
{ "type": "Feature", "properties": { "thesum": 54, "themax": 54, "themin": 54, "theproduct": 54, "themean": 54, "theconcat": 54, "thecomma": 54 }, "geometry": { "type": "Point", "coordinates": [ -141.394664,-11.763473 ] } }
{ "type": "Feature", "properties": { "thesum": 55, "themax": 55, "themin": 55, "theproduct": 55, "themean": 55, "theconcat": 55, "thecomma": 55 }, "geometry": { "type": "Point", "coordinates": [ 96.026399,83.713544 ] } }
{ "type": "Feature", "properties": { "thesum": 56, "themax": 56, "themin": 56, "theproduct": 56, "themean": 56, "theconcat": 56, "thecomma": 56 }, "geometry": { "type": "Point", "coordinates": [ -154.653153,-89.307708 ] } }
{ "type": "Feature", "properties": { "thesum": 57, "themax": 57, "themin": 57, "theproduct": 57, "themean": 57, "theconcat": 57, "thecomma": 57 }, "geometry": { "type": "Point", "coordinates": [ -71.769818,83.010189 ] } }
{ "type": "Feature", "properties": { "thesum": 58, "themax": 58, "themin": 58, "theproduct": 58, "themean": 58, "theconcat": 58, "thecomma": 58 }, "geometry": { "type": "Point", "coordinates": [ 141.629089,-84.969764 ] } }
{ "type": "Feature", "properties": { "thesum": 59, "themax": 59, "themin": 59, "theproduct": 59, "themean": 59, "theconcat": 59, "thecomma": 59 }, "geometry": { "type": "Point", "coordinates": [ -146.893857,-72.900555 ] } }
{ "type": "Feature", "properties": { "thesum": 60, "themax": 60, "themin": 60, "theproduct": 60, "themean": 60, "theconcat": 60, "thecomma": 60 }, "geometry": { "type": "Point", "coordinates": [ 13.616243,86.468765 ] } }
{ "type": "Feature", "properties": { "thesum": 61, "themax": 61, "themin": 61, "theproduct": 61, "themean": 61, "theconcat": 61, "thecomma": 61 }, "geometry": { "type": "Point", "coordinates": [ 146.239761,-77.415130 ] } }
{ "type": "Feature", "properties": { "thesum": 62, "themax": 62, "themin": 62, "theproduct": 62, "themean": 62, "theconcat": 62, "thecomma": 62 }, "geometry": { "type": "Point", "coordinates": [ 120.720040,34.052368 ] } }
{ "type": "Feature", "properties": { "thesum": 63, "themax": 63, "themin": 63, "theproduct": 63, "themean": 63, "theconcat": 63, "thecomma": 63 }, "geometry": { "type": "Point", "coordinates": [ -50.738121,-49.044879 ] } }
{ "type": "Feature", "properties": { "thesum": 64, "themax": 64, "themin": 64, "theproduct": 64, "themean": 64, "theconcat": 64, "thecomma": 64 }, "geometry": { "type": "Point", "coordinates": [ 159.682795,-17.137421 ] } }
{ "type": "Feature", "properties": { "thesum": 65, "themax": 65, "themin": 65, "theproduct": 65, "themean": 65, "theconcat": 65, "thecomma": 65 }, "geometry": { "type": "Point", "coordinates": [ -166.439086,2.775299 ] } }
{ "type": "Feature", "properties": { "thesum": 66, "themax": 66, "themin": 66, "theproduct": 66, "themean": 66, "theconcat": 66, "thecomma": 66 }, "geometry": { "type": "Point", "coordinates": [ -68.075084,-6.863559 ] } }
{ "type": "Feature", "properties": { "thesum": 67, "themax": 67, "themin": 67, "theproduct": 67, "themean": 67, "theconcat": 67, "thecomma": 67 }, "geometry": { "type": "Point", "coordinates": [ -177.446873,22.270257 ] } }
{ "type": "Feature", "properties": { "thesum": 68, "themax": 68, "themin": 68, "theproduct": 68, "themean": 68, "theconcat": 68, "thecomma": 68 }, "geometry": { "type": "Point", "coordinates": [ 116.851469,-89.159093 ] } }
{ "type": "Feature", "properties": { "thesum": 69, "themax": 69, "themin": 69, "theproduct": 69, "themean": 69, "theconcat": 69, "thecomma": 69 }, "geometry": { "type": "Point", "coordinates": [ 113.612595,13.841587 ] } }
{ "type": "Feature", "properties": { "thesum": 70, "themax": 70, "themin": 70, "theproduct": 70, "themean": 70, "theconcat": 70, "thecomma": 70 }, "geometry": { "type": "Point", "coordinates": [ 147.030951,-21.627240 ] } }
{ "type": "Feature", "properties": { "thesum": 71, "themax": 71, "themin": 71, "theproduct": 71, "themean": 71, "theconcat": 71, "thecomma": 71 }, "geometry": { "type": "Point", "coordinates": [ -171.838003,-55.021829 ] } }
{ "type": "Feature", "properties": { "thesum": 72, "themax": 72, "themin": 72, "theproduct": 72, "themean": 72, "theconcat": 72, "thecomma": 72 }, "geometry": { "type": "Point", "coordinates": [ -179.320808,-69.030987 ] } }
{ "type": "Feature", "properties": { "thesum": 73, "themax": 73, "themin": 73, "theproduct": 73, "themean": 73, "theconcat": 73, "thecomma": 73 }, "geometry": { "type": "Point", "coordinates": [ -41.291951,-0.546778 ] } }
{ "type": "Feature", "properties": { "thesum": 74, "themax": 74, "themin": 74, "theproduct": 74, "themean": 74, "theconcat": 74, "thecomma": 74 }, "geometry": { "type": "Point", "coordinates": [ -159.602264,33.516804 ] } }
{ "type": "Feature", "properties": { "thesum": 75, "themax": 75, "themin": 75, "theproduct": 75, "themean": 75, "theconcat": 75, "thecomma": 75 }, "geometry": { "type": "Point", "coordinates": [ -157.220701,-62.925493 ] } }
{ "type": "Feature", "properties": { "thesum": 76, "themax": 76, "themin": 76, "theproduct": 76, "themean": 76, "theconcat": 76, "thecomma": 76 }, "geometry": { "type": "Point", "coordinates": [ 35.449285,-21.548332 ] } }
{ "type": "Feature", "properties": { "thesum": 77, "themax": 77, "themin": 77, "theproduct": 77, "themean": 77, "theconcat": 77, "thecomma": 77 }, "geometry": { "type": "Point", "coordinates": [ 101.921779,85.807116 ] } }
{ "type": "Feature", "properties": { "thesum": 78, "themax": 78, "themin": 78, "theproduct": 78, "themean": 78, "theconcat": 78, "thecomma": 78 }, "geometry": { "type": "Point", "coordinates": [ -128.051674,83.348143 ] } }
{ "type": "Feature", "properties": { "thesum": 79, "themax": 79, "themin": 79, "theproduct": 79, "themean": 79, "theconcat": 79, "thecomma": 79 }, "geometry": { "type": "Point", "coordinates": [ 53.387503,-84.129458 ] } }
{ "type": "Feature", "properties": { "thesum": 80, "themax": 80, "themin": 80, "theproduct": 80, "themean": 80, "theconcat": 80, "thecomma": 80 }, "geometry": { "type": "Point", "coordinates": [ 58.273040,-53.030862 ] } }
{ "type": "Feature", "properties": { "thesum": 81, "themax": 81, "themin": 81, "theproduct": 81, "themean": 81, "theconcat": 81, "thecomma": 81 }, "geometry": { "type": "Point", "coordinates": [ 125.294919,18.287339 ] } }
{ "type": "Feature", "properties": { "thesum": 82, "themax": 82, "themin": 82, "theproduct": 82, "themean": 82, "theconcat": 82, "thecomma": 82 }, "geometry": { "type": "Point", "coordinates": [ 31.960448,55.594735 ] } }
{ "type": "Feature", "properties": { "thesum": 83, "themax": 83, "themin": 83, "theproduct": 83, "themean": 83, "theconcat": 83, "thecomma": 83 }, "geometry": { "type": "Point", "coordinates": [ 43.356826,-79.995205 ] } }
{ "type": "Feature", "properties": { "thesum": 84, "themax": 84, "themin": 84, "theproduct": 84, "themean": 84, "theconcat": 84, "thecomma": 84 }, "geometry": { "type": "Point", "coordinates": [ -117.349281,13.354257 ] } }
{ "type": "Feature", "properties": { "thesum": 85, "themax": 85, "themin": 85, "theproduct": 85, "themean": 85, "theconcat": 85, "thecomma": 85 }, "geometry": { "type": "Point", "coordinates": [ 7.392891,-80.387558 ] } }
{ "type": "Feature", "properties": { "thesum": 86, "themax": 86, "themin": 86, "theproduct": 86, "themean": 86, "theconcat": 86, "thecomma": 86 }, "geometry": { "type": "Point", "coordinates": [ -0.255971,-32.692982 ] } }
{ "type": "Feature", "properties": { "thesum": 87, "themax": 87, "themin": 87, "theproduct": 87, "themean": 87, "theconcat": 87, "thecomma": 87 }, "geometry": { "type": "Point", "coordinates": [ 165.528504,-69.862641 ] } }
{ "type": "Feature", "properties": { "thesum": 88, "themax": 88, "themin": 88, "theproduct": 88, "themean": 88, "theconcat": 88, "thecomma": 88 }, "geometry": { "type": "Point", "coordinates": [ -137.105444,-88.260877 ] } }
{ "type": "Feature", "properties": { "thesum": 89, "themax": 89, "themin": 89, "theproduct": 89, "themean": 89, "theconcat": 89, "thecomma": 89 }, "geometry": { "type": "Point", "coordinates": [ 28.112105,24.529585 ] } }
{ "type": "Feature", "properties": { "thesum": 90, "themax": 90, "themin": 90, "theproduct": 90, "themean": 90, "theconcat": 90, "thecomma": 90 }, "geometry": { "type": "Point", "coordinates": [ -29.013503,48.460714 ] } }
{ "type": "Feature", "properties": { "thesum": 91, "themax": 91, "themin": 91, "theproduct": 91, "themean": 91, "theconcat": 91, "thecomma": 91 }, "geometry": { "type": "Point", "coordinates": [ 114.967139,84.177181 ] } }
{ "type": "Feature", "properties": { "thesum": 92, "themax": 92, "themin": 92, "theproduct": 92, "themean": 92, "theconcat": 92, "thecomma": 92 }, "geometry": { "type": "Point", "coordinates": [ -63.363328,58.006985 ] } }
{ "type": "Feature", "properties": { "thesum": 93, "themax": 93, "themin": 93, "theproduct": 93, "themean": 93, "theconcat": 93, "thecomma": 93 }, "geometry": { "type": "Point", "coordinates": [ 169.765226,17.852955 ] } }
{ "type": "Feature", "properties": { "thesum": 94, "themax": 94, "themin": 94, "theproduct": 94, "themean": 94, "theconcat": 94, "thecomma": 94 }, "geometry": { "type": "Point", "coordinates": [ -132.507302,18.086814 ] } }
{ "type": "Feature", "properties": { "thesum": 95, "themax": 95, "themin": 95, "theproduct": 95, "themean": 95, "theconcat": 95, "thecomma": 95 }, "geometry": { "type": "Point", "coordinates": [ -56.678179,-62.556708 ] } }
{ "type": "Feature", "properties": { "thesum": 96, "themax": 96, "themin": 96, "theproduct": 96, "themean": 96, "theconcat": 96, "thecomma": 96 }, "geometry": { "type": "Point", "coordinates": [ 174.715105,-76.783064 ] } }
{ "type": "Feature", "properties": { "thesum": 97, "themax": 97, "themin": 97, "theproduct": 97, "themean": 97, "theconcat": 97, "thecomma": 97 }, "geometry": { "type": "Point", "coordinates": [ -19.142632,85.007238 ] } }
{ "type": "Feature", "properties": { "thesum": 98, "themax": 98, "themin": 98, "theproduct": 98, "themean": 98, "theconcat": 98, "thecomma": 98 }, "geometry": { "type": "Point", "coordinates": [ 58.241524,86.371735 ] } }
{ "type": "Feature", "properties": { "thesum": 99, "themax": 99, "themin": 99, "theproduct": 99, "themean": 99, "theconcat": 99, "thecomma": 99 }, "geometry": { "type": "Point", "coordinates": [ -27.756470,53.336764 ] } }
{ "type": "Feature", "properties": { "thesum": 100, "themax": 100, "themin": 100, "theproduct": 100, "themean": 100, "theconcat": 100, "thecomma": 100 }, "geometry": { "type": "Point", "coordinates": [ -123.948513,-81.873970 ] } }

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,6 @@
"center": "0.000000,0.000000,0",
"description": "tests/attribute-type/out/-z0_-Tinttype@int_-Tfloattype@float_-Tbooltype@bool_-Tstringtype@string.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/attribute-type/out/-z0_-Tinttype@int_-Tfloattype@float_-Tbooltype@bool_-Tstringtype@string.json.check.mbtiles -z0 -Tinttype:int -Tfloattype:float -Tbooltype:bool -Tstringtype:string tests/attribute-type/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {\"booltype\": \"Boolean\", \"expect\": \"Mixed\", \"floattype\": \"Number\", \"inttype\": \"Number\", \"stringtype\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 39,\"geometry\": \"Point\",\"attributeCount\": 5,\"attributes\": [{\"attribute\": \"booltype\",\"count\": 2,\"type\": \"boolean\",\"values\": [false,true]},{\"attribute\": \"expect\",\"count\": 14,\"type\": \"mixed\",\"values\": [0,\"2\",\"2.5\",3,5,5.6,6,\"[2,3]\",\"false\",false,\"null\",\"something\",\"true\",true],\"min\": 0,\"max\": 6},{\"attribute\": \"floattype\",\"count\": 4,\"type\": \"number\",\"values\": [0,3,5,5.6],\"min\": 0,\"max\": 5.6},{\"attribute\": \"inttype\",\"count\": 5,\"type\": \"number\",\"values\": [0,0.000000,3.000000,5,6.000000],\"min\": 0,\"max\": 6},{\"attribute\": \"stringtype\",\"count\": 7,\"type\": \"string\",\"values\": [\"2\",\"2.5\",\"[2,3]\",\"false\",\"null\",\"something\",\"true\"]}]}]}}",
"maxzoom": "0",
"minzoom": "0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -239,11 +239,6 @@ scalerank,natscale,labelrank,featurecla,name,namepar,namealt,diffascii,nameascii
0,600,1,Admin-1 capital,Kolkata,Calcutta,,0,Kolkata,0.00000000000,,,0.00000000000,1,India,IND,India,IND,West Bengal,IN,,22.49496929830,88.32467565810,4.00000000000,1,Name changed. Changed scale rank.,14787000,4631392,7783716,14,12,1275004.00000000000,Kolkata,Calcutta,1,0,3.7
0,600,1,Admin-1 capital,Rio de Janeiro,,,0,Rio de Janeiro,0.00000000000,,,1.00000000000,1,Brazil,BRA,Brazil,BRA,Rio de Janeiro,BR,,-22.92502317420,-43.22502079420,0.00000000000,0,,11748000,2010175,1821489,14,12,3451190.00000000000,Rio de Janeiro,Rio de Janeiro,1,0,1.7
0,600,1,Admin-1 capital,São Paulo,,Sao Paulo|Sio Paulo,0,Sao Paulo,0.00000000000,,,1.00000000000,1,Brazil,BRA,Brazil,BRA,São Paulo,BR,,-23.55867958700,-46.62501998040,0.00000000000,0,,18845000,10021295,11522944,14,14,3448439.00000000000,S,Sao Paolo,1,0,3.0
0,600,3,Admin-1 capital,Sydney,,,0,Sydney,0.00000000000,,,1.00000000000,1,Australia,AUS,Australia,AUS,New South Wales,AU,,-33.92001096720,151.18517980900,4.00000000000,0,Changed feature class.,4630000,3641422,2669348,12,12,2147714.00000000000,Sydney,Sydney1,1,0,
0,600,3,Admin-1 capital,Sydney,,,0,Sydney,0.00000000000,,,1.00000000000,1,Australia,AUS,Australia,AUS,New South Wales,AU,,-33.92001096720,151.18517980900,4.00000000000,0,Changed feature class.,4630000,3641422,2669348,12,12,2147714.00000000000,Sydney,Sydney1,1,0,1.7
0,600,0,Admin-0 capital,Singapore,,,0,Singapore,1.00000000000,,,1.00000000000,1,Singapore,SGP,Singapore,SGP,,SG,,1.29303346649,103.85582067800,0.00000000000,0,,5183700,3289529,3314179,13,12,1880252.00000000000,Singapore,Singapore,1,5,2.1
0,600,0,Admin-0 region capital,Hong Kong,,,0,Hong Kong,0.00000000000,,,1.00000000000,1,China,CHN,Hong Kong S.A.R.,HKG,,HK,,22.30498089500,114.18500931700,0.00000000000,0,,7206000,4551579,4549026,13,12,1819729.00000000000,Hong Kong,Hong Kong,1,0,3.0
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
0,600,0,Admin-0 region capital,Hong Kong,,,0,Hong Kong,0.00000000000,,,1.00000000000,1,China,CHN,Hong Kong S.A.R.,HKG,,HK,,nan,114.18500931700,0.00000000000,0,,7206000,4551579,4549026,13,12,1819729.00000000000,Hong Kong,Hong Kong,1,0,3.0
0,600,0,Admin-0 region capital,Hong Kong,,,0,Hong Kong,0.00000000000,,,1.00000000000,1,China,CHN,Hong Kong S.A.R.,HKG,,HK,,inf,114.18500931700,0.00000000000,0,,7206000,4551579,4549026,13,12,1819729.00000000000,Hong Kong,Hong Kong,1,0,3.0
0,600,0,Admin-0 region capital,Hong Kong,,,0,Hong Kong,0.00000000000,,,1.00000000000,1,China,CHN,Hong Kong S.A.R.,HKG,,HK,,22.30498089500,nan,0.00000000000,0,,7206000,4551579,4549026,13,12,1819729.00000000000,Hong Kong,Hong Kong,1,0,3.0
0,600,0,Admin-0 region capital,Hong Kong,,,0,Hong Kong,0.00000000000,,,1.00000000000,1,China,CHN,Hong Kong S.A.R.,HKG,,HK,,22.30498089500,inf,0.00000000000,0,,7206000,4551579,4549026,13,12,1819729.00000000000,Hong Kong,Hong Kong,1,0,3.0

1 scalerank natscale labelrank featurecla name namepar namealt diffascii nameascii adm0cap capalt capin worldcity megacity sov0name sov_a3 adm0name adm0_a3 adm1name iso_a2 note latitude longitude changed namediff diffnote pop_max pop_min pop_other rank_max rank_min geonameid meganame ls_name ls_match checkme min_zoom
239 0 600 1 Admin-1 capital Kolkata Calcutta 0 Kolkata 0.00000000000 0.00000000000 1 India IND India IND West Bengal IN 22.49496929830 88.32467565810 4.00000000000 1 Name changed. Changed scale rank. 14787000 4631392 7783716 14 12 1275004.00000000000 Kolkata Calcutta 1 0 3.7
240 0 600 1 Admin-1 capital Rio de Janeiro 0 Rio de Janeiro 0.00000000000 1.00000000000 1 Brazil BRA Brazil BRA Rio de Janeiro BR -22.92502317420 -43.22502079420 0.00000000000 0 11748000 2010175 1821489 14 12 3451190.00000000000 Rio de Janeiro Rio de Janeiro 1 0 1.7
241 0 600 1 Admin-1 capital São Paulo Sao Paulo|Sio Paulo 0 Sao Paulo 0.00000000000 1.00000000000 1 Brazil BRA Brazil BRA São Paulo BR -23.55867958700 -46.62501998040 0.00000000000 0 18845000 10021295 11522944 14 14 3448439.00000000000 S Sao Paolo 1 0 3.0
242 0 600 3 Admin-1 capital Sydney 0 Sydney 0.00000000000 1.00000000000 1 Australia AUS Australia AUS New South Wales AU -33.92001096720 151.18517980900 4.00000000000 0 Changed feature class. 4630000 3641422 2669348 12 12 2147714.00000000000 Sydney Sydney1 1 0 1.7
243 0 600 0 Admin-0 capital Singapore 0 Singapore 1.00000000000 1.00000000000 1 Singapore SGP Singapore SGP SG 1.29303346649 103.85582067800 0.00000000000 0 5183700 3289529 3314179 13 12 1880252.00000000000 Singapore Singapore 1 5 2.1
244 0 600 0 Admin-0 region capital Hong Kong 0 Hong Kong 0.00000000000 1.00000000000 1 China CHN Hong Kong S.A.R. HKG HK 22.30498089500 114.18500931700 0.00000000000 0 7206000 4551579 4549026 13 12 1819729.00000000000 Hong Kong Hong Kong 1 0 3.0
0 600 0 Admin-0 region capital Hong Kong 0 Hong Kong 0.00000000000 1.00000000000 1 China CHN Hong Kong S.A.R. HKG HK nan 114.18500931700 0.00000000000 0 7206000 4551579 4549026 13 12 1819729.00000000000 Hong Kong Hong Kong 1 0 3.0
0 600 0 Admin-0 region capital Hong Kong 0 Hong Kong 0.00000000000 1.00000000000 1 China CHN Hong Kong S.A.R. HKG HK inf 114.18500931700 0.00000000000 0 7206000 4551579 4549026 13 12 1819729.00000000000 Hong Kong Hong Kong 1 0 3.0
0 600 0 Admin-0 region capital Hong Kong 0 Hong Kong 0.00000000000 1.00000000000 1 China CHN Hong Kong S.A.R. HKG HK 22.30498089500 nan 0.00000000000 0 7206000 4551579 4549026 13 12 1819729.00000000000 Hong Kong Hong Kong 1 0 3.0
0 600 0 Admin-0 region capital Hong Kong 0 Hong Kong 0.00000000000 1.00000000000 1 China CHN Hong Kong S.A.R. HKG HK 22.30498089500 inf 0.00000000000 0 7206000 4551579 4549026 13 12 1819729.00000000000 Hong Kong Hong Kong 1 0 3.0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,6 @@
"center": "-135.000000,75.782195,2",
"description": "tests/curve/out/-z2.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/curve/out/-z2.json.check.mbtiles -z2 tests/curve/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 2, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 2,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}",
"maxzoom": "2",
"minzoom": "0",

View File

@ -3,7 +3,6 @@
"center": "-135.000000,75.782195,2",
"description": "tests/curve/out/-z2_--no-clipping.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/curve/out/-z2_--no-clipping.json.check.mbtiles -z2 --no-clipping tests/curve/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 2, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 2,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}",
"maxzoom": "2",
"minzoom": "0",

View File

@ -3,7 +3,6 @@
"center": "45.000000,33.256630,2",
"description": "tests/curve/out/-z2_--no-duplication.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/curve/out/-z2_--no-duplication.json.check.mbtiles -z2 --no-duplication tests/curve/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 2, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 2,\"geometry\": \"Polygon\",\"attributeCount\": 0,\"attributes\": []}]}}",
"maxzoom": "2",
"minzoom": "0",

View File

@ -1,6 +1,4 @@
{"type":"FeatureCollection",
"crs": { "type": "name", "properties": { } },
"features":[
{"type":"FeatureCollection","features":[
{"type":"Feature","properties":{
"boolean": true,
"otherboolean": false,
@ -11,78 +9,6 @@
"prêt": "ready"
},"geometry":{"type":"Polygon","coordinates":[[[-189.492187,64.774125],[-182.460937,67.339860],[-169.101562,68.269386],[-156.09375,68.138851],[-144.492187,66.089364],[-134.648437,62.431074],[-131.835937,55.379110],[-133.59375,48.690960],[-146.25,38.548165],[-169.453124,34.885930],[-184.218749,37.160316],[-198.28125,45.336701],[-203.203125,54.977613],[-196.523437,62.431074],[-189.492187,64.774125]],[[-177.890625,62.593340],[-185.976562,58.813741],[-188.4375,54.367758],[-185.976562,47.279229],[-177.539062,44.339565],[-164.882812,43.325177],[-153.28125,46.558860],[-144.492187,51.179342],[-143.789062,57.136239],[-148.007812,61.100788],[-158.554687,63.860035],[-169.453124,64.472793],[-177.890625,62.593340]]]}},
{
"type": "Feature",
"properties": {"where": "-180"},
"geometry": {
"type": "LineString",
"coordinates": [
[ -180, 20 ],
[ -180, 50 ]
]
}
},
{
"type": "Feature",
"properties": {"where": "180"},
"geometry": {
"type": "LineString",
"coordinates": [
[ 180, 10 ],
[ 180, 30 ]
]
}
},
{
"type": "Feature",
"properties": {"where": "-173, duplicated"},
"geometry": {
"type": "LineString",
"coordinates": [
[ -173, 10 ],
[ -173, 30 ]
]
}
},
{
"type": "Feature",
"properties": {"where": "-172, not duplicated"},
"geometry": {
"type": "LineString",
"coordinates": [
[ -172, 10 ],
[ -172, 30 ]
]
}
},
{
"type": "Feature",
"properties": {"where": "173, duplicated"},
"geometry": {
"type": "LineString",
"coordinates": [
[ 173, 10 ],
[ 173, 30 ]
]
}
},
{
"type": "Feature",
"properties": {"where": "172, not duplicated"},
"geometry": {
"type": "LineString",
"coordinates": [
[ 172, 10 ],
[ 172, 30 ]
]
}
},
{
"type": "Feature",
"tippecanoe": { "maxzoom": 2 },
@ -124,26 +50,6 @@
]
]
}
},
{
"type": "Feature",
"tippecanoe": { "minzoom": 1e1 },
"properties": { "zoom": "nothing, since 10 > 5"},
"geometry": {
"type": "LineString",
"coordinates": [ [ 0, 0 ], [ 1, 1 ] ]
}
},
{
"type": "Feature",
"tippecanoe": { "maxzoom": 1e1},
"properties": { "zoom": "0-5, since 10 > 5"},
"geometry": {
"type": "LineString",
"coordinates": [ [ 0, 0 ], [ 1, 1 ] ]
}
}
]}

View File

@ -1,10 +1,9 @@
{ "type": "FeatureCollection", "properties": {
"bounds": "-180.000000,0.000000,180.000000,68.269386",
"center": "-174.375000,16.560724,5",
"bounds": "-180.000000,34.885930,180.000000,68.269386",
"center": "-151.875000,64.059828,5",
"description": "tests/dateline/out/-z5.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/dateline/out/-z5.json.check.mbtiles -z5 tests/dateline/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 5, \"fields\": {\"\": \"String\", \"boolean\": \"Boolean\", \"escape\": \"String\", \"otherboolean\": \"Boolean\", \"prêt\": \"String\", \"stringify\": \"String\", \"where\": \"String\", \"zoom\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 11,\"geometry\": \"LineString\",\"attributeCount\": 8,\"attributes\": [{\"attribute\": \"\",\"count\": 1,\"type\": \"string\",\"values\": [\"something for nothing\"]},{\"attribute\": \"boolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [true]},{\"attribute\": \"escape\",\"count\": 1,\"type\": \"string\",\"values\": [\"foo\\u0001bar,ü\\\"\\\\/\\u0008\\u000c\\u000a\\u000d\\u0009→🐂🐳\"]},{\"attribute\": \"otherboolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [false]},{\"attribute\": \"prêt\",\"count\": 1,\"type\": \"string\",\"values\": [\"ready\"]},{\"attribute\": \"stringify\",\"count\": 1,\"type\": \"string\",\"values\": [\"[\\\"yes\\\",27,27,1.4e+27,{\\\"foo\\\":\\\"bar\\\"}]\"]},{\"attribute\": \"where\",\"count\": 6,\"type\": \"string\",\"values\": [\"-172, not duplicated\",\"-173, duplicated\",\"-180\",\"172, not duplicated\",\"173, duplicated\",\"180\"]},{\"attribute\": \"zoom\",\"count\": 4,\"type\": \"string\",\"values\": [\"0-5, since 10 > 5\",\"3-5\",\"nothing, since 10 > 5\",\"z0-2\"]}]}]}}",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 5, \"fields\": {\"\": \"String\", \"boolean\": \"Boolean\", \"escape\": \"String\", \"otherboolean\": \"Boolean\", \"prêt\": \"String\", \"stringify\": \"String\", \"zoom\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 3,\"geometry\": \"LineString\",\"attributeCount\": 7,\"attributes\": [{\"attribute\": \"\",\"count\": 1,\"type\": \"string\",\"values\": [\"something for nothing\"]},{\"attribute\": \"boolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [true]},{\"attribute\": \"escape\",\"count\": 1,\"type\": \"string\",\"values\": [\"foo\\u0001bar,ü\\\"\\\\/\\u0008\\u000c\\u000a\\u000d\\u0009→🐂🐳\"]},{\"attribute\": \"otherboolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [false]},{\"attribute\": \"prêt\",\"count\": 1,\"type\": \"string\",\"values\": [\"ready\"]},{\"attribute\": \"stringify\",\"count\": 1,\"type\": \"string\",\"values\": [\"[\\\"yes\\\",27,27,1.4e+27,{\\\"foo\\\":\\\"bar\\\"}]\"]},{\"attribute\": \"zoom\",\"count\": 2,\"type\": \"string\",\"values\": [\"3-5\",\"z0-2\"]}]}]}}",
"maxzoom": "5",
"minzoom": "0",
"name": "tests/dateline/out/-z5.json.check.mbtiles",
@ -13,83 +12,29 @@
}, "features": [
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -187.031250, 56.992883 ], [ -187.031250, 65.730626 ], [ -182.460938, 67.339861 ], [ -180.000000, 67.542167 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -184.218750, 37.160317 ], [ -187.031250, 38.891033 ], [ -187.031250, 50.457504 ], [ -185.976562, 47.279229 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.689872 ], [ -185.976562, 58.813742 ], [ -187.031250, 56.992883 ] ] ], [ [ [ 187.031250, 44.024422 ], [ 187.031250, 35.460670 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.542167 ], [ 187.031250, 68.007571 ], [ 187.031250, 63.704722 ], [ 182.109375, 62.593341 ], [ 180.000000, 61.689872 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 182.460938, 44.339565 ], [ 187.031250, 44.024422 ] ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -180.000000, 20.055931 ], [ -180.000000, 50.007739 ] ], [ [ 180.000000, 20.055931 ], [ 180.000000, 50.007739 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 180.000000, 10.055403 ], [ 180.000000, 30.069094 ] ], [ [ -180.000000, 10.055403 ], [ -180.000000, 30.069094 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -173.056641, 10.055403 ], [ -173.056641, 30.069094 ] ], [ [ 186.943359, 10.055403 ], [ 186.943359, 30.069094 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.055403 ], [ -172.001953, 30.069094 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -187.031250, 50.457504 ], [ -185.976562, 47.279229 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.689872 ], [ -185.976562, 58.813742 ], [ -187.031250, 56.992883 ], [ -187.031250, 65.730626 ], [ -182.460938, 67.339861 ], [ -180.000000, 67.542167 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -184.218750, 37.160317 ], [ -187.031250, 38.891033 ], [ -187.031250, 50.457504 ] ] ], [ [ [ 187.031250, 63.704722 ], [ 182.109375, 62.593341 ], [ 180.000000, 61.689872 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 182.460938, 44.339565 ], [ 187.031250, 44.024422 ], [ 187.031250, 35.460670 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.542167 ], [ 187.031250, 68.007571 ], [ 187.031250, 63.704722 ] ] ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.054628 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.914062, 10.055403 ], [ 171.914062, 30.069094 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 172.968750, 10.055403 ], [ 172.968750, 30.069094 ] ], [ [ -187.031250, 10.055403 ], [ -187.031250, 30.069094 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -183.515625, 60.020952 ], [ -183.515625, 66.981666 ], [ -182.460938, 67.339861 ], [ -180.000000, 67.525373 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -183.515625, 37.055177 ], [ -183.515625, 46.437857 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.669024 ], [ -183.515625, 60.020952 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.014645 ], [ -180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.012130 ], [ -180.000000, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.012695, 10.012130 ], [ -173.012695, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.012130 ], [ -172.001953, 30.031055 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -183.515625, 46.437857 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.669024 ], [ -183.515625, 60.020952 ], [ -183.515625, 66.981666 ], [ -182.460938, 67.339861 ], [ -180.000000, 67.525373 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -183.515625, 37.055177 ], [ -183.515625, 46.437857 ] ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 183.515625, 44.276671 ], [ 183.515625, 35.995785 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.525373 ], [ 183.515625, 67.776025 ], [ 183.515625, 62.915233 ], [ 182.109375, 62.593341 ], [ 180.000000, 61.669024 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 182.460938, 44.339565 ], [ 183.515625, 44.276671 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.014645 ], [ 180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.012130 ], [ 180.000000, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.010690 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.958008, 10.012130 ], [ 171.958008, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.968750, 10.012130 ], [ 172.968750, 30.031055 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 183.515625, 62.915233 ], [ 182.109375, 62.593341 ], [ 180.000000, 61.669024 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 182.460938, 44.339565 ], [ 183.515625, 44.276671 ], [ 183.515625, 35.995785 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.525373 ], [ 183.515625, 67.776025 ], [ 183.515625, 62.915233 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -181.757812, 60.844911 ], [ -181.757812, 67.204032 ], [ -150.688477, 67.204032 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -181.757812, 36.791691 ], [ -181.757812, 45.828799 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.658595 ], [ -181.757812, 60.844911 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.014645 ], [ -180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.012130 ], [ -180.000000, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.012695, 10.012130 ], [ -173.012695, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.012130 ], [ -172.001953, 30.012031 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -181.757812, 45.828799 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.658595 ], [ -181.757812, 60.844911 ], [ -181.757812, 67.204032 ], [ -150.688477, 67.204032 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -181.757812, 36.791691 ], [ -181.757812, 45.828799 ] ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
] }
@ -101,41 +46,9 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 1, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.988770, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 1, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.988770, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 2, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.988770, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 2, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.988770, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 3, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 181.757812, 44.590467 ], [ 181.757812, 36.261992 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 177.143555, 67.204032 ], [ 181.757812, 67.204032 ], [ 181.757812, 62.441242 ], [ 180.000000, 61.658595 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 181.757812, 44.590467 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.014645 ], [ 180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.012130 ], [ 180.000000, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.979980, 10.012130 ], [ 171.979980, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.990723, 10.012130 ], [ 172.990723, 30.012031 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 181.757812, 62.441242 ], [ 180.000000, 61.658595 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 181.757812, 44.590467 ], [ 181.757812, 36.261992 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 177.143555, 67.204032 ], [ 181.757812, 67.204032 ], [ 181.757812, 62.441242 ] ] ] } }
] }
] }
,
@ -148,22 +61,12 @@
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 0, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -142.613525, 41.640078 ], [ -143.404541, 40.979898 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.518466 ], [ -180.878906, 36.659606 ], [ -180.878906, 41.640078 ], [ -142.613525, 41.640078 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.004322 ], [ -180.000000, 40.979898 ], [ -180.000000, 41.640078 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 0, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.878906, 61.249102 ], [ -180.878906, 66.861082 ], [ -148.754883, 66.861082 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.573106 ], [ -134.648438, 62.431074 ], [ -134.121094, 61.217379 ], [ -134.121094, 48.305121 ], [ -135.000000, 47.650588 ], [ -144.195557, 40.313043 ], [ -180.878906, 40.313043 ], [ -180.878906, 45.521744 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.653379 ], [ -180.878906, 61.249102 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.313043 ], [ -180.000000, 40.979898 ], [ -180.000000, 50.000678 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.878906, 45.521744 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.653379 ], [ -180.878906, 61.249102 ], [ -180.878906, 66.861082 ], [ -148.754883, 66.861082 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.573106 ], [ -134.648438, 62.431074 ], [ -134.121094, 61.217379 ], [ -134.121094, 48.305121 ], [ -135.000000, 47.650588 ], [ -144.195557, 40.313043 ], [ -180.878906, 40.313043 ], [ -180.878906, 45.521744 ] ] ] } }
] }
] }
,
@ -179,36 +82,12 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 3, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.867920, 0.878872 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 3, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.878906, 0.889857 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 3, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ], [ 0.878906, 46.619261 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.867920, 0.878872 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -0.878906, 46.012224 ], [ 0.000000, 46.316584 ], [ 16.171875, 51.618017 ] ] } }
@ -218,22 +97,12 @@
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.878906, 41.640078 ], [ 180.878906, 36.385913 ], [ 180.000000, 36.518466 ], [ 175.781250, 37.160317 ], [ 169.420166, 40.979898 ], [ 168.288574, 41.640078 ], [ 180.878906, 41.640078 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.004322 ], [ 180.000000, 40.979898 ], [ 180.000000, 41.640078 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.990967, 10.001310 ], [ 171.990967, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.990723, 10.001310 ], [ 172.990723, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.878906, 44.902578 ], [ 180.878906, 40.313043 ], [ 170.562744, 40.313043 ], [ 169.420166, 40.979898 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 176.165771, 66.861082 ], [ 180.878906, 66.861082 ], [ 180.878906, 62.047288 ], [ 180.000000, 61.653379 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.878906, 44.902578 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.313043 ], [ 180.000000, 40.979898 ], [ 180.000000, 50.000678 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.878906, 62.047288 ], [ 180.000000, 61.653379 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.878906, 44.902578 ], [ 180.878906, 40.313043 ], [ 170.562744, 40.313043 ], [ 169.420166, 40.979898 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 176.165771, 66.861082 ], [ 180.878906, 66.861082 ], [ 180.878906, 62.047288 ] ] ] } }
] }
] }
,
@ -243,43 +112,21 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.004322 ], [ -180.000000, 21.943046 ], [ -180.000000, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 21.943046 ], [ -180.000000, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 21.943046 ], [ -173.001709, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 21.943046 ], [ -172.001953, 22.350076 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.060547, 41.310824 ], [ -157.060547, 36.866438 ], [ -157.500000, 36.796090 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.518466 ], [ -180.439453, 36.589068 ], [ -180.439453, 41.310824 ], [ -157.060547, 41.310824 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.534847 ], [ -180.000000, 21.943046 ], [ -180.000000, 40.979898 ], [ -180.000000, 41.310824 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.534847 ], [ -180.000000, 21.943046 ], [ -180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 21.534847 ], [ -173.001709, 21.943046 ], [ -173.001709, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 21.534847 ], [ -172.001953, 21.943046 ], [ -172.001953, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.060547, 45.525592 ], [ -157.060547, 40.647304 ], [ -180.439453, 40.647304 ], [ -180.439453, 45.367584 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -157.500000, 45.406164 ], [ -157.060547, 45.525592 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.647304 ], [ -180.000000, 40.979898 ], [ -180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.060547, 63.484863 ], [ -157.500000, 63.597448 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.439453, 61.451896 ], [ -180.439453, 66.687784 ], [ -157.060547, 66.687784 ], [ -157.060547, 63.484863 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.060547, 66.687784 ], [ -157.060547, 63.484863 ], [ -157.500000, 63.597448 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.439453, 61.451896 ], [ -180.439453, 66.687784 ], [ -157.060547, 66.687784 ] ] ] } }
] }
] }
,
@ -297,13 +144,13 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.939453, 45.282617 ], [ -157.500000, 45.406164 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.959351, 55.776573 ], [ -143.931885, 56.022948 ], [ -134.560547, 56.022948 ], [ -134.560547, 47.978891 ], [ -135.000000, 47.650588 ], [ -143.800049, 40.647304 ], [ -157.939453, 40.647304 ], [ -157.939453, 45.282617 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -134.560547, 56.022948 ], [ -134.560547, 47.978891 ], [ -135.000000, 47.650588 ], [ -143.800049, 40.647304 ], [ -157.939453, 40.647304 ], [ -157.939453, 45.282617 ], [ -157.500000, 45.406164 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.959351, 55.776573 ], [ -143.931885, 56.022948 ], [ -134.560547, 56.022948 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.939453, 63.707156 ], [ -157.939453, 66.687784 ], [ -147.782593, 66.687784 ], [ -146.815796, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.570575 ], [ -134.648438, 62.431074 ], [ -134.560547, 62.232115 ], [ -134.560547, 55.528631 ], [ -143.992310, 55.528631 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -157.500000, 63.597448 ], [ -157.939453, 63.707156 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -147.782593, 66.687784 ], [ -146.815796, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.570575 ], [ -134.648438, 62.431074 ], [ -134.560547, 62.232115 ], [ -134.560547, 55.528631 ], [ -143.992310, 55.528631 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -157.500000, 63.597448 ], [ -157.939453, 63.707156 ], [ -157.939453, 66.687784 ], [ -147.782593, 66.687784 ] ] ] } }
] }
] }
,
@ -325,36 +172,12 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 7, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.433960, 0.439449 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 7, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.439453, 0.444942 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 7, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ], [ 0.439453, 46.468133 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.433960, 0.439449 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.005197 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -0.439453, 46.164614 ], [ 0.000000, 46.316584 ], [ 16.171875, 51.618017 ] ] } }
@ -373,37 +196,15 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.004322 ], [ 180.000000, 21.943046 ], [ 180.000000, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 21.943046 ], [ 180.000000, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.996460, 10.001310 ], [ 171.996460, 21.943046 ], [ 171.996460, 22.350076 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.996216, 10.001310 ], [ 172.996216, 21.943046 ], [ 172.996216, 22.350076 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.439453, 41.310824 ], [ 180.439453, 36.452218 ], [ 180.000000, 36.518466 ], [ 175.781250, 37.160317 ], [ 169.425659, 40.979898 ], [ 168.859863, 41.310824 ], [ 180.439453, 41.310824 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.534847 ], [ 180.000000, 21.943046 ], [ 180.000000, 40.979898 ], [ 180.000000, 41.310824 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.534847 ], [ 180.000000, 21.943046 ], [ 180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.996460, 21.534847 ], [ 171.996460, 21.943046 ], [ 171.996460, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.996216, 21.534847 ], [ 172.996216, 21.943046 ], [ 172.996216, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.439453, 45.058001 ], [ 180.439453, 40.647304 ], [ 169.991455, 40.647304 ], [ 169.425659, 40.979898 ], [ 161.718750, 45.336702 ], [ 157.500000, 53.719466 ], [ 157.060547, 54.511516 ], [ 157.060547, 55.304138 ], [ 157.648315, 56.022948 ], [ 172.441406, 56.022948 ], [ 172.309570, 55.776573 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.439453, 45.058001 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.647304 ], [ 180.000000, 40.979898 ], [ 180.000000, 50.000678 ] ] } }
] }
] }
,
@ -419,71 +220,27 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 11.178402 ], [ -180.000000, 11.393879 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 11.178402 ], [ -173.001709, 11.393879 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 11.178402 ], [ -172.001953, 11.393879 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 14 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.001741 ], [ -180.000000, 21.943046 ], [ -180.000000, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.962764 ], [ -180.000000, 11.178402 ], [ -180.000000, 21.943046 ], [ -180.000000, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.962764 ], [ -173.001709, 11.178402 ], [ -173.001709, 21.943046 ], [ -173.001709, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.962764 ], [ -172.001953, 11.178402 ], [ -172.001953, 21.943046 ], [ -172.001953, 22.146708 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 13 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.739091 ], [ -180.000000, 21.943046 ], [ -180.000000, 31.952162 ], [ -180.000000, 32.138409 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.739091 ], [ -180.000000, 21.943046 ], [ -180.000000, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 21.739091 ], [ -173.001709, 21.943046 ], [ -173.001709, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 21.739091 ], [ -172.001953, 21.943046 ], [ -172.001953, 30.000138 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.530273, 41.145570 ], [ -168.530273, 35.036743 ], [ -168.750000, 35.000754 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.520673 ], [ -180.219727, 36.553775 ], [ -180.219727, 41.145570 ], [ -168.530273, 41.145570 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 31.765537 ], [ -180.000000, 31.952162 ], [ -180.000000, 40.979898 ], [ -180.000000, 41.145570 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.219727, 45.290347 ], [ -177.539062, 44.339565 ], [ -168.750000, 43.638063 ], [ -168.530273, 43.620171 ], [ -168.530273, 40.813809 ], [ -180.219727, 40.813809 ], [ -180.219727, 45.290347 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.813809 ], [ -180.000000, 40.979898 ], [ -180.000000, 48.922499 ], [ -180.000000, 49.066668 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 48.777913 ], [ -180.000000, 48.922499 ], [ -180.000000, 50.000678 ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.530273, 43.620171 ], [ -168.530273, 40.813809 ], [ -180.219727, 40.813809 ], [ -180.219727, 45.290347 ], [ -177.539062, 44.339565 ], [ -168.750000, 43.638063 ], [ -168.530273, 43.620171 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.219727, 61.551493 ], [ -180.219727, 61.710706 ], [ -179.868164, 61.710706 ], [ -180.219727, 61.551493 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -179.868164, 61.710706 ], [ -180.219727, 61.551493 ], [ -180.219727, 61.710706 ], [ -179.868164, 61.710706 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.530273, 64.421851 ], [ -168.750000, 64.433707 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.219727, 61.551493 ], [ -180.219727, 66.600676 ], [ -168.530273, 66.600676 ], [ -168.530273, 64.421851 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.530273, 66.600676 ], [ -168.530273, 64.421851 ], [ -168.750000, 64.433707 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.219727, 61.551493 ], [ -180.219727, 66.600676 ], [ -168.530273, 66.600676 ] ] ] } }
] }
] }
,
@ -507,7 +264,7 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 1, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.969727, 64.446742 ], [ -168.969727, 66.600676 ], [ -157.280273, 66.600676 ], [ -157.280273, 63.541211 ], [ -157.500000, 63.596226 ], [ -158.554688, 63.860036 ], [ -168.750000, 64.433707 ], [ -168.969727, 64.446742 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.280273, 66.600676 ], [ -157.280273, 63.541211 ], [ -157.500000, 63.596226 ], [ -158.554688, 63.860036 ], [ -168.750000, 64.433707 ], [ -168.969727, 64.446742 ], [ -168.969727, 66.600676 ], [ -157.280273, 66.600676 ] ] ] } }
] }
] }
,
@ -525,7 +282,7 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.719727, 45.344424 ], [ -157.500000, 45.406164 ], [ -153.281250, 46.558860 ], [ -148.612061, 49.066668 ], [ -146.030273, 49.066668 ], [ -146.030273, 40.813809 ], [ -157.719727, 40.813809 ], [ -157.719727, 45.344424 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.030273, 49.066668 ], [ -146.030273, 40.813809 ], [ -157.719727, 40.813809 ], [ -157.719727, 45.344424 ], [ -157.500000, 45.406164 ], [ -153.281250, 46.558860 ], [ -148.612061, 49.066668 ], [ -146.030273, 49.066668 ] ] ] } }
] }
] }
,
@ -543,7 +300,7 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.719727, 63.652355 ], [ -157.719727, 66.600676 ], [ -147.296448, 66.600676 ], [ -146.813049, 66.513260 ], [ -146.250000, 66.411253 ], [ -146.030273, 66.371654 ], [ -146.030273, 61.501734 ], [ -149.482727, 61.501734 ], [ -149.869995, 61.606396 ], [ -157.500000, 63.597448 ], [ -157.719727, 63.652355 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -147.296448, 66.600676 ], [ -146.813049, 66.513260 ], [ -146.250000, 66.411253 ], [ -146.030273, 66.371654 ], [ -146.030273, 61.501734 ], [ -149.482727, 61.501734 ], [ -149.869995, 61.606396 ], [ -157.500000, 63.597448 ], [ -157.719727, 63.652355 ], [ -157.719727, 66.600676 ], [ -147.296448, 66.600676 ] ] ] } }
] }
] }
,
@ -567,13 +324,13 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.469727, 50.176898 ], [ -144.492188, 51.179343 ], [ -143.962097, 55.776573 ], [ -143.945618, 55.899956 ], [ -134.780273, 55.899956 ], [ -134.780273, 48.777913 ], [ -146.469727, 48.777913 ], [ -146.469727, 50.176898 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -134.780273, 55.899956 ], [ -134.780273, 48.777913 ], [ -146.469727, 48.777913 ], [ -146.469727, 50.176898 ], [ -144.492188, 51.179343 ], [ -143.962097, 55.776573 ], [ -143.945618, 55.899956 ], [ -134.780273, 55.899956 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.469727, 59.709327 ], [ -146.469727, 61.710706 ], [ -134.780273, 61.710706 ], [ -134.780273, 55.652798 ], [ -143.975830, 55.652798 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -146.250000, 59.505061 ], [ -146.469727, 59.709327 ] ] ] } }
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -134.780273, 61.710706 ], [ -134.780273, 55.652798 ], [ -143.975830, 55.652798 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -146.250000, 59.505061 ], [ -146.469727, 59.709327 ], [ -146.469727, 61.710706 ], [ -134.780273, 61.710706 ] ] ] } }
] }
] }
,
@ -613,36 +370,12 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 15, "y": 16 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.216980, 0.219726 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 15, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.219727, 0.222473 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 15, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ], [ 0.219727, 46.392411 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 16 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.216980, 0.219726 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.002451 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -0.219727, 46.240652 ], [ 0.000000, 46.316584 ], [ 7.734375, 48.922499 ], [ 8.173828, 49.066668 ] ] } }
@ -697,61 +430,21 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 11.178402 ], [ 180.000000, 11.393879 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 10.001310 ], [ 171.999207, 11.178402 ], [ 171.999207, 11.393879 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 10.001310 ], [ 172.998962, 11.178402 ], [ 172.998962, 11.393879 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 14 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.001741 ], [ 180.000000, 21.943046 ], [ 180.000000, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.962764 ], [ 180.000000, 11.178402 ], [ 180.000000, 21.943046 ], [ 180.000000, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 10.962764 ], [ 171.999207, 11.178402 ], [ 171.999207, 21.943046 ], [ 171.999207, 22.146708 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 10.962764 ], [ 172.998962, 11.178402 ], [ 172.998962, 21.943046 ], [ 172.998962, 22.146708 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 13 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.739091 ], [ 180.000000, 21.943046 ], [ 180.000000, 31.952162 ], [ 180.000000, 32.138409 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.739091 ], [ 180.000000, 21.943046 ], [ 180.000000, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 21.739091 ], [ 171.999207, 21.943046 ], [ 171.999207, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 21.739091 ], [ 172.998962, 21.943046 ], [ 172.998962, 30.000138 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.219727, 41.145570 ], [ 180.219727, 36.487557 ], [ 180.000000, 36.520673 ], [ 175.781250, 37.160317 ], [ 169.425659, 40.979898 ], [ 169.142761, 41.145570 ], [ 180.219727, 41.145570 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 31.765537 ], [ 180.000000, 31.952162 ], [ 180.000000, 40.979898 ], [ 180.000000, 41.145570 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.219727, 45.135555 ], [ 180.219727, 40.813809 ], [ 169.708557, 40.813809 ], [ 169.425659, 40.979898 ], [ 168.750000, 41.376809 ], [ 168.530273, 41.504464 ], [ 168.530273, 49.066668 ], [ 173.435669, 49.066668 ], [ 173.485107, 48.922499 ], [ 174.023438, 47.279229 ], [ 180.219727, 45.135555 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.813809 ], [ 180.000000, 40.979898 ], [ 180.000000, 48.922499 ], [ 180.000000, 49.066668 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 172.375488, 55.899956 ], [ 172.309570, 55.776573 ], [ 171.562500, 54.367759 ], [ 173.485107, 48.922499 ], [ 173.531799, 48.777913 ], [ 168.530273, 48.777913 ], [ 168.530273, 55.899956 ], [ 172.375488, 55.899956 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 48.777913 ], [ 180.000000, 48.922499 ], [ 180.000000, 50.000678 ] ] } }
] }
] }
,

View File

@ -1,677 +0,0 @@
{ "type": "FeatureCollection", "properties": {
"bounds": "-180.000000,0.000000,180.000000,68.269386",
"center": "174.375000,44.951199,5",
"description": "tests/dateline/out/-z5_-b0.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/dateline/out/-z5_-b0.json.check.mbtiles -z5 -b0 tests/dateline/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 5, \"fields\": {\"\": \"String\", \"boolean\": \"Boolean\", \"escape\": \"String\", \"otherboolean\": \"Boolean\", \"prêt\": \"String\", \"stringify\": \"String\", \"where\": \"String\", \"zoom\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 11,\"geometry\": \"LineString\",\"attributeCount\": 8,\"attributes\": [{\"attribute\": \"\",\"count\": 1,\"type\": \"string\",\"values\": [\"something for nothing\"]},{\"attribute\": \"boolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [true]},{\"attribute\": \"escape\",\"count\": 1,\"type\": \"string\",\"values\": [\"foo\\u0001bar,ü\\\"\\\\/\\u0008\\u000c\\u000a\\u000d\\u0009→🐂🐳\"]},{\"attribute\": \"otherboolean\",\"count\": 1,\"type\": \"boolean\",\"values\": [false]},{\"attribute\": \"prêt\",\"count\": 1,\"type\": \"string\",\"values\": [\"ready\"]},{\"attribute\": \"stringify\",\"count\": 1,\"type\": \"string\",\"values\": [\"[\\\"yes\\\",27,27,1.4e+27,{\\\"foo\\\":\\\"bar\\\"}]\"]},{\"attribute\": \"where\",\"count\": 6,\"type\": \"string\",\"values\": [\"-172, not duplicated\",\"-173, duplicated\",\"-180\",\"172, not duplicated\",\"173, duplicated\",\"180\"]},{\"attribute\": \"zoom\",\"count\": 4,\"type\": \"string\",\"values\": [\"0-5, since 10 > 5\",\"3-5\",\"nothing, since 10 > 5\",\"z0-2\"]}]}]}}",
"maxzoom": "5",
"minzoom": "0",
"name": "tests/dateline/out/-z5_-b0.json.check.mbtiles",
"type": "overlay",
"version": "2"
}, "features": [
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -180.000000, 61.689872 ], [ -180.000000, 67.542167 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.689872 ] ] ], [ [ [ 180.000000, 45.213004 ], [ 180.000000, 36.527295 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.542167 ], [ 180.000000, 61.689872 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ -180.000000, 20.055931 ], [ -180.000000, 50.007739 ] ], [ [ 180.000000, 20.055931 ], [ 180.000000, 50.007739 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [ 180.000000, 10.055403 ], [ 180.000000, 30.069094 ] ], [ [ -180.000000, 10.055403 ], [ -180.000000, 30.069094 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.056641, 10.055403 ], [ -173.056641, 30.069094 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.055403 ], [ -172.001953, 30.069094 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.054628 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.914062, 10.055403 ], [ 171.914062, 30.069094 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.968750, 10.055403 ], [ 172.968750, 30.069094 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.000000, 61.669024 ], [ -180.000000, 67.525373 ], [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.669024 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.014645 ], [ -180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.012130 ], [ -180.000000, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.012695, 10.012130 ], [ -173.012695, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.012130 ], [ -172.001953, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 45.213004 ], [ 180.000000, 36.527295 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.525373 ], [ 180.000000, 61.669024 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.014645 ], [ 180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.012130 ], [ 180.000000, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.966797, 1.010690 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.958008, 10.012130 ], [ 171.958008, 30.031055 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.968750, 10.012130 ], [ 172.968750, 30.031055 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.000000, 61.658595 ], [ -180.000000, 66.513260 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.527295 ], [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.658595 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.014645 ], [ -180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.012130 ], [ -180.000000, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.012695, 10.012130 ], [ -173.012695, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.012130 ], [ -172.001953, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "zoom": "z0-2" }, "geometry": { "type": "LineString", "coordinates": [ [ -112.851562, 55.178868 ], [ -117.773438, 44.590467 ], [ -104.414062, 51.179343 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -146.821289, 66.513260 ], [ -180.000000, 66.513260 ], [ -180.000000, 67.516972 ], [ -169.101562, 68.269387 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 2, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.988770, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 3, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 45.213004 ], [ 180.000000, 36.527295 ], [ 175.781250, 37.160317 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 180.000000, 66.513260 ], [ 180.000000, 61.658595 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.014645 ], [ 180.000000, 50.007739 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.012130 ], [ 180.000000, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.979980, 10.012130 ], [ 171.979980, 30.012031 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.990723, 10.012130 ], [ 172.990723, 30.012031 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 3, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 67.516972 ], [ 180.000000, 66.513260 ], [ 175.187988, 66.513260 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.516972 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 0, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -143.404541, 40.979898 ], [ -146.250000, 38.548165 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.518466 ], [ -180.000000, 40.979898 ], [ -143.404541, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.004322 ], [ -180.000000, 40.979898 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 0, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.000000, 61.653379 ], [ -180.000000, 66.513260 ], [ -146.821289, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.573106 ], [ -135.000000, 47.650588 ], [ -143.404541, 40.979898 ], [ -180.000000, 40.979898 ], [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.653379 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.979898 ], [ -180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -169.101562, 68.269387 ], [ -156.093750, 68.138852 ], [ -146.821289, 66.513260 ], [ -180.000000, 66.513260 ], [ -180.000000, 67.516972 ], [ -169.101562, 68.269387 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 1, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -135.000000, 62.573106 ], [ -134.648438, 62.431074 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -135.000000, 47.650588 ], [ -135.000000, 62.573106 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 3, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.010690 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 46.316584 ], [ 16.171875, 51.618017 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 40.979898 ], [ 180.000000, 36.518466 ], [ 175.781250, 37.160317 ], [ 169.420166, 40.979898 ], [ 180.000000, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.004322 ], [ 180.000000, 40.979898 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.990967, 10.001310 ], [ 171.990967, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.990723, 10.001310 ], [ 172.990723, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 45.213004 ], [ 180.000000, 40.979898 ], [ 169.420166, 40.979898 ], [ 161.718750, 45.336702 ], [ 156.796875, 54.977614 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.187988, 66.513260 ], [ 180.000000, 66.513260 ], [ 180.000000, 61.653379 ], [ 174.023438, 58.813742 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.979898 ], [ 180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 67.516972 ], [ 180.000000, 66.513260 ], [ 175.187988, 66.513260 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.516972 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.004322 ], [ -180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 21.943046 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 40.979898 ], [ -157.500000, 36.796090 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.518466 ], [ -180.000000, 40.979898 ], [ -157.500000, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.943046 ], [ -180.000000, 40.979898 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.943046 ], [ -180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 21.943046 ], [ -173.001709, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 21.943046 ], [ -172.001953, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 45.406164 ], [ -157.500000, 40.979898 ], [ -180.000000, 40.979898 ], [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -164.882812, 43.325178 ], [ -157.500000, 45.406164 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.979898 ], [ -180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 63.597448 ], [ -158.554688, 63.860036 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.000000, 66.513260 ], [ -157.500000, 66.513260 ], [ -157.500000, 63.597448 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 0, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -169.101562, 68.269387 ], [ -157.500000, 68.153165 ], [ -157.500000, 66.513260 ], [ -180.000000, 66.513260 ], [ -180.000000, 67.514872 ], [ -169.101562, 68.269387 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -143.404541, 40.979898 ], [ -146.250000, 38.548165 ], [ -157.500000, 36.796090 ], [ -157.500000, 40.979898 ], [ -143.404541, 40.979898 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 45.406164 ], [ -153.281250, 46.558860 ], [ -144.492188, 51.179343 ], [ -143.959351, 55.776573 ], [ -135.000000, 55.776573 ], [ -135.000000, 47.650588 ], [ -143.404541, 40.979898 ], [ -157.500000, 40.979898 ], [ -157.500000, 45.406164 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 63.597448 ], [ -157.500000, 66.513260 ], [ -146.815796, 66.513260 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.570575 ], [ -135.000000, 55.776573 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -148.007812, 61.100789 ], [ -157.500000, 63.597448 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 1, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 68.153165 ], [ -156.093750, 68.138852 ], [ -146.815796, 66.513260 ], [ -157.500000, 66.513260 ], [ -157.500000, 68.153165 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 2, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -131.984253, 55.776573 ], [ -131.835938, 55.379110 ], [ -133.593750, 48.690960 ], [ -135.000000, 47.650588 ], [ -135.000000, 55.776573 ], [ -131.984253, 55.776573 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 2, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -135.000000, 62.570575 ], [ -134.648438, 62.431074 ], [ -131.984253, 55.776573 ], [ -135.000000, 55.776573 ], [ -135.000000, 62.570575 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 7, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.005197 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 46.316584 ], [ 16.171875, 51.618017 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 14, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 157.500000, 55.776573 ], [ 157.500000, 53.719466 ], [ 156.796875, 54.977614 ], [ 157.445068, 55.776573 ], [ 157.500000, 55.776573 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 14, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 157.500000, 55.841398 ], [ 157.500000, 55.776573 ], [ 157.445068, 55.776573 ], [ 157.500000, 55.841398 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.004322 ], [ 180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.996460, 10.001310 ], [ 171.996460, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.996216, 10.001310 ], [ 172.996216, 21.943046 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 40.979898 ], [ 180.000000, 36.518466 ], [ 175.781250, 37.160317 ], [ 169.425659, 40.979898 ], [ 180.000000, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.943046 ], [ 180.000000, 40.979898 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.943046 ], [ 180.000000, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.996460, 21.943046 ], [ 171.996460, 30.002517 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.996216, 21.943046 ], [ 172.996216, 30.002517 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 45.213004 ], [ 180.000000, 40.979898 ], [ 169.425659, 40.979898 ], [ 161.718750, 45.336702 ], [ 157.500000, 53.719466 ], [ 157.500000, 55.776573 ], [ 172.309570, 55.776573 ], [ 171.562500, 54.367759 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.979898 ], [ 180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 66.513260 ], [ 180.000000, 61.650771 ], [ 174.023438, 58.813742 ], [ 172.309570, 55.776573 ], [ 157.500000, 55.776573 ], [ 157.500000, 55.841398 ], [ 163.476562, 62.431074 ], [ 170.507812, 64.774125 ], [ 175.193481, 66.513260 ], [ 180.000000, 66.513260 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 15, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 67.514872 ], [ 180.000000, 66.513260 ], [ 175.193481, 66.513260 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.514872 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 10.001310 ], [ -180.000000, 11.178402 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 10.001310 ], [ -173.001709, 11.178402 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 10.001310 ], [ -172.001953, 11.178402 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 14 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 20.001741 ], [ -180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 11.178402 ], [ -180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 11.178402 ], [ -173.001709, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 11.178402 ], [ -172.001953, 21.943046 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 13 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.943046 ], [ -180.000000, 31.952162 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 21.943046 ], [ -180.000000, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -173.001709, 21.943046 ], [ -173.001709, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "-172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ -172.001953, 21.943046 ], [ -172.001953, 30.000138 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.750000, 40.979898 ], [ -168.750000, 35.000754 ], [ -169.453125, 34.885931 ], [ -180.000000, 36.518466 ], [ -180.000000, 40.979898 ], [ -168.750000, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 31.952162 ], [ -180.000000, 40.979898 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -180.000000, 45.213004 ], [ -177.539062, 44.339565 ], [ -168.750000, 43.638063 ], [ -168.750000, 40.979898 ], [ -180.000000, 40.979898 ], [ -180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 40.979898 ], [ -180.000000, 48.922499 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ -180.000000, 48.922499 ], [ -180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.750000, 64.433707 ], [ -169.453125, 64.472794 ], [ -177.890625, 62.593341 ], [ -180.000000, 61.650771 ], [ -180.000000, 66.513260 ], [ -168.750000, 66.513260 ], [ -168.750000, 64.433707 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 0, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -169.101562, 68.269387 ], [ -168.750000, 68.266336 ], [ -168.750000, 66.513260 ], [ -180.000000, 66.513260 ], [ -180.000000, 67.514872 ], [ -169.101562, 68.269387 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 1, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 40.979898 ], [ -157.500000, 36.796090 ], [ -168.750000, 35.000754 ], [ -168.750000, 40.979898 ], [ -157.500000, 40.979898 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 1, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 45.404235 ], [ -157.500000, 40.979898 ], [ -168.750000, 40.979898 ], [ -168.750000, 43.638063 ], [ -164.882812, 43.325178 ], [ -157.500000, 45.404235 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 1, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.750000, 64.433707 ], [ -168.750000, 66.513260 ], [ -157.500000, 66.513260 ], [ -157.500000, 63.596226 ], [ -158.554688, 63.860036 ], [ -168.750000, 64.433707 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 1, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -168.750000, 68.266336 ], [ -157.500000, 68.153165 ], [ -157.500000, 66.513260 ], [ -168.750000, 66.513260 ], [ -168.750000, 68.266336 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 40.979898 ], [ -146.250000, 38.548165 ], [ -157.500000, 36.796090 ], [ -157.500000, 40.979898 ], [ -146.250000, 40.979898 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 45.404235 ], [ -153.281250, 46.558860 ], [ -148.886719, 48.922499 ], [ -146.250000, 48.922499 ], [ -146.250000, 40.979898 ], [ -157.500000, 40.979898 ], [ -157.500000, 45.404235 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 50.289339 ], [ -146.250000, 48.922499 ], [ -148.886719, 48.922499 ], [ -146.250000, 50.289339 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 59.505061 ], [ -148.007812, 61.100789 ], [ -149.869995, 61.606396 ], [ -146.250000, 61.606396 ], [ -146.250000, 59.505061 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 63.596226 ], [ -157.500000, 66.513260 ], [ -146.813049, 66.513260 ], [ -146.250000, 66.411253 ], [ -146.250000, 61.606396 ], [ -149.869995, 61.606396 ], [ -157.500000, 63.596226 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 2, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -157.500000, 68.153165 ], [ -156.093750, 68.138852 ], [ -146.813049, 66.513260 ], [ -157.500000, 66.513260 ], [ -157.500000, 68.153165 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -143.404541, 40.979898 ], [ -146.250000, 38.548165 ], [ -146.250000, 40.979898 ], [ -143.404541, 40.979898 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -135.000000, 48.922499 ], [ -135.000000, 47.650588 ], [ -143.404541, 40.979898 ], [ -146.250000, 40.979898 ], [ -146.250000, 48.922499 ], [ -135.000000, 48.922499 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 50.289339 ], [ -144.492188, 51.179343 ], [ -143.959351, 55.776573 ], [ -135.000000, 55.776573 ], [ -135.000000, 48.922499 ], [ -146.250000, 48.922499 ], [ -146.250000, 50.289339 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 59.505061 ], [ -146.250000, 61.606396 ], [ -135.000000, 61.606396 ], [ -135.000000, 55.776573 ], [ -143.959351, 55.776573 ], [ -143.789062, 57.136239 ], [ -146.250000, 59.505061 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 3, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -146.250000, 66.411253 ], [ -144.492188, 66.089364 ], [ -135.000000, 62.570575 ], [ -135.000000, 61.606396 ], [ -146.250000, 61.606396 ], [ -146.250000, 66.411253 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 4, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -133.538818, 48.922499 ], [ -133.593750, 48.690960 ], [ -135.000000, 47.650588 ], [ -135.000000, 48.922499 ], [ -133.538818, 48.922499 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 4, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -131.981506, 55.776573 ], [ -131.835938, 55.379110 ], [ -133.538818, 48.922499 ], [ -135.000000, 48.922499 ], [ -135.000000, 55.776573 ], [ -131.981506, 55.776573 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 4, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -134.288635, 61.606396 ], [ -131.981506, 55.776573 ], [ -135.000000, 55.776573 ], [ -135.000000, 61.606396 ], [ -134.288635, 61.606396 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 4, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -135.000000, 62.570575 ], [ -134.648438, 62.431074 ], [ -134.288635, 61.606396 ], [ -135.000000, 61.606396 ], [ -135.000000, 62.570575 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 15, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ -2.109375, 45.583290 ], [ 0.000000, 46.316584 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "0-5, since 10 > 5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 0.000000 ], [ 0.999756, 1.002451 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ 0.000000, 46.316584 ], [ 7.734375, 48.922499 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 16, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ 7.734375, 48.922499 ], [ 11.250000, 50.064192 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 17, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "zoom": "3-5" }, "geometry": { "type": "LineString", "coordinates": [ [ 11.250000, 50.064192 ], [ 16.171875, 51.618017 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 29, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 157.500000, 55.776573 ], [ 157.500000, 53.719466 ], [ 156.796875, 54.977614 ], [ 157.447815, 55.776573 ], [ 157.500000, 55.776573 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 29, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 157.500000, 55.839856 ], [ 157.500000, 55.776573 ], [ 157.447815, 55.776573 ], [ 157.500000, 55.839856 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 30, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 168.750000, 48.922499 ], [ 168.750000, 41.376809 ], [ 161.718750, 45.336702 ], [ 159.999390, 48.922499 ], [ 168.750000, 48.922499 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 30, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 168.750000, 55.776573 ], [ 168.750000, 48.922499 ], [ 159.999390, 48.922499 ], [ 157.500000, 53.719466 ], [ 157.500000, 55.776573 ], [ 168.750000, 55.776573 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 30, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 168.750000, 61.606396 ], [ 168.750000, 55.776573 ], [ 157.500000, 55.776573 ], [ 157.500000, 55.839856 ], [ 162.660828, 61.606396 ], [ 168.750000, 61.606396 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 30, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 168.750000, 64.206377 ], [ 168.750000, 61.606396 ], [ 162.660828, 61.606396 ], [ 163.476562, 62.431074 ], [ 168.750000, 64.206377 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 15 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 10.001310 ], [ 180.000000, 11.178402 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 10.001310 ], [ 171.999207, 11.178402 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 10.001310 ], [ 172.998962, 11.178402 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 14 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 20.001741 ], [ 180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 11.178402 ], [ 180.000000, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 11.178402 ], [ 171.999207, 21.943046 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 11.178402 ], [ 172.998962, 21.943046 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 13 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.943046 ], [ 180.000000, 31.952162 ] ] } }
,
{ "type": "Feature", "properties": { "where": "180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 21.943046 ], [ 180.000000, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "172, not duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 171.999207, 21.943046 ], [ 171.999207, 30.000138 ] ] } }
,
{ "type": "Feature", "properties": { "where": "173, duplicated" }, "geometry": { "type": "LineString", "coordinates": [ [ 172.998962, 21.943046 ], [ 172.998962, 30.000138 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 12 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 40.979898 ], [ 180.000000, 36.518466 ], [ 175.781250, 37.160317 ], [ 169.428406, 40.979898 ], [ 180.000000, 40.979898 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 31.952162 ], [ 180.000000, 40.979898 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 11 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 45.213004 ], [ 180.000000, 40.979898 ], [ 169.428406, 40.979898 ], [ 168.750000, 41.376809 ], [ 168.750000, 48.922499 ], [ 173.485107, 48.922499 ], [ 174.023438, 47.279229 ], [ 180.000000, 45.213004 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 40.979898 ], [ 180.000000, 48.922499 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 10 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 172.309570, 55.776573 ], [ 171.562500, 54.367759 ], [ 173.485107, 48.922499 ], [ 168.750000, 48.922499 ], [ 168.750000, 55.776573 ], [ 172.309570, 55.776573 ] ] ] } }
,
{ "type": "Feature", "properties": { "where": "-180" }, "geometry": { "type": "LineString", "coordinates": [ [ 180.000000, 48.922499 ], [ 180.000000, 50.000678 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 179.901123, 61.606396 ], [ 174.023438, 58.813742 ], [ 172.309570, 55.776573 ], [ 168.750000, 55.776573 ], [ 168.750000, 61.606396 ], [ 179.901123, 61.606396 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 66.513260 ], [ 180.000000, 61.650771 ], [ 179.901123, 61.606396 ], [ 168.750000, 61.606396 ], [ 168.750000, 64.206377 ], [ 170.507812, 64.774125 ], [ 175.193481, 66.513260 ], [ 180.000000, 66.513260 ] ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 5, "x": 31, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "boolean": true, "otherboolean": false, "stringify": "[\"yes\",27,27,1.4e+27,{\"foo\":\"bar\"}]", "": "something for nothing", "escape": "foo\u0001bar,ü\"\\/\u0008\u000c\u000a\u000d\u0009→🐂🐳", "prêt": "ready" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 180.000000, 67.514872 ], [ 180.000000, 66.513260 ], [ 175.193481, 66.513260 ], [ 177.539062, 67.339861 ], [ 180.000000, 67.514872 ] ] ] } }
] }
] }
] }

View File

@ -3,7 +3,6 @@
"center": "-122.249782,37.796763,14",
"description": "tests/empty-linestring/out/-ac.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/empty-linestring/out/-ac.json.check.mbtiles -ac tests/empty-linestring/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 14, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 5,\"geometry\": \"LineString\",\"attributeCount\": 0,\"attributes\": []}]}}",
"maxzoom": "14",
"minzoom": "0",

View File

@ -3,7 +3,6 @@
"center": "16.875000,44.951199,5",
"description": "tests/epsg-3857/out/-yNAME_-z5_-sEPSG@3857.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/epsg-3857/out/-yNAME_-z5_-sEPSG@3857.json.check.mbtiles -yNAME -z5 -sEPSG:3857 tests/epsg-3857/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 5, \"fields\": {\"NAME\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 243,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"NAME\",\"count\": 243,\"type\": \"string\",\"values\": [\"Abidjan\",\"Abu Dhabi\",\"Abuja\",\"Accra\",\"Addis Ababa\",\"Algiers\",\"Amman\",\"Amsterdam\",\"Andorra\",\"Ankara\",\"Antananarivo\",\"Apia\",\"Ashgabat\",\"Asmara\",\"Astana\",\"Asuncion\",\"Athens\",\"Atlanta\",\"Auckland\",\"Baghdad\",\"Baguio City\",\"Baku\",\"Bamako\",\"Bandar Seri Begawan\",\"Bangalore\",\"Bangkok\",\"Bangui\",\"Banjul\",\"Basseterre\",\"Beijing\",\"Beirut\",\"Belgrade\",\"Belmopan\",\"Berlin\",\"Bern\",\"Bir Lehlou\",\"Bishkek\",\"Bissau\",\"Bloemfontein\",\"Bogota\",\"Brasilia\",\"Bratislava\",\"Brazzaville\",\"Bridgetown\",\"Brussels\",\"Bucharest\",\"Budapest\",\"Buenos Aires\",\"Bujumbura\",\"Cairo\",\"Canberra\",\"Cape Town\",\"Caracas\",\"Casablanca\",\"Castries\",\"Chengdu\",\"Chicago\",\"Chisinau\",\"Colombo\",\"Conakry\",\"Cotonou\",\"Dakar\",\"Damascus\",\"Dar es Salaam\",\"Denver\",\"Dhaka\",\"Dili\",\"Djibouti\",\"Dodoma\",\"Doha\",\"Dubai\",\"Dublin\",\"Dushanbe\",\"Freetown\",\"Funafuti\",\"Gaborone\",\"Geneva\",\"Georgetown\",\"Guatemala\",\"Hanoi\",\"Harare\",\"Hargeysa\",\"Havana\",\"Helsinki\",\"Hong Kong\",\"Honiara\",\"Houston\",\"Islamabad\",\"Istanbul\",\"Jakarta\",\"Jerusalem\",\"Johannesburg\",\"Juba\",\"Kabul\",\"Kampala\",\"Kathmandu\",\"Khartoum\",\"Kiev\",\"Kigali\",\"Kingston\"]}]}]}}",
"maxzoom": "5",
"minzoom": "0",
@ -15,9 +14,9 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Vancouver" }, "geometry": { "type": "Point", "coordinates": [ -123.134766, 49.325122 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Malabo" }, "geometry": { "type": "Point", "coordinates": [ 8.701172, 3.776559 ] } }
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.460938, 6.402648 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kinshasa" }, "geometry": { "type": "Point", "coordinates": [ 15.292969, -4.302591 ] } }
{ "type": "Feature", "properties": { "NAME": "Bandar Seri Begawan" }, "geometry": { "type": "Point", "coordinates": [ 114.873047, 4.915833 ] } }
] }
] }
,
@ -31,29 +30,27 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Vancouver" }, "geometry": { "type": "Point", "coordinates": [ -123.134766, 49.296472 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Conakry" }, "geometry": { "type": "Point", "coordinates": [ -13.710938, 9.535749 ] } }
{ "type": "Feature", "properties": { "NAME": "Praia" }, "geometry": { "type": "Point", "coordinates": [ -23.554688, 14.944785 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.504883, 6.402648 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Sao Tome" }, "geometry": { "type": "Point", "coordinates": [ 6.723633, 0.351560 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kinshasa" }, "geometry": { "type": "Point", "coordinates": [ 15.292969, -4.302591 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Honiara" }, "geometry": { "type": "Point", "coordinates": [ 159.916992, -9.405710 ] } }
{ "type": "Feature", "properties": { "NAME": "Brazzaville" }, "geometry": { "type": "Point", "coordinates": [ 15.249023, -4.214943 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 1, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "London" }, "geometry": { "type": "Point", "coordinates": [ -0.131836, 51.508742 ] } }
{ "type": "Feature", "properties": { "NAME": "Oslo" }, "geometry": { "type": "Point", "coordinates": [ 10.722656, 59.933000 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Geneva" }, "geometry": { "type": "Point", "coordinates": [ 6.108398, 46.225453 ] } }
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.504883, 6.402648 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Malabo" }, "geometry": { "type": "Point", "coordinates": [ 8.745117, 3.776559 ] } }
{ "type": "Feature", "properties": { "NAME": "Baku" }, "geometry": { "type": "Point", "coordinates": [ 49.833984, 40.413496 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuwait" }, "geometry": { "type": "Point", "coordinates": [ 47.944336, 29.382175 ] } }
{ "type": "Feature", "properties": { "NAME": "Bandar Seri Begawan" }, "geometry": { "type": "Point", "coordinates": [ 114.916992, 4.915833 ] } }
] }
] }
,
@ -66,8 +63,6 @@
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 0, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Vancouver" }, "geometry": { "type": "Point", "coordinates": [ -123.134766, 49.282140 ] } }
,
{ "type": "Feature", "properties": { "NAME": "San Salvador" }, "geometry": { "type": "Point", "coordinates": [ -89.208984, 13.731381 ] } }
] }
] }
,
@ -79,13 +74,13 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 1, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Guatemala" }, "geometry": { "type": "Point", "coordinates": [ -90.549316, 14.626109 ] } }
{ "type": "Feature", "properties": { "NAME": "Chicago" }, "geometry": { "type": "Point", "coordinates": [ -87.758789, 41.836828 ] } }
,
{ "type": "Feature", "properties": { "NAME": "San Salvador" }, "geometry": { "type": "Point", "coordinates": [ -89.208984, 13.731381 ] } }
{ "type": "Feature", "properties": { "NAME": "Port-au-Prince" }, "geometry": { "type": "Point", "coordinates": [ -72.355957, 18.562947 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Saint George's" }, "geometry": { "type": "Point", "coordinates": [ -61.743164, 12.060809 ] } }
{ "type": "Feature", "properties": { "NAME": "Praia" }, "geometry": { "type": "Point", "coordinates": [ -23.532715, 14.923554 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Conakry" }, "geometry": { "type": "Point", "coordinates": [ -13.688965, 9.535749 ] } }
{ "type": "Feature", "properties": { "NAME": "Ouagadougou" }, "geometry": { "type": "Point", "coordinates": [ -1.538086, 12.382928 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Quito" }, "geometry": { "type": "Point", "coordinates": [ -78.508301, -0.197754 ] } }
] }
@ -93,47 +88,43 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 2, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Sao Tome" }, "geometry": { "type": "Point", "coordinates": [ 6.723633, 0.351560 ] } }
{ "type": "Feature", "properties": { "NAME": "Brazzaville" }, "geometry": { "type": "Point", "coordinates": [ 15.270996, -4.236856 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kinshasa" }, "geometry": { "type": "Point", "coordinates": [ 15.292969, -4.324501 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Moroni" }, "geometry": { "type": "Point", "coordinates": [ 43.220215, -11.695273 ] } }
{ "type": "Feature", "properties": { "NAME": "Pretoria" }, "geometry": { "type": "Point", "coordinates": [ 28.212891, -25.700938 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 2, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "London" }, "geometry": { "type": "Point", "coordinates": [ -0.131836, 51.508742 ] } }
{ "type": "Feature", "properties": { "NAME": "Ouagadougou" }, "geometry": { "type": "Point", "coordinates": [ -1.538086, 12.382928 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Geneva" }, "geometry": { "type": "Point", "coordinates": [ 6.130371, 46.210250 ] } }
{ "type": "Feature", "properties": { "NAME": "Oslo" }, "geometry": { "type": "Point", "coordinates": [ 10.744629, 59.921990 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vatican City" }, "geometry": { "type": "Point", "coordinates": [ 12.436523, 41.918629 ] } }
{ "type": "Feature", "properties": { "NAME": "San Marino" }, "geometry": { "type": "Point", "coordinates": [ 12.436523, 43.945372 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Chisinau" }, "geometry": { "type": "Point", "coordinates": [ 28.850098, 47.010226 ] } }
{ "type": "Feature", "properties": { "NAME": "Riga" }, "geometry": { "type": "Point", "coordinates": [ 24.082031, 56.956957 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Malabo" }, "geometry": { "type": "Point", "coordinates": [ 8.767090, 3.754634 ] } }
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.504883, 6.402648 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Juba" }, "geometry": { "type": "Point", "coordinates": [ 31.574707, 4.850154 ] } }
{ "type": "Feature", "properties": { "NAME": "Jerusalem" }, "geometry": { "type": "Point", "coordinates": [ 35.200195, 31.784217 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuwait" }, "geometry": { "type": "Point", "coordinates": [ 47.966309, 29.382175 ] } }
{ "type": "Feature", "properties": { "NAME": "Baku" }, "geometry": { "type": "Point", "coordinates": [ 49.855957, 40.413496 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Sri Jawewardenepura Kotte" }, "geometry": { "type": "Point", "coordinates": [ 79.936523, 6.904614 ] } }
{ "type": "Feature", "properties": { "NAME": "Islamabad" }, "geometry": { "type": "Point", "coordinates": [ 73.146973, 33.706063 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 3, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Singapore" }, "geometry": { "type": "Point", "coordinates": [ 103.842773, 1.296276 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Honiara" }, "geometry": { "type": "Point", "coordinates": [ 159.938965, -9.427387 ] } }
{ "type": "Feature", "properties": { "NAME": "Jakarta" }, "geometry": { "type": "Point", "coordinates": [ 106.809082, -6.162401 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 2, "x": 3, "y": 1 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Thimphu" }, "geometry": { "type": "Point", "coordinates": [ 89.626465, 27.488781 ] } }
{ "type": "Feature", "properties": { "NAME": "Ulaanbaatar" }, "geometry": { "type": "Point", "coordinates": [ 106.896973, 47.931066 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuala Lumpur" }, "geometry": { "type": "Point", "coordinates": [ 101.689453, 3.184394 ] } }
{ "type": "Feature", "properties": { "NAME": "Bandar Seri Begawan" }, "geometry": { "type": "Point", "coordinates": [ 114.916992, 4.893941 ] } }
] }
] }
,
@ -146,10 +137,6 @@
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 1, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "San Francisco" }, "geometry": { "type": "Point", "coordinates": [ -122.420654, 37.770715 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Guatemala" }, "geometry": { "type": "Point", "coordinates": [ -90.538330, 14.626109 ] } }
,
{ "type": "Feature", "properties": { "NAME": "San Salvador" }, "geometry": { "type": "Point", "coordinates": [ -89.208984, 13.720708 ] } }
] }
] }
,
@ -169,17 +156,15 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 2, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Guatemala" }, "geometry": { "type": "Point", "coordinates": [ -90.538330, 14.626109 ] } }
{ "type": "Feature", "properties": { "NAME": "Atlanta" }, "geometry": { "type": "Point", "coordinates": [ -84.407959, 33.833920 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Havana" }, "geometry": { "type": "Point", "coordinates": [ -82.375488, 23.140360 ] } }
{ "type": "Feature", "properties": { "NAME": "Belmopan" }, "geometry": { "type": "Point", "coordinates": [ -88.769531, 17.256236 ] } }
,
{ "type": "Feature", "properties": { "NAME": "San Salvador" }, "geometry": { "type": "Point", "coordinates": [ -89.208984, 13.720708 ] } }
{ "type": "Feature", "properties": { "NAME": "Port-au-Prince" }, "geometry": { "type": "Point", "coordinates": [ -72.344971, 18.552532 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Basseterre" }, "geometry": { "type": "Point", "coordinates": [ -62.720947, 17.308688 ] } }
{ "type": "Feature", "properties": { "NAME": "Roseau" }, "geometry": { "type": "Point", "coordinates": [ -61.391602, 15.305380 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Saint George's" }, "geometry": { "type": "Point", "coordinates": [ -61.743164, 12.060809 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Paramaribo" }, "geometry": { "type": "Point", "coordinates": [ -55.173340, 5.845545 ] } }
{ "type": "Feature", "properties": { "NAME": "Georgetown" }, "geometry": { "type": "Point", "coordinates": [ -58.172607, 6.806444 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Quito" }, "geometry": { "type": "Point", "coordinates": [ -78.508301, -0.208740 ] } }
] }
@ -201,11 +186,9 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Praia" }, "geometry": { "type": "Point", "coordinates": [ -23.521729, 14.923554 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Casablanca" }, "geometry": { "type": "Point", "coordinates": [ -7.624512, 33.605470 ] } }
{ "type": "Feature", "properties": { "NAME": "Dakar" }, "geometry": { "type": "Point", "coordinates": [ -17.479248, 14.721761 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Conakry" }, "geometry": { "type": "Point", "coordinates": [ -13.688965, 9.535749 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Yamoussoukro" }, "geometry": { "type": "Point", "coordinates": [ -5.284424, 6.828261 ] } }
{ "type": "Feature", "properties": { "NAME": "Ouagadougou" }, "geometry": { "type": "Point", "coordinates": [ -1.527100, 12.382928 ] } }
] }
] }
,
@ -217,51 +200,47 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Sao Tome" }, "geometry": { "type": "Point", "coordinates": [ 6.723633, 0.340574 ] } }
{ "type": "Feature", "properties": { "NAME": "Brazzaville" }, "geometry": { "type": "Point", "coordinates": [ 15.281982, -4.247812 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kinshasa" }, "geometry": { "type": "Point", "coordinates": [ 15.303955, -4.324501 ] } }
{ "type": "Feature", "properties": { "NAME": "Lusaka" }, "geometry": { "type": "Point", "coordinates": [ 28.278809, -15.411319 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bujumbura" }, "geometry": { "type": "Point", "coordinates": [ 29.355469, -3.370856 ] } }
{ "type": "Feature", "properties": { "NAME": "Lilongwe" }, "geometry": { "type": "Point", "coordinates": [ 33.782959, -13.976715 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Moroni" }, "geometry": { "type": "Point", "coordinates": [ 43.231201, -11.695273 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Maputo" }, "geometry": { "type": "Point", "coordinates": [ 32.585449, -25.948166 ] } }
{ "type": "Feature", "properties": { "NAME": "Pretoria" }, "geometry": { "type": "Point", "coordinates": [ 28.223877, -25.700938 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Accra" }, "geometry": { "type": "Point", "coordinates": [ -0.219727, 5.561315 ] } }
{ "type": "Feature", "properties": { "NAME": "Algiers" }, "geometry": { "type": "Point", "coordinates": [ 3.043213, 36.765292 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Valletta" }, "geometry": { "type": "Point", "coordinates": [ 14.512939, 35.906849 ] } }
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.515869, 6.402648 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Malabo" }, "geometry": { "type": "Point", "coordinates": [ 8.778076, 3.754634 ] } }
{ "type": "Feature", "properties": { "NAME": "Ndjamena" }, "geometry": { "type": "Point", "coordinates": [ 15.040283, 12.125264 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Athens" }, "geometry": { "type": "Point", "coordinates": [ 23.730469, 37.987504 ] } }
{ "type": "Feature", "properties": { "NAME": "Nicosia" }, "geometry": { "type": "Point", "coordinates": [ 33.365479, 35.173808 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Beirut" }, "geometry": { "type": "Point", "coordinates": [ 35.496826, 33.879537 ] } }
{ "type": "Feature", "properties": { "NAME": "Jerusalem" }, "geometry": { "type": "Point", "coordinates": [ 35.200195, 31.784217 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Juba" }, "geometry": { "type": "Point", "coordinates": [ 31.574707, 4.839207 ] } }
{ "type": "Feature", "properties": { "NAME": "Sanaa" }, "geometry": { "type": "Point", "coordinates": [ 44.197998, 15.358356 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 4, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "London" }, "geometry": { "type": "Point", "coordinates": [ -0.120850, 51.508742 ] } }
{ "type": "Feature", "properties": { "NAME": "Oslo" }, "geometry": { "type": "Point", "coordinates": [ 10.744629, 59.921990 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Amsterdam" }, "geometry": { "type": "Point", "coordinates": [ 4.910889, 52.355474 ] } }
{ "type": "Feature", "properties": { "NAME": "Paris" }, "geometry": { "type": "Point", "coordinates": [ 2.329102, 48.871941 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Geneva" }, "geometry": { "type": "Point", "coordinates": [ 6.130371, 46.210250 ] } }
{ "type": "Feature", "properties": { "NAME": "Prague" }, "geometry": { "type": "Point", "coordinates": [ 14.458008, 50.085344 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Berlin" }, "geometry": { "type": "Point", "coordinates": [ 13.392334, 52.529590 ] } }
{ "type": "Feature", "properties": { "NAME": "San Marino" }, "geometry": { "type": "Point", "coordinates": [ 12.436523, 43.937462 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vatican City" }, "geometry": { "type": "Point", "coordinates": [ 12.447510, 41.910453 ] } }
{ "type": "Feature", "properties": { "NAME": "Belgrade" }, "geometry": { "type": "Point", "coordinates": [ 20.456543, 44.824708 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Pristina" }, "geometry": { "type": "Point", "coordinates": [ 21.159668, 42.674359 ] } }
{ "type": "Feature", "properties": { "NAME": "Riga" }, "geometry": { "type": "Point", "coordinates": [ 24.093018, 56.950966 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vilnius" }, "geometry": { "type": "Point", "coordinates": [ 25.312500, 54.686534 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Chisinau" }, "geometry": { "type": "Point", "coordinates": [ 28.850098, 47.010226 ] } }
{ "type": "Feature", "properties": { "NAME": "Bucharest" }, "geometry": { "type": "Point", "coordinates": [ 26.092529, 44.441624 ] } }
] }
] }
,
@ -273,45 +252,45 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 5, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Yerevan" }, "geometry": { "type": "Point", "coordinates": [ 44.505615, 40.187267 ] } }
{ "type": "Feature", "properties": { "NAME": "Sanaa" }, "geometry": { "type": "Point", "coordinates": [ 44.197998, 15.358356 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Tashkent" }, "geometry": { "type": "Point", "coordinates": [ 69.290771, 41.319076 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuwait" }, "geometry": { "type": "Point", "coordinates": [ 47.966309, 29.372602 ] } }
{ "type": "Feature", "properties": { "NAME": "Baku" }, "geometry": { "type": "Point", "coordinates": [ 49.855957, 40.405131 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Abu Dhabi" }, "geometry": { "type": "Point", "coordinates": [ 54.360352, 24.467151 ] } }
,
{ "type": "Feature", "properties": { "NAME": "New Delhi" }, "geometry": { "type": "Point", "coordinates": [ 77.189941, 28.603814 ] } }
{ "type": "Feature", "properties": { "NAME": "Islamabad" }, "geometry": { "type": "Point", "coordinates": [ 73.157959, 33.706063 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Sri Jawewardenepura Kotte" }, "geometry": { "type": "Point", "coordinates": [ 79.947510, 6.904614 ] } }
{ "type": "Feature", "properties": { "NAME": "Mumbai" }, "geometry": { "type": "Point", "coordinates": [ 72.850342, 19.020577 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Dhaka" }, "geometry": { "type": "Point", "coordinates": [ 90.406494, 23.725012 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 5, "y": 2 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Tbilisi" }, "geometry": { "type": "Point", "coordinates": [ 44.780273, 41.730330 ] } }
{ "type": "Feature", "properties": { "NAME": "Astana" }, "geometry": { "type": "Point", "coordinates": [ 71.422119, 51.186230 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Tashkent" }, "geometry": { "type": "Point", "coordinates": [ 69.290771, 41.319076 ] } }
{ "type": "Feature", "properties": { "NAME": "Baku" }, "geometry": { "type": "Point", "coordinates": [ 49.855957, 40.405131 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 6, "y": 4 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Jakarta" }, "geometry": { "type": "Point", "coordinates": [ 106.820068, -6.162401 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Dili" }, "geometry": { "type": "Point", "coordinates": [ 125.573730, -8.559294 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 6, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Thimphu" }, "geometry": { "type": "Point", "coordinates": [ 89.637451, 27.479035 ] } }
{ "type": "Feature", "properties": { "NAME": "Dhaka" }, "geometry": { "type": "Point", "coordinates": [ 90.406494, 23.725012 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Rangoon" }, "geometry": { "type": "Point", "coordinates": [ 96.163330, 16.794024 ] } }
{ "type": "Feature", "properties": { "NAME": "Hanoi" }, "geometry": { "type": "Point", "coordinates": [ 105.842285, 21.043491 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuala Lumpur" }, "geometry": { "type": "Point", "coordinates": [ 101.689453, 3.173425 ] } }
{ "type": "Feature", "properties": { "NAME": "Shanghai" }, "geometry": { "type": "Point", "coordinates": [ 121.431885, 31.222197 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Pyongyang" }, "geometry": { "type": "Point", "coordinates": [ 125.749512, 39.027719 ] } }
{ "type": "Feature", "properties": { "NAME": "Bandar Seri Begawan" }, "geometry": { "type": "Point", "coordinates": [ 114.927979, 4.893941 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Osaka" }, "geometry": { "type": "Point", "coordinates": [ 135.450439, 34.759666 ] } }
] }
] }
,
@ -331,15 +310,15 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Port Moresby" }, "geometry": { "type": "Point", "coordinates": [ 147.183838, -9.459899 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Honiara" }, "geometry": { "type": "Point", "coordinates": [ 159.938965, -9.427387 ] } }
{ "type": "Feature", "properties": { "NAME": "Funafuti" }, "geometry": { "type": "Point", "coordinates": [ 179.208984, -8.515836 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Wellington" }, "geometry": { "type": "Point", "coordinates": [ 174.781494, -41.294317 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 3, "x": 7, "y": 3 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Melekeok" }, "geometry": { "type": "Point", "coordinates": [ 134.626465, 7.493196 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Tokyo" }, "geometry": { "type": "Point", "coordinates": [ 139.746094, 35.692995 ] } }
{ "type": "Feature", "properties": { "NAME": "Osaka" }, "geometry": { "type": "Point", "coordinates": [ 135.450439, 34.759666 ] } }
] }
] }
,
@ -352,8 +331,6 @@
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 2, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "San Francisco" }, "geometry": { "type": "Point", "coordinates": [ -122.420654, 37.770715 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Los Angeles" }, "geometry": { "type": "Point", "coordinates": [ -118.185425, 33.993473 ] } }
] }
] }
,
@ -366,8 +343,6 @@
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 3, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Mexico City" }, "geometry": { "type": "Point", "coordinates": [ -99.135132, 19.445874 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Guatemala" }, "geometry": { "type": "Point", "coordinates": [ -90.532837, 14.626109 ] } }
] }
] }
,
@ -375,7 +350,7 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Denver" }, "geometry": { "type": "Point", "coordinates": [ -104.990845, 39.745210 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Monterrey" }, "geometry": { "type": "Point", "coordinates": [ -100.332642, 25.676187 ] } }
{ "type": "Feature", "properties": { "NAME": "Houston" }, "geometry": { "type": "Point", "coordinates": [ -95.344849, 29.826348 ] } }
] }
] }
,
@ -399,10 +374,12 @@
,
{ "type": "Feature", "properties": { "NAME": "San Salvador" }, "geometry": { "type": "Point", "coordinates": [ -89.208984, 13.715372 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Panama City" }, "geometry": { "type": "Point", "coordinates": [ -79.535522, 8.971897 ] } }
{ "type": "Feature", "properties": { "NAME": "San Jose" }, "geometry": { "type": "Point", "coordinates": [ -84.089355, 9.941798 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Port-au-Prince" }, "geometry": { "type": "Point", "coordinates": [ -72.339478, 18.547325 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bogota" }, "geometry": { "type": "Point", "coordinates": [ -74.086304, 4.603803 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Quito" }, "geometry": { "type": "Point", "coordinates": [ -78.502808, -0.208740 ] } }
] }
] }
@ -411,9 +388,9 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Atlanta" }, "geometry": { "type": "Point", "coordinates": [ -84.402466, 33.833920 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Havana" }, "geometry": { "type": "Point", "coordinates": [ -82.369995, 23.135309 ] } }
{ "type": "Feature", "properties": { "NAME": "Miami" }, "geometry": { "type": "Point", "coordinates": [ -80.227661, 25.790000 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Washington, D.C." }, "geometry": { "type": "Point", "coordinates": [ -77.014160, 38.903858 ] } }
{ "type": "Feature", "properties": { "NAME": "New York" }, "geometry": { "type": "Point", "coordinates": [ -73.987427, 40.755580 ] } }
] }
] }
,
@ -421,7 +398,9 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Chicago" }, "geometry": { "type": "Point", "coordinates": [ -87.753296, 41.832735 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Toronto" }, "geometry": { "type": "Point", "coordinates": [ -79.425659, 43.703622 ] } }
{ "type": "Feature", "properties": { "NAME": "Ottawa" }, "geometry": { "type": "Point", "coordinates": [ -75.706787, 45.421588 ] } }
,
{ "type": "Feature", "properties": { "NAME": "New York" }, "geometry": { "type": "Point", "coordinates": [ -73.987427, 40.755580 ] } }
] }
] }
,
@ -429,7 +408,7 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Asuncion" }, "geometry": { "type": "Point", "coordinates": [ -57.645264, -25.294371 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Montevideo" }, "geometry": { "type": "Point", "coordinates": [ -56.173096, -34.854383 ] } }
{ "type": "Feature", "properties": { "NAME": "Sao Paulo" }, "geometry": { "type": "Point", "coordinates": [ -46.631470, -23.553917 ] } }
] }
] }
,
@ -445,11 +424,11 @@
,
{ "type": "Feature", "properties": { "NAME": "Roseau" }, "geometry": { "type": "Point", "coordinates": [ -61.391602, 15.305380 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Saint George's" }, "geometry": { "type": "Point", "coordinates": [ -61.743164, 12.055437 ] } }
{ "type": "Feature", "properties": { "NAME": "Kingstown" }, "geometry": { "type": "Point", "coordinates": [ -61.215820, 13.149027 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Caracas" }, "geometry": { "type": "Point", "coordinates": [ -66.923218, 10.504016 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Paramaribo" }, "geometry": { "type": "Point", "coordinates": [ -55.167847, 5.840081 ] } }
{ "type": "Feature", "properties": { "NAME": "Georgetown" }, "geometry": { "type": "Point", "coordinates": [ -58.167114, 6.806444 ] } }
] }
] }
,
@ -469,15 +448,13 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Dakar" }, "geometry": { "type": "Point", "coordinates": [ -17.479248, 14.721761 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Nouakchott" }, "geometry": { "type": "Point", "coordinates": [ -15.979614, 18.088423 ] } }
{ "type": "Feature", "properties": { "NAME": "Banjul" }, "geometry": { "type": "Point", "coordinates": [ -16.594849, 13.459080 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Conakry" }, "geometry": { "type": "Point", "coordinates": [ -13.683472, 9.535749 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bamako" }, "geometry": { "type": "Point", "coordinates": [ -8.003540, 12.656418 ] } }
{ "type": "Feature", "properties": { "NAME": "Ouagadougou" }, "geometry": { "type": "Point", "coordinates": [ -1.527100, 12.377563 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Yamoussoukro" }, "geometry": { "type": "Point", "coordinates": [ -5.278931, 6.822807 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Accra" }, "geometry": { "type": "Point", "coordinates": [ -0.219727, 5.555848 ] } }
] }
] }
,
@ -487,7 +464,7 @@
,
{ "type": "Feature", "properties": { "NAME": "Casablanca" }, "geometry": { "type": "Point", "coordinates": [ -7.619019, 33.605470 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bir Lehlou" }, "geometry": { "type": "Point", "coordinates": [ -9.656982, 26.120918 ] } }
{ "type": "Feature", "properties": { "NAME": "Madrid" }, "geometry": { "type": "Point", "coordinates": [ -3.685913, 40.405131 ] } }
] }
] }
,
@ -511,15 +488,15 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 8 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Sao Tome" }, "geometry": { "type": "Point", "coordinates": [ 6.729126, 0.335081 ] } }
{ "type": "Feature", "properties": { "NAME": "Brazzaville" }, "geometry": { "type": "Point", "coordinates": [ 15.281982, -4.253290 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kinshasa" }, "geometry": { "type": "Point", "coordinates": [ 15.309448, -4.324501 ] } }
{ "type": "Feature", "properties": { "NAME": "Luanda" }, "geometry": { "type": "Point", "coordinates": [ 13.227539, -8.836223 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Accra" }, "geometry": { "type": "Point", "coordinates": [ -0.219727, 5.555848 ] } }
{ "type": "Feature", "properties": { "NAME": "Niamey" }, "geometry": { "type": "Point", "coordinates": [ 2.109375, 13.523179 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Cotonou" }, "geometry": { "type": "Point", "coordinates": [ 2.515869, 6.402648 ] } }
,
@ -535,37 +512,35 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Algiers" }, "geometry": { "type": "Point", "coordinates": [ 3.043213, 36.765292 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Tunis" }, "geometry": { "type": "Point", "coordinates": [ 10.178833, 36.804887 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Valletta" }, "geometry": { "type": "Point", "coordinates": [ 14.512939, 35.902400 ] } }
{ "type": "Feature", "properties": { "NAME": "Tripoli" }, "geometry": { "type": "Point", "coordinates": [ 13.178101, 32.893426 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 8, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "London" }, "geometry": { "type": "Point", "coordinates": [ -0.120850, 51.505323 ] } }
{ "type": "Feature", "properties": { "NAME": "The Hague" }, "geometry": { "type": "Point", "coordinates": [ 4.268188, 52.082882 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Amsterdam" }, "geometry": { "type": "Point", "coordinates": [ 4.910889, 52.352119 ] } }
{ "type": "Feature", "properties": { "NAME": "Brussels" }, "geometry": { "type": "Point", "coordinates": [ 4.328613, 50.837167 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Luxembourg" }, "geometry": { "type": "Point", "coordinates": [ 6.124878, 49.614269 ] } }
{ "type": "Feature", "properties": { "NAME": "Paris" }, "geometry": { "type": "Point", "coordinates": [ 2.329102, 48.871941 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Geneva" }, "geometry": { "type": "Point", "coordinates": [ 6.135864, 46.210250 ] } }
{ "type": "Feature", "properties": { "NAME": "Bern" }, "geometry": { "type": "Point", "coordinates": [ 7.465210, 46.920255 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vaduz" }, "geometry": { "type": "Point", "coordinates": [ 9.514160, 47.137425 ] } }
{ "type": "Feature", "properties": { "NAME": "Monaco" }, "geometry": { "type": "Point", "coordinates": [ 7.404785, 43.743321 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Berlin" }, "geometry": { "type": "Point", "coordinates": [ 13.397827, 52.526248 ] } }
{ "type": "Feature", "properties": { "NAME": "Prague" }, "geometry": { "type": "Point", "coordinates": [ 14.463501, 50.085344 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Warsaw" }, "geometry": { "type": "Point", "coordinates": [ 20.994873, 52.254709 ] } }
{ "type": "Feature", "properties": { "NAME": "Vienna" }, "geometry": { "type": "Point", "coordinates": [ 16.364136, 48.202710 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Zagreb" }, "geometry": { "type": "Point", "coordinates": [ 15.996094, 45.801999 ] } }
{ "type": "Feature", "properties": { "NAME": "San Marino" }, "geometry": { "type": "Point", "coordinates": [ 12.436523, 43.937462 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vatican City" }, "geometry": { "type": "Point", "coordinates": [ 12.453003, 41.906365 ] } }
{ "type": "Feature", "properties": { "NAME": "Rome" }, "geometry": { "type": "Point", "coordinates": [ 12.480469, 41.898188 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Budapest" }, "geometry": { "type": "Point", "coordinates": [ 19.077759, 47.502359 ] } }
{ "type": "Feature", "properties": { "NAME": "Sarajevo" }, "geometry": { "type": "Point", "coordinates": [ 18.380127, 43.850374 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Podgorica" }, "geometry": { "type": "Point", "coordinates": [ 19.264526, 42.468045 ] } }
{ "type": "Feature", "properties": { "NAME": "Belgrade" }, "geometry": { "type": "Point", "coordinates": [ 20.462036, 44.820812 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Pristina" }, "geometry": { "type": "Point", "coordinates": [ 21.165161, 42.670320 ] } }
{ "type": "Feature", "properties": { "NAME": "Skopje" }, "geometry": { "type": "Point", "coordinates": [ 21.428833, 42.000325 ] } }
] }
] }
,
@ -591,13 +566,13 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Kampala" }, "geometry": { "type": "Point", "coordinates": [ 32.579956, 0.324095 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bujumbura" }, "geometry": { "type": "Point", "coordinates": [ 29.355469, -3.370856 ] } }
{ "type": "Feature", "properties": { "NAME": "Kigali" }, "geometry": { "type": "Point", "coordinates": [ 30.053101, -1.949697 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Harare" }, "geometry": { "type": "Point", "coordinates": [ 31.041870, -17.811456 ] } }
{ "type": "Feature", "properties": { "NAME": "Lusaka" }, "geometry": { "type": "Point", "coordinates": [ 28.278809, -15.411319 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Dar es Salaam" }, "geometry": { "type": "Point", "coordinates": [ 39.265137, -6.795535 ] } }
{ "type": "Feature", "properties": { "NAME": "Nairobi" }, "geometry": { "type": "Point", "coordinates": [ 36.809692, -1.279801 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Moroni" }, "geometry": { "type": "Point", "coordinates": [ 43.236694, -11.700652 ] } }
{ "type": "Feature", "properties": { "NAME": "Lilongwe" }, "geometry": { "type": "Point", "coordinates": [ 33.782959, -13.982046 ] } }
] }
] }
,
@ -605,27 +580,27 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Khartoum" }, "geometry": { "type": "Point", "coordinates": [ 32.530518, 15.591293 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Juba" }, "geometry": { "type": "Point", "coordinates": [ 31.574707, 4.833733 ] } }
{ "type": "Feature", "properties": { "NAME": "Kampala" }, "geometry": { "type": "Point", "coordinates": [ 32.579956, 0.324095 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Sanaa" }, "geometry": { "type": "Point", "coordinates": [ 44.203491, 15.358356 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Addis Ababa" }, "geometry": { "type": "Point", "coordinates": [ 38.693848, 9.037003 ] } }
{ "type": "Feature", "properties": { "NAME": "Hargeysa" }, "geometry": { "type": "Point", "coordinates": [ 44.060669, 9.562834 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Mogadishu" }, "geometry": { "type": "Point", "coordinates": [ 45.362549, 2.070472 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 9, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Istanbul" }, "geometry": { "type": "Point", "coordinates": [ 29.003906, 41.108330 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Athens" }, "geometry": { "type": "Point", "coordinates": [ 23.730469, 37.987504 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Nicosia" }, "geometry": { "type": "Point", "coordinates": [ 33.365479, 35.169318 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Beirut" }, "geometry": { "type": "Point", "coordinates": [ 35.502319, 33.874976 ] } }
{ "type": "Feature", "properties": { "NAME": "Tel Aviv-Yafo" }, "geometry": { "type": "Point", "coordinates": [ 34.766235, 32.082575 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Yerevan" }, "geometry": { "type": "Point", "coordinates": [ 44.511108, 40.187267 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Amman" }, "geometry": { "type": "Point", "coordinates": [ 35.930786, 31.952162 ] } }
{ "type": "Feature", "properties": { "NAME": "Jerusalem" }, "geometry": { "type": "Point", "coordinates": [ 35.205688, 31.779547 ] } }
] }
] }
,
@ -635,7 +610,7 @@
,
{ "type": "Feature", "properties": { "NAME": "Kiev" }, "geometry": { "type": "Point", "coordinates": [ 30.514526, 50.436516 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Chisinau" }, "geometry": { "type": "Point", "coordinates": [ 28.855591, 47.006480 ] } }
{ "type": "Feature", "properties": { "NAME": "Bucharest" }, "geometry": { "type": "Point", "coordinates": [ 26.092529, 44.437702 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Moscow" }, "geometry": { "type": "Point", "coordinates": [ 37.611694, 55.754941 ] } }
] }
@ -645,6 +620,8 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Helsinki" }, "geometry": { "type": "Point", "coordinates": [ 24.927979, 60.179770 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Riga" }, "geometry": { "type": "Point", "coordinates": [ 24.098511, 56.950966 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Moscow" }, "geometry": { "type": "Point", "coordinates": [ 37.611694, 55.754941 ] } }
] }
] }
@ -653,7 +630,7 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Victoria" }, "geometry": { "type": "Point", "coordinates": [ 55.447998, -4.614753 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Antananarivo" }, "geometry": { "type": "Point", "coordinates": [ 47.510376, -18.911483 ] } }
{ "type": "Feature", "properties": { "NAME": "Port Louis" }, "geometry": { "type": "Point", "coordinates": [ 57.496948, -20.164255 ] } }
] }
] }
,
@ -677,17 +654,11 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 10, "y": 5 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Tbilisi" }, "geometry": { "type": "Point", "coordinates": [ 44.785767, 41.730330 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 11, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Mumbai" }, "geometry": { "type": "Point", "coordinates": [ 72.850342, 19.020577 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Bangalore" }, "geometry": { "type": "Point", "coordinates": [ 77.557983, 12.972442 ] } }
{ "type": "Feature", "properties": { "NAME": "Male" }, "geometry": { "type": "Point", "coordinates": [ 73.498535, 4.171115 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Sri Jawewardenepura Kotte" }, "geometry": { "type": "Point", "coordinates": [ 79.947510, 6.904614 ] } }
] }
@ -697,11 +668,9 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Dushanbe" }, "geometry": { "type": "Point", "coordinates": [ 68.768921, 38.561053 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kabul" }, "geometry": { "type": "Point", "coordinates": [ 69.180908, 34.520136 ] } }
{ "type": "Feature", "properties": { "NAME": "Islamabad" }, "geometry": { "type": "Point", "coordinates": [ 73.163452, 33.706063 ] } }
,
{ "type": "Feature", "properties": { "NAME": "New Delhi" }, "geometry": { "type": "Point", "coordinates": [ 77.195435, 28.603814 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kolkata" }, "geometry": { "type": "Point", "coordinates": [ 88.319092, 22.497332 ] } }
{ "type": "Feature", "properties": { "NAME": "Kathmandu" }, "geometry": { "type": "Point", "coordinates": [ 85.314331, 27.722436 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Dhaka" }, "geometry": { "type": "Point", "coordinates": [ 90.406494, 23.725012 ] } }
] }
@ -711,9 +680,7 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Astana" }, "geometry": { "type": "Point", "coordinates": [ 71.427612, 51.182786 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Tashkent" }, "geometry": { "type": "Point", "coordinates": [ 69.290771, 41.314950 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Urumqi" }, "geometry": { "type": "Point", "coordinates": [ 87.572021, 43.810747 ] } }
{ "type": "Feature", "properties": { "NAME": "Bishkek" }, "geometry": { "type": "Point", "coordinates": [ 74.580688, 42.875964 ] } }
] }
] }
,
@ -727,20 +694,16 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Naypyidaw" }, "geometry": { "type": "Point", "coordinates": [ 96.113892, 19.771873 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Rangoon" }, "geometry": { "type": "Point", "coordinates": [ 96.163330, 16.788765 ] } }
{ "type": "Feature", "properties": { "NAME": "Bangkok" }, "geometry": { "type": "Point", "coordinates": [ 100.513916, 13.752725 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Vientiane" }, "geometry": { "type": "Point", "coordinates": [ 102.595825, 17.968283 ] } }
{ "type": "Feature", "properties": { "NAME": "Hanoi" }, "geometry": { "type": "Point", "coordinates": [ 105.847778, 21.038364 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Kuala Lumpur" }, "geometry": { "type": "Point", "coordinates": [ 101.694946, 3.173425 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Singapore" }, "geometry": { "type": "Point", "coordinates": [ 103.853760, 1.296276 ] } }
{ "type": "Feature", "properties": { "NAME": "Putrajaya" }, "geometry": { "type": "Point", "coordinates": [ 101.700439, 2.915611 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 12, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Thimphu" }, "geometry": { "type": "Point", "coordinates": [ 89.637451, 27.474161 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Dhaka" }, "geometry": { "type": "Point", "coordinates": [ 90.406494, 23.725012 ] } }
] }
] }
@ -759,11 +722,9 @@
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 13, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Hong Kong" }, "geometry": { "type": "Point", "coordinates": [ 114.180908, 22.309426 ] } }
{ "type": "Feature", "properties": { "NAME": "Baguio City" }, "geometry": { "type": "Point", "coordinates": [ 120.569458, 16.430816 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Manila" }, "geometry": { "type": "Point", "coordinates": [ 120.975952, 14.610163 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Melekeok" }, "geometry": { "type": "Point", "coordinates": [ 134.626465, 7.487750 ] } }
{ "type": "Feature", "properties": { "NAME": "Bandar Seri Begawan" }, "geometry": { "type": "Point", "coordinates": [ 114.927979, 4.888467 ] } }
] }
] }
,
@ -780,6 +741,8 @@
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 14, "y": 9 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Melbourne" }, "geometry": { "type": "Point", "coordinates": [ 144.970093, -37.814124 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Canberra" }, "geometry": { "type": "Point", "coordinates": [ 149.128418, -35.281501 ] } }
] }
] }
,
@ -789,12 +752,6 @@
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 14, "y": 7 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Melekeok" }, "geometry": { "type": "Point", "coordinates": [ 134.626465, 7.487750 ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 4, "x": 14, "y": 6 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Osaka" }, "geometry": { "type": "Point", "coordinates": [ 135.455933, 34.755153 ] } }
@ -829,7 +786,7 @@
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "NAME": "Palikir" }, "geometry": { "type": "Point", "coordinates": [ 158.148193, 6.920974 ] } }
,
{ "type": "Feature", "properties": { "NAME": "Majuro" }, "geometry": { "type": "Point", "coordinates": [ 171.375732, 7.106344 ] } }
{ "type": "Feature", "properties": { "NAME": "Tarawa" }, "geometry": { "type": "Point", "coordinates": [ 173.012695, 1.340210 ] } }
] }
] }
,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,20 +0,0 @@
{ "*": [
"all",
[
"attribute-filter",
"NAMEALT",
[ ">=", "$zoom", 2 ]
],
[
"any",
[ "all", [ "==", "SCALERANK", 0 ], [ ">=", "$zoom", 0 ] ],
[ "all", [ "==", "SCALERANK", 1 ], [ ">=", "$zoom", 1 ] ],
[ "all", [ "==", "SCALERANK", 2 ], [ ">=", "$zoom", 2 ] ],
[ "all", [ "==", "SCALERANK", 3 ], [ ">=", "$zoom", 3 ] ],
[ "all", [ "==", "SCALERANK", 4 ], [ ">=", "$zoom", 4 ] ],
[ "all", [ "==", "SCALERANK", 5 ], [ ">=", "$zoom", 5 ] ],
[ "all", [ "==", "SCALERANK", 6 ], [ ">=", "$zoom", 6 ] ],
[ "all", [ "==", "SCALERANK", 7 ], [ ">=", "$zoom", 7 ] ],
[ "all", [ ">=", "SCALERANK", 8 ], [ ">=", "$zoom", 8 ] ]
]
] }

View File

@ -1,3 +0,0 @@
#!/bin/sh
echo '{ "type": "Feature", "properties": { "scalerank": 1, "featurecla": "Admin-0 country", "labelrank": 3.000000, "sovereignt": "Afghanistan", "sov_a3": "AFG", "adm0_dif": 0.000000, "level": 2.000000, "type": "Sovereign country", "admin": "Afghanistan", "adm0_a3": "AFG", "geou_dif": 0.000000, "geounit": "Afghanistan", "gu_a3": "AFG", "su_dif": 0.000000, "subunit": "Afghanistan", "su_a3": "AFG", "brk_diff": 0.000000, "name": "Afghanistan", "name_long": "Afghanistan", "brk_a3": "AFG", "brk_name": "Afghanistan", "brk_group": null, "abbrev": "Afg.", "postal": "AF", "formal_en": "Islamic State of Afghanistan", "formal_fr": null, "note_adm0": null, "note_brk": null, "name_sort": "Afghanistan", "name_alt": null, "mapcolor7": 5.000000, "mapcolor8": 6.000000, "mapcolor9": 8.000000, "mapcolor13": 7.000000, "pop_est": 28400000.000000, "gdp_md_est": 22270.000000, "pop_year": -99.000000, "lastcensus": 1979.000000, "gdp_year": -99.000000, "economy": "7. Least developed region", "income_grp": "5. Low income", "wikipedia": -99.000000, "fips_10": null, "iso_a2": "AF", "iso_a3": "AFG", "iso_n3": "004", "un_a3": "004", "wb_a2": "AF", "wb_a3": "AFG", "woe_id": -99.000000, "adm0_a3_is": "AFG", "adm0_a3_us": "AFG", "adm0_a3_un": -99.000000, "adm0_a3_wb": -99.000000, "continent": "Asia", "region_un": "Asia", "subregion": "Southern Asia", "region_wb": "South Asia", "name_len": 11.000000, "long_len": 11.000000, "abbrev_len": 4.000000, "tiny": -99.000000, "homepart": 1.000000 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 61.210817, 35.650072 ], [ 62.230651, 35.270663 ], [ 62.984662, 35.404040 ], [ 63.193538, 35.857165 ], [ 63.982895, 36.007957 ], [ 64.546479, 36.312073 ], [ 64.746105, 37.111817 ], [ 65.588947, 37.305216 ], [ 65.745630, 37.661164 ], [ 66.217384, 37.393790 ], [ 66.518606, 37.362784 ], [ 67.075782, 37.356143 ], [ 67.829999, 37.144994 ], [ 68.135562, 37.023115 ], [ 68.859445, 37.344335 ], [ 69.196272, 37.151143 ], [ 69.518785, 37.608996 ], [ 70.116578, 37.588222 ], [ 70.270574, 37.735164 ], [ 70.376304, 38.138395 ], [ 70.806820, 38.486281 ], [ 71.348131, 38.258905 ], [ 71.239403, 37.953265 ], [ 71.541917, 37.905774 ], [ 71.448693, 37.065644 ], [ 71.844638, 36.738171 ], [ 72.193040, 36.948287 ], [ 72.636889, 37.047558 ], [ 73.260055, 37.495256 ], [ 73.948695, 37.421566 ], [ 74.980002, 37.419990 ], [ 75.158027, 37.133030 ], [ 74.575892, 37.020841 ], [ 74.067551, 36.836175 ], [ 72.920024, 36.720007 ], [ 71.846291, 36.509942 ], [ 71.262348, 36.074387 ], [ 71.498767, 35.650563 ], [ 71.613076, 35.153203 ], [ 71.115018, 34.733125 ], [ 71.156773, 34.348911 ], [ 70.881803, 33.988855 ], [ 69.930543, 34.020120 ], [ 70.323594, 33.358532 ], [ 69.687147, 33.105498 ], [ 69.262522, 32.501944 ], [ 69.317764, 31.901412 ], [ 68.926676, 31.620189 ], [ 68.556932, 31.713310 ], [ 67.792689, 31.582930 ], [ 67.683393, 31.303154 ], [ 66.938891, 31.304911 ], [ 66.381457, 30.738899 ], [ 66.346472, 29.887943 ], [ 65.046862, 29.472180 ], [ 64.350418, 29.560030 ], [ 64.148002, 29.340819 ], [ 63.550260, 29.468330 ], [ 62.549856, 29.318572 ], [ 60.874248, 29.829238 ], [ 61.781221, 30.735850 ], [ 61.699314, 31.379506 ], [ 60.941944, 31.548074 ], [ 60.863654, 32.182919 ], [ 60.536077, 32.981268 ], [ 60.963700, 33.528832 ], [ 60.528429, 33.676446 ], [ 60.803193, 34.404101 ], [ 61.210817, 35.650072 ] ] ] } }'

View File

@ -3,7 +3,6 @@
"center": "22.500000,20.489949,3",
"description": "tests/geometry/out/-z3.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/geometry/out/-z3.json.check.mbtiles -z3 tests/geometry/bare.json tests/geometry/geometrycollection.json tests/geometry/multipoint.json tests/geometry/onebare.json",
"json": "{\"vector_layers\": [ { \"id\": \"bare\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 3, \"fields\": {} }, { \"id\": \"geometrycollection\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 3, \"fields\": {\"collection\": \"Boolean\"} }, { \"id\": \"multipoint\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 3, \"fields\": {\"point\": \"String\"} }, { \"id\": \"onebare\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 3, \"fields\": {} } ],\"tilestats\": {\"layerCount\": 4,\"layers\": [{\"layer\": \"bare\",\"count\": 4,\"geometry\": \"LineString\",\"attributeCount\": 0,\"attributes\": []},{\"layer\": \"geometrycollection\",\"count\": 2,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"collection\",\"count\": 1,\"type\": \"boolean\",\"values\": [true]}]},{\"layer\": \"multipoint\",\"count\": 1,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"point\",\"count\": 1,\"type\": \"string\",\"values\": [\"multi\"]}]},{\"layer\": \"onebare\",\"count\": 1,\"geometry\": \"LineString\",\"attributeCount\": 0,\"attributes\": []}]}}",
"maxzoom": "3",
"minzoom": "0",
@ -24,8 +23,6 @@
,
{ "type": "FeatureCollection", "properties": { "layer": "geometrycollection", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "collection": true }, "geometry": { "type": "LineString", "coordinates": [ [ 100.986328, 0.000000 ], [ 101.953125, 1.054628 ] ] } }
,
{ "type": "Feature", "properties": { "collection": true }, "geometry": { "type": "Point", "coordinates": [ 99.931641, 0.000000 ] } }
] }
,
{ "type": "FeatureCollection", "properties": { "layer": "multipoint", "version": 2, "extent": 4096 }, "features": [

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "hpa": 103200 }, "geometry": { "type": "MultiLineString", "coordinates": [ [ [254,35], [204,35], [204,30], [254,30], [254,35] ] ] } } ] }

View File

@ -1,25 +0,0 @@
{ "type": "FeatureCollection", "properties": {
"bounds": "-180.000000,30.000000,180.000000,35.000000",
"center": "-90.000000,35.000000,1",
"description": "tests/high-longitude/out/-z1.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/high-longitude/out/-z1.json.check.mbtiles -z1 tests/high-longitude/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 1, \"fields\": {\"hpa\": \"Number\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 1,\"geometry\": \"LineString\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"hpa\",\"count\": 1,\"type\": \"number\",\"values\": [103200],\"min\": 103200,\"max\": 103200}]}]}}",
"maxzoom": "1",
"minzoom": "0",
"name": "tests/high-longitude/out/-z1.json.check.mbtiles",
"type": "overlay",
"version": "2"
}, "features": [
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "hpa": 103200 }, "geometry": { "type": "LineString", "coordinates": [ [ -106.083984, 35.029996 ], [ -156.005859, 35.029996 ], [ -156.005859, 30.069094 ], [ -106.083984, 30.069094 ], [ -106.083984, 35.029996 ] ] } }
] }
] }
,
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "hpa": 103200 }, "geometry": { "type": "LineString", "coordinates": [ [ -106.040039, 35.029996 ], [ -156.005859, 35.029996 ], [ -156.005859, 30.031055 ], [ -106.040039, 30.031055 ], [ -106.040039, 35.029996 ] ] } }
] }
] }
] }

View File

@ -3,7 +3,6 @@
"center": "-121.999912,37.000000,20",
"description": "tests/highzoom/out/-z30.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/highzoom/out/-z30.json.check.mbtiles -z30 tests/highzoom/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 20, \"fields\": {\"name\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 2,\"geometry\": \"Point\",\"attributeCount\": 1,\"attributes\": [{\"attribute\": \"name\",\"count\": 2,\"type\": \"string\",\"values\": [\"London\",\"Santa Cruz\"]}]}]}}",
"maxzoom": "20",
"minzoom": "0",
@ -20,6 +19,8 @@
{ "type": "FeatureCollection", "properties": { "zoom": 1, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "name": "Santa Cruz" }, "geometry": { "type": "Point", "coordinates": [ -122.036133, 37.020098 ] } }
,
{ "type": "Feature", "properties": { "name": "London" }, "geometry": { "type": "Point", "coordinates": [ 0.000000, 51.508742 ] } }
] }
] }
,

View File

@ -3,7 +3,6 @@
"center": "-122.156982,37.762029,14",
"description": "tests/id/out/-Z11.json.check.mbtiles",
"format": "pbf",
"generator_options": "./tippecanoe -q -a@ -f -o tests/id/out/-Z11.json.check.mbtiles -Z11 tests/id/in.json",
"json": "{\"vector_layers\": [ { \"id\": \"in\", \"description\": \"\", \"minzoom\": 11, \"maxzoom\": 14, \"fields\": {\"FULLNAME\": \"String\", \"LINEARID\": \"String\", \"MTFCC\": \"String\", \"RTTYP\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"in\",\"count\": 8,\"geometry\": \"LineString\",\"attributeCount\": 4,\"attributes\": [{\"attribute\": \"FULLNAME\",\"count\": 3,\"type\": \"string\",\"values\": [\"Macarthur\",\"Macarthur Blvd\",\"Macarthur Fwy\"]},{\"attribute\": \"LINEARID\",\"count\": 8,\"type\": \"string\",\"values\": [\"1102406970092\",\"1102638069562\",\"1102954918511\",\"1103690483032\",\"1104469713187\",\"1104469713198\",\"1104486090991\",\"1105089465114\"]},{\"attribute\": \"MTFCC\",\"count\": 2,\"type\": \"string\",\"values\": [\"S1100\",\"S1400\"]},{\"attribute\": \"RTTYP\",\"count\": 1,\"type\": \"string\",\"values\": [\"M\"]}]}]}}",
"maxzoom": "14",
"minzoom": "11",

File diff suppressed because one or more lines are too long

View File

@ -1,65 +0,0 @@
{ "type": "FeatureCollection", "properties": {
"bounds": "-180.000000,-85.051129,180.000000,85.051129",
"center": "-122.104097,37.695438,0",
"description": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
"format": "pbf",
"generator_options": "./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tippecanoe -q -f -z0 -n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -o tests/join-population/macarthur.mbtiles tests/join-population/macarthur.json; ./tile-join -f -o tests/join-population/concat.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles tests/join-population/macarthur.mbtiles",
"json": "{\"vector_layers\": [ { \"id\": \"macarthur\", \"description\": \"\", \"minzoom\": 0, \"maxzoom\": 0, \"fields\": {\"FULLNAME\": \"String\", \"LINEARID\": \"String\", \"MTFCC\": \"String\", \"RTTYP\": \"String\"} } ],\"tilestats\": {\"layerCount\": 1,\"layers\": [{\"layer\": \"macarthur\",\"count\": 24,\"geometry\": \"LineString\",\"attributeCount\": 4,\"attributes\": [{\"attribute\": \"FULLNAME\",\"count\": 3,\"type\": \"string\",\"values\": [\"Macarthur\",\"Macarthur Fwy\",\"W Macarthur\"]},{\"attribute\": \"LINEARID\",\"count\": 4,\"type\": \"string\",\"values\": [\"1102954918511\",\"1104474748623\",\"1104486090991\",\"1104486392881\"]},{\"attribute\": \"MTFCC\",\"count\": 2,\"type\": \"string\",\"values\": [\"S1100\",\"S1400\"]},{\"attribute\": \"RTTYP\",\"count\": 1,\"type\": \"string\",\"values\": [\"M\"]}]}]}}",
"maxzoom": "0",
"minzoom": "0",
"name": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
"type": "overlay",
"version": "2"
}, "features": [
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
{ "type": "FeatureCollection", "properties": { "layer": "macarthur", "version": 2, "extent": 4096 }, "features": [
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486392881", "FULLNAME": "W Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.857507 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104486090991", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.343750, 37.857507 ], [ -122.167969, 37.718590 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1104474748623", "FULLNAME": "Macarthur Fwy", "RTTYP": "M", "MTFCC": "S1100" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.167969, 37.718590 ], [ -122.343750, 37.857507 ] ] } }
,
{ "type": "Feature", "properties": { "LINEARID": "1102954918511", "FULLNAME": "Macarthur", "RTTYP": "M", "MTFCC": "S1400" }, "geometry": { "type": "LineString", "coordinates": [ [ -122.255859, 37.788081 ], [ -122.167969, 37.788081 ] ] } }
] }
] }
] }

Some files were not shown because too many files have changed in this diff Show More