├── tests ├── __init__.py ├── python │ ├── __init__.py │ ├── README.md │ ├── test_import_wikidata.py │ ├── test_helpers.py │ └── test_utils.py ├── expected │ ├── monaco2.bbox │ ├── monaco.bbox │ ├── parallel_sql │ │ ├── run_last.sql │ │ ├── run_first.sql │ │ └── parallel │ │ │ ├── mountain_peak.sql │ │ │ ├── housenumber.sql │ │ │ └── enumfield.sql │ ├── parallel_sql2 │ │ ├── run_last.sql │ │ ├── run_first.sql │ │ └── parallel │ │ │ ├── mountain_peak.sql │ │ │ ├── housenumber.sql │ │ │ └── enumfield.sql │ ├── devdoc │ │ ├── enumfield │ │ │ ├── etl_diagram │ │ │ ├── mapping_diagram │ │ │ ├── etl_diagram.png │ │ │ ├── mapping_diagram.png │ │ │ ├── etl_diagram.svg │ │ │ └── mapping_diagram.svg │ │ ├── mountain_peak │ │ │ ├── etl_diagram │ │ │ ├── etl_diagram.png │ │ │ ├── mapping_diagram.png │ │ │ ├── mapping_diagram │ │ │ ├── etl_diagram.svg │ │ │ └── mapping_diagram.svg │ │ ├── etl_housenumber.png │ │ ├── mapping_diagram.png │ │ ├── housenumber │ │ │ ├── etl_diagram.png │ │ │ ├── mapping_diagram.png │ │ │ ├── etl_diagram │ │ │ ├── mapping_diagram │ │ │ ├── mapping_diagram.svg │ │ │ └── etl_diagram.svg │ │ ├── etl_housenumber │ │ ├── mapping_diagram │ │ ├── mapping_diagram.svg │ │ └── etl_housenumber.svg │ ├── monaco-cfg.json │ ├── LabelGrid.sql.out │ ├── LineLabel.sql.out │ ├── ZRes.sql.out │ ├── Z.sql.out │ ├── sqlquery.sql │ ├── doc.md │ ├── omt_is_latin.sql.out │ ├── delete_empty_keys.sql.out │ ├── omt_as_numeric.sql.out │ ├── debug_mvt_STDIN_dump_summary.out │ ├── debug_mvt_dump_summary.out │ ├── debug_mvt_URL_dump_summary.out │ ├── debug_mvt_dump_summary_show_names.out │ ├── ToPoint.sql.out │ ├── TileBBox.sql.out │ ├── mvttile_query_v2.5.sql │ ├── imposm3.yaml │ ├── mvttile_query_no_feat_ids.sql │ ├── mvttile_query.sql │ ├── mvttile_query_v3.0.sql │ ├── mvttile_query_gzip.sql │ ├── mvttile_query_gzip9.sql │ ├── mvttile_query_v2.4.8.sql │ ├── mvttile_query_v2.4.0dev-a.sql │ ├── mvttile_query_v2.4.0dev.sql │ ├── mvttile_query_v2.4.8-a.sql │ ├── mvttile_psql.sql │ ├── mvttile_func.sql │ ├── mvttile_func_key.sql │ ├── mvttile_prep.sql │ ├── mvttile_query_test_geom.sql │ ├── mvttile_query_test_geom_key.sql │ ├── CleanNumeric.sql.out │ ├── debug_mvt_dump.out │ ├── debug_mvt_dump_show_names.out │ ├── debug_mvt_dump_show_names_sorted.out │ ├── tm2source.yml │ ├── tm2source2.yml │ └── tm2source3.yml ├── http │ ├── monaco-20150428.osm.pbf.md5 │ ├── empty.mbtiles │ ├── osm_13_4388_2568.mvt │ └── monaco-20150428.osm.pbf ├── sql │ ├── test.env │ ├── LabelGrid.sql │ ├── Z.sql │ ├── ZRes.sql │ ├── README.md │ ├── LineLabel.sql │ ├── TileBBox.sql │ ├── docker-compose.yml │ ├── omt_as_numeric.sql │ ├── delete_empty_keys.sql │ ├── omt_is_latin.sql │ ├── ToPoint.sql │ └── CleanNumeric.sql ├── testlayers │ ├── housenumber │ │ ├── housenumber_centroid.sql │ │ ├── mapping.yaml │ │ ├── layer.sql │ │ └── housenumber.yaml │ ├── enumfield │ │ ├── enumfield.sql │ │ └── enumfield.yaml │ ├── mountain_peak │ │ ├── mapping.yaml │ │ └── mountain_peak.yaml │ └── testmaptiles.yaml └── cache │ ├── Bbbike.json │ └── Geofabrik.json ├── openmaptiles ├── __init__.py ├── sqlite_utils.py ├── tmsource.py ├── vector_tile.py ├── imposm.py ├── styleutils.py └── vector_tile.proto ├── .flake8 ├── docs ├── test-perf.png ├── README.md ├── LocalDocker.md └── gcp_test_startup.sh ├── bin ├── config │ └── repl_config.json ├── generate-imposm3 ├── psql.sh ├── pgwait ├── import-update ├── import-diff ├── generate-doc ├── generate-sqlquery ├── generate-mapping-graph ├── style-tools ├── generate-etlgraph ├── tile_multiplier ├── generate-tm2source ├── generate-sql ├── import-osm ├── import-sql ├── postserve └── generate-sqltomvt ├── sql ├── Makefile ├── zzz_omt_as_numeric.sql ├── CleanNumeric.sql ├── Z.sql ├── LineLabel.sql ├── ZRes.sql ├── TileBBox.sql ├── ToPoint.sql ├── LabelGrid.sql └── LICENSE.md ├── docker ├── generate-vectortiles │ ├── Dockerfile │ ├── export-list.sh │ ├── README.md │ ├── export-local.sh │ ├── LICENSE │ └── utils.sh ├── postgis-preloaded │ ├── README.md │ ├── preload-database.sh │ ├── LICENSE │ └── Dockerfile ├── import-data │ ├── LICENSE │ ├── README.md │ ├── Dockerfile │ ├── clean-natural-earth.sh │ └── import_data.sh └── postgis │ ├── README.md │ ├── initdb-postgis.sh │ └── Dockerfile ├── requirements.txt ├── docker-run.sh ├── .github └── workflows │ └── pull_request.yml ├── LICENSE ├── setup.py ├── .gitignore └── .dockerignore /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/python/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /openmaptiles/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.0.0' 2 | -------------------------------------------------------------------------------- /tests/expected/monaco2.bbox: -------------------------------------------------------------------------------- 1 | 7.409205,43.72335,7.448637,43.75169 2 | -------------------------------------------------------------------------------- /tests/expected/monaco.bbox: -------------------------------------------------------------------------------- 1 | 7.3830115,43.516333,7.500333,43.7543525 2 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | # do not warn for line length > 80 3 | ignore = E501,W503 4 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql/run_last.sql: -------------------------------------------------------------------------------- 1 | -- This SQL code should be executed last 2 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql2/run_last.sql: -------------------------------------------------------------------------------- 1 | -- This SQL code should be executed last 2 | -------------------------------------------------------------------------------- /tests/expected/devdoc/enumfield/etl_diagram: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [rankdir=LR] 3 | } 4 | -------------------------------------------------------------------------------- /docs/test-perf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/docs/test-perf.png -------------------------------------------------------------------------------- /tests/http/monaco-20150428.osm.pbf.md5: -------------------------------------------------------------------------------- 1 | caf8ad16c7c3a0bdfa78780832745457 monaco-20150428.osm.pbf 2 | -------------------------------------------------------------------------------- /tests/expected/devdoc/enumfield/mapping_diagram: -------------------------------------------------------------------------------- 1 | digraph "Imposm Mapping" { 2 | graph [rankdir=LR ranksep=3] 3 | } 4 | -------------------------------------------------------------------------------- /tests/http/empty.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/http/empty.mbtiles -------------------------------------------------------------------------------- /tests/expected/devdoc/mountain_peak/etl_diagram: -------------------------------------------------------------------------------- 1 | digraph G { 2 | graph [rankdir=LR] 3 | imposm3 -> osm_peak_point 4 | } 5 | -------------------------------------------------------------------------------- /tests/http/osm_13_4388_2568.mvt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/http/osm_13_4388_2568.mvt -------------------------------------------------------------------------------- /tests/http/monaco-20150428.osm.pbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/http/monaco-20150428.osm.pbf -------------------------------------------------------------------------------- /tests/expected/devdoc/etl_housenumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/etl_housenumber.png -------------------------------------------------------------------------------- /tests/expected/devdoc/mapping_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/mapping_diagram.png -------------------------------------------------------------------------------- /bin/config/repl_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "replication_url": "http://planet.openstreetmap.org/replication/day/", 3 | "replication_interval": "24h" 4 | } 5 | -------------------------------------------------------------------------------- /tests/expected/devdoc/enumfield/etl_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/enumfield/etl_diagram.png -------------------------------------------------------------------------------- /tests/expected/monaco-cfg.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "replication_interval": "4h", 4 | "replication_url": "http://localhost:8555/fake-updates/" 5 | } 6 | -------------------------------------------------------------------------------- /tests/sql/test.env: -------------------------------------------------------------------------------- 1 | POSTGRES_DB=openmaptiles 2 | POSTGRES_USER=openmaptiles 3 | POSTGRES_PASSWORD=openmaptiles 4 | POSTGRES_HOST=postgres 5 | POSTGRES_PORT=5432 6 | -------------------------------------------------------------------------------- /tests/expected/devdoc/housenumber/etl_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/housenumber/etl_diagram.png -------------------------------------------------------------------------------- /tests/expected/devdoc/enumfield/mapping_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/enumfield/mapping_diagram.png -------------------------------------------------------------------------------- /tests/expected/devdoc/housenumber/mapping_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/housenumber/mapping_diagram.png -------------------------------------------------------------------------------- /tests/expected/devdoc/mountain_peak/etl_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/mountain_peak/etl_diagram.png -------------------------------------------------------------------------------- /tests/sql/LabelGrid.sql: -------------------------------------------------------------------------------- 1 | -- LabelGrid 2 | SELECT LabelGrid(ST_GeomFromText('POINT(100 -100)',900913), 64*9.5546285343) AS v1; -- POINT(305.7481130976 -305.7481130976) 3 | -------------------------------------------------------------------------------- /tests/expected/devdoc/mountain_peak/mapping_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openmaptiles/openmaptiles-tools/HEAD/tests/expected/devdoc/mountain_peak/mapping_diagram.png -------------------------------------------------------------------------------- /tests/expected/LabelGrid.sql.out: -------------------------------------------------------------------------------- 1 | v1 2 | --------------------------------------- 3 | POINT(305.7481130976 -305.7481130976) 4 | (1 row) 5 | 6 | -------------------------------------------------------------------------------- /tests/expected/LineLabel.sql.out: -------------------------------------------------------------------------------- 1 | t_v1 2 | ------ 3 | t 4 | (1 row) 5 | 6 | f_v2 7 | ------ 8 | f 9 | (1 row) 10 | 11 | t_v3 12 | ------ 13 | t 14 | (1 row) 15 | 16 | -------------------------------------------------------------------------------- /sql/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: README.md 2 | README.md: 3 | sed -n -i'' -e '1,/ 6 | 7 | 9 | 10 | G 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sql/CleanNumeric.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### CleanNumeric ### 3 | 4 | Returns the input text as an numeric if possible, otherwise null. 5 | 6 | __Parameters:__ 7 | 8 | - `text` i - Text that you would like as an numeric. 9 | 10 | __Returns:__ `numeric` 11 | ******************************************************************************/ 12 | create or replace function CleanNumeric (i text) returns numeric as 13 | $body$ 14 | SELECT substring(i from '^\s*([-+]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee][-+]?\d+)?)\s*$')::numeric; 15 | $body$ 16 | language sql 17 | strict immutable cost 20 18 | parallel safe; 19 | -------------------------------------------------------------------------------- /tests/expected/devdoc/enumfield/mapping_diagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | Imposm Mapping 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/sql/delete_empty_keys.sql: -------------------------------------------------------------------------------- 1 | -- delete_empty_keys 2 | SELECT delete_empty_keys(NULL) AS v1_null; 3 | SELECT delete_empty_keys(''::hstore) AS v2_null; 4 | SELECT delete_empty_keys('"empty"=>""'::hstore) AS v3_null; 5 | SELECT delete_empty_keys('"foo"=>"bar"'::hstore) AS v4; 6 | SELECT delete_empty_keys('"foo"=>"bar", "empty"=>""'::hstore) AS v5; 7 | SELECT delete_empty_keys('"foo"=>"bar", "empty"=>"", "xx"=>"zz"'::hstore) AS v6; 8 | SELECT delete_empty_keys('"empty"=>"", "foo"=>"bar"'::hstore) AS v7; 9 | SELECT delete_empty_keys('""=>"empty_key"'::hstore) AS v8; 10 | SELECT delete_empty_keys('"nil"=>NULL, "foo"=>"bar"'::hstore) AS v9; 11 | SELECT delete_empty_keys('"nil"=>NULL'::hstore) AS v10_null; 12 | -------------------------------------------------------------------------------- /tests/testlayers/housenumber/mapping.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | include: 3 | - access 4 | 5 | tables: 6 | 7 | # --- test that duplicate items are removed 8 | # etldoc: imposm3 -> osm_housenumber_point 9 | # etldoc: imposm3 -> osm_housenumber_point 10 | housenumber_point: 11 | type: geometry 12 | fields: 13 | - name: osm_id 14 | type: id 15 | - name: geometry 16 | type: geometry 17 | - name: housenumber 18 | key: addr:housenumber 19 | type: string 20 | - name: tags 21 | type: hstore_tags 22 | type_mappings: 23 | points: 24 | addr:housenumber: 25 | - __any__ 26 | polygons: 27 | addr:housenumber: 28 | - __any__ 29 | -------------------------------------------------------------------------------- /tests/testlayers/mountain_peak/mapping.yaml: -------------------------------------------------------------------------------- 1 | tables: 2 | 3 | # etldoc: imposm3 -> osm_peak_point 4 | peak_point: 5 | type: point 6 | columns: 7 | - name: osm_id 8 | type: id 9 | - name: geometry 10 | type: geometry 11 | - name: name 12 | key: name 13 | type: string 14 | - name: name_en 15 | key: name:en 16 | type: string 17 | - name: name_de 18 | key: name:de 19 | type: string 20 | - name: tags 21 | type: hstore_tags 22 | - name: ele 23 | key: ele 24 | type: string 25 | - name: wikipedia 26 | key: wikipedia 27 | type: string 28 | mapping: 29 | natural: 30 | - peak 31 | - volcano 32 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ## This list is also used by setup.py - install_requires 2 | ## But there it removes all version restrictions 3 | ## To upgrade this list, run 4 | ## make build-docker 5 | ## make bash 6 | ## pip install pip-upgrader 7 | ## /home/openmaptiles/.local/bin/pip-upgrade --skip-virtualenv-check 8 | ## choose all if asked 9 | ## this file should now be updated 10 | aiohttp==3.12.14 11 | ascii_graph==1.5.1 12 | asyncpg==0.25.0 13 | beautifulsoup4==4.10.0 14 | betterproto==1.2.5 15 | dataclasses-json==0.5.6 16 | deprecated==1.2.13 17 | docopt-ng==0.7.2 18 | flake8==4.0.1 19 | flake8-quotes==3.3.1 20 | graphviz==0.19.1 21 | psycopg2-binary==2.9.3 22 | pyyaml==6.0 23 | requests==2.32.4 24 | tabulate==0.8.9 25 | tornado==6.5 26 | -------------------------------------------------------------------------------- /tests/expected/delete_empty_keys.sql.out: -------------------------------------------------------------------------------- 1 | v1_null 2 | --------- 3 | 4 | (1 row) 5 | 6 | v2_null 7 | --------- 8 | 9 | (1 row) 10 | 11 | v3_null 12 | --------- 13 | 14 | (1 row) 15 | 16 | v4 17 | -------------- 18 | "foo"=>"bar" 19 | (1 row) 20 | 21 | v5 22 | -------------- 23 | "foo"=>"bar" 24 | (1 row) 25 | 26 | v6 27 | -------------------------- 28 | "xx"=>"zz", "foo"=>"bar" 29 | (1 row) 30 | 31 | v7 32 | -------------- 33 | "foo"=>"bar" 34 | (1 row) 35 | 36 | v8 37 | ----------------- 38 | ""=>"empty_key" 39 | (1 row) 40 | 41 | v9 42 | -------------- 43 | "foo"=>"bar" 44 | (1 row) 45 | 46 | v10_null 47 | ---------- 48 | 49 | (1 row) 50 | 51 | -------------------------------------------------------------------------------- /tests/sql/omt_is_latin.sql: -------------------------------------------------------------------------------- 1 | SELECT omt_is_latin('') as empty_str; 2 | SELECT omt_is_latin(' ') as space; 3 | SELECT omt_is_latin('abc_xyz') as abc_xyz; 4 | SELECT omt_is_latin('ABC_XYZ') as ABC_XYZ; 5 | SELECT omt_is_latin('0123456789') as digits; 6 | 7 | -- Extended Latin from https://en.wikipedia.org/wiki/Latin_Extended_Additional#Compact_table 8 | SELECT omt_is_latin('ḀḁḂḃḄḅḆḇḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẜẝẞẟẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹỺỻỼỽỾỿ') as ext_latin; 9 | 10 | -- Russian 11 | SELECT omt_is_latin('привет') as russian_lc; 12 | SELECT omt_is_latin('ПРИВЕТ') as russian_uc; 13 | -------------------------------------------------------------------------------- /docker-run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Get package version from the openmaptiles/__init__.py 5 | : "${VERSION:=$(grep '__version__' "$(dirname "$0")/openmaptiles/__init__.py" | sed -E 's/^(.*"([^"]+)".*|.*)$/\2/')}" 6 | : "${IMAGE_NAME:=openmaptiles/openmaptiles-tools}" 7 | : "${DOCKER_IMAGE:=${IMAGE_NAME}:${VERSION}}" 8 | : "${DOCKER_USER:=$(id -u "${USER}"):$(id -g "${USER}")}" 9 | 10 | # Current dir is shared with the docker, allowing scripts to write to the dir as a current user 11 | : "${WORKDIR:="$( pwd -P )"}" 12 | 13 | if [[ -t 1 ]]; then 14 | # Running in a terminal 15 | : "${DOCKER_OPTS:="-it --rm"}" 16 | else 17 | : "${DOCKER_OPTS:="--rm"}" 18 | fi 19 | 20 | set -x 21 | docker run ${DOCKER_OPTS} -u "${DOCKER_USER}" -v "${WORKDIR}:/tileset" "${DOCKER_IMAGE}" "$@" 22 | -------------------------------------------------------------------------------- /bin/psql.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Start psql command ! 4 | 5 | set -o errexit 6 | set -o pipefail 7 | set -o nounset 8 | 9 | # wait for Postgres. On error, this script will exit too 10 | SOURCE_DIR="$(dirname "$(readlink -f "$0")")" 11 | # shellcheck source=./pgwait 12 | source "$SOURCE_DIR/pgwait" 13 | 14 | # For backward compatibility, allow both PG* and POSTGRES_* forms, 15 | # with the non-standard POSTGRES_* form taking precedence. 16 | # An error will be raised if neither form is given, except for the PGPORT 17 | export PGHOST="${POSTGRES_HOST:-${PGHOST?}}" 18 | export PGDATABASE="${POSTGRES_DB:-${PGDATABASE?}}" 19 | export PGUSER="${POSTGRES_USER:-${PGUSER?}}" 20 | export PGPASSWORD="${POSTGRES_PASSWORD:-${PGPASSWORD?}}" 21 | export PGPORT="${POSTGRES_PORT:-${PGPORT:-5432}}" 22 | 23 | psql "$@" 24 | -------------------------------------------------------------------------------- /tests/testlayers/testmaptiles.yaml: -------------------------------------------------------------------------------- 1 | tileset: 2 | layers: 3 | - housenumber/housenumber.yaml 4 | - enumfield/enumfield.yaml 5 | - mountain_peak/mountain_peak.yaml 6 | name: TestMapTiles v1.0 7 | version: 1.1.1 8 | id: testmaptiles 9 | description: "Simple tileset for testing." 10 | attribution: "© OpenStreetMap contributors" 11 | center: [-12.2168, 28.6135, 4] 12 | bounds: [-180.0,-85.0511,180.0,85.0511] 13 | maxzoom: 10 14 | minzoom: 0 15 | pixel_scale: 256 16 | languages: 17 | - en 18 | - de 19 | - cs 20 | defaults: 21 | srs: +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over 22 | datasource: 23 | srid: 900913 24 | -------------------------------------------------------------------------------- /docker/generate-vectortiles/export-list.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | 6 | source utils.sh 7 | 8 | readonly LIST_FILE="$EXPORT_DIR/tiles.txt" 9 | readonly TILE_TIMEOUT=${TILE_TIMEOUT:-1800000} 10 | 11 | function export_local_mbtiles() { 12 | local mbtiles_name="tiles.mbtiles" 13 | 14 | if [ ! -f "$LIST_FILE" ]; then 15 | echo "List file "$LIST_FILE" does not exist" 16 | exit 500 17 | fi 18 | 19 | exec tilelive-copy \ 20 | --scheme="list" \ 21 | --list="$LIST_FILE" \ 22 | --timeout="$TILE_TIMEOUT" \ 23 | "tmsource://$DEST_PROJECT_DIR" "mbtiles://$EXPORT_DIR/$mbtiles_name" 24 | } 25 | 26 | function main() { 27 | copy_source_project 28 | cleanup_dest_project 29 | replace_db_connection 30 | export_local_mbtiles 31 | } 32 | 33 | main 34 | -------------------------------------------------------------------------------- /tests/testlayers/housenumber/layer.sql: -------------------------------------------------------------------------------- 1 | 2 | -- etldoc: layer_housenumber[shape=record fillcolor=lightpink, style="rounded,filled", 3 | -- etldoc: label="layer_housenumber | z14_" ] ; 4 | 5 | CREATE OR REPLACE FUNCTION layer_housenumber(bbox geometry, zoom_level integer) 6 | RETURNS TABLE(osm_id bigint, geometry geometry, housenumber text, tags hstore) AS $$ 7 | -- etldoc: osm_housenumber_point -> layer_housenumber:z14_ 8 | SELECT osm_id, geometry, housenumber, tags FROM osm_housenumber_point 9 | WHERE zoom_level >= 14 AND geometry && bbox; 10 | $$ LANGUAGE SQL IMMUTABLE; 11 | 12 | 13 | DROP MATERIALIZED VIEW IF EXISTS layer_housenumber_gen1 CASCADE; 14 | CREATE MATERIALIZED VIEW layer_housenumber_gen1 AS ( 15 | SELECT ST_Simplify(geometry, 10) AS geometry, osm_id, housenumber 16 | FROM osm_housenumber_point 17 | ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; 18 | -------------------------------------------------------------------------------- /tests/expected/omt_as_numeric.sql.out: -------------------------------------------------------------------------------- 1 | fail_null 2 | ----------- 3 | -1 4 | (1 row) 5 | 6 | fail_dot 7 | ---------- 8 | -1 9 | (1 row) 10 | 11 | fail_prefixed_letter 12 | ---------------------- 13 | -1 14 | (1 row) 15 | 16 | fail_postfixed_letter 17 | ----------------------- 18 | -1 19 | (1 row) 20 | 21 | fail_text 22 | ----------- 23 | -1 24 | (1 row) 25 | 26 | ok_big_positive 27 | ----------------- 28 | 9999999999 29 | (1 row) 30 | 31 | ok_big_negative 32 | ----------------- 33 | -9999999999 34 | (1 row) 35 | 36 | ok_integer 37 | ------------ 38 | 123 39 | (1 row) 40 | 41 | ok_float 42 | ---------- 43 | 123.456 44 | (1 row) 45 | 46 | ok_float_trim 47 | --------------- 48 | 123.456 49 | (1 row) 50 | 51 | ok_e_notation 52 | --------------- 53 | 45678.9 54 | (1 row) 55 | 56 | -------------------------------------------------------------------------------- /docker/postgis-preloaded/preload-database.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -Eeo pipefail 3 | 4 | # This code was adapted from a postgres issue 5 | # https://github.com/docker-library/postgres/issues/661#issuecomment-573192715 6 | 7 | source "$(command -v docker-entrypoint.sh)" 8 | 9 | docker_setup_env 10 | docker_create_db_directories 11 | 12 | docker_verify_minimum_env 13 | docker_init_database_dir 14 | pg_setup_hba_conf 15 | 16 | # only required for '--auth[-local]=md5' on POSTGRES_INITDB_ARGS 17 | export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}" 18 | 19 | # Support for the import scripts from other docker containers 20 | # Override PGCONN so that ogr2ogr would connect via socket rather than TCP 21 | export PGCONN="dbname=$POSTGRES_DB user=$POSTGRES_USER password=$PGPASSWORD" 22 | 23 | docker_temp_server_start -c autovacuum=off 24 | docker_setup_db 25 | docker_process_init_files /docker-entrypoint-initdb.d/* 26 | docker_temp_server_stop 27 | -------------------------------------------------------------------------------- /tests/expected/debug_mvt_STDIN_dump_summary.out: -------------------------------------------------------------------------------- 1 | Tile from STDIN size=2,222 bytes, gzipped=1,248 bytes, 3 layers 2 | Layer Extent Ver Features GeoType GeoSize AVG GeoSize Fields (percentage only if not all features have it) name:* fields 3 | ------------------- -------- ----- ---------- ---------------------------- --------- ------------- ---------------------------------------------------------------- --------------- 4 | water 4096 2 1 POLYGON 304 304.0 class 5 | transportation 4096 2 11 LINESTRING(91%), POLYGON(9%) 237 21.5 class, oneway, ramp, brunnel, layer, subclass(55%), surface(36%) 6 | transportation_name 4096 2 2 LINESTRING 72 36.0 name_en, name_de, ref, ref_length, network, class 1 languages 7 | -------------------------------------------------------------------------------- /bin/pgwait: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Wait for Postgres to start using pg_isready 4 | 5 | set -o errexit 6 | set -o pipefail 7 | set -o nounset 8 | 9 | # For backward compatibility, allow both PG* and POSTGRES_* forms, 10 | # with the non-standard POSTGRES_* form taking precedence. 11 | # An error will be raised if neither form is given, except for the PGPORT 12 | export PGHOST="${POSTGRES_HOST:-${PGHOST?}}" 13 | export PGDATABASE="${POSTGRES_DB:-${PGDATABASE?}}" 14 | export PGUSER="${POSTGRES_USER:-${PGUSER?}}" 15 | export PGPORT="${POSTGRES_PORT:-${PGPORT:-5432}}" 16 | 17 | : "${MAX_RETRIES:=40}" # Maximum number of pg_isready calls 18 | tries=0 19 | while ! pg_isready -q 20 | do 21 | tries=$((tries + 1)) 22 | if (( tries > MAX_RETRIES )); then 23 | echo "... gave up waiting for Postgres: PGHOST=${PGHOST} PGDATABASE=${PGDATABASE} PGUSER=${PGUSER} PGPORT=${PGPORT} pg_isready" 24 | exit 1 25 | fi 26 | sleep 2 27 | done 28 | -------------------------------------------------------------------------------- /bin/import-update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | 6 | # For backward compatibility, allow both PG* and POSTGRES_* forms, 7 | # with the non-standard POSTGRES_* form taking precedence. 8 | # An error will be raised if neither form is given, except for the PGPORT 9 | export PGHOST="${POSTGRES_HOST:-${PGHOST?}}" 10 | export PGDATABASE="${POSTGRES_DB:-${PGDATABASE?}}" 11 | export PGUSER="${POSTGRES_USER:-${PGUSER?}}" 12 | export PGPASSWORD="${POSTGRES_PASSWORD:-${PGPASSWORD?}}" 13 | export PGPORT="${POSTGRES_PORT:-${PGPORT:-5432}}" 14 | 15 | imposm run \ 16 | -connection "postgis://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE" \ 17 | -mapping "${IMPOSM_MAPPING_FILE:?}" \ 18 | -cachedir "${IMPOSM_CACHE_DIR:?}" \ 19 | -diffdir "${IMPOSM_DIFF_DIR:?}" \ 20 | -expiretiles-dir "${EXPIRETILES_DIR:?}" \ 21 | -expiretiles-zoom "${EXPIRETILES_ZOOM:-14}" \ 22 | -config "${IMPOSM_CONFIG_FILE:?}" 23 | -------------------------------------------------------------------------------- /tests/sql/ToPoint.sql: -------------------------------------------------------------------------------- 1 | -- ToPoint 2 | SELECT ToPoint(ST_GeomFromText('POINT(0 0)',900913)) AS v1; -- 010100002031BF0D0000000000000000000000000000000000 3 | SELECT ToPoint(ST_GeomFromText('POLYGON EMPTY',900913)) AS null_v2; -- \\N 4 | SELECT ToPoint(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))',900913)) AS v3; -- 010100002031BF0D0000000000000014400000000000001440 5 | SELECT ToPoint(ST_GeomFromText('POLYGON((0 0, 10 0, 0 10, 10 10, 0 0))',900913)) AS v4; -- 010100002031BF0D0000000000000014400000000000000440 6 | SELECT ToPoint(ST_GeomFromText('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))',900913)) AS v5; -- 010100002031BF0D0000000000000014400000000000001440 7 | SELECT ToPoint(ST_GeomFromText('MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)), ((20 20, 30 20, 30 30, 20 30, 20 20)))',900913)) AS v6; -- 010100002031BF0D0000000000000014400000000000001440 8 | SELECT ST_AsText(ToPoint(ST_GeomFromText('POLYGON((50 5,10 8,10 10,100 190,150 30,150 10,50 5))',900913))) AS v7; -- POINT(92.5 110) 9 | -------------------------------------------------------------------------------- /tests/expected/debug_mvt_dump_summary.out: -------------------------------------------------------------------------------- 1 | Uncompressed tile from tests/http/osm_13_4388_2568.mvt size=2,222 bytes, gzipped=1,248 bytes, 3 layers 2 | Layer Extent Ver Features GeoType GeoSize AVG GeoSize Fields (percentage only if not all features have it) name:* fields 3 | ------------------- -------- ----- ---------- ---------------------------- --------- ------------- ---------------------------------------------------------------- --------------- 4 | water 4096 2 1 POLYGON 304 304.0 class 5 | transportation 4096 2 11 LINESTRING(91%), POLYGON(9%) 237 21.5 class, oneway, ramp, brunnel, layer, subclass(55%), surface(36%) 6 | transportation_name 4096 2 2 LINESTRING 72 36.0 name_en, name_de, ref, ref_length, network, class 1 languages 7 | -------------------------------------------------------------------------------- /tests/expected/debug_mvt_URL_dump_summary.out: -------------------------------------------------------------------------------- 1 | Uncompressed tile from http://localhost:8555/osm_13_4388_2568.mvt size=2,222 bytes, gzipped=1,248 bytes, 3 layers 2 | Layer Extent Ver Features GeoType GeoSize AVG GeoSize Fields (percentage only if not all features have it) name:* fields 3 | ------------------- -------- ----- ---------- ---------------------------- --------- ------------- ---------------------------------------------------------------- --------------- 4 | water 4096 2 1 POLYGON 304 304.0 class 5 | transportation 4096 2 11 LINESTRING(91%), POLYGON(9%) 237 21.5 class, oneway, ramp, brunnel, layer, subclass(55%), surface(36%) 6 | transportation_name 4096 2 2 LINESTRING 72 36.0 name_en, name_de, ref, ref_length, network, class 1 languages 7 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Validate PR 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | 7 | job: 8 | name: Run integrity test 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout the changes 12 | uses: actions/checkout@v4 13 | 14 | - name: Tests 15 | run: | 16 | make test 17 | 18 | - name: Save test results 19 | if: ${{ always() }} 20 | uses: actions/upload-artifact@v4 21 | with: 22 | name: build-result 23 | path: build 24 | 25 | - name: Build postgis docker 26 | run: | 27 | pushd docker/postgis 28 | docker build . 29 | popd 30 | 31 | - name: Build generate-vectortiles docker 32 | continue-on-error: true 33 | run: | 34 | pushd docker/generate-vectortiles 35 | docker build . 36 | popd 37 | 38 | # Do not auto-build import-data and postgis-preload due to high download requirements 39 | -------------------------------------------------------------------------------- /bin/import-diff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | 6 | # For backward compatibility, allow both PG* and POSTGRES_* forms, 7 | # with the non-standard POSTGRES_* form taking precedence. 8 | # An error will be raised if neither form is given, except for the PGPORT 9 | export PGHOST="${POSTGRES_HOST:-${PGHOST?}}" 10 | export PGDATABASE="${POSTGRES_DB:-${PGDATABASE?}}" 11 | export PGUSER="${POSTGRES_USER:-${PGUSER?}}" 12 | export PGPASSWORD="${POSTGRES_PASSWORD:-${PGPASSWORD?}}" 13 | export PGPORT="${POSTGRES_PORT:-${PGPORT:-5432}}" 14 | 15 | imposm diff \ 16 | -connection "postgis://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE" \ 17 | -mapping "${IMPOSM_MAPPING_FILE:?}" \ 18 | -cachedir "${IMPOSM_CACHE_DIR:?}" \ 19 | -diffdir "${IMPOSM_DIFF_DIR:?}" \ 20 | -expiretiles-dir "${EXPIRETILES_DIR:?}" \ 21 | -expiretiles-zoom "${EXPIRETILES_ZOOM:-14}" \ 22 | -config "${IMPOSM_CONFIG_FILE:?}" \ 23 | "${PBF_DATA_DIR:?}/changes.osc.gz" 24 | -------------------------------------------------------------------------------- /bin/generate-doc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: 4 | generate-doc 5 | generate-doc --help 6 | generate-doc --version 7 | Options: 8 | --help Show this screen. 9 | --version Show version. 10 | """ 11 | from docopt import docopt 12 | 13 | import openmaptiles 14 | from openmaptiles.tileset import Layer, Field 15 | 16 | 17 | def generate_field_doc(field: Field): 18 | field_doc = f'### {field.name}\n\n{field.description}\n' 19 | if field.values: 20 | field_doc += '\nPossible values:\n\n' 21 | field_doc += '\n'.join((f'- `{v}`' for v in field.values)) + '\n\n' 22 | return field_doc 23 | 24 | 25 | def main(args): 26 | layer = Layer.parse(args['']) 27 | fields_doc = '\n'.join((generate_field_doc(f) for f in layer.fields)) 28 | print(f'{layer.description}\n\n## Fields\n\n{fields_doc}\n\n\n') 29 | 30 | 31 | if __name__ == '__main__': 32 | main(docopt(__doc__, version=openmaptiles.__version__)) 33 | -------------------------------------------------------------------------------- /tests/testlayers/housenumber/housenumber.yaml: -------------------------------------------------------------------------------- 1 | layer: 2 | id: "housenumber" 3 | description: | 4 | Everything in OpenStreetMap which contains a `addr:housenumber` tag useful for labelling housenumbers on a map. 5 | This adds significant size to *z14*. For buildings the centroid of the building is used as housenumber. 6 | buffer_size: 8 7 | srs: +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over 8 | fields: 9 | housenumber: Value of the [`addr:housenumber`](http://wiki.openstreetmap.org/wiki/Key:addr) tag (Faked from current zoom). 10 | datasource: 11 | geometry_field: geometry 12 | srid: 900913 13 | query: (SELECT !bbox! as geometry, z(!scale_denominator!) AS housenumber, {name_languages} FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 14 | schema: 15 | - ./housenumber_centroid.sql 16 | - ./layer.sql 17 | datasources: 18 | - type: imposm3 19 | mapping_file: ./mapping.yaml 20 | -------------------------------------------------------------------------------- /bin/generate-sqlquery: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Usage: 5 | generate-sqlquery 6 | generate-sqlquery --help 7 | generate-sqlquery --version 8 | Options: 9 | --help Show this screen. 10 | --version Show version. 11 | """ 12 | import re 13 | 14 | from docopt import docopt 15 | 16 | import openmaptiles 17 | from openmaptiles.tileset import Layer 18 | 19 | 20 | def main(args): 21 | bbox = "ST_SetSRID('BOX3D(-20037508.34 -20037508.34, 20037508.34 20037508.34)'::box3d, 3857)" 22 | zoom = args[''] 23 | layer = Layer.parse(args['']) 24 | 25 | sql = (layer.query 26 | .replace('!bbox!', bbox) 27 | .replace('z(!scale_denominator!)', zoom) 28 | .replace('!pixel_width!', '1')) 29 | 30 | match = re.search(r'\((.*)\) AS *', sql) 31 | print(match.group(1)) 32 | 33 | 34 | if __name__ == '__main__': 35 | main(docopt(__doc__, version=openmaptiles.__version__)) 36 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql/parallel/mountain_peak.sql: -------------------------------------------------------------------------------- 1 | DO $$ BEGIN RAISE NOTICE 'Processing layer mountain_peak'; END$$; 2 | 3 | DO $$ BEGIN 4 | PERFORM 'my_magic_table'::regclass; 5 | EXCEPTION 6 | WHEN undefined_table THEN 7 | RAISE EXCEPTION '%', SQLERRM 8 | USING DETAIL = 'this table or view is required for layer "mountain_peak"'; 9 | END; 10 | $$ LANGUAGE 'plpgsql'; 11 | 12 | DO $$ BEGIN 13 | PERFORM 'my_magic_func(TEXT, TEXT)'::regprocedure; 14 | EXCEPTION 15 | WHEN undefined_function THEN 16 | RAISE EXCEPTION '%', SQLERRM 17 | USING DETAIL = 'this function is required for layer "mountain_peak"'; 18 | WHEN invalid_text_representation THEN 19 | RAISE EXCEPTION '%', SQLERRM 20 | USING DETAIL = 'Required function "my_magic_func(TEXT, TEXT)" in layer "mountain_peak" is incorrectly declared. Use full function signature with parameter types, e.g. "my_magic_func(TEXT, TEXT)"'; 21 | END; 22 | $$ LANGUAGE 'plpgsql'; 23 | 24 | DO $$ BEGIN RAISE NOTICE 'Finished layer mountain_peak'; END$$; 25 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql2/parallel/mountain_peak.sql: -------------------------------------------------------------------------------- 1 | DO $$ BEGIN RAISE NOTICE 'Processing layer mountain_peak'; END$$; 2 | 3 | DO $$ BEGIN 4 | PERFORM 'my_magic_table'::regclass; 5 | EXCEPTION 6 | WHEN undefined_table THEN 7 | RAISE EXCEPTION '%', SQLERRM 8 | USING DETAIL = 'this table or view is required for layer "mountain_peak"'; 9 | END; 10 | $$ LANGUAGE 'plpgsql'; 11 | 12 | DO $$ BEGIN 13 | PERFORM 'my_magic_func(TEXT, TEXT)'::regprocedure; 14 | EXCEPTION 15 | WHEN undefined_function THEN 16 | RAISE EXCEPTION '%', SQLERRM 17 | USING DETAIL = 'this function is required for layer "mountain_peak"'; 18 | WHEN invalid_text_representation THEN 19 | RAISE EXCEPTION '%', SQLERRM 20 | USING DETAIL = 'Required function "my_magic_func(TEXT, TEXT)" in layer "mountain_peak" is incorrectly declared. Use full function signature with parameter types, e.g. "my_magic_func(TEXT, TEXT)"'; 21 | END; 22 | $$ LANGUAGE 'plpgsql'; 23 | 24 | DO $$ BEGIN RAISE NOTICE 'Finished layer mountain_peak'; END$$; 25 | -------------------------------------------------------------------------------- /tests/expected/debug_mvt_dump_summary_show_names.out: -------------------------------------------------------------------------------- 1 | Uncompressed tile from tests/http/osm_13_4388_2568.mvt size=2,222 bytes, gzipped=1,248 bytes, 3 layers 2 | Layer Extent Ver Features GeoType GeoSize AVG GeoSize Fields (percentage only if not all features have it) name:* fields (percentage of features with that language) 3 | ------------------- -------- ----- ---------- ---------------------------- --------- ------------- ---------------------------------------------------------------- ----------------------------------------------------------- 4 | water 4096 2 1 POLYGON 304 304.0 class 5 | transportation 4096 2 11 LINESTRING(91%), POLYGON(9%) 237 21.5 class, oneway, ramp, brunnel, layer, subclass(55%), surface(36%) 6 | transportation_name 4096 2 2 LINESTRING 72 36.0 name_en, name_de, ref, ref_length, network, class da(100%) 7 | -------------------------------------------------------------------------------- /sql/Z.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### Z ### 3 | 4 | Returns a Web Mercator integer zoom level given a scale denominator. 5 | 6 | Useful with Mapnik's !scale_denominator! token in vector tile source 7 | queries. 8 | 9 | __Parameters:__ 10 | 11 | - `numeric` scale_denominator - The denominator of the scale, eg `250000` 12 | for a 1:250,000 scale. 13 | 14 | __Returns:__ `integer` 15 | 16 | __Example Mapbox Studio query:__ 17 | 18 | ```sql 19 | ( SELECT * FROM roads 20 | WHERE Z(!scale_denominator!) >= 12 21 | ) AS data 22 | ``` 23 | ******************************************************************************/ 24 | create or replace function z (numeric) 25 | returns integer 26 | language sql 27 | immutable 28 | parallel safe 29 | returns null on null input 30 | as $func$ 31 | select 32 | case 33 | -- Don't bother if the scale is larger than ~zoom level 0 34 | when $1 > 600000000 or $1 = 0 then null 35 | else cast (round(log(2,559082264.028/$1)) as integer) 36 | end; 37 | $func$; 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/expected/ToPoint.sql.out: -------------------------------------------------------------------------------- 1 | v1 2 | ---------------------------------------------------- 3 | 010100002031BF0D0000000000000000000000000000000000 4 | (1 row) 5 | 6 | null_v2 7 | --------- 8 | 9 | (1 row) 10 | 11 | v3 12 | ---------------------------------------------------- 13 | 010100002031BF0D0000000000000014400000000000001440 14 | (1 row) 15 | 16 | v4 17 | ---------------------------------------------------- 18 | 010100002031BF0D0000000000000014400000000000001E40 19 | (1 row) 20 | 21 | v5 22 | ---------------------------------------------------- 23 | 010100002031BF0D0000000000000014400000000000001440 24 | (1 row) 25 | 26 | v6 27 | ---------------------------------------------------- 28 | 010100002031BF0D0000000000000014400000000000001440 29 | (1 row) 30 | 31 | v7 32 | ----------------- 33 | POINT(92.5 110) 34 | (1 row) 35 | 36 | -------------------------------------------------------------------------------- /tests/expected/TileBBox.sql.out: -------------------------------------------------------------------------------- 1 | v1 2 | ----------------------------------------------------------------------------------------------------------------------------------------- 3 | POLYGON((-20037508.34 20037508.34,-20037508.34 -20037508.34,20037508.34 -20037508.34,20037508.34 20037508.34,-20037508.34 20037508.34)) 4 | (1 row) 5 | 6 | v2 7 | -------------------------------------------------------------------------------------------------------------------------------------------- 8 | POLYGON((-8590298.99 4715858.9,-8590298.99 4696291.0200000005,-8570731.11 4696291.0200000005,-8570731.11 4715858.9,-8590298.99 4715858.9)) 9 | (1 row) 10 | 11 | v3 12 | ------------------------------------------------------------------- 13 | POLYGON((-180 85.05,-180 -85.05,180 -85.05,180 85.05,-180 85.05)) 14 | (1 row) 15 | 16 | -------------------------------------------------------------------------------- /docker/generate-vectortiles/README.md: -------------------------------------------------------------------------------- 1 | # Generate Vector Tiles from TM2Source 2 | [![Docker Automated build](https://img.shields.io/docker/automated/openmaptiles/generate-vectortiles.svg?maxAge=2592000)]() [![](https://images.microbadger.com/badges/image/openmaptiles/generate-vectortiles.svg)](https://microbadger.com/images/openmaptiles/generate-vectortiles) 3 | 4 | A Docker image to export MBTiles (containing gzipped MVT PBF) from a TM2Source project. 5 | The TM2Source project usually references a database you need to link against this container. 6 | 7 | ## Usage 8 | 9 | You need to provide the database credentials and run `generate-vectortiles`. 10 | 11 | ```bash 12 | docker run --rm \ 13 | -v $(pwd)/project.tm2source:/tm2source \ 14 | -v $(pwd):/export \ 15 | -e PGHOST="127.0.0.1" \ 16 | -e PGDATABASE="openmaptiles" \ 17 | -e PGUSER="openmaptiles" \ 18 | -e PGPASSWORD="openmaptiles" \ 19 | openmaptiles/generate-vectortiles 20 | ``` 21 | 22 | Optional environment variables: 23 | * `PGPORT` (defaults to `5432`) 24 | 25 | Legacy env variables are still supported, but they are not recommended: 26 | `POSTGRES_HOST`,`POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_PORT` 27 | -------------------------------------------------------------------------------- /docker/generate-vectortiles/export-local.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | 6 | source utils.sh 7 | 8 | readonly RENDER_SCHEME=${RENDER_SCHEME:-pyramid} 9 | readonly MIN_ZOOM=${MIN_ZOOM:-0} 10 | readonly MAX_ZOOM=${MAX_ZOOM:-14} 11 | readonly BBOX=${BBOX:-"-180,-85.0511,180,85.0511"} 12 | readonly COPY_CONCURRENCY=${COPY_CONCURRENCY:-10} 13 | readonly TILE_TIMEOUT=${TILE_TIMEOUT:-1800000} 14 | readonly MBTILES_NAME=${MBTILES_NAME:-tiles.mbtiles} 15 | 16 | function export_local_mbtiles() { 17 | echo "Generating tiles into $EXPORT_DIR/$MBTILES_NAME for zooms $MIN_ZOOM..$MAX_ZOOM inside ($BBOX) using $COPY_CONCURRENCY concurrent I/O operations" 18 | 19 | exec tilelive-copy \ 20 | --scheme="$RENDER_SCHEME" \ 21 | --bounds="$BBOX" \ 22 | --timeout="$TILE_TIMEOUT" \ 23 | --concurrency="$COPY_CONCURRENCY" \ 24 | --minzoom="$MIN_ZOOM" \ 25 | --maxzoom="$MAX_ZOOM" \ 26 | "tmsource://$DEST_PROJECT_DIR" "mbtiles://$EXPORT_DIR/$MBTILES_NAME" 27 | } 28 | 29 | function main() { 30 | copy_source_project 31 | cleanup_dest_project 32 | replace_db_connection 33 | export_local_mbtiles 34 | } 35 | 36 | main 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024, MapTiler.com & OpenMapTiles/OSM2VectorTiles contributors. 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /docker/import-data/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020, Yuri Astrakhan (YuriAstrakhan@gmail.com) 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /docker/postgis-preloaded/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020, Yuri Astrakhan (YuriAstrakhan@gmail.com) 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /sql/LineLabel.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### LineLabel ### 3 | 4 | This function tries to estimate whether a line geometry would be long enough to 5 | have the given text placed along it at the specified scale. 6 | 7 | It is useful in vector tile queries to filter short lines from zoom levels 8 | where they would be unlikely to have text places on them anyway. 9 | 10 | __Parameters:__ 11 | 12 | - `numeric` zoom - The Web Mercator zoom level you are considering. 13 | - `text` label - The label text that you will be placing along the line. 14 | - `geometry(linestring)` g - A line geometry. 15 | 16 | __Returns:__ `boolean` 17 | ******************************************************************************/ 18 | create or replace function LineLabel ( 19 | zoom numeric, 20 | label text, 21 | g geometry 22 | ) 23 | returns boolean 24 | language sql immutable 25 | parallel safe as 26 | $func$ 27 | SELECT CASE 28 | -- if length is 0 geom is (probably) a point; keep it 29 | WHEN zoom > 20 or ST_Length(g) = 0 THEN true 30 | ELSE length(label) between 1 and ST_Length(g)/(2^(20-zoom)) 31 | END; 32 | $func$; 33 | 34 | 35 | -------------------------------------------------------------------------------- /docker/generate-vectortiles/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024, MapTiler.com & OpenMapTiles/OSM2VectorTiles contributors. 4 | All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /sql/ZRes.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### ZRES ### 3 | 4 | Takes a web mercator zoom level and returns the pixel resolution for that 5 | scale, assuming 256x256 pixel tiles. Non-integer zoom levels are accepted. 6 | 7 | __Parameters:__ 8 | 9 | - `integer` or `float` z - A Web Mercator zoom level. 10 | 11 | __Returns:__ `float` 12 | 13 | __Examples:__ 14 | 15 | ```sql 16 | -- Delete all polygons smaller than 1px square at zoom level 10 17 | DELETE FROM water_polygons WHERE sqrt(ST_Area(geom)) < ZRes(10); 18 | 19 | -- Simplify geometries to a resolution appropriate for zoom level 10 20 | UPDATE water_polygons SET geom = ST_Simplify(geom, ZRes(10)); 21 | ``` 22 | ******************************************************************************/ 23 | create or replace function ZRes (z integer) 24 | returns float 25 | returns null on null input 26 | language sql immutable 27 | parallel safe as 28 | $func$ 29 | select (40075016.6855785/(256*2^z)); 30 | $func$; 31 | 32 | create or replace function ZRes (z float) 33 | returns float 34 | returns null on null input 35 | language sql immutable 36 | parallel safe as 37 | $func$ 38 | select (40075016.6855785/(256*2^z)); 39 | $func$; 40 | 41 | 42 | -------------------------------------------------------------------------------- /sql/TileBBox.sql: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ### TileBBox ### 3 | 4 | Given a Web Mercator tile ID as (z, x, y), returns a bounding-box 5 | geometry of the area covered by that tile. 6 | 7 | __Parameters:__ 8 | 9 | - `integer` z - A tile zoom level. 10 | - `integer` x - A tile x-position. 11 | - `integer` y - A tile y-position. 12 | - `integer` srid - SRID of the desired target projection of the bounding 13 | box. Defaults to 3857 (Web Mercator). 14 | 15 | __Returns:__ `geometry(polygon)` 16 | ******************************************************************************/ 17 | create or replace function TileBBox (z int, x int, y int, srid int = 3857) 18 | returns geometry 19 | language plpgsql immutable 20 | parallel safe as 21 | $func$ 22 | declare 23 | max numeric := 20037508.34; 24 | res numeric := (max*2)/(2^z); 25 | bbox geometry; 26 | begin 27 | bbox := ST_MakeEnvelope( 28 | -max + (x * res), 29 | max - (y * res), 30 | -max + (x * res) + res, 31 | max - (y * res) - res, 32 | 3857 33 | ); 34 | if srid = 3857 then 35 | return bbox; 36 | else 37 | return ST_Transform(bbox, srid); 38 | end if; 39 | end; 40 | $func$; 41 | 42 | 43 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v2.5.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT TileBBox($1, $2, $3) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql2/parallel/housenumber.sql: -------------------------------------------------------------------------------- 1 | DO $$ BEGIN RAISE NOTICE 'Processing layer housenumber'; END$$; 2 | 3 | -- Layer housenumber - ./housenumber_centroid.sql 4 | 5 | 6 | -- etldoc: osm_housenumber_point -> osm_housenumber_point 7 | UPDATE osm_housenumber_point SET geometry=topoint(geometry) 8 | WHERE ST_GeometryType(geometry) <> 'ST_Point'; 9 | 10 | -- Layer housenumber - ./layer.sql 11 | 12 | 13 | -- etldoc: layer_housenumber[shape=record fillcolor=lightpink, style="rounded,filled", 14 | -- etldoc: label="layer_housenumber | z14_" ] ; 15 | 16 | CREATE OR REPLACE FUNCTION layer_housenumber(bbox geometry, zoom_level integer) 17 | RETURNS TABLE(osm_id bigint, geometry geometry, housenumber text, tags hstore) AS $$ 18 | -- etldoc: osm_housenumber_point -> layer_housenumber:z14_ 19 | SELECT osm_id, geometry, housenumber, tags FROM osm_housenumber_point 20 | WHERE zoom_level >= 14 AND geometry && bbox; 21 | $$ LANGUAGE SQL IMMUTABLE; 22 | 23 | 24 | DROP MATERIALIZED VIEW IF EXISTS layer_housenumber_gen1 CASCADE; 25 | CREATE MATERIALIZED VIEW layer_housenumber_gen1 AS ( 26 | SELECT ST_Simplify(geometry, 10) AS geometry, osm_id, housenumber 27 | FROM osm_housenumber_point 28 | ) WITH NO DATA ; 29 | 30 | DO $$ BEGIN RAISE NOTICE 'Finished layer housenumber'; END$$; 31 | -------------------------------------------------------------------------------- /docker/postgis/README.md: -------------------------------------------------------------------------------- 1 | # PostGIS + OSM-specific extensions Docker image 2 | [![Docker Automated build](https://img.shields.io/docker/automated/openmaptiles/postgis.svg)]() 3 | 4 | This images is based on PostgreSQL 14 and PostGIS 3.2 [Docker image](https://hub.docker.com/r/postgis/postgis/) and includes [osml10n extension](https://github.com/openmaptiles/mapnik-german-l10n.git) - OSM-specific label manipulation support. 5 | 6 | ## Usage 7 | 8 | Run a PostgreSQL container and mount it to a persistent data directory outside. 9 | 10 | In this example we start up the container and create a database `openmaptiles` with the owner `openmaptiles` and password `openmaptiles` 11 | and mount our local directory `./data` as storage. 12 | 13 | ```bash 14 | docker run \ 15 | -v $(pwd)/data:/var/lib/postgresql/data \ 16 | -e POSTGRES_DB="openmaptiles" \ 17 | -e POSTGRES_USER="openmaptiles" \ 18 | -e POSTGRES_PASSWORD="openmaptiles" \ 19 | -d openmaptiles/postgis 20 | ``` 21 | 22 | ### Environment Variables 23 | Unlike all other OpenMapTiles repositories, this repo uses a different set of environment variables to initialize the database - `POSTGRES_*`. See (full documentation](https://hub.docker.com/_/postgres/). 24 | 25 | ## Build 26 | 27 | ```bash 28 | docker build -t openmaptiles/postgis . 29 | ``` 30 | -------------------------------------------------------------------------------- /tests/expected/imposm3.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | include: 3 | - access 4 | - int_name 5 | - loc_name 6 | - name 7 | - name:cs 8 | - name:de 9 | - name:en 10 | - wikidata 11 | - wikipedia 12 | generalized_tables: {} 13 | tables: 14 | housenumber_point: 15 | type: geometry 16 | fields: 17 | - name: osm_id 18 | type: id 19 | - name: geometry 20 | type: geometry 21 | - name: housenumber 22 | key: addr:housenumber 23 | type: string 24 | - name: tags 25 | type: hstore_tags 26 | type_mappings: 27 | points: 28 | addr:housenumber: 29 | - __any__ 30 | polygons: 31 | addr:housenumber: 32 | - __any__ 33 | peak_point: 34 | type: point 35 | columns: 36 | - name: osm_id 37 | type: id 38 | - name: geometry 39 | type: geometry 40 | - name: name 41 | key: name 42 | type: string 43 | - name: name_en 44 | key: name:en 45 | type: string 46 | - name: name_de 47 | key: name:de 48 | type: string 49 | - name: tags 50 | type: hstore_tags 51 | - name: ele 52 | key: ele 53 | type: string 54 | - name: wikipedia 55 | key: wikipedia 56 | type: string 57 | mapping: 58 | natural: 59 | - peak 60 | - volcano 61 | 62 | -------------------------------------------------------------------------------- /tests/expected/parallel_sql/parallel/housenumber.sql: -------------------------------------------------------------------------------- 1 | DO $$ BEGIN RAISE NOTICE 'Processing layer housenumber'; END$$; 2 | 3 | -- Layer housenumber - ./housenumber_centroid.sql 4 | 5 | 6 | -- etldoc: osm_housenumber_point -> osm_housenumber_point 7 | UPDATE osm_housenumber_point SET geometry=topoint(geometry) 8 | WHERE ST_GeometryType(geometry) <> 'ST_Point'; 9 | 10 | -- Layer housenumber - ./layer.sql 11 | 12 | 13 | -- etldoc: layer_housenumber[shape=record fillcolor=lightpink, style="rounded,filled", 14 | -- etldoc: label="layer_housenumber | z14_" ] ; 15 | 16 | CREATE OR REPLACE FUNCTION layer_housenumber(bbox geometry, zoom_level integer) 17 | RETURNS TABLE(osm_id bigint, geometry geometry, housenumber text, tags hstore) AS $$ 18 | -- etldoc: osm_housenumber_point -> layer_housenumber:z14_ 19 | SELECT osm_id, geometry, housenumber, tags FROM osm_housenumber_point 20 | WHERE zoom_level >= 14 AND geometry && bbox; 21 | $$ LANGUAGE SQL IMMUTABLE; 22 | 23 | 24 | DROP MATERIALIZED VIEW IF EXISTS layer_housenumber_gen1 CASCADE; 25 | CREATE MATERIALIZED VIEW layer_housenumber_gen1 AS ( 26 | SELECT ST_Simplify(geometry, 10) AS geometry, osm_id, housenumber 27 | FROM osm_housenumber_point 28 | ) /* DELAY_MATERIALIZED_VIEW_CREATION */ ; 29 | 30 | DO $$ BEGIN RAISE NOTICE 'Finished layer housenumber'; END$$; 31 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_no_feat_ids.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_TileEnvelope($1, $2, $3) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_TileEnvelope($1, $2, $3) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v3.0.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_TileEnvelope($1, $2, $3) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_gzip.sql: -------------------------------------------------------------------------------- 1 | SELECT GZIP(STRING_AGG(mvtl, '')) AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_TileEnvelope($1, $2, $3) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_gzip9.sql: -------------------------------------------------------------------------------- 1 | SELECT GZIP(STRING_AGG(mvtl, ''), 9) AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_TileEnvelope($1, $2, $3) as ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, ST_TileEnvelope($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v2.4.8.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t WHERE mvtgeometry IS NOT NULL 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT TileBBox($1, $2, $3) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t WHERE mvtgeometry IS NOT NULL 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t WHERE mvtgeometry IS NOT NULL 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v2.4.0dev-a.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT('housenumber', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t WHERE mvtgeometry IS NOT NULL 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT('enumfield', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT TileBBox($1, $2, $3) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t WHERE mvtgeometry IS NOT NULL 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT('mountain_peak', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t WHERE mvtgeometry IS NOT NULL 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v2.4.0dev.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT('housenumber', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t WHERE mvtgeometry IS NOT NULL 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT('enumfield', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT TileBBox($1, $2, $3) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t WHERE mvtgeometry IS NOT NULL 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT('mountain_peak', 4096, 'mvtgeometry', t), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t WHERE mvtgeometry IS NOT NULL 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /tests/expected/mvttile_query_v2.4.8-a.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 1252344.2714243282/2^$1) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 128, true) AS mvtgeometry, $1 AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t WHERE mvtgeometry IS NOT NULL 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT TileBBox($1, $2, $3) as ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 0, true) AS mvtgeometry, $1 AS osm_id, 'foo' AS class) AS t WHERE mvtgeometry IS NOT NULL 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(TileBBox($1, $2, $3), 10018754.171394626/2^$1) AS ST_AsMVTGeom(geometry, TileBBox($1, $2, $3), 4096, 1024, true) AS mvtgeometry, $1 AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, $1 AS ele, $1 AS ele_ft, $1 AS rank) AS t WHERE mvtgeometry IS NOT NULL 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /bin/generate-mapping-graph: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: 4 | generate-mapping-graph [] [--keep] 5 | [--format ]... 6 | generate-mapping-graph --help 7 | generate-mapping-graph --version 8 | 9 | If tileset file is given, will create one dir per layer 10 | in the output directory. 11 | If set, compares generated graphs with graphs that already 12 | exist at this location, and exit with non-zero code 13 | if they are not the same. 14 | 15 | Options: 16 | -k --keep If set, do not delete generated .dot file 17 | -f --format Specify which format(s) to output. [default: png] 18 | --help Show this screen. 19 | --version Show version. 20 | """ 21 | 22 | from docopt import docopt 23 | 24 | import openmaptiles 25 | from openmaptiles.diagram import MappingGraph 26 | 27 | 28 | def main(args): 29 | exit(MappingGraph( 30 | args[''], 31 | args[''], 32 | args[''], 33 | not args['--keep'], 34 | args['--format'], 35 | ).run()) 36 | 37 | 38 | if __name__ == '__main__': 39 | main(docopt(__doc__, version=openmaptiles.__version__)) 40 | -------------------------------------------------------------------------------- /tests/expected/mvttile_psql.sql: -------------------------------------------------------------------------------- 1 | SELECT STRING_AGG(mvtl, '') AS mvt FROM ( 2 | SELECT COALESCE(ST_AsMVT(t, 'housenumber', 4096, 'mvtgeometry'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope(:zoom, :x, :y), 1252344.2714243282/2^:zoom) as ST_AsMVTGeom(geometry, ST_TileEnvelope(:zoom, :x, :y), 4096, 128, true) AS mvtgeometry, :zoom AS housenumber, NULLIF(tags->'name:en', '') AS "name:en", NULLIF(tags->'name:de', '') AS "name:de", NULLIF(tags->'name:cs', '') AS "name:cs", NULLIF(tags->'name_int', '') AS "name_int", NULLIF(tags->'name:latin', '') AS "name:latin", NULLIF(tags->'name:nonlatin', '') AS "name:nonlatin" FROM (SELECT 'name:en=>"enname"'::hstore as tags) AS tt) AS t 3 | UNION ALL 4 | SELECT COALESCE(ST_AsMVT(t, 'enumfield', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_TileEnvelope(:zoom, :x, :y) as ST_AsMVTGeom(geometry, ST_TileEnvelope(:zoom, :x, :y), 4096, 0, true) AS mvtgeometry, :zoom AS osm_id, 'foo' AS class) AS t 5 | UNION ALL 6 | SELECT COALESCE(ST_AsMVT(t, 'mountain_peak', 4096, 'mvtgeometry', 'osm_id'), '') as mvtl FROM (SELECT ST_Expand(ST_TileEnvelope(:zoom, :x, :y), 10018754.171394626/2^:zoom) AS ST_AsMVTGeom(geometry, ST_TileEnvelope(:zoom, :x, :y), 4096, 1024, true) AS mvtgeometry, :zoom AS osm_id, 'foo_name' AS name, 'foo_name_en' AS name_en, 'foo_name_de' AS name_de, 'foo_class' AS class, :zoom AS ele, :zoom AS ele_ft, :zoom AS rank) AS t 7 | ) AS all_layers 8 | 9 | -------------------------------------------------------------------------------- /bin/style-tools: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: 4 | style-tools split