├── .gitignore ├── .gitmodules ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── bench ├── enf.t5yd5cdi_14_13089_8506.vector.mvt ├── multi_line_13_1310_3166.vector.mvt ├── readme.md ├── run-bench.sh ├── vtile-decode.cpp ├── vtile-encode.cpp └── vtile-transform.cpp ├── bin └── vtile-edit.cpp ├── bootstrap.sh ├── codecov.yml ├── examples ├── c++ │ ├── Makefile │ ├── README.md │ └── tileinfo.cpp └── data │ ├── 14_2620_6331-area_label.geojson │ ├── 14_2620_6331-barrier_line.geojson │ ├── 14_2620_6331-bridge.geojson │ ├── 14_2620_6331-building.geojson │ ├── 14_2620_6331-building_label.geojson │ ├── 14_2620_6331-landuse.geojson │ ├── 14_2620_6331-rail_station_label.geojson │ ├── 14_2620_6331-road.geojson │ ├── 14_2620_6331-road_label.geojson │ ├── 14_2620_6331-tunnel.geojson │ ├── 14_2620_6331-water.geojson │ ├── 14_2620_6331.geojson │ ├── 14_2620_6331.vector.mvt.z │ └── 14_8716_8015.vector.mvt ├── gyp ├── build.gyp └── common.gypi ├── include_dirs.js ├── install_mason.sh ├── package.json ├── proto └── vector_tile.proto ├── scripts ├── build.sh └── coverage.sh ├── src ├── boost_geometry_adapters.hpp ├── vector_tile_composite.hpp ├── vector_tile_compression.cpp ├── vector_tile_compression.hpp ├── vector_tile_compression.ipp ├── vector_tile_config.hpp ├── vector_tile_datasource_pbf.cpp ├── vector_tile_datasource_pbf.hpp ├── vector_tile_datasource_pbf.ipp ├── vector_tile_douglas_peucker.hpp ├── vector_tile_featureset_pbf.cpp ├── vector_tile_featureset_pbf.hpp ├── vector_tile_featureset_pbf.ipp ├── vector_tile_geometry_clipper.hpp ├── vector_tile_geometry_decoder.cpp ├── vector_tile_geometry_decoder.hpp ├── vector_tile_geometry_decoder.ipp ├── vector_tile_geometry_encoder_pbf.cpp ├── vector_tile_geometry_encoder_pbf.hpp ├── vector_tile_geometry_encoder_pbf.ipp ├── vector_tile_geometry_feature.hpp ├── vector_tile_geometry_simplifier.hpp ├── vector_tile_is_valid.hpp ├── vector_tile_layer.cpp ├── vector_tile_layer.hpp ├── vector_tile_layer.ipp ├── vector_tile_load_tile.hpp ├── vector_tile_merc_tile.hpp ├── vector_tile_processor.cpp ├── vector_tile_processor.hpp ├── vector_tile_processor.ipp ├── vector_tile_projection.hpp ├── vector_tile_raster_clipper.cpp ├── vector_tile_raster_clipper.hpp ├── vector_tile_raster_clipper.ipp ├── vector_tile_strategy.hpp ├── vector_tile_tile.cpp ├── vector_tile_tile.hpp └── vector_tile_tile.ipp └── test ├── catch.hpp ├── data ├── 0.0.0.vector-b.mvt ├── 0.0.0.vector.mvt ├── 256x256.png ├── NZ_Coastline_NZMG.dbf ├── NZ_Coastline_NZMG.prj ├── NZ_Coastline_NZMG.qpj ├── NZ_Coastline_NZMG.shp ├── NZ_Coastline_NZMG.shx ├── image.mvt ├── invalid-interior-ring.json ├── layer_scale_denom_style.xml ├── linestrings_and_point.geojson ├── natural_earth.tif ├── poly-lat-invalid-4269.dbf ├── poly-lat-invalid-4269.prj ├── poly-lat-invalid-4269.shp ├── poly-lat-invalid-4269.shx ├── poly.geojson ├── polygon-style.xml ├── raster_style.xml ├── simplified_geometry.geojson ├── simplified_geometry_pbf.geojson ├── singapore.dbf ├── singapore.prj ├── singapore.sbn ├── singapore.sbx ├── singapore.shp ├── singapore.shx ├── singapore.xml ├── style.xml ├── tile_with_extra_feature_field.mvt ├── tile_with_extra_field.mvt ├── tile_with_extra_layer_fields.mvt ├── tile_with_invalid_layer_value_type.mvt └── tile_with_unexpected_geomtype.mvt ├── fixtures ├── alpha-white-2.png ├── expected-1.png ├── expected-2.jpeg ├── expected-2.png ├── expected-3.png ├── expected-4.png ├── rasterize-expected-1.png ├── transform-expected-1.png └── transform-expected-2.png ├── geometry_visual_test.cpp ├── raster_tile.cpp ├── run.sh ├── system ├── encode_and_datasource_decode.cpp ├── encode_and_decode.cpp ├── processor_and_datasource.cpp ├── remove_repeated_point.cpp ├── round_trip.cpp ├── round_trip_fill_type.cpp └── round_trip_simplification.cpp ├── test_main.cpp ├── test_utils.cpp ├── test_utils.hpp ├── unit ├── composite │ └── vector.cpp ├── compression │ └── compression.cpp ├── datasource-pbf │ └── from_layer.cpp ├── decoding │ ├── linestring.cpp │ ├── point.cpp │ ├── polygon.cpp │ └── polygon_scaling.cpp ├── encoding │ ├── geometry_to_feature_pbf.cpp │ ├── linestring_pbf.cpp │ ├── point_pbf.cpp │ └── polygon_pbf.cpp ├── is_valid │ ├── feature_is_valid.cpp │ └── value_is_valid.cpp ├── layer_impl │ └── layer.cpp ├── load │ └── merge.cpp ├── processor │ ├── reprojection_error.cpp │ ├── scale_denom_filter.cpp │ └── variables.cpp └── tile_impl │ └── tile.cpp ├── utils ├── decoding_util.cpp ├── decoding_util.hpp ├── encoding_util.cpp ├── encoding_util.hpp ├── geom_to_wkt.cpp ├── geom_to_wkt.hpp ├── geometry_equal.hpp ├── round_trip.cpp └── round_trip.hpp ├── vector_tile.cpp ├── vector_tile_pbf.cpp ├── vector_tile_projection.cpp └── vector_tile_rasterize.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | build 3 | deps 4 | archive 5 | python 6 | .DS_Store 7 | src/vector_tile.pb.cc 8 | src/vector_tile.pb.h 9 | python/vector_tile_pb2.py 10 | test/run-test 11 | test/run-geom-test 12 | test/run-raster-test 13 | *pyc 14 | archive 15 | TODO.md 16 | examples/c++/tileinfo 17 | mason_packages 18 | mason/ 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/geometry-test-data"] 2 | path = test/geometry-test-data 3 | url = https://github.com/mapnik/geometry-test-data.git 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | archive 2 | examples 3 | python 4 | .DS_Store 5 | src/vector_tile.pb.cc 6 | src/vector_tile.pb.h 7 | python/vector_tile_pb2.py 8 | test/run-test 9 | *pyc 10 | archive 11 | TODO.md 12 | mason 13 | mason_packages 14 | deps 15 | build 16 | .travis.yml 17 | scripts 18 | gyp 19 | test 20 | CONTRIBUTING.md 21 | bootstrap.sh 22 | install_mason.sh 23 | bin 24 | bench 25 | codecov.yml 26 | proto/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | 3 | git: 4 | depth: 10 5 | 6 | cache: 7 | directories: 8 | - $HOME/.ccache 9 | 10 | env: 11 | global: 12 | - CCACHE_TEMPDIR=/tmp/.ccache-temp 13 | - CCACHE_COMPRESS=1 14 | 15 | matrix: 16 | include: 17 | - os: linux 18 | sudo: false 19 | compiler: ": gcc5" 20 | env: JOBS=10 CXX="ccache g++-5" 21 | addons: 22 | apt: 23 | sources: ['ubuntu-toolchain-r-test'] 24 | packages: [ 'libstdc++-5-dev','g++-5', 'xutils-dev'] 25 | - os: linux 26 | sudo: false 27 | compiler: ": clang" 28 | env: JOBS=10 CXX="ccache clang++-4.0 -Qunused-arguments" 29 | addons: 30 | apt: 31 | sources: ['ubuntu-toolchain-r-test'] 32 | packages: [ 'libstdc++-5-dev', 'xutils-dev'] 33 | # test a build with sse disabled 34 | - os: linux 35 | sudo: false 36 | compiler: ": clang" 37 | env: JOBS=10 SSE_MATH=false CXX="ccache clang++-4.0 -Qunused-arguments" 38 | addons: 39 | apt: 40 | sources: ['ubuntu-toolchain-r-test'] 41 | packages: [ 'libstdc++-5-dev', 'xutils-dev'] 42 | - os: linux 43 | sudo: false 44 | compiler: ": clang-coverage" 45 | env: JOBS=10 CXX="ccache clang++-4.0 -Qunused-arguments" COVERAGE=true 46 | addons: 47 | apt: 48 | sources: ['ubuntu-toolchain-r-test'] 49 | packages: [ 'libstdc++-5-dev', 'xutils-dev'] 50 | - os: osx 51 | compiler: clang 52 | env: JOBS=10 53 | # https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions 54 | osx_image: xcode8.3 # upgrades clang from 6 -> 7 55 | 56 | before_install: 57 | - ./install_mason.sh 58 | - | 59 | if [[ $(uname -s) == 'Linux' ]]; then 60 | ./mason/mason install llvm-cov 4.0.1 61 | ./mason/mason install clang++ 4.0.1 62 | export PATH=$(./mason/mason prefix clang++ 4.0.1)/bin:${PATH} 63 | which clang++ 64 | export PATH=$(./mason/mason prefix llvm-cov 4.0.1)/bin:${PATH} 65 | which llvm-cov 66 | fi 67 | 68 | install: 69 | - source ./scripts/build.sh 70 | 71 | before_script: 72 | - ./scripts/coverage.sh 73 | 74 | script: 75 | # make sure tileinfo command works 76 | - ./build/Debug/tileinfo examples/data/14_2620_6331.vector.mvt.z 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | General guidelines for contributing to mapnik-vector-tile 4 | 5 | ## Releasing 6 | 7 | To release a new mapnik-vector-tile version: 8 | 9 | - Make sure that all tests as passing (including travis tests). 10 | - Update the CHANGELOG.md 11 | - Make a "bump commit" by updating the version in `package.json` and adding a commit like `-m "bump to v0.8.5"` 12 | - Create a github tag like `git tag -a v0.8.5 -m "v0.8.5" && git push --tags` 13 | - Ensure travis tests are passing 14 | - Ensure you have a clean checkout (no extra files in your check that are not known by git). You need to be careful, for instance, to avoid a large accidental file being packaged by npm. You can get a view of what npm will publish by running `make testpack` 15 | - Then publish the module to npm repositories by running `npm publish` 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) MapBox 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | - Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | - Neither the name "MapBox" nor the names of its contributors may be 13 | used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #GYP_REVISION=6a5d2545 2 | 3 | SSE_MATH ?= true 4 | 5 | default: release 6 | 7 | mason_packages/.link/bin: 8 | SKIP_MAPNIK_INSTALL=YES ./install_mason.sh 9 | 10 | mason_packages/.link/bin/mapnik-config: 11 | ./install_mason.sh 12 | 13 | pre_build_check: 14 | @echo "Looking for mapnik-config on your PATH..." 15 | mapnik-config -v 16 | 17 | ./deps/gyp: 18 | git clone https://github.com/chromium/gyp ./deps/gyp && cd ./deps/gyp 19 | 20 | build/Makefile: pre_build_check ./deps/gyp gyp/build.gyp test/* 21 | python deps/gyp/gyp_main.py gyp/build.gyp -Denable_sse=$(SSE_MATH) --depth=. -DMAPNIK_PLUGINDIR=\"$(shell mapnik-config --input-plugins)\" -Goutput_dir=. --generator-output=./build -f make 22 | $(MAKE) -C build/ V=$(V) 23 | 24 | release: mason_packages/.link/bin/mapnik-config Makefile 25 | CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 $(CXXFLAGS)" $(MAKE) release_base 26 | 27 | debug: mason_packages/.link/bin/mapnik-config Makefile 28 | CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 $(CXXFLAGS)" $(MAKE) debug_base 29 | 30 | # note: we set PATH to the mason bins to pick up protoc 31 | # and CXXFLAGS/LDFLAGS to find protobuf headers/libs 32 | # This will only find mason installed mapnik-config if run via the `release` or `debug` targets 33 | release_base: mason_packages/.link/bin Makefile 34 | CXXFLAGS="-isystem `pwd`/mason_packages/.link/include $(CXXFLAGS)" \ 35 | LDFLAGS="-L`pwd`/mason_packages/.link/lib $(LDFLAGS)" \ 36 | PATH="`pwd`/mason_packages/.link/bin/:${PATH}" \ 37 | BUILDTYPE=Release $(MAKE) build/Makefile 38 | 39 | debug_base: mason_packages/.link/bin Makefile 40 | CXXFLAGS="-isystem `pwd`/mason_packages/.link/include $(CXXFLAGS)" \ 41 | LDFLAGS="-L`pwd`/mason_packages/.link/lib $(LDFLAGS)" \ 42 | PATH="`pwd`/mason_packages/.link/bin/:${PATH}" \ 43 | BUILDTYPE=Debug $(MAKE) build/Makefile 44 | 45 | test/geometry-test-data/README.md: 46 | git submodule update --init 47 | 48 | test: test/geometry-test-data/README.md 49 | BUILDTYPE=Release ./test/run.sh 50 | 51 | test-debug: test/geometry-test-data/README.md 52 | BUILDTYPE=Debug ./test/run.sh 53 | 54 | testpack: 55 | rm -f ./*tgz 56 | npm pack 57 | tar -ztvf *tgz 58 | rm -f ./*tgz 59 | 60 | clean: 61 | rm -rf ./build 62 | 63 | distclean: clean 64 | rm -rf ./mason 65 | rm -rf ./deps/gyp 66 | rm -rf ./mason_packages 67 | 68 | .PHONY: test build/Makefile 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## mapnik-vector-tile 2 | 3 | A Mapnik implemention of [Mapbox Vector Tile specification](https://github.com/mapbox/vector-tile-spec). 4 | 5 | Provides C++ headers that support rendering geodata into vector tiles and rendering vector tiles into images. 6 | 7 | - Master: [![Build Status](https://travis-ci.com/mapbox/mapnik-vector-tile.svg?branch=master)](https://travis-ci.com/mapbox/mapnik-vector-tile) 8 | - 0.6.x series: [![Build Status](https://secure.travis-ci.com/mapbox/mapnik-vector-tile.svg?branch=0.6.x)](http://travis-ci.com/mapbox/mapnik-vector-tile) 9 | 10 | [![codecov](https://codecov.io/gh/mapbox/mapnik-vector-tile/branch/master/graph/badge.svg)](https://codecov.io/gh/mapbox/mapnik-vector-tile) 11 | 12 | ## Depends 13 | 14 | ## Implementation details 15 | 16 | Vector tiles in this code represent a direct serialization of Mapnik layers optimized for space efficient storage and fast deserialization. For those familiar with the Mapnik API vector tiles here can be considered a named array of `mapnik::featureset_ptr` whose geometries have been pre-tiled. 17 | 18 | For more details see [vector-tile-spec](https://github.com/mapbox/vector-tile-spec). 19 | 20 | ## Building from source 21 | 22 | If you do not need to build against an external mapnik, just type: 23 | 24 | make 25 | 26 | This will download all deps (including Mapnik) and compile against them. 27 | 28 | To build and test in debug mode do: 29 | 30 | make debug test-debug 31 | 32 | If you have Mapnik, libprotobuf, and all the Mapnik deps already installed on your system then you can build against them with: 33 | 34 | make release_base 35 | 36 | Note: SSE optimizations are enabled by default. If you want to turn them off do: 37 | 38 | ``` 39 | SSE_MATH=false make 40 | ``` 41 | 42 | If building against an external Mapnik please know that Mapnik Vector Tile does not currently support Mapnik 3.1.x. 43 | 44 | - mapnik-vector-tile >=1.4.x depends on Mapnik >=v3.0.14 45 | - mapnik-vector-tile >=1.0.x depends on Mapnik >=v3.0.11 46 | - mapnik-vector-tile 1.0.0 to 0.7.x depends on Mapnik v3.0.x (until 3.0.0 is released this means latest mapnik HEAD) 47 | - mapnik-vector-tile 0.6.x and previous work with Mapnik v2.2.x or v2.3.x 48 | - You will need `libmapnik` and `mapnik-config` available 49 | - Protobuf: `libprotobuf` and `protoc` 50 | 51 | 52 | ## Tests 53 | 54 | Run the C++ tests like: 55 | 56 | make test 57 | 58 | ## Examples 59 | 60 | ### C++ 61 | 62 | See examples in examples/c++ 63 | 64 | ## Authors 65 | 66 | - [Artem Pavlenko](https://github.com/artemp) 67 | - [Dane Springmeyer](https://github.com/springmeyer) 68 | - [Konstantin Käfer](https://github.com/kkaefer) 69 | 70 | ## See also 71 | 72 | - http://mike.teczno.com/notes/postgreslessness-mapnik-vectiles.html 73 | - https://github.com/jones139/ceramic 74 | - https://github.com/opensciencemap/vtm 75 | -------------------------------------------------------------------------------- /bench/enf.t5yd5cdi_14_13089_8506.vector.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/bench/enf.t5yd5cdi_14_13089_8506.vector.mvt -------------------------------------------------------------------------------- /bench/multi_line_13_1310_3166.vector.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/bench/multi_line_13_1310_3166.vector.mvt -------------------------------------------------------------------------------- /bench/readme.md: -------------------------------------------------------------------------------- 1 | ### decode benchmark 2 | 3 | With reserve 4 | 5 | ``` 6 | $ ./build/Release/vtile-decode bench/multi_line_13_1310_3166.vector.mvt 13 1310 3166 7 | z:13 x:1310 y:3166 iterations:100 8 | message: zlib compressed 9 | 4026.30ms (cpu 4020.96ms) | decode as datasource_pbf: bench/multi_line_13_1310_3166.vector.mvt 10 | ``` 11 | 12 | without reserve code 13 | 14 | ``` 15 | $ ./build/Release/vtile-decode bench/multi_line_13_1310_3166.vector.mvt 13 1310 3166 16 | z:13 x:1310 y:3166 iterations:100 17 | message: zlib compressed 18 | 4296.88ms (cpu 4289.05ms) | decode as datasource_pbf: bench/multi_line_13_1310_3166.vector.mvt 19 | ``` 20 | --------- 21 | 22 | baseline (using mapnik::geometry::envelope + filter.pass) 23 | 24 | ``` 25 | $ .//build/Release/vtile-decode bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 14 13089 8506 200 26 | z:14 x:13089 y:8506 iterations:200 27 | 2822.66ms (cpu 2821.10ms) | decode as datasource_pbf: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 28 | 2070.90ms (cpu 2070.44ms) | decode as datasource: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 29 | processed 6800 features 30 | ``` 31 | 32 | ``` 33 | $ ./build/Release/vtile-decode bench/multi_line_13_1310_3166.vector.mvt 13 1310 3166 100 34 | z:13 x:1310 y:3166 iterations:100 35 | message: zlib compressed 36 | 4289.26ms (cpu 4275.29ms) | decode as datasource_pbf: bench/multi_line_13_1310_3166.vector.mvt 37 | ``` 38 | 39 | commenting filter.pass/geometry::envelope in datasource_pbf 40 | 41 | ``` 42 | $ .//build/Release/vtile-decode bench/enf.t5yd5cdi_14_13089_8506.vector.pbf 14 13089 8506 200 43 | z:14 x:13089 y:8506 iterations:200 44 | 2305.45ms (cpu 2301.07ms) | decode as datasource_pbf: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 45 | 2142.56ms (cpu 2140.40ms) | decode as datasource: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 46 | processed 6800 features 47 | ``` 48 | 49 | 50 | with bbox filter: 51 | 52 | ``` 53 | $ .//build/Release/vtile-decode bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 14 13089 8506 200 54 | z:14 x:13089 y:8506 iterations:200 55 | 2497.01ms (cpu 2493.40ms) | decode as datasource_pbf: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 56 | 1753.55ms (cpu 1751.10ms) | decode as datasource: bench/enf.t5yd5cdi_14_13089_8506.vector.mvt 57 | processed 6600 features 58 | ``` 59 | 60 | ``` 61 | $ ./build/Release/vtile-decode bench/multi_line_13_1310_3166.vector.mvt 13 1310 3166 100 62 | z:13 x:1310 y:3166 iterations:100 63 | message: zlib compressed 64 | 4090.67ms (cpu 4083.65ms) | decode as datasource_pbf: bench/multi_line_13_1310_3166.vector.mvt 65 | ``` 66 | 67 | ### encode benchmark: 68 | 69 | ``` 70 | $ ./build/Release/vtile-encode ./test/data/linestrings_and_point.geojson 0 0 0 71 | ``` 72 | -------------------------------------------------------------------------------- /bench/run-bench.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # encode geojson 4 | if [ "$1" == "encode" ] ; then 5 | FILE_PATH=./test/geometry-test-data/input/* 6 | COMMAND=./build/Release/vtile-encode 7 | for f in $FILE_PATH 8 | do 9 | echo "${f##*/}" 10 | for n in 10000 20000 30000 40000 50000 60000 70000 80000 90000 100000 11 | do 12 | DYLD_LIBRARY_PATH=$MVT_LIBRARY_PATH $COMMAND $f 0 0 0 -i $n 13 | done 14 | echo " " 15 | echo " " 16 | done 17 | #decode pbf 18 | elif [ "$1" == "decode" ] ; then 19 | FILE_PATH=./test/data/**.pbf 20 | COMMAND=./build/Release/vtile-decode 21 | for f in $FILE_PATH 22 | do 23 | echo "${f##*/}" 24 | for n in 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 25 | do 26 | DYLD_LIBRARY_PATH=$MVT_LIBRARY_PATH $COMMAND $f 0 0 0 $n 27 | done 28 | echo " " 29 | echo " " 30 | done 31 | else 32 | echo "Please specify 'encode' or 'decode'" 33 | fi 34 | -------------------------------------------------------------------------------- /bench/vtile-decode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "vector_tile_datasource_pbf.hpp" 4 | #include "vector_tile_compression.hpp" 5 | 6 | #pragma GCC diagnostic push 7 | #pragma GCC diagnostic ignored "-Wunused-parameter" 8 | #pragma GCC diagnostic ignored "-Wsign-conversion" 9 | #include "vector_tile.pb.h" 10 | #pragma GCC diagnostic pop 11 | 12 | #include 13 | 14 | #include 15 | 16 | int main(int argc, char** argv) 17 | { 18 | try 19 | { 20 | 21 | if (argc < 4) 22 | { 23 | std::clog << "usage: vtile-decode /path/to/tile.vector.mvt z x y [iterations]\n"; 24 | return -1; 25 | } 26 | std::string vtile(argv[1]); 27 | mapnik::util::file input(vtile); 28 | if (!input.is_open()) 29 | { 30 | std::clog << std::string("failed to open ") + vtile << "\n"; 31 | return -1; 32 | } 33 | 34 | int z = std::stoi(argv[2]); 35 | int x = std::stoi(argv[3]); 36 | int y = std::stoi(argv[4]); 37 | 38 | std::size_t iterations = 100; 39 | if (argc > 5) 40 | { 41 | iterations = std::stoi(argv[5]); 42 | } 43 | 44 | std::clog << "z:" << z << " x:" << x << " y:" << y << " iterations:" << iterations << "\n"; 45 | 46 | std::string message(input.data().get(), input.size()); 47 | bool is_zlib = mapnik::vector_tile_impl::is_zlib_compressed(message); 48 | bool is_gzip = mapnik::vector_tile_impl::is_gzip_compressed(message); 49 | if (is_zlib || is_gzip) 50 | { 51 | if (is_zlib) 52 | { 53 | std::cout << "message: zlib compressed\n"; 54 | } 55 | else if (is_gzip) 56 | { 57 | std::cout << "message: gzip compressed\n"; 58 | } 59 | std::string uncompressed; 60 | mapnik::vector_tile_impl::zlib_decompress(message,uncompressed); 61 | message = uncompressed; 62 | } 63 | 64 | std::size_t feature_count = 0; 65 | std::size_t layer_count = 0; 66 | { 67 | mapnik::progress_timer __stats__(std::clog, std::string("decode as datasource_pbf: ") + vtile); 68 | for (std::size_t i=0;i(layer,x,y,z); 75 | mapnik::query q(ds->get_tile_extent()); 76 | auto fs = ds->features(q); 77 | if (!fs) continue; 78 | while (fs->next()) { 79 | ++feature_count; 80 | } 81 | } 82 | } 83 | } 84 | 85 | if (feature_count == 0) 86 | { 87 | std::clog << "error: no features processed\n"; 88 | return -1; 89 | } 90 | else 91 | { 92 | std::clog << "processed " << feature_count << " features\n"; 93 | } 94 | } 95 | catch (std::exception const& ex) 96 | { 97 | std::clog << "error: " << ex.what() << "\n"; 98 | return -1; 99 | } 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /bench/vtile-transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if MAPNIK_VERSION >= 300100 4 | #include 5 | #include 6 | #else 7 | #include 8 | #include 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "vector_tile_strategy.hpp" 17 | #include "vector_tile_projection.hpp" 18 | 19 | /* 20 | 21 | # 10000 times 22 | no reserve + transform_visitor 23 | - 2.77 24 | 25 | with reserve 26 | - 1.69 27 | 28 | boost::geometry::transform 29 | - 2.3 30 | 31 | */ 32 | 33 | int main() 34 | { 35 | mapnik::projection merc("+init=epsg:3857",true); 36 | mapnik::projection merc2("+init=epsg:4326",true); 37 | mapnik::proj_transform prj_trans(merc,merc); // no-op 38 | mapnik::proj_transform prj_trans2(merc2,merc); // op 39 | unsigned tile_size = 256; 40 | mapnik::box2d z15_extent = mapnik::vector_tile_impl::tile_mercator_bbox(9664,20435,15); 41 | unsigned path_multiplier = 16; 42 | mapnik::view_transform tr(tile_size * path_multiplier, 43 | tile_size * path_multiplier, 44 | z15_extent,0,0); 45 | std::string geojson_file("./test/data/poly.geojson"); 46 | mapnik::util::file input(geojson_file); 47 | if (!input.is_open()) 48 | { 49 | throw std::runtime_error("failed to open geojson"); 50 | } 51 | mapnik::geometry::geometry geom; 52 | std::string json_string(input.data().get(), input.size()); 53 | if (!mapnik::json::from_geojson(json_string, geom)) 54 | { 55 | throw std::runtime_error("failed to parse geojson"); 56 | } 57 | mapnik::geometry::correct(geom); 58 | 59 | unsigned count = 0; 60 | unsigned count2 = 0; 61 | unsigned count3 = 0; 62 | unsigned count4 = 0; 63 | { 64 | mapnik::vector_tile_impl::vector_tile_strategy vs(tr); 65 | mapnik::progress_timer __stats__(std::clog, "boost::geometry::transform"); 66 | for (unsigned i=0;i<10000;++i) 67 | { 68 | mapnik::geometry::geometry new_geom = mapnik::geometry::transform(geom, vs); 69 | auto const& poly = mapbox::util::get>(new_geom); 70 | count += poly.size(); 71 | } 72 | } 73 | { 74 | mapnik::vector_tile_impl::vector_tile_strategy_proj vs(prj_trans,tr); 75 | mapnik::progress_timer __stats__(std::clog, "transform_visitor with reserve with proj no-op"); 76 | mapnik::box2d clip_extent(std::numeric_limits::min(), 77 | std::numeric_limits::min(), 78 | std::numeric_limits::max(), 79 | std::numeric_limits::max()); 80 | mapnik::vector_tile_impl::geom_out_visitor out_geom; 81 | mapnik::vector_tile_impl::transform_visitor< 82 | mapnik::vector_tile_impl::vector_tile_strategy_proj, 83 | mapnik::vector_tile_impl::geom_out_visitor 84 | > transit(vs, clip_extent, out_geom); 85 | for (unsigned i=0;i<10000;++i) 86 | { 87 | mapbox::util::apply_visitor(transit,geom); 88 | auto const& poly = mapbox::util::get>(*out_geom.geom); 89 | count2 += poly.size(); 90 | } 91 | if (count != count2) 92 | { 93 | std::clog << "tests did not run as expected!\n"; 94 | return -1; 95 | } 96 | } 97 | { 98 | mapnik::vector_tile_impl::vector_tile_strategy_proj vs(prj_trans2,tr); 99 | mapnik::progress_timer __stats__(std::clog, "transform_visitor with reserve with proj op"); 100 | mapnik::box2d clip_extent(std::numeric_limits::min(), 101 | std::numeric_limits::min(), 102 | std::numeric_limits::max(), 103 | std::numeric_limits::max()); 104 | mapnik::vector_tile_impl::geom_out_visitor out_geom; 105 | mapnik::vector_tile_impl::transform_visitor< 106 | mapnik::vector_tile_impl::vector_tile_strategy_proj, 107 | mapnik::vector_tile_impl::geom_out_visitor 108 | > transit(vs, clip_extent, out_geom); 109 | for (unsigned i=0;i<10000;++i) 110 | { 111 | mapbox::util::apply_visitor(transit,geom); 112 | auto const& poly = mapbox::util::get>(*out_geom.geom); 113 | count4 += poly.size(); 114 | } 115 | if (count != count4) 116 | { 117 | std::clog << "tests did not run as expected!\n"; 118 | return -1; 119 | } 120 | } 121 | { 122 | mapnik::vector_tile_impl::vector_tile_strategy vs(tr); 123 | mapnik::progress_timer __stats__(std::clog, "transform_visitor with reserve with no proj function call overhead"); 124 | mapnik::box2d clip_extent(std::numeric_limits::min(), 125 | std::numeric_limits::min(), 126 | std::numeric_limits::max(), 127 | std::numeric_limits::max()); 128 | mapnik::vector_tile_impl::geom_out_visitor out_geom; 129 | mapnik::vector_tile_impl::transform_visitor< 130 | mapnik::vector_tile_impl::vector_tile_strategy, 131 | mapnik::vector_tile_impl::geom_out_visitor 132 | > transit(vs, clip_extent, out_geom); 133 | for (unsigned i=0;i<10000;++i) 134 | { 135 | mapnik::util::apply_visitor(transit,geom); 136 | auto const& poly = mapbox::util::get>(*out_geom.geom); 137 | count3 += poly.size(); 138 | } 139 | if (count != count3) 140 | { 141 | std::clog << "tests did not run as expected!\n"; 142 | return -1; 143 | } 144 | } 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /bin/vtile-edit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "vector_tile.pb.h" 3 | #include "vector_tile_compression.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int main(int argc, char** argv) 11 | { 12 | try 13 | { 14 | if (argc < 2) 15 | { 16 | std::clog << "usage: vtile-edit /path/to/tile.vector.mvt [--set-version version]" << std::endl; 17 | return -1; 18 | } 19 | std::string vtile(argv[1]); 20 | mapnik::util::file input(vtile); 21 | if (!input.is_open()) 22 | { 23 | std::clog << std::string("failed to open ") + vtile << "\n"; 24 | return -1; 25 | } 26 | 27 | unsigned version = 0; 28 | bool clean_empty = false; 29 | if (argc > 2) 30 | { 31 | for (int i = 2; i < argc; i++) 32 | { 33 | std::string flag = argv[i]; 34 | if (flag == "--set-version") 35 | { 36 | version = std::stoi(argv[i + 1]); 37 | } 38 | if (flag == "--clean-empty") 39 | { 40 | clean_empty = true; 41 | } 42 | } 43 | } 44 | 45 | std::string message(input.data().get(), input.size()); 46 | 47 | bool is_zlib = mapnik::vector_tile_impl::is_zlib_compressed(message); 48 | bool is_gzip = mapnik::vector_tile_impl::is_gzip_compressed(message); 49 | if (is_zlib || is_gzip) 50 | { 51 | if (is_zlib) 52 | { 53 | std::cout << "message: zlib compressed\n"; 54 | } 55 | else if (is_gzip) 56 | { 57 | std::cout << "message: gzip compressed\n"; 58 | } 59 | std::string uncompressed; 60 | mapnik::vector_tile_impl::zlib_decompress(message,uncompressed); 61 | message = uncompressed; 62 | } 63 | 64 | vector_tile::Tile tile; 65 | tile.ParseFromString(message); 66 | 67 | for (int j=0;jname() << std::endl; 71 | if (version != 0) 72 | { 73 | std::clog << "old version: " << layer->version() << std::endl; 74 | if (version != layer->version()) 75 | { 76 | layer->set_version(version); 77 | } 78 | std::clog << "new version: " << layer->version() << std::endl; 79 | } 80 | if (clean_empty) 81 | { 82 | std::clog << "Cleaning empty features" << std::endl; 83 | for (int i = 0; i < layer->features_size(); ++i) 84 | { 85 | auto feature = layer->mutable_features(i); 86 | if (feature->geometry_size() == 0 && !feature->has_raster()) 87 | { 88 | layer->mutable_features()->DeleteSubrange(i,1); 89 | --i; 90 | } 91 | } 92 | if (layer->features_size() == 0) 93 | { 94 | tile.mutable_layers()->DeleteSubrange(j,1); 95 | --j; 96 | } 97 | } 98 | } 99 | 100 | // Serialize 101 | std::string output; 102 | tile.SerializeToString(&output); 103 | 104 | // Recompress 105 | bool gzip = true; 106 | if (is_zlib || is_gzip) 107 | { 108 | if (is_zlib) 109 | { 110 | gzip = false; 111 | std::cout << "message: zlib compressing\n"; 112 | } 113 | else if (is_gzip) 114 | { 115 | gzip = true; 116 | std::cout << "message: gzip compressing\n"; 117 | } 118 | std::string compressed; 119 | mapnik::vector_tile_impl::zlib_compress(output,compressed,gzip); 120 | output = compressed; 121 | } 122 | 123 | std::ofstream file(vtile); 124 | file << output; 125 | 126 | std::clog << "wrote to: " << vtile << std::endl; 127 | } 128 | catch (std::exception const& ex) 129 | { 130 | std::clog << "error: " << ex.what() << "\n"; 131 | return -1; 132 | } 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # if built against mason package fix dynamic data locations 4 | function setup_runtime_settings() { 5 | if [[ -f $(pwd)/mason_packages/.link/bin/mapnik-config ]]; then 6 | # TODO: use --proj-lib, --gdal-data, etc after https://github.com/mapnik/mapnik/pull/3759 is fixed 7 | #export PROJ_LIB=$(mapnik-config --proj-lib) 8 | #export GDAL_DATA=$(mapnik-config --gdal-data) 9 | #export ICU_DATA=$(mapnik-config --icu-data) 10 | local MASON_LINKED_ABS=$(pwd)/mason_packages/.link 11 | export PROJ_LIB=${MASON_LINKED_ABS}/share/proj 12 | ICU_VERSION=$(ls ${MASON_LINKED_ABS}/share/icu/) 13 | export ICU_DATA=${MASON_LINKED_ABS}/share/icu/${ICU_VERSION} 14 | export GDAL_DATA=${MASON_LINKED_ABS}/share/gdal 15 | if [[ $(uname -s) == 'Darwin' ]]; then 16 | export DYLD_LIBRARY_PATH=$(pwd)/mason_packages/.link/lib:${DYLD_LIBRARY_PATH:-} 17 | # OS X > 10.11 blocks DYLD_LIBRARY_PATH so we pass along using a 18 | # differently named variable 19 | export MVT_LIBRARY_PATH=${DYLD_LIBRARY_PATH} 20 | else 21 | export LD_LIBRARY_PATH=$(pwd)/mason_packages/.link/lib:${LD_LIBRARY_PATH:-} 22 | fi 23 | export PATH=$(pwd)/mason_packages/.link/bin:${PATH} 24 | fi 25 | } 26 | 27 | function main() { 28 | setup_runtime_settings 29 | echo "Ready, now run:" 30 | echo "" 31 | echo " make test" 32 | } 33 | 34 | main 35 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "bin" 3 | - "bench" 4 | - "examples" 5 | - "test" -------------------------------------------------------------------------------- /examples/c++/Makefile: -------------------------------------------------------------------------------- 1 | PROTOBUF_CXXFLAGS=$(shell pkg-config protobuf --cflags) 2 | PROTOBUF_LDFLAGS=$(shell pkg-config protobuf --libs-only-L) -lprotobuf-lite 3 | CXXFLAGS := $(CXXFLAGS) # inherit from env 4 | LDFLAGS := $(LDFLAGS) # inherit from env 5 | 6 | all: tileinfo 7 | 8 | tileinfo: tileinfo.cpp ../../src/vector_tile.pb.cc 9 | $(CXX) $(CXXFLAGS) $(PROTOBUF_CXXFLAGS) $(LDFLAGS) $(PROTOBUF_LDFLAGS) tileinfo.cpp ../../src/vector_tile.pb.cc -o tileinfo -lprotobuf-lite -lz 10 | 11 | install: tileinfo 12 | mkdir -p /usr/local/bin 13 | cp ./tileinfo /usr/local/bin/tileinfo 14 | chmod +x /usr/local/bin/tileinfo 15 | 16 | test: 17 | ./tileinfo ../data/14_8716_8015.vector.mvt 18 | ./tileinfo ../data/14_2620_6331.vector.mvt.z 19 | 20 | clean: 21 | @rm -f ./tileinfo 22 | 23 | .PHONY: test 24 | -------------------------------------------------------------------------------- /examples/c++/README.md: -------------------------------------------------------------------------------- 1 | 2 | # tileinfo 3 | 4 | A commandline tool to dump details about what layers, features, and geometries exist in a vector tile. 5 | 6 | Vector tiles can be either zlib deflated (compressed) or not. 7 | 8 | 9 | ## Depends 10 | 11 | - C++ compiler 12 | - libprotobuf 13 | 14 | Install these dependencies on Ubuntu: 15 | 16 | apt-get install pkg-config libprotobuf7 libprotobuf-dev protobuf-compiler build-essential g++ 17 | 18 | Install these dependencies on OS X: 19 | 20 | brew install pkg-config protobuf 21 | 22 | ## Installation 23 | 24 | make 25 | 26 | ## Usage 27 | 28 | tileinfo ../data/14_8716_8015.vector.mvt 29 | -------------------------------------------------------------------------------- /examples/data/14_2620_6331-barrier_line.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "LineString", 8 | "coordinates": [ 9 | [ 10 | -122.4106764793396, 11 | 37.797488026453316 12 | ], 13 | [ 14 | -122.41059064865112, 15 | 37.797500743050065 16 | ] 17 | ] 18 | }, 19 | "properties": { 20 | "class": "fence" 21 | } 22 | }, 23 | { 24 | "type": "Feature", 25 | "geometry": { 26 | "type": "LineString", 27 | "coordinates": [ 28 | [ 29 | -122.42149651050568, 30 | 37.80330352159015 31 | ], 32 | [ 33 | -122.42159307003023, 34 | 37.80351120937674 35 | ], 36 | [ 37 | -122.42170572280884, 38 | 37.80357478715385 39 | ], 40 | [ 41 | -122.4218773841858, 42 | 37.80360445676443 43 | ], 44 | [ 45 | -122.42223143577577, 46 | 37.8035875027027 47 | ] 48 | ] 49 | }, 50 | "properties": { 51 | "class": "fence" 52 | } 53 | }, 54 | { 55 | "type": "Feature", 56 | "geometry": { 57 | "type": "LineString", 58 | "coordinates": [ 59 | [ 60 | -122.41996765136719, 61 | 37.79620363890844 62 | ], 63 | [ 64 | -122.41783797740936, 65 | 37.79647493054711 66 | ], 67 | [ 68 | -122.41766095161438, 69 | 37.79650036408717 70 | ] 71 | ] 72 | }, 73 | "properties": { 74 | "class": "fence" 75 | } 76 | }, 77 | { 78 | "type": "Feature", 79 | "geometry": { 80 | "type": "LineString", 81 | "coordinates": [ 82 | [ 83 | -122.41993546485901, 84 | 37.79603408112835 85 | ], 86 | [ 87 | -122.4178057909012, 88 | 37.79630113445578 89 | ], 90 | [ 91 | -122.41762340068819, 92 | 37.796326568055655 93 | ] 94 | ] 95 | }, 96 | "properties": { 97 | "class": "fence" 98 | } 99 | }, 100 | { 101 | "type": "Feature", 102 | "geometry": { 103 | "type": "LineString", 104 | "coordinates": [ 105 | [ 106 | -122.42317020893097, 107 | 37.7972040218895 108 | ], 109 | [ 110 | -122.42319703102112, 111 | 37.797318471621196 112 | ], 113 | [ 114 | -122.42319166660309, 115 | 37.797318471621196 116 | ] 117 | ] 118 | }, 119 | "properties": { 120 | "class": "fence" 121 | } 122 | }, 123 | { 124 | "type": "Feature", 125 | "geometry": { 126 | "type": "LineString", 127 | "coordinates": [ 128 | [ 129 | -122.42300391197205, 130 | 37.797314232745414 131 | ], 132 | [ 133 | -122.42307364940643, 134 | 37.79730575499309 135 | ], 136 | [ 137 | -122.42307901382446, 138 | 37.79733118824711 139 | ] 140 | ] 141 | }, 142 | "properties": { 143 | "class": "fence" 144 | } 145 | }, 146 | { 147 | "type": "Feature", 148 | "geometry": { 149 | "type": "LineString", 150 | "coordinates": [ 151 | [ 152 | -122.42313802242279, 153 | 37.79686491053231 154 | ], 155 | [ 156 | -122.42310583591461, 157 | 37.79686914943388 158 | ] 159 | ] 160 | }, 161 | "properties": { 162 | "class": "fence" 163 | } 164 | }, 165 | { 166 | "type": "Feature", 167 | "geometry": { 168 | "type": "LineString", 169 | "coordinates": [ 170 | [ 171 | -122.41827249526978, 172 | 37.80348153972869 173 | ], 174 | [ 175 | -122.41839051246643, 176 | 37.80405373798221 177 | ], 178 | [ 179 | -122.41847634315491, 180 | 37.80414274620096 181 | ], 182 | [ 183 | -122.4185460805893, 184 | 37.80413426923238 185 | ] 186 | ] 187 | }, 188 | "properties": { 189 | "class": "fence" 190 | } 191 | }, 192 | { 193 | "type": "Feature", 194 | "geometry": { 195 | "type": "LineString", 196 | "coordinates": [ 197 | [ 198 | -122.42148578166962, 199 | 37.8028923828208 200 | ], 201 | [ 202 | -122.42155015468599, 203 | 37.80322722797084 204 | ] 205 | ] 206 | }, 207 | "properties": { 208 | "class": "fence" 209 | } 210 | }, 211 | { 212 | "type": "Feature", 213 | "geometry": { 214 | "type": "LineString", 215 | "coordinates": [ 216 | [ 217 | -122.41452276706696, 218 | 37.796983599684395 219 | ], 220 | [ 221 | -122.41449058055878, 222 | 37.796835238214484 223 | ] 224 | ] 225 | }, 226 | "properties": { 227 | "class": "fence" 228 | } 229 | }, 230 | { 231 | "type": "Feature", 232 | "geometry": { 233 | "type": "LineString", 234 | "coordinates": [ 235 | [ 236 | -122.41538643836975, 237 | 37.798017882795456 238 | ], 239 | [ 240 | -122.41534352302551, 241 | 37.79781441840957 242 | ] 243 | ] 244 | }, 245 | "properties": { 246 | "class": "fence" 247 | } 248 | }, 249 | { 250 | "type": "Feature", 251 | "geometry": { 252 | "type": "LineString", 253 | "coordinates": [ 254 | [ 255 | -122.41532742977142, 256 | 37.79772540256451 257 | ], 258 | [ 259 | -122.41528451442719, 260 | 37.79752617623693 261 | ] 262 | ] 263 | }, 264 | "properties": { 265 | "class": "fence" 266 | } 267 | }, 268 | { 269 | "type": "Feature", 270 | "geometry": { 271 | "type": "LineString", 272 | "coordinates": [ 273 | [ 274 | -122.41532742977142, 275 | 37.79781865725665 276 | ], 277 | [ 278 | -122.41531133651733, 279 | 37.79772964141673 280 | ] 281 | ] 282 | }, 283 | "properties": { 284 | "class": "fence" 285 | } 286 | } 287 | ], 288 | "name": "barrier_line" 289 | } -------------------------------------------------------------------------------- /examples/data/14_2620_6331-bridge.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "LineString", 8 | "coordinates": [ 9 | [ 10 | -122.41849780082703, 11 | 37.79639862987445 12 | ], 13 | [ 14 | -122.41846024990083, 15 | 37.79621635572625 16 | ] 17 | ] 18 | }, 19 | "properties": { 20 | "class": "street", 21 | "layer": 1, 22 | "oneway": 0 23 | } 24 | }, 25 | { 26 | "type": "Feature", 27 | "geometry": { 28 | "type": "LineString", 29 | "coordinates": [ 30 | [ 31 | -122.41861045360565, 32 | 37.79641982451364 33 | ], 34 | [ 35 | -122.41856217384338, 36 | 37.79616972738355 37 | ] 38 | ] 39 | }, 40 | "properties": { 41 | "class": "path", 42 | "layer": 1, 43 | "oneway": 0 44 | } 45 | }, 46 | { 47 | "type": "Feature", 48 | "geometry": { 49 | "type": "LineString", 50 | "coordinates": [ 51 | [ 52 | -122.41839587688446, 53 | 37.79644525807265 54 | ], 55 | [ 56 | -122.41833150386809, 57 | 37.79618244420722 58 | ] 59 | ] 60 | }, 61 | "properties": { 62 | "class": "path", 63 | "layer": 1, 64 | "oneway": 0 65 | } 66 | }, 67 | { 68 | "type": "Feature", 69 | "geometry": { 70 | "type": "LineString", 71 | "coordinates": [ 72 | [ 73 | -122.41844415664673, 74 | 37.79622059466506 75 | ], 76 | [ 77 | -122.41848707199097, 78 | 37.79640286880277 79 | ] 80 | ] 81 | }, 82 | "properties": { 83 | "class": "minor_rail", 84 | "layer": 1, 85 | "oneway": 0 86 | } 87 | }, 88 | { 89 | "type": "Feature", 90 | "geometry": { 91 | "type": "LineString", 92 | "coordinates": [ 93 | [ 94 | -122.41851925849915, 95 | 37.79639862987445 96 | ], 97 | [ 98 | -122.41848170757295, 99 | 37.79621635572625 100 | ] 101 | ] 102 | }, 103 | "properties": { 104 | "class": "minor_rail", 105 | "layer": 1, 106 | "oneway": 0 107 | } 108 | } 109 | ], 110 | "name": "bridge" 111 | } -------------------------------------------------------------------------------- /examples/data/14_2620_6331-rail_station_label.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "Point", 8 | "coordinates": [ 9 | -122.40694284439087, 10 | 37.78496111569185 11 | ] 12 | }, 13 | "properties": { 14 | "class": "light", 15 | "group": "name", 16 | "name": "Powell Muni", 17 | "name_de": "Powell Muni", 18 | "name_en": "Powell Muni", 19 | "name_es": "Powell Muni", 20 | "name_fr": "Powell Muni", 21 | "network": "light" 22 | } 23 | }, 24 | { 25 | "type": "Feature", 26 | "geometry": { 27 | "type": "Point", 28 | "coordinates": [ 29 | -122.40691065788269, 30 | 37.78493143859335 31 | ] 32 | }, 33 | "properties": { 34 | "class": "light", 35 | "group": "name", 36 | "name": "Powell", 37 | "name_de": "Powell", 38 | "name_en": "Powell", 39 | "name_es": "Powell", 40 | "name_fr": "Powell", 41 | "network": "light" 42 | } 43 | }, 44 | { 45 | "type": "Feature", 46 | "geometry": { 47 | "type": "Point", 48 | "coordinates": [ 49 | -122.40694284439087, 50 | 37.78496111569185 51 | ] 52 | }, 53 | "properties": { 54 | "class": "light", 55 | "group": "network", 56 | "name": "Powell Muni", 57 | "name_de": "Powell Muni", 58 | "name_en": "Powell Muni", 59 | "name_es": "Powell Muni", 60 | "name_fr": "Powell Muni", 61 | "network": "light" 62 | } 63 | }, 64 | { 65 | "type": "Feature", 66 | "geometry": { 67 | "type": "Point", 68 | "coordinates": [ 69 | -122.40691065788269, 70 | 37.78493143859335 71 | ] 72 | }, 73 | "properties": { 74 | "class": "light", 75 | "group": "network", 76 | "name": "Powell", 77 | "name_de": "Powell", 78 | "name_en": "Powell", 79 | "name_es": "Powell", 80 | "name_fr": "Powell", 81 | "network": "light" 82 | } 83 | } 84 | ], 85 | "name": "rail_station_label" 86 | } -------------------------------------------------------------------------------- /examples/data/14_2620_6331-tunnel.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "LineString", 8 | "coordinates": [ 9 | [ 10 | -122.41784870624542, 11 | 37.796335045920344 12 | ], 13 | [ 14 | -122.41178691387177, 15 | 37.797110766421454 16 | ], 17 | [ 18 | -122.41127192974089, 19 | 37.7971785885917 20 | ] 21 | ] 22 | }, 23 | "properties": { 24 | "class": "main", 25 | "layer": -1, 26 | "oneway": 1 27 | } 28 | }, 29 | { 30 | "type": "Feature", 31 | "geometry": { 32 | "type": "LineString", 33 | "coordinates": [ 34 | [ 35 | -122.411288022995, 36 | 37.797254888458816 37 | ], 38 | [ 39 | -122.41180300712585, 40 | 37.797187066358596 41 | ], 42 | [ 43 | -122.41785407066345, 44 | 37.79641558558629 45 | ] 46 | ] 47 | }, 48 | "properties": { 49 | "class": "main", 50 | "layer": -1, 51 | "oneway": 1 52 | } 53 | } 54 | ], 55 | "name": "tunnel" 56 | } -------------------------------------------------------------------------------- /examples/data/14_2620_6331.vector.mvt.z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/examples/data/14_2620_6331.vector.mvt.z -------------------------------------------------------------------------------- /examples/data/14_8716_8015.vector.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/examples/data/14_8716_8015.vector.mvt -------------------------------------------------------------------------------- /gyp/common.gypi: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | ["OS=='win'", { 4 | "target_defaults": { 5 | "default_configuration": "Release_x64", 6 | "msbuild_toolset":"CTP_Nov2013", 7 | "msvs_settings": { 8 | "VCCLCompilerTool": { 9 | "ExceptionHandling": 1, # /EHsc 10 | "RuntimeTypeInfo": "true" # /GR 11 | } 12 | }, 13 | "configurations": { 14 | "Debug_Win32": { 15 | "msvs_configuration_platform": "Win32", 16 | "defines": [ "DEBUG","_DEBUG"], 17 | "msvs_settings": { 18 | "VCCLCompilerTool": { 19 | "RuntimeLibrary": "1", # static debug /MTd 20 | "Optimization": 0, # /Od, no optimization 21 | "MinimalRebuild": "false", 22 | "OmitFramePointers": "false", 23 | "BasicRuntimeChecks": 3 # /RTC1 24 | } 25 | } 26 | }, 27 | "Debug_x64": { 28 | "msvs_configuration_platform": "x64", 29 | "defines": [ "DEBUG","_DEBUG"], 30 | "msvs_settings": { 31 | "VCCLCompilerTool": { 32 | "RuntimeLibrary": "1", # static debug /MTd 33 | "Optimization": 0, # /Od, no optimization 34 | "MinimalRebuild": "false", 35 | "OmitFramePointers": "false", 36 | "BasicRuntimeChecks": 3 # /RTC1 37 | } 38 | } 39 | }, 40 | "Release_Win32": { 41 | "msvs_configuration_platform": "Win32", 42 | "defines": [ "NDEBUG"], 43 | "msvs_settings": { 44 | "VCCLCompilerTool": { 45 | "RuntimeLibrary": 0, # static release 46 | "Optimization": 3, # /Ox, full optimization 47 | "FavorSizeOrSpeed": 1, # /Ot, favour speed over size 48 | "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible 49 | "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG 50 | "OmitFramePointers": "true", 51 | "EnableFunctionLevelLinking": "true", 52 | "EnableIntrinsicFunctions": "true", 53 | "AdditionalOptions": [ 54 | "/MP", # compile across multiple CPUs 55 | ], 56 | "DebugInformationFormat": "0" 57 | }, 58 | "VCLibrarianTool": { 59 | "AdditionalOptions": [ 60 | "/LTCG" # link time code generation 61 | ], 62 | }, 63 | "VCLinkerTool": { 64 | "LinkTimeCodeGeneration": 1, # link-time code generation 65 | "OptimizeReferences": 2, # /OPT:REF 66 | "EnableCOMDATFolding": 2, # /OPT:ICF 67 | "LinkIncremental": 1, # disable incremental linking 68 | "GenerateDebugInformation": "false" 69 | } 70 | } 71 | }, 72 | "Release_x64": { 73 | "msvs_configuration_platform": "x64", 74 | "defines": [ "NDEBUG"], 75 | "msvs_settings": { 76 | "VCCLCompilerTool": { 77 | "RuntimeLibrary": 0, # static release 78 | "Optimization": 3, # /Ox, full optimization 79 | "FavorSizeOrSpeed": 1, # /Ot, favour speed over size 80 | "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible 81 | "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG 82 | "OmitFramePointers": "true", 83 | "EnableFunctionLevelLinking": "true", 84 | "EnableIntrinsicFunctions": "true", 85 | "AdditionalOptions": [ 86 | "/MP", # compile across multiple CPUs 87 | ], 88 | "DebugInformationFormat": "0" 89 | }, 90 | "VCLibrarianTool": { 91 | "AdditionalOptions": [ 92 | "/LTCG" # link time code generation 93 | ], 94 | }, 95 | "VCLinkerTool": { 96 | "LinkTimeCodeGeneration": 1, # link-time code generation 97 | "OptimizeReferences": 2, # /OPT:REF 98 | "EnableCOMDATFolding": 2, # /OPT:ICF 99 | "LinkIncremental": 1, # disable incremental linking 100 | "GenerateDebugInformation": "false" 101 | } 102 | } 103 | } 104 | } 105 | } 106 | }, { 107 | "target_defaults": { 108 | "default_configuration": "Release", 109 | "xcode_settings": { 110 | "CLANG_CXX_LIBRARY": "libc++", 111 | "CLANG_CXX_LANGUAGE_STANDARD":"c++11", 112 | "GCC_VERSION": "com.apple.compilers.llvm.clang.1_0", 113 | }, 114 | "cflags_cc": ["-std=c++11"], 115 | "configurations": { 116 | "Debug": { 117 | "defines": [ 118 | "DEBUG" 119 | ], 120 | 'defines!': [ 121 | 'NDEBUG' 122 | ], 123 | 'cflags_cc!': [ 124 | '-O3', 125 | '-O2', 126 | '-O1', 127 | '-Os', 128 | '-DNDEBUG' 129 | ], 130 | "xcode_settings": { 131 | 'OTHER_CPLUSPLUSFLAGS!': [ 132 | '-O3', 133 | '-O2', 134 | '-O1', 135 | '-Os', 136 | '-DNDEBUG' 137 | ], 138 | "GCC_OPTIMIZATION_LEVEL": "0", 139 | "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES", 140 | "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ] 141 | } 142 | }, 143 | "Release": { 144 | "defines": [ 145 | "NDEBUG" 146 | ], 147 | "xcode_settings": { 148 | "GCC_OPTIMIZATION_LEVEL": "3", 149 | "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO", 150 | "DEAD_CODE_STRIPPING": "YES", 151 | "GCC_INLINES_ARE_PRIVATE_EXTERN": "YES", 152 | "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wno-unknown-pragmas", "-O3" ] 153 | } 154 | } 155 | } 156 | } 157 | }] 158 | ] 159 | } 160 | 161 | -------------------------------------------------------------------------------- /include_dirs.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | console.log(path.join(path.relative('.', __dirname),'src')); 3 | -------------------------------------------------------------------------------- /install_mason.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | function install() { 7 | ./mason/mason install $1 $2 8 | ./mason/mason link $1 $2 9 | } 10 | 11 | ICU_VERSION="58.1" 12 | MASON_VERSION="f359edb1" 13 | 14 | if [ ! -f ./mason/mason.sh ]; then 15 | mkdir -p ./mason 16 | curl -sSfL https://github.com/mapbox/mason/archive/${MASON_VERSION}.tar.gz | tar --gunzip --extract --strip-components=1 --exclude="*md" --exclude="test*" --directory=./mason 17 | fi 18 | 19 | # core deps 20 | install protozero 1.6.4 21 | install geometry 1.0.0 22 | install wagyu 0.4.3 23 | install protobuf 3.5.1 24 | 25 | # mapnik 26 | if [[ ${SKIP_MAPNIK_INSTALL:-} != 'YES' ]] && [[ ! -f ./mason_packages/.link/bin/mapnik-config ]]; then 27 | 28 | # mapnik deps 29 | install jpeg_turbo 1.5.2 30 | install libpng 1.6.32 31 | install libtiff 4.0.8 32 | install icu ${ICU_VERSION}-brkitr 33 | install proj 7.2.1 libproj 34 | install pixman 0.34.0 35 | install cairo 1.14.8 36 | install webp 0.6.0 37 | install libgdal 2.2.3 38 | install boost 1.75.0 39 | install boost_libsystem 1.75.0 40 | install boost_libfilesystem 1.75.0 41 | install boost_libregex_icu58 1.75.0 42 | install freetype 2.7.1 43 | install harfbuzz 1.4.4-ft 44 | 45 | # mapnik 46 | install mapnik e553f55dc 47 | 48 | fi 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mapnik-vector-tile", 3 | "version": "3.0.1", 4 | "description": "Mapnik Vector Tile API", 5 | "main": "include_dirs.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/mapbox/mapnik-vector-tile.git" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /proto/vector_tile.proto: -------------------------------------------------------------------------------- 1 | // Protocol Version 1 2 | 3 | syntax = "proto2"; 4 | 5 | package vector_tile; 6 | 7 | option optimize_for = LITE_RUNTIME; 8 | 9 | message Tile { 10 | enum GeomType { 11 | UNKNOWN = 0; 12 | POINT = 1; 13 | LINESTRING = 2; 14 | POLYGON = 3; 15 | } 16 | 17 | // Variant type encoding 18 | message Value { 19 | // Exactly one of these values may be present in a valid message 20 | optional string string_value = 1; 21 | optional float float_value = 2; 22 | optional double double_value = 3; 23 | optional int64 int_value = 4; 24 | optional uint64 uint_value = 5; 25 | optional sint64 sint_value = 6; 26 | optional bool bool_value = 7; 27 | 28 | extensions 8 to max; 29 | } 30 | 31 | message Feature { 32 | optional uint64 id = 1 [ default = 0 ]; 33 | 34 | // Tags of this feature are encoded as repeated pairs of 35 | // integers. Even indexed values (n, beginning with 0) are 36 | // themselves indexes into the layer's keys list. Odd indexed 37 | // values (n+1) are indexes into the layer's values list. 38 | // The first (n=0) tag of a feature, therefore, has a key of 39 | // layer.keys[feature.tags[0]] and a value of 40 | // layer.values[feature.tags[1]]. 41 | repeated uint32 tags = 2 [ packed = true ]; 42 | 43 | // The type of geometry stored in this feature. 44 | optional GeomType type = 3 [ default = UNKNOWN ]; 45 | 46 | // Contains a stream of commands and parameters (vertices). The 47 | // repeat count is shifted to the left by 3 bits. This means 48 | // that the command has 3 bits (0-7). The repeat count 49 | // indicates how often this command is to be repeated. Defined 50 | // commands are: 51 | // - MoveTo: 1 (2 parameters follow) 52 | // - LineTo: 2 (2 parameters follow) 53 | // - ClosePath: 7 (no parameters follow) 54 | // 55 | // Commands are encoded as uint32 varints. Vertex parameters 56 | // are encoded as deltas to the previous position and, as they 57 | // may be negative, are further "zigzag" encoded as unsigned 58 | // 32-bit ints: 59 | // 60 | // n = (n << 1) ^ (n >> 31) 61 | // 62 | // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath 63 | // Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 64 | // | | `> [00001 111] command type 7 (ClosePath), length 1 65 | // | | ===== relative LineTo(+12, +22) == LineTo(20, 34) 66 | // | | ===== relative LineTo(+5, +6) == LineTo(8, 12) 67 | // | `> [00010 010] = command type 2 (LineTo), length 2 68 | // | ==== relative MoveTo(+3, +6) 69 | // `> [00001 001] = command type 1 (MoveTo), length 1 70 | // 71 | // The original position is (0,0). 72 | repeated uint32 geometry = 4 [ packed = true ]; 73 | 74 | optional bytes raster = 5; 75 | } 76 | 77 | message Layer { 78 | // Any compliant implementation must first read the version 79 | // number encoded in this message and choose the correct 80 | // implementation for this version number before proceeding to 81 | // decode other parts of this message. 82 | required uint32 version = 15 [ default = 1 ]; 83 | 84 | required string name = 1; 85 | 86 | // The actual features in this tile. 87 | repeated Feature features = 2; 88 | 89 | // Dictionary encoding for keys 90 | repeated string keys = 3; 91 | 92 | // Dictionary encoding for values 93 | repeated Value values = 4; 94 | 95 | // The bounding box in this tile spans from 0..4095 units 96 | optional uint32 extent = 5 [ default = 4096 ]; 97 | 98 | extensions 16 to max; 99 | } 100 | 101 | repeated Layer layers = 3; 102 | 103 | extensions 16 to 8191; 104 | } 105 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | set -e -u 2 | set -o pipefail 3 | 4 | if [[ ${COVERAGE:-false} == true ]]; then 5 | # test only debug version 6 | export LDFLAGS="--coverage" 7 | export CXXFLAGS="--coverage" 8 | make debug -j${JOBS:-1} V=1 9 | make test-debug 10 | else 11 | # test both release and debug 12 | make release -j${JOBS:-1} V=1 13 | make test 14 | make debug -j${JOBS:-1} V=1 15 | make test-debug 16 | fi 17 | 18 | set +e +u 19 | -------------------------------------------------------------------------------- /scripts/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e -u 4 | set -o pipefail 5 | 6 | if [[ ${COVERAGE:-false} != false ]]; then 7 | curl -S -f https://codecov.io/bash -o codecov 8 | chmod +x codecov 9 | ./codecov -x "llvm-cov gcov" -Z 10 | fi -------------------------------------------------------------------------------- /src/vector_tile_composite.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // mapnik-vector-tile 4 | #include "vector_tile_merc_tile.hpp" 5 | #include "vector_tile_datasource_pbf.hpp" 6 | #include "vector_tile_processor.hpp" 7 | #include "vector_tile_config.hpp" 8 | 9 | // mapnik 10 | #include 11 | #include 12 | 13 | //protozero 14 | #include 15 | 16 | namespace mapnik 17 | { 18 | 19 | namespace vector_tile_impl 20 | { 21 | 22 | inline void composite(merc_tile & target_vt, 23 | std::vector const& vtiles, 24 | mapnik::Map & map, 25 | processor & ren, // processor should be on map object provided 26 | double scale_denominator = 0.0, 27 | unsigned offset_x = 0, 28 | unsigned offset_y = 0, 29 | bool reencode = false) 30 | { 31 | if (target_vt.tile_size() <= 0) 32 | { 33 | throw std::runtime_error("Vector tile size must be great than zero"); 34 | } 35 | 36 | for (auto const& vt : vtiles) 37 | { 38 | if (vt->tile_size() <= 0) 39 | { 40 | throw std::runtime_error("Vector tile size must be great than zero"); 41 | } 42 | 43 | if (vt->is_empty()) 44 | { 45 | continue; 46 | } 47 | 48 | bool reencode_tile = reencode; 49 | if (!reencode_tile && !target_vt.same_extent(*vt)) 50 | { 51 | reencode_tile = true; 52 | } 53 | 54 | protozero::pbf_reader tile_message(vt->get_reader()); 55 | // loop through the layers of the tile! 56 | while (tile_message.next(Tile_Encoding::LAYERS)) 57 | { 58 | bool reencode_layer = reencode_tile; 59 | const auto data_view = tile_message.get_view(); 60 | protozero::pbf_reader layer_message(data_view); 61 | if (!layer_message.next(Layer_Encoding::NAME)) 62 | { 63 | continue; 64 | } 65 | 66 | std::string layer_name = layer_message.get_string(); 67 | 68 | if (!reencode_layer) 69 | { 70 | target_vt.append_layer_buffer(data_view.data(), data_view.size(), layer_name); 71 | } 72 | 73 | if (target_vt.has_layer(layer_name)) 74 | { 75 | continue; 76 | } 77 | 78 | protozero::pbf_reader layer_pbf(data_view); 79 | auto ds = std::make_shared( 80 | layer_pbf, 81 | vt->x(), 82 | vt->y(), 83 | vt->z(), 84 | true); 85 | mapnik::layer lyr(layer_name,"epsg:3857"); 86 | ds->set_envelope(vt->get_buffered_extent()); 87 | lyr.set_datasource(ds); 88 | map.add_layer(lyr); 89 | } 90 | } 91 | if (!map.layers().empty()) 92 | { 93 | ren.update_tile(target_vt, 94 | scale_denominator, 95 | offset_x, 96 | offset_y); 97 | } 98 | } 99 | 100 | } // end ns vector_tile_impl 101 | 102 | } // end ns mapnik 103 | -------------------------------------------------------------------------------- /src/vector_tile_compression.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_compression.hpp" 2 | #include "vector_tile_compression.ipp" -------------------------------------------------------------------------------- /src/vector_tile_compression.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // mapnik-vector-tile 4 | #include "vector_tile_config.hpp" 5 | 6 | // zlib 7 | #include 8 | 9 | // std 10 | #include 11 | 12 | namespace mapnik 13 | { 14 | 15 | namespace vector_tile_impl 16 | { 17 | 18 | inline bool is_zlib_compressed(const char * data, std::size_t size) 19 | { 20 | return size > 2 && 21 | static_cast(data[0]) == 0x78 && 22 | ( 23 | static_cast(data[1]) == 0x9C || 24 | static_cast(data[1]) == 0x01 || 25 | static_cast(data[1]) == 0xDA || 26 | static_cast(data[1]) == 0x5E 27 | ); 28 | } 29 | 30 | inline bool is_zlib_compressed(std::string const& data) 31 | { 32 | return data.size() > 2 && 33 | static_cast(data[0]) == 0x78 && 34 | ( 35 | static_cast(data[1]) == 0x9C || 36 | static_cast(data[1]) == 0x01 || 37 | static_cast(data[1]) == 0xDA || 38 | static_cast(data[1]) == 0x5E 39 | ); 40 | } 41 | 42 | inline bool is_gzip_compressed(const char * data, std::size_t size) 43 | { 44 | return size > 2 && static_cast(data[0]) == 0x1F && static_cast(data[1]) == 0x8B; 45 | } 46 | 47 | inline bool is_gzip_compressed(std::string const& data) 48 | { 49 | return data.size() > 2 && static_cast(data[0]) == 0x1F && static_cast(data[1]) == 0x8B; 50 | } 51 | 52 | // decodes both zlib and gzip 53 | // http://stackoverflow.com/a/1838702/2333354 54 | MAPNIK_VECTOR_INLINE void zlib_decompress(std::string const& input, 55 | std::string & output); 56 | 57 | MAPNIK_VECTOR_INLINE void zlib_compress(std::string const& input, 58 | std::string & output, 59 | bool gzip=true, 60 | int level=Z_DEFAULT_COMPRESSION, 61 | int strategy=Z_DEFAULT_STRATEGY); 62 | 63 | MAPNIK_VECTOR_INLINE void zlib_decompress(const char * data, 64 | std::size_t size, 65 | std::string & output); 66 | 67 | MAPNIK_VECTOR_INLINE void zlib_compress(const char * data, 68 | std::size_t size, 69 | std::string & output, 70 | bool gzip=true, 71 | int level=Z_DEFAULT_COMPRESSION, 72 | int strategy=Z_DEFAULT_STRATEGY); 73 | 74 | } // end ns vector_tile_impl 75 | 76 | } // end ns mapnik 77 | 78 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 79 | #include "vector_tile_compression.ipp" 80 | #endif 81 | -------------------------------------------------------------------------------- /src/vector_tile_compression.ipp: -------------------------------------------------------------------------------- 1 | // zlib 2 | #include 3 | 4 | // std 5 | #include 6 | 7 | namespace mapnik 8 | { 9 | 10 | namespace vector_tile_impl 11 | { 12 | 13 | // decodes both zlib and gzip 14 | // http://stackoverflow.com/a/1838702/2333354 15 | void zlib_decompress(const char * data, std::size_t size, std::string & output) 16 | { 17 | z_stream inflate_s; 18 | inflate_s.zalloc = Z_NULL; 19 | inflate_s.zfree = Z_NULL; 20 | inflate_s.opaque = Z_NULL; 21 | inflate_s.avail_in = 0; 22 | inflate_s.next_in = Z_NULL; 23 | inflateInit2(&inflate_s, 32 + 15); 24 | inflate_s.next_in = (Bytef *)data; 25 | inflate_s.avail_in = size; 26 | size_t length = 0; 27 | do { 28 | output.resize(length + 2 * size); 29 | inflate_s.avail_out = 2 * size; 30 | inflate_s.next_out = (Bytef *)(output.data() + length); 31 | int ret = inflate(&inflate_s, Z_FINISH); 32 | if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) 33 | { 34 | std::string error_msg = inflate_s.msg; 35 | inflateEnd(&inflate_s); 36 | throw std::runtime_error(error_msg); 37 | } 38 | 39 | length += (2 * size - inflate_s.avail_out); 40 | } while (inflate_s.avail_out == 0); 41 | inflateEnd(&inflate_s); 42 | output.resize(length); 43 | } 44 | 45 | void zlib_decompress(std::string const& input, std::string & output) 46 | { 47 | zlib_decompress(input.data(),input.size(),output); 48 | } 49 | 50 | void zlib_compress(const char * data, std::size_t size, std::string & output, bool gzip, int level, int strategy) 51 | { 52 | z_stream deflate_s; 53 | deflate_s.zalloc = Z_NULL; 54 | deflate_s.zfree = Z_NULL; 55 | deflate_s.opaque = Z_NULL; 56 | deflate_s.avail_in = 0; 57 | deflate_s.next_in = Z_NULL; 58 | int windowsBits = 15; 59 | if (gzip) 60 | { 61 | windowsBits = windowsBits | 16; 62 | } 63 | if (deflateInit2(&deflate_s, level, Z_DEFLATED, windowsBits, 8, strategy) != Z_OK) 64 | { 65 | throw std::runtime_error("deflate init failed"); 66 | } 67 | deflate_s.next_in = (Bytef *)data; 68 | deflate_s.avail_in = size; 69 | size_t length = 0; 70 | do { 71 | size_t increase = size / 2 + 1024; 72 | output.resize(length + increase); 73 | deflate_s.avail_out = increase; 74 | deflate_s.next_out = (Bytef *)(output.data() + length); 75 | // From http://www.zlib.net/zlib_how.html 76 | // "deflate() has a return value that can indicate errors, yet we do not check it here. 77 | // Why not? Well, it turns out that deflate() can do no wrong here." 78 | // Basically only possible error is from deflateInit not working properly 79 | deflate(&deflate_s, Z_FINISH); 80 | length += (increase - deflate_s.avail_out); 81 | } while (deflate_s.avail_out == 0); 82 | deflateEnd(&deflate_s); 83 | output.resize(length); 84 | } 85 | 86 | void zlib_compress(std::string const& input, std::string & output, bool gzip, int level, int strategy) 87 | { 88 | zlib_compress(input.data(),input.size(),output,gzip,level,strategy); 89 | } 90 | 91 | } // end ns vector_tile_impl 92 | 93 | } // end ns mapnik 94 | -------------------------------------------------------------------------------- /src/vector_tile_config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 4 | #define MAPNIK_VECTOR_INLINE inline 5 | #else 6 | #define MAPNIK_VECTOR_INLINE 7 | #endif 8 | 9 | #include 10 | 11 | #define VT_LEGACY_IMAGE_SIZE 256.0 12 | 13 | namespace mapnik 14 | { 15 | 16 | namespace vector_tile_impl 17 | { 18 | 19 | enum Tile_Encoding : protozero::pbf_tag_type 20 | { 21 | LAYERS = 3 22 | }; 23 | 24 | enum Layer_Encoding : protozero::pbf_tag_type 25 | { 26 | VERSION = 15, 27 | NAME = 1, 28 | FEATURES = 2, 29 | KEYS = 3, 30 | VALUES = 4, 31 | EXTENT = 5 32 | }; 33 | 34 | enum Feature_Encoding : protozero::pbf_tag_type 35 | { 36 | ID = 1, 37 | TAGS = 2, 38 | TYPE = 3, 39 | GEOMETRY = 4, 40 | RASTER = 5 41 | }; 42 | 43 | enum Value_Encoding : protozero::pbf_tag_type 44 | { 45 | STRING = 1, 46 | FLOAT = 2, 47 | DOUBLE = 3, 48 | INT = 4, 49 | UINT = 5, 50 | SINT = 6, 51 | BOOL = 7 52 | }; 53 | 54 | enum Geometry_Type : std::uint8_t 55 | { 56 | UNKNOWN = 0, 57 | POINT = 1, 58 | LINESTRING = 2, 59 | POLYGON = 3 60 | }; 61 | 62 | enum polygon_fill_type : std::uint8_t { 63 | even_odd_fill = 0, 64 | non_zero_fill, 65 | positive_fill, 66 | negative_fill, 67 | polygon_fill_type_max 68 | }; 69 | 70 | } // end ns vector_tile_impl 71 | 72 | } // end ns mapnik 73 | -------------------------------------------------------------------------------- /src/vector_tile_datasource_pbf.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_datasource_pbf.hpp" 2 | #include "vector_tile_datasource_pbf.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_datasource_pbf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // mapnik 4 | //#include 5 | #include 6 | #include 7 | 8 | // protozero 9 | #include 10 | 11 | namespace mapnik 12 | { 13 | 14 | namespace vector_tile_impl 15 | { 16 | 17 | // TODO: consider using mapnik::value here instead 18 | using pbf_attr_value_type = mapnik::util::variant; 19 | using layer_pbf_attr_type = std::vector; 20 | 21 | class tile_datasource_pbf : public datasource 22 | { 23 | public: 24 | tile_datasource_pbf(protozero::pbf_reader const& layer, 25 | std::uint64_t x, 26 | std::uint64_t y, 27 | std::uint64_t z, 28 | bool use_tile_extent = false); 29 | virtual ~tile_datasource_pbf(); 30 | datasource::datasource_t type() const; 31 | featureset_ptr features(query const& q) const; 32 | featureset_ptr features_at_point(coord2d const& pt, double tol = 0) const; 33 | void set_envelope(box2d const& bbox); 34 | box2d get_tile_extent() const; 35 | box2d envelope() const; 36 | boost::optional get_geometry_type() const; 37 | layer_descriptor get_descriptor() const; 38 | std::string const& get_name() { return name_; } 39 | std::uint32_t get_layer_extent() { return tile_size_; } 40 | private: 41 | mutable mapnik::layer_descriptor desc_; 42 | mutable bool attributes_added_; 43 | mutable bool valid_layer_; 44 | protozero::pbf_reader layer_; 45 | std::uint64_t x_; 46 | std::uint64_t y_; 47 | std::uint64_t z_; 48 | std::uint32_t tile_size_; 49 | mutable bool extent_initialized_; 50 | mutable mapnik::box2d extent_; 51 | double tile_x_; 52 | double tile_y_; 53 | double scale_; 54 | uint32_t version_; 55 | datasource::datasource_t type_; 56 | 57 | std::string name_; 58 | std::vector features_; 59 | std::vector layer_keys_; 60 | layer_pbf_attr_type layer_values_; 61 | }; 62 | 63 | } // end ns vector_tile_impl 64 | 65 | } // end ns mapnik 66 | 67 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 68 | #include "vector_tile_datasource_pbf.ipp" 69 | #endif 70 | -------------------------------------------------------------------------------- /src/vector_tile_featureset_pbf.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_featureset_pbf.hpp" 2 | #include "vector_tile_featureset_pbf.ipp" 3 | #include 4 | 5 | template class mapnik::vector_tile_impl::tile_featureset_pbf; 6 | template class mapnik::vector_tile_impl::tile_featureset_pbf; 7 | -------------------------------------------------------------------------------- /src/vector_tile_featureset_pbf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // protozero 4 | #include 5 | 6 | // mapnik 7 | //#include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // std 15 | #include 16 | 17 | namespace mapnik 18 | { 19 | 20 | namespace vector_tile_impl 21 | { 22 | 23 | using pbf_attr_value_type = mapnik::util::variant; 24 | using layer_pbf_attr_type = std::vector; 25 | 26 | template 27 | class tile_featureset_pbf : public Featureset 28 | { 29 | public: 30 | tile_featureset_pbf(Filter const& filter, 31 | mapnik::box2d const& tile_extent, 32 | mapnik::box2d const& unbuffered_query, 33 | std::set const& attribute_names, 34 | std::vector const& features, 35 | double tile_x, 36 | double tile_y, 37 | double scale, 38 | std::vector const& layer_keys, 39 | layer_pbf_attr_type const& layer_values, 40 | unsigned version); 41 | 42 | virtual ~tile_featureset_pbf() {} 43 | 44 | feature_ptr next(); 45 | 46 | private: 47 | Filter filter_; 48 | mapnik::box2d tile_extent_; 49 | mapnik::box2d unbuffered_query_; 50 | std::vector const& features_; 51 | std::vector const& layer_keys_; 52 | layer_pbf_attr_type const& layer_values_; 53 | std::size_t num_keys_; 54 | std::size_t num_values_; 55 | double tile_x_; 56 | double tile_y_; 57 | double scale_; 58 | unsigned itr_; 59 | unsigned version_; 60 | mapnik::transcoder tr_; 61 | mapnik::context_ptr ctx_; 62 | }; 63 | 64 | } // end ns vector_tile_impl 65 | 66 | } // end ns mapnik 67 | 68 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 69 | #include "vector_tile_featureset_pbf.ipp" 70 | #endif 71 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_decoder.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_geometry_decoder.hpp" 2 | #include "vector_tile_geometry_decoder.ipp" 3 | 4 | namespace mapnik 5 | { 6 | 7 | namespace vector_tile_impl 8 | { 9 | 10 | // decode geometry 11 | template mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 12 | int32_t geom_type, 13 | unsigned version, 14 | double tile_x, 15 | double tile_y, 16 | double scale_x, 17 | double scale_y); 18 | template mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 19 | int32_t geom_type, 20 | unsigned version, 21 | std::int64_t tile_x, 22 | std::int64_t tile_y, 23 | double scale_x, 24 | double scale_y); 25 | template mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 26 | int32_t geom_type, 27 | unsigned version, 28 | double tile_x, 29 | double tile_y, 30 | double scale_x, 31 | double scale_y, 32 | mapnik::box2d const& bbox); 33 | template mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 34 | int32_t geom_type, 35 | unsigned version, 36 | std::int64_t tile_x, 37 | std::int64_t tile_y, 38 | double scale_x, 39 | double scale_y, 40 | mapnik::box2d const& bbox); 41 | 42 | } // end ns vector_tile_impl 43 | 44 | } // end ns mapnik 45 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_decoder.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // mapnik-vector-tile 4 | #include "vector_tile_config.hpp" 5 | 6 | //protozero 7 | #include 8 | 9 | //mapnik 10 | #include 11 | #include 12 | #if defined(DEBUG) 13 | #include 14 | #endif 15 | 16 | //std 17 | #include 18 | #include 19 | #include 20 | 21 | namespace mapnik 22 | { 23 | 24 | namespace vector_tile_impl 25 | { 26 | 27 | // NOTE: this object is for one-time use. Once you've progressed to the end 28 | // by calling next(), to re-iterate, you must construct a new object 29 | class GeometryPBF 30 | { 31 | public: 32 | using value_type = std::int64_t; 33 | using iterator_type = protozero::pbf_reader::const_uint32_iterator; 34 | using pbf_itr = protozero::iterator_range; 35 | 36 | explicit GeometryPBF(pbf_itr const& geo_iterator); 37 | 38 | enum command : uint8_t 39 | { 40 | end = 0, 41 | move_to = 1, 42 | line_to = 2, 43 | close = 7 44 | }; 45 | 46 | uint32_t get_length() const 47 | { 48 | return length; 49 | } 50 | 51 | command point_next(value_type & rx, value_type & ry); 52 | command line_next(value_type & rx, value_type & ry, bool skip_lineto_zero); 53 | command ring_next(value_type & rx, value_type & ry, bool skip_lineto_zero); 54 | 55 | private: 56 | iterator_type geo_itr_; 57 | iterator_type geo_end_itr_; 58 | value_type x, y; 59 | value_type ox, oy; 60 | uint32_t length; 61 | uint8_t cmd; 62 | #if defined(DEBUG) 63 | public: 64 | bool already_had_error; 65 | #endif 66 | }; 67 | 68 | template 69 | MAPNIK_VECTOR_INLINE mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 70 | std::int32_t geom_type, 71 | unsigned version, 72 | value_type tile_x, 73 | value_type tile_y, 74 | double scale_x, 75 | double scale_y, 76 | mapnik::box2d const& bbox); 77 | 78 | template 79 | MAPNIK_VECTOR_INLINE mapnik::geometry::geometry decode_geometry(GeometryPBF & paths, 80 | std::int32_t geom_type, 81 | unsigned version, 82 | value_type tile_x, 83 | value_type tile_y, 84 | double scale_x, 85 | double scale_y); 86 | 87 | } // end ns vector_tile_impl 88 | 89 | } // end ns mapnik 90 | 91 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 92 | #include "vector_tile_geometry_decoder.ipp" 93 | #endif 94 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_encoder_pbf.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_geometry_encoder_pbf.hpp" 2 | #include "vector_tile_geometry_encoder_pbf.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_encoder_pbf.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_GEOMETRY_ENCODER_PBF_H__ 2 | #define __MAPNIK_VECTOR_TILE_GEOMETRY_ENCODER_PBF_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | 7 | // mapbox 8 | #include 9 | 10 | // protozero 11 | #include 12 | #include 13 | 14 | // std 15 | #include 16 | #include 17 | 18 | namespace mapnik 19 | { 20 | 21 | namespace vector_tile_impl 22 | { 23 | 24 | template 25 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(T const& pt, 26 | protozero::pbf_writer & current_feature, 27 | int32_t & start_x, 28 | int32_t & start_y); 29 | template <> 30 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::point const& pt, 31 | protozero::pbf_writer & current_feature, 32 | int32_t & start_x, 33 | int32_t & start_y); 34 | 35 | template <> 36 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::multi_point const& geom, 37 | protozero::pbf_writer & current_feature, 38 | int32_t & start_x, 39 | int32_t & start_y); 40 | 41 | template <> 42 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::line_string const& line, 43 | protozero::pbf_writer & current_feature, 44 | int32_t & start_x, 45 | int32_t & start_y); 46 | template <> 47 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::multi_line_string const& geom, 48 | protozero::pbf_writer & current_feature, 49 | int32_t & start_x, 50 | int32_t & start_y); 51 | 52 | template <> 53 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::polygon const& poly, 54 | protozero::pbf_writer & current_feature, 55 | int32_t & start_x, 56 | int32_t & start_y); 57 | template <> 58 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::multi_polygon const& poly, 59 | protozero::pbf_writer & current_feature, 60 | int32_t & start_x, 61 | int32_t & start_y); 62 | template <> 63 | MAPNIK_VECTOR_INLINE bool encode_geometry_pbf(mapbox::geometry::geometry const& geom, 64 | protozero::pbf_writer & current_feature, 65 | int32_t & start_x, 66 | int32_t & start_y); 67 | 68 | } // end ns vector_tile_impl 69 | 70 | } // end ns mapnik 71 | 72 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 73 | #include "vector_tile_geometry_encoder_pbf.ipp" 74 | #endif 75 | 76 | #endif // __MAPNIK_VECTOR_TILE_GEOMETRY_ENCODER_PBF_H__ 77 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_feature.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_GEOMETRY_FEATURE_H__ 2 | #define __MAPNIK_VECTOR_TILE_GEOMETRY_FEATURE_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | #include "vector_tile_layer.hpp" 7 | #include "vector_tile_geometry_encoder_pbf.hpp" 8 | 9 | // mapnik 10 | #include 11 | #include 12 | 13 | // Mapbox 14 | #include 15 | 16 | 17 | namespace mapnik 18 | { 19 | 20 | namespace vector_tile_impl 21 | { 22 | 23 | inline void raster_to_feature(std::string const& buffer, 24 | mapnik::feature_impl const& mapnik_feature, 25 | layer_builder_pbf & builder) 26 | { 27 | std::vector feature_tags; 28 | protozero::pbf_writer layer_writer = builder.add_feature(mapnik_feature, feature_tags); 29 | protozero::pbf_writer feature_writer(layer_writer, Layer_Encoding::FEATURES); 30 | feature_writer.add_uint64(Feature_Encoding::ID, static_cast(mapnik_feature.id())); 31 | feature_writer.add_string(Feature_Encoding::RASTER, buffer); 32 | feature_writer.add_packed_uint32(Feature_Encoding::TAGS, feature_tags.begin(), feature_tags.end()); 33 | builder.make_not_empty(); 34 | } 35 | 36 | struct geometry_to_feature_pbf_visitor 37 | { 38 | mapnik::feature_impl const& mapnik_feature_; 39 | layer_builder_pbf & builder_; 40 | 41 | geometry_to_feature_pbf_visitor(mapnik::feature_impl const& mapnik_feature, 42 | layer_builder_pbf & builder) 43 | : mapnik_feature_(mapnik_feature), 44 | builder_(builder) {} 45 | 46 | template 47 | void operator() (T const& geom) 48 | { 49 | std::int32_t x = 0; 50 | std::int32_t y = 0; 51 | bool success = false; 52 | std::vector feature_tags; 53 | protozero::pbf_writer layer_writer = builder_.add_feature(mapnik_feature_, feature_tags); 54 | { 55 | protozero::pbf_writer feature_writer(layer_writer, Layer_Encoding::FEATURES); 56 | success = encode_geometry_pbf(geom, feature_writer, x, y); 57 | if (success) 58 | { 59 | feature_writer.add_uint64(Feature_Encoding::ID, static_cast(mapnik_feature_.id())); 60 | feature_writer.add_packed_uint32(Feature_Encoding::TAGS, feature_tags.begin(), feature_tags.end()); 61 | builder_.make_not_empty(); 62 | } 63 | else 64 | { 65 | feature_writer.rollback(); 66 | } 67 | } 68 | } 69 | 70 | void operator() (mapbox::geometry::geometry_collection const& collection) 71 | { 72 | for (auto & g : collection) 73 | { 74 | mapbox::util::apply_visitor((*this), g); 75 | } 76 | } 77 | }; 78 | 79 | } // end ns vector_tile_impl 80 | 81 | } // end ns mapnik 82 | 83 | #endif // __MAPNIK_VECTOR_GEOMETRY_FEATURE_H__ 84 | -------------------------------------------------------------------------------- /src/vector_tile_geometry_simplifier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_GEOMETRY_SIMPLIFIER_H__ 2 | #define __MAPNIK_VECTOR_TILE_GEOMETRY_SIMPLIFIER_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | #include "vector_tile_douglas_peucker.hpp" 7 | 8 | // mapbox 9 | #include 10 | 11 | namespace mapnik 12 | { 13 | 14 | namespace vector_tile_impl 15 | { 16 | 17 | template 18 | struct geometry_simplifier 19 | { 20 | geometry_simplifier(unsigned simplify_distance, 21 | NextProcessor & next) 22 | : next_(next), 23 | simplify_distance_(simplify_distance) {} 24 | 25 | void operator() (mapbox::geometry::point & geom) 26 | { 27 | next_(geom); 28 | } 29 | 30 | void operator() (mapbox::geometry::multi_point & geom) 31 | { 32 | next_(geom); 33 | } 34 | 35 | void operator() (mapbox::geometry::line_string & geom) 36 | { 37 | if (geom.size() <= 2) 38 | { 39 | next_(geom); 40 | } 41 | else 42 | { 43 | mapbox::geometry::line_string simplified; 44 | douglas_peucker(geom, std::back_inserter(simplified), simplify_distance_); 45 | next_(simplified); 46 | } 47 | } 48 | 49 | void operator() (mapbox::geometry::multi_line_string & geom) 50 | { 51 | mapbox::geometry::multi_line_string simplified; 52 | for (auto const & g : geom) 53 | { 54 | if (g.size() <= 2) 55 | { 56 | simplified.push_back(g); 57 | } 58 | else 59 | { 60 | mapbox::geometry::line_string simplified_line; 61 | douglas_peucker(g, std::back_inserter(simplified_line), simplify_distance_); 62 | simplified.push_back(simplified_line); 63 | } 64 | } 65 | next_(simplified); 66 | } 67 | 68 | void operator() (mapbox::geometry::polygon & geom) 69 | { 70 | mapbox::geometry::polygon simplified; 71 | for (auto const & g : geom) 72 | { 73 | if (g.size() <= 4) 74 | { 75 | simplified.push_back(g); 76 | } 77 | else 78 | { 79 | mapbox::geometry::linear_ring simplified_ring; 80 | douglas_peucker(g, std::back_inserter(simplified_ring), simplify_distance_); 81 | simplified.push_back(simplified_ring); 82 | } 83 | } 84 | next_(simplified); 85 | } 86 | 87 | void operator() (mapbox::geometry::multi_polygon & multi_geom) 88 | { 89 | mapbox::geometry::multi_polygon simplified_multi; 90 | for (auto const & geom : multi_geom) 91 | { 92 | mapbox::geometry::polygon simplified; 93 | for (auto const & g : geom) 94 | { 95 | if (g.size() <= 4) 96 | { 97 | simplified.push_back(g); 98 | } 99 | else 100 | { 101 | mapbox::geometry::linear_ring simplified_ring; 102 | douglas_peucker(g, std::back_inserter(simplified_ring), simplify_distance_); 103 | simplified.push_back(simplified_ring); 104 | } 105 | } 106 | simplified_multi.push_back(simplified); 107 | } 108 | next_(simplified_multi); 109 | } 110 | 111 | void operator() (mapbox::geometry::geometry_collection & geom) 112 | { 113 | for (auto & g : geom) 114 | { 115 | mapnik::util::apply_visitor((*this), g); 116 | } 117 | } 118 | 119 | NextProcessor & next_; 120 | double simplify_distance_; 121 | }; 122 | 123 | } // end ns vector_tile_impl 124 | 125 | } // end ns mapnik 126 | 127 | #endif // __MAPNIK_VECTOR_GEOMETRY_SIMPLIFIER_H__ 128 | -------------------------------------------------------------------------------- /src/vector_tile_layer.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_layer.hpp" 2 | #include "vector_tile_layer.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_layer.ipp: -------------------------------------------------------------------------------- 1 | // mapnik 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // protozero 8 | #include 9 | 10 | // std 11 | #include 12 | #include 13 | 14 | namespace mapnik 15 | { 16 | 17 | namespace vector_tile_impl 18 | { 19 | 20 | namespace detail 21 | { 22 | 23 | struct to_tile_value_pbf 24 | { 25 | public: 26 | to_tile_value_pbf(protozero::pbf_writer & value): 27 | value_(value) {} 28 | 29 | void operator () ( value_integer val ) const 30 | { 31 | value_.add_int64(Value_Encoding::INT,val); 32 | } 33 | 34 | void operator () ( mapnik::value_bool val ) const 35 | { 36 | value_.add_bool(Value_Encoding::BOOL,val); 37 | } 38 | 39 | void operator () ( mapnik::value_double val ) const 40 | { 41 | float fval = static_cast(val); 42 | if (val == static_cast(fval)) 43 | { 44 | value_.add_float(Value_Encoding::FLOAT, fval); 45 | } 46 | else 47 | { 48 | value_.add_double(Value_Encoding::DOUBLE, val); 49 | } 50 | } 51 | 52 | void operator () ( mapnik::value_unicode_string const& val ) const 53 | { 54 | std::string str; 55 | to_utf8(val, str); 56 | value_.add_string(Value_Encoding::STRING, str); 57 | } 58 | 59 | void operator () ( mapnik::value_null const& /*val*/ ) const 60 | { 61 | // do nothing 62 | } 63 | private: 64 | protozero::pbf_writer & value_; 65 | }; 66 | 67 | } // end ns detail 68 | 69 | MAPNIK_VECTOR_INLINE protozero::pbf_writer layer_builder_pbf::add_feature(mapnik::feature_impl const& mapnik_feature, 70 | std::vector & feature_tags) 71 | 72 | { 73 | protozero::pbf_writer layer_writer(layer_buffer); 74 | // Feature id should be unique from mapnik so we should comply with 75 | // the following wording of the specification: 76 | // "the value of the (feature) id SHOULD be unique among the features of the parent layer." 77 | 78 | // note that feature.id is signed int64_t so we are casting. 79 | 80 | // Mapnik features can not have more then one value for 81 | // a single key. Therefore, we do not have to check if 82 | // key already exists in the feature as we insert each 83 | // key value pair into the feature. 84 | feature_kv_iterator itr = mapnik_feature.begin(); 85 | feature_kv_iterator end = mapnik_feature.end(); 86 | for (; itr!=end; ++itr) 87 | { 88 | std::string const& name = std::get<0>(*itr); 89 | mapnik::value const& val = std::get<1>(*itr); 90 | if (!val.is_null()) 91 | { 92 | // Insert the key index 93 | keys_container::const_iterator key_itr = keys.find(name); 94 | if (key_itr == keys.end()) 95 | { 96 | // The key doesn't exist yet in the dictionary. 97 | layer_writer.add_string(Layer_Encoding::KEYS, name); 98 | size_t index = keys.size(); 99 | keys.emplace(name, index); 100 | feature_tags.push_back(index); 101 | } 102 | else 103 | { 104 | feature_tags.push_back(key_itr->second); 105 | } 106 | 107 | // Insert the value index 108 | values_container::const_iterator val_itr = values.find(val); 109 | if (val_itr == values.end()) 110 | { 111 | // The value doesn't exist yet in the dictionary. 112 | { 113 | protozero::pbf_writer value_writer(layer_writer, Layer_Encoding::VALUES); 114 | detail::to_tile_value_pbf visitor(value_writer); 115 | mapnik::util::apply_visitor(visitor, val); 116 | } 117 | size_t index = values.size(); 118 | values.emplace(val, index); 119 | feature_tags.push_back(index); 120 | } 121 | else 122 | { 123 | feature_tags.push_back(val_itr->second); 124 | } 125 | } 126 | } 127 | return layer_writer; 128 | } 129 | 130 | } // end ns vector_tile_impl 131 | 132 | } // end ns mapnik 133 | -------------------------------------------------------------------------------- /src/vector_tile_load_tile.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_LOAD_TILE_H__ 2 | #define __MAPNIK_VECTOR_TILE_LOAD_TILE_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | #include "vector_tile_compression.hpp" 7 | #include "vector_tile_tile.hpp" 8 | #include "vector_tile_datasource_pbf.hpp" 9 | #include "vector_tile_is_valid.hpp" 10 | #include "vector_tile_processor.hpp" 11 | 12 | // mapnik 13 | #include 14 | #include 15 | 16 | //protozero 17 | #include 18 | #include 19 | 20 | // std 21 | #include 22 | #include 23 | #include 24 | 25 | namespace mapnik 26 | { 27 | 28 | namespace vector_tile_impl 29 | { 30 | 31 | inline std::pair get_layer_name_and_version(protozero::pbf_reader & layer_msg) 32 | { 33 | std::string name; 34 | std::uint32_t version = 1; 35 | while (layer_msg.next()) 36 | { 37 | switch (layer_msg.tag()) 38 | { 39 | case Layer_Encoding::NAME: 40 | name = layer_msg.get_string(); 41 | break; 42 | case Layer_Encoding::VERSION: 43 | version = layer_msg.get_uint32();; 44 | break; 45 | default: 46 | layer_msg.skip(); 47 | break; 48 | } 49 | } 50 | return std::make_pair(name,version); 51 | } 52 | 53 | inline void merge_from_buffer(merc_tile & t, const char * data, std::size_t size, bool validate = false, bool upgrade = false) 54 | { 55 | using ds_ptr = std::shared_ptr; 56 | protozero::pbf_reader tile_msg(data, size); 57 | std::vector ds_vec; 58 | while (tile_msg.next()) 59 | { 60 | switch (tile_msg.tag()) 61 | { 62 | case Tile_Encoding::LAYERS: 63 | { 64 | const auto layer_view = tile_msg.get_view(); 65 | protozero::pbf_reader layer_props_msg(layer_view); 66 | auto layer_info = get_layer_name_and_version(layer_props_msg); 67 | std::string const& layer_name = layer_info.first; 68 | std::uint32_t version = layer_info.second; 69 | if (validate) 70 | { 71 | std::set errors; 72 | if (version < 1 || version > 2) 73 | { 74 | errors.insert(LAYER_HAS_UNSUPPORTED_VERSION); 75 | } 76 | if (t.has_layer(layer_name)) 77 | { 78 | errors.insert(TILE_REPEATED_LAYER_NAMES); 79 | } 80 | protozero::pbf_reader layer_valid_msg(layer_view); 81 | layer_is_valid(layer_valid_msg, errors); 82 | if (!errors.empty()) 83 | { 84 | std::string layer_errors; 85 | validity_error_to_string(errors, layer_errors); 86 | throw std::runtime_error(layer_errors); 87 | } 88 | } 89 | else if (layer_name.empty() || t.has_layer(layer_name)) 90 | { 91 | continue; 92 | } 93 | if (upgrade && version == 1) 94 | { 95 | // v1 tiles will be converted to v2 96 | protozero::pbf_reader layer_msg(layer_view); 97 | ds_vec.push_back(std::make_shared( 98 | layer_msg, 99 | t.x(), 100 | t.y(), 101 | t.z(), 102 | true)); 103 | } 104 | else 105 | { 106 | t.append_layer_buffer(layer_view.data(), layer_view.size(), layer_name); 107 | } 108 | } 109 | break; 110 | default: 111 | throw std::runtime_error("Vector Tile Buffer contains invalid tag"); 112 | break; 113 | } 114 | } 115 | if (ds_vec.empty()) 116 | { 117 | return; 118 | } 119 | // Convert v1 tiles to v2 120 | std::int32_t prev_buffer_size = t.buffer_size(); 121 | t.buffer_size(4096); // very large buffer so we don't miss any buffered points 122 | mapnik::Map map(t.tile_size(), t.tile_size(), "epsg:3857"); 123 | for (auto const& ds : ds_vec) 124 | { 125 | ds->set_envelope(t.get_buffered_extent()); 126 | mapnik::layer lyr(ds->get_name(), "epsg:3857"); 127 | lyr.set_datasource(ds); 128 | map.add_layer(std::move(lyr)); 129 | } 130 | mapnik::vector_tile_impl::processor ren(map); 131 | ren.set_multi_polygon_union(true); 132 | ren.set_fill_type(mapnik::vector_tile_impl::even_odd_fill); 133 | ren.set_process_all_rings(true); 134 | //ren.set_simplify_distance(4.0); 135 | ren.update_tile(t); 136 | t.buffer_size(prev_buffer_size); 137 | } 138 | 139 | inline void merge_from_compressed_buffer(merc_tile & t, const char * data, std::size_t size, bool validate = false, bool upgrade = false) 140 | { 141 | if (mapnik::vector_tile_impl::is_gzip_compressed(data,size) || 142 | mapnik::vector_tile_impl::is_zlib_compressed(data,size)) 143 | { 144 | std::string decompressed; 145 | mapnik::vector_tile_impl::zlib_decompress(data, size, decompressed); 146 | return merge_from_buffer(t, decompressed.data(), decompressed.size(), validate, upgrade); 147 | } 148 | else 149 | { 150 | return merge_from_buffer(t, data, size, validate, upgrade); 151 | } 152 | } 153 | 154 | inline void add_image_buffer_as_tile_layer(merc_tile & t, std::string const& layer_name, const char * data, std::size_t size) 155 | { 156 | std::string layer_buffer; 157 | protozero::pbf_writer layer_writer(layer_buffer); 158 | layer_writer.add_uint32(Layer_Encoding::VERSION, 2); 159 | layer_writer.add_string(Layer_Encoding::NAME, layer_name); 160 | layer_writer.add_uint32(Layer_Encoding::EXTENT, 4096); 161 | { 162 | protozero::pbf_writer feature_writer(layer_writer, Layer_Encoding::FEATURES); 163 | feature_writer.add_bytes(Feature_Encoding::RASTER, data, size); 164 | } 165 | t.append_layer_buffer(layer_buffer.data(), layer_buffer.size(), layer_name); 166 | } 167 | 168 | } // end ns vector_tile_impl 169 | 170 | } // end ns mapnik 171 | 172 | #endif // __MAPNIK_VECTOR_TILE_LOAD_TILE_H__ 173 | -------------------------------------------------------------------------------- /src/vector_tile_merc_tile.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_MERC_TILE_H__ 2 | #define __MAPNIK_VECTOR_TILE_MERC_TILE_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_tile.hpp" 6 | #include "vector_tile_projection.hpp" 7 | 8 | namespace mapnik 9 | { 10 | 11 | namespace vector_tile_impl 12 | { 13 | 14 | class merc_tile : public tile 15 | { 16 | private: 17 | std::uint64_t x_; 18 | std::uint64_t y_; 19 | std::uint64_t z_; 20 | public: 21 | merc_tile(std::uint64_t x, 22 | std::uint64_t y, 23 | std::uint64_t z, 24 | std::uint32_t tile_size = 4096, 25 | std::int32_t buffer_size = 128) 26 | : tile(tile_mercator_bbox(x, y, z), tile_size, buffer_size), 27 | x_(x), 28 | y_(y), 29 | z_(z) {} 30 | 31 | merc_tile(merc_tile && rhs) = default; 32 | 33 | bool same_extent(merc_tile const& other) 34 | { 35 | return x_ == other.x_ && 36 | y_ == other.y_ && 37 | z_ == other.z_; 38 | } 39 | 40 | std::uint64_t x() const 41 | { 42 | return x_; 43 | } 44 | 45 | void x(std::uint64_t x) 46 | { 47 | x_ = x; 48 | extent_ = tile_mercator_bbox(x_, y_, z_); 49 | } 50 | 51 | std::uint64_t y() const 52 | { 53 | return y_; 54 | } 55 | 56 | void y(std::uint64_t y) 57 | { 58 | y_ = y; 59 | extent_ = tile_mercator_bbox(x_, y_, z_); 60 | } 61 | 62 | std::uint64_t z() const 63 | { 64 | return z_; 65 | } 66 | 67 | void z(std::uint64_t z) 68 | { 69 | z_ = z; 70 | extent_ = tile_mercator_bbox(x_, y_, z_); 71 | } 72 | }; 73 | 74 | typedef std::shared_ptr merc_tile_ptr; 75 | 76 | } // end ns vector_tile_impl 77 | 78 | } // end ns mapnik 79 | 80 | #endif // __MAPNIK_VECTOR_TILE_MERC_TILE_H__ 81 | -------------------------------------------------------------------------------- /src/vector_tile_processor.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_processor.hpp" 2 | #include "vector_tile_processor.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_processor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_PROCESSOR_H__ 2 | #define __MAPNIK_VECTOR_PROCESSOR_H__ 3 | 4 | // mapnik 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // mapnik-vector-tile 14 | #include "vector_tile_config.hpp" 15 | #include "vector_tile_tile.hpp" 16 | #include "vector_tile_merc_tile.hpp" 17 | 18 | // std 19 | #include 20 | 21 | namespace mapnik 22 | { 23 | 24 | namespace vector_tile_impl 25 | { 26 | 27 | /* 28 | This processor combines concepts from mapnik's 29 | feature_style_processor and agg_renderer. It 30 | differs in that here we only process layers in 31 | isolation of their styles, and because of this we need 32 | options for clipping and simplification, for example, 33 | that would normally come from a style's symbolizers 34 | */ 35 | 36 | class processor : private mapnik::util::noncopyable 37 | { 38 | private: 39 | mapnik::Map const& m_; 40 | std::string image_format_; 41 | double scale_factor_; 42 | double area_threshold_; 43 | double simplify_distance_; 44 | polygon_fill_type fill_type_; 45 | scaling_method_e scaling_method_; 46 | bool strictly_simple_; 47 | bool multi_polygon_union_; 48 | bool process_all_rings_; 49 | std::launch threading_mode_; 50 | mapnik::attributes vars_; 51 | 52 | public: 53 | processor(mapnik::Map const& map, mapnik::attributes const& vars = mapnik::attributes()) 54 | : m_(map), 55 | image_format_("webp"), 56 | scale_factor_(1.0), 57 | area_threshold_(0.1), 58 | simplify_distance_(0.0), 59 | fill_type_(positive_fill), 60 | scaling_method_(SCALING_BILINEAR), 61 | strictly_simple_(true), 62 | multi_polygon_union_(false), 63 | process_all_rings_(false), 64 | threading_mode_(std::launch::deferred), 65 | vars_(vars) {} 66 | 67 | MAPNIK_VECTOR_INLINE void update_tile(tile & t, 68 | double scale_denom = 0.0, 69 | int offset_x = 0, 70 | int offset_y = 0); 71 | 72 | merc_tile create_tile(std::uint64_t x, 73 | std::uint64_t y, 74 | std::uint64_t z, 75 | std::uint32_t tile_size = 4096, 76 | std::int32_t buffer_size = 0, 77 | double scale_denom = 0.0, 78 | int offset_x = 0, 79 | int offset_y = 0) 80 | { 81 | merc_tile t(x, y, z, tile_size, buffer_size); 82 | update_tile(t, scale_denom, offset_x, offset_y); 83 | return t; 84 | } 85 | 86 | tile create_tile(mapnik::box2d const & extent, 87 | std::uint32_t tile_size = 4096, 88 | std::int32_t buffer_size = 0, 89 | double scale_denom = 0.0, 90 | int offset_x = 0, 91 | int offset_y = 0) 92 | { 93 | tile t(extent, tile_size, buffer_size); 94 | update_tile(t, scale_denom, offset_x, offset_y); 95 | return t; 96 | } 97 | 98 | void set_simplify_distance(double dist) 99 | { 100 | simplify_distance_ = dist; 101 | } 102 | 103 | double get_simplify_distance() const 104 | { 105 | return simplify_distance_; 106 | } 107 | 108 | void set_area_threshold(double value) 109 | { 110 | area_threshold_ = value; 111 | } 112 | 113 | double get_area_threshold() const 114 | { 115 | return area_threshold_; 116 | } 117 | 118 | void set_scale_factor(double value) 119 | { 120 | scale_factor_ = value; 121 | } 122 | 123 | double get_scale_factor() const 124 | { 125 | return scale_factor_; 126 | } 127 | 128 | void set_process_all_rings(bool value) 129 | { 130 | process_all_rings_ = value; 131 | } 132 | 133 | bool get_process_all_rings() const 134 | { 135 | return process_all_rings_; 136 | } 137 | 138 | void set_multi_polygon_union(bool value) 139 | { 140 | multi_polygon_union_ = value; 141 | } 142 | 143 | bool get_multi_polygon_union() const 144 | { 145 | return multi_polygon_union_; 146 | } 147 | 148 | void set_strictly_simple(bool value) 149 | { 150 | strictly_simple_ = value; 151 | } 152 | 153 | bool get_multipolygon_union() const 154 | { 155 | return strictly_simple_; 156 | } 157 | 158 | void set_fill_type(polygon_fill_type type) 159 | { 160 | fill_type_ = type; 161 | } 162 | 163 | polygon_fill_type set_fill_type() const 164 | { 165 | return fill_type_; 166 | } 167 | 168 | void set_scaling_method(scaling_method_e type) 169 | { 170 | scaling_method_ = type; 171 | } 172 | 173 | scaling_method_e set_scaling_method() const 174 | { 175 | return scaling_method_; 176 | } 177 | 178 | void set_image_format(std::string const& value) 179 | { 180 | image_format_ = value; 181 | } 182 | 183 | std::string const& get_image_format() const 184 | { 185 | return image_format_; 186 | } 187 | 188 | mapnik::attributes const& get_variables() const 189 | { 190 | return vars_; 191 | } 192 | 193 | void set_threading_mode(std::launch mode) 194 | { 195 | threading_mode_ = mode; 196 | } 197 | 198 | std::launch set_threading_mode() const 199 | { 200 | return threading_mode_; 201 | } 202 | 203 | }; 204 | 205 | } // end ns vector_tile_impl 206 | 207 | } // end ns mapnik 208 | 209 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 210 | #include "vector_tile_processor.ipp" 211 | #endif 212 | 213 | #endif // __MAPNIK_VECTOR_TILE_PROCESSOR_H__ 214 | -------------------------------------------------------------------------------- /src/vector_tile_projection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_PROJECTION_H__ 2 | #define __MAPNIK_VECTOR_TILE_PROJECTION_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | 7 | // mapnik 8 | #include 9 | #include 10 | 11 | namespace mapnik 12 | { 13 | 14 | namespace vector_tile_impl 15 | { 16 | 17 | inline mapnik::box2d tile_mercator_bbox(std::uint64_t x, 18 | std::uint64_t y, 19 | std::uint64_t z) 20 | { 21 | const double half_of_equator = M_PI * EARTH_RADIUS; 22 | const double tile_size = 2.0 * half_of_equator / (1ull << z); 23 | double minx = -half_of_equator + x * tile_size; 24 | double miny = half_of_equator - (y + 1.0) * tile_size; 25 | double maxx = -half_of_equator + (x + 1.0) * tile_size; 26 | double maxy = half_of_equator - y * tile_size; 27 | return mapnik::box2d(minx,miny,maxx,maxy); 28 | } 29 | 30 | } // end vector_tile_impl ns 31 | 32 | } // end mapnik ns 33 | 34 | #endif // __MAPNIK_VECTOR_TILE_PROJECTION_H__ 35 | -------------------------------------------------------------------------------- /src/vector_tile_raster_clipper.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_raster_clipper.hpp" 2 | #include "vector_tile_raster_clipper.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_raster_clipper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_RASTER_CLIPPER_H__ 2 | #define __MAPNIK_VECTOR_TILE_RASTER_CLIPPER_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | 7 | // mapnik 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // std 14 | #include 15 | 16 | namespace mapnik 17 | { 18 | 19 | namespace vector_tile_impl 20 | { 21 | 22 | struct raster_clipper 23 | { 24 | private: 25 | mapnik::raster const& source_; 26 | box2d const& target_ext_; 27 | box2d const& ext_; 28 | mapnik::proj_transform const& prj_trans_; 29 | std::string const& image_format_; 30 | scaling_method_e scaling_method_; 31 | unsigned width_; 32 | unsigned height_; 33 | unsigned raster_width_; 34 | unsigned raster_height_; 35 | int start_x_; 36 | int start_y_; 37 | public: 38 | raster_clipper(mapnik::raster const& source, 39 | box2d const& target_ext, 40 | box2d const& ext, 41 | mapnik::proj_transform const& prj_trans, 42 | std::string const& image_format, 43 | scaling_method_e scaling_method, 44 | unsigned width, 45 | unsigned height, 46 | unsigned raster_width, 47 | unsigned raster_height, 48 | int start_x, 49 | int start_y) 50 | : source_(source), 51 | target_ext_(target_ext), 52 | ext_(ext), 53 | prj_trans_(prj_trans), 54 | image_format_(image_format), 55 | scaling_method_(scaling_method), 56 | width_(width), 57 | height_(height), 58 | raster_width_(raster_width), 59 | raster_height_(raster_height), 60 | start_x_(start_x), 61 | start_y_(start_y) 62 | { 63 | } 64 | 65 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_rgba8 & source_data); 66 | 67 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray8 & source_data); 68 | 69 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray8s & source_data); 70 | 71 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray16 & source_data); 72 | 73 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray16s & source_data); 74 | 75 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray32 & source_data); 76 | 77 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray32s & source_data); 78 | 79 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray32f & source_data); 80 | 81 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray64 & source_data); 82 | 83 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray64s & source_data); 84 | 85 | MAPNIK_VECTOR_INLINE std::string operator() (mapnik::image_gray64f & source_data); 86 | 87 | std::string operator() (image_null &) const 88 | { 89 | throw std::runtime_error("Null data passed to visitor"); 90 | } 91 | 92 | }; 93 | 94 | } // end ns vector_tile_impl 95 | 96 | } // end ns mapnik 97 | 98 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 99 | #include "vector_tile_raster_clipper.ipp" 100 | #endif 101 | 102 | #endif // __MAPNIK_VECTOR_TILE_RASTER_CLIPPER_H__ 103 | -------------------------------------------------------------------------------- /src/vector_tile_tile.cpp: -------------------------------------------------------------------------------- 1 | #include "vector_tile_tile.hpp" 2 | #include "vector_tile_tile.ipp" 3 | -------------------------------------------------------------------------------- /src/vector_tile_tile.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_TILE_H__ 2 | #define __MAPNIK_VECTOR_TILE_TILE_H__ 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_config.hpp" 6 | 7 | //protozero 8 | #include 9 | 10 | // mapnik 11 | #include 12 | 13 | // std 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace mapnik 20 | { 21 | 22 | namespace vector_tile_impl 23 | { 24 | 25 | // fwd declare 26 | class tile_layer; 27 | 28 | class tile 29 | { 30 | protected: 31 | std::unique_ptr buffer_; 32 | std::set painted_layers_; 33 | std::set empty_layers_; 34 | std::set layers_set_; 35 | std::vector layers_; 36 | mapnik::box2d extent_; 37 | std::uint32_t tile_size_; 38 | std::int32_t buffer_size_; 39 | 40 | public: 41 | tile(mapnik::box2d const& extent, 42 | std::uint32_t tile_size = 4096, 43 | std::int32_t buffer_size = 128) 44 | : buffer_(std::make_unique()), 45 | painted_layers_(), 46 | empty_layers_(), 47 | layers_set_(), 48 | layers_(), 49 | extent_(extent), 50 | tile_size_(tile_size), 51 | buffer_size_(buffer_size) {} 52 | 53 | tile(tile && rhs) = default; 54 | 55 | MAPNIK_VECTOR_INLINE bool add_layer(tile_layer const& layer); 56 | 57 | void add_empty_layer(std::string const& name) 58 | { 59 | empty_layers_.insert(name); 60 | } 61 | 62 | const char * data() const 63 | { 64 | return buffer_->data(); 65 | } 66 | 67 | std::size_t size() const 68 | { 69 | return buffer_->size(); 70 | } 71 | 72 | std::string const& get_buffer() const 73 | { 74 | return *buffer_; 75 | } 76 | 77 | double scale() const 78 | { 79 | if (tile_size_ > 0) 80 | { 81 | return extent_.width()/tile_size_; 82 | } 83 | return extent_.width(); 84 | } 85 | 86 | box2d get_buffered_extent() const 87 | { 88 | double extra = 2.0 * scale() * buffer_size_; 89 | box2d ext(extent_); 90 | double extra_width = extent_.width() + extra; 91 | double extra_height = extent_.height() + extra; 92 | if (extra_width < 0.0) 93 | { 94 | extra_width = 0.0; 95 | } 96 | if (extra_height < 0.0) 97 | { 98 | extra_height = 0.0; 99 | } 100 | ext.width(extra_width); 101 | ext.height(extra_height); 102 | return ext; 103 | } 104 | 105 | void append_to_string(std::string & str) const 106 | { 107 | str.append(*buffer_); 108 | } 109 | 110 | void serialize_to_string(std::string & str) const 111 | { 112 | str = *buffer_; 113 | } 114 | 115 | bool is_painted() const 116 | { 117 | return !painted_layers_.empty(); 118 | } 119 | 120 | bool is_empty() const 121 | { 122 | return layers_.empty(); 123 | } 124 | 125 | box2d const& extent() const 126 | { 127 | return extent_; 128 | } 129 | 130 | std::uint32_t tile_size() const 131 | { 132 | return tile_size_; 133 | } 134 | 135 | void tile_size(std::uint32_t val) 136 | { 137 | tile_size_ = val; 138 | } 139 | 140 | std::int32_t buffer_size() const 141 | { 142 | return buffer_size_; 143 | } 144 | 145 | void buffer_size(std::int32_t val) 146 | { 147 | buffer_size_ = val; 148 | } 149 | 150 | MAPNIK_VECTOR_INLINE bool append_layer_buffer(const char * data, std::size_t size, std::string const& name); 151 | 152 | std::set const& get_painted_layers() const 153 | { 154 | return painted_layers_; 155 | } 156 | 157 | std::set const& get_empty_layers() const 158 | { 159 | return empty_layers_; 160 | } 161 | 162 | std::vector const& get_layers() const 163 | { 164 | return layers_; 165 | } 166 | 167 | std::set const& get_layers_set() const 168 | { 169 | return layers_set_; 170 | } 171 | 172 | bool same_extent(tile const& other) const 173 | { 174 | return extent_ == other.extent_; 175 | } 176 | 177 | void clear() 178 | { 179 | buffer_->clear(); 180 | empty_layers_.clear(); 181 | layers_.clear(); 182 | layers_set_.clear(); 183 | painted_layers_.clear(); 184 | } 185 | 186 | bool has_layer(std::string const& name) 187 | { 188 | auto itr = layers_set_.find(name); 189 | return itr != layers_set_.end(); 190 | } 191 | 192 | protozero::pbf_reader get_reader() const 193 | { 194 | return protozero::pbf_reader(buffer_->data(), buffer_->size()); 195 | } 196 | 197 | std::unique_ptr release_buffer() 198 | { 199 | std::unique_ptr out = std::move(buffer_); 200 | buffer_ = std::make_unique(); 201 | clear(); 202 | return out; 203 | } 204 | 205 | MAPNIK_VECTOR_INLINE bool layer_reader(std::string const& name, protozero::pbf_reader & layer_msg) const; 206 | 207 | MAPNIK_VECTOR_INLINE bool layer_reader(std::size_t index, protozero::pbf_reader & layer_msg) const; 208 | }; 209 | 210 | } // end ns vector_tile_impl 211 | 212 | } // end ns mapnik 213 | 214 | #if !defined(MAPNIK_VECTOR_TILE_LIBRARY) 215 | #include "vector_tile_tile.ipp" 216 | #endif 217 | 218 | #endif // __MAPNIK_VECTOR_TILE_TILE_H__ 219 | -------------------------------------------------------------------------------- /src/vector_tile_tile.ipp: -------------------------------------------------------------------------------- 1 | // mapnik-vector-tile 2 | #include "vector_tile_config.hpp" 3 | #include "vector_tile_layer.hpp" 4 | 5 | //protozero 6 | #include 7 | #include 8 | 9 | // std 10 | #include 11 | #include 12 | 13 | namespace mapnik 14 | { 15 | 16 | namespace vector_tile_impl 17 | { 18 | 19 | MAPNIK_VECTOR_INLINE bool tile::add_layer(tile_layer const& layer) 20 | { 21 | std::string const& new_name = layer.name(); 22 | if (layer.is_empty()) 23 | { 24 | empty_layers_.insert(new_name); 25 | if (layer.is_painted()) 26 | { 27 | painted_layers_.insert(new_name); 28 | } 29 | } 30 | else 31 | { 32 | painted_layers_.insert(new_name); 33 | auto p = layers_set_.insert(new_name); 34 | if (!p.second) 35 | { 36 | // Layer already in tile 37 | return false; 38 | } 39 | layers_.push_back(new_name); 40 | protozero::pbf_writer tile_writer(*buffer_); 41 | tile_writer.add_message(Tile_Encoding::LAYERS, layer.get_data()); 42 | auto itr = empty_layers_.find(new_name); 43 | if (itr != empty_layers_.end()) 44 | { 45 | empty_layers_.erase(itr); 46 | } 47 | } 48 | return true; 49 | } 50 | 51 | MAPNIK_VECTOR_INLINE bool tile::append_layer_buffer(const char * data, std::size_t size, std::string const& name) 52 | { 53 | painted_layers_.insert(name); 54 | auto p = layers_set_.insert(name); 55 | if (!p.second) 56 | { 57 | // Layer already in tile 58 | return false; 59 | } 60 | layers_.push_back(name); 61 | protozero::pbf_writer writer(*buffer_); 62 | writer.add_message(3, data, size); 63 | auto itr = empty_layers_.find(name); 64 | if (itr != empty_layers_.end()) 65 | { 66 | empty_layers_.erase(itr); 67 | } 68 | return true; 69 | } 70 | 71 | MAPNIK_VECTOR_INLINE bool tile::layer_reader(std::string const& name, protozero::pbf_reader & layer_msg) const 72 | { 73 | protozero::pbf_reader item(buffer_->data(), buffer_->size()); 74 | while (item.next(Tile_Encoding::LAYERS)) 75 | { 76 | layer_msg = item.get_message(); 77 | protozero::pbf_reader lay(layer_msg); 78 | while (lay.next(Layer_Encoding::NAME)) 79 | { 80 | if (lay.get_string() == name) 81 | { 82 | return true; 83 | } 84 | } 85 | } 86 | return false; 87 | } 88 | 89 | MAPNIK_VECTOR_INLINE bool tile::layer_reader(std::size_t index, protozero::pbf_reader & layer_msg) const 90 | { 91 | protozero::pbf_reader item(buffer_->data(), buffer_->size()); 92 | std::size_t idx = 0; 93 | while (item.next(Tile_Encoding::LAYERS)) 94 | { 95 | if (idx == index) 96 | { 97 | layer_msg = item.get_message(); 98 | return true; 99 | } 100 | ++idx; 101 | item.skip(); 102 | } 103 | return false; 104 | } 105 | 106 | } // end ns vector_tile_impl 107 | 108 | } // end ns mapnik 109 | -------------------------------------------------------------------------------- /test/data/0.0.0.vector-b.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/0.0.0.vector-b.mvt -------------------------------------------------------------------------------- /test/data/0.0.0.vector.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/0.0.0.vector.mvt -------------------------------------------------------------------------------- /test/data/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/256x256.png -------------------------------------------------------------------------------- /test/data/NZ_Coastline_NZMG.dbf: -------------------------------------------------------------------------------- 1 | _ascalerankN 2 | featureclaC 0Coastline 0Coastline -------------------------------------------------------------------------------- /test/data/NZ_Coastline_NZMG.prj: -------------------------------------------------------------------------------- 1 | PROJCS["NZGD49_New_Zealand_Map_Grid",GEOGCS["GCS_New_Zealand_1949",DATUM["D_New_Zealand_1949",SPHEROID["International_1924",6378388,297]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["New_Zealand_Map_Grid"],PARAMETER["latitude_of_origin",-41],PARAMETER["Longitude_Of_Origin",173],PARAMETER["false_easting",2510000],PARAMETER["false_northing",6023150],UNIT["Meter",1]] -------------------------------------------------------------------------------- /test/data/NZ_Coastline_NZMG.qpj: -------------------------------------------------------------------------------- 1 | PROJCS["NZGD49 / New Zealand Map Grid",GEOGCS["NZGD49",DATUM["New_Zealand_Geodetic_Datum_1949",SPHEROID["International 1924",6378388,297,AUTHORITY["EPSG","7022"]],TOWGS84[59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993],AUTHORITY["EPSG","6272"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4272"]],PROJECTION["New_Zealand_Map_Grid"],PARAMETER["latitude_of_origin",-41],PARAMETER["central_meridian",173],PARAMETER["false_easting",2510000],PARAMETER["false_northing",6023150],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","27200"]] 2 | -------------------------------------------------------------------------------- /test/data/NZ_Coastline_NZMG.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/NZ_Coastline_NZMG.shp -------------------------------------------------------------------------------- /test/data/NZ_Coastline_NZMG.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/NZ_Coastline_NZMG.shx -------------------------------------------------------------------------------- /test/data/image.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/image.mvt -------------------------------------------------------------------------------- /test/data/invalid-interior-ring.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Polygon", 3 | "coordinates": [ 4 | [ 5 | [ 6 | -17.2265625, 7 | 63.074865690586634 8 | ], 9 | [ 10 | -40.78125, 11 | 45.583289756006316 12 | ], 13 | [ 14 | -47.109375, 15 | 20.3034175184893 16 | ], 17 | [ 18 | -42.5390625, 19 | 2.811371193331128 20 | ], 21 | [ 22 | -15.468749999999998, 23 | 2.811371193331128 24 | ], 25 | [ 26 | 10.8984375, 27 | 16.29905101458183 28 | ], 29 | [ 30 | 17.578125, 31 | 38.272688535980976 32 | ], 33 | [ 34 | 16.5234375, 35 | 56.36525013685606 36 | ], 37 | [ 38 | 1.0546875, 39 | 65.5129625532949 40 | ], 41 | [ 42 | -17.2265625, 43 | 63.074865690586634 44 | ] 45 | ], 46 | [ 47 | [ 48 | -10.8984375, 49 | 54.77534585936447 50 | ], 51 | [ 52 | -23.5546875, 53 | 32.24997445586331 54 | ], 55 | [ 56 | -10.8984375, 57 | 18.646245142670608 58 | ], 59 | [ 60 | 4.21875, 61 | 35.17380831799959 62 | ], 63 | [ 64 | 4.21875, 65 | 46.800059446787316 66 | ], 67 | [ 68 | -10.8984375, 69 | 54.77534585936447 70 | ] 71 | ], 72 | [ 73 | [ 74 | -10.1953125, 75 | 44.33956524809713 76 | ], 77 | [ 78 | -12.65625, 79 | 0.0 80 | ], 81 | [ 82 | 18446744073709551615, 83 | 32.84267363195431 84 | ], 85 | [ 86 | -3.515625, 87 | 42.032974332441405 88 | ], 89 | [ 90 | -10.1953125, 91 | 44.33956524809713 92 | ] 93 | ] 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /test/data/layer_scale_denom_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | csv 5 | 6 | x, y 7 | 1, 2 8 | 9 | 10 | 11 | 12 | 13 | csv 14 | 15 | x, y 16 | 3, 4 17 | 1, 4 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/data/linestrings_and_point.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "id": 1, 7 | "geometry": { 8 | "type": "LineString", 9 | "coordinates": [ 10 | [ 11 | -180, 12 | 60.020952153748 13 | ], 14 | [ 15 | 180, 16 | -60.020952153748 17 | ] 18 | ] 19 | }, 20 | "properties": {} 21 | }, 22 | { 23 | "type": "Feature", 24 | "id": 2, 25 | "geometry": { 26 | "type": "LineString", 27 | "coordinates": [ 28 | [ 29 | -180, 30 | -60.020952153748 31 | ], 32 | [ 33 | 180, 34 | 60.020952153748 35 | ] 36 | ] 37 | }, 38 | "properties": {} 39 | }, 40 | { 41 | "type": "Feature", 42 | "id": 1, 43 | "geometry": { 44 | "type": "Point", 45 | "coordinates": [ 46 | 0, 47 | 0 48 | ] 49 | }, 50 | "properties": { 51 | "x": 0, 52 | "y": 10, 53 | "pbool": false 54 | } 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /test/data/natural_earth.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/natural_earth.tif -------------------------------------------------------------------------------- /test/data/poly-lat-invalid-4269.dbf: -------------------------------------------------------------------------------- 1 | _A WFIDN 0 -------------------------------------------------------------------------------- /test/data/poly-lat-invalid-4269.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /test/data/poly-lat-invalid-4269.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/poly-lat-invalid-4269.shp -------------------------------------------------------------------------------- /test/data/poly-lat-invalid-4269.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/poly-lat-invalid-4269.shx -------------------------------------------------------------------------------- /test/data/polygon-style.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /test/data/raster_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /test/data/simplified_geometry.geojson: -------------------------------------------------------------------------------- 1 | {"type":"MultiPolygon","coordinates":[[[[160.5234375,11.2197860479317],[160.5234375,11.2335794562443],[160.509375,11.2335794562443],[160.509375,11.2197860479317],[160.5234375,11.2197860479317]]],[[[160.2140625,11.0542139873837],[160.228125,11.0542139873837],[160.2703125,11.0542139873837],[160.2703125,11.068015249669],[160.2421875,11.068015249669],[160.2421875,11.0818158616881],[160.2,11.0818158616881],[160.2,11.068015249669],[160.1859375,11.068015249669],[160.171875,11.0542139873837],[160.2140625,11.0542139873837]]],[[[160.2984375,11.0818158616881],[160.284375,11.0818158616881],[160.284375,11.068015249669],[160.2984375,11.068015249669],[160.2984375,11.0818158616881]]],[[[160.621875,11.123213788449],[160.6078125,11.123213788449],[160.6078125,11.1094151318478],[160.65,11.1094151318478],[160.65,11.123213788449],[160.6359375,11.123213788449],[160.621875,11.123213788449]]],[[[160.340625,11.1094151318478],[160.3265625,11.095615822671],[160.340625,11.095615822671],[160.340625,11.1094151318478]]],[[[160.5796875,11.150809140847],[160.5796875,11.1370117917051],[160.59375,11.1370117917051],[160.59375,11.123213788449],[160.6078125,11.123213788449],[160.6078125,11.150809140847],[160.5796875,11.150809140847]]],[[[160.4109375,11.3163260298893],[160.396875,11.3163260298893],[160.396875,11.3025365900508],[160.425,11.3025365900508],[160.425,11.3163260298893],[160.4109375,11.3163260298893]]],[[[160.565625,11.123213788449],[160.5515625,11.123213788449],[160.5515625,11.1094151318478],[160.565625,11.1094151318478],[160.565625,11.123213788449]]],[[[160.5234375,11.2473722050633],[160.5234375,11.2611642936208],[160.509375,11.2611642936208],[160.509375,11.2473722050633],[160.5234375,11.2473722050633]]],[[[160.340625,11.3576903617558],[160.340625,11.3714771406069],[160.3265625,11.3714771406069],[160.3265625,11.3576903617558],[160.340625,11.3576903617558]]],[[[160.396875,11.3852632522956],[160.4109375,11.3852632522956],[160.4109375,11.3990486960562],[160.396875,11.3990486960562],[160.396875,11.3852632522956]]],[[[160.565625,11.1370117917051],[160.565625,11.123213788449],[160.5796875,11.123213788449],[160.5796875,11.1370117917051],[160.565625,11.1370117917051]]],[[[160.565625,11.150809140847],[160.5515625,11.150809140847],[160.5515625,11.1370117917051],[160.565625,11.1370117917051],[160.565625,11.150809140847]]],[[[160.4109375,11.3301148056307],[160.396875,11.3301148056307],[160.4109375,11.3163260298893],[160.4109375,11.3301148056307]]],[[[160.3828125,11.1784018737118],[160.36875,11.1646058351055],[160.3828125,11.1646058351055],[160.3828125,11.1784018737118]]],[[[160.5234375,11.2197860479317],[160.5234375,11.2059919808932],[160.509375,11.2059919808932],[160.509375,11.2197860479317],[160.4953125,11.2197860479317],[160.4953125,11.2059919808932],[160.4109375,11.2059919808932],[160.4109375,11.2197860479317],[160.3546875,11.2197860479317],[160.3546875,11.2335794562443],[160.36875,11.2335794562443],[160.36875,11.2611642936208],[160.3546875,11.2611642936208],[160.3546875,11.2887464868818],[160.340625,11.2887464868818],[160.340625,11.3025365900508],[160.36875,11.3025365900508],[160.36875,11.2887464868818],[160.396875,11.2887464868818],[160.396875,11.3025365900508],[160.3828125,11.3025365900508],[160.3828125,11.3163260298893],[160.36875,11.3163260298893],[160.36875,11.3301148056307],[160.3828125,11.3301148056307],[160.3828125,11.3439029165083],[160.396875,11.3439029165083],[160.4109375,11.3439029165083],[160.4109375,11.3714771406069],[160.396875,11.3714771406069],[160.396875,11.3576903617558],[160.36875,11.3576903617558],[160.36875,11.3439029165083],[160.3265625,11.3439029165083],[160.3265625,11.3576903617558],[160.2984375,11.3576903617558],[160.2984375,11.3301148056307],[160.284375,11.3163260298893],[160.2703125,11.3163260298893],[160.2703125,11.3025365900508],[160.284375,11.3025365900508],[160.284375,11.2749557211495],[160.284375,11.2611642936208],[160.2984375,11.2611642936208],[160.2984375,11.2473722050633],[160.284375,11.2473722050633],[160.284375,11.1921972558972],[160.3125,11.1921972558972],[160.3125,11.1646058351055],[160.3265625,11.1646058351055],[160.3265625,11.150809140847],[160.3125,11.150809140847],[160.3125,11.1370117917051],[160.2984375,11.1370117917051],[160.2984375,11.123213788449],[160.284375,11.123213788449],[160.284375,11.1094151318478],[160.2421875,11.1094151318478],[160.228125,11.1094151318478],[160.2140625,11.1094151318478],[160.2140625,11.095615822671],[160.2421875,11.095615822671],[160.2421875,11.0818158616881],[160.25625,11.0818158616881],[160.25625,11.095615822671],[160.2703125,11.095615822671],[160.2984375,11.095615822671],[160.2984375,11.0818158616881],[160.3125,11.0818158616881],[160.3125,11.095615822671],[160.3265625,11.095615822671],[160.3265625,11.1094151318478],[160.3265625,11.123213788449],[160.340625,11.123213788449],[160.340625,11.1094151318478],[160.3546875,11.1094151318478],[160.3546875,11.095615822671],[160.36875,11.095615822671],[160.36875,11.1094151318478],[160.396875,11.1094151318478],[160.396875,11.123213788449],[160.4109375,11.123213788449],[160.4109375,11.1370117917051],[160.3828125,11.1370117917051],[160.3828125,11.150809140847],[160.36875,11.150809140847],[160.36875,11.1646058351055],[160.36875,11.1784018737118],[160.3828125,11.1784018737118],[160.453125,11.1784018737118],[160.453125,11.1921972558972],[160.48125,11.1921972558972],[160.48125,11.1784018737118],[160.4953125,11.1784018737118],[160.509375,11.1784018737118],[160.5234375,11.1784018737118],[160.5234375,11.1646058351055],[160.5375,11.1646058351055],[160.5375,11.150809140847],[160.5515625,11.150809140847],[160.5515625,11.1646058351055],[160.565625,11.1646058351055],[160.565625,11.1784018737118],[160.5515625,11.1784018737118],[160.5515625,11.1921972558972],[160.565625,11.1921972558972],[160.565625,11.2059919808932],[160.5375,11.2059919808932],[160.5375,11.2197860479317],[160.5234375,11.2197860479317]],[[160.340625,11.2887464868818],[160.340625,11.2749557211495],[160.340625,11.2611642936208],[160.3265625,11.2611642936208],[160.3265625,11.2749557211495],[160.3125,11.2749557211495],[160.3125,11.2887464868818],[160.340625,11.2887464868818]],[[160.340625,11.1370117917051],[160.340625,11.150809140847],[160.3546875,11.150809140847],[160.3546875,11.1370117917051],[160.340625,11.1370117917051]]]]} -------------------------------------------------------------------------------- /test/data/simplified_geometry_pbf.geojson: -------------------------------------------------------------------------------- 1 | {"type":"MultiPolygon","coordinates":[[[[160.5234375,11.2197860479317],[160.5234375,11.2335794562443],[160.509375,11.2335794562443],[160.509375,11.2197860479317],[160.5234375,11.2197860479317]]],[[[160.2140625,11.0542139873837],[160.228125,11.0542139873837],[160.2703125,11.0542139873837],[160.2703125,11.068015249669],[160.2421875,11.068015249669],[160.2421875,11.0818158616881],[160.2,11.0818158616881],[160.2,11.068015249669],[160.1859375,11.068015249669],[160.171875,11.0542139873837],[160.2140625,11.0542139873837]]],[[[160.2984375,11.0818158616881],[160.284375,11.0818158616881],[160.284375,11.068015249669],[160.2984375,11.068015249669],[160.2984375,11.0818158616881]]],[[[160.621875,11.123213788449],[160.6078125,11.123213788449],[160.6078125,11.1094151318478],[160.65,11.1094151318478],[160.65,11.123213788449],[160.6359375,11.123213788449],[160.621875,11.123213788449]]],[[[160.340625,11.1094151318478],[160.3265625,11.095615822671],[160.340625,11.095615822671],[160.340625,11.1094151318478]]],[[[160.5796875,11.150809140847],[160.5796875,11.1370117917051],[160.59375,11.1370117917051],[160.59375,11.123213788449],[160.6078125,11.123213788449],[160.6078125,11.150809140847],[160.5796875,11.150809140847]]],[[[160.4109375,11.3163260298893],[160.396875,11.3163260298893],[160.396875,11.3025365900508],[160.425,11.3025365900508],[160.425,11.3163260298893],[160.4109375,11.3163260298893]]],[[[160.565625,11.123213788449],[160.5515625,11.123213788449],[160.5515625,11.1094151318478],[160.565625,11.1094151318478],[160.565625,11.123213788449]]],[[[160.5234375,11.2473722050633],[160.5234375,11.2611642936208],[160.509375,11.2611642936208],[160.509375,11.2473722050633],[160.5234375,11.2473722050633]]],[[[160.340625,11.3576903617558],[160.340625,11.3714771406069],[160.3265625,11.3714771406069],[160.3265625,11.3576903617558],[160.340625,11.3576903617558]]],[[[160.396875,11.3852632522956],[160.4109375,11.3852632522956],[160.4109375,11.3990486960562],[160.396875,11.3990486960562],[160.396875,11.3852632522956]]],[[[160.565625,11.1370117917051],[160.565625,11.123213788449],[160.5796875,11.123213788449],[160.5796875,11.1370117917051],[160.565625,11.1370117917051]]],[[[160.565625,11.150809140847],[160.5515625,11.150809140847],[160.5515625,11.1370117917051],[160.565625,11.1370117917051],[160.565625,11.150809140847]]],[[[160.4109375,11.3301148056307],[160.396875,11.3301148056307],[160.4109375,11.3163260298893],[160.4109375,11.3301148056307]]],[[[160.3828125,11.1784018737118],[160.36875,11.1646058351055],[160.3828125,11.1646058351055],[160.3828125,11.1784018737118]]],[[[160.5234375,11.2197860479317],[160.5234375,11.2059919808932],[160.509375,11.2059919808932],[160.509375,11.2197860479317],[160.4953125,11.2197860479317],[160.4953125,11.2059919808932],[160.4109375,11.2059919808932],[160.4109375,11.2197860479317],[160.3546875,11.2197860479317],[160.3546875,11.2335794562443],[160.36875,11.2335794562443],[160.36875,11.2611642936208],[160.3546875,11.2611642936208],[160.3546875,11.2887464868818],[160.340625,11.2887464868818],[160.340625,11.3025365900508],[160.36875,11.3025365900508],[160.36875,11.2887464868818],[160.396875,11.2887464868818],[160.396875,11.3025365900508],[160.3828125,11.3025365900508],[160.3828125,11.3163260298893],[160.36875,11.3163260298893],[160.36875,11.3301148056307],[160.3828125,11.3301148056307],[160.3828125,11.3439029165083],[160.396875,11.3439029165083],[160.4109375,11.3439029165083],[160.4109375,11.3714771406069],[160.396875,11.3714771406069],[160.396875,11.3576903617558],[160.36875,11.3576903617558],[160.36875,11.3439029165083],[160.3265625,11.3439029165083],[160.3265625,11.3576903617558],[160.2984375,11.3576903617558],[160.2984375,11.3301148056307],[160.284375,11.3163260298893],[160.2703125,11.3163260298893],[160.2703125,11.3025365900508],[160.284375,11.3025365900508],[160.284375,11.2749557211495],[160.284375,11.2611642936208],[160.2984375,11.2611642936208],[160.2984375,11.2473722050633],[160.284375,11.2473722050633],[160.284375,11.1921972558972],[160.3125,11.1921972558972],[160.3125,11.1646058351055],[160.3265625,11.1646058351055],[160.3265625,11.150809140847],[160.3125,11.150809140847],[160.3125,11.1370117917051],[160.2984375,11.1370117917051],[160.2984375,11.123213788449],[160.284375,11.123213788449],[160.284375,11.1094151318478],[160.2421875,11.1094151318478],[160.228125,11.1094151318478],[160.2140625,11.1094151318478],[160.2140625,11.095615822671],[160.2421875,11.095615822671],[160.2421875,11.0818158616881],[160.25625,11.0818158616881],[160.25625,11.095615822671],[160.2703125,11.095615822671],[160.2984375,11.095615822671],[160.2984375,11.0818158616881],[160.3125,11.0818158616881],[160.3125,11.095615822671],[160.3265625,11.095615822671],[160.3265625,11.1094151318478],[160.3265625,11.123213788449],[160.340625,11.123213788449],[160.340625,11.1094151318478],[160.3546875,11.1094151318478],[160.3546875,11.095615822671],[160.36875,11.095615822671],[160.36875,11.1094151318478],[160.396875,11.1094151318478],[160.396875,11.123213788449],[160.4109375,11.123213788449],[160.4109375,11.1370117917051],[160.3828125,11.1370117917051],[160.3828125,11.150809140847],[160.36875,11.150809140847],[160.36875,11.1646058351055],[160.36875,11.1784018737118],[160.3828125,11.1784018737118],[160.453125,11.1784018737118],[160.453125,11.1921972558972],[160.48125,11.1921972558972],[160.48125,11.1784018737118],[160.4953125,11.1784018737118],[160.509375,11.1784018737118],[160.5234375,11.1784018737118],[160.5234375,11.1646058351055],[160.5375,11.1646058351055],[160.5375,11.150809140847],[160.5515625,11.150809140847],[160.5515625,11.1646058351055],[160.565625,11.1646058351055],[160.565625,11.1784018737118],[160.5515625,11.1784018737118],[160.5515625,11.1921972558972],[160.565625,11.1921972558972],[160.565625,11.2059919808932],[160.5375,11.2059919808932],[160.5375,11.2197860479317],[160.5234375,11.2197860479317]],[[160.340625,11.2887464868818],[160.340625,11.2749557211495],[160.340625,11.2611642936208],[160.3265625,11.2611642936208],[160.3265625,11.2749557211495],[160.3125,11.2749557211495],[160.3125,11.2887464868818],[160.340625,11.2887464868818]],[[160.340625,11.1370117917051],[160.340625,11.150809140847],[160.3546875,11.150809140847],[160.3546875,11.1370117917051],[160.340625,11.1370117917051]]]]} -------------------------------------------------------------------------------- /test/data/singapore.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/singapore.dbf -------------------------------------------------------------------------------- /test/data/singapore.prj: -------------------------------------------------------------------------------- 1 | PROJCS["SVY21",GEOGCS["SVY21[WGS84]",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",28001.642],PARAMETER["False_Northing",38744.572],PARAMETER["Central_Meridian",103.8333333333333],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",1.366666666666667],UNIT["Meter",1.0]] -------------------------------------------------------------------------------- /test/data/singapore.sbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/singapore.sbn -------------------------------------------------------------------------------- /test/data/singapore.sbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/singapore.sbx -------------------------------------------------------------------------------- /test/data/singapore.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/singapore.shp -------------------------------------------------------------------------------- /test/data/singapore.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/singapore.shx -------------------------------------------------------------------------------- /test/data/singapore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 103.92383995989066,1.3312732063470314,0 6 | 103.92116959172444,1.3293149668842956,103.92651032805688,1.3332314458097674 7 | pbf 8 | 9 | 15 10 | 0 11 | 12 | 13 | 14 | 15 | shape 16 | singapore.shp 17 | zika_cluster 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/data/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /test/data/tile_with_extra_feature_field.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/tile_with_extra_feature_field.mvt -------------------------------------------------------------------------------- /test/data/tile_with_extra_field.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/tile_with_extra_field.mvt -------------------------------------------------------------------------------- /test/data/tile_with_extra_layer_fields.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/tile_with_extra_layer_fields.mvt -------------------------------------------------------------------------------- /test/data/tile_with_invalid_layer_value_type.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/tile_with_invalid_layer_value_type.mvt -------------------------------------------------------------------------------- /test/data/tile_with_unexpected_geomtype.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/data/tile_with_unexpected_geomtype.mvt -------------------------------------------------------------------------------- /test/fixtures/alpha-white-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/alpha-white-2.png -------------------------------------------------------------------------------- /test/fixtures/expected-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/expected-1.png -------------------------------------------------------------------------------- /test/fixtures/expected-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/expected-2.jpeg -------------------------------------------------------------------------------- /test/fixtures/expected-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/expected-2.png -------------------------------------------------------------------------------- /test/fixtures/expected-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/expected-3.png -------------------------------------------------------------------------------- /test/fixtures/expected-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/expected-4.png -------------------------------------------------------------------------------- /test/fixtures/rasterize-expected-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/rasterize-expected-1.png -------------------------------------------------------------------------------- /test/fixtures/transform-expected-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/transform-expected-1.png -------------------------------------------------------------------------------- /test/fixtures/transform-expected-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapnik-vector-tile/98ace1c737c6c9a80058835d41de233621394678/test/fixtures/transform-expected-2.png -------------------------------------------------------------------------------- /test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | source ./bootstrap.sh 7 | 8 | BUILDTYPE=${BUILDTYPE:-Release} 9 | 10 | ./build/${BUILDTYPE}/tests -------------------------------------------------------------------------------- /test/system/encode_and_datasource_decode.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik 4 | #include 5 | #include 6 | #if MAPNIK_VERSION >= 300100 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | // mapnik-vector-tile 15 | #include "vector_tile_geometry_encoder_pbf.hpp" 16 | #include "vector_tile_datasource_pbf.hpp" 17 | 18 | // vector tile 19 | #pragma GCC diagnostic push 20 | #pragma GCC diagnostic ignored "-Wunused-parameter" 21 | #pragma GCC diagnostic ignored "-Wsign-conversion" 22 | #include "vector_tile.pb.h" 23 | #pragma GCC diagnostic pop 24 | 25 | TEST_CASE("encoding multi line string and check output datasource") 26 | { 27 | mapbox::geometry::multi_line_string geom; 28 | { 29 | mapbox::geometry::line_string ring; 30 | ring.emplace_back(0,0); 31 | ring.emplace_back(2,2); 32 | geom.emplace_back(std::move(ring)); 33 | } 34 | { 35 | mapbox::geometry::line_string ring; 36 | ring.emplace_back(1,1); 37 | ring.emplace_back(2,2); 38 | geom.emplace_back(std::move(ring)); 39 | } 40 | 41 | vector_tile::Tile tile; 42 | vector_tile::Tile_Layer * t_layer = tile.add_layers(); 43 | t_layer->set_name("layer"); 44 | t_layer->set_version(2); 45 | t_layer->set_extent(4096); 46 | vector_tile::Tile_Feature * t_feature = t_layer->add_features(); 47 | std::int32_t x = 0; 48 | std::int32_t y = 0; 49 | std::string feature_str; 50 | protozero::pbf_writer feature_writer(feature_str); 51 | CHECK(mapnik::vector_tile_impl::encode_geometry_pbf(geom, feature_writer, x, y)); 52 | t_feature->ParseFromString(feature_str); 53 | 54 | REQUIRE(1 == tile.layers_size()); 55 | vector_tile::Tile_Layer const& layer = tile.layers(0); 56 | REQUIRE(1 == layer.features_size()); 57 | vector_tile::Tile_Feature const& f = layer.features(0); 58 | CHECK(12 == f.geometry_size()); 59 | CHECK(9 == f.geometry(0)); // 1 move_to 60 | CHECK(0 == f.geometry(1)); // x:0 61 | CHECK(0 == f.geometry(2)); // y:0 62 | CHECK(10 == f.geometry(3)); // 1 line_to 63 | CHECK(4 == f.geometry(4)); // x:2 64 | CHECK(4 == f.geometry(5)); // y:2 65 | CHECK(9 == f.geometry(6)); // 1 move_to 66 | CHECK(1 == f.geometry(7)); // x:1 67 | CHECK(1 == f.geometry(8)); // y:1 68 | CHECK(10 == f.geometry(9)); // 1 line_to 69 | CHECK(2 == f.geometry(10)); // x:2 70 | CHECK(2 == f.geometry(11)); // y:2 71 | 72 | mapnik::featureset_ptr fs; 73 | mapnik::feature_ptr f_ptr; 74 | 75 | std::string buffer; 76 | tile.SerializeToString(&buffer); 77 | protozero::pbf_reader pbf_tile(buffer); 78 | pbf_tile.next(); 79 | protozero::pbf_reader layer2 = pbf_tile.get_message(); 80 | mapnik::vector_tile_impl::tile_datasource_pbf ds(layer2,0,0,0); 81 | mapnik::box2d bbox(-20037508.342789,-20037508.342789,20037508.342789,20037508.342789); 82 | fs = ds.features(mapnik::query(bbox)); 83 | f_ptr = fs->next(); 84 | REQUIRE(f_ptr != mapnik::feature_ptr()); 85 | // no attributes 86 | CHECK(f_ptr->context()->size() == 0); 87 | 88 | CHECK(f_ptr->get_geometry().is >()); 89 | } 90 | 91 | TEST_CASE("encoding and decoding with datasource simple polygon") 92 | { 93 | mapnik::geometry::polygon geom; 94 | { 95 | mapnik::geometry::linear_ring ring; 96 | ring.emplace_back(168.267850,-24.576888); 97 | ring.emplace_back(167.982618,-24.697145); 98 | ring.emplace_back(168.114561,-24.783548); 99 | ring.emplace_back(168.267850,-24.576888); 100 | ring.emplace_back(168.267850,-24.576888); 101 | geom.emplace_back(std::move(ring)); 102 | } 103 | 104 | unsigned path_multiplier = 16; 105 | mapnik::geometry::scale_rounding_strategy scale_strat(path_multiplier); 106 | mapnik::geometry::polygon geom2 = mapnik::geometry::transform(geom, scale_strat); 107 | 108 | // encode geometry 109 | vector_tile::Tile tile; 110 | vector_tile::Tile_Layer * t_layer = tile.add_layers(); 111 | vector_tile::Tile_Feature * t_feature = t_layer->add_features(); 112 | std::int32_t x = 0; 113 | std::int32_t y = 0; 114 | std::string feature_str; 115 | protozero::pbf_writer feature_writer(feature_str); 116 | CHECK(mapnik::vector_tile_impl::encode_geometry_pbf(geom2, feature_writer, x, y)); 117 | t_feature->ParseFromString(feature_str); 118 | 119 | // test results 120 | REQUIRE(1 == tile.layers_size()); 121 | vector_tile::Tile_Layer const& layer = tile.layers(0); 122 | CHECK(1 == layer.features_size()); 123 | vector_tile::Tile_Feature const& f = layer.features(0); 124 | CHECK(11 == f.geometry_size()); 125 | } 126 | -------------------------------------------------------------------------------- /test/system/encode_and_decode.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // test utils 4 | #include "encoding_util.hpp" 5 | 6 | // 7 | // Point Round Trip 8 | // 9 | 10 | TEST_CASE("encode and decode point") 11 | { 12 | mapbox::geometry::point g(0,0); 13 | std::string expected( 14 | "move_to(0,0)\n" 15 | ); 16 | 17 | SECTION("protozero decoder VT Spec v1") 18 | { 19 | CHECK(compare_pbf(g,1) == expected); 20 | } 21 | 22 | SECTION("protozero decoder VT Spec v2") 23 | { 24 | CHECK(compare_pbf(g,2) == expected); 25 | } 26 | } 27 | 28 | TEST_CASE( "encode and decode multipoint" ) 29 | { 30 | mapbox::geometry::multi_point g; 31 | g.emplace_back(0,0); 32 | g.emplace_back(1,1); 33 | g.emplace_back(2,2); 34 | std::string expected( 35 | "move_to(0,0)\n" 36 | "move_to(1,1)\n" 37 | "move_to(2,2)\n" 38 | ); 39 | 40 | SECTION("protozero decoder VT Spec v1") 41 | { 42 | CHECK(compare_pbf(g,1) == expected); 43 | } 44 | 45 | SECTION("protozero decoder VT Spec v2") 46 | { 47 | CHECK(compare_pbf(g,2) == expected); 48 | } 49 | } 50 | 51 | // 52 | // Linestring Round Trip 53 | // 54 | 55 | TEST_CASE( "encode and decode linestring" ) 56 | { 57 | mapbox::geometry::line_string g; 58 | g.emplace_back(0,0); 59 | g.emplace_back(1,1); 60 | g.emplace_back(100,100); 61 | std::string expected( 62 | "move_to(0,0)\n" 63 | "line_to(1,1)\n" 64 | "line_to(100,100)\n" 65 | ); 66 | 67 | SECTION("protozero decoder VT Spec v1") 68 | { 69 | CHECK(compare_pbf(g,1) == expected); 70 | } 71 | 72 | SECTION("protozero decoder VT Spec v2") 73 | { 74 | CHECK(compare_pbf(g,2) == expected); 75 | } 76 | } 77 | 78 | TEST_CASE( "encode and decode multi_line_string" ) 79 | { 80 | mapbox::geometry::multi_line_string g; 81 | { 82 | mapbox::geometry::line_string line; 83 | line.emplace_back(0,0); 84 | line.emplace_back(1,1); 85 | line.emplace_back(100,100); 86 | g.emplace_back(std::move(line)); 87 | } 88 | { 89 | mapbox::geometry::line_string line; 90 | line.emplace_back(-10,-10); 91 | line.emplace_back(-20,-20); 92 | line.emplace_back(-100,-100); 93 | g.emplace_back(std::move(line)); 94 | } 95 | std::string expected( 96 | "move_to(0,0)\n" 97 | "line_to(1,1)\n" 98 | "line_to(100,100)\n" 99 | "move_to(-10,-10)\n" 100 | "line_to(-20,-20)\n" 101 | "line_to(-100,-100)\n" 102 | ); 103 | 104 | SECTION("protozero decoder VT Spec v1") 105 | { 106 | CHECK(compare_pbf(g,1) == expected); 107 | } 108 | 109 | SECTION("protozero decoder VT Spec v2") 110 | { 111 | CHECK(compare_pbf(g,2) == expected); 112 | } 113 | } 114 | 115 | TEST_CASE( "encode and decode polygon" ) 116 | { 117 | mapbox::geometry::polygon g; 118 | mapbox::geometry::linear_ring lr; 119 | lr.emplace_back(0,0); 120 | lr.emplace_back(100,0); 121 | lr.emplace_back(100,100); 122 | lr.emplace_back(0,0); 123 | g.push_back(std::move(lr)); 124 | std::string expected( 125 | "move_to(0,0)\n" 126 | "line_to(100,0)\n" 127 | "line_to(100,100)\n" 128 | "close_path(0,0)\n" 129 | ); 130 | 131 | SECTION("protozero decoder VT Spec v1") 132 | { 133 | CHECK(compare_pbf(g,1) == expected); 134 | } 135 | 136 | SECTION("protozero decoder VT Spec v2") 137 | { 138 | CHECK(compare_pbf(g,2) == expected); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /test/system/remove_repeated_point.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // test-utils 4 | #include "round_trip.hpp" 5 | #include "geom_to_wkt.hpp" 6 | #include 7 | 8 | // mapnik 9 | #if MAPNIK_VERSION >= 300100 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | TEST_CASE("vector tile multi_point encoding with repeated points should be removed") 16 | { 17 | mapnik::geometry::multi_point geom; 18 | geom.emplace_back(0,0); 19 | geom.emplace_back(0,0); 20 | geom.emplace_back(1,1); 21 | geom.emplace_back(1,1); 22 | mapnik::geometry::geometry new_geom = test_utils::round_trip(geom); 23 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 24 | std::string wkt; 25 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 26 | CHECK( wkt == "MULTIPOINT(128 -128,128.711 -126.578)" ); 27 | CHECK( new_geom.is >() ); 28 | } 29 | -------------------------------------------------------------------------------- /test/system/round_trip_fill_type.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // test-utils 4 | #include "round_trip.hpp" 5 | #include "geom_to_wkt.hpp" 6 | 7 | // mapnik 8 | #include 9 | #if MAPNIK_VERSION >= 300100 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | TEST_CASE("vector tile polygon even odd fill") 16 | { 17 | using namespace mapnik::geometry; 18 | polygon poly; 19 | { 20 | linear_ring ring; 21 | ring.emplace_back(0,0); 22 | ring.emplace_back(-10,0); 23 | ring.emplace_back(-10,10); 24 | ring.emplace_back(0,10); 25 | ring.emplace_back(0,0); 26 | poly.push_back(std::move(ring)); 27 | linear_ring hole; 28 | hole.emplace_back(-7,7); 29 | hole.emplace_back(-7,3); 30 | hole.emplace_back(-3,3); 31 | hole.emplace_back(-3,7); 32 | hole.emplace_back(-7,7); 33 | poly.push_back(std::move(hole)); 34 | } 35 | mapnik::geometry::geometry new_geom = test_utils::round_trip(poly,0,mapnik::vector_tile_impl::even_odd_fill); 36 | std::string wkt; 37 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 38 | CHECK( wkt == "POLYGON((128 -113.778,120.889 -113.778,120.889 -128,128 -128,128 -113.778),(123.022 -123.733,123.022 -118.044,125.867 -118.044,125.867 -123.733,123.022 -123.733))"); 39 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 40 | REQUIRE( new_geom.is >() ); 41 | } 42 | 43 | TEST_CASE("vector tile polygon non zero fill") 44 | { 45 | using namespace mapnik::geometry; 46 | polygon poly; 47 | { 48 | linear_ring ring; 49 | ring.emplace_back(0,0); 50 | ring.emplace_back(-10,0); 51 | ring.emplace_back(-10,10); 52 | ring.emplace_back(0,10); 53 | ring.emplace_back(0,0); 54 | poly.push_back(std::move(ring)); 55 | linear_ring hole; 56 | hole.emplace_back(-7,7); 57 | hole.emplace_back(-7,3); 58 | hole.emplace_back(-3,3); 59 | hole.emplace_back(-3,7); 60 | hole.emplace_back(-7,7); 61 | poly.push_back(std::move(hole)); 62 | } 63 | mapnik::geometry::geometry new_geom = test_utils::round_trip(poly,0,mapnik::vector_tile_impl::non_zero_fill); 64 | std::string wkt; 65 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 66 | CHECK( wkt == "POLYGON((128 -113.778,120.889 -113.778,120.889 -128,128 -128,128 -113.778),(123.022 -123.733,123.022 -118.044,125.867 -118.044,125.867 -123.733,123.022 -123.733))"); 67 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 68 | REQUIRE( new_geom.is >() ); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /test/system/round_trip_simplification.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // test-utils 4 | #include "round_trip.hpp" 5 | #include "geom_to_wkt.hpp" 6 | 7 | // mapnik 8 | #include 9 | #if MAPNIK_VERSION >= 300100 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | TEST_CASE("vector tile point correctly passed through simplification code path") 16 | { 17 | mapnik::geometry::point geom(-122,48); 18 | mapnik::geometry::geometry new_geom = test_utils::round_trip(geom,500); 19 | std::string wkt; 20 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 21 | CHECK( wkt == "POINT(41.244 -59.733)" ); 22 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 23 | CHECK( new_geom.is >() ); 24 | } 25 | 26 | TEST_CASE("vector tile mulit_point correctly passed through simplification code path") 27 | { 28 | mapnik::geometry::multi_point geom; 29 | geom.emplace_back(-122,48); 30 | geom.emplace_back(-123,49); 31 | mapnik::geometry::geometry new_geom = test_utils::round_trip(geom,500); 32 | std::string wkt; 33 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 34 | CHECK( wkt == "MULTIPOINT(41.244 -59.733,40.533 -58.311)" ); 35 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 36 | CHECK( new_geom.is >() ); 37 | } 38 | 39 | TEST_CASE("vector tile line_string is simplified") 40 | { 41 | mapnik::geometry::line_string line; 42 | line.emplace_back(0,0); 43 | line.emplace_back(1,1); 44 | line.emplace_back(2,2); 45 | line.emplace_back(100,100); 46 | mapnik::geometry::geometry new_geom = test_utils::round_trip(line,500); 47 | std::string wkt; 48 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 49 | CHECK( wkt == "LINESTRING(128 -128,192 0)" ); 50 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 51 | CHECK( new_geom.is >() ); 52 | auto const& line2 = mapnik::util::get >(new_geom); 53 | CHECK( line2.size() == 2 ); 54 | } 55 | 56 | TEST_CASE("vector tile multi_line_string is simplified") 57 | { 58 | mapnik::geometry::multi_line_string geom; 59 | mapnik::geometry::line_string line; 60 | line.emplace_back(0,0); 61 | line.emplace_back(1,1); 62 | line.emplace_back(2,2); 63 | line.emplace_back(100,100); 64 | geom.emplace_back(std::move(line)); 65 | mapnik::geometry::geometry new_geom = test_utils::round_trip(geom,500); 66 | std::string wkt; 67 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 68 | CHECK( wkt == "LINESTRING(128 -128,192 0)" ); 69 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 70 | CHECK( new_geom.is >() ); 71 | auto const& line2 = mapnik::util::get >(new_geom); 72 | CHECK( line2.size() == 2 ); 73 | } 74 | 75 | TEST_CASE("vector tile polygon is simplified") 76 | { 77 | using namespace mapnik::geometry; 78 | polygon poly; 79 | { 80 | linear_ring ring; 81 | ring.emplace_back(0,0); 82 | ring.emplace_back(-10,0); 83 | ring.emplace_back(-10,10); 84 | ring.emplace_back(0,10); 85 | ring.emplace_back(0,0); 86 | poly.push_back(std::move(ring)); 87 | linear_ring hole; 88 | hole.emplace_back(-7,7); 89 | hole.emplace_back(-7,3); 90 | hole.emplace_back(-3,3); 91 | hole.emplace_back(-3,7); 92 | hole.emplace_back(-7,7); 93 | poly.push_back(std::move(hole)); 94 | } 95 | mapnik::geometry::geometry new_geom = test_utils::round_trip(poly,500); 96 | std::string wkt; 97 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 98 | CHECK( wkt == "POLYGON((128 -113.778,120.889 -113.778,120.889 -128,128 -128,128 -113.778),(123.022 -123.733,123.022 -118.044,125.867 -118.044,125.867 -123.733,123.022 -123.733))"); 99 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 100 | REQUIRE( new_geom.is >() ); 101 | } 102 | 103 | TEST_CASE("vector tile mulit_polygon is simplified") 104 | { 105 | using namespace mapnik::geometry; 106 | polygon poly; 107 | { 108 | linear_ring ring; 109 | ring.emplace_back(0,0); 110 | ring.emplace_back(-10,0); 111 | ring.emplace_back(-10,10); 112 | ring.emplace_back(0,10); 113 | ring.emplace_back(0,0); 114 | poly.push_back(std::move(ring)); 115 | linear_ring hole; 116 | hole.emplace_back(-7,7); 117 | hole.emplace_back(-7,3); 118 | hole.emplace_back(-3,3); 119 | hole.emplace_back(-3,7); 120 | hole.emplace_back(-7,7); 121 | poly.push_back(std::move(hole)); 122 | } 123 | multi_polygon mp; 124 | mp.push_back(poly); 125 | mapnik::geometry::geometry new_geom = test_utils::round_trip(mp,500); 126 | std::string wkt; 127 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 128 | CHECK( wkt == "POLYGON((128 -113.778,120.889 -113.778,120.889 -128,128 -128,128 -113.778),(123.022 -123.733,123.022 -118.044,125.867 -118.044,125.867 -123.733,123.022 -123.733))"); 129 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 130 | REQUIRE( new_geom.is >() ); 131 | } 132 | 133 | TEST_CASE("vector tile line_string is simplified when outside bounds", "should create vector tile with data" ) { 134 | mapnik::geometry::multi_line_string geom; 135 | mapnik::geometry::line_string line; 136 | line.emplace_back(-10000,0); 137 | line.emplace_back(-10000.1,0); 138 | line.emplace_back(100000,0); 139 | geom.emplace_back(std::move(line)); 140 | mapnik::geometry::geometry new_geom = test_utils::round_trip(geom,100); 141 | std::string wkt; 142 | CHECK( test_utils::to_wkt(wkt, new_geom) ); 143 | // yep this test is weird - more of a fuzz than anything 144 | CHECK( wkt == "LINESTRING(0 -128,256 -128)" ); 145 | CHECK( !mapnik::geometry::is_empty(new_geom) ); 146 | CHECK( new_geom.is >() ); 147 | auto const& line2 = mapnik::util::get >(new_geom); 148 | CHECK( line2.size() == 2 ); 149 | } 150 | -------------------------------------------------------------------------------- /test/test_main.cpp: -------------------------------------------------------------------------------- 1 | // https://github.com/philsquared/Catch/blob/master/docs/own-main.md 2 | #define CATCH_CONFIG_RUNNER 3 | #include "catch.hpp" 4 | 5 | #include 6 | #include 7 | 8 | int main (int argc, char* const argv[]) 9 | { 10 | try 11 | { 12 | GOOGLE_PROTOBUF_VERIFY_VERSION; 13 | } 14 | catch (std::exception const& ex) { 15 | std::clog << ex.what() << "\n"; 16 | return -1; 17 | } 18 | mapnik::datasource_cache::instance().register_datasources(MAPNIK_PLUGINDIR); 19 | int result = Catch::Session().run( argc, argv ); 20 | if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n"); 21 | google::protobuf::ShutdownProtobufLibrary(); 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /test/test_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "test_utils.hpp" 2 | 3 | // mapnik 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #if MAPNIK_VERSION >= 300100 23 | #include 24 | #else 25 | #include 26 | #endif 27 | #include 28 | #include 29 | #include 30 | 31 | namespace testing 32 | { 33 | 34 | std::shared_ptr build_ds(double x,double y, bool second) 35 | { 36 | mapnik::parameters params; 37 | params["type"] = "memory"; 38 | std::shared_ptr ds = std::make_shared(params); 39 | mapnik::context_ptr ctx = std::make_shared(); 40 | ctx->push("name"); 41 | mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); 42 | mapnik::transcoder tr("utf-8"); 43 | feature->put("name",tr.transcode("null island")); 44 | // NOTE: all types below that are not part of mapnik::value 45 | // are likely getting converted, e.g. float -> double 46 | feature->put_new("int",static_cast(-73)); 47 | feature->put_new("uint",static_cast(37)); 48 | feature->put_new("float",static_cast(99.2)); 49 | feature->put_new("double",static_cast(83.4)); 50 | feature->put_new("bool",true); 51 | feature->put_new("boolf",false); 52 | feature->set_geometry(mapnik::geometry::point(x,y)); 53 | ds->push(feature); 54 | if (second) 55 | { 56 | ctx->push("name2"); 57 | mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx,1)); 58 | feature2->put("name",tr.transcode("null island")); 59 | feature2->put("name2",tr.transcode("null island 2")); 60 | feature2->set_geometry(mapnik::geometry::point(x+1,y+1)); 61 | ds->push(feature2); 62 | } 63 | return ds; 64 | } 65 | 66 | std::shared_ptr build_geojson_ds(std::string const& geojson_file) 67 | { 68 | mapnik::util::file input(geojson_file); 69 | if (!input.is_open()) 70 | { 71 | throw std::runtime_error("failed to open geojson"); 72 | } 73 | mapnik::geometry::geometry geom; 74 | std::string json_string(input.data().get(), input.size()); 75 | if (!mapnik::json::from_geojson(json_string, geom)) 76 | { 77 | throw std::runtime_error("failed to parse geojson"); 78 | } 79 | mapnik::geometry::correct(geom); 80 | mapnik::parameters params; 81 | params["type"] = "memory"; 82 | std::shared_ptr ds = std::make_shared(params); 83 | mapnik::context_ptr ctx = std::make_shared(); 84 | ctx->push("name"); 85 | mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); 86 | feature->set_geometry(std::move(geom)); 87 | ds->push(feature); 88 | return ds; 89 | } 90 | 91 | mapnik::datasource_ptr build_geojson_fs_ds(std::string const& geojson_file) 92 | { 93 | mapnik::parameters params; 94 | params["type"] = "geojson"; 95 | params["file"] = geojson_file; 96 | params["cache_features"] = "false"; 97 | return mapnik::datasource_cache::instance().create(params); 98 | } 99 | 100 | mapnik::geometry::geometry read_geojson(std::string const& geojson_file) 101 | { 102 | mapnik::util::file input(geojson_file); 103 | if (!input.is_open()) 104 | { 105 | throw std::runtime_error("failed to open geojson"); 106 | } 107 | mapnik::geometry::geometry geom; 108 | std::string json_string(input.data().get(), input.size()); 109 | if (!mapnik::json::from_geojson(json_string, geom)) 110 | { 111 | throw std::runtime_error("failed to parse geojson"); 112 | } 113 | mapnik::geometry::correct(geom); 114 | return geom; 115 | } 116 | 117 | unsigned compare_images(mapnik::image_rgba8 const& src1, 118 | std::string const& filepath, 119 | int threshold, 120 | bool alpha) 121 | { 122 | boost::optional type = mapnik::type_from_filename(filepath); 123 | if (!type) 124 | { 125 | throw mapnik::image_reader_exception("Failed to detect type of: " + filepath); 126 | } 127 | std::unique_ptr reader2(mapnik::get_image_reader(filepath,*type)); 128 | if (!reader2.get()) 129 | { 130 | throw mapnik::image_reader_exception("Failed to load: " + filepath); 131 | } 132 | mapnik::image_any const& image_2 = reader2->read(0,0,reader2->width(),reader2->height()); 133 | 134 | mapnik::image_rgba8 const& src2 = mapnik::util::get(image_2); 135 | return mapnik::compare(src1,src2,threshold,alpha); 136 | } 137 | 138 | } // end ns 139 | -------------------------------------------------------------------------------- /test/test_utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TEST_UTILS_H__ 2 | #define __MAPNIK_VECTOR_TEST_UTILS_H__ 3 | 4 | // mapnik 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace testing { 11 | 12 | std::shared_ptr build_ds(double x,double y, bool second=false); 13 | mapnik::geometry::geometry read_geojson(std::string const& geojson_file); 14 | std::shared_ptr build_geojson_ds(std::string const& geojson_file); 15 | mapnik::datasource_ptr build_geojson_fs_ds(std::string const& geojson_file); 16 | 17 | unsigned compare_images(std::string const& src_fn, 18 | std::string const& dest_fn, 19 | int threshold=16, 20 | bool alpha=true); 21 | unsigned compare_images(mapnik::image_rgba8 const& src1, 22 | std::string const& filepath, 23 | int threshold=16, 24 | bool alpha=true); 25 | unsigned compare_images(mapnik::image_any const& src1, 26 | std::string const& filepath, 27 | int threshold=16, 28 | bool alpha=true); 29 | 30 | } 31 | 32 | #endif // __MAPNIK_VECTOR_TEST_UTILS_H__ 33 | -------------------------------------------------------------------------------- /test/unit/composite/vector.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik vector tile 4 | #include "vector_tile_composite.hpp" 5 | 6 | // 7 | // Unit tests for vt compositing 8 | // 9 | 10 | TEST_CASE("composite") 11 | { 12 | CHECK(true); 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/unit/encoding/geometry_to_feature_pbf.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik vector tile 4 | #include "vector_tile_geometry_feature.hpp" 5 | 6 | // mapnik 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // protozero 13 | #include 14 | 15 | // libprotobuf 16 | #pragma GCC diagnostic push 17 | #pragma GCC diagnostic ignored "-Wunused-parameter" 18 | #pragma GCC diagnostic ignored "-Wsign-conversion" 19 | #include "vector_tile.pb.h" 20 | #pragma GCC diagnostic pop 21 | 22 | // std 23 | #include 24 | 25 | // 26 | // Unit tests for encoding of geometries to features 27 | // 28 | 29 | TEST_CASE("encode feature pbf of degenerate linestring") 30 | { 31 | mapbox::geometry::line_string line; 32 | line.emplace_back(10,10); 33 | 34 | std::string layer_buffer = ""; 35 | mapnik::vector_tile_impl::layer_builder_pbf layer("foo", 4096, layer_buffer); 36 | mapnik::feature_ptr f(mapnik::feature_factory::create(std::make_shared(),1)); 37 | mapnik::vector_tile_impl::geometry_to_feature_pbf_visitor visitor(*f, layer); 38 | visitor(line); 39 | 40 | REQUIRE(layer.empty == true); 41 | } 42 | -------------------------------------------------------------------------------- /test/unit/is_valid/feature_is_valid.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mvt 4 | #include "vector_tile_is_valid.hpp" 5 | 6 | // protozero 7 | #include 8 | 9 | #include "vector_tile.pb.h" 10 | 11 | typedef std::set error_set_T; 12 | 13 | TEST_CASE( "invalid empty feature" ) 14 | { 15 | std::string buffer; 16 | vector_tile::Tile_Feature feature; 17 | error_set_T errs; 18 | 19 | feature.SerializeToString(&buffer); 20 | protozero::pbf_reader pbf_feature(buffer); 21 | 22 | feature_is_valid(pbf_feature, errs); 23 | 24 | CHECK(errs.empty() == false); 25 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::FEATURE_IS_EMPTY) == 1); 26 | } 27 | 28 | TEST_CASE( "invalid geometry without type" ) 29 | { 30 | std::string buffer; 31 | vector_tile::Tile_Feature feature; 32 | error_set_T errs; 33 | 34 | feature.add_geometry(9); // move_to | (1 << 3) 35 | feature.add_geometry(protozero::encode_zigzag32(5)); 36 | feature.add_geometry(protozero::encode_zigzag32(5)); 37 | 38 | feature.SerializeToString(&buffer); 39 | protozero::pbf_reader pbf_feature(buffer); 40 | 41 | feature_is_valid(pbf_feature, errs); 42 | 43 | CHECK(errs.empty() == false); 44 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::FEATURE_NO_GEOM_TYPE) == 1); 45 | } 46 | 47 | TEST_CASE( "valid raster feature" ) 48 | { 49 | std::string buffer; 50 | vector_tile::Tile_Feature feature; 51 | error_set_T errs; 52 | 53 | feature.set_raster("raster-blaster"); 54 | 55 | feature.SerializeToString(&buffer); 56 | protozero::pbf_reader pbf_feature(buffer); 57 | 58 | feature_is_valid(pbf_feature, errs); 59 | 60 | CHECK(errs.empty() == true); 61 | } 62 | 63 | TEST_CASE( "valid geometry feature" ) 64 | { 65 | std::string buffer; 66 | vector_tile::Tile_Feature feature; 67 | error_set_T errs; 68 | 69 | feature.set_type(vector_tile::Tile_GeomType::Tile_GeomType_POINT); 70 | feature.add_geometry(9); // move_to | (1 << 3) 71 | feature.add_geometry(protozero::encode_zigzag32(5)); 72 | feature.add_geometry(protozero::encode_zigzag32(5)); 73 | 74 | feature.SerializeToString(&buffer); 75 | protozero::pbf_reader pbf_feature(buffer); 76 | 77 | feature_is_valid(pbf_feature, errs); 78 | 79 | CHECK(errs.empty() == true); 80 | } 81 | 82 | TEST_CASE( "geometry feature with invalid type" ) 83 | { 84 | std::string buffer; 85 | error_set_T errs; 86 | 87 | protozero::pbf_writer pbf_message(buffer); 88 | pbf_message.add_uint32(3, 4); 89 | 90 | protozero::pbf_reader pbf_feature(buffer); 91 | 92 | feature_is_valid(pbf_feature, errs); 93 | 94 | CHECK(errs.empty() == false); 95 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::FEATURE_HAS_INVALID_GEOM_TYPE) == 1); 96 | } 97 | 98 | TEST_CASE( "invalid feature with geometry and raster" ) 99 | { 100 | std::string buffer; 101 | vector_tile::Tile_Feature feature; 102 | error_set_T errs; 103 | 104 | feature.set_type(vector_tile::Tile_GeomType::Tile_GeomType_POINT); 105 | feature.add_geometry(9); // move_to | (1 << 3) 106 | feature.add_geometry(protozero::encode_zigzag32(5)); 107 | feature.add_geometry(protozero::encode_zigzag32(5)); 108 | 109 | feature.set_raster("raster-blaster"); 110 | 111 | feature.SerializeToString(&buffer); 112 | protozero::pbf_reader pbf_feature(buffer); 113 | 114 | feature_is_valid(pbf_feature, errs); 115 | 116 | CHECK(errs.empty() == false); 117 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::FEATURE_RASTER_AND_GEOM) == 1); 118 | } 119 | 120 | TEST_CASE( "invalid unknown tag in feature" ) 121 | { 122 | std::string buffer; 123 | error_set_T errs; 124 | 125 | protozero::pbf_writer pbf_message(buffer); 126 | pbf_message.add_string(8, "unknown field"); 127 | 128 | protozero::pbf_reader pbf_value(buffer); 129 | 130 | feature_is_valid(pbf_value, errs); 131 | 132 | CHECK(errs.empty() == false); 133 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::FEATURE_HAS_UNKNOWN_TAG) == 1); 134 | } 135 | -------------------------------------------------------------------------------- /test/unit/is_valid/value_is_valid.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mvt 4 | #include "vector_tile_is_valid.hpp" 5 | 6 | // protozero 7 | #include 8 | 9 | #include "vector_tile.pb.h" 10 | 11 | 12 | typedef std::set error_set_T; 13 | 14 | TEST_CASE( "invalid empty value" ) 15 | { 16 | std::string buffer; 17 | vector_tile::Tile_Value value; 18 | error_set_T errs; 19 | 20 | value.SerializeToString(&buffer); 21 | protozero::pbf_reader pbf_value(buffer); 22 | 23 | value_is_valid(pbf_value, errs); 24 | 25 | CHECK(errs.empty() == false); 26 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::VALUE_NO_VALUE) == 1); 27 | } 28 | 29 | TEST_CASE( "valid values" ) 30 | { 31 | SECTION("valid string") 32 | { 33 | std::string buffer; 34 | vector_tile::Tile_Value value; 35 | error_set_T errs; 36 | 37 | value.set_string_value("just another mapnik monday"); 38 | 39 | value.SerializeToString(&buffer); 40 | protozero::pbf_reader pbf_value(buffer); 41 | 42 | value_is_valid(pbf_value, errs); 43 | 44 | CHECK(errs.empty() == true); 45 | } 46 | 47 | SECTION("valid float") 48 | { 49 | std::string buffer; 50 | vector_tile::Tile_Value value; 51 | error_set_T errs; 52 | 53 | value.set_float_value(2015.0); 54 | 55 | value.SerializeToString(&buffer); 56 | protozero::pbf_reader pbf_value(buffer); 57 | 58 | value_is_valid(pbf_value, errs); 59 | 60 | CHECK(errs.empty() == true); 61 | } 62 | 63 | SECTION("valid double") 64 | { 65 | std::string buffer; 66 | vector_tile::Tile_Value value; 67 | error_set_T errs; 68 | 69 | value.set_double_value(2016.0); 70 | 71 | value.SerializeToString(&buffer); 72 | protozero::pbf_reader pbf_value(buffer); 73 | 74 | value_is_valid(pbf_value, errs); 75 | 76 | CHECK(errs.empty() == true); 77 | } 78 | 79 | SECTION("valid int") 80 | { 81 | std::string buffer; 82 | vector_tile::Tile_Value value; 83 | error_set_T errs; 84 | 85 | value.set_int_value(2017); 86 | 87 | value.SerializeToString(&buffer); 88 | protozero::pbf_reader pbf_value(buffer); 89 | 90 | value_is_valid(pbf_value, errs); 91 | 92 | CHECK(errs.empty() == true); 93 | } 94 | 95 | SECTION("valid uint") 96 | { 97 | std::string buffer; 98 | vector_tile::Tile_Value value; 99 | error_set_T errs; 100 | 101 | value.set_uint_value(2017); 102 | 103 | value.SerializeToString(&buffer); 104 | protozero::pbf_reader pbf_value(buffer); 105 | 106 | value_is_valid(pbf_value, errs); 107 | 108 | CHECK(errs.empty() == true); 109 | } 110 | 111 | SECTION("valid sint") 112 | { 113 | std::string buffer; 114 | vector_tile::Tile_Value value; 115 | error_set_T errs; 116 | 117 | value.set_sint_value(2017); 118 | 119 | value.SerializeToString(&buffer); 120 | protozero::pbf_reader pbf_value(buffer); 121 | 122 | value_is_valid(pbf_value, errs); 123 | 124 | CHECK(errs.empty() == true); 125 | } 126 | 127 | SECTION("valid bool") 128 | { 129 | std::string buffer; 130 | vector_tile::Tile_Value value; 131 | error_set_T errs; 132 | 133 | value.set_bool_value(false); 134 | 135 | value.SerializeToString(&buffer); 136 | protozero::pbf_reader pbf_value(buffer); 137 | 138 | value_is_valid(pbf_value, errs); 139 | 140 | CHECK(errs.empty() == true); 141 | } 142 | } 143 | 144 | TEST_CASE( "invalid multiple values" ) 145 | { 146 | std::string buffer; 147 | vector_tile::Tile_Value value; 148 | error_set_T errs; 149 | 150 | value.set_bool_value(false); 151 | value.set_string_value("false"); 152 | 153 | value.SerializeToString(&buffer); 154 | protozero::pbf_reader pbf_value(buffer); 155 | 156 | value_is_valid(pbf_value, errs); 157 | 158 | CHECK(errs.empty() == false); 159 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::VALUE_MULTIPLE_VALUES) == 1); 160 | } 161 | 162 | TEST_CASE( "invalid unknown values" ) 163 | { 164 | std::string buffer; 165 | vector_tile::Tile_Value value; 166 | error_set_T errs; 167 | 168 | value.set_bool_value(false); 169 | value.set_string_value("false"); 170 | 171 | value.SerializeToString(&buffer); 172 | protozero::pbf_reader pbf_value(buffer); 173 | 174 | value_is_valid(pbf_value, errs); 175 | 176 | CHECK(errs.empty() == false); 177 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::VALUE_MULTIPLE_VALUES) == 1); 178 | } 179 | 180 | TEST_CASE( "invalid garbage value throws" ) 181 | { 182 | std::string buffer = "garbage"; 183 | error_set_T errs; 184 | 185 | protozero::pbf_reader pbf_value(buffer); 186 | 187 | CHECK_THROWS(value_is_valid(pbf_value, errs)); 188 | } 189 | 190 | TEST_CASE( "invalid unknown tag" ) 191 | { 192 | std::string buffer; 193 | error_set_T errs; 194 | 195 | protozero::pbf_writer pbf_message(buffer); 196 | pbf_message.add_string(8, "unknown field"); 197 | 198 | protozero::pbf_reader pbf_value(buffer); 199 | 200 | value_is_valid(pbf_value, errs); 201 | 202 | CHECK(errs.empty() == false); 203 | CHECK(errs.count(mapnik::vector_tile_impl::validity_error::VALUE_HAS_UNKNOWN_TAG) == 1); 204 | } 205 | -------------------------------------------------------------------------------- /test/unit/layer_impl/layer.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik 4 | #include 5 | #include 6 | #include 7 | 8 | // mapnik vector tile layer class 9 | #include "vector_tile_layer.hpp" 10 | 11 | TEST_CASE("Vector tile layer class") 12 | { 13 | SECTION("The constructor can produce a valid tile_layer with empty vars") 14 | { 15 | mapnik::Map map(256, 256); 16 | 17 | // Create memory datasource 18 | mapnik::parameters params; 19 | params["type"] = "memory"; 20 | auto ds = std::make_shared(params); 21 | 22 | mapnik::layer layer("layer", "epsg:3857"); 23 | layer.set_datasource(ds); 24 | mapnik::box2d extent(-20037508.342789,-20037508.342789,20037508.342789,20037508.342789); 25 | const mapnik::attributes empty_vars; 26 | 27 | mapnik::vector_tile_impl::tile_layer some_layer(map, 28 | layer, 29 | extent, 30 | 256, // tile_size 31 | 10, // buffer_size 32 | 1.0, // scale_factor 33 | 0, // scale_denom 34 | 0, // offset_x 35 | 0, // offset_y 36 | empty_vars); 37 | CHECK(some_layer.is_valid()); 38 | } 39 | 40 | SECTION("The query has the variables passed to the constructor") 41 | { 42 | mapnik::Map map(256, 256); 43 | 44 | // Create memory datasource 45 | mapnik::parameters params; 46 | params["type"] = "memory"; 47 | auto ds = std::make_shared(params); 48 | 49 | mapnik::layer layer("layer", "epsg:3857"); 50 | layer.set_datasource(ds); 51 | mapnik::box2d extent(-20037508.342789,-20037508.342789,20037508.342789,20037508.342789); 52 | const mapnik::attributes vars { {"zoom_level", 20} }; 53 | 54 | mapnik::vector_tile_impl::tile_layer some_layer(map, 55 | layer, 56 | extent, 57 | 256, // tile_size 58 | 10, // buffer_size 59 | 1.0, // scale_factor 60 | 0, // scale_denom 61 | 0, // offset_x 62 | 0, // offset_y 63 | vars); 64 | CHECK(some_layer.is_valid()); 65 | CHECK( ( vars == some_layer.get_query().variables() ) ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/unit/load/merge.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mvt 4 | #include "vector_tile_load_tile.hpp" 5 | 6 | //protozero 7 | #include 8 | 9 | // std 10 | #include 11 | #include 12 | 13 | TEST_CASE( "merge_from_compressed_buffer - vector" ) 14 | { 15 | std::ifstream stream("./test/data/0.0.0.vector.mvt",std::ios_base::in|std::ios_base::binary); 16 | REQUIRE(stream.is_open()); 17 | std::string buffer(std::istreambuf_iterator(stream.rdbuf()),(std::istreambuf_iterator())); 18 | REQUIRE(buffer.size() == 3812); 19 | mapnik::vector_tile_impl::merc_tile tile(0,0,0); 20 | // not validating or upgrading 21 | mapnik::vector_tile_impl::merge_from_compressed_buffer(tile, buffer.data(), buffer.size()); 22 | CHECK(tile.get_layers().size() == 1); 23 | { 24 | protozero::pbf_reader tile_msg(tile.get_buffer()); 25 | while (tile_msg.next(mapnik::vector_tile_impl::Tile_Encoding::LAYERS)) 26 | { 27 | const auto layer_view = tile_msg.get_view(); 28 | protozero::pbf_reader layer_props_msg(layer_view); 29 | auto layer_info = mapnik::vector_tile_impl::get_layer_name_and_version(layer_props_msg); 30 | std::string const& layer_name = layer_info.first; 31 | std::uint32_t version = layer_info.second; 32 | CHECK(layer_name == "water"); 33 | CHECK(version == 1); 34 | std::set errors; 35 | protozero::pbf_reader layer_valid_msg(layer_view); 36 | layer_is_valid(layer_valid_msg, errors); 37 | CHECK(errors.size() == 0); 38 | } 39 | } 40 | 41 | // re-adding silently skips existing layer by the same name 42 | mapnik::vector_tile_impl::merge_from_compressed_buffer(tile, buffer.data(), buffer.size()); 43 | CHECK(tile.get_layers().size() == 1); 44 | 45 | // re-adding and validating throws on duplicate layer name 46 | REQUIRE_THROWS(mapnik::vector_tile_impl::merge_from_compressed_buffer(tile, buffer.data(), buffer.size(), true)); 47 | 48 | mapnik::vector_tile_impl::merc_tile tile2(0,0,0); 49 | mapnik::vector_tile_impl::merge_from_compressed_buffer(tile2, buffer.data(), buffer.size(), true, true); 50 | { 51 | protozero::pbf_reader tile_msg(tile2.get_buffer()); 52 | while (tile_msg.next(mapnik::vector_tile_impl::Tile_Encoding::LAYERS)) 53 | { 54 | const auto layer_view = tile_msg.get_view(); 55 | protozero::pbf_reader layer_props_msg(layer_view); 56 | auto layer_info = mapnik::vector_tile_impl::get_layer_name_and_version(layer_props_msg); 57 | std::string const& layer_name = layer_info.first; 58 | std::uint32_t version = layer_info.second; 59 | CHECK(layer_name == "water"); 60 | CHECK(version == 2); 61 | std::set errors; 62 | protozero::pbf_reader layer_valid_msg(layer_view); 63 | layer_is_valid(layer_valid_msg, errors); 64 | CHECK(errors.size() == 0); 65 | } 66 | } 67 | } 68 | 69 | TEST_CASE( "merge_from_compressed_buffer - raster" ) 70 | { 71 | std::ifstream stream("./test/data/image.mvt",std::ios_base::in|std::ios_base::binary); 72 | REQUIRE(stream.is_open()); 73 | std::string buffer(std::istreambuf_iterator(stream.rdbuf()),(std::istreambuf_iterator())); 74 | REQUIRE(buffer.size() == 146098); 75 | mapnik::vector_tile_impl::merc_tile tile(0,0,0); 76 | mapnik::vector_tile_impl::merge_from_compressed_buffer(tile, buffer.data(), buffer.size(), true, true); 77 | CHECK(tile.get_layers().size() == 1); 78 | { 79 | protozero::pbf_reader tile_msg(tile.get_buffer()); 80 | while (tile_msg.next(mapnik::vector_tile_impl::Tile_Encoding::LAYERS)) 81 | { 82 | const auto layer_view = tile_msg.get_view(); 83 | protozero::pbf_reader layer_props_msg(layer_view); 84 | auto layer_info = mapnik::vector_tile_impl::get_layer_name_and_version(layer_props_msg); 85 | std::string const& layer_name = layer_info.first; 86 | std::uint32_t version = layer_info.second; 87 | CHECK(layer_name == "layer"); 88 | CHECK(version == 2); 89 | std::set errors; 90 | protozero::pbf_reader layer_valid_msg(layer_view); 91 | layer_is_valid(layer_valid_msg, errors); 92 | CHECK(errors.size() == 0); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/unit/processor/reprojection_error.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik 4 | #include 5 | 6 | // mapnik-vector-tile 7 | #include "vector_tile_processor.hpp" 8 | 9 | // libprotobuf 10 | #pragma GCC diagnostic push 11 | #pragma GCC diagnostic ignored "-Wunused-parameter" 12 | #pragma GCC diagnostic ignored "-Wsign-conversion" 13 | #include "vector_tile.pb.h" 14 | #pragma GCC diagnostic pop 15 | 16 | 17 | TEST_CASE("feature processor - handle strange projection issues") 18 | { 19 | mapnik::Map map(256, 256); 20 | mapnik::load_map(map, "test/data/singapore.xml"); 21 | mapnik::vector_tile_impl::processor ren(map); 22 | 23 | { 24 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile(1, 0, 1); 25 | vector_tile::Tile tile; 26 | REQUIRE(tile.ParseFromString(out_tile.get_buffer())); 27 | // Should be empty due to simplification 28 | REQUIRE(0 == tile.layers_size()); 29 | } 30 | { 31 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile(1, 0, 1, 4096 * 1024); 32 | vector_tile::Tile tile; 33 | REQUIRE(tile.ParseFromString(out_tile.get_buffer())); 34 | // Expanding the extent here we get some data as simplification doesn't occur 35 | REQUIRE(1 == tile.layers_size()); 36 | CHECK(1 == tile.layers(0).features_size()); 37 | } 38 | { 39 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile(50, 31, 6); 40 | vector_tile::Tile tile; 41 | REQUIRE(tile.ParseFromString(out_tile.get_buffer())); 42 | // Slightly more zoomed in we get data. 43 | REQUIRE(1 == tile.layers_size()); 44 | CHECK(1 == tile.layers(0).features_size()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/unit/processor/scale_denom_filter.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik 4 | #include 5 | 6 | // mapnik-vector-tile 7 | #include "vector_tile_processor.hpp" 8 | 9 | // libprotobuf 10 | #pragma GCC diagnostic push 11 | #pragma GCC diagnostic ignored "-Wunused-parameter" 12 | #pragma GCC diagnostic ignored "-Wsign-conversion" 13 | #include "vector_tile.pb.h" 14 | #pragma GCC diagnostic pop 15 | 16 | 17 | TEST_CASE("feature processor - filtering by scale denominator on layer level") 18 | { 19 | mapnik::Map map(256, 256); 20 | mapnik::load_map(map, "test/data/layer_scale_denom_style.xml"); 21 | mapnik::vector_tile_impl::processor ren(map); 22 | const double scale_denom = 200000; 23 | 24 | { 25 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile( 26 | 2048, 2047, 12, 4096, 0, scale_denom); 27 | vector_tile::Tile tile; 28 | REQUIRE(tile.ParseFromString(out_tile.get_buffer())); 29 | REQUIRE(2 == tile.layers_size()); 30 | CHECK(1 == tile.layers(0).features_size()); 31 | CHECK(2 == tile.layers(1).features_size()); 32 | } 33 | { 34 | // One layer is filtered out after change of scale denominator. 35 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile( 36 | 2048, 2047, 12, 4096, 0, scale_denom * 2.0); 37 | vector_tile::Tile tile; 38 | REQUIRE(tile.ParseFromString(out_tile.get_buffer())); 39 | REQUIRE(1 == tile.layers_size()); 40 | CHECK(1 == tile.layers(0).features_size()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/unit/processor/variables.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // mapnik-vector-tile 10 | #include "vector_tile_processor.hpp" 11 | #include "vector_tile_tile.hpp" 12 | 13 | 14 | TEST_CASE("feature processor - can pass variables down to layers") 15 | { 16 | SECTION("variables are optional") 17 | { 18 | mapnik::Map map(256, 256); 19 | mapnik::attributes empty_vars; 20 | 21 | mapnik::vector_tile_impl::processor some_processor(map); 22 | CHECK( ( empty_vars == some_processor.get_variables() ) ); 23 | } 24 | 25 | SECTION("variables can be passed down to the processor") 26 | { 27 | mapnik::Map map(256, 256); 28 | const mapnik::attributes vars { {"zoom_level", 20} }; 29 | 30 | mapnik::vector_tile_impl::processor some_processor(map, vars); 31 | CHECK( ( vars == some_processor.get_variables() ) ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/utils/decoding_util.cpp: -------------------------------------------------------------------------------- 1 | // test utils 2 | #include "decoding_util.hpp" 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_geometry_decoder.hpp" 6 | 7 | mapnik::vector_tile_impl::GeometryPBF feature_to_pbf_geometry(std::string const& feature_string) 8 | { 9 | protozero::pbf_reader feature_pbf(feature_string); 10 | feature_pbf.next(4); 11 | return mapnik::vector_tile_impl::GeometryPBF(feature_pbf.get_packed_uint32()); 12 | } 13 | -------------------------------------------------------------------------------- /test/utils/decoding_util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_TEST_DECODING_UTIL_H__ 2 | #define __MAPNIK_VECTOR_TILE_TEST_DECODING_UTIL_H__ 3 | 4 | // mapnik vector tile 5 | #include "vector_tile_geometry_decoder.hpp" 6 | 7 | mapnik::vector_tile_impl::GeometryPBF feature_to_pbf_geometry(std::string const& feature_string); 8 | 9 | #endif // __MAPNIK_VECTOR_TILE_TEST_DECODING_UTIL_H__ 10 | -------------------------------------------------------------------------------- /test/utils/encoding_util.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | // mapnik vector tile 4 | #include "vector_tile_geometry_decoder.hpp" 5 | #include "vector_tile_geometry_encoder_pbf.hpp" 6 | 7 | // mapnik 8 | #include 9 | #include 10 | #include 11 | 12 | // test utils 13 | #include "encoding_util.hpp" 14 | #include "decoding_util.hpp" 15 | 16 | #include 17 | 18 | using namespace mapnik::geometry; 19 | 20 | struct show_path 21 | { 22 | std::string & str_; 23 | show_path(std::string & out) : 24 | str_(out) {} 25 | 26 | template 27 | void operator()(T & path) 28 | { 29 | unsigned cmd = -1; 30 | double x = 0; 31 | double y = 0; 32 | std::ostringstream s; 33 | path.rewind(0); 34 | while ((cmd = path.vertex(&x, &y)) != mapnik::SEG_END) 35 | { 36 | switch (cmd) 37 | { 38 | case mapnik::SEG_MOVETO: s << "move_to("; break; 39 | case mapnik::SEG_LINETO: s << "line_to("; break; 40 | case mapnik::SEG_CLOSE: s << "close_path("; break; 41 | default: std::clog << "unhandled cmd " << cmd << "\n"; break; 42 | } 43 | s << x << "," << y << ")\n"; 44 | } 45 | str_ += s.str(); 46 | } 47 | }; 48 | 49 | template 50 | std::string decode_to_path_string(mapnik::geometry::geometry const& g) 51 | { 52 | using decode_path_type = mapnik::geometry::vertex_processor; 53 | std::string out; 54 | show_path sp(out); 55 | mapnik::util::apply_visitor(decode_path_type(sp), g); 56 | return out; 57 | } 58 | 59 | std::string compare_pbf(mapbox::geometry::geometry const& g, unsigned version) 60 | { 61 | std::int32_t x = 0; 62 | std::int32_t y = 0; 63 | std::string feature_str; 64 | protozero::pbf_writer feature_writer(feature_str); 65 | REQUIRE(mapnik::vector_tile_impl::encode_geometry_pbf(g, feature_writer, x, y)); 66 | protozero::pbf_reader feature_reader(feature_str); 67 | int32_t geometry_type = mapnik::vector_tile_impl::Geometry_Type::UNKNOWN; 68 | mapnik::vector_tile_impl::GeometryPBF::pbf_itr geom_itr; 69 | while (feature_reader.next()) 70 | { 71 | if (feature_reader.tag() == mapnik::vector_tile_impl::Feature_Encoding::GEOMETRY) 72 | { 73 | geom_itr = feature_reader.get_packed_uint32(); 74 | } 75 | else if (feature_reader.tag() == mapnik::vector_tile_impl::Feature_Encoding::TYPE) 76 | { 77 | geometry_type = feature_reader.get_enum(); 78 | } 79 | else 80 | { 81 | feature_reader.skip(); 82 | } 83 | } 84 | mapnik::vector_tile_impl::GeometryPBF geoms(geom_itr); 85 | auto g2 = mapnik::vector_tile_impl::decode_geometry(geoms, geometry_type, version, 0.0, 0.0, 1.0, 1.0); 86 | return decode_to_path_string(g2); 87 | } 88 | -------------------------------------------------------------------------------- /test/utils/encoding_util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MAPNIK_VECTOR_TILE_TEST_ENCODING_UTIL_H__ 2 | #define __MAPNIK_VECTOR_TILE_TEST_ENCODING_UTIL_H__ 3 | 4 | // mapbox 5 | #include 6 | 7 | // libprotobuf 8 | #pragma GCC diagnostic push 9 | #pragma GCC diagnostic ignored "-Wunused-parameter" 10 | #pragma GCC diagnostic ignored "-Wsign-conversion" 11 | #include "vector_tile.pb.h" 12 | #pragma GCC diagnostic pop 13 | 14 | std::string compare_pbf(mapbox::geometry::geometry const& g, unsigned version); 15 | 16 | #endif // __MAPNIK_VECTOR_TILE_TEST_ENCODING_UTIL_H__ 17 | -------------------------------------------------------------------------------- /test/utils/geom_to_wkt.cpp: -------------------------------------------------------------------------------- 1 | // mapnik 2 | #include 3 | 4 | namespace test_utils 5 | { 6 | 7 | bool to_wkt(std::string & wkt, mapnik::geometry::geometry const& geom) 8 | { 9 | return mapnik::util::to_wkt(wkt, geom); 10 | } 11 | 12 | bool to_wkt(std::string & wkt, mapnik::geometry::geometry const& geom) 13 | { 14 | return mapnik::util::to_wkt(wkt, geom); 15 | } 16 | 17 | } // end ns test_utils 18 | -------------------------------------------------------------------------------- /test/utils/geom_to_wkt.hpp: -------------------------------------------------------------------------------- 1 | // mapnik 2 | #include 3 | 4 | namespace test_utils 5 | { 6 | 7 | bool to_wkt(std::string & wkt, mapnik::geometry::geometry const& geom); 8 | bool to_wkt(std::string & wkt, mapnik::geometry::geometry const& geom); 9 | 10 | } // end ns test_utils 11 | -------------------------------------------------------------------------------- /test/utils/round_trip.cpp: -------------------------------------------------------------------------------- 1 | // test utils 2 | #include "round_trip.hpp" 3 | 4 | // mapnik-vector-tile 5 | #include "vector_tile_processor.hpp" 6 | #include "vector_tile_strategy.hpp" 7 | #include "vector_tile_geometry_decoder.hpp" 8 | 9 | // mapnik 10 | #include 11 | #include 12 | 13 | // std 14 | #include 15 | 16 | // libprotobuf 17 | #pragma GCC diagnostic push 18 | #pragma GCC diagnostic ignored "-Wunused-parameter" 19 | #pragma GCC diagnostic ignored "-Wsign-conversion" 20 | #include "vector_tile.pb.h" 21 | #pragma GCC diagnostic pop 22 | 23 | namespace test_utils 24 | { 25 | 26 | mapnik::geometry::geometry round_trip(mapnik::geometry::geometry const& geom, 27 | double simplify_distance, 28 | mapnik::vector_tile_impl::polygon_fill_type fill_type, 29 | bool mpu) 30 | { 31 | unsigned tile_size = 256 * 1000; 32 | // Create map note its not 3857 -- round trip as 4326 33 | mapnik::Map map(tile_size,tile_size,"epsg:4326"); 34 | // create layer 35 | mapnik::layer lyr("layer",map.srs()); 36 | // create feature with geometry 37 | mapnik::context_ptr ctx = std::make_shared(); 38 | mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); 39 | mapnik::geometry::geometry g(geom); 40 | feature->set_geometry(std::move(g)); 41 | mapnik::parameters params; 42 | params["type"] = "memory"; 43 | std::shared_ptr ds = std::make_shared(params); 44 | ds->push(feature); 45 | lyr.set_datasource(ds); 46 | map.add_layer(lyr); 47 | 48 | // Build request 49 | mapnik::box2d bbox(-180,-90,180,90); 50 | 51 | // Build processor and create tile 52 | mapnik::vector_tile_impl::processor ren(map); 53 | ren.set_simplify_distance(simplify_distance); 54 | ren.set_fill_type(fill_type); 55 | ren.set_multi_polygon_union(mpu); 56 | mapnik::vector_tile_impl::tile out_tile = ren.create_tile(bbox, tile_size); 57 | 58 | if (out_tile.get_layers().size() != 1) 59 | { 60 | std::stringstream s; 61 | s << "expected 1 layer in `round_trip` found " << out_tile.get_layers().size(); 62 | throw std::runtime_error(s.str()); 63 | } 64 | 65 | protozero::pbf_reader layer_reader; 66 | out_tile.layer_reader(0, layer_reader); 67 | if (!layer_reader.next(mapnik::vector_tile_impl::Layer_Encoding::FEATURES)) 68 | { 69 | throw std::runtime_error("Expected at least one feature in layer"); 70 | } 71 | protozero::pbf_reader feature_reader = layer_reader.get_message(); 72 | int32_t geometry_type = mapnik::vector_tile_impl::Geometry_Type::UNKNOWN; 73 | mapnik::vector_tile_impl::GeometryPBF::pbf_itr geom_itr; 74 | while (feature_reader.next()) 75 | { 76 | if (feature_reader.tag() == mapnik::vector_tile_impl::Feature_Encoding::GEOMETRY) 77 | { 78 | geom_itr = feature_reader.get_packed_uint32(); 79 | } 80 | else if (feature_reader.tag() == mapnik::vector_tile_impl::Feature_Encoding::TYPE) 81 | { 82 | geometry_type = feature_reader.get_enum(); 83 | } 84 | else 85 | { 86 | feature_reader.skip(); 87 | } 88 | } 89 | mapnik::vector_tile_impl::GeometryPBF geoms(geom_itr); 90 | return mapnik::vector_tile_impl::decode_geometry(geoms, geometry_type, 2, 0.0, 0.0, 1000.0, -1000.0); 91 | } 92 | 93 | } // end ns 94 | -------------------------------------------------------------------------------- /test/utils/round_trip.hpp: -------------------------------------------------------------------------------- 1 | // mapnik-vector-tile 2 | #include "vector_tile_processor.hpp" 3 | 4 | // mapnik 5 | #include 6 | 7 | namespace test_utils 8 | { 9 | 10 | mapnik::geometry::geometry round_trip(mapnik::geometry::geometry const& geom, 11 | double simplify_distance=0.0, 12 | mapnik::vector_tile_impl::polygon_fill_type fill_type = mapnik::vector_tile_impl::non_zero_fill, 13 | bool mpu = false); 14 | 15 | } // end ns 16 | -------------------------------------------------------------------------------- /test/vector_tile_projection.cpp: -------------------------------------------------------------------------------- 1 | #include "catch.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "vector_tile_projection.hpp" 8 | 9 | std::vector pointToTile(double lon, double lat, unsigned z) 10 | { 11 | double s = std::sin(lat * M_PI / 180.0); 12 | double z2 = std::pow(2.0,z); 13 | double x = z2 * (lon / 360.0 + 0.5); 14 | double y = z2 * (0.5 - 0.25 * std::log((1 + s) / (1 - s)) / M_PI) - 1; 15 | return { x, y }; 16 | } 17 | 18 | int getBboxZoom(std::vector const& bbox) 19 | { 20 | int MAX_ZOOM = 32; 21 | for (int z = 0; z < MAX_ZOOM; z++) { 22 | int mask = (1 << (32 - (z + 1))); 23 | if (((static_cast(bbox[0]) & mask) != (static_cast(bbox[2]) & mask)) || 24 | ((static_cast(bbox[1]) & mask) != (static_cast(bbox[3]) & mask))) { 25 | return z; 26 | } 27 | } 28 | 29 | return MAX_ZOOM; 30 | } 31 | 32 | std::vector bboxToXYZ(mapnik::box2d const& bboxCoords) 33 | { 34 | double minx = bboxCoords.minx(); 35 | double miny = bboxCoords.miny(); 36 | double maxx = bboxCoords.maxx(); 37 | double maxy = bboxCoords.maxy(); 38 | mapnik::merc2lonlat(&minx,&miny,1); 39 | mapnik::merc2lonlat(&maxx,&maxy,1); 40 | 41 | std::vector ubbox = { 42 | minx, 43 | miny, 44 | maxx, 45 | maxy 46 | }; 47 | unsigned z = getBboxZoom(ubbox); 48 | if (z == 0) return {0, 0, 0}; 49 | minx = pointToTile(minx, miny, 32)[0]; 50 | miny = pointToTile(minx, miny, 32)[1]; 51 | unsigned x = static_cast(minx); 52 | unsigned y = static_cast(miny); 53 | return {x, y, z}; 54 | } 55 | 56 | TEST_CASE( "vector tile projection 1", "should support z/x/y to bbox conversion at 0/0/0" ) { 57 | mapnik::box2d map_extent = mapnik::vector_tile_impl::tile_mercator_bbox(0,0,0); 58 | mapnik::box2d e(-20037508.342789,-20037508.342789,20037508.342789,20037508.342789); 59 | double epsilon = 0.000001; 60 | CHECK(std::fabs(map_extent.minx() - e.minx()) < epsilon); 61 | CHECK(std::fabs(map_extent.miny() - e.miny()) < epsilon); 62 | CHECK(std::fabs(map_extent.maxx() - e.maxx()) < epsilon); 63 | CHECK(std::fabs(map_extent.maxy() - e.maxy()) < epsilon); 64 | auto xyz = bboxToXYZ(map_extent); 65 | /* 66 | CHECK(xyz[0] == 0); 67 | CHECK(xyz[1] == 0); 68 | CHECK(xyz[2] == 0); 69 | */ 70 | } 71 | 72 | TEST_CASE( "vector tile projection 2", "should support z/x/y to bbox conversion up to z33" ) { 73 | int x = 2145960701; 74 | int y = 1428172928; 75 | int z = 32; 76 | mapnik::box2d map_extent = mapnik::vector_tile_impl::tile_mercator_bbox(x,y,z); 77 | mapnik::box2d e(-14210.1492817168364127,6711666.7204630710184574,-14210.1399510249066225,6711666.7297937674447894); 78 | double epsilon = 0.00000001; 79 | CHECK(std::fabs(map_extent.minx() - e.minx()) < epsilon); 80 | CHECK(std::fabs(map_extent.miny() - e.miny()) < epsilon); 81 | CHECK(std::fabs(map_extent.maxx() - e.maxx()) < epsilon); 82 | CHECK(std::fabs(map_extent.maxy() - e.maxy()) < epsilon); 83 | auto xyz = bboxToXYZ(map_extent); 84 | /* 85 | CHECK(xyz[0] == x); 86 | CHECK(xyz[1] == y); 87 | CHECK(xyz[2] == z); 88 | */ 89 | } 90 | 91 | TEST_CASE( "vector tile projection 3", "should support z/x/y to bbox conversion for z3" ) { 92 | int x = 3; 93 | int y = 3; 94 | int z = 3; 95 | mapnik::box2d map_extent = mapnik::vector_tile_impl::tile_mercator_bbox(x,y,z); 96 | mapnik::box2d e(-5009377.085697311,0.0,0.0,5009377.085697311); 97 | double epsilon = 0.00000001; 98 | CHECK(std::fabs(map_extent.minx() - e.minx()) < epsilon); 99 | CHECK(std::fabs(map_extent.miny() - e.miny()) < epsilon); 100 | CHECK(std::fabs(map_extent.maxx() - e.maxx()) < epsilon); 101 | CHECK(std::fabs(map_extent.maxy() - e.maxy()) < epsilon); 102 | auto xyz = bboxToXYZ(map_extent); 103 | /* 104 | CHECK(xyz[0] == x); 105 | CHECK(xyz[1] == y); 106 | CHECK(xyz[2] == z); 107 | */ 108 | } 109 | --------------------------------------------------------------------------------