mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 16:35:40 +02:00
Remove undocumented command-line options (#361)
* Remove --accumulate-numeric-attributes * Remove join-sqlite, etc. * Remove --accumulate-numeric-attributes from overzoom * Remove --assign-to-bins and --bin-by-id-list * Remove --clip-polygon and --clip-bounding-box * Remove FSL expressions * Update version and changelog
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
# 2.80.0
|
||||||
|
|
||||||
|
* Remove undocumented command-line options
|
||||||
|
|
||||||
# 2.79.0
|
# 2.79.0
|
||||||
|
|
||||||
* When deduplicating features by ID in tippecanoe-overzoom, be careful
|
* When deduplicating features by ID in tippecanoe-overzoom, be careful
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ indent:
|
|||||||
TESTS = $(wildcard tests/*/out/*.json)
|
TESTS = $(wildcard tests/*/out/*.json)
|
||||||
SPACE = $(NULL) $(NULL)
|
SPACE = $(NULL) $(NULL)
|
||||||
|
|
||||||
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test pmtiles-test decode-pmtiles-test overzoom-test accumulate-test
|
test: tippecanoe tippecanoe-decode $(addsuffix .check,$(TESTS)) raw-tiles-test parallel-test pbf-test join-test enumerate-test decode-test join-filter-test unit json-tool-test allow-existing-test csv-test layer-json-test pmtiles-test decode-pmtiles-test overzoom-test
|
||||||
./unit
|
./unit
|
||||||
|
|
||||||
suffixes = json json.gz
|
suffixes = json json.gz
|
||||||
@@ -322,7 +322,7 @@ overzoom-test: tippecanoe-overzoom
|
|||||||
# Filtering
|
# Filtering
|
||||||
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
||||||
# 27 of them match the filter and are retained
|
# 27 of them match the filter and are retained
|
||||||
./tippecanoe-overzoom -y NAME -j'{"*":["SCALERANK","eq",0]}' -o tests/pbf/0-0-0-pop-expr.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
./tippecanoe-overzoom -y NAME -j'{"*":["==","SCALERANK",0]}' -o tests/pbf/0-0-0-pop-expr.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-pop-expr.pbf 0 0 0 > tests/pbf/0-0-0-pop-expr.pbf.json.check
|
./tippecanoe-decode tests/pbf/0-0-0-pop-expr.pbf 0 0 0 > tests/pbf/0-0-0-pop-expr.pbf.json.check
|
||||||
cmp tests/pbf/0-0-0-pop-expr.pbf.json.check tests/pbf/0-0-0-pop-expr.pbf.json
|
cmp tests/pbf/0-0-0-pop-expr.pbf.json.check tests/pbf/0-0-0-pop-expr.pbf.json
|
||||||
rm tests/pbf/0-0-0-pop-expr.pbf tests/pbf/0-0-0-pop-expr.pbf.json.check
|
rm tests/pbf/0-0-0-pop-expr.pbf tests/pbf/0-0-0-pop-expr.pbf.json.check
|
||||||
@@ -334,13 +334,13 @@ overzoom-test: tippecanoe-overzoom
|
|||||||
# Filtering with multiplier
|
# Filtering with multiplier
|
||||||
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
||||||
# 8 features survive into the output, from 9 clusters of 30
|
# 8 features survive into the output, from 9 clusters of 30
|
||||||
./tippecanoe-overzoom -y NAME -y SCALERANK -j'{"*":["SCALERANK","eq",0]}' -m -o tests/pbf/0-0-0-filter-mult.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
./tippecanoe-overzoom -y NAME -y SCALERANK -j'{"*":["==","SCALERANK",0]}' -m -o tests/pbf/0-0-0-filter-mult.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-filter-mult.pbf 0 0 0 > tests/pbf/0-0-0-filter-mult.pbf.json.check
|
./tippecanoe-decode tests/pbf/0-0-0-filter-mult.pbf 0 0 0 > tests/pbf/0-0-0-filter-mult.pbf.json.check
|
||||||
cmp tests/pbf/0-0-0-filter-mult.pbf.json.check tests/pbf/0-0-0-filter-mult.pbf.json
|
cmp tests/pbf/0-0-0-filter-mult.pbf.json.check tests/pbf/0-0-0-filter-mult.pbf.json
|
||||||
rm tests/pbf/0-0-0-filter-mult.pbf tests/pbf/0-0-0-filter-mult.pbf.json.check
|
rm tests/pbf/0-0-0-filter-mult.pbf tests/pbf/0-0-0-filter-mult.pbf.json.check
|
||||||
# Filtering with multiplier and preserve-input-order
|
# Filtering with multiplier and preserve-input-order
|
||||||
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
# 243 features in the source tile tests/pbf/0-0-0-pop.pbf
|
||||||
./tippecanoe-overzoom -y NAME -y SCALERANK -j'{"*":["NAME","cn","e"]}' -m --preserve-input-order -o tests/pbf/0-0-0-filter-mult-order.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
./tippecanoe-overzoom -y NAME -y SCALERANK -y LATITUDE -j'{"*":[">","LATITUDE",40]}' -m --preserve-input-order -o tests/pbf/0-0-0-filter-mult-order.pbf tests/pbf/0-0-0-pop.pbf 0/0/0 0/0/0
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-filter-mult-order.pbf 0 0 0 > tests/pbf/0-0-0-filter-mult-order.pbf.json.check
|
./tippecanoe-decode tests/pbf/0-0-0-filter-mult-order.pbf 0 0 0 > tests/pbf/0-0-0-filter-mult-order.pbf.json.check
|
||||||
cmp tests/pbf/0-0-0-filter-mult-order.pbf.json.check tests/pbf/0-0-0-filter-mult-order.pbf.json
|
cmp tests/pbf/0-0-0-filter-mult-order.pbf.json.check tests/pbf/0-0-0-filter-mult-order.pbf.json
|
||||||
rm tests/pbf/0-0-0-filter-mult-order.pbf tests/pbf/0-0-0-filter-mult-order.pbf.json.check
|
rm tests/pbf/0-0-0-filter-mult-order.pbf tests/pbf/0-0-0-filter-mult-order.pbf.json.check
|
||||||
@@ -352,97 +352,11 @@ overzoom-test: tippecanoe-overzoom
|
|||||||
./tippecanoe-decode tests/muni/out/out.dir/000.pbf 0 0 0 > tests/muni/out/out.dir/overzoomed.json
|
./tippecanoe-decode tests/muni/out/out.dir/000.pbf 0 0 0 > tests/muni/out/out.dir/overzoomed.json
|
||||||
cmp tests/muni/out/out.dir/overzoomed.json tests/muni/out/out.dir/direct.json
|
cmp tests/muni/out/out.dir/overzoomed.json tests/muni/out/out.dir/direct.json
|
||||||
rm -rf tests/muni/out/out.dir tests/muni/out/out.mbtiles tests/muni/out/out.dir/overzoomed.json tests/muni/out/out.dir/direct.json
|
rm -rf tests/muni/out/out.dir tests/muni/out/out.mbtiles tests/muni/out/out.dir/overzoomed.json tests/muni/out/out.dir/direct.json
|
||||||
# Test filter with null attribute
|
|
||||||
./tippecanoe-overzoom -j '{"*":["name","ni",[1,5,6,9]]}' -o tests/pbf/12-2145-1391-filter1.pbf tests/pbf/12-2145-1391.pbf 12/2145/1391 12/2145/1391
|
|
||||||
./tippecanoe-decode tests/pbf/12-2145-1391-filter1.pbf 12 2145 1391 > tests/pbf/12-2145-1391-filter1.pbf.json.check
|
|
||||||
cmp tests/pbf/12-2145-1391-filter1.pbf.json.check tests/pbf/12-2145-1391-filter1.pbf.json
|
|
||||||
rm tests/pbf/12-2145-1391-filter1.pbf.json.check tests/pbf/12-2145-1391-filter1.pbf
|
|
||||||
# Test filter with null attribute in "ni" list
|
|
||||||
./tippecanoe-overzoom -j '{"*":["name","ni",[1,5,6,9,null]]}' -o tests/pbf/12-2145-1391-filter2.pbf tests/pbf/12-2145-1391.pbf 12/2145/1391 12/2145/1391
|
|
||||||
./tippecanoe-decode tests/pbf/12-2145-1391-filter2.pbf 12 2145 1391 > tests/pbf/12-2145-1391-filter2.pbf.json.check
|
|
||||||
cmp tests/pbf/12-2145-1391-filter2.pbf.json.check tests/pbf/12-2145-1391-filter2.pbf.json
|
|
||||||
rm tests/pbf/12-2145-1391-filter2.pbf.json.check tests/pbf/12-2145-1391-filter2.pbf
|
|
||||||
# Tiny polygon reduction
|
# Tiny polygon reduction
|
||||||
./tippecanoe-overzoom --line-simplification=5 --tiny-polygon-size=50 -o tests/pbf/countries-0-0-0.pbf.out tests/pbf/countries-0-0-0.pbf 0/0/0 0/0/0
|
./tippecanoe-overzoom --line-simplification=5 --tiny-polygon-size=50 -o tests/pbf/countries-0-0-0.pbf.out tests/pbf/countries-0-0-0.pbf 0/0/0 0/0/0
|
||||||
./tippecanoe-decode tests/pbf/countries-0-0-0.pbf.out 0 0 0 > tests/pbf/countries-0-0-0.pbf.out.json.check
|
./tippecanoe-decode tests/pbf/countries-0-0-0.pbf.out 0 0 0 > tests/pbf/countries-0-0-0.pbf.out.json.check
|
||||||
cmp tests/pbf/countries-0-0-0.pbf.out.json.check tests/pbf/countries-0-0-0.pbf.out.json
|
cmp tests/pbf/countries-0-0-0.pbf.out.json.check tests/pbf/countries-0-0-0.pbf.out.json
|
||||||
rm tests/pbf/countries-0-0-0.pbf.out tests/pbf/countries-0-0-0.pbf.out.json.check
|
rm tests/pbf/countries-0-0-0.pbf.out tests/pbf/countries-0-0-0.pbf.out.json.check
|
||||||
# Clipping to bounding box
|
|
||||||
./tippecanoe-overzoom --clip-bounding-box 5,5,25.7,50 -o tests/pbf/countries-0-0-0-clip.pbf.out tests/pbf/countries-0-0-0.pbf 0/0/0 0/0/0
|
|
||||||
./tippecanoe-decode tests/pbf/countries-0-0-0-clip.pbf.out 0 0 0 > tests/pbf/countries-0-0-0-clip.pbf.out.json.check
|
|
||||||
cmp tests/pbf/countries-0-0-0-clip.pbf.out.json.check tests/pbf/countries-0-0-0-clip.pbf.out.json
|
|
||||||
rm tests/pbf/countries-0-0-0-clip.pbf.out tests/pbf/countries-0-0-0-clip.pbf.out.json.check
|
|
||||||
# Binning
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/bin-11-327-791.pbf.out --assign-to-bins tests/pbf/sf-zips.json tests/pbf/muni-11-327-791.pbf 11/327/791 11/327/791
|
|
||||||
./tippecanoe-decode tests/pbf/bin-11-327-791.pbf.out 11 327 791 > tests/pbf/bin-11-327-791.pbf.out.json.check
|
|
||||||
cmp tests/pbf/bin-11-327-791.pbf.out.json.check tests/pbf/bin-11-327-791.pbf.out.json
|
|
||||||
rm tests/pbf/bin-11-327-791.pbf.out.json.check tests/pbf/bin-11-327-791.pbf.out
|
|
||||||
# Binning by id
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/bin-11-327-791-ids.pbf.out --assign-to-bins tests/pbf/sf-zips.json --bin-by-id-list bin-ids tests/pbf/yearbuilt.pbf 11/327/791 11/327/791
|
|
||||||
./tippecanoe-decode tests/pbf/bin-11-327-791-ids.pbf.out 11 327 791 > tests/pbf/bin-11-327-791-ids.pbf.out.json.check
|
|
||||||
cmp tests/pbf/bin-11-327-791-ids.pbf.out.json.check tests/pbf/bin-11-327-791-ids.pbf.out.json
|
|
||||||
rm tests/pbf/bin-11-327-791-ids.pbf.out.json.check tests/pbf/bin-11-327-791-ids.pbf.out
|
|
||||||
# Binning by id, clipping by polygon
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/bin-11-327-791-ids-clip.pbf.out --clip-polygon='{"coordinates":[[[-122.4527379,37.8128815],[-122.4598853,37.7834743],[-122.4280914,37.7959397],[-122.4527379,37.8128815]]],"type":"Polygon"}' --assign-to-bins tests/pbf/sf-zips.json --bin-by-id-list bin-ids tests/pbf/yearbuilt.pbf 11/327/791 11/327/791
|
|
||||||
./tippecanoe-decode tests/pbf/bin-11-327-791-ids-clip.pbf.out 11 327 791 > tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check
|
|
||||||
cmp tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-clip.pbf.out.json
|
|
||||||
rm tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-clip.pbf.out
|
|
||||||
# Binning by id, clipping by polygon from file
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/bin-11-327-791-ids-clip.pbf.out --clip-polygon-file=tests/pbf/clip-poly.json --assign-to-bins tests/pbf/sf-zips.json --bin-by-id-list bin-ids tests/pbf/yearbuilt.pbf 11/327/791 11/327/791
|
|
||||||
./tippecanoe-decode tests/pbf/bin-11-327-791-ids-clip.pbf.out 11 327 791 > tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check
|
|
||||||
cmp tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-clip.pbf.out.json
|
|
||||||
rm tests/pbf/bin-11-327-791-ids-clip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-clip.pbf.out
|
|
||||||
# Binning by id, attribute stripping
|
|
||||||
# Note that it still works even if we exclude the ID that we are binning by
|
|
||||||
./tippecanoe-overzoom -yZCTA5CE10 -ytippecanoe:count -o tests/pbf/bin-11-327-791-ids-zip.pbf.out --assign-to-bins tests/pbf/sf-zips.json --bin-by-id-list bin-ids tests/pbf/yearbuilt.pbf 11/327/791 11/327/791
|
|
||||||
./tippecanoe-decode tests/pbf/bin-11-327-791-ids-zip.pbf.out 11 327 791 > tests/pbf/bin-11-327-791-ids-zip.pbf.out.json.check
|
|
||||||
cmp tests/pbf/bin-11-327-791-ids-zip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-zip.pbf.out.json
|
|
||||||
rm tests/pbf/bin-11-327-791-ids-zip.pbf.out.json.check tests/pbf/bin-11-327-791-ids-zip.pbf.out
|
|
||||||
# Binning with longitude wraparound problems
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/0-0-0-pop-2-0-1.pbf.out --accumulate-numeric-attributes=tippecanoe --assign-to-bins tests/pbf/h3-2-0-1.geojson tests/pbf/0-0-0.pbf 2/0/1 2/0/1
|
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-pop-2-0-1.pbf.out 2 0 1 > tests/pbf/0-0-0-pop-2-0-1.pbf.out.json.check
|
|
||||||
cmp tests/pbf/0-0-0-pop-2-0-1.pbf.out.json.check tests/pbf/0-0-0-pop-2-0-1.pbf.out.json
|
|
||||||
rm tests/pbf/0-0-0-pop-2-0-1.pbf.out tests/pbf/0-0-0-pop-2-0-1.pbf.out.json.check
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/0-0-0-pop-1-1-0.pbf.out --accumulate-numeric-attributes=tippecanoe --assign-to-bins tests/pbf/h3-1-1-0.geojson tests/pbf/0-0-0.pbf 1/1/0 1/1/0
|
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-pop-1-1-0.pbf.out 1 1 0 > tests/pbf/0-0-0-pop-1-1-0.pbf.out.json.check
|
|
||||||
cmp tests/pbf/0-0-0-pop-1-1-0.pbf.out.json.check tests/pbf/0-0-0-pop-1-1-0.pbf.out.json
|
|
||||||
rm tests/pbf/0-0-0-pop-1-1-0.pbf.out tests/pbf/0-0-0-pop-1-1-0.pbf.out.json.check
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/0-0-0-pop-0-0-0.pbf.out --accumulate-numeric-attributes=tippecanoe --assign-to-bins tests/pbf/h3-0-0-0.geojson tests/pbf/0-0-0.pbf 0/0/0 0/0/0
|
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-pop-0-0-0.pbf.out 0 0 0 > tests/pbf/0-0-0-pop-0-0-0.pbf.out.json.check
|
|
||||||
cmp tests/pbf/0-0-0-pop-0-0-0.pbf.out.json.check tests/pbf/0-0-0-pop-0-0-0.pbf.out.json
|
|
||||||
rm tests/pbf/0-0-0-pop-0-0-0.pbf.out tests/pbf/0-0-0-pop-0-0-0.pbf.out.json.check
|
|
||||||
# Binning, clipping to bounding box
|
|
||||||
./tippecanoe-overzoom --clip-bounding-box 88,67.5,138,78 -o tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out --accumulate-numeric-attributes=tippecanoe --assign-to-bins tests/pbf/h3-1-1-0.geojson tests/pbf/0-0-0.pbf 1/1/0 1/1/0
|
|
||||||
./tippecanoe-decode tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out 1 1 0 > tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out.json.check
|
|
||||||
cmp tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out.json.check tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out.json
|
|
||||||
rm tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out tests/pbf/0-0-0-pop-1-1-0-clip.pbf.out.json.check
|
|
||||||
# Verify fix for crash
|
|
||||||
./tippecanoe-overzoom '-o' tests/10188-crash/out.pbf '-t' '3/2/2' '--assign-to-bins' 'tests/10188-crash/bins.json' '--bin-by-id-list' 'felt:bin_features' '-b5' 'tests/10188-crash/2-0-0.pbf' '2/0/0'
|
|
||||||
rm tests/10188-crash/out.pbf
|
|
||||||
# Polygon clipping
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/countries-1-1-0-clip.pbf --clip-polygon "`cat tests/pbf/region.json`" tests/pbf/countries-1-1-0.pbf 1/1/0 1/1/0
|
|
||||||
./tippecanoe-decode tests/pbf/countries-1-1-0-clip.pbf 1 1 0 > tests/pbf/countries-1-1-0-clip.json.check
|
|
||||||
cmp tests/pbf/countries-1-1-0-clip.json.check tests/pbf/countries-1-1-0-clip.json
|
|
||||||
rm tests/pbf/countries-1-1-0-clip.pbf tests/pbf/countries-1-1-0-clip.json.check
|
|
||||||
# LineString clipping
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/roads-1-1-0-clip.pbf --clip-polygon "`cat tests/pbf/region.json`" tests/pbf/roads-1-1-0.pbf 1/1/0 1/1/0
|
|
||||||
./tippecanoe-decode tests/pbf/roads-1-1-0-clip.pbf 1 1 0 > tests/pbf/roads-1-1-0-clip.json.check
|
|
||||||
cmp tests/pbf/roads-1-1-0-clip.json.check tests/pbf/roads-1-1-0-clip.json
|
|
||||||
rm tests/pbf/roads-1-1-0-clip.pbf tests/pbf/roads-1-1-0-clip.json.check
|
|
||||||
# Point clipping
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/places-1-1-0-clip.pbf --clip-polygon "`cat tests/pbf/region.json`" tests/pbf/places-1-1-0.pbf 1/1/0 1/1/0
|
|
||||||
./tippecanoe-decode tests/pbf/places-1-1-0-clip.pbf 1 1 0 > tests/pbf/places-1-1-0-clip.json.check
|
|
||||||
cmp tests/pbf/places-1-1-0-clip.json.check tests/pbf/places-1-1-0-clip.json
|
|
||||||
rm tests/pbf/places-1-1-0-clip.pbf tests/pbf/places-1-1-0-clip.json.check
|
|
||||||
# Polygon clipping, with excessively large clip region
|
|
||||||
./tippecanoe-overzoom -b10 -o tests/pbf/countries-8-135-86-bigclip.pbf --clip-polygon "`cat tests/pbf/region.json`" tests/pbf/countries-1-1-0.pbf 1/1/0 8/135/86
|
|
||||||
./tippecanoe-decode tests/pbf/countries-8-135-86-bigclip.pbf 8 135 86 > tests/pbf/countries-8-135-86-bigclip.json.check
|
|
||||||
cmp tests/pbf/countries-8-135-86-bigclip.json.check tests/pbf/countries-8-135-86-bigclip.json
|
|
||||||
rm tests/pbf/countries-8-135-86-bigclip.pbf tests/pbf/countries-8-135-86-bigclip.json.check
|
|
||||||
# Clip region that does not intersect with the tile
|
|
||||||
./tippecanoe-overzoom -o tests/pbf/squirrels-13-2413-3077-clip.pbf --clip-polygon-file tests/pbf/squirrels-clip.json tests/pbf/squirrels-13-2413-3077.pbf 13/2413/3077 13/2413/3077
|
|
||||||
cmp tests/pbf/squirrels-13-2413-3077-clip.pbf /dev/null # clipped away
|
|
||||||
rm tests/pbf/squirrels-13-2413-3077-clip.pbf
|
|
||||||
# Deduplication by feature ID
|
# Deduplication by feature ID
|
||||||
./tippecanoe -z0 -f -e tests/pbf/1.json.dir -l layer tests/pbf/1.json
|
./tippecanoe -z0 -f -e tests/pbf/1.json.dir -l layer tests/pbf/1.json
|
||||||
./tippecanoe -z0 -f -e tests/pbf/2.json.dir -l layer tests/pbf/2.json
|
./tippecanoe -z0 -f -e tests/pbf/2.json.dir -l layer tests/pbf/2.json
|
||||||
@@ -588,145 +502,6 @@ join-test: tippecanoe tippecanoe-decode tile-join
|
|||||||
./tippecanoe-decode -x generator tests/ne_110m_ocean/join/joined.mbtiles > tests/ne_110m_ocean/join/joined.mbtiles.json.check
|
./tippecanoe-decode -x generator tests/ne_110m_ocean/join/joined.mbtiles > tests/ne_110m_ocean/join/joined.mbtiles.json.check
|
||||||
cmp tests/ne_110m_ocean/join/joined.mbtiles.json.check tests/ne_110m_ocean/join/joined.mbtiles.json
|
cmp tests/ne_110m_ocean/join/joined.mbtiles.json.check tests/ne_110m_ocean/join/joined.mbtiles.json
|
||||||
rm -f tests/ne_110m_ocean/join/ocean.mbtiles tests/ne_110m_ocean/join/countries.mbtiles tests/ne_110m_ocean/join/joined.mbtiles tests/ne_110m_ocean/join/joined.mbtiles.json.check
|
rm -f tests/ne_110m_ocean/join/ocean.mbtiles tests/ne_110m_ocean/join/countries.mbtiles tests/ne_110m_ocean/join/joined.mbtiles tests/ne_110m_ocean/join/joined.mbtiles.json.check
|
||||||
#
|
|
||||||
# Test sql join
|
|
||||||
#
|
|
||||||
./tile-join -i -f -o tests/join-sql/countries.pmtiles --join-sqlite tests/join-sql/countries.gpkg --join-table countries --join-tile-attribute ne10-admin0:name_en --join-table-expression 'lower(country)' tests/join-sql/bboxes.pmtiles
|
|
||||||
./tippecanoe-decode -x generator tests/join-sql/countries.pmtiles > tests/join-sql/countries.pmtiles.json.check
|
|
||||||
cmp tests/join-sql/countries.pmtiles.json.check tests/join-sql/countries.pmtiles.json
|
|
||||||
rm -f tests/join-sql/countries.pmtiles tests/join-sql/countries.pmtiles.json.check
|
|
||||||
#
|
|
||||||
# Test sql join with limit
|
|
||||||
#
|
|
||||||
./tile-join --join-count-limit 3 -i -f -o tests/join-sql/countries-limit3.pmtiles --join-sqlite tests/join-sql/countries.gpkg --join-table countries --join-tile-attribute ne10-admin0:name_en --join-table-expression 'lower(country)' tests/join-sql/bboxes.pmtiles
|
|
||||||
./tippecanoe-decode -x generator tests/join-sql/countries-limit3.pmtiles > tests/join-sql/countries-limit3.pmtiles.json.check
|
|
||||||
cmp tests/join-sql/countries-limit3.pmtiles.json.check tests/join-sql/countries-limit3.pmtiles.json
|
|
||||||
rm -f tests/join-sql/countries-limit3.pmtiles tests/join-sql/countries-limit3.pmtiles.json.check
|
|
||||||
|
|
||||||
accumulate-test:
|
|
||||||
# there are 144 features with POP1950 in the original dataset
|
|
||||||
test `grep '"POP1950": [0-9]' tests/ne_110m_populated_places_nulls/in.json | wc -l` == 144
|
|
||||||
# and 99 without it
|
|
||||||
test `grep '"POP1950": null' tests/ne_110m_populated_places_nulls/in.json | wc -l` == 99
|
|
||||||
./tippecanoe -yNAME -yPOP1950 -yclustered:cluster_size -yclustered:unrelated -q -z3 -r1.75 -b0 -f -e tests/pbf/accum.dir --accumulate-numeric-attributes=clustered --set-attribute '{"clustered:cluster_size":1}' --accumulate-attribute '{"clustered:cluster_size":"sum"}' --retain-points-multiplier 3 tests/ne_110m_populated_places_nulls/in.json
|
|
||||||
# at this drop rate, there are 61 points at z0 that have no POP1950s clustered onto them....
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | wc -l` == 61
|
|
||||||
# 26 of which have no POP1950 at all
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep -v 'POP1950' | wc -l` == 26
|
|
||||||
# 35 of which do have POP1950
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | grep 'POP1950' | wc -l` == 35
|
|
||||||
# plus 60 that are clustered
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep 'clustered:count:POP1950' | wc -l` == 60
|
|
||||||
# the 60 clustered POP1950s have a total count of 109
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep 'clustered:count:POP1950' | sed 's/.*"clustered:count:POP1950": //' | awk '{sum += $$1} END {print sum}'` == 109
|
|
||||||
# we have already established that there are 36 bare POP1950s
|
|
||||||
# which makes a total of 144, which is the total count expected
|
|
||||||
#
|
|
||||||
# meanwhile, regular attribute accumulation.
|
|
||||||
# there are 121 features in the z0 tile, and they all have clustered:cluster_size
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep 'clustered:cluster_size' | wc -l` == 121
|
|
||||||
# there are no features that lack it.
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep -v 'clustered:cluster_size' | wc -l` == 0
|
|
||||||
# they add up to the 243 original features
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | sed 's/.*clustered:cluster_size": //' | awk '{sum += $$1} END {print sum}'` == 243
|
|
||||||
# Make sure we do *not* accumulate a numeric attribute that already has the magic prefix:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep sum:clustered:unrelated | wc -l` == 0
|
|
||||||
# But that we *do* preserve those attributes into the output features:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep clustered:unrelated | wc -l` == 61
|
|
||||||
#
|
|
||||||
# on to the sums:
|
|
||||||
# in the original data set, the POP1950s that are present add up to 161590
|
|
||||||
test `grep '"POP1950": [0-9]' tests/ne_110m_populated_places_nulls/in.json | sed 's/.*"POP1950": //' | awk '{sum += $$1} END {print sum}' ` == 161590
|
|
||||||
# in the z0 tile, the clustered POP1950s add up to 116967
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep 'clustered:sum:POP1950' | sed 's/.*"clustered:sum:POP1950": //' | awk '{sum += $$1} END {print sum}'` == 116967
|
|
||||||
# and the non-clustered ones add up to 44623
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum.dir/0/0/0.pbf 0 0 0 | grep -v 'clustered:sum:POP1950' | grep POP1950 | sed 's/.*"POP1950": //' | awk '{sum += $$1} END {print sum}'` == 44623
|
|
||||||
# which is the correct 161590
|
|
||||||
#
|
|
||||||
# OK, so do these still hold after megatile filtering?
|
|
||||||
./tippecanoe-overzoom --accumulate-numeric-attributes=clustered --accumulate-attribute '{"clustered:cluster_size":"sum"}' -m -o tests/pbf/accum-0-0-0.pbf tests/pbf/accum.dir/0/0/0.pbf 0/0/0 0/0/0
|
|
||||||
# Now there are 40 features with POP1950 clusters
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep 'clustered:count:POP1950' | wc -l` == 40
|
|
||||||
# There are 4 with bare POP1950
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | grep 'POP1950' | wc -l` == 4
|
|
||||||
# And 2 with no POP1950 at all
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep -v 'POP1950' | wc -l` == 2
|
|
||||||
# (which is the same as you get if you don't use -retain-points-multiplier when creating the tileset)
|
|
||||||
#
|
|
||||||
# the clustered and megatile-filtered POP1950s add up to 146370
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep 'clustered:sum:POP1950' | sed 's/.*"clustered:sum:POP1950": //' | awk '{sum += $$1} END {print sum}'` == 146370
|
|
||||||
# the non-clustered but megatile-filtered POP1950s add up to 15220
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep -v 'clustered:sum:POP1950' | grep POP1950 | sed 's/.*"POP1950": //' | awk '{sum += $$1} END {print sum}'` == 15220
|
|
||||||
# which add up to 161590 so we have the right global total
|
|
||||||
# Make sure we do *not* accumulate a numeric attribute that already has the magic prefix:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep sum:clustered:unrelated | wc -l` == 0
|
|
||||||
# But that we *do* preserve those attributes into the output features:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep clustered:unrelated | wc -l` == 22
|
|
||||||
# the cluster sizes still add up to the 243 original features
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | sed 's/.*clustered:cluster_size": //' | awk '{sum += $$1} END {print sum}'` == 243
|
|
||||||
#
|
|
||||||
# We actually want to serve point tiles without the numeric accumulations,
|
|
||||||
# but with cluster size, so test that combination:
|
|
||||||
./tippecanoe-overzoom --accumulate-attribute '{"clustered:cluster_size":"sum"}' --exclude-prefix clustered:sum --exclude-prefix clustered:count --exclude-prefix clustered:min --exclude-prefix clustered:max --exclude-prefix clustered:mean -m -o tests/pbf/accum-0-0-0.pbf tests/pbf/accum.dir/0/0/0.pbf 0/0/0 0/0/0
|
|
||||||
# There are no POP1950 clusters
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep 'clustered:count:POP1950' | wc -l` == 0
|
|
||||||
# But there are still 28 with bare POP1950
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | grep 'POP1950' | wc -l` == 28
|
|
||||||
# And 18 with no POP1950 at all
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | grep -v 'POP1950' | wc -l` == 18
|
|
||||||
# which matches the 46 features that you get if you tile without --retain-points-multiplier.
|
|
||||||
# the cluster sizes still add up to the 243 original features
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/accum-0-0-0.pbf 0 0 0 | sed 's/.*clustered:cluster_size": //' | awk '{sum += $$1} END {print sum}'` == 243
|
|
||||||
#
|
|
||||||
# Now on to binning!
|
|
||||||
./tippecanoe-overzoom --assign-to-bins tests/pbf/h3-0-0-0.geojson --accumulate-numeric-attributes=clustered --accumulate-attribute '{"clustered:cluster_size":"sum"}' -o tests/pbf/bins-0-0-0.pbf tests/pbf/accum.dir/0/0/0.pbf 0/0/0 0/0/0
|
|
||||||
# Now there are 30 bins with POP1950 clusters
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep 'clustered:count:POP1950' | wc -l` == 41
|
|
||||||
# There are none with bare POP1950 (which is expected; we should only have summary statistics)
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | grep 'POP1950' | wc -l` == 0
|
|
||||||
# And 4 with no POP1950 at all
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep -v 'POP1950' | wc -l` == 3
|
|
||||||
#
|
|
||||||
# the clustered and megatile-filtered and binned POP1950s add up to 161590
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep 'clustered:sum:POP1950' | sed 's/.*"clustered:sum:POP1950": //' | awk '{sum += $$1} END {print sum}'` == 161590
|
|
||||||
# which is the right global total
|
|
||||||
# Make sure we do *not* accumulate a numeric attribute that already has the magic prefix:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep sum:clustered:unrelated | wc -l` == 0
|
|
||||||
# And those attributes do *not* make it onto the bins
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep clustered:unrelated | wc -l` == 0
|
|
||||||
# the cluster sizes still add up to the 243 original features
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | sed 's/.*clustered:cluster_size": //' | awk '{sum += $$1} END {print sum}'` == 243
|
|
||||||
#
|
|
||||||
# Binning with attribute stripping
|
|
||||||
./tippecanoe-overzoom -y clustered:count:POP1950 -y clustered:sum:POP1950 -y POP1950 -y clustered:cluster_size --assign-to-bins tests/pbf/h3-0-0-0.geojson --accumulate-numeric-attributes=clustered --accumulate-attribute '{"clustered:cluster_size":"sum"}' -o tests/pbf/bins-0-0-0.pbf tests/pbf/accum.dir/0/0/0.pbf 0/0/0 0/0/0
|
|
||||||
# Now there are 30 bins with POP1950 clusters
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep 'clustered:count:POP1950' | wc -l` == 41
|
|
||||||
# There are none with bare POP1950 (which is expected; we should only have summary statistics)
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep -v 'clustered:count:POP1950' | grep 'POP1950' | wc -l` == 0
|
|
||||||
# And 4 with no POP1950 at all
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep -v 'POP1950' | wc -l` == 3
|
|
||||||
#
|
|
||||||
# the clustered and megatile-filtered and binned POP1950s add up to 161590
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep 'clustered:sum:POP1950' | sed 's/.*"clustered:sum:POP1950": //' | awk '{sum += $$1} END {print sum}'` == 161590
|
|
||||||
# which is the right global total
|
|
||||||
# Make sure we do *not* accumulate a numeric attribute that already has the magic prefix:
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep sum:clustered:unrelated | wc -l` == 0
|
|
||||||
# And those attributes do *not* make it onto the bins
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | grep clustered:unrelated | wc -l` == 0
|
|
||||||
# the cluster sizes still add up to the 243 original features
|
|
||||||
test `./tippecanoe-decode -c tests/pbf/bins-0-0-0.pbf 0 0 0 | sed 's/.*clustered:cluster_size": //' | awk '{sum += $$1} END {print sum}'` == 243
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# A tile where the counts and means were previously wrong:
|
|
||||||
./tippecanoe-overzoom --accumulate-numeric-attributes=felt -m -o tests/pbf/yearbuilt-accum.pbf tests/pbf/yearbuilt.pbf 0/0/0 0/0/0
|
|
||||||
./tippecanoe-decode tests/pbf/yearbuilt-accum.pbf 0 0 0 > tests/pbf/yearbuilt-accum.pbf.json.check
|
|
||||||
cmp tests/pbf/yearbuilt-accum.pbf.json.check tests/pbf/yearbuilt-accum.pbf.json
|
|
||||||
rm tests/pbf/yearbuilt-accum.pbf tests/pbf/yearbuilt-accum.pbf.json.check
|
|
||||||
# Same tile, with attribute stripping
|
|
||||||
./tippecanoe-overzoom --accumulate-numeric-attributes=felt -y bldgsqft -y felt:sum:bldgsqft -m -o tests/pbf/yearbuilt-accum-bldgsqft.pbf tests/pbf/yearbuilt.pbf 0/0/0 0/0/0
|
|
||||||
./tippecanoe-decode tests/pbf/yearbuilt-accum-bldgsqft.pbf 0 0 0 > tests/pbf/yearbuilt-accum-bldgsqft.pbf.json.check
|
|
||||||
cmp tests/pbf/yearbuilt-accum-bldgsqft.pbf.json.check tests/pbf/yearbuilt-accum-bldgsqft.pbf.json
|
|
||||||
rm tests/pbf/yearbuilt-accum-bldgsqft.pbf tests/pbf/yearbuilt-accum-bldgsqft.pbf.json.check
|
|
||||||
|
|
||||||
join-filter-test: tippecanoe tippecanoe-decode tile-join
|
join-filter-test: tippecanoe tippecanoe-decode tile-join
|
||||||
# Comes out different from the direct tippecanoe run because null attributes are lost
|
# Comes out different from the direct tippecanoe run because null attributes are lost
|
||||||
|
|||||||
@@ -1214,47 +1214,6 @@ bool pnpoly_mp(drawvec const &geom, long long x, long long y) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
clipbbox parse_clip_poly(std::string arg) {
|
|
||||||
json_pull *jp = json_begin_string(arg.c_str());
|
|
||||||
json_object *j = json_read_tree(jp);
|
|
||||||
if (j == NULL) {
|
|
||||||
fprintf(stderr, "Expected JSON object, not %s\n", arg.c_str());
|
|
||||||
exit(EXIT_ARGS);
|
|
||||||
}
|
|
||||||
if (j->type != JSON_HASH) {
|
|
||||||
fprintf(stderr, "Expected JSON geometry object, not %s\n", arg.c_str());
|
|
||||||
exit(EXIT_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<int, drawvec> parsed_geometry = parse_geometry(j, jp, j, 0, 0, 0, 1LL << 32, false, false);
|
|
||||||
json_end(jp);
|
|
||||||
|
|
||||||
clipbbox out;
|
|
||||||
out.minx = LLONG_MAX;
|
|
||||||
out.miny = LLONG_MAX;
|
|
||||||
out.maxx = LLONG_MIN;
|
|
||||||
out.maxy = LLONG_MIN;
|
|
||||||
for (auto const &d : parsed_geometry.second) {
|
|
||||||
if (d.op == VT_MOVETO || d.op == VT_LINETO) {
|
|
||||||
if (d.x < out.minx) {
|
|
||||||
out.minx = d.x;
|
|
||||||
}
|
|
||||||
if (d.y < out.miny) {
|
|
||||||
out.miny = d.y;
|
|
||||||
}
|
|
||||||
if (d.x > out.maxx) {
|
|
||||||
out.maxx = d.x;
|
|
||||||
}
|
|
||||||
if (d.y > out.maxy) {
|
|
||||||
out.maxy = d.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.dv = std::move(parsed_geometry.second);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int ny,
|
std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int ny,
|
||||||
int detail_or_unspecified, int buffer,
|
int detail_or_unspecified, int buffer,
|
||||||
std::set<std::string> const &keep,
|
std::set<std::string> const &keep,
|
||||||
@@ -1266,9 +1225,9 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
|
|||||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||||
std::vector<std::string> const &unidecode_data, double simplification,
|
std::vector<std::string> const &unidecode_data, double simplification,
|
||||||
double tiny_polygon_size,
|
double tiny_polygon_size,
|
||||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
std::vector<mvt_layer> const &unused2, std::string const &unused3,
|
||||||
std::string const &accumulate_numeric, size_t feature_limit,
|
std::string const &unused, size_t feature_limit,
|
||||||
std::vector<clipbbox> const &clipbboxes,
|
std::vector<clipbbox> const &unused4,
|
||||||
bool deduplicate_by_id) {
|
bool deduplicate_by_id) {
|
||||||
std::vector<source_tile> decoded;
|
std::vector<source_tile> decoded;
|
||||||
|
|
||||||
@@ -1295,7 +1254,7 @@ std::string overzoom(std::vector<input_tile> const &tiles, int nz, int nx, int n
|
|||||||
decoded.push_back(out);
|
decoded.push_back(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, bins, bin_by_id_list, accumulate_numeric, feature_limit, clipbboxes, deduplicate_by_id);
|
return overzoom(decoded, nz, nx, ny, detail_or_unspecified, buffer, keep, exclude, exclude_prefix, do_compress, next_overzoomed_tiles, demultiply, filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, unused2, unused3, unused, feature_limit, unused4, deduplicate_by_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// like a minimal serial_feature, but with mvt_feature-style attributes
|
// like a minimal serial_feature, but with mvt_feature-style attributes
|
||||||
@@ -1330,152 +1289,6 @@ static bool should_keep(std::string const &key,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_mean(mvt_feature &feature, mvt_layer &layer, std::string const &accumulate_numeric,
|
|
||||||
std::set<std::string> const &keep, std::set<std::string> const &exclude,
|
|
||||||
std::vector<std::string> const &exclude_prefix) {
|
|
||||||
std::string accumulate_numeric_colon = accumulate_numeric + ":";
|
|
||||||
|
|
||||||
std::unordered_map<std::string, size_t> attributes;
|
|
||||||
for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) {
|
|
||||||
std::string const &key = layer.keys[feature.tags[i]];
|
|
||||||
if (starts_with(key, accumulate_numeric_colon)) {
|
|
||||||
attributes.emplace(key, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i + 1 < feature.tags.size(); i += 2) {
|
|
||||||
std::string accumulate_numeric_sum_colon = accumulate_numeric + ":sum:";
|
|
||||||
|
|
||||||
std::string const &key = layer.keys[feature.tags[i]];
|
|
||||||
if (starts_with(key, accumulate_numeric_sum_colon)) {
|
|
||||||
std::string trunc = key.substr(accumulate_numeric_sum_colon.size());
|
|
||||||
auto const f = attributes.find(accumulate_numeric + ":count:" + trunc);
|
|
||||||
if (f != attributes.end()) {
|
|
||||||
mvt_value const &sum = layer.values[feature.tags[i + 1]];
|
|
||||||
mvt_value const &count = layer.values[feature.tags[f->second + 1]];
|
|
||||||
double count_val = mvt_value_to_double(count);
|
|
||||||
if (count_val <= 0) {
|
|
||||||
fprintf(stderr, "can't happen: count is %s (type %d)\n", count.toString().c_str(), count.type);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
mvt_value mean;
|
|
||||||
mean.type = mvt_double;
|
|
||||||
mean.numeric_value.double_value = mvt_value_to_double(sum) / count_val;
|
|
||||||
|
|
||||||
if (should_keep(key, keep, exclude, exclude_prefix)) {
|
|
||||||
layer.tag(feature, accumulate_numeric + ":mean:" + trunc, mean);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// accumulate :sum:, :min:, :max:, and :count: versions of the specified attribute
|
|
||||||
static void preserve_numeric(const std::string &key, const mvt_value &val, // numeric attribute being accumulated
|
|
||||||
std::vector<std::shared_ptr<std::string>> &full_keys, // keys of feature being accumulated onto
|
|
||||||
std::vector<mvt_value> &full_values, // values of features being accumulated onto
|
|
||||||
const std::string &accumulate_numeric, // prefix of accumulations
|
|
||||||
std::set<std::string> &keys, // key presence in the source feature
|
|
||||||
std::map<std::string, size_t> &numeric_out_field, // key index in the output feature
|
|
||||||
key_pool &key_pool,
|
|
||||||
std::set<std::string> const &keep, std::set<std::string> const &exclude,
|
|
||||||
std::vector<std::string> const &exclude_prefix) {
|
|
||||||
// If this is a numeric attribute, but there is also a prefix:sum (etc.) for the
|
|
||||||
// same attribute, we want to use that one instead of this one.
|
|
||||||
|
|
||||||
for (auto const &op : numeric_operations) {
|
|
||||||
std::string compound_key = accumulate_numeric + ":" + op.first + ":" + key;
|
|
||||||
auto compound_found = keys.find(compound_key);
|
|
||||||
if (compound_found != keys.end()) {
|
|
||||||
// found, so skip this one
|
|
||||||
} else {
|
|
||||||
// not found, so accumulate this one
|
|
||||||
|
|
||||||
// if this is already prefixed, strip off the prefix
|
|
||||||
// if it is the right one, and skip the attribute if
|
|
||||||
// it is the wrong one.
|
|
||||||
|
|
||||||
std::string outkey = key;
|
|
||||||
bool starting_from_accumulation;
|
|
||||||
|
|
||||||
if (starts_with(outkey, accumulate_numeric + ":")) {
|
|
||||||
std::string prefix = accumulate_numeric + ":" + op.first + ":";
|
|
||||||
if (starts_with(outkey, prefix)) {
|
|
||||||
outkey = outkey.substr(prefix.size());
|
|
||||||
starting_from_accumulation = true; // from a subaccumulation
|
|
||||||
} else {
|
|
||||||
continue; // to next operation
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
starting_from_accumulation = false; // from a plain value
|
|
||||||
}
|
|
||||||
// and then put it back on for the output field
|
|
||||||
std::string prefixed = accumulate_numeric + ":" + op.first + ":" + outkey;
|
|
||||||
|
|
||||||
if (!should_keep(prefixed, keep, exclude, exclude_prefix)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does it exist in the output feature already?
|
|
||||||
|
|
||||||
auto prefixed_attr = numeric_out_field.find(prefixed);
|
|
||||||
if (prefixed_attr == numeric_out_field.end()) {
|
|
||||||
// No? Does it exist unprefixed in the output feature already?
|
|
||||||
|
|
||||||
auto out_attr = numeric_out_field.find(outkey);
|
|
||||||
if (out_attr == numeric_out_field.end()) {
|
|
||||||
// not present at all, so copy our value to the prefixed output
|
|
||||||
numeric_out_field.emplace(prefixed, full_keys.size());
|
|
||||||
full_keys.push_back(key_pool.pool(prefixed));
|
|
||||||
|
|
||||||
if (op.second == op_count) {
|
|
||||||
if (starting_from_accumulation) {
|
|
||||||
// copy our count
|
|
||||||
full_values.push_back(val);
|
|
||||||
} else {
|
|
||||||
// new count of 1
|
|
||||||
full_values.push_back(mvt_value(1));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
full_values.push_back(val);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// exists unprefixed, so copy it, and then accumulate on our value
|
|
||||||
numeric_out_field.emplace(prefixed, full_keys.size());
|
|
||||||
full_keys.push_back(key_pool.pool(prefixed));
|
|
||||||
|
|
||||||
if (op.second == op_count) {
|
|
||||||
mvt_value v;
|
|
||||||
if (starting_from_accumulation) {
|
|
||||||
// sum our count onto the existing 1
|
|
||||||
v = mvt_value(1 + mvt_value_to_long_long(val));
|
|
||||||
} else {
|
|
||||||
// sum our 1 onto the existing 1
|
|
||||||
v = mvt_value(2);
|
|
||||||
}
|
|
||||||
full_values.push_back(v);
|
|
||||||
} else {
|
|
||||||
full_values.push_back(full_values[out_attr->second]);
|
|
||||||
preserve_attribute(op.second, prefixed, val, full_keys, full_values, key_pool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// exists, so accumulate on our value
|
|
||||||
if (op.second == op_count) {
|
|
||||||
if (starting_from_accumulation) {
|
|
||||||
// sum our count onto the existing count
|
|
||||||
full_values[prefixed_attr->second] = mvt_value(mvt_value_to_long_long(full_values[prefixed_attr->second]) + mvt_value_to_long_long(val));
|
|
||||||
} else {
|
|
||||||
full_values[prefixed_attr->second] = mvt_value(mvt_value_to_long_long(full_values[prefixed_attr->second]) + 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
preserve_attribute(op.second, prefixed, val, full_keys, full_values, key_pool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_closepath_from_mvt(drawvec &geom) {
|
static void handle_closepath_from_mvt(drawvec &geom) {
|
||||||
// mvt geometries close polygons with a mvt_closepath operation
|
// mvt geometries close polygons with a mvt_closepath operation
|
||||||
// tippecanoe-internal geometries close polygons with a lineto to the initial point
|
// tippecanoe-internal geometries close polygons with a lineto to the initial point
|
||||||
@@ -1497,9 +1310,9 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
std::set<std::string> const &exclude,
|
std::set<std::string> const &exclude,
|
||||||
std::vector<std::string> const &exclude_prefix,
|
std::vector<std::string> const &exclude_prefix,
|
||||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||||
std::string const &accumulate_numeric,
|
std::string const &,
|
||||||
key_pool &key_pool, int buffer, bool include_nonaggregate,
|
key_pool &key_pool, int buffer, bool include_nonaggregate,
|
||||||
std::vector<clipbbox> const &clipbboxes, int nz, int nx, int ny,
|
std::vector<clipbbox> const &, int, int, int,
|
||||||
std::set<unsigned long long> *deduplicate_ids) {
|
std::set<unsigned long long> *deduplicate_ids) {
|
||||||
// Add geometry to output feature
|
// Add geometry to output feature
|
||||||
|
|
||||||
@@ -1507,7 +1320,7 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
int t = features[0].t;
|
int t = features[0].t;
|
||||||
|
|
||||||
bool fix_polygons = false;
|
bool fix_polygons = false;
|
||||||
if ((buffer >= 0 || clipbboxes.size() > 0) && t == VT_POLYGON) {
|
if ((buffer >= 0) && t == VT_POLYGON) {
|
||||||
fix_polygons = true;
|
fix_polygons = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1528,48 +1341,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
geom = remove_noop(geom, t, 0);
|
geom = remove_noop(geom, t, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipbboxes.size() != 0) {
|
|
||||||
// bounding box is in world coordinates at world scale
|
|
||||||
// feature is in local coordinates at tile scale
|
|
||||||
|
|
||||||
long long dx = (long long) nx << (32 - nz);
|
|
||||||
long long dy = (long long) ny << (32 - nz);
|
|
||||||
double scale = (double) outlayer.extent / (1LL << (32 - nz));
|
|
||||||
|
|
||||||
for (auto const &c_world : clipbboxes) {
|
|
||||||
clipbbox c = c_world;
|
|
||||||
|
|
||||||
c.minx = std::llround((c_world.minx - dx) * scale);
|
|
||||||
c.miny = std::llround((c_world.miny - dy) * scale);
|
|
||||||
c.maxx = std::llround((c_world.maxx - dx) * scale);
|
|
||||||
c.maxy = std::llround((c_world.maxy - dy) * scale);
|
|
||||||
|
|
||||||
for (auto &p : c.dv) {
|
|
||||||
p.x = std::llround((p.x - dx) * scale);
|
|
||||||
p.y = std::llround((p.y - dy) * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == VT_POLYGON) {
|
|
||||||
geom = simple_clip_poly(geom, c.minx, c.miny, c.maxx, c.maxy, false);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_poly_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
} else if (t == VT_LINE) {
|
|
||||||
geom = clip_lines(geom, c.minx, c.miny, c.maxx, c.maxy);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_lines_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
} else if (t == VT_POINT) {
|
|
||||||
geom = clip_point(geom, c.minx, c.miny, c.maxx, c.maxy);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_point_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
geom = remove_noop(geom, t, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fix_polygons) {
|
if (fix_polygons) {
|
||||||
geom = clean_or_clip_poly(geom, 0, 0, false, false);
|
geom = clean_or_clip_poly(geom, 0, 0, false, false);
|
||||||
geom = close_poly(geom);
|
geom = close_poly(geom);
|
||||||
@@ -1599,7 +1370,7 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
|
|
||||||
outfeature.seq = features[0].seq;
|
outfeature.seq = features[0].seq;
|
||||||
|
|
||||||
if (attribute_accum.size() > 0 || accumulate_numeric.size() > 0) {
|
if (attribute_accum.size() > 0) {
|
||||||
// convert the attributes of the output feature
|
// convert the attributes of the output feature
|
||||||
// from layer references to a vector so they can have
|
// from layer references to a vector so they can have
|
||||||
// attributes from the other features of the
|
// attributes from the other features of the
|
||||||
@@ -1617,11 +1388,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
// this attribute has an accumulator, so convert it
|
// this attribute has an accumulator, so convert it
|
||||||
full_keys.push_back(key_pool.pool(f.layer->keys[f.tags[i]]));
|
full_keys.push_back(key_pool.pool(f.layer->keys[f.tags[i]]));
|
||||||
full_values.push_back(f.layer->values[f.tags[i + 1]]);
|
full_values.push_back(f.layer->values[f.tags[i + 1]]);
|
||||||
} else if (accumulate_numeric.size() > 0 && f.layer->values[f.tags[i + 1]].is_numeric()) {
|
|
||||||
// convert numeric for accumulation
|
|
||||||
numeric_out_field.emplace(key, full_keys.size());
|
|
||||||
full_keys.push_back(key_pool.pool(key));
|
|
||||||
full_values.push_back(f.layer->values[f.tags[i + 1]]);
|
|
||||||
} else if (include_nonaggregate) {
|
} else if (include_nonaggregate) {
|
||||||
// otherwise just tag it directly onto the output feature
|
// otherwise just tag it directly onto the output feature
|
||||||
outlayer.tag(outfeature, f.layer->keys[f.tags[i]], f.layer->values[f.tags[i + 1]]);
|
outlayer.tag(outfeature, f.layer->keys[f.tags[i]], f.layer->values[f.tags[i + 1]]);
|
||||||
@@ -1650,14 +1416,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
if (found != attribute_accum.end()) {
|
if (found != attribute_accum.end()) {
|
||||||
mvt_value val = features[i].layer->values[features[i].tags[j + 1]];
|
mvt_value val = features[i].layer->values[features[i].tags[j + 1]];
|
||||||
preserve_attribute(found->second, key, val, full_keys, full_values, key_pool);
|
preserve_attribute(found->second, key, val, full_keys, full_values, key_pool);
|
||||||
} else if (accumulate_numeric.size() > 0) {
|
|
||||||
const mvt_value &val = features[i].layer->values[features[i].tags[j + 1]];
|
|
||||||
if (val.is_numeric()) {
|
|
||||||
preserve_numeric(key, val, full_keys, full_values,
|
|
||||||
accumulate_numeric,
|
|
||||||
keys, numeric_out_field, key_pool,
|
|
||||||
keep, exclude, exclude_prefix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1671,10 +1429,6 @@ static bool feature_out(std::vector<tile_feature> const &features, mvt_layer &ou
|
|||||||
outlayer.tag(outfeature, *full_keys[i], full_values[i]);
|
outlayer.tag(outfeature, *full_keys[i], full_values[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accumulate_numeric.size() > 0) {
|
|
||||||
add_mean(outfeature, outlayer, accumulate_numeric, keep, exclude, exclude_prefix);
|
|
||||||
}
|
|
||||||
} else if (include_nonaggregate) {
|
} else if (include_nonaggregate) {
|
||||||
for (size_t i = 0; i + 1 < features[0].tags.size(); i += 2) {
|
for (size_t i = 0; i + 1 < features[0].tags.size(); i += 2) {
|
||||||
if (should_keep(features[0].layer->keys[features[0].tags[i]], keep, exclude, exclude_prefix)) {
|
if (should_keep(features[0].layer->keys[features[0].tags[i]], keep, exclude, exclude_prefix)) {
|
||||||
@@ -1696,316 +1450,6 @@ static struct preservecmp {
|
|||||||
}
|
}
|
||||||
} preservecmp;
|
} preservecmp;
|
||||||
|
|
||||||
struct index_event {
|
|
||||||
unsigned long long where;
|
|
||||||
enum index_event_kind {
|
|
||||||
ENTER = 0, // new bin in is now active
|
|
||||||
CHECK, // point needs to be checked against active bins
|
|
||||||
EXIT // bin has ceased to be active
|
|
||||||
} kind;
|
|
||||||
size_t layer;
|
|
||||||
size_t feature;
|
|
||||||
long long xmin, ymin, xmax, ymax;
|
|
||||||
|
|
||||||
index_event(unsigned long long where_, index_event_kind kind_, size_t layer_, size_t feature_,
|
|
||||||
long long xmin_, long long ymin_, long long xmax_, long long ymax_)
|
|
||||||
: where(where_), kind(kind_), layer(layer_), feature(feature_), xmin(xmin_), ymin(ymin_), xmax(xmax_), ymax(ymax_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const index_event &ie) const {
|
|
||||||
if (where < ie.where) {
|
|
||||||
return true;
|
|
||||||
} else if (where == ie.where) {
|
|
||||||
if (kind < ie.kind) {
|
|
||||||
return true;
|
|
||||||
} else if (kind == ie.kind) {
|
|
||||||
if (layer < ie.layer) {
|
|
||||||
return true;
|
|
||||||
} else if (layer == ie.layer) {
|
|
||||||
if (feature < ie.feature) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct active_bin {
|
|
||||||
size_t layer;
|
|
||||||
size_t feature;
|
|
||||||
|
|
||||||
active_bin(size_t layer_, size_t feature_)
|
|
||||||
: layer(layer_), feature(feature_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const active_bin &o) const {
|
|
||||||
if (layer < o.layer) {
|
|
||||||
return true;
|
|
||||||
} else if (layer == o.layer) {
|
|
||||||
if (feature < o.feature) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t outfeature;
|
|
||||||
long long xmin, ymin, xmax, ymax;
|
|
||||||
size_t counter = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void get_quadkey_bounds(long long xmin, long long ymin, long long xmax, long long ymax,
|
|
||||||
unsigned long long *start, unsigned long long *end) {
|
|
||||||
if (xmin < 0 || ymin < 0 || xmax >= 1LL << 32 || ymax >= 1LL << 32) {
|
|
||||||
*start = 0;
|
|
||||||
*end = ULLONG_MAX;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*start = encode_quadkey(xmin, ymin);
|
|
||||||
*end = encode_quadkey(xmax, ymax);
|
|
||||||
|
|
||||||
for (ssize_t i = 62; i >= 0; i -= 2) {
|
|
||||||
if ((*start & (3LL << i)) != (*end & (3LL << i))) {
|
|
||||||
for (; i >= 0; i -= 2) {
|
|
||||||
*start &= ~(3LL << i);
|
|
||||||
*end |= 3LL << i;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool bbox_intersects(long long x1min, long long y1min, long long x1max, long long y1max,
|
|
||||||
long long x2min, long long y2min, long long x2max, long long y2max) {
|
|
||||||
if (x1max < x2min) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (x2max < x1min) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (y1max < y2min) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (y2max < y1min) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<size_t> parse_ids_string(mvt_value const &v) {
|
|
||||||
std::vector<size_t> out;
|
|
||||||
std::string s = v.toString();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < s.size(); i++) {
|
|
||||||
if (i == 0 || s[i - 1] == ',') {
|
|
||||||
out.push_back(atoll(s.c_str() + i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
mvt_tile assign_to_bins(mvt_tile &features,
|
|
||||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
|
||||||
int z, int x, int y,
|
|
||||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
|
||||||
std::string const &accumulate_numeric,
|
|
||||||
std::set<std::string> keep,
|
|
||||||
std::set<std::string> exclude,
|
|
||||||
std::vector<std::string> exclude_prefix,
|
|
||||||
int buffer, std::vector<clipbbox> const &clipbboxes) {
|
|
||||||
std::vector<index_event> events;
|
|
||||||
key_pool key_pool;
|
|
||||||
|
|
||||||
if (bins.size() == 0) {
|
|
||||||
return mvt_tile();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index bins
|
|
||||||
for (size_t i = 0; i < bins.size(); i++) {
|
|
||||||
for (size_t j = 0; j < bins[i].features.size(); j++) {
|
|
||||||
long long xmin, ymin, xmax, ymax;
|
|
||||||
unsigned long long start, end;
|
|
||||||
|
|
||||||
get_bbox(bins[i].features[j].geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, bins[i].detail());
|
|
||||||
get_quadkey_bounds(xmin, ymin, xmax, ymax, &start, &end);
|
|
||||||
events.emplace_back(start, index_event::ENTER, i, j, xmin, ymin, xmax, ymax);
|
|
||||||
events.emplace_back(end, index_event::EXIT, i, j, xmin, ymin, xmax, ymax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<unsigned long long, std::pair<size_t, size_t>> fid_to_feature;
|
|
||||||
|
|
||||||
// Index points
|
|
||||||
for (size_t i = 0; i < features.layers.size(); i++) {
|
|
||||||
for (size_t j = 0; j < features.layers[i].features.size(); j++) {
|
|
||||||
long long xmin, ymin, xmax, ymax;
|
|
||||||
unsigned long long start, end;
|
|
||||||
|
|
||||||
if (features.layers[i].features[j].geometry.size() > 0) {
|
|
||||||
if (features.layers[i].features[j].has_id) {
|
|
||||||
fid_to_feature.emplace(features.layers[i].features[j].id, std::make_pair(i, j));
|
|
||||||
}
|
|
||||||
|
|
||||||
get_bbox(features.layers[i].features[j].geometry, &xmin, &ymin, &xmax, &ymax, z, x, y, features.layers[i].detail());
|
|
||||||
get_quadkey_bounds(xmin, ymin, xmax, ymax, &start, &end);
|
|
||||||
events.emplace_back(start, index_event::CHECK, i, j, xmin, ymin, xmax, ymax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(events.begin(), events.end());
|
|
||||||
std::set<active_bin> active;
|
|
||||||
|
|
||||||
mvt_layer outlayer;
|
|
||||||
outlayer.extent = bins[0].extent;
|
|
||||||
outlayer.version = 2;
|
|
||||||
outlayer.name = features.layers[0].name;
|
|
||||||
|
|
||||||
std::vector<std::vector<tile_feature>> outfeatures;
|
|
||||||
|
|
||||||
for (auto &e : events) {
|
|
||||||
if (e.kind == index_event::ENTER) {
|
|
||||||
active_bin a(e.layer, e.feature);
|
|
||||||
a.xmin = e.xmin;
|
|
||||||
a.ymin = e.ymin;
|
|
||||||
a.xmax = e.xmax;
|
|
||||||
a.ymax = e.ymax;
|
|
||||||
|
|
||||||
const mvt_feature &bin = bins[e.layer].features[e.feature];
|
|
||||||
|
|
||||||
{
|
|
||||||
tile_feature outfeature;
|
|
||||||
for (auto const &g : bin.geometry) {
|
|
||||||
outfeature.geom.emplace_back(g.op, g.x, g.y);
|
|
||||||
}
|
|
||||||
outfeature.t = bin.type;
|
|
||||||
outfeature.has_id = bin.has_id;
|
|
||||||
outfeature.id = bin.id;
|
|
||||||
outfeature.tags = bin.tags;
|
|
||||||
outfeature.layer = &bins[e.layer];
|
|
||||||
outfeature.seq = e.feature;
|
|
||||||
|
|
||||||
a.outfeature = outfeatures.size();
|
|
||||||
outfeatures.push_back({std::move(outfeature)});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bin_by_id_list.size() > 0) {
|
|
||||||
for (size_t k = 0; k < bin.tags.size(); k += 2) {
|
|
||||||
if (bins[e.layer].keys[bin.tags[k]] == bin_by_id_list) {
|
|
||||||
std::vector<size_t> ids = parse_ids_string(bins[e.layer].values[bin.tags[k + 1]]);
|
|
||||||
for (auto &id : ids) {
|
|
||||||
auto f = fid_to_feature.find(id);
|
|
||||||
if (f != fid_to_feature.end()) {
|
|
||||||
mvt_feature &feature = features.layers[f->second.first].features[f->second.second];
|
|
||||||
if (feature.geometry.size() > 0) {
|
|
||||||
tile_feature outfeature;
|
|
||||||
for (auto const &g : feature.geometry) {
|
|
||||||
outfeature.geom.emplace_back(g.op, g.x, g.y);
|
|
||||||
}
|
|
||||||
feature.geometry.clear();
|
|
||||||
outfeature.t = feature.type;
|
|
||||||
outfeature.has_id = feature.has_id;
|
|
||||||
outfeature.id = feature.id;
|
|
||||||
outfeature.tags = feature.tags;
|
|
||||||
outfeature.layer = &features.layers[e.layer];
|
|
||||||
outfeature.seq = e.feature;
|
|
||||||
outfeatures.back().push_back(std::move(outfeature));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
active.insert(std::move(a));
|
|
||||||
} else if (e.kind == index_event::CHECK) {
|
|
||||||
if (bin_by_id_list.size() > 0) {
|
|
||||||
continue; // only bin by id, not geometrically
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const &feature = features.layers[e.layer].features[e.feature];
|
|
||||||
|
|
||||||
if (feature.geometry.size() == 0) {
|
|
||||||
// already assigned by ID
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we can't find a real match,
|
|
||||||
// assign points to the most nearby bin
|
|
||||||
ssize_t which_outfeature = outfeatures.size() - 1;
|
|
||||||
|
|
||||||
for (auto const &a : active) {
|
|
||||||
auto const &bin = bins[a.layer].features[a.feature];
|
|
||||||
|
|
||||||
if (bbox_intersects(e.xmin, e.ymin, e.xmax, e.ymax,
|
|
||||||
a.xmin, a.ymin, a.xmax, a.ymax)) {
|
|
||||||
if (pnpoly_mp(bin.geometry, feature.geometry[0].x, feature.geometry[0].y)) {
|
|
||||||
which_outfeature = a.outfeature;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (which_outfeature >= 0) {
|
|
||||||
tile_feature outfeature;
|
|
||||||
for (auto const &g : feature.geometry) {
|
|
||||||
outfeature.geom.emplace_back(g.op, g.x, g.y);
|
|
||||||
}
|
|
||||||
outfeature.t = feature.type;
|
|
||||||
outfeature.has_id = feature.has_id;
|
|
||||||
outfeature.id = feature.id;
|
|
||||||
outfeature.tags = feature.tags;
|
|
||||||
outfeature.layer = &features.layers[e.layer];
|
|
||||||
outfeature.seq = e.feature;
|
|
||||||
outfeatures[which_outfeature].push_back(std::move(outfeature));
|
|
||||||
}
|
|
||||||
} else /* EXIT */ {
|
|
||||||
auto const &found = active.find({e.layer, e.feature});
|
|
||||||
if (found != active.end()) {
|
|
||||||
active.erase(found);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "event mismatch: can't happen\n");
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < outfeatures.size(); i++) {
|
|
||||||
if (outfeatures[i].size() > 1) {
|
|
||||||
if (feature_out(outfeatures[i], outlayer,
|
|
||||||
keep, exclude, exclude_prefix, attribute_accum,
|
|
||||||
accumulate_numeric, key_pool, buffer, true,
|
|
||||||
clipbboxes, z, x, y, NULL)) {
|
|
||||||
mvt_feature &nfeature = outlayer.features.back();
|
|
||||||
mvt_value val;
|
|
||||||
val.type = mvt_uint;
|
|
||||||
val.numeric_value.uint_value = outfeatures[i].size() - 1;
|
|
||||||
|
|
||||||
std::string attrname;
|
|
||||||
if (accumulate_numeric.size() == 0) {
|
|
||||||
attrname = "tippecanoe:count";
|
|
||||||
} else {
|
|
||||||
attrname = accumulate_numeric + ":count";
|
|
||||||
}
|
|
||||||
if (should_keep(attrname, keep, exclude, exclude_prefix)) {
|
|
||||||
outlayer.tag(nfeature, attrname, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mvt_tile ret;
|
|
||||||
ret.layers.push_back(outlayer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int ny,
|
std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int ny,
|
||||||
int detail_or_unspecified, int buffer,
|
int detail_or_unspecified, int buffer,
|
||||||
std::set<std::string> const &keep,
|
std::set<std::string> const &keep,
|
||||||
@@ -2017,9 +1461,9 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
std::unordered_map<std::string, attribute_op> const &attribute_accum,
|
||||||
std::vector<std::string> const &unidecode_data, double simplification,
|
std::vector<std::string> const &unidecode_data, double simplification,
|
||||||
double tiny_polygon_size,
|
double tiny_polygon_size,
|
||||||
std::vector<mvt_layer> const &bins, std::string const &bin_by_id_list,
|
std::vector<mvt_layer> const &unused2, std::string const &unused3,
|
||||||
std::string const &accumulate_numeric, size_t feature_limit,
|
std::string const &unused, size_t feature_limit,
|
||||||
std::vector<clipbbox> const &clipbboxes,
|
std::vector<clipbbox> const &unused4,
|
||||||
bool deduplicate_by_id) {
|
bool deduplicate_by_id) {
|
||||||
mvt_tile outtile;
|
mvt_tile outtile;
|
||||||
key_pool key_pool;
|
key_pool key_pool;
|
||||||
@@ -2093,30 +1537,6 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clip to user-specified bounding boxes.
|
|
||||||
// Bounding box clip first, to reduce complexity of the full clip.
|
|
||||||
// But don't clip here if we are binning, because we need to bin points in the buffer
|
|
||||||
if (bins.size() == 0) {
|
|
||||||
for (auto &c : clipbboxes) {
|
|
||||||
if (t == VT_POLYGON) {
|
|
||||||
geom = simple_clip_poly(geom, c.minx, c.miny, c.maxx, c.maxy, false);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_poly_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
} else if (t == VT_LINE) {
|
|
||||||
geom = clip_lines(geom, c.minx, c.miny, c.maxx, c.maxy);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_lines_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
} else if (t == VT_POINT) {
|
|
||||||
geom = clip_point(geom, c.minx, c.miny, c.maxx, c.maxy);
|
|
||||||
if (c.dv.size() > 0 && geom.size() > 0) {
|
|
||||||
geom = clip_point_poly(geom, c.dv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now offset from world coordinates to output tile coordinates,
|
// Now offset from world coordinates to output tile coordinates,
|
||||||
// but retain world scale, because that is what tippecanoe zoom-oriented clipping expects
|
// but retain world scale, because that is what tippecanoe zoom-oriented clipping expects
|
||||||
|
|
||||||
@@ -2126,8 +1546,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
g.y -= ny * outtilesize;
|
g.y -= ny * outtilesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't clip here if we are binning, because we need to bin points in the buffer
|
{
|
||||||
if (bins.size() == 0) {
|
|
||||||
// Clip to output tile
|
// Clip to output tile
|
||||||
|
|
||||||
long long xmin = LLONG_MAX;
|
long long xmin = LLONG_MAX;
|
||||||
@@ -2190,7 +1609,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
|
|
||||||
if (flush_multiplier_cluster) {
|
if (flush_multiplier_cluster) {
|
||||||
if (pending_tile_features.size() > 0) {
|
if (pending_tile_features.size() > 0) {
|
||||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric, key_pool, -1, bins.size() == 0, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, unused, key_pool, -1, true, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||||
if (outlayer->features.size() >= feature_limit) {
|
if (outlayer->features.size() >= feature_limit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2262,7 +1681,7 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pending_tile_features.size() > 0) {
|
if (pending_tile_features.size() > 0) {
|
||||||
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, accumulate_numeric, key_pool, -1, bins.size() == 0, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
feature_out(pending_tile_features, *outlayer, keep, exclude, exclude_prefix, attribute_accum, unused, key_pool, -1, true, std::vector<clipbbox>(), nz, nx, ny, deduplicate_by_id_set);
|
||||||
pending_tile_features.clear();
|
pending_tile_features.clear();
|
||||||
if (outlayer->features.size() >= feature_limit) {
|
if (outlayer->features.size() >= feature_limit) {
|
||||||
break;
|
break;
|
||||||
@@ -2301,8 +1720,8 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
nz + 1, nx * 2 + x, ny * 2 + y,
|
nz + 1, nx * 2 + x, ny * 2 + y,
|
||||||
detail_or_unspecified, buffer, keep, exclude, exclude_prefix, false, NULL,
|
detail_or_unspecified, buffer, keep, exclude, exclude_prefix, false, NULL,
|
||||||
demultiply, filter, preserve_input_order, attribute_accum, unidecode_data,
|
demultiply, filter, preserve_input_order, attribute_accum, unidecode_data,
|
||||||
simplification, tiny_polygon_size, bins, bin_by_id_list, accumulate_numeric,
|
simplification, tiny_polygon_size, unused2, unused3, unused,
|
||||||
1, clipbboxes, deduplicate_by_id);
|
1, unused4, deduplicate_by_id);
|
||||||
if (child.size() > 0) {
|
if (child.size() > 0) {
|
||||||
next_overzoomed_tiles->emplace_back(nx * 2 + x, ny * 2 + y);
|
next_overzoomed_tiles->emplace_back(nx * 2 + x, ny * 2 + y);
|
||||||
}
|
}
|
||||||
@@ -2311,12 +1730,6 @@ std::string overzoom(std::vector<source_tile> const &tiles, int nz, int nx, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bins.size() > 0) {
|
|
||||||
outtile = assign_to_bins(outtile, bins, bin_by_id_list, nz, nx, ny,
|
|
||||||
attribute_accum, accumulate_numeric,
|
|
||||||
keep, exclude, exclude_prefix, buffer, clipbboxes);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ssize_t i = outtile.layers.size() - 1; i >= 0; i--) {
|
for (ssize_t i = outtile.layers.size() - 1; i >= 0; i--) {
|
||||||
if (outtile.layers[i].features.size() == 0) {
|
if (outtile.layers[i].features.size() == 0) {
|
||||||
outtile.layers.erase(outtile.layers.begin() + i);
|
outtile.layers.erase(outtile.layers.begin() + i);
|
||||||
|
|||||||
-321
@@ -9,170 +9,6 @@
|
|||||||
#include "milo/dtoa_milo.h"
|
#include "milo/dtoa_milo.h"
|
||||||
#include "text.hpp"
|
#include "text.hpp"
|
||||||
|
|
||||||
static std::string mvt_value_to_string(mvt_value const &one, bool &fail, std::vector<std::string> const &unidecode_data) {
|
|
||||||
switch (one.type) {
|
|
||||||
case mvt_string:
|
|
||||||
if (unidecode_data.size() > 0) {
|
|
||||||
return unidecode_smash(unidecode_data, one.c_str());
|
|
||||||
} else {
|
|
||||||
return one.get_string_value();
|
|
||||||
}
|
|
||||||
case mvt_float:
|
|
||||||
return milo::dtoa_milo(one.numeric_value.float_value);
|
|
||||||
case mvt_double:
|
|
||||||
return milo::dtoa_milo(one.numeric_value.double_value);
|
|
||||||
case mvt_int:
|
|
||||||
return std::to_string(one.numeric_value.int_value);
|
|
||||||
case mvt_uint:
|
|
||||||
return std::to_string(one.numeric_value.uint_value);
|
|
||||||
case mvt_sint:
|
|
||||||
return std::to_string(one.numeric_value.sint_value);
|
|
||||||
case mvt_bool:
|
|
||||||
return one.numeric_value.bool_value ? "true" : "false";
|
|
||||||
case mvt_null:
|
|
||||||
fail = true; // null op string => null
|
|
||||||
return "";
|
|
||||||
case mvt_no_such_key:
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unhandled mvt_type %d\n", one.type);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alter the JSON parse tree in place to replace the original match string
|
|
||||||
// with its unidecode-smashed version.
|
|
||||||
//
|
|
||||||
// To avoid repeated re-smashings of the same JSON object, objects that have
|
|
||||||
// already been smashed are marked by setting their refcon to the unidecode data.
|
|
||||||
static void smash(std::vector<std::string> const &unidecode_data, json_object *j) {
|
|
||||||
if (j->value.string.refcon == (void *) &unidecode_data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string s = unidecode_smash(unidecode_data, j->value.string.string);
|
|
||||||
j->value.string.string = (char *) realloc(j->value.string.string, s.size() + 1);
|
|
||||||
if (j->value.string.string == NULL) {
|
|
||||||
perror("realloc for unidecode_smash");
|
|
||||||
exit(EXIT_MEMORY);
|
|
||||||
}
|
|
||||||
strcpy(j->value.string.string, s.c_str());
|
|
||||||
j->value.string.refcon = (void *) &unidecode_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare_fsl(mvt_value const &one, json_object *two, bool &fail, std::vector<std::string> const &unidecode_data) {
|
|
||||||
// In FSL expressions, the attribute value is coerced to the type
|
|
||||||
// of the JSON literal value it is being compared to.
|
|
||||||
//
|
|
||||||
// If it cannot be converted, the comparison returns null
|
|
||||||
// (which is distinct from true and false but is falsy if
|
|
||||||
// it is the final output value).
|
|
||||||
|
|
||||||
if (two->type == JSON_NULL) {
|
|
||||||
fail = true; // anything op null => null
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (two->type == JSON_NUMBER) {
|
|
||||||
double lhs;
|
|
||||||
|
|
||||||
switch (one.type) {
|
|
||||||
case mvt_string: {
|
|
||||||
char *endptr = NULL;
|
|
||||||
const char *s = one.c_str();
|
|
||||||
lhs = strtod(s, &endptr);
|
|
||||||
if (endptr == s) {
|
|
||||||
fail = true; // non-numeric-string op number => null
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case mvt_float:
|
|
||||||
lhs = one.numeric_value.float_value;
|
|
||||||
break;
|
|
||||||
case mvt_double:
|
|
||||||
lhs = one.numeric_value.double_value;
|
|
||||||
break;
|
|
||||||
case mvt_int:
|
|
||||||
lhs = one.numeric_value.int_value;
|
|
||||||
break;
|
|
||||||
case mvt_uint:
|
|
||||||
lhs = one.numeric_value.uint_value;
|
|
||||||
break;
|
|
||||||
case mvt_sint:
|
|
||||||
lhs = one.numeric_value.sint_value;
|
|
||||||
break;
|
|
||||||
case mvt_bool:
|
|
||||||
lhs = one.numeric_value.bool_value;
|
|
||||||
break;
|
|
||||||
case mvt_null:
|
|
||||||
fail = true; // null op number => null
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unhandled mvt_type %d\n", one.type);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lhs < two->value.number.number) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs > two->value.number.number) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (two->type == JSON_STRING) {
|
|
||||||
std::string lhs = mvt_value_to_string(one, fail, unidecode_data);
|
|
||||||
|
|
||||||
if (unidecode_data.size() > 0) {
|
|
||||||
smash(unidecode_data, two);
|
|
||||||
}
|
|
||||||
|
|
||||||
return strcmp(lhs.c_str(), two->value.string.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (two->type == JSON_TRUE || two->type == JSON_FALSE) {
|
|
||||||
bool lhs;
|
|
||||||
|
|
||||||
switch (one.type) {
|
|
||||||
case mvt_string:
|
|
||||||
lhs = one.get_string_view().size() > 0;
|
|
||||||
break;
|
|
||||||
case mvt_float:
|
|
||||||
lhs = one.numeric_value.float_value != 0;
|
|
||||||
break;
|
|
||||||
case mvt_double:
|
|
||||||
lhs = one.numeric_value.double_value != 0;
|
|
||||||
break;
|
|
||||||
case mvt_int:
|
|
||||||
lhs = one.numeric_value.int_value != 0;
|
|
||||||
break;
|
|
||||||
case mvt_uint:
|
|
||||||
lhs = one.numeric_value.uint_value != 0;
|
|
||||||
break;
|
|
||||||
case mvt_sint:
|
|
||||||
lhs = one.numeric_value.sint_value != 0;
|
|
||||||
break;
|
|
||||||
case mvt_bool:
|
|
||||||
lhs = one.numeric_value.bool_value;
|
|
||||||
break;
|
|
||||||
case mvt_null:
|
|
||||||
fail = true; // null op bool => null
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case mvt_no_such_key:
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "unhandled mvt_type %d\n", one.type);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rhs = two->type == JSON_TRUE;
|
|
||||||
return lhs - rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "unhandled JSON type %d\n", two->type);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare(mvt_value const &one, json_object *two, bool &fail) {
|
int compare(mvt_value const &one, json_object *two, bool &fail) {
|
||||||
switch (one.type) {
|
switch (one.type) {
|
||||||
case mvt_string:
|
case mvt_string:
|
||||||
@@ -292,163 +128,6 @@ static int eval(std::function<mvt_value(std::string const &)> feature, json_obje
|
|||||||
exit(EXIT_FILTER);
|
exit(EXIT_FILTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FSL conjunctions
|
|
||||||
if (f->value.array.length == 3 &&
|
|
||||||
f->value.array.array[1]->type == JSON_STRING &&
|
|
||||||
(strcmp(f->value.array.array[1]->value.string.string, "or") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "and") == 0)) {
|
|
||||||
int lhs;
|
|
||||||
|
|
||||||
if (f->value.array.array[0]->type == JSON_STRING) {
|
|
||||||
// if LHS of a boolean conjunction is a string, it is an attribute reference
|
|
||||||
mvt_value ff = feature(std::string(f->value.array.array[0]->value.string.string));
|
|
||||||
if (ff.type != mvt_no_such_key) {
|
|
||||||
if (ff.type == mvt_bool) {
|
|
||||||
lhs = ff.numeric_value.bool_value;
|
|
||||||
} else {
|
|
||||||
lhs = -1; // not boolean: null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lhs = -1; // not found: null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lhs = eval(feature, f->value.array.array[0], exclude_attributes, unidecode_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rhs = eval(feature, f->value.array.array[2], exclude_attributes, unidecode_data);
|
|
||||||
if (lhs < 0 && rhs < 0) {
|
|
||||||
return -1; // null op null => null
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "or") == 0) {
|
|
||||||
return (lhs > 0) || (rhs > 0);
|
|
||||||
} else {
|
|
||||||
return (lhs > 0) && (rhs > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FSL comparators
|
|
||||||
if (f->value.array.length == 3 &&
|
|
||||||
f->value.array.array[0]->type == JSON_STRING &&
|
|
||||||
f->value.array.array[1]->type == JSON_STRING &&
|
|
||||||
(strcmp(f->value.array.array[1]->value.string.string, "lt") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "gt") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "le") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "ge") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "eq") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "ne") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "cn") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "nc") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "in") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "ni") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "is") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "isnt") == 0 ||
|
|
||||||
false)) {
|
|
||||||
mvt_value lhs = feature(std::string(f->value.array.array[0]->value.string.string));
|
|
||||||
if (lhs.type == mvt_no_such_key) {
|
|
||||||
lhs.type = mvt_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->value.array.array[2]->type == JSON_NULL && strcmp(f->value.array.array[1]->value.string.string, "is") == 0) {
|
|
||||||
return lhs.type == mvt_null; // null is null => true, anything is null => false
|
|
||||||
}
|
|
||||||
if (f->value.array.array[2]->type == JSON_NULL && strcmp(f->value.array.array[1]->value.string.string, "isnt") == 0) {
|
|
||||||
return lhs.type != mvt_null; // null isnt null => false, anything isnt null => true
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fail = false;
|
|
||||||
|
|
||||||
if (f->value.array.array[2]->type == JSON_STRING &&
|
|
||||||
(strcmp(f->value.array.array[1]->value.string.string, "cn") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "nc") == 0)) {
|
|
||||||
if (lhs.type == mvt_null) {
|
|
||||||
return -1; // null cn/nc anything => null
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string s = mvt_value_to_string(lhs, fail, unidecode_data);
|
|
||||||
if (fail) {
|
|
||||||
return -1; // null cn anything => false
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains;
|
|
||||||
if (unidecode_data.size() > 0) {
|
|
||||||
smash(unidecode_data, f->value.array.array[2]);
|
|
||||||
}
|
|
||||||
contains = strstr(s.c_str(), f->value.array.array[2]->value.string.string);
|
|
||||||
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "cn") == 0) {
|
|
||||||
return contains;
|
|
||||||
} else {
|
|
||||||
return !contains;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->value.array.array[2]->type == JSON_ARRAY &&
|
|
||||||
(strcmp(f->value.array.array[1]->value.string.string, "in") == 0 ||
|
|
||||||
strcmp(f->value.array.array[1]->value.string.string, "ni") == 0)) {
|
|
||||||
// no null check here, since null can be in or not in
|
|
||||||
|
|
||||||
bool contains = false;
|
|
||||||
for (size_t i = 0; i < f->value.array.array[2]->value.array.length; i++) {
|
|
||||||
if (lhs.type == mvt_null) {
|
|
||||||
if (f->value.array.array[2]->value.array.array[i]->type == JSON_NULL) {
|
|
||||||
contains = true; // null is null
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
contains = false; // null isnt non-null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fail = false;
|
|
||||||
static std::vector<std::string> no_unidecode_data;
|
|
||||||
int cmp = compare_fsl(lhs, f->value.array.array[2]->value.array.array[i], fail, no_unidecode_data);
|
|
||||||
|
|
||||||
if (fail) {
|
|
||||||
contains = false; // non-null isnt null
|
|
||||||
} else if (cmp == 0) {
|
|
||||||
contains = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "in") == 0) {
|
|
||||||
return contains;
|
|
||||||
} else {
|
|
||||||
return !contains;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lhs.type == mvt_null) {
|
|
||||||
return -1; // null compared to anything => null
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmp = compare_fsl(lhs, f->value.array.array[2], fail, unidecode_data);
|
|
||||||
if (fail) {
|
|
||||||
return -1; // null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "eq") == 0) {
|
|
||||||
return cmp == 0;
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "ne") == 0) {
|
|
||||||
return cmp != 0;
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "gt") == 0) {
|
|
||||||
return cmp > 0;
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "ge") == 0) {
|
|
||||||
return cmp >= 0;
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "lt") == 0) {
|
|
||||||
return cmp < 0;
|
|
||||||
}
|
|
||||||
if (strcmp(f->value.array.array[1]->value.string.string, "le") == 0) {
|
|
||||||
return cmp <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "expression fsl comparison: can't happen %s\n", f->value.array.array[1]->value.string.string);
|
|
||||||
exit(EXIT_IMPOSSIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->value.array.array[0]->type != JSON_STRING) {
|
if (f->value.array.array[0]->type != JSON_STRING) {
|
||||||
fprintf(stderr, "Filter operation is not a string: %s\n", json_stringify(f));
|
fprintf(stderr, "Filter operation is not a string: %s\n", json_stringify(f));
|
||||||
exit(EXIT_FILTER);
|
exit(EXIT_FILTER);
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ long long extend_zooms_max = 0;
|
|||||||
int retain_points_multiplier = 1;
|
int retain_points_multiplier = 1;
|
||||||
std::vector<std::string> unidecode_data;
|
std::vector<std::string> unidecode_data;
|
||||||
size_t maximum_string_attribute_length = 0;
|
size_t maximum_string_attribute_length = 0;
|
||||||
std::string accumulate_numeric;
|
|
||||||
|
|
||||||
std::vector<order_field> order_by;
|
std::vector<order_field> order_by;
|
||||||
bool order_reverse;
|
bool order_reverse;
|
||||||
@@ -3062,7 +3061,6 @@ int main(int argc, char **argv) {
|
|||||||
{"attribute-type", required_argument, 0, 'T'},
|
{"attribute-type", required_argument, 0, 'T'},
|
||||||
{"attribute-description", required_argument, 0, 'Y'},
|
{"attribute-description", required_argument, 0, 'Y'},
|
||||||
{"accumulate-attribute", required_argument, 0, 'E'},
|
{"accumulate-attribute", required_argument, 0, 'E'},
|
||||||
{"accumulate-numeric-attributes", required_argument, 0, '~'},
|
|
||||||
{"empty-csv-columns-are-null", no_argument, &prevent[P_EMPTY_CSV_COLUMNS], 1},
|
{"empty-csv-columns-are-null", no_argument, &prevent[P_EMPTY_CSV_COLUMNS], 1},
|
||||||
{"convert-stringified-ids-to-numbers", no_argument, &additional[A_CONVERT_NUMERIC_IDS], 1},
|
{"convert-stringified-ids-to-numbers", no_argument, &additional[A_CONVERT_NUMERIC_IDS], 1},
|
||||||
{"use-attribute-for-id", required_argument, 0, '~'},
|
{"use-attribute-for-id", required_argument, 0, '~'},
|
||||||
@@ -3309,8 +3307,6 @@ int main(int argc, char **argv) {
|
|||||||
unidecode_data = read_unidecode(optarg);
|
unidecode_data = read_unidecode(optarg);
|
||||||
} else if (strcmp(opt, "maximum-string-attribute-length") == 0) {
|
} else if (strcmp(opt, "maximum-string-attribute-length") == 0) {
|
||||||
maximum_string_attribute_length = atoll_require(optarg, "Maximum string attribute length");
|
maximum_string_attribute_length = atoll_require(optarg, "Maximum string attribute length");
|
||||||
} else if (strcmp(opt, "accumulate-numeric-attributes") == 0) {
|
|
||||||
accumulate_numeric = optarg;
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
||||||
exit(EXIT_ARGS);
|
exit(EXIT_ARGS);
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ extern std::map<std::string, serial_val> set_attributes;
|
|||||||
extern long long extend_zooms_max;
|
extern long long extend_zooms_max;
|
||||||
extern int retain_points_multiplier;
|
extern int retain_points_multiplier;
|
||||||
extern size_t maximum_string_attribute_length;
|
extern size_t maximum_string_attribute_length;
|
||||||
extern std::string accumulate_numeric;
|
|
||||||
extern unsigned long long preserve_multiplier_density_threshold;
|
extern unsigned long long preserve_multiplier_density_threshold;
|
||||||
|
|
||||||
struct order_field {
|
struct order_field {
|
||||||
|
|||||||
+2
-99
@@ -25,13 +25,10 @@ std::string filter;
|
|||||||
bool preserve_input_order = false;
|
bool preserve_input_order = false;
|
||||||
std::unordered_map<std::string, attribute_op> attribute_accum;
|
std::unordered_map<std::string, attribute_op> attribute_accum;
|
||||||
std::vector<std::string> unidecode_data;
|
std::vector<std::string> unidecode_data;
|
||||||
std::vector<mvt_layer> bins;
|
|
||||||
std::string accumulate_numeric;
|
|
||||||
|
|
||||||
std::set<std::string> keep;
|
std::set<std::string> keep;
|
||||||
std::set<std::string> exclude;
|
std::set<std::string> exclude;
|
||||||
std::vector<std::string> exclude_prefix;
|
std::vector<std::string> exclude_prefix;
|
||||||
std::vector<clipbbox> clipbboxes;
|
|
||||||
|
|
||||||
void usage(char **argv) {
|
void usage(char **argv) {
|
||||||
fprintf(stderr, "Usage: %s -o newtile.pbf.gz tile.pbf.gz oz/ox/oy nz/nx/ny\n", argv[0]);
|
fprintf(stderr, "Usage: %s -o newtile.pbf.gz tile.pbf.gz oz/ox/oy nz/nx/ny\n", argv[0]);
|
||||||
@@ -67,8 +64,6 @@ int main(int argc, char **argv) {
|
|||||||
const char *outfile = NULL;
|
const char *outfile = NULL;
|
||||||
double simplification = 0;
|
double simplification = 0;
|
||||||
double tiny_polygon_size = 0;
|
double tiny_polygon_size = 0;
|
||||||
std::string assign_to_bins;
|
|
||||||
std::string bin_by_id_list;
|
|
||||||
|
|
||||||
std::vector<input_tile> sources;
|
std::vector<input_tile> sources;
|
||||||
|
|
||||||
@@ -88,13 +83,7 @@ int main(int argc, char **argv) {
|
|||||||
{"line-simplification", required_argument, 0, 'S'},
|
{"line-simplification", required_argument, 0, 'S'},
|
||||||
{"tiny-polygon-size", required_argument, 0, 's' & 0x1F},
|
{"tiny-polygon-size", required_argument, 0, 's' & 0x1F},
|
||||||
{"source-tile", required_argument, 0, 't'},
|
{"source-tile", required_argument, 0, 't'},
|
||||||
{"assign-to-bins", required_argument, 0, 'b' & 0x1F},
|
|
||||||
{"bin-by-id-list", required_argument, 0, 'c' & 0x1F},
|
|
||||||
{"accumulate-numeric-attributes", required_argument, 0, 'a' & 0x1F},
|
|
||||||
{"no-tile-compression", no_argument, 0, 'd' & 0x1F},
|
{"no-tile-compression", no_argument, 0, 'd' & 0x1F},
|
||||||
{"clip-bounding-box", required_argument, 0, 'k' & 0x1F},
|
|
||||||
{"clip-polygon", required_argument, 0, 'l' & 0x1F},
|
|
||||||
{"clip-polygon-file", required_argument, 0, 'm' & 0x1F},
|
|
||||||
{"deduplicate-by-id", no_argument, 0, 'i' & 0x1F},
|
{"deduplicate-by-id", no_argument, 0, 'i' & 0x1F},
|
||||||
|
|
||||||
{0, 0, 0, 0},
|
{0, 0, 0, 0},
|
||||||
@@ -174,47 +163,10 @@ int main(int argc, char **argv) {
|
|||||||
simplification = atof(optarg);
|
simplification = atof(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b' & 0x1F:
|
|
||||||
assign_to_bins = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'c' & 0x1F:
|
|
||||||
bin_by_id_list = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a' & 0x1F:
|
|
||||||
accumulate_numeric = optarg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd' & 0x1F:
|
case 'd' & 0x1F:
|
||||||
do_compress = false;
|
do_compress = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k' & 0x1F: {
|
|
||||||
clipbbox clip;
|
|
||||||
if (sscanf(optarg, "%lf,%lf,%lf,%lf", &clip.lon1, &clip.lat1, &clip.lon2, &clip.lat2) == 4) {
|
|
||||||
projection->project(clip.lon1, clip.lat1, 32, &clip.minx, &clip.maxy);
|
|
||||||
projection->project(clip.lon2, clip.lat2, 32, &clip.maxx, &clip.miny);
|
|
||||||
clipbboxes.push_back(clip);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "%s: Can't parse bounding box --clip-bounding-box=%s\n", argv[0], optarg);
|
|
||||||
exit(EXIT_ARGS);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'l' & 0x1F: {
|
|
||||||
clipbbox clip = parse_clip_poly(optarg);
|
|
||||||
clipbboxes.push_back(clip);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'm' & 0x1F: {
|
|
||||||
clipbbox clip = parse_clip_poly(read_json_file(optarg));
|
|
||||||
clipbboxes.push_back(clip);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'i' & 0x1F: {
|
case 'i' & 0x1F: {
|
||||||
deduplicate_by_id = true;
|
deduplicate_by_id = true;
|
||||||
break;
|
break;
|
||||||
@@ -283,58 +235,9 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assign_to_bins.size() != 0) {
|
|
||||||
FILE *f = fopen(assign_to_bins.c_str(), "r");
|
|
||||||
if (f == NULL) {
|
|
||||||
perror(assign_to_bins.c_str());
|
|
||||||
exit(EXIT_OPEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
int det = detail;
|
|
||||||
if (det < 0) {
|
|
||||||
det = 12;
|
|
||||||
}
|
|
||||||
bins = parse_layers(f, nz, nx, ny, 1LL << det, true);
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clip the clip polygons, if any, to the tile bounds,
|
|
||||||
// to reduce their complexity
|
|
||||||
|
|
||||||
bool clipped_to_nothing = false;
|
|
||||||
if (clipbboxes.size() > 0) {
|
|
||||||
long long wx1 = (nx - buffer / 256.0) * (1LL << (32 - nz));
|
|
||||||
long long wy1 = (ny - buffer / 256.0) * (1LL << (32 - nz));
|
|
||||||
long long wx2 = (nx + 1 + buffer / 256.0) * (1LL << (32 - nz));
|
|
||||||
long long wy2 = (ny + 1 + buffer / 256.0) * (1LL << (32 - nz));
|
|
||||||
|
|
||||||
drawvec tile_bounds;
|
|
||||||
tile_bounds.emplace_back(VT_MOVETO, wx1, wy1);
|
|
||||||
tile_bounds.emplace_back(VT_LINETO, wx2, wy1);
|
|
||||||
tile_bounds.emplace_back(VT_LINETO, wx2, wy2);
|
|
||||||
tile_bounds.emplace_back(VT_LINETO, wx1, wy2);
|
|
||||||
tile_bounds.emplace_back(VT_LINETO, wx1, wy1);
|
|
||||||
|
|
||||||
for (auto &c : clipbboxes) {
|
|
||||||
c.minx = std::max(c.minx, wx1);
|
|
||||||
c.miny = std::max(c.miny, wy1);
|
|
||||||
c.maxx = std::min(c.maxx, wx2);
|
|
||||||
c.maxy = std::min(c.maxy, wy2);
|
|
||||||
|
|
||||||
if (c.dv.size() > 0) {
|
|
||||||
c.dv = clip_poly_poly(c.dv, tile_bounds);
|
|
||||||
|
|
||||||
if (c.dv.size() == 0) {
|
|
||||||
clipped_to_nothing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
|
|
||||||
if (!clipped_to_nothing) {
|
{
|
||||||
json_object *json_filter = NULL;
|
json_object *json_filter = NULL;
|
||||||
if (filter.size() > 0) {
|
if (filter.size() > 0) {
|
||||||
json_filter = parse_filter(filter.c_str());
|
json_filter = parse_filter(filter.c_str());
|
||||||
@@ -361,7 +264,7 @@ int main(int argc, char **argv) {
|
|||||||
its.push_back(std::move(t));
|
its.push_back(std::move(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
out = overzoom(its, nz, nx, ny, detail, buffer, keep, exclude, exclude_prefix, do_compress, NULL, demultiply, json_filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, bins, bin_by_id_list, accumulate_numeric, SIZE_MAX, clipbboxes, deduplicate_by_id);
|
out = overzoom(its, nz, nx, ny, detail, buffer, keep, exclude, exclude_prefix, do_compress, NULL, demultiply, json_filter, preserve_input_order, attribute_accum, unidecode_data, simplification, tiny_polygon_size, std::vector<mvt_layer>(), "", "", SIZE_MAX, std::vector<clipbbox>(), deduplicate_by_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *f = fopen(outfile, "wb");
|
FILE *f = fopen(outfile, "wb");
|
||||||
|
|||||||
-1426
File diff suppressed because one or more lines are too long
@@ -1,21 +1,15 @@
|
|||||||
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
|
{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [
|
||||||
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
|
{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 4, "NAME": "Castries" }, "geometry": { "type": "Point", "coordinates": [ -60.996094, 14.008696 ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Reykjavík", "LATITUDE": 64.150024 }, "geometry": { "type": "Point", "coordinates": [ -21.884766, 64.129784 ] } }
|
||||||
,
|
,
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Niamey" }, "geometry": { "type": "Point", "coordinates": [ 2.109375, 13.496473 ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Astana", "LATITUDE": 51.181125 }, "geometry": { "type": "Point", "coordinates": [ 71.455078, 51.179343 ] } }
|
||||||
,
|
,
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Wellington" }, "geometry": { "type": "MultiPoint", "coordinates": [ [ 174.814453, -41.310824 ], [ -185.273438, -41.310824 ] ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Yerevan", "LATITUDE": 40.181151 }, "geometry": { "type": "Point", "coordinates": [ 44.560547, 40.178873 ] } }
|
||||||
,
|
,
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Sucre" }, "geometry": { "type": "Point", "coordinates": [ -65.214844, -19.062118 ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 2, "NAME": "Oslo", "LATITUDE": 59.91669 }, "geometry": { "type": "Point", "coordinates": [ 10.810547, 59.888937 ] } }
|
||||||
,
|
,
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 3, "NAME": "Hargeysa" }, "geometry": { "type": "Point", "coordinates": [ 44.121094, 9.535749 ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 1, "NAME": "Vancouver", "LATITUDE": 49.273417 }, "geometry": { "type": "Point", "coordinates": [ -123.134766, 49.267805 ] } }
|
||||||
,
|
,
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 1, "NAME": "Chengdu" }, "geometry": { "type": "Point", "coordinates": [ 104.062500, 30.675715 ] } }
|
{ "type": "Feature", "properties": { "SCALERANK": 1, "NAME": "Vienna", "LATITUDE": 48.200015 }, "geometry": { "type": "Point", "coordinates": [ 16.347656, 48.166085 ] } }
|
||||||
,
|
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 1, "NAME": "Vancouver" }, "geometry": { "type": "Point", "coordinates": [ -123.134766, 49.267805 ] } }
|
|
||||||
,
|
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 1, "NAME": "Vienna" }, "geometry": { "type": "Point", "coordinates": [ 16.347656, 48.166085 ] } }
|
|
||||||
,
|
|
||||||
{ "type": "Feature", "properties": { "SCALERANK": 0, "NAME": "Cape Town" }, "geometry": { "type": "Point", "coordinates": [ 18.457031, -33.943360 ] } }
|
|
||||||
] }
|
] }
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"*":["SCALERANK","eq",0]}
|
{"*":["==","SCALERANK",0]}
|
||||||
|
|||||||
+1
-178
@@ -57,11 +57,6 @@ std::map<std::string, std::string> renames;
|
|||||||
bool exclude_all = false;
|
bool exclude_all = false;
|
||||||
bool exclude_all_tile_attributes = false;
|
bool exclude_all_tile_attributes = false;
|
||||||
std::vector<std::string> unidecode_data;
|
std::vector<std::string> unidecode_data;
|
||||||
std::string join_tile_attribute;
|
|
||||||
std::string join_table_expression;
|
|
||||||
std::string join_table;
|
|
||||||
size_t join_count_limit = 1;
|
|
||||||
std::string attribute_for_id;
|
|
||||||
|
|
||||||
bool want_overzoom = false;
|
bool want_overzoom = false;
|
||||||
int buffer = 5;
|
int buffer = 5;
|
||||||
@@ -79,92 +74,6 @@ struct stats {
|
|||||||
std::vector<struct strategy> strategies{};
|
std::vector<struct strategy> strategies{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// list, per feature in the tile,
|
|
||||||
// of lists of features in the sqlite response,
|
|
||||||
// each of which is a mapping from keys to values
|
|
||||||
std::vector<std::vector<std::map<std::string, mvt_value>>> get_joined_rows(sqlite3 *db, const std::vector<mvt_value> &join_keys) {
|
|
||||||
std::vector<std::vector<std::map<std::string, mvt_value>>> ret;
|
|
||||||
ret.resize(join_keys.size());
|
|
||||||
|
|
||||||
// double quotes for table and column identifiers
|
|
||||||
const char *s = sqlite3_mprintf("select %s, * from \"%w\" where %s in (",
|
|
||||||
join_table_expression.c_str(), join_table.c_str(), join_table_expression.c_str());
|
|
||||||
std::string query = s;
|
|
||||||
sqlite3_free((void *) s);
|
|
||||||
|
|
||||||
std::multimap<std::string, size_t> key_to_row;
|
|
||||||
for (size_t i = 0; i < join_keys.size(); i++) {
|
|
||||||
const mvt_value &v = join_keys[i];
|
|
||||||
|
|
||||||
// single quotes for literals
|
|
||||||
if (v.type == mvt_string) {
|
|
||||||
s = sqlite3_mprintf("'%q'", v.c_str());
|
|
||||||
query += s;
|
|
||||||
sqlite3_free((void *) s);
|
|
||||||
key_to_row.emplace(v.get_string_value(), i);
|
|
||||||
} else {
|
|
||||||
std::string stringified = v.toString();
|
|
||||||
key_to_row.emplace(stringified, i);
|
|
||||||
query += stringified;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i + 1 < join_keys.size()) {
|
|
||||||
query += ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this doesn't add a LIMIT to the query because our limit
|
|
||||||
// is per tiled feature, not a limit on the entire query response.
|
|
||||||
query += ");";
|
|
||||||
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL) != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "sqlite3 query %s failed: %s\n", query.c_str(), sqlite3_errmsg(db));
|
|
||||||
exit(EXIT_SQLITE);
|
|
||||||
}
|
|
||||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
||||||
int count = sqlite3_column_count(stmt);
|
|
||||||
std::map<std::string, mvt_value> row;
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
// join key is 0th column of query
|
|
||||||
std::string key = (const char *) sqlite3_column_text(stmt, 0);
|
|
||||||
auto f = key_to_row.equal_range(key);
|
|
||||||
if (f.first == f.second) {
|
|
||||||
fprintf(stderr, "Unexpected join key: %s\n", key.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto ff = f.first; ff != f.second; ++ff) {
|
|
||||||
if (ret[ff->second].size() < join_count_limit) {
|
|
||||||
for (int i = 1; i < count; i++) {
|
|
||||||
int type = sqlite3_column_type(stmt, i);
|
|
||||||
mvt_value v;
|
|
||||||
v.type = mvt_null;
|
|
||||||
|
|
||||||
if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) {
|
|
||||||
v = mvt_value(sqlite3_column_double(stmt, i));
|
|
||||||
} else if (type == SQLITE_TEXT || type == SQLITE_BLOB) {
|
|
||||||
v.set_string_value((const char *) sqlite3_column_text(stmt, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *name = sqlite3_column_name(stmt, i);
|
|
||||||
row.emplace(name, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[ff->second].push_back(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sqlite3_finalize(stmt) != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "sqlite3 finalize failed: %s\n", sqlite3_errmsg(db));
|
|
||||||
exit(EXIT_SQLITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct arg {
|
struct arg {
|
||||||
std::map<zxy, std::vector<std::string>> inputs{};
|
std::map<zxy, std::vector<std::string>> inputs{};
|
||||||
std::map<zxy, std::string> outputs{};
|
std::map<zxy, std::string> outputs{};
|
||||||
@@ -187,7 +96,7 @@ struct arg {
|
|||||||
double minlon2, maxlon2;
|
double minlon2, maxlon2;
|
||||||
};
|
};
|
||||||
|
|
||||||
void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<std::string, layermap_entry> &layermap, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 *db, std::set<std::string> &exclude, std::set<std::string> &include, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, int ifmatched, mvt_tile &outtile, json_object *filter, struct arg *a) {
|
void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<std::string, layermap_entry> &layermap, std::vector<std::string> &header, std::map<std::string, std::vector<std::string>> &mapping, sqlite3 * /* db */, std::set<std::string> &exclude, std::set<std::string> &include, std::set<std::string> &keep_layers, std::set<std::string> &remove_layers, int ifmatched, mvt_tile &outtile, json_object *filter, struct arg *a) {
|
||||||
mvt_tile tile;
|
mvt_tile tile;
|
||||||
int features_added = 0;
|
int features_added = 0;
|
||||||
bool was_compressed;
|
bool was_compressed;
|
||||||
@@ -253,30 +162,6 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<std::map<std::string, mvt_value>>> joined;
|
|
||||||
if (db != NULL) {
|
|
||||||
// collect join keys for sql query
|
|
||||||
|
|
||||||
std::vector<mvt_value> join_keys;
|
|
||||||
join_keys.resize(layer.features.size());
|
|
||||||
|
|
||||||
for (size_t f = 0; f < layer.features.size(); f++) {
|
|
||||||
mvt_feature &feat = layer.features[f];
|
|
||||||
join_keys[f].type = mvt_no_such_key;
|
|
||||||
|
|
||||||
for (size_t t = 0; t + 1 < feat.tags.size(); t += 2) {
|
|
||||||
const std::string &key = layer.keys[feat.tags[t]];
|
|
||||||
if (key == join_tile_attribute) {
|
|
||||||
const mvt_value &val = layer.values[feat.tags[t + 1]];
|
|
||||||
join_keys[f] = val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
joined = get_joined_rows(db, join_keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tilestats = layermap.find(layer.name);
|
auto tilestats = layermap.find(layer.name);
|
||||||
|
|
||||||
long long minx = LLONG_MAX;
|
long long minx = LLONG_MAX;
|
||||||
@@ -306,47 +191,6 @@ void append_tile(std::string message, int z, unsigned x, unsigned y, std::map<st
|
|||||||
std::vector<match> matches;
|
std::vector<match> matches;
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
|
|
||||||
// start filling out sql matches
|
|
||||||
|
|
||||||
if (f < joined.size()) {
|
|
||||||
if (joined[f].size() > 0) {
|
|
||||||
matched = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &joined_feature : joined[f]) {
|
|
||||||
match m;
|
|
||||||
m.has_id = feat.has_id;
|
|
||||||
m.id = feat.id;
|
|
||||||
|
|
||||||
if (!exclude_all_tile_attributes) {
|
|
||||||
for (size_t t = 0; t + 1 < feat.tags.size(); t += 2) {
|
|
||||||
const std::string &key = layer.keys[feat.tags[t]];
|
|
||||||
mvt_value &val = layer.values[feat.tags[t + 1]];
|
|
||||||
serial_val sv = mvt_value_to_serial_val(val);
|
|
||||||
|
|
||||||
if (include.count(key) || (!exclude_all && exclude.count(key) == 0 && exclude_attributes.count(key) == 0)) {
|
|
||||||
m.attributes.insert(std::pair<std::string, std::pair<mvt_value, serial_val>>(key, std::pair<mvt_value, serial_val>(val, sv)));
|
|
||||||
m.key_order.push_back(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &kv : joined_feature) {
|
|
||||||
if (kv.first == attribute_for_id) {
|
|
||||||
m.has_id = true;
|
|
||||||
m.id = mvt_value_to_long_long(kv.second);
|
|
||||||
} else if (include.count(kv.first) || (!exclude_all && exclude.count(kv.first) == 0 && exclude_attributes.count(kv.first) == 0)) {
|
|
||||||
if (kv.second.type != mvt_null) {
|
|
||||||
m.attributes.insert(std::pair<std::string, std::pair<mvt_value, serial_val>>(kv.first, std::pair<mvt_value, serial_val>(kv.second, mvt_value_to_serial_val(kv.second))));
|
|
||||||
m.key_order.push_back(kv.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
matches.push_back(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// look for csv matches and start filling them out
|
// look for csv matches and start filling them out
|
||||||
|
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
@@ -1475,11 +1319,6 @@ int main(int argc, char **argv) {
|
|||||||
{"rename-layer", required_argument, 0, 'R'},
|
{"rename-layer", required_argument, 0, 'R'},
|
||||||
{"read-from", required_argument, 0, 'r'},
|
{"read-from", required_argument, 0, 'r'},
|
||||||
|
|
||||||
{"join-sqlite", required_argument, 0, '~'},
|
|
||||||
{"join-tile-attribute", required_argument, 0, '~'},
|
|
||||||
{"join-table-expression", required_argument, 0, '~'},
|
|
||||||
{"join-table", required_argument, 0, '~'},
|
|
||||||
{"join-count-limit", required_argument, 0, '~'},
|
|
||||||
{"use-attribute-for-id", required_argument, 0, '~'},
|
{"use-attribute-for-id", required_argument, 0, '~'},
|
||||||
|
|
||||||
{"no-tile-size-limit", no_argument, &pk, 1},
|
{"no-tile-size-limit", no_argument, &pk, 1},
|
||||||
@@ -1666,24 +1505,8 @@ int main(int argc, char **argv) {
|
|||||||
max_tilestats_values = atoi(optarg);
|
max_tilestats_values = atoi(optarg);
|
||||||
} else if (strcmp(opt, "unidecode-data") == 0) {
|
} else if (strcmp(opt, "unidecode-data") == 0) {
|
||||||
unidecode_data = read_unidecode(optarg);
|
unidecode_data = read_unidecode(optarg);
|
||||||
} else if (strcmp(opt, "join-sqlite") == 0) {
|
|
||||||
join_sqlite_fname = optarg;
|
|
||||||
if (sqlite3_open(optarg, &db) != SQLITE_OK) {
|
|
||||||
fprintf(stderr, "%s: %s\n", optarg, sqlite3_errmsg(db));
|
|
||||||
exit(EXIT_SQLITE);
|
|
||||||
}
|
|
||||||
} else if (strcmp(opt, "join-table") == 0) {
|
|
||||||
join_table = optarg;
|
|
||||||
} else if (strcmp(opt, "join-table-expression") == 0) {
|
|
||||||
join_table_expression = optarg;
|
|
||||||
} else if (strcmp(opt, "join-tile-attribute") == 0) {
|
|
||||||
join_tile_attribute = optarg;
|
|
||||||
} else if (strcmp(opt, "use-attribute-for-id") == 0) {
|
|
||||||
attribute_for_id = optarg;
|
|
||||||
} else if (strcmp(opt, "exclude-all-tile-attributes") == 0) {
|
} else if (strcmp(opt, "exclude-all-tile-attributes") == 0) {
|
||||||
exclude_all_tile_attributes = true;
|
exclude_all_tile_attributes = true;
|
||||||
} else if (strcmp(opt, "join-count-limit") == 0) {
|
|
||||||
join_count_limit = atoi(optarg);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
fprintf(stderr, "%s: Unrecognized option --%s\n", argv[0], opt);
|
||||||
exit(EXIT_ARGS);
|
exit(EXIT_ARGS);
|
||||||
|
|||||||
@@ -1478,11 +1478,8 @@ void promote_attribute_prefix(std::string const &key, std::string const &prefixe
|
|||||||
|
|
||||||
// accumulate attribute values from sf onto p
|
// accumulate attribute values from sf onto p
|
||||||
void preserve_attributes(std::unordered_map<std::string, attribute_op> const *attribute_accum, const serial_feature &sf, serial_feature &p, key_pool &key_pool) {
|
void preserve_attributes(std::unordered_map<std::string, attribute_op> const *attribute_accum, const serial_feature &sf, serial_feature &p, key_pool &key_pool) {
|
||||||
std::string accumulate_numeric_colon = accumulate_numeric + ":";
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sf.keys.size(); i++) {
|
for (size_t i = 0; i < sf.keys.size(); i++) {
|
||||||
std::string key = sf.stringpool + sf.keys[i] + 1;
|
std::string key = sf.stringpool + sf.keys[i] + 1;
|
||||||
int type = sf.stringpool[sf.values[i]];
|
|
||||||
|
|
||||||
auto f = attribute_accum->find(key);
|
auto f = attribute_accum->find(key);
|
||||||
if (f != attribute_accum->end()) {
|
if (f != attribute_accum->end()) {
|
||||||
@@ -1492,21 +1489,10 @@ void preserve_attributes(std::unordered_map<std::string, attribute_op> const *at
|
|||||||
|
|
||||||
promote_attribute(key, p, key_pool);
|
promote_attribute(key, p, key_pool);
|
||||||
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, key_pool);
|
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, key_pool);
|
||||||
} else if (type == mvt_double && accumulate_numeric.size() > 0 && !starts_with(key, accumulate_numeric_colon)) {
|
|
||||||
for (auto const &operation : numeric_operations) {
|
|
||||||
serial_val sv;
|
|
||||||
sv.type = sf.stringpool[sf.values[i]];
|
|
||||||
sv.s = sf.stringpool + sf.values[i] + 1;
|
|
||||||
|
|
||||||
std::string prefixed_key = accumulate_numeric + ":" + operation.first + ":" + key;
|
|
||||||
promote_attribute_prefix(key, prefixed_key, p, key_pool);
|
|
||||||
preserve_attribute(operation.second, prefixed_key, sv, p.full_keys, p.full_values, key_pool);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < sf.full_keys.size(); i++) {
|
for (size_t i = 0; i < sf.full_keys.size(); i++) {
|
||||||
const std::string key = *sf.full_keys[i];
|
const std::string key = *sf.full_keys[i];
|
||||||
int type = sf.full_values[i].type;
|
|
||||||
|
|
||||||
auto f = attribute_accum->find(key);
|
auto f = attribute_accum->find(key);
|
||||||
if (f != attribute_accum->end()) {
|
if (f != attribute_accum->end()) {
|
||||||
@@ -1514,12 +1500,6 @@ void preserve_attributes(std::unordered_map<std::string, attribute_op> const *at
|
|||||||
|
|
||||||
promote_attribute(key, p, key_pool); // promotes it in the target feature
|
promote_attribute(key, p, key_pool); // promotes it in the target feature
|
||||||
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, key_pool);
|
preserve_attribute(f->second, key, sv, p.full_keys, p.full_values, key_pool);
|
||||||
} else if (type == mvt_double && accumulate_numeric.size() > 0 && !starts_with(key, accumulate_numeric_colon)) {
|
|
||||||
for (auto const &operation : numeric_operations) {
|
|
||||||
std::string prefixed_key = accumulate_numeric + ":" + operation.first + ":" + key;
|
|
||||||
promote_attribute_prefix(key, prefixed_key, p, key_pool);
|
|
||||||
preserve_attribute(operation.second, prefixed_key, sf.full_values[i], p.full_keys, p.full_values, key_pool);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,31 +128,6 @@ TEST_CASE("Bit reversal", "bit reversal") {
|
|||||||
REQUIRE(bit_reverse(0xF3D912481E6A2C48) == 0x1234567812489BCF);
|
REQUIRE(bit_reverse(0xF3D912481E6A2C48) == 0x1234567812489BCF);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("mvt_geometry bbox") {
|
|
||||||
std::vector<mvt_geometry> geom;
|
|
||||||
|
|
||||||
geom.emplace_back(mvt_moveto, 128, 128);
|
|
||||||
geom.emplace_back(mvt_lineto, 256, 256);
|
|
||||||
|
|
||||||
long long xmin, ymin, xmax, ymax;
|
|
||||||
get_bbox(geom, &xmin, &ymin, &xmax, &ymax, 11, 327, 791, 9);
|
|
||||||
|
|
||||||
double lon, lat;
|
|
||||||
tile2lonlat(xmin, ymin, 32, &lon, &lat);
|
|
||||||
REQUIRE(std::to_string(lon) == "-122.475586");
|
|
||||||
REQUIRE(std::to_string(lat) == "37.822802");
|
|
||||||
|
|
||||||
tile2lonlat(xmax, ymax, 32, &lon, &lat);
|
|
||||||
REQUIRE(std::to_string(lon) == "-122.431641");
|
|
||||||
REQUIRE(std::to_string(lat) == "37.788081");
|
|
||||||
|
|
||||||
unsigned long long start, end;
|
|
||||||
get_quadkey_bounds(xmin, ymin, xmax, ymax, &start, &end);
|
|
||||||
// 22 bits in common, for z11
|
|
||||||
REQUIRE(start == 0x1c84fc0000000000);
|
|
||||||
REQUIRE(end == 0x1c84ffffffffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("line_is_too_small") {
|
TEST_CASE("line_is_too_small") {
|
||||||
drawvec dv;
|
drawvec dv;
|
||||||
dv.emplace_back(VT_MOVETO, 4243099709, 2683872952);
|
dv.emplace_back(VT_MOVETO, 4243099709, 2683872952);
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#ifndef VERSION_HPP
|
#ifndef VERSION_HPP
|
||||||
#define VERSION_HPP
|
#define VERSION_HPP
|
||||||
|
|
||||||
#define VERSION "v2.79.0"
|
#define VERSION "v2.80.0"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user