├── .gitignore ├── .gitlab-ci.yml ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README-DOCKER.md ├── README-MANUAL.md ├── README.md ├── db ├── TEST-REDUCTIONS.sql ├── data │ ├── layer_definitions.sql │ ├── routable.sql │ └── thematic_road.sql ├── deploy │ ├── 001.sql │ ├── 002.sql │ ├── 003.sql │ └── 004.sql ├── revert │ ├── 001.sql │ ├── 002.sql │ ├── 003.sql │ └── 004.sql ├── sqitch.conf ├── sqitch.plan ├── style │ ├── README.md │ ├── create_layer_styles.sql │ └── layer_styles_defaults.sql └── verify │ ├── 001.sql │ ├── 002.sql │ ├── 003.sql │ └── 004.sql ├── docker └── run_pgosm_subregion.sh ├── docs ├── Makefile ├── conf.py ├── index.rst └── make.bat ├── flex-config ├── README.md ├── building.lua ├── building.sql ├── natural.lua ├── natural.sql ├── road.lua ├── road.sql ├── road_major.lua ├── road_major.sql ├── run-all.lua ├── traffic.lua └── unitable.lua ├── pgosm ├── __init__.py ├── config.py ├── db.py ├── file_manager.py ├── layers.py └── travel_time_grid.py ├── requirements.txt ├── tests ├── README.md ├── __init__.py └── pgosm_file_manager_test.py └── travel_time_grid.md /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | docs/_build 3 | pgosm/__pycache__/ 4 | tests/__pycache__/ 5 | output/create_pgosm_layers.sql 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | stages: 4 | - build 5 | - verify 6 | - code_quality 7 | 8 | 9 | before_script: 10 | - python3.7 -V 11 | 12 | 13 | install_venv: 14 | stage: build 15 | script: 16 | - python3.7 -m venv venv 17 | - source venv/bin/activate 18 | - python -V 19 | - pip install --upgrade pip 20 | - pip install -r requirements.txt 21 | artifacts: 22 | paths: 23 | - venv/ 24 | 25 | 26 | #install_db: 27 | # stage: build 28 | # script: 29 | # - sqitch deploy db:pg://your_db_user@localhost/pgosm 30 | 31 | 32 | 33 | run_junit_test: 34 | stage: verify 35 | script: 36 | - source venv/bin/activate 37 | - python -V 38 | - python -m pytest --junitxml=pytest.xml tests/ 39 | artifacts: 40 | paths: 41 | - pytest.xml 42 | reports: 43 | junit: pytest.xml 44 | allow_failure: true 45 | 46 | 47 | run_coverage: 48 | stage: code_quality 49 | script: 50 | - source venv/bin/activate 51 | - python -V 52 | - coverage run -m unittest tests/*.py 53 | - coverage report -m pgosm/*.py 54 | - coverage xml --include="pgosm/*.py" -o coverage.xml 55 | artifacts: 56 | paths: 57 | - coverage.xml 58 | reports: 59 | metrics: coverage.xml 60 | allow_failure: true 61 | 62 | 63 | pip_check_outdated: 64 | stage: code_quality 65 | script: 66 | - source venv/bin/activate 67 | - python -V 68 | - pip list --outdated > pip_outdated_packages.log 69 | artifacts: 70 | paths: 71 | - pip_outdated_packages.log 72 | 73 | 74 | ... -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We encourage pull requests from everyone. 4 | 5 | You should fork the project into your own repo, create a topic branch there and then make one or more pull requests back to the RustProof Labs repository. Your pull requests will then be reviewed and discussed. 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgis/postgis:13-3.0 2 | 3 | LABEL maintainer="PgOSM Project - https://github.com/rustprooflabs/pgosm" 4 | 5 | RUN apt-get update \ 6 | && apt-get install -y --no-install-recommends \ 7 | sqitch wget ca-certificates \ 8 | git make cmake g++ \ 9 | libboost-dev libboost-system-dev \ 10 | libboost-filesystem-dev libexpat1-dev zlib1g-dev \ 11 | libbz2-dev libpq-dev libproj-dev lua5.2 liblua5.2-dev \ 12 | python3.7 python3-pip python3-psycopg2 \ 13 | && rm -rf /var/lib/apt/lists/* 14 | 15 | 16 | WORKDIR /tmp 17 | RUN git clone git://github.com/openstreetmap/osm2pgsql.git \ 18 | && mkdir osm2pgsql/build \ 19 | && cd osm2pgsql/build \ 20 | && cmake .. \ 21 | && make \ 22 | && make install \ 23 | && apt remove -y \ 24 | git make cmake g++ \ 25 | libboost-dev libboost-system-dev \ 26 | libboost-filesystem-dev libexpat1-dev zlib1g-dev \ 27 | libbz2-dev libpq-dev libproj-dev \ 28 | && apt autoremove -y \ 29 | && cd /tmp && rm -r /tmp/osm2pgsql 30 | 31 | 32 | WORKDIR /app 33 | COPY . ./ 34 | RUN pip3 install setuptools \ 35 | && pip3 install -r requirements.txt 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2020 Ryan Lambert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README-DOCKER.md: -------------------------------------------------------------------------------- 1 | # PgOSM Docker 2 | 3 | Notes covering Docker and generating image for Docker Hub. 4 | 5 | Uses [main Postgres image](https://hub.docker.com/_/postgres/) via the [main PostGIS image](https://hub.docker.com/r/postgis/postgis) as starting point, see that 6 | repo for full instructions on using the core Postgres functionality. 7 | 8 | Build latest. 9 | 10 | ``` 11 | docker build -t rustprooflabs/pgosm . 12 | ``` 13 | 14 | 15 | Tag with Pg version. 16 | 17 | ``` 18 | docker build -t rustprooflabs/pgosm:pg13 . 19 | ``` 20 | 21 | > Note: Update the Dockerfile to build with non-default Postgres/PostGIS version. 22 | 23 | Push to Dockerhub 24 | 25 | ``` 26 | docker push rustprooflabs/pgosm:pg12 27 | docker push rustprooflabs/pgosm:pg13 28 | docker push rustprooflabs/pgosm:latest 29 | ``` 30 | -------------------------------------------------------------------------------- /README-MANUAL.md: -------------------------------------------------------------------------------- 1 | # Using PgOSM - Non-Docker 2 | 3 | If you want to install and configure osm2pgsql and PgOSM manually, follow these 4 | instructions. The [recommended method](README.md) to run this for most users is to use the Docker 5 | image. 6 | 7 | 8 | The manuall process overview looks like this: 9 | 10 | * Download OSM PBF file 11 | * `osm2pgsql` loads PBF -> Postgres 12 | * `pgosm` converts into user-defined layer tables 13 | * Enjoy! 14 | 15 | ## Prereqs 16 | 17 | * PostgreSQL 18 | * PostGIS 19 | * osm2pgsql 1.2 20 | * Python 3.7+ 21 | 22 | This guide is written for Debian/Ubuntu variants of Linux. 23 | 24 | ## Load data via osm2psql 25 | 26 | Start by loading the OpenStreetMap data to Postgres/PostGIS. 27 | The RustProof Labs blog has a post explaining how to 28 | [load an OpenStreetMap PBF to PostGIS](https://blog.rustprooflabs.com/2020/01/postgis-osm-load-2020) using [osm2pgsql](https://github.com/openstreetmap/osm2pgsql). 29 | 30 | ## Clone and setup PgOSM 31 | 32 | Switch to the `postgres` user and clone the PgOSM repo. 33 | 34 | sudo su - postgres 35 | mkdir ~/git 36 | cd ~/git 37 | git clone https://github.com/rustprooflabs/pgosm.git 38 | 39 | ## Deploy schema and define layers 40 | 41 | Deploying the table structure is done via [sqitch](https://sqitch.org/). 42 | 43 | cd ~/git/pgosm/db 44 | sqitch deploy db:pg:pgosm 45 | 46 | 47 | Load included layer groupings: 48 | 49 | psql -d pgosm -f ~/git/pgosm/db/data/layer_definitions.sql 50 | psql -d pgosm -f ~/git/pgosm/db/data/thematic_road.sql 51 | 52 | 53 | Load included routable roads definitions (optional). 54 | 55 | psql -d pgosm -f ~/git/pgosm/db/data/routable.sql 56 | 57 | 58 | ## Setup Python environment 59 | 60 | The PgOSM transformations are processed using Python. The Python program 61 | reads the data loaded in the prior step to generate the SQL code 62 | to transform the OpenStreetMap data structure. 63 | 64 | Create a `pgosm` virtual environment for Python and install the required modules. 65 | 66 | mkdir ~/venv 67 | cd ~/venv 68 | python3.8 -m venv pgosm 69 | source ~/venv/pgosm/bin/activate 70 | pip install -r ~/git/pgosm/requirements.txt 71 | 72 | > Note: On `linux/arm64` architecture (e.g. Raspberry Pi) you may need to use `pip install Cython numpy` before installing the `requirements.txt` file. 73 | 74 | 75 | Create the folder for the generated SQL statements . 76 | 77 | mkdir ~/git/pgosm/output 78 | 79 | 80 | ### Env vars 81 | 82 | The Python portion of the process needs to build a connection string to connect to the data and apply the 83 | transformations. Set these appropriately to connect to your `pgosm` database. 84 | 85 | export DB_HOST=localhost 86 | export DB_NAME=pgosm 87 | export DB_USER=your_db_user 88 | 89 | The above assumes you have a password setup in `~/.pgpass`. If you can't do that (or don't want 90 | to) you can define the `DB_PW` variable. 91 | 92 | export DB_PW=NonyaBusine$s 93 | 94 | 95 | ## Run PgOSM 96 | 97 | It's time to run the transformation! These commands ensure the virtual environment is active and 98 | runs the process via Python. 99 | 100 | source ~/venv/pgosm/bin/activate 101 | cd ~/git/pgosm 102 | python -c "import pgosm; pgosm.process_layers();" 103 | 104 | Output should look similar to the following snippet. 105 | 106 | 107 | DB Password not set. Will attempt to use ~/.pgpass. 108 | DB Port not set. Defaulting to 5432 109 | Output Path: output/create_pgosm_layers.sql 110 | Starting processing. 111 | 26 layers returned 112 | Processing layer place (layer_group_id=1). 113 | Processing layer boundary (layer_group_id=2). 114 | Processing layer admin_area (layer_group_id=3). 115 | ... 116 | Processing layer waterway (layer_group_id=23). 117 | Processing layer water (layer_group_id=24). 118 | Processing layer coastline (layer_group_id=25). 119 | Processing layer t_road (layer_group_id=26). 120 | Executing SQL Script... 121 | Executing SQL Script completed. 122 | Finished processing. Total time elapsed: 90.7 seconds. 123 | 124 | The `pgosm` database now has a new schema named `osm` with the transformed 125 | OpenStreetMap tables. 126 | 127 | ## Variations 128 | 129 | 130 | Use the optional `schema` parameter (i.e. `pgosm.process_layers(schema='osm_co')`) to override the default `osm` schema name. 131 | 132 | 133 | Use the optional `generate_only` parameter 134 | (i.e. `pgosm.process_layers(generate_only=True)`) to generate the SQL script 135 | for the transformations, but not run it. 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :warning: Use PgOSM Flex instead! :warning: 2 | 3 | 4 | This project is obsolete and unmaintained! Use [the PgOSM Flex project](https://github.com/rustprooflabs/pgosm-flex) instead 5 | 6 | ---- 7 | 8 | 9 | # PgOSM: Making PostGIS + OpenStreetMap easier! 10 | 11 | The goal of `PgOSM` is to make it simpler to load an OpenStreetMap `.pbf` file into PostGIS. The resulting data structure provides spatial analysts easier access to open-source spatial data. One focus of this project is to be easy to setup and run on low-power (e.g. non-server) hardware. The target machine for this process is a virtual machine within a consumer-grade laptop given 1GB ram and a single core processor. 12 | 13 | See included `LICENSE` file for more details about licensing. 14 | 15 | 16 | 17 | ## PgOSM via Docker 18 | 19 | 20 | PgOSM is easiest deployed using the Docker image from [Docker Hub](https://hub.docker.com/r/rustprooflabs/pgosm). To use PgOSM without Docker, see the [manual instructions (README-MANUAL.md)](README-MANUAL.md). 21 | 22 | 23 | Create folder for the output (``~/pgosm-data``), 24 | this stores the generated SQL file used to perform the PgOSM transformations and the 25 | output file from ``pg_dump`` containing the ``osm`` and ``pgosm`` schemas to load into a production database. 26 | The ``.osm.pbf`` file and associated ``md5``are saved here. Custom templates, and custom OSM file inputs can be stored here. 27 | 28 | 29 | ``` 30 | mkdir ~/pgosm-data 31 | mkdir ~/pgosm-input 32 | ``` 33 | 34 | To run custom transformations, place the SQL for the 35 | setup into `~/pgosm-input`. The following command adds the included `thematic_road` 36 | transformation into the processing queue, thus into the 37 | SQL output at the end. 38 | 39 | *(Optional)* 40 | 41 | ``` 42 | cp ~/git/pgosm/db/data/thematic_road.sql ~/pgosm-input/ 43 | ``` 44 | 45 | To skip the default transformations, place a `skip_default` file into `~/pgosm-input`. 46 | 47 | *(Optional)* 48 | 49 | ``` 50 | touch ~/pgosm-input/skip_default 51 | ``` 52 | 53 | Start the `pgosm` container to make PostgreSQL/PostGIS available. This command exposes Postgres inside Docker on port 5433 and establishes links to local directories. 54 | 55 | ``` 56 | docker run --name pgosm -d \ 57 | -v ~/pgosm-data:/app/output \ 58 | -v ~/pgosm-input:/app/db/data/custom \ 59 | -e POSTGRES_PASSWORD=mysecretpassword \ 60 | -p 5433:5432 -d rustprooflabs/pgosm 61 | ``` 62 | 63 | 64 | Run the PgOSM Sub-region processing. Using the Washington D.C. sub-region is great 65 | for testing, it runs fast even on the smallest hardware. 66 | 67 | ``` 68 | docker exec -it \ 69 | -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_USER=postgres \ 70 | -e PGOSM_SCHEMA=osm_dc \ 71 | pgosm bash docker/run_pgosm_subregion.sh \ 72 | north-america/us \ 73 | district-of-columbia \ 74 | 400 75 | ``` 76 | 77 | > Skip the PgOSM processing entirely with a `skip_default` file and no custom files. This is helpful for developing custom transformations. 78 | 79 | ## Always download 80 | 81 | To force the processing to remove existing files and re-download the latest PBF and MD5 files from Geofabrik, set the `PGOSM_ALWAYS_DOWNLOAD` env var when running the Docker 82 | container. 83 | 84 | ``` 85 | docker run --name pgosm -d \ 86 | -v ~/pgosm-data:/app/output \ 87 | -v ~/pgosm-input:/app/db/data/custom \ 88 | -e POSTGRES_PASSWORD=mysecretpassword \ 89 | -e PGOSM_ALWAYS_DOWNLOAD=1 \ 90 | -p 5433:5432 -d rustprooflabs/pgosm 91 | ``` 92 | 93 | ---- 94 | 95 | ## Why use PgOSM? 96 | 97 | ### Before PgOSM 98 | 99 | When data is loaded from `osm2pgsql` into your database you're left with a set of three (3) `planet_osm_*` tables split based on type of geometry, not by type of data. 100 | 101 | * `public.planet_osm_point` 102 | * `public.planet_osm_line` 103 | * `public.planet_osm_polygon` 104 | 105 | This means that all the data representing waterways are found in the table `public.planet_osm_line`. So are all the roads, sidewalks, rivers, railways, and administrative boundaries. This setup makes it impossible for an analyst used to a properly normalized relational database to simply connect to the database and be productive. 106 | 107 | ### After PgOSM 108 | 109 | When `pgosm` runs it creates a schema named `osm` and loads layer-specific data into each table. The current default configuration generates 43 tables of logically grouped data. A few examples: 110 | 111 | * `osm.road_line` 112 | * `osm.natural_point` 113 | * `osm.building_polygon` 114 | * `osm.waterway_line` 115 | 116 | The `natural_point` layer, for example, contains trees, peaks, and other items with [nature-related tags](https://wiki.openstreetmap.org/wiki/Key:natural) in OpenStreetMap. 117 | 118 | 119 | ## QGIS Layer Styles 120 | 121 | See [the QGIS styles](./db/style/README.md) README for details. 122 | 123 | -------------------------------------------------------------------------------- /db/TEST-REDUCTIONS.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE TABLE osm.road_type 3 | ( 4 | road_type TEXT NOT NULL, 5 | road_type_display TEXT NOT NULL, 6 | CONSTRAINT PK_osm_road_type PRIMARY KEY (road_type) 7 | ); 8 | 9 | COMMENT ON TABLE osm.road_type IS 'Descriptor/Roll-up table for osm.road_line highway types.'; 10 | COMMENT ON COLUMN osm.road_type.road_type_display IS 'Rollup value to reduce number of categories for thematic formatting.'; 11 | 12 | 13 | INSERT INTO osm.road_type (road_type, road_type_display) 14 | VALUES ('abandoned', 'foot'), ('bridleway', 'foot'), ('construction', 'minor'), 15 | ('cycleway', 'unknown'), ('disused', 'unknown'), ('escape', 'unknown'), ('footway', 'foot'), 16 | ('living_street', 'minor'), ('motorway', 'primary'), ('motorway_link', 'primary'), 17 | ('passing_place', 'unknown'), ('path', 'foot'), ('pedestrian', 'foot'), ('primary', 'primary'), 18 | ('primary_link', 'primary'), ('proposed', 'unknown'), ('raceway', 'minor'), ('rest_area', 'minor'), 19 | ('road', 'minor'), ('secondary', 'secondary'), 20 | ('secondary_link', 'secondary'), ('service', 'minor'), ('steps', 'foot'), 21 | ('tertiary', 'secondary'), ('tertiary_link', 'secondary'), ('track', 'foot'), 22 | ('trunk', 'primary'), ('trunk_link', 'primary'), ('unclassified', 'unknown'), 23 | ('yes', 'unknown'), ('residential', 'minor') 24 | ; 25 | 26 | 27 | 28 | -- DROP TABLE osm_co.road_line_main_thematic; 29 | CREATE TABLE osm_co.road_line_main_thematic AS 30 | SELECT row_number() OVER () AS gid, r.name, r.ref, rt.road_type_display, 31 | ST_Simplify(ST_Collect(r.way), 10) AS way 32 | FROM osm_co.road_line r 33 | INNER JOIN osm.road_type rt ON r.highway = rt.road_type 34 | WHERE rt.road_type_display IN ('primary', 'secondary') 35 | GROUP BY r.name, r.ref, rt.road_type_display 36 | ; 37 | 38 | CREATE INDEX gix_osm_road_line_main_thematic ON osm_co.road_line_main_thematic 39 | USING GIST (way); 40 | 41 | 42 | -------------------------------------------- 43 | 44 | CREATE TABLE osm_co.boundary_county AS 45 | SELECT osm_id, name, code, boundary, ST_Simplify(way, 10) AS way 46 | FROM osm.boundaries_polygon 47 | WHERE code = '1106' 48 | ; 49 | 50 | CREATE INDEX gix_osm_boundary_county_thematic ON osm_co.boundary_county 51 | USING GIST (way); 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /db/data/layer_definitions.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('1000','1099','place','osm_id, name, place, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 5 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('1100','1199','boundary','osm_id, name, admin_level, boundary, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Administrative boundaries, roughly follows https://wiki.openstreetmap.org/wiki/Tag%3aboundary=administrative'); 6 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('1200','1299','admin_area','osm_id, name, admin_level, boundary, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 7 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('1500','1599','building','osm_id, "addr:housename" AS housename, "addr:housenumber" AS housenumber, building, name, place, COALESCE(tags -> ''building:levels'', ''1'') AS levels, regexp_replace(COALESCE(tags -> ''building:height'', ''4''), ''[^0-9\.]+'', '''', ''g'')::NUMERIC AS height, operator, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 8 | 9 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('1600','1699','indoor','osm_id, name, ref, COALESCE(tags -> ''indoor'', ''area'') AS indoor, area, COALESCE(tags -> ''room'', '''') AS room, amenity, COALESCE(tags -> ''level'', ''1'') AS level, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Indoor areas, typically within buildings. Roughly conforms to https://wiki.openstreetmap.org/wiki/Simple_Indoor_Tagging'); 10 | 11 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2000','2099','public','osm_id, name, amenity, landuse, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','government offices, post office, police, etc.'); 12 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2100','2199','health','osm_id, name, amenity, landuse, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Hospitals, pharmacies'); 13 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2200','2299','leisure','osm_id, name, amenity, landuse, leisure, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 14 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2300','2399','food','osm_id, name, amenity, tags -> ''cuisine'' AS cuisine, tags -> ''takeaway'' AS takeaway, tags -> ''capacity'' AS capacity, tags -> ''opening_hours'' AS opening_hours, tags -> ''outdoor_seating'' AS outdoor_seating, "addr:housename" AS housename, "addr:housenumber" AS housenumber, tags -> ''addr:street'' AS street, tags -> ''addr:unit'' AS addr_unit, tags -> ''addr:suite'' AS addr_suite, COALESCE(tags -> ''website'', tags -> ''contact:website'', tags -> ''url'', '''') AS website, COALESCE(tags -> ''email'', tags -> ''contact:email'', '''') AS email, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Restaurants, pubs, cafes'); 15 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2400','2499','accomodation','osm_id, name, landuse, leisure, tourism, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Hotel, motel, etc.'); 16 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2500','2599','shopping','osm_id, name, shop, amenity, tags -> ''vending'' AS vending, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 17 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2600','2899','tourism','osm_id, name, tourism, amenity, tags -> ''information'' AS information, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','I am not so sure about this range….'); 18 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('2900','2999','miscpoi','osm_id, name, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 19 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('3000','3999','pofw','osm_id, name, religion, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way','Place of Worship'); 20 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('4100','4199','natural','osm_id, name, "natural", tags -> ''ele'' AS elevation, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 21 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('5000','5099','transport','osm_id, name, tags -> ''traffic'' AS traffic, highway, ref, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 22 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('5100','5199','road','osm_id, name, tags -> ''traffic'' AS traffic, highway, ref, REPLACE(tags -> ''maxspeed'', '' mph'', '''') AS maxspeed, oneway, tracktype, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 23 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('5200','5299','traffic','osm_id, name, tags -> ''traffic'' AS traffic, highway, ref, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 24 | 25 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('6100','6199','railway','osm_id, name, tags -> ''traffic'' AS traffic, highway, ref, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 26 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('6400','6499','power','osm_id, name, power, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 27 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('6500','6599','powerline','osm_id, name, power, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 28 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('7200','7299','landuse','osm_id, name, landuse, "natural", leisure, boundary, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 29 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('8100','8199','waterway','osm_id, name, waterway, "natural", landuse, tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 30 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('8200','8299','water','osm_id, name, waterway, "natural", landuse,tags, CASE WHEN osm_id < 0 THEN ''https://www.openstreetmap.org/relation/'' || (@ osm_id)::TEXT ELSE ''https://www.openstreetmap.org/way/'' || osm_id::TEXT END AS osm_url, way',''); 31 | INSERT INTO pgosm.layer_group (code_start, code_end, class, osm_columns, description) VALUES ('8300','8399','coastline','',''); 32 | 33 | 34 | 35 | --------------------------------------------------------------- 36 | --------------------------------------------------------------- 37 | --------------------------------------------------------------- 38 | 39 | 40 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1001','city','TRUE','FALSE','TRUE','place=''city''','Largest urban areas. See also 1005'); 41 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1002','town','TRUE','FALSE','TRUE','place=''town''',''); 42 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1003','village','TRUE','FALSE','TRUE','place=''village''',''); 43 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1004','hamlet','TRUE','FALSE','TRUE','place=''hamlet''',''); 44 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1005','national_capital','TRUE','FALSE','TRUE','place=''city'' AND (tags -> ''is_capital''=''country'' OR admin_level=''2'' OR (tags -> ''capital''=''yes'' and admin_level IS NULL))',''); 45 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1010','suburb','TRUE','FALSE','TRUE','place=''suburb''',''); 46 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1020','island','TRUE','FALSE','TRUE','place=''island''',''); 47 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1030','farm','TRUE','FALSE','TRUE','place=''farm''',''); 48 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1031','dwelling','TRUE','FALSE','TRUE','place=''isolated_dwelling''',''); 49 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1040','region','TRUE','FALSE','TRUE','place=''region''',''); 50 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1041','county','TRUE','FALSE','TRUE','place=''county''',''); 51 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1050','locality','TRUE','FALSE','TRUE','place=''locality''',''); 52 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1099','named_place','TRUE','FALSE','TRUE','name IS NOT NULL','Includes all named objects. Duplicates a large number of objects found in other, more specific subclasses.'); 53 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1101','admin_level1','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''1''','Unknown/unused'); 54 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1102','admin_level2','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''2''','National Border'); 55 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1103','admin_level3','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''3''',''); 56 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1104','admin_level4','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''4''','U.S. State, Commonwealths, and similar'); 57 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1105','admin_level5','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''5''','New York City (unique in USA as an agglomerate of multiple county equivalents)'); 58 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1106','admin_level6','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''6''','U.S. County and similar'); 59 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1107','admin_level7','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''7''','Civil townships'); 60 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1108','admin_level8','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''8''','City, borough, town, village'); 61 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1109','admin_level9','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''9''','Wards (rare)'); 62 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1110','admin_level10','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''10''','Neighborhoods'); 63 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1111','admin_level11','FALSE','TRUE','TRUE','boundary=''administrative'' AND admin_level=''11''','Non-U.S. usages.'); 64 | 65 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1500','building','FALSE','FALSE','TRUE','building IS NOT NULL','All building polygon objects.'); 66 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1551','entrance','TRUE','FALSE','FALSE','building = ''entrance'' OR (tags -> ''entrance'' IN (''main'',''yes'' ))','Building entrances.'); 67 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1552','exit','TRUE','FALSE','FALSE','building = ''exit''','Building exits.'); 68 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1553','emergency_exit','TRUE','FALSE','FALSE','tags -> ''entrance'' = ''emergency''','Building emergency exits.'); 69 | 70 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1600', 'area','FALSE','FALSE','TRUE', ' tags -> ''indoor'' = ''area''',''); 71 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1601', 'door','TRUE','FALSE','FALSE', ' tags -> ''indoor'' = ''door''',''); 72 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1602', 'wall','FALSE','TRUE','TRUE', ' tags -> ''indoor'' = ''wall''',''); 73 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1603', 'corridor','FALSE','FALSE','TRUE', ' tags -> ''indoor'' = ''corridor''',''); 74 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1610', 'room','FALSE','FALSE','TRUE', ' tags -> ''indoor'' = ''room''',''); 75 | 76 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2001','police','TRUE','FALSE','TRUE','amenity=''police''',''); 77 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2002','fire_station','TRUE','FALSE','TRUE','amenity=''fire_station''',''); 78 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2004','post_box','TRUE','FALSE','TRUE','amenity=''post_box''',''); 79 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2005','post_office','TRUE','FALSE','TRUE','amenity=''post_office''',''); 80 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2006','telephone','TRUE','FALSE','TRUE','amenity=''telephone''',''); 81 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2007','library','TRUE','FALSE','TRUE','amenity=''library''',''); 82 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2008','town_hall','TRUE','FALSE','TRUE','amenity=''townhall''',''); 83 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2009','courthouse','TRUE','FALSE','TRUE','amenity=''courthouse''',''); 84 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2010','prison','TRUE','FALSE','TRUE','amenity=''prison''',''); 85 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2011','embassy','TRUE','FALSE','TRUE','amenity=''embassy''',''); 86 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2012','community_centre','TRUE','FALSE','TRUE','amenity=''community_centre''',''); 87 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2013','nursing_home','TRUE','FALSE','TRUE','amenity=''nursing_home''',''); 88 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2014','arts_centre','TRUE','FALSE','TRUE','amenity=''arts_centre''',''); 89 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2015','graveyard','TRUE','FALSE','TRUE','amenity=''grave_yard'' OR landuse=''cemetery''',''); 90 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2016','market_place','TRUE','FALSE','TRUE','amenity=''market_place''',''); 91 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2030','recycling','TRUE','FALSE','TRUE','amenity=''recycling'' AND tags -> ''recycling:glass'' <> ''yes'' AND tags -> ''recycling:paper'' <> ''yes'' AND tags -> ''recycling:clothes'' <> ''yes''',''); 92 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2031','recycling_glass','TRUE','FALSE','TRUE','tags -> ''recycling:glass''=''yes''',''); 93 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2032','recycling_paper','TRUE','FALSE','TRUE','tags -> ''recycling:paper''=''yes''',''); 94 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2033','recycling_clothes','TRUE','FALSE','TRUE','tags -> ''recycling:clothes''=''yes''',''); 95 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2081','university','TRUE','FALSE','TRUE','amenity=''university''',''); 96 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2082','school','TRUE','FALSE','TRUE','amenity=''school''',''); 97 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2083','kindergarten','TRUE','FALSE','TRUE','amenity=''kindergarten''',''); 98 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2084','college','TRUE','FALSE','TRUE','amenity=''college''',''); 99 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2099','public_building','TRUE','FALSE','TRUE','amenity=''public_building''',''); 100 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2101','pharmacy','TRUE','FALSE','TRUE','amenity=''pharmacy''',''); 101 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2110','hospital','TRUE','FALSE','TRUE','amenity=''hospital''',''); 102 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2120','doctors','TRUE','FALSE','TRUE','amenity=''doctors''',''); 103 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2121','dentist','TRUE','FALSE','TRUE','amenity=''dentist''',''); 104 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2129','veterinary','TRUE','FALSE','TRUE','amenity=''veterinary''',''); 105 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2201','theatre','TRUE','FALSE','TRUE','amenity=''theatre''',''); 106 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2202','nightclub','TRUE','FALSE','TRUE','amenity=''nightclub''',''); 107 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2203','cinema','TRUE','FALSE','TRUE','amenity=''cinema''',''); 108 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2204','park','TRUE','FALSE','TRUE','leisure=''park''',''); 109 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2205','playground','TRUE','FALSE','TRUE','leisure=''playground''',''); 110 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2206','dog_park','TRUE','FALSE','TRUE','leisure=''dog_park''',''); 111 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2251','sports_centre','TRUE','FALSE','TRUE','leisure=''sports_centre''',''); 112 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2252','pitch','TRUE','FALSE','TRUE','leisure=''pitch''',''); 113 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2253','swimming_pool','TRUE','FALSE','TRUE','amenity=''swimming_pool'' OR leisure=''swimming_pool'' OR leisure=''water_park''',''); 114 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2255','golf_course','TRUE','FALSE','TRUE','leisure=''golf_course''',''); 115 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2256','stadium','TRUE','FALSE','TRUE','leisure=''stadium''',''); 116 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2257','ice_rink','TRUE','FALSE','TRUE','leisure=''ice_rink''',''); 117 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2301','restaurant','TRUE','FALSE','TRUE','amenity=''restaurant''',''); 118 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2302','fast_food','TRUE','FALSE','TRUE','amenity=''fast_food''',''); 119 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2303','café','TRUE','FALSE','TRUE','amenity=''cafe''',''); 120 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2304','pub','TRUE','FALSE','TRUE','amenity=''pub''',''); 121 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2305','bar','TRUE','FALSE','TRUE','amenity=''bar''',''); 122 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2306','food_court','TRUE','FALSE','TRUE','amenity=''food_court''',''); 123 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2307','biergarten','TRUE','FALSE','TRUE','amenity=''biergarten''',''); 124 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2308','bbq','TRUE','FALSE','TRUE','amenity=''bbq''',''); 125 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2310','ice_cream','TRUE','FALSE','TRUE','amenity=''ice_cream'' ',''); 126 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2311','catering','TRUE','FALSE','TRUE','amenity=''catering'' ',''); 127 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2401','hotel','TRUE','FALSE','TRUE','tourism=''hotel''',''); 128 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2402','motel','TRUE','FALSE','TRUE','tourism=''motel''',''); 129 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2403','bed_and_breakfast','TRUE','FALSE','TRUE','tourism=''bed_and_breakfast''',''); 130 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2404','guesthouse','TRUE','FALSE','TRUE','tourism=''guest_house''',''); 131 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2405','hostel','TRUE','FALSE','TRUE','tourism=''hostel''',''); 132 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2406','chalet','TRUE','FALSE','TRUE','tourism=''chalet''',''); 133 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2421','shelter','TRUE','FALSE','TRUE','amenity=''shelter''',''); 134 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2422','camp_site','TRUE','FALSE','TRUE','tourism=''camp_site''',''); 135 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2423','alpine_hut','TRUE','FALSE','TRUE','tourism=''alpine_hut''',''); 136 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2424','caravan_site','TRUE','FALSE','TRUE','tourism=''caravan_site''',''); 137 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2501','supermarket','TRUE','FALSE','TRUE','shop=''supermarket''',''); 138 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2502','bakery','TRUE','FALSE','TRUE','shop=''bakery''',''); 139 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2503','kiosk','TRUE','FALSE','TRUE','shop=''kiosk''',''); 140 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2504','mall','TRUE','FALSE','TRUE','shop=''mall''',''); 141 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2505','department_store','TRUE','FALSE','TRUE','shop=''department_store''',''); 142 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2511','convenience','TRUE','FALSE','TRUE','shop=''convenience''',''); 143 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2512','clothes','TRUE','FALSE','TRUE','shop=''clothes''',''); 144 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2513','florist','TRUE','FALSE','TRUE','shop=''florist''',''); 145 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2514','chemist','TRUE','FALSE','TRUE','shop=''chemist''',''); 146 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2515','bookshop','TRUE','FALSE','TRUE','shop=''books''',''); 147 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2516','butcher','TRUE','FALSE','TRUE','shop=''butcher''',''); 148 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2517','shoe_shop','TRUE','FALSE','TRUE','shop=''shoes''',''); 149 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2518','beverages','TRUE','FALSE','TRUE','shop=''alcohol'' OR shop=''beverages''',''); 150 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2519','optician','TRUE','FALSE','TRUE','shop=''optician''',''); 151 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2520','jeweller','TRUE','FALSE','TRUE','shop=''jewelry''',''); 152 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2521','gift_shop','TRUE','FALSE','TRUE','shop=''gift''',''); 153 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2522','sports_shop','TRUE','FALSE','TRUE','shop=''sports''',''); 154 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2523','stationery','TRUE','FALSE','TRUE','shop=''stationery''',''); 155 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2524','outdoor_shop','TRUE','FALSE','TRUE','shop=''outdoor''',''); 156 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2525','mobile_phone_shop','TRUE','FALSE','TRUE','shop=''mobile_phone''',''); 157 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2526','toy_shop','TRUE','FALSE','TRUE','shop=''toys''',''); 158 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2527','newsagent','TRUE','FALSE','TRUE','shop=''newsagent''',''); 159 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2528','greengrocer','TRUE','FALSE','TRUE','shop=''greengrocer''',''); 160 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2529','beauty_shop','TRUE','FALSE','TRUE','shop=''beauty''',''); 161 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2530','video_shop','TRUE','FALSE','TRUE','shop=''video''',''); 162 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2541','car_dealership','TRUE','FALSE','TRUE','shop=''car''',''); 163 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2542','bicycle_shop','TRUE','FALSE','TRUE','shop=''bicycle''',''); 164 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2543','doityourself','TRUE','FALSE','TRUE','shop=''doityourself'' AND shop=''hardware''',''); 165 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2544','furniture_shop','TRUE','FALSE','TRUE','shop=''furniture''',''); 166 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2546','computer_shop','TRUE','FALSE','TRUE','shop=''computer''',''); 167 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2547','garden_centre','TRUE','FALSE','TRUE','shop=''garden_centre''',''); 168 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2561','hairdresser','TRUE','FALSE','TRUE','shop=''hairdresser''',''); 169 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2562','car_repair','TRUE','FALSE','TRUE','shop=''car_repair''',''); 170 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2563','car_rental','TRUE','FALSE','TRUE','amenity=''car_rental''',''); 171 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2564','car_wash','TRUE','FALSE','TRUE','amenity=''car_wash''',''); 172 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2565','car_sharing','TRUE','FALSE','TRUE','amenity=''car_sharing''',''); 173 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2566','bicycle_rental','TRUE','FALSE','TRUE','amenity=''bicycle_rental''',''); 174 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2567','travel_agent','TRUE','FALSE','TRUE','shop=''travel_agent''',''); 175 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2568','laundry','TRUE','FALSE','TRUE','shop=''laundry'' OR shop=''dry_cleaning''',''); 176 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2590','vending_machine','TRUE','FALSE','TRUE','amenity=''vending_machine'' AND tags -> ''vending'' <> ''''',''); 177 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2591','vending_cigarette','TRUE','FALSE','TRUE','tags -> ''vending'' =''cigarettes''',''); 178 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2592','vending_parking','TRUE','FALSE','TRUE','tags -> ''vending'' =''parking_tickets''',''); 179 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2601','bank','TRUE','FALSE','TRUE','amenity=''bank''',''); 180 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2602','atm','TRUE','FALSE','TRUE','amenity=''atm''',''); 181 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2701','tourist_info','TRUE','FALSE','TRUE','tourism=''information'' AND tags -> ''information'' <> ''''',''); 182 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2704','tourist_map','TRUE','FALSE','TRUE','tourism=''information'' AND tags -> ''information'' = ''map''',''); 183 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2705','tourist_board','TRUE','FALSE','TRUE','tourism=''information'' AND tags -> ''information'' = ''board''',''); 184 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2706','tourist_guidepost','TRUE','FALSE','TRUE','tourism=''information'' AND tags -> ''information'' =''guidepost''',''); 185 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2721','attraction','TRUE','FALSE','TRUE','tourism=''attraction''',''); 186 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2722','mueseum','TRUE','FALSE','TRUE','tourism=''museum''',''); 187 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2723','monument','TRUE','FALSE','TRUE','historic=''monument''',''); 188 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2724','memorial','TRUE','FALSE','TRUE','historic=''memorial''',''); 189 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2725','art','TRUE','FALSE','TRUE','tourism=''artwork''',''); 190 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2731','castle','TRUE','FALSE','TRUE','historic=''castle''',''); 191 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2732','ruins','TRUE','FALSE','TRUE','historic=''ruins''',''); 192 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2733','archaeological','TRUE','FALSE','TRUE','historic=''archaeological_site''',''); 193 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2734','wayside_cross','TRUE','FALSE','TRUE','historic=''wayside_cross''','Geofabrik docs said "historic=wayside_criss" but I assume that''s a typo'); 194 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2735','wayside_shrine','TRUE','FALSE','TRUE','historic=''wayside_shrine''',''); 195 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2736','battlefield','TRUE','FALSE','TRUE','historic=''battlefield''',''); 196 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2737','fort','TRUE','FALSE','TRUE','historic=''fort''',''); 197 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2741','picnic_site','TRUE','FALSE','TRUE','tourism=''picnic_site''',''); 198 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2742','viewpoint','TRUE','FALSE','TRUE','tourism=''viewpoint''',''); 199 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2743','zoo','TRUE','FALSE','TRUE','tourism=''zoo''',''); 200 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2744','theme_park','TRUE','FALSE','TRUE','tourism=''theme_park''',''); 201 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2901','toilet','TRUE','FALSE','TRUE','amenity=''toilets''',''); 202 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2902','bench','TRUE','FALSE','TRUE','amenity=''bench''',''); 203 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2903','drinking_water','TRUE','FALSE','TRUE','amenity=''drinking_water''',''); 204 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2904','fountain','TRUE','FALSE','TRUE','amenity=''fountain''',''); 205 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2905','hunting_stand','TRUE','FALSE','TRUE','amenity=''hunting_stand''',''); 206 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2906','waste_basket','TRUE','FALSE','TRUE','amenity=''waste_basket''',''); 207 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2907','camera_surveillance','TRUE','FALSE','TRUE','man_made=''surveillance''',''); 208 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2921','emergency_phone','TRUE','FALSE','TRUE','amenity=''emergency_phone'' OR tags -> ''emergency''=''phone''',''); 209 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2922','fire_hydrant','TRUE','FALSE','TRUE','amenity=''fire_hydrant'' OR tags -> ''emergency''=''fire_hydrant''',''); 210 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2923','emergency_access','TRUE','FALSE','TRUE','highway=''emergency_access_point''',''); 211 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2950','tower','TRUE','FALSE','TRUE','man_made=''tower'' ',''); 212 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2952','water_tower','TRUE','FALSE','TRUE','man_made=''water_tower''',''); 213 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2954','windmill','TRUE','FALSE','TRUE','man_made=''windmill''',''); 214 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2955','lighthouse','TRUE','FALSE','TRUE','man_made=''lighthouse''',''); 215 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2961','wasewater_plant','TRUE','FALSE','TRUE','man_made=''wasewater_plant''',''); 216 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2962','water_well','TRUE','FALSE','TRUE','man_made=''water_well''',''); 217 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2963','water_mill','TRUE','FALSE','TRUE','man_made=''watermill''',''); 218 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('2964','water_works','TRUE','FALSE','TRUE','man_made=''water_works''',''); 219 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('3100','christian','TRUE','FALSE','TRUE','religion=''christian''',''); 220 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('3200','jewish','TRUE','FALSE','TRUE','religion=''jewish''',''); 221 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('3300','muslim','TRUE','FALSE','TRUE','religion=''muslim'' ',''); 222 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4101','spring','TRUE','FALSE','TRUE','"natural"=''spring''',''); 223 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4103','glacier','TRUE','FALSE','TRUE','"natural"=''glacier''',''); 224 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4111','peak','TRUE','FALSE','TRUE','"natural"=''peak''',''); 225 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4112','cliff','TRUE','TRUE','TRUE','"natural"=''cliff''',''); 226 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4113','volcano','TRUE','FALSE','TRUE','"natural"=''volcano''',''); 227 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4121','tree','TRUE','FALSE','TRUE','"natural"=''tree''',''); 228 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4131','mine','TRUE','FALSE','TRUE','"natural"=''mine''',''); 229 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4132','cave_entrance','TRUE','FALSE','TRUE','"natural"=''cave_entrance''',''); 230 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('4141','beach','TRUE','FALSE','TRUE','"natural"=''beach''',''); 231 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5111','motorway','FALSE','TRUE','FALSE','highway=''motorway''',''); 232 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5112','trunk','FALSE','TRUE','FALSE','highway=''trunk''',''); 233 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5113','primary','FALSE','TRUE','FALSE','highway=''primary''',''); 234 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5114','secondary','FALSE','TRUE','FALSE','highway=''secondary''',''); 235 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5115','tertiary','FALSE','TRUE','FALSE','highway=''tertiary''',''); 236 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5121','unclassified','FALSE','TRUE','FALSE','highway=''unclassified''',''); 237 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5122','residential','FALSE','TRUE','FALSE','highway=''residential''',''); 238 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5123','living_street','FALSE','TRUE','FALSE','highway=''living_street''',''); 239 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5124','pedestrian','FALSE','TRUE','FALSE','highway=''pedestrian''',''); 240 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5131','motorway_link','FALSE','TRUE','FALSE','highway=''motorway_link''',''); 241 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5132','trunk_link','FALSE','TRUE','FALSE','highway=''trunk_link''',''); 242 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5133','primary_link','FALSE','TRUE','FALSE','highway=''primary_link''',''); 243 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5134','secondary_link','FALSE','TRUE','FALSE','highway=''secondary_link''',''); 244 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5141','service','FALSE','TRUE','FALSE','highway=''service''',''); 245 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5142','track','FALSE','TRUE','FALSE','highway=''track'' AND tracktype IS NULL',''); 246 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5143','track_grade1','FALSE','TRUE','FALSE','highway=''track'' AND tracktype=''grade1''',''); 247 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5144','track_grade2','FALSE','TRUE','FALSE','highway=''track'' AND tracktype=''grade2''',''); 248 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5145','track_grade3','FALSE','TRUE','FALSE','highway=''track'' AND tracktype=''grade3''',''); 249 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5146','track_grade4','FALSE','TRUE','FALSE','highway=''track'' AND tracktype=''grade4''',''); 250 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5147','track_grade5','FALSE','TRUE','FALSE','highway=''track'' AND tracktype=''grade5''',''); 251 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5151','bridleway','FALSE','TRUE','FALSE','highway=''bridleway'' OR (highway=''path'' AND horse=''designated'')',''); 252 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5152','cycleway','FALSE','TRUE','FALSE','highway=''cycleway'' OR (highway IS NOT NULL AND tags -> ''cycle''=''designated'')','I modified the second half from Geofabrik to not require highway=path when cycle=designated'); 253 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5153','footway','FALSE','TRUE','FALSE','highway=''footway'' OR foot=''designated''','I modified the second half from Geofabrik to not require highway=path when foot=designated'); 254 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5154','path','FALSE','TRUE','FALSE','highway=''path''',''); 255 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5155','steps','FALSE','TRUE','FALSE','highway=''steps''',''); 256 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5199','unknown','FALSE','TRUE','FALSE','highway=''road''',''); 257 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5201','traffic_signals','TRUE','FALSE','TRUE','highway=''traffic_signals''',''); 258 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5202','mini_roundabout','TRUE','FALSE','TRUE','highway=''mini_roundabout''',''); 259 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5203','stop','TRUE','FALSE','TRUE','highway=''stop''',''); 260 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5204','crossing','TRUE','FALSE','TRUE','highway=''crossing'' OR railway=''level_crossing''',''); 261 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5205','speed_camera','TRUE','FALSE','TRUE','highway=''speed_camera''',''); 262 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5206','motoway_junction','TRUE','FALSE','TRUE','highway=''motorway_junction''',''); 263 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5207','turning_circle','TRUE','FALSE','TRUE','highway=''turning_circle''',''); 264 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5208','ford','TRUE','FALSE','TRUE','highway=''ford''',''); 265 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5209','street_lamp','TRUE','FALSE','TRUE','highway=''street_lamp''',''); 266 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5210','barrier','TRUE','FALSE','TRUE','barrier IS NOT NULL AND barrier NOT IN(''gate'',''bollard'',''lift_gate'',''stile'',''cycle_barrier'',''fence'',''toll_booth'',''block'',''kissing_gate'',''cattle_grid'')',''); 267 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5211','barrier_gate','TRUE','FALSE','TRUE','barrier=''gate''',''); 268 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5212','barrier_bollard','TRUE','FALSE','TRUE','barrier=''bollard''',''); 269 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5213','barrier_lift_gate','TRUE','FALSE','TRUE','barrier=''lift_gate''',''); 270 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5214','barrier_stile','TRUE','FALSE','TRUE','barrier=''stile'' OR highway=''stile''',''); 271 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5215','barrier_cycle','TRUE','FALSE','TRUE','barrier=''cycle_barrier''',''); 272 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5216','barrier_fence','TRUE','TRUE','TRUE','barrier=''fence''',''); 273 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5217','barrier_toll','TRUE','FALSE','TRUE','barrier=''toll_booth''',''); 274 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5218','barrier_block','TRUE','FALSE','TRUE','barrier=''block''',''); 275 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5219','barrier_kissing_gate','TRUE','FALSE','TRUE','barrier=''kissing_gate''',''); 276 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5220','barrier_cattle_grid','TRUE','FALSE','TRUE','barrier=''cattle_grid''',''); 277 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5231','calming_hump','TRUE','FALSE','TRUE','tags -> ''traffic_calming'' =''hump''',''); 278 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5232','calming_bump','TRUE','FALSE','TRUE','tags -> ''traffic_calming''=''bump''',''); 279 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5233','calming_table','TRUE','FALSE','TRUE','tags -> ''traffic_calming''=''table''',''); 280 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5234','calming_chicane','TRUE','FALSE','TRUE','tags -> ''traffic_calming''=''chicane''',''); 281 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5235','calming_cushion','TRUE','FALSE','TRUE','tags -> ''traffic_calming''=''cushion''',''); 282 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5250','fuel','TRUE','FALSE','TRUE','amenity=''fuel''',''); 283 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5251','service','TRUE','FALSE','TRUE','highway=''services''',''); 284 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5260','parking','TRUE','FALSE','TRUE','amenity=''parking'' ',''); 285 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5261','parking_site','TRUE','FALSE','TRUE','amenity=''parking'' AND tags -> ''parking''=''site''',''); 286 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5262','parking_multistorey','TRUE','FALSE','TRUE','amenity=''parking'' AND tags -> ''parking''=''multi-storey''',''); 287 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5263','parking_underground','TRUE','FALSE','TRUE','amenity=''parking'' AND tags -> ''parking''=''underground''',''); 288 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5270','parking_bicycle','TRUE','FALSE','TRUE','amenity=''bicycle_parking''',''); 289 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5301','slipway','FALSE','FALSE','FALSE','leisure=''slipway''',''); 290 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5302','marina','FALSE','FALSE','FALSE','leisure=''marina''',''); 291 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5303','pier','FALSE','FALSE','FALSE','man_made=''pier''',''); 292 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5311','dam','FALSE','FALSE','FALSE','waterway=''dam''',''); 293 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5321','waterfall','FALSE','FALSE','FALSE','waterway=''waterfall''',''); 294 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5331','lock_gate','FALSE','FALSE','FALSE','waterway=''lock_gate''',''); 295 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5332','weir','FALSE','FALSE','FALSE','waterway=''weir''',''); 296 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5501','fence','FALSE','FALSE','FALSE','barrier=''fence'' OR barrier=''wood_fence'' OR barrier=''wire_fence''',''); 297 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5511','hedge','FALSE','FALSE','FALSE','barrier=''hedge''',''); 298 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5512','tree_row','FALSE','FALSE','FALSE','barrier=''tree_row''',''); 299 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5521','wall','FALSE','FALSE','FALSE','barrier=''wall''',''); 300 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5531','dyke','FALSE','FALSE','FALSE','man_made=''dyke''',''); 301 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5601','railway_station','FALSE','FALSE','FALSE','railway=''station''',''); 302 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5602','railway_halt','FALSE','FALSE','FALSE','railway=''halt'' OR (public_transport=''stop_position'' AND train=''yes'')',''); 303 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5603','tram_stop','FALSE','FALSE','FALSE','railway=''tram_stop'' OR (public_transport=''stop_position'' AND tram=''yes'')',''); 304 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5621','bus_stop','FALSE','FALSE','FALSE','highway=''bus_stop'' OR (public_transport=''stop_position'' AND bus=''yes'')',''); 305 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5622','bus_station','FALSE','FALSE','FALSE','amenity=''bus_station''',''); 306 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5641','taxi_rank','FALSE','FALSE','FALSE','amenity=''taxi_rank''',''); 307 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5651','airport','FALSE','FALSE','FALSE','amenity=''airport'' OR (aeroway=''aerodome'' AND type <> ''airstrip'')',''); 308 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5652','airfield','FALSE','FALSE','FALSE','aeroway=''airfield'' OR military=''airfield'' OR (aeroway=''aeroway'' AND type=''airstrip'')',''); 309 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5655','helipad','FALSE','FALSE','FALSE','aeroway=''helipad''',''); 310 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5661','ferry_terminal','FALSE','FALSE','FALSE','amenity=''ferry_terminal''',''); 311 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('5671','aerialway_station','FALSE','FALSE','FALSE','aerialway=''station''',''); 312 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6101','rail','FALSE','TRUE','FALSE','railway=''rail'' AND tags -> ''propulsion'' <> ''''',''); 313 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6102','light_rail','FALSE','TRUE','FALSE','railway=''light_rail''',''); 314 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6103','subway','FALSE','TRUE','FALSE','railway=''subway''',''); 315 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6104','tram','FALSE','TRUE','FALSE','railway=''tram''',''); 316 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6105','monorail','FALSE','TRUE','FALSE','railway=''monorail''',''); 317 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6106','narrow_gauge','FALSE','TRUE','FALSE','railway=''narrow_gauge''',''); 318 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6107','miniature','FALSE','TRUE','FALSE','railway=''miniature''',''); 319 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6108','funicular','FALSE','TRUE','FALSE','railway=''funicular'' OR (railway=''rail'' AND tags -> ''propulsion''=''funicular'')',''); 320 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6109','rack','FALSE','TRUE','FALSE','railway=''rack'' OR (railway=''rail'' AND tags -> ''propulsion''=''rack'')',''); 321 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6111','drag_lift','FALSE','TRUE','FALSE','aerialway=''drag_lift''',''); 322 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6112','chair_lift','FALSE','TRUE','FALSE','aerialway=''chair_lift'' OR aerialway=''high_speed_chair_lift''',''); 323 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6113','cable_car','FALSE','TRUE','FALSE','aerialway=''cable_car''',''); 324 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6114','gondola','FALSE','TRUE','FALSE','aerialway=''gondola''',''); 325 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6115','goods','FALSE','TRUE','FALSE','aerialway=''goods''',''); 326 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6119','other_lift','FALSE','TRUE','FALSE','aerialway IS NOT NULL AND aerialway NOT IN (''drag_lift'',''chair_lift'',''high_speed_chair_lift'',''cable_car'',''gondola'',''goods'')',''); 327 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6204','pole','TRUE','FALSE','TRUE','power=''pole''','Should this code be 6404??'); 328 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6401','tower','TRUE','FALSE','TRUE','power=''tower''',''); 329 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6410','station','TRUE','FALSE','TRUE','power=''generator'' ',''); 330 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6422','substation','TRUE','FALSE','TRUE','power=''sub_station''',''); 331 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6423','transformer','TRUE','FALSE','TRUE','power=''transformer''',''); 332 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6500','line','FALSE','TRUE','FALSE','power=''line''',''); 333 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6501','minor_line','FALSE','TRUE','FALSE','power=''minor_line''',''); 334 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6511','cable','FALSE','TRUE','FALSE','power=''cable''',''); 335 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('6512','minor_cable','FALSE','TRUE','FALSE','power=''minor_cable''',''); 336 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7201','forest','FALSE','FALSE','TRUE','landuse=''forest'' OR "natural"=''wood''',''); 337 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7202','park','FALSE','FALSE','TRUE','leisure=''park''',''); 338 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7203','residential','FALSE','FALSE','TRUE','landuse=''residential''',''); 339 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7204','industrial','FALSE','FALSE','TRUE','landuse=''industrial''',''); 340 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7205','farm','FALSE','FALSE','TRUE','landuse IN (''farm'',''farmland'',''farm yard'')',''); 341 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7206','cemetery','FALSE','FALSE','TRUE','landuse=''cemetery''',''); 342 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7207','allotments','FALSE','FALSE','TRUE','landuse=''allotments''',''); 343 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7208','meadow','FALSE','FALSE','TRUE','landuse=''meadow''',''); 344 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7209','commercial','FALSE','FALSE','TRUE','landuse=''commercial''',''); 345 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7210','nature_reserve','FALSE','FALSE','TRUE','leisure=''recreation_ground'' OR landuse=''recreation_ground''',''); 346 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7211','recreation_ground','FALSE','FALSE','TRUE','leisure=''recreation_ground'' OR landuse=''recreation_ground''',''); 347 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7212','retail','FALSE','FALSE','TRUE','landuse=''retail''',''); 348 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7213','military','FALSE','FALSE','TRUE','landuse=''military''',''); 349 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7214','quarry','FALSE','FALSE','TRUE','landuse=''quarry''',''); 350 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7215','orchard','FALSE','FALSE','TRUE','landuse=''orchard''',''); 351 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7216','vineyard','FALSE','FALSE','TRUE','landuse=''vineyard''',''); 352 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7217','scrub','FALSE','FALSE','TRUE','landuse=''scrub'' or "natural"=''scrub''',''); 353 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7218','grass','FALSE','FALSE','TRUE','landuse=''grass''',''); 354 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7219','heath','FALSE','FALSE','TRUE','"natural"=''heath''',''); 355 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('7220','national_park','FALSE','FALSE','TRUE','boundary=''national_park''',''); 356 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8101','river','FALSE','TRUE','FALSE','waterway=''river''',''); 357 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8102','stream','FALSE','TRUE','FALSE','waterway=''stream''',''); 358 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8103','canal','FALSE','TRUE','FALSE','waterway=''canal''',''); 359 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8104','drain','FALSE','TRUE','FALSE','waterway=''drain''',''); 360 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8200','water','FALSE','FALSE','TRUE','"natural"=''water''',''); 361 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8201','reservoir','FALSE','FALSE','TRUE','landuse=''reservoir''',''); 362 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8202','river','FALSE','FALSE','TRUE','waterway=''riverbank''',''); 363 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8203','basin','FALSE','FALSE','TRUE','landuse=''basin''',''); 364 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8211','glacier','FALSE','FALSE','TRUE','"natural"=''glacier''',''); 365 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8221','wetland','FALSE','FALSE','TRUE','"natural"=''wetland''',''); 366 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('8300','coastline','FALSE','FALSE','FALSE','???',''); 367 | INSERT INTO pgosm.layer_detail (code, subclass, geom_point, geom_line, geom_polygon, osm_tag_filter, description) VALUES ('1011','neighborhood','FALSE','TRUE','TRUE','boundary=''neighborhood'' ',''); 368 | 369 | 370 | 371 | UPDATE pgosm.layer_detail ld 372 | SET layer_group_id = l.layer_group_id 373 | FROM pgosm.layer_group l 374 | WHERE ld.code BETWEEN l.code_start AND l.code_end 375 | ; 376 | 377 | 378 | --------------------------------------------------------------- 379 | --------------------------------------------------------------- 380 | --------------------------------------------------------------- 381 | -------------------------------------------------------------------------------- /db/data/routable.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO pgosm.routable (layer_detail_id, max_speed, route_foot) 2 | SELECT ld.layer_detail_id, a.max_speed, a.route_foot 3 | FROM ( 4 | VALUES ('5111', 65.0, False), 5 | ('5112', 60.0, False), 6 | ('5113', 60.0, False), 7 | ('5114', 45.0, True), 8 | ('5115', 45.0, True), 9 | ('5121', 25.0, True), 10 | ('5122', 25.0, True), 11 | ('5123', 10.0, True), 12 | ('5131', 55.0, True), 13 | ('5132', 50.0, True), 14 | ('5133', 50.0, True), 15 | ('5134', 35.0, True), 16 | ('5141', 10.0, True) 17 | ) a (code, max_speed, route_foot) 18 | INNER JOIN pgosm.layer_group lg 19 | ON lg.class = 'road' 20 | INNER JOIN pgosm.layer_detail ld 21 | ON lg.layer_group_id = ld.layer_group_id 22 | AND ld.code = a.code 23 | ; 24 | 25 | -- Main footway/cycleway with max speed, set False motorway 26 | INSERT INTO pgosm.routable (layer_detail_id, max_speed, route_motor) 27 | SELECT ld.layer_detail_id, a.max_speed, a.route_motor 28 | FROM ( 29 | VALUES ('5124', 2.5, False), 30 | ('5142', 2.0, False), 31 | ('5143', 2.0, False), 32 | ('5144', 1.8, False), 33 | ('5145', 1.6, False), 34 | ('5146', 1.2, False), 35 | ('5147', 0.8, False), 36 | ('5151', 1.0, False), 37 | ('5152', 8, False), 38 | ('5153', 2.5, False), 39 | ('5154', 2.5, False), 40 | ('5155', 0.75, False) 41 | ) a (code, max_speed, route_motor) 42 | INNER JOIN pgosm.layer_group lg 43 | ON lg.class = 'road' 44 | INNER JOIN pgosm.layer_detail ld 45 | ON lg.layer_group_id = ld.layer_group_id 46 | AND ld.code = a.code 47 | ; 48 | -------------------------------------------------------------------------------- /db/data/thematic_road.sql: -------------------------------------------------------------------------------- 1 | 2 | INSERT INTO pgosm.layer_group 3 | (code_start, code_end, class, osm_columns, description) 4 | VALUES ('T001','T001','t_road', 5 | 'osm_id, name, highway, ref, REPLACE(tags -> ''maxspeed'', '' mph'', '''') AS maxspeed, oneway, tracktype, way','' 6 | ); 7 | 8 | 9 | INSERT INTO pgosm.layer_detail (layer_group_id, code, 10 | subclass, geom_point, geom_line, geom_polygon, 11 | osm_tag_filter, description) 12 | SELECT lg.layer_group_id, a.* 13 | FROM ( 14 | VALUES ('5111', 'motorway', False,True, False, 'highway=''motorway''','') 15 | ,('5112', 'trunk', False,True, False, 'highway=''trunk''','') 16 | ,('5113','primary',False,True,False,'highway=''primary''','') 17 | ,('5114','secondary',False,True,False,'highway=''secondary''','') 18 | ,('5115','tertiary',False,True,False,'highway=''tertiary''','') 19 | ,('5131','motorway_link',False,True,False,'highway=''motorway_link''','') 20 | ,('5132','trunk_link',False,True,False,'highway=''trunk_link''','') 21 | ,('5133','primary_link',False,True,False,'highway=''primary_link''','') 22 | ,('5134','secondary_link',False,True,False,'highway=''secondary_link''','') 23 | ) a 24 | INNER JOIN pgosm.layer_group lg ON lg.code_start = 'T001' 25 | ; 26 | -------------------------------------------------------------------------------- /db/deploy/001.sql: -------------------------------------------------------------------------------- 1 | -- Deploy PgOSM:001 to pg 2 | 3 | BEGIN; 4 | 5 | CREATE EXTENSION IF NOT EXISTS postgis; 6 | CREATE EXTENSION IF NOT EXISTS hstore; 7 | 8 | ----------------------------------------------- 9 | ----------------------------------------------- 10 | ----------------------------------------------- 11 | 12 | CREATE SCHEMA pgosm; 13 | 14 | CREATE TABLE pgosm.layer_group 15 | ( 16 | layer_group_id SERIAL NOT NULL, 17 | code_start CHAR(4) NOT NULL, 18 | code_end CHAR(4) NOT NULL, 19 | class TEXT NOT NULL, 20 | osm_columns TEXT NULL, 21 | description TEXT NULL, 22 | CONSTRAINT PK_layer_group_id PRIMARY KEY (layer_group_id) 23 | ); 24 | 25 | --------------------------------------------------------------- 26 | --------------------------------------------------------------- 27 | --------------------------------------------------------------- 28 | 29 | 30 | CREATE TABLE pgosm.layer_detail 31 | ( 32 | layer_detail_id SERIAL NOT NULL, 33 | layer_group_id INT NULL REFERENCES pgosm.layer_group (layer_group_id), 34 | code CHAR(4) NOT NULL, 35 | subclass TEXT NOT NULL, 36 | geom_point BOOLEAN NOT NULL, 37 | geom_line BOOLEAN NOT NULL, 38 | geom_polygon BOOLEAN NOT NULL, 39 | osm_tag_filter TEXT NOT NULL, 40 | description TEXT NULL, 41 | CONSTRAINT PK_layer_detail_id PRIMARY KEY (layer_detail_id), 42 | CONSTRAINT UQ_layer_detail_code UNIQUE (code) 43 | ); 44 | 45 | 46 | 47 | ---------------------------------------- 48 | ---------------------------------------- 49 | ---------------------------------------- 50 | 51 | 52 | 53 | 54 | COMMIT; 55 | -------------------------------------------------------------------------------- /db/deploy/002.sql: -------------------------------------------------------------------------------- 1 | -- Deploy PgOSM:002 to pg 2 | 3 | BEGIN; 4 | 5 | 6 | CREATE TABLE pgosm.routable 7 | ( 8 | code CHAR(4) NOT NULL, 9 | route_motor BOOLEAN DEFAULT True, 10 | route_foot BOOLEAN DEFAULT True, 11 | max_speed NUMERIC(5,2), 12 | CONSTRAINT PK_pgosm_routable_code PRIMARY KEY (code), 13 | CONSTRAINT FK_pgosm_routable_code FOREIGN KEY (code) 14 | REFERENCES pgosm.layer_detail (code) 15 | ); 16 | 17 | COMMENT ON TABLE pgosm.routable IS 'Provides lookup information for routeable layers based on code.'; 18 | 19 | COMMIT; 20 | -------------------------------------------------------------------------------- /db/deploy/003.sql: -------------------------------------------------------------------------------- 1 | -- Deploy PgOSM:003 to pg 2 | 3 | BEGIN; 4 | 5 | COMMENT ON TABLE pgosm.layer_group IS 'PgOSM meta table. Layer Groups define table names and columns for pgosm transformations. Provides SQL searchable meta to aid users.'; 6 | COMMENT ON TABLE pgosm.layer_detail IS 'PgOSM meta table. Layer Detail define subsets of layer groups. Defines filters used by pgosm transformations for processing. Provides SQL searchable meta to aid users.'; 7 | COMMENT ON TABLE pgosm.routable IS 'Provides routing details for roads (e.g. `highway IS NOT NULL`) based on code from pgosm.layer_detail. Uses PgOSM transformed roads.'; 8 | 9 | COMMENT ON COLUMN pgosm.layer_detail.code IS 'Unique 4 character code used to identify a specific subclass.'; 10 | COMMENT ON COLUMN pgosm.layer_detail.osm_tag_filter IS 'Contents to use in the `WHERE` clause for to select this subset of data. Invalid contents here will cause PgOSM processing to fail.'; 11 | COMMENT ON COLUMN pgosm.layer_group.code_start IS 'Beginning of code range to include in group.'; 12 | COMMENT ON COLUMN pgosm.layer_group.code_end IS 'End of code range to include in group.'; 13 | COMMENT ON COLUMN pgosm.layer_group.osm_columns IS 'Columns to include in the output table. All columns must exist in source tables or error will occur during PgOSM processing.'; 14 | 15 | COMMENT ON COLUMN pgosm.routable.route_motor IS 'Indicates if motorized traffic is allowed.'; 16 | COMMENT ON COLUMN pgosm.routable.route_foot IS 'Indicates if foot traffic is allowed.'; 17 | COMMENT ON COLUMN pgosm.routable.max_speed IS 'Assumed max speed in miles per hour (MPH)'; 18 | 19 | COMMIT; 20 | -------------------------------------------------------------------------------- /db/deploy/004.sql: -------------------------------------------------------------------------------- 1 | -- Deploy PgOSM:004 to pg 2 | 3 | BEGIN; 4 | 5 | /* 6 | First fix the routable table to have proper PK. 7 | Want PK column first so rename original, create new 8 | structure, then migrate data. 9 | */ 10 | ALTER TABLE pgosm.routable RENAME TO routable_original; 11 | 12 | CREATE TABLE pgosm.routable 13 | ( 14 | routable_id SERIAL NOT NULL, 15 | layer_detail_id INT NOT NULL, 16 | route_motor BOOLEAN NOT NULL DEFAULT True, 17 | route_foot BOOLEAN NOT NULL DEFAULT True, 18 | max_speed NUMERIC(5,2), 19 | CONSTRAINT PK_pgosm_routable PRIMARY KEY (routable_id), 20 | CONSTRAINT FK_pgosm_routable_layer_detail_id 21 | FOREIGN KEY (layer_detail_id) 22 | REFERENCES pgosm.layer_detail (layer_detail_id) 23 | ); 24 | 25 | 26 | INSERT INTO pgosm.routable (layer_detail_id, route_motor, route_foot, max_speed) 27 | SELECT ld.layer_detail_id, o.route_motor, 28 | o.route_foot, o.max_speed 29 | FROM pgosm.routable_original o 30 | INNER JOIN pgosm.layer_detail ld ON o.code = ld.code 31 | ; 32 | 33 | DROP TABLE pgosm.routable_original; 34 | 35 | 36 | -- Improve layer_detail unique constraint 37 | ALTER TABLE pgosm.layer_detail 38 | DROP CONSTRAINT uq_layer_detail_code; 39 | 40 | ALTER TABLE pgosm.layer_detail 41 | ADD CONSTRAINT uq_layer_detail_code_layer_group 42 | UNIQUE (layer_group_id, code); 43 | 44 | 45 | -- Put latest comments back on routable 46 | COMMENT ON TABLE pgosm.routable IS 'Provides routing details for roads (e.g. `highway IS NOT NULL`) based on code from pgosm.layer_detail. Uses PgOSM transformed roads.'; 47 | COMMENT ON COLUMN pgosm.routable.route_motor IS 'Indicates if motorized traffic is allowed.'; 48 | COMMENT ON COLUMN pgosm.routable.route_foot IS 'Indicates if foot traffic is allowed.'; 49 | COMMENT ON COLUMN pgosm.routable.max_speed IS 'Assumed max speed in miles per hour (MPH).'; 50 | COMMIT; 51 | -------------------------------------------------------------------------------- /db/revert/001.sql: -------------------------------------------------------------------------------- 1 | -- Revert PgOSM:001 from pg 2 | 3 | BEGIN; 4 | 5 | DROP SCHEMA pgosm CASCADE; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /db/revert/002.sql: -------------------------------------------------------------------------------- 1 | -- Revert PgOSM:002 from pg 2 | 3 | BEGIN; 4 | 5 | DROP TABLE pgosm.routable; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /db/revert/003.sql: -------------------------------------------------------------------------------- 1 | -- Revert PgOSM:003 from pg 2 | 3 | BEGIN; 4 | 5 | -- XXX Add DDLs here. 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /db/revert/004.sql: -------------------------------------------------------------------------------- 1 | -- Revert PgOSM:004 from pg 2 | 3 | BEGIN; 4 | 5 | ALTER TABLE pgosm.layer_detail 6 | DROP CONSTRAINT uq_layer_detail_code_layer_group; 7 | 8 | ALTER TABLE pgosm.layer_detail 9 | ADD CONSTRAINT uq_layer_detail_code UNIQUE (code); 10 | 11 | 12 | ALTER TABLE pgosm.routable RENAME TO routable_original; 13 | 14 | CREATE TABLE pgosm.routable 15 | ( 16 | code CHAR(4) NOT NULL, 17 | route_motor BOOLEAN DEFAULT True, 18 | route_foot BOOLEAN DEFAULT True, 19 | max_speed NUMERIC(5,2), 20 | CONSTRAINT PK_pgosm_routable_code PRIMARY KEY (code), 21 | CONSTRAINT FK_pgosm_routable_code FOREIGN KEY (code) 22 | REFERENCES pgosm.layer_detail (code) 23 | ); 24 | 25 | COMMENT ON TABLE pgosm.routable IS 'Provides lookup information for routeable layers based on code.'; 26 | 27 | INSERT INTO pgosm.routable (code, route_motor, route_foot, max_speed) 28 | SELECT ld.code, o.route_motor, 29 | o.route_foot, o.max_speed 30 | FROM pgosm.routable_original o 31 | INNER JOIN pgosm.layer_detail ld ON o.layer_detail_id = ld.layer_detail_id 32 | ; 33 | 34 | DROP TABLE pgosm.routable_original; 35 | 36 | 37 | COMMIT; 38 | -------------------------------------------------------------------------------- /db/sqitch.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | plan_file = sqitch.plan 4 | top_dir = . 5 | -------------------------------------------------------------------------------- /db/sqitch.plan: -------------------------------------------------------------------------------- 1 | %syntax-version=1.0.0 2 | %project=PgOSM 3 | %uri=https://bitbucket.org/rplinternal/pgosm 4 | 5 | 001 2018-12-10T21:20:08Z Ryan Lambert # Initial DB structures, cleaning up original version. 6 | 002 [001] 2019-11-18T01:06:28Z Ryan Lambert # Add table for routing details per detail code 7 | 003 [002] 2020-03-01T15:07:06Z Ryan Lambert # Improve meta 8 | 004 [003] 2020-03-21T15:35:14Z Ryan Lambert # Update layer_detail unique constraint 9 | -------------------------------------------------------------------------------- /db/style/README.md: -------------------------------------------------------------------------------- 1 | # QGIS Styles 2 | 3 | PgOSM includes layer styles that should work in QGIS 3.4 and later. 4 | These styles should be helpful to quickly get started with PgOSM data with QGIS. 5 | They give new users an easy starting point 6 | towards visualizing the restructured OpenStreetMap data in QGIS. 7 | 8 | 9 | ## Load Styles to Staging 10 | 11 | The following commands load default styles where they have been developed and 12 | included in this project. The `create_layer_styles.sql` script create a staging 13 | table for the incoming layer styles. The table structure is the same as what 14 | QGIS creates (as of 3.4) except the `id` column is a plain `INT` column instead 15 | of the `SERIAL`, and there is no primary key. 16 | 17 | psql -d pgosm -f create_layer_styles.sql 18 | psql -d pgosm -f layer_styles_defaults.sql 19 | 20 | 21 | ### Prepare 22 | 23 | To use these styles as defaults, update the `f_table_catalog` and 24 | `f_table_schema` values in the staging table. 25 | 26 | ```sql 27 | UPDATE public.layer_styles_staging 28 | SET f_table_catalog = 'your_db', 29 | f_table_schema = 'osm' 30 | ; 31 | ``` 32 | 33 | ### Update existing records 34 | 35 | Example command showing update from staging based on object names. 36 | 37 | ```sql 38 | UPDATE public.layer_styles ls 39 | SET f_geometry_column = new.f_geometry_column, 40 | styleqml = new.styleqml, 41 | stylesld = new.stylesld, 42 | useasdefault = new.useasdefault, 43 | description = new.description, 44 | "owner" = new."owner", 45 | ui = new.ui, 46 | update_time = new.update_time 47 | FROM public.layer_styles_staging new 48 | WHERE new.f_table_catalog = ls.f_table_catalog 49 | AND new.f_table_schema = ls.f_table_schema 50 | AND new.f_table_name = ls.f_table_name 51 | AND new.stylename = ls.stylename 52 | ; 53 | ``` 54 | 55 | Add new records from staging, based on object names. 56 | 57 | ```sql 58 | INSERT INTO public.layer_styles 59 | (f_table_catalog, f_table_schema, f_table_name, 60 | f_geometry_column, stylename, styleqml, stylesld, 61 | useasdefault, description, "owner", ui, update_time) 62 | SELECT new.f_table_catalog, new.f_table_schema, new.f_table_name, 63 | new.f_geometry_column, new.stylename, new.styleqml, new.stylesld, 64 | new.useasdefault, new.description, new."owner", new.ui, new.update_time 65 | FROM public.layer_styles_staging new 66 | LEFT JOIN public.layer_styles ls 67 | ON new.f_table_catalog = ls.f_table_catalog 68 | AND new.f_table_schema = ls.f_table_schema 69 | AND new.f_table_name = ls.f_table_name 70 | AND new.stylename = ls.stylename 71 | WHERE ls.id IS NULL 72 | ; 73 | ``` 74 | 75 | 76 | ## Style naming conventions 77 | 78 | Table `public.layer_styles` is created/maintained by QGIS software. 79 | 80 | `f_table_schema` is always set to `osm`. Table name is defined by PgOSM using data from `pgosm/db/data/layer_definitons.sql`. 81 | 82 | stylename = f_table_schema || '_' || f_table_name 83 | 84 | e.g. 85 | 86 | stylename = osm_road_line 87 | 88 | 89 | ## Export styles 90 | 91 | Before exporting and updated styles, set owner to `postgres`. 92 | 93 | UPDATE public.layer_styles SET owner = 'postgres'; 94 | 95 | 96 | Data only, column inserts to allow not passing in the primary key (if needed). 97 | 98 | pg_dump -d pgosm --data-only --column-inserts -t public.layer_styles > layer_styles_defaults.sql 99 | 100 | > Remove the id from the `INSERT` command so it doesn't try to force a potentially-conflicting primary key with an existing table. 101 | 102 | ## Older Postgres 103 | 104 | Bug fixed in 11.3 (and older varients back through 9.4...). See: 105 | https://blog.rustprooflabs.com/2019/05/pg-fixed-xml-pg_dump 106 | 107 | If upgrading isn't an option, this applies the work around. 108 | 109 | echo "SET XML OPTION DOCUMENT;" > ~/tmp/layer_styles_export.sql 110 | pg_dump --data-only --column-inserts -d geodb -t public.layer_styles >> ~/tmp/layer_styles_export.sql 111 | 112 | -------------------------------------------------------------------------------- /db/style/create_layer_styles.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE TABLE IF NOT EXISTS public.layer_styles_staging ( 3 | id INT NOT NULL, 4 | f_table_catalog character varying(256), 5 | f_table_schema character varying(256), 6 | f_table_name character varying(256), 7 | f_geometry_column character varying(256), 8 | stylename character varying(30), 9 | styleqml xml, 10 | stylesld xml, 11 | useasdefault boolean, 12 | description text, 13 | owner character varying(30), 14 | ui xml, 15 | update_time timestamp without time zone DEFAULT now() 16 | ); 17 | 18 | COMMENT ON TABLE public.layer_styles_staging IS 'Staging table to load QGIS Layer Styles. Similar to QGIS-created table, no primary key.'; 19 | 20 | 21 | CREATE TABLE IF NOT EXISTS public.layer_styles ( 22 | id SERIAL NOT NULL, 23 | f_table_catalog character varying(256), 24 | f_table_schema character varying(256), 25 | f_table_name character varying(256), 26 | f_geometry_column character varying(256), 27 | stylename character varying(30), 28 | styleqml xml, 29 | stylesld xml, 30 | useasdefault boolean, 31 | description text, 32 | owner character varying(30), 33 | ui xml, 34 | update_time timestamp without time zone DEFAULT now(), 35 | type character varying, 36 | CONSTRAINT layer_styles_pkey PRIMARY KEY (id) 37 | ); 38 | -------------------------------------------------------------------------------- /db/verify/001.sql: -------------------------------------------------------------------------------- 1 | -- Verify PgOSM:001 on pg 2 | 3 | BEGIN; 4 | 5 | -- Ensures PostGIS extension is installed 6 | SELECT PostGIS_Full_Version() 7 | WHERE False; 8 | 9 | ROLLBACK; 10 | -------------------------------------------------------------------------------- /db/verify/002.sql: -------------------------------------------------------------------------------- 1 | -- Verify PgOSM:002 on pg 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /db/verify/003.sql: -------------------------------------------------------------------------------- 1 | -- Verify PgOSM:003 on pg 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /db/verify/004.sql: -------------------------------------------------------------------------------- 1 | -- Verify PgOSM:004 on pg 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /docker/run_pgosm_subregion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Run with: 3 | # ./run_pgosm_subregion.sh \ 4 | # north-america/us \ 5 | # district-of-columbia \ 6 | # 4000 7 | # 8 | # $1 - Region - e.g. north-america/us 9 | # $2 - Subregion - e.g. district-of-columbia 10 | # $3 - Cache (mb) - e.g. 4000 11 | 12 | BASE_PATH=/app/ 13 | 14 | OUT_PATH=/app/output/ 15 | DB_PATH=/app/db/ 16 | 17 | # Naming scheme must match Geofabrik's for MD5 sums to validatate 18 | PBF_FILE=$OUT_PATH$2-latest.osm.pbf 19 | MD5_FILE=$OUT_PATH$2-latest.osm.pbf.md5 20 | 21 | LOG_FILE=$OUT_PATH$2.log 22 | 23 | echo "Monitor $LOG_FILE for progress..." 24 | echo "If paths setup as outlined in README.md, use:" 25 | echo " tail -f ~/pgosm-data/$2.log" 26 | 27 | ALWAYS_DOWNLOAD=${PGOSM_ALWAYS_DOWNLOAD:-0} 28 | 29 | echo "Region: $1" >> $LOG_FILE 30 | echo "Sub-Region: $2" >> $LOG_FILE 31 | echo "Cache: $3" >> $LOG_FILE 32 | 33 | 34 | if [ $ALWAYS_DOWNLOAD == "1" ]; then 35 | echo 'Removing PBF and md5 files if exists...' >> $LOG_FILE 36 | BE_NICE = 'NOTE: Be nice to Geofabrik''s download server!' 37 | echo "$BE_NICE" >> $LOG_FILE 38 | echo "$BE_NICE" 39 | rm $PBF_FILE 40 | rm $MD5_FILE 41 | fi 42 | 43 | if [ -f $PBF_FILE ]; then 44 | echo "$PBF_FILE exists. Not downloading." >> $LOG_FILE 45 | else 46 | echo "$PBF_FILE does not exist. Downloading..." >> $LOG_FILE 47 | wget https://download.geofabrik.de/$1/$2-latest.osm.pbf -O $PBF_FILE --quiet &> $LOG_FILE 48 | fi 49 | 50 | if [ -f $MD5_FILE ]; then 51 | echo "$MD5_FILE exists. Not downloading." >> $LOG_FILE 52 | else 53 | echo "$MD5_FILE does not exist. Downloading..." >> $LOG_FILE 54 | wget https://download.geofabrik.de/$1/$2-latest.osm.pbf.md5 -O $MD5_FILE --quiet &> $LOG_FILE 55 | fi 56 | 57 | 58 | if cd $OUT_PATH && md5sum -c $MD5_FILE; then 59 | echo 'MD5 checksum validated' >> $LOG_FILE 60 | else 61 | ERR_MSG = 'ERROR - MD5 sum did not match. Try re-running with PGOSM_ALWAYS_DOWNLOAD=1' 62 | echo "$ERR_MSG" >> $LOG_FILE 63 | echo "$ERR_MSG" 64 | exit 1 65 | fi 66 | 67 | cd $BASE_PATH 68 | 69 | echo "Create empty pgosm database with extensions..." 70 | psql -U postgres -c "DROP DATABASE IF EXISTS pgosm;" 71 | psql -U postgres -c "CREATE DATABASE pgosm;" 72 | psql -U postgres -d pgosm -c "CREATE EXTENSION postgis;" 73 | psql -U postgres -d pgosm -c "CREATE EXTENSION hstore;" 74 | 75 | echo "Running osm2pgsql..." 76 | osm2pgsql -U postgres --create --slim --drop \ 77 | --cache $3 \ 78 | --hstore --multi-geometry \ 79 | -d pgosm $PBF_FILE &> $LOG_FILE 80 | 81 | 82 | # Change to DB directory and prepare layer transformations 83 | cd $DB_PATH 84 | 85 | echo "Deploying PgOSM schema with sqitch..." >> $LOG_FILE 86 | sqitch deploy db:pg://postgres@localhost/pgosm >> $LOG_FILE 87 | 88 | if [ -f data/custom/skip_default ]; then 89 | echo "Skipping default layer definitions script." >> $LOG_FILE 90 | else 91 | echo "Loading default layers (same logfile as above)" >> $LOG_FILE 92 | psql -U postgres -d pgosm -f data/layer_definitions.sql >> $LOG_FILE 93 | fi 94 | 95 | for i in data/custom/*.sql; do 96 | [ -f "$i" ] || break 97 | echo "Running custom script..." >> $LOG_FILE 98 | echo "$i" >> $LOG_FILE 99 | psql -U postgres -d pgosm -f $i >> $LOG_FILE 100 | done 101 | 102 | export DB_HOST=localhost 103 | export DB_NAME=pgosm 104 | export DB_USER=$POSTGRES_USER 105 | export DB_PW=$POSTGRES_PASSWORD 106 | 107 | 108 | cd $BASE_PATH 109 | echo 'Running PgOSM processing...' 110 | echo 'Running PgOSM processing...' >> $LOG_FILE 111 | python3 -c "import pgosm; pgosm.process_layers(schema='$PGOSM_SCHEMA');" >> $LOG_FILE 112 | 113 | pg_dump -U postgres -d pgosm --schema=$PGOSM_SCHEMA --schema=pgosm > /app/output/pgosm-$2.sql 114 | 115 | echo "PgOSM processing complete. Final output file: pgosm-$2.sql" >> $LOG_FILE 116 | echo "PgOSM processing complete. Final output file: pgosm-$2.sql" 117 | 118 | exit 0 119 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'PgOSM' 21 | copyright = '2013 - 2020, Ryan Lambert' 22 | author = 'Ryan Lambert' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '0.0.7' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = ['sphinx.ext.coverage', 34 | 'sphinx.ext.napoleon', 35 | 'sphinx.ext.viewcode', 36 | 'sphinx_git' 37 | ] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # List of patterns, relative to source directory, that match files and 43 | # directories to ignore when looking for source files. 44 | # This pattern also affects html_static_path and html_extra_path. 45 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 46 | 47 | 48 | # -- Options for HTML output ------------------------------------------------- 49 | 50 | # The theme to use for HTML and HTML Help pages. See the documentation for 51 | # a list of builtin themes. 52 | 53 | html_theme = 'sphinx_rtd_theme' 54 | 55 | # From: https://sphinx-rtd-theme.readthedocs.io/en/latest/configuring.html 56 | html_theme_options = { 57 | 'canonical_url': '', 58 | 'analytics_id': 'UA-XXXXXXX-1', # Provided by Google in your dashboard 59 | 'logo_only': False, 60 | 'display_version': True, 61 | 'prev_next_buttons_location': 'bottom', 62 | 'style_external_links': True, 63 | 'style_nav_header_background': '#2980B9', 64 | # Toc options 65 | 'collapse_navigation': True, 66 | 'sticky_navigation': True, 67 | 'navigation_depth': 4, 68 | 'includehidden': True, 69 | 'titles_only': False 70 | } 71 | 72 | 73 | 74 | numfig = True 75 | 76 | extensions.append('autoapi.extension') 77 | 78 | autoapi_type = 'python' 79 | autoapi_dirs = ['../pgosm', '../tests'] 80 | 81 | 82 | # Add any paths that contain custom static files (such as style sheets) here, 83 | # relative to this directory. They are copied after the builtin static files, 84 | # so a file named "default.css" will overwrite the builtin "default.css". 85 | html_static_path = ['_static'] -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. PgOSM documentation master file, created by 2 | sphinx-quickstart on Mon Oct 5 17:15:42 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PgOSM's documentation! 7 | ================================= 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | 22 | 23 | Build Information 24 | ------------------------- 25 | 26 | .. git_commit_detail:: 27 | :branch: 28 | :commit: 29 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /flex-config/README.md: -------------------------------------------------------------------------------- 1 | # PgOSM Flex Usage 2 | 3 | > Warning - This is experimental! 4 | 5 | Goal is to define as much as possible/convenient in `.lua` script with final 6 | transformations and cleanup in `.sql`. 7 | 8 | ## Load road lines 9 | 10 | 11 | ``` 12 | osm2pgsql --slim --drop --output=flex --style=./road.lua -d pgosm ~/tmp/district-of-columbia-latest.osm.pbf 13 | ``` 14 | 15 | ```sql 16 | psql -d pgosm -f ./road.sql 17 | ``` 18 | 19 | 20 | ## Load Natural points 21 | 22 | ``` 23 | osm2pgsql --slim --drop --output=flex --style=./natural.lua -d pgosm ~/tmp/district-of-columbia-latest.osm.pbf 24 | ``` 25 | 26 | ```sql 27 | psql -d pgosm -f ./natural.sql 28 | ``` 29 | 30 | 31 | ## Run multiple Lua scripts 32 | 33 | The `run-all.lua` script requires the individual Lua scripts. This makes it easy to develop 34 | independent components that projects can pick and choose from and include in a project 35 | specific lua style including the desired layer definitions. This also allows individual 36 | layers to be loaded ad-hoc, as shown above. 37 | 38 | 39 | ``` 40 | osm2pgsql --slim --drop --output=flex --style=./run-all.lua -d pgosm ~/tmp/district-of-columbia-latest.osm.pbf 41 | ``` 42 | 43 | Similarly, the `.sql` script uses psql's `\i` slash command to include the appropriate SQL 44 | scripts. 45 | 46 | 47 | ```sql 48 | psql -d pgosm -f ./run-all.sql 49 | ``` 50 | 51 | Later in the Lua script when the tag data is added to the row it must be encoded for JSON. 52 | This line: 53 | 54 | tags = object.tags, 55 | 56 | Becomes: 57 | 58 | tags = json.encode(object.tags), 59 | 60 | 61 | 62 | 63 | 64 | ## Explore it All 65 | 66 | Load the `unitable.lua` script to make the full OpenStreetMap data set available in one table. This could be helpful for exploring the data when you don't really know what you are 67 | looking for. 68 | 69 | Adapted from https://github.com/openstreetmap/osm2pgsql/blob/master/flex-config/unitable.lua 70 | to use JSONB instead of HSTORE. JSONB has been supported natively since PostgreSQL 9.4. 71 | 72 | ``` 73 | osm2pgsql --slim --drop --output=flex --style=./unitable.lua --style=./natural.lua -d pgosm ~/tmp/district-of-columbia-latest.osm.pbf 74 | ``` 75 | 76 | 77 | -------------------------------------------------------------------------------- /flex-config/building.lua: -------------------------------------------------------------------------------- 1 | -- Building polygons 2 | -- 3 | -- When copy/paste to create new style, find and replace values 4 | -- marked with: "Change function name here" 5 | -- 6 | 7 | -- Use JSON encoder 8 | local json = require('dkjson') 9 | 10 | local tables = {} 11 | 12 | tables.buildings = osm2pgsql.define_way_table('building_polygon', { 13 | { column = 'osm_type', type = 'text' , not_null = true}, 14 | { column = 'name', type = 'text' }, 15 | { column = 'levels', type = 'int'}, 16 | { column = 'height', type = 'numeric'}, 17 | { column = 'housenumber', type = 'text'}, 18 | { column = 'street', type = 'text' }, 19 | { column = 'city', type = 'text' }, 20 | { column = 'state', type = 'text'}, 21 | { column = 'wheelchair', type = 'bool'}, 22 | { column = 'tags', type = 'jsonb' }, 23 | { column = 'geom', type = 'multipolygon' }, 24 | }, { schema = 'osm' }) 25 | 26 | 27 | function clean_tags(tags) 28 | tags.odbl = nil 29 | tags.created_by = nil 30 | tags.source = nil 31 | tags['source:ref'] = nil 32 | 33 | return next(tags) == nil 34 | end 35 | 36 | 37 | 38 | function parse_building_height(input) 39 | if not input then 40 | return nil 41 | end 42 | 43 | local height = tonumber(input) 44 | 45 | -- If height is just a number, it is in meters, just return it 46 | if height then 47 | return height 48 | end 49 | 50 | -- If there is an 'ft' at the end, convert to meters and return 51 | if input:sub(-2) == 'ft' then 52 | local num = tonumber(input:sub(1, -3)) 53 | if num then 54 | return num * 0.3048 55 | end 56 | end 57 | 58 | return nil 59 | end 60 | 61 | 62 | -- Change function name here 63 | function building_process_way(object) 64 | if not object.tags.building then 65 | return 66 | end 67 | 68 | if not object.is_closed then 69 | return 70 | end 71 | 72 | clean_tags(object.tags) 73 | 74 | -- Using grab_tag() removes from remaining key/value saved to Pg 75 | local osm_type = object:grab_tag('building') 76 | local name = object:grab_tag('name') 77 | local street = object:grab_tag('addr:street') 78 | local city = object:grab_tag('addr:city') 79 | local state = object:grab_tag('addr:state') 80 | local wheelchair = object:grab_tag('wheelchair') 81 | local levels = object:grab_tag('building:levels') 82 | local height = parse_building_height(object.tags['building:height']) 83 | local housenumber = object:grab_tag('addr:housenumber') 84 | local operator = object:grab_tag('operator') 85 | 86 | tables.buildings:add_row({ 87 | tags = json.encode(object.tags), 88 | osm_type = osm_type, 89 | name = name, 90 | housenumber = housenumber, 91 | street = street, 92 | city = city, 93 | state = state, 94 | wheelchair = wheelchair, 95 | levels = levels, 96 | height = height, 97 | operator = operator, 98 | geom = { create = 'area' } 99 | }) 100 | 101 | 102 | end 103 | 104 | -- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244 105 | function deep_copy(obj) 106 | if type(obj) ~= 'table' then return obj end 107 | local res = setmetatable({}, getmetatable(obj)) 108 | for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end 109 | return res 110 | end 111 | 112 | 113 | if osm2pgsql.process_way == nil then 114 | -- Change function name here 115 | osm2pgsql.process_way = building_process_way 116 | else 117 | local nested = osm2pgsql.process_way 118 | osm2pgsql.process_way = function(object) 119 | local object_copy = deep_copy(object) 120 | nested(object) 121 | -- Change function name here 122 | building_process_way(object_copy) 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /flex-config/building.sql: -------------------------------------------------------------------------------- 1 | COMMENT ON TABLE osm.building_polygon IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/building.lua'; 2 | 3 | ALTER TABLE osm.building_polygon 4 | ADD CONSTRAINT pk_osm_building_polygon_way_id 5 | PRIMARY KEY (way_id) 6 | ; 7 | 8 | CREATE INDEX ix_osm_building_polygon_type ON osm.building_polygon (osm_type); 9 | -------------------------------------------------------------------------------- /flex-config/natural.lua: -------------------------------------------------------------------------------- 1 | 2 | -- Use JSON encoder 3 | local json = require('dkjson') 4 | 5 | local tables = {} 6 | 7 | tables.natural = osm2pgsql.define_node_table('natural_point', { 8 | { column = 'osm_type', type = 'text', not_null = true }, 9 | { column = 'tags', type = 'jsonb' }, 10 | { column = 'geom', type = 'point' }, 11 | }, { schema = 'osm' }) 12 | 13 | tables.natural_line = osm2pgsql.define_way_table('natural_line', { 14 | { column = 'osm_type', type = 'text', not_null = true }, 15 | { column = 'tags', type = 'jsonb' }, 16 | { column = 'geom', type = 'linestring' }, 17 | }, { schema = 'osm' }) 18 | 19 | 20 | tables.natural_polygon = osm2pgsql.define_way_table('natural_polygon', { 21 | { column = 'osm_type', type = 'text' , not_null = true}, 22 | { column = 'tags', type = 'jsonb' }, 23 | { column = 'geom', type = 'multipolygon' }, 24 | }, { schema = 'osm' }) 25 | 26 | 27 | 28 | function clean_tags(tags) 29 | tags.odbl = nil 30 | tags.created_by = nil 31 | tags.source = nil 32 | tags['source:ref'] = nil 33 | 34 | return next(tags) == nil 35 | end 36 | 37 | 38 | function osm2pgsql.process_node(object) 39 | -- We are only interested in natural details 40 | if not object.tags.natural then 41 | return 42 | end 43 | 44 | clean_tags(object.tags) 45 | 46 | -- Using grab_tag() removes from remaining key/value saved to Pg 47 | local osm_type = object:grab_tag('natural') 48 | 49 | tables.natural:add_row({ 50 | tags = json.encode(object.tags), 51 | osm_type = osm_type, 52 | geom = { create = 'point' } 53 | }) 54 | 55 | end 56 | 57 | -- Change function name here 58 | function natural_process_way(object) 59 | -- We are only interested in highways 60 | if not object.tags.natural then 61 | return 62 | end 63 | 64 | clean_tags(object.tags) 65 | 66 | local osm_type = object:grab_tag('natural') 67 | 68 | 69 | if object.is_closed then 70 | tables.natural_polygon:add_row({ 71 | tags = json.encode(object.tags), 72 | osm_type = osm_type, 73 | geom = { create = 'area' } 74 | }) 75 | else 76 | tables.natural_line:add_row({ 77 | tags = json.encode(object.tags), 78 | osm_type = osm_type, 79 | geom = { create = 'line' } 80 | }) 81 | end 82 | 83 | end 84 | 85 | 86 | -- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244 87 | function deep_copy(obj) 88 | if type(obj) ~= 'table' then return obj end 89 | local res = setmetatable({}, getmetatable(obj)) 90 | for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end 91 | return res 92 | end 93 | 94 | 95 | if osm2pgsql.process_way == nil then 96 | -- Change function name here 97 | osm2pgsql.process_way = natural_process_way 98 | else 99 | local nested = osm2pgsql.process_way 100 | osm2pgsql.process_way = function(object) 101 | local object_copy = deep_copy(object) 102 | nested(object) 103 | -- Change function name here 104 | natural_process_way(object_copy) 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /flex-config/natural.sql: -------------------------------------------------------------------------------- 1 | COMMENT ON TABLE osm.natural_point IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/natural.lua'; 2 | COMMENT ON TABLE osm.natural_line IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/natural.lua'; 3 | COMMENT ON TABLE osm.natural_polygon IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/natural.lua'; 4 | 5 | 6 | ALTER TABLE osm.natural_point 7 | ADD CONSTRAINT pk_osm_natural_point_node_id 8 | PRIMARY KEY (node_id) 9 | ; 10 | ALTER TABLE osm.natural_line 11 | ADD CONSTRAINT pk_osm_natural_line_way_id 12 | PRIMARY KEY (way_id) 13 | ; 14 | ALTER TABLE osm.natural_polygon 15 | ADD CONSTRAINT pk_osm_natural_polygon_way_id 16 | PRIMARY KEY (way_id) 17 | ; 18 | 19 | 20 | CREATE INDEX ix_osm_natural_point_type ON osm.natural_point (osm_type); 21 | CREATE INDEX ix_osm_natural_line_type ON osm.natural_line (osm_type); 22 | CREATE INDEX ix_osm_natural_polygon_type ON osm.natural_polygon (osm_type); 23 | 24 | 25 | -------------------------------------------------------------------------------- /flex-config/road.lua: -------------------------------------------------------------------------------- 1 | -- Use JSON encoder 2 | local json = require('dkjson') 3 | 4 | local tables = {} 5 | 6 | tables.highways = osm2pgsql.define_way_table('road_line', 7 | { 8 | { column = 'osm_type', type = 'text', not_null = true }, 9 | { column = 'name', type = 'text' }, 10 | { column = 'ref', type = 'text' }, 11 | { column = 'maxspeed', type = 'int' }, 12 | { column = 'oneway', type = 'direction' }, 13 | { column = 'tags', type = 'jsonb' }, 14 | { column = 'geom', type = 'linestring' }, 15 | }, 16 | { schema = 'osm' } 17 | ) 18 | 19 | 20 | function clean_tags(tags) 21 | tags.odbl = nil 22 | tags.created_by = nil 23 | tags.source = nil 24 | tags['source:ref'] = nil 25 | 26 | return next(tags) == nil 27 | end 28 | 29 | 30 | -- Parse a maxspeed value like "30" or "55 mph" and return a number in km/h 31 | function parse_speed(input) 32 | -- from osm2pgsql/flex-config/data-types.lua 33 | if not input then 34 | return nil 35 | end 36 | 37 | local maxspeed = tonumber(input) 38 | 39 | -- If maxspeed is just a number, it is in km/h, so just return it 40 | if maxspeed then 41 | return maxspeed 42 | end 43 | 44 | -- If there is an 'mph' at the end, convert to km/h and return 45 | if input:sub(-3) == 'mph' then 46 | local num = tonumber(input:sub(1, -4)) 47 | if num then 48 | return math.floor(num * 1.60934) 49 | end 50 | end 51 | 52 | return nil 53 | end 54 | 55 | 56 | -- Change function name here 57 | function road_process_way(object) 58 | -- We are only interested in highways 59 | if not object.tags.highway then 60 | return 61 | end 62 | 63 | clean_tags(object.tags) 64 | 65 | -- Using grab_tag() removes from remaining key/value saved to Pg 66 | local name = object:grab_tag('name') 67 | local osm_type = object:grab_tag('highway') 68 | local ref = object:grab_tag('ref') 69 | -- in km/hr 70 | maxspeed = parse_speed(object.tags.maxspeed) 71 | 72 | oneway = object:grab_tag('oneway') or 0 73 | 74 | tables.highways:add_row({ 75 | tags = json.encode(object.tags), 76 | name = name, 77 | osm_type = osm_type, 78 | ref = ref, 79 | maxspeed = maxspeed, 80 | oneway = oneway, 81 | geom = { create = 'line' } 82 | }) 83 | 84 | end 85 | 86 | 87 | -- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244 88 | function deep_copy(obj) 89 | if type(obj) ~= 'table' then return obj end 90 | local res = setmetatable({}, getmetatable(obj)) 91 | for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end 92 | return res 93 | end 94 | 95 | 96 | if osm2pgsql.process_way == nil then 97 | -- Change function name here 98 | osm2pgsql.process_way = road_process_way 99 | else 100 | local nested = osm2pgsql.process_way 101 | osm2pgsql.process_way = function(object) 102 | local object_copy = deep_copy(object) 103 | nested(object) 104 | -- Change function name here 105 | road_process_way(object_copy) 106 | end 107 | end 108 | -------------------------------------------------------------------------------- /flex-config/road.sql: -------------------------------------------------------------------------------- 1 | COMMENT ON TABLE osm.road_line IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/road.lua'; 2 | COMMENT ON COLUMN osm.road_line.osm_type IS 'Value from "highway" key from OpenStreetMap data. e.g. motorway, residential, service, footway, etc.'; 3 | 4 | ALTER TABLE osm.road_line 5 | ADD CONSTRAINT pk_osm_road_line_way_id 6 | PRIMARY KEY (way_id) 7 | ; 8 | 9 | CREATE INDEX ix_osm_road_line_highway ON osm.road_line (osm_type); 10 | -------------------------------------------------------------------------------- /flex-config/road_major.lua: -------------------------------------------------------------------------------- 1 | -- Use JSON encoder 2 | local json = require('dkjson') 3 | 4 | local tables = {} 5 | 6 | tables.road_major = osm2pgsql.define_table({ 7 | name = 'road_major', 8 | schema = 'osm', 9 | ids = { type = 'way', id_column = 'osm_id' }, 10 | columns = { 11 | { column = 'osm_type', type = 'text', not_null = true }, 12 | { column = 'name', type = 'text' }, 13 | { column = 'ref', type = 'text' }, 14 | { column = 'maxspeed', type = 'int' }, 15 | { column = 'tags', type = 'jsonb' }, 16 | { column = 'geom', type = 'linestring' }, 17 | } 18 | }) 19 | 20 | 21 | function clean_tags(tags) 22 | tags.odbl = nil 23 | tags.created_by = nil 24 | tags.source = nil 25 | tags['source:ref'] = nil 26 | 27 | return next(tags) == nil 28 | end 29 | 30 | 31 | -- Parse a maxspeed value like "30" or "55 mph" and return a number in km/h 32 | function parse_speed(input) 33 | -- from osm2pgsql/flex-config/data-types.lua 34 | if not input then 35 | return nil 36 | end 37 | 38 | local maxspeed = tonumber(input) 39 | 40 | -- If maxspeed is just a number, it is in km/h, so just return it 41 | if maxspeed then 42 | return maxspeed 43 | end 44 | 45 | -- If there is an 'mph' at the end, convert to km/h and return 46 | if input:sub(-3) == 'mph' then 47 | local num = tonumber(input:sub(1, -4)) 48 | if num then 49 | return math.floor(num * 1.60934) 50 | end 51 | end 52 | 53 | return nil 54 | end 55 | 56 | 57 | -- Change function name here 58 | function road_major_process_way(object) 59 | -- We are only interested in highways 60 | if not object.tags.highway then 61 | return 62 | end 63 | 64 | -- Only major highways 65 | if not (object.tags.highway == 'motorway' 66 | or object.tags.highway == 'motorway_link' 67 | or object.tags.highway == 'primary' 68 | or object.tags.highway == 'primary_link' 69 | or object.tags.highway == 'secondary' 70 | or object.tags.highway == 'secondary_link' 71 | or object.tags.highway == 'tertiary' 72 | or object.tags.highway == 'tertiary_link' 73 | or object.tags.highway == 'trunk' 74 | or object.tags.highway == 'trunk_link') 75 | then 76 | return 77 | end 78 | 79 | clean_tags(object.tags) 80 | 81 | -- Using grab_tag() removes from remaining key/value saved to Pg 82 | local name = object:grab_tag('name') 83 | local osm_type = object:grab_tag('highway') 84 | local ref = object:grab_tag('ref') 85 | -- in km/hr 86 | maxspeed = parse_speed(object.tags.maxspeed) 87 | 88 | tables.road_major:add_row({ 89 | tags = json.encode(object.tags), 90 | name = name, 91 | osm_type = osm_type, 92 | ref = ref, 93 | maxspeed = maxspeed, 94 | geom = { create = 'line' } 95 | }) 96 | 97 | end 98 | 99 | 100 | -- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244 101 | function deep_copy(obj) 102 | if type(obj) ~= 'table' then return obj end 103 | local res = setmetatable({}, getmetatable(obj)) 104 | for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end 105 | return res 106 | end 107 | 108 | 109 | if osm2pgsql.process_way == nil then 110 | -- Change function name here 111 | osm2pgsql.process_way = road_major_process_way 112 | else 113 | local nested = osm2pgsql.process_way 114 | osm2pgsql.process_way = function(object) 115 | local object_copy = deep_copy(object) 116 | nested(object) 117 | -- Change function name here 118 | road_major_process_way(object_copy) 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /flex-config/road_major.sql: -------------------------------------------------------------------------------- 1 | COMMENT ON TABLE osm.road_major IS 'Generated by osm2pgsql Flex output using pgosm/flex-config/road.lua'; 2 | COMMENT ON COLUMN osm.road_major.osm_type IS 'Value from "highway" key from OpenStreetMap data. e.g. motorway, residential, etc.'; 3 | 4 | ALTER TABLE osm.road_major 5 | ADD CONSTRAINT pk_osm_road_major_osm_id 6 | PRIMARY KEY (osm_id) 7 | ; 8 | 9 | CREATE INDEX ix_osm_road_major_type ON osm.road_major (osm_type); 10 | -------------------------------------------------------------------------------- /flex-config/run-all.lua: -------------------------------------------------------------------------------- 1 | require "road" 2 | require "road_major" 3 | require "building" 4 | require "natural" 5 | require "traffic" 6 | -------------------------------------------------------------------------------- /flex-config/traffic.lua: -------------------------------------------------------------------------------- 1 | -- Use JSON encoder 2 | local json = require('dkjson') 3 | 4 | local tables = {} 5 | 6 | tables.traffic_point = osm2pgsql.define_node_table('traffic_point', { 7 | { column = 'osm_type', type = 'text', not_null = false }, 8 | { column = 'tags', type = 'jsonb' }, 9 | { column = 'geom', type = 'point' }, 10 | }, { schema = 'osm' }) 11 | 12 | 13 | tables.traffic_line = osm2pgsql.define_node_table('traffic_line', { 14 | { column = 'osm_type', type = 'text', not_null = false }, 15 | { column = 'tags', type = 'jsonb' }, 16 | { column = 'geom', type = 'point' }, 17 | }, { schema = 'osm' }) 18 | 19 | 20 | tables.traffic_polygon = osm2pgsql.define_node_table('traffic_polygon', { 21 | { column = 'osm_type', type = 'text', not_null = false }, 22 | { column = 'tags', type = 'jsonb' }, 23 | { column = 'geom', type = 'point' }, 24 | }, { schema = 'osm' }) 25 | 26 | function clean_tags(tags) 27 | tags.odbl = nil 28 | tags.created_by = nil 29 | tags.source = nil 30 | tags['source:ref'] = nil 31 | 32 | return next(tags) == nil 33 | end 34 | 35 | -- Change function name here 36 | function traffic_process_node(object) 37 | if not object.tags.highway and not object.tags.railway and not 38 | object.tags.barrier and not object.tags.traffic_calming and not 39 | object.tags.amenity then 40 | return 41 | end 42 | 43 | clean_tags(object.tags) 44 | 45 | if object.tags.highway == 'traffic_signals' 46 | or object.tags.highway == 'mini_roundabout' 47 | or object.tags.highway == 'stop' 48 | or object.tags.highway == 'crossing' 49 | or object.tags.highway == 'speed_camera' 50 | or object.tags.highway == 'motorway_junction' 51 | or object.tags.highway == 'turning_circle' 52 | or object.tags.highway == 'ford' 53 | or object.tags.highway == 'street_lamp' 54 | or object.tags.highway == 'services' 55 | then 56 | local osm_type = object:grab_tag('highway') 57 | 58 | tables.traffic_point:add_row({ 59 | tags = json.encode(object.tags), 60 | osm_type = osm_type, 61 | geom = { create = 'point' } 62 | }) 63 | 64 | elseif object.tags.railway == 'level_crossing' then 65 | local osm_type = 'crossing' 66 | 67 | tables.traffic_point:add_row({ 68 | tags = json.encode(object.tags), 69 | osm_type = osm_type, 70 | geom = { create = 'point' } 71 | }) 72 | 73 | elseif object.tags.barrier then 74 | local osm_type = object:grab_tag('barrier') 75 | 76 | tables.traffic_point:add_row({ 77 | tags = json.encode(object.tags), 78 | osm_type = osm_type, 79 | geom = { create = 'point' } 80 | }) 81 | 82 | elseif object.tags.traffic_calming then 83 | local osm_type = object:grab_tag('traffic_calming') 84 | 85 | tables.traffic_point:add_row({ 86 | tags = json.encode(object.tags), 87 | osm_type = osm_type, 88 | geom = { create = 'point' } 89 | }) 90 | 91 | elseif object.tags.amenity == 'fuel' 92 | or object.tags.amenity == 'parking' 93 | or object.tags.amenity == 'bicycle_parking' 94 | then 95 | local osm_type = object:grab_tag('amenity') 96 | 97 | tables.traffic_point:add_row({ 98 | tags = json.encode(object.tags), 99 | osm_type = osm_type, 100 | geom = { create = 'point' } 101 | }) 102 | 103 | else 104 | return 105 | end 106 | 107 | 108 | end 109 | 110 | 111 | --[[ 112 | FIXME: Repeat with Lines and Polyons 113 | --]] 114 | 115 | 116 | 117 | -- deep_copy based on copy2: https://gist.github.com/tylerneylon/81333721109155b2d244 118 | function deep_copy(obj) 119 | if type(obj) ~= 'table' then return obj end 120 | local res = setmetatable({}, getmetatable(obj)) 121 | for k, v in pairs(obj) do res[deep_copy(k)] = deep_copy(v) end 122 | return res 123 | end 124 | 125 | 126 | if osm2pgsql.process_node == nil then 127 | -- Change function name here 128 | osm2pgsql.process_node = traffic_process_node 129 | else 130 | local nested = osm2pgsql.process_node 131 | osm2pgsql.process_node = function(object) 132 | local object_copy = deep_copy(object) 133 | nested(object) 134 | -- Change function name here 135 | traffic_process_node(object_copy) 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /flex-config/unitable.lua: -------------------------------------------------------------------------------- 1 | -- Converted from https://github.com/openstreetmap/osm2pgsql/blob/master/flex-config/unitable.lua 2 | -- to use JSONB instead of HSTORE 3 | 4 | -- Put all OSM data into a single table 5 | local json = require('dkjson') 6 | 7 | -- inspect = require('inspect') 8 | 9 | -- We define a single table that can take any OSM object and any geometry. 10 | -- XXX expire will currently not work on these tables. 11 | local dtable = osm2pgsql.define_table{ 12 | name = "data", 13 | -- This will generate a column "osm_id INT8" for the id, and a column 14 | -- "osm_type CHAR(1)" for the type of object: N(ode), W(way), R(relation) 15 | ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' }, 16 | columns = { 17 | { column = 'attrs', type = 'jsonb' }, 18 | { column = 'tags', type = 'jsonb' }, 19 | { column = 'geom', type = 'geometry' }, 20 | } 21 | } 22 | 23 | -- print("columns=" .. inspect(dtable:columns())) 24 | 25 | -- Helper function to remove some of the tags we usually are not interested in. 26 | -- Returns true if there are no tags left. 27 | function clean_tags(tags) 28 | tags.odbl = nil 29 | tags.created_by = nil 30 | tags.source = nil 31 | tags['source:ref'] = nil 32 | 33 | return next(tags) == nil 34 | end 35 | 36 | function process(object, geometry_type) 37 | if clean_tags(object.tags) then 38 | return 39 | end 40 | dtable:add_row({ 41 | attrs = json.encode({ 42 | version = object.version, 43 | timestamp = object.timestamp, 44 | }), 45 | tags = json.encode(object.tags), 46 | geom = { create = geometry_type } 47 | }) 48 | end 49 | 50 | function osm2pgsql.process_node(object) 51 | process(object, 'point') 52 | end 53 | 54 | function osm2pgsql.process_way(object) 55 | process(object, 'line') 56 | end 57 | 58 | function osm2pgsql.process_relation(object) 59 | if clean_tags(object.tags) then 60 | return 61 | end 62 | 63 | if object.tags.type == 'multipolygon' or object.tags.type == 'boundary' then 64 | dtable:add_row({ 65 | attrs = json.encode({ 66 | version = object.version, 67 | timestamp = object.timestamp, 68 | }), 69 | tags = json.encode(object.tags), 70 | geom = { create = 'area' } 71 | }) 72 | end 73 | end 74 | 75 | -------------------------------------------------------------------------------- /pgosm/__init__.py: -------------------------------------------------------------------------------- 1 | """PgOSM module to make it easy to transform OpenStreetMap into 2 | improved PostGIS table structures.""" 3 | from pgosm.layers import process_layers 4 | from pgosm import travel_time_grid 5 | -------------------------------------------------------------------------------- /pgosm/config.py: -------------------------------------------------------------------------------- 1 | """Configuration for PgOSM runtime.""" 2 | import os 3 | 4 | 5 | try: 6 | DB_HOST = os.environ['DB_HOST'] 7 | except KeyError: 8 | DB_HOST = '127.0.0.1' 9 | msg = 'DB_HOST not set. Defaulting to {}'.format(DB_HOST) 10 | print(msg) 11 | 12 | 13 | try: 14 | DB_NAME, DB_USER = (os.environ['DB_NAME'], 15 | os.environ['DB_USER']) 16 | except KeyError: 17 | key_msg = ('Database environment variables not set.' 18 | 'All values are required for proper operation.\n' 19 | 'DB_NAME\nDB_USER') 20 | print(key_msg) 21 | DB_NAME, DB_USER = ('NotSet', 'Invalid') 22 | 23 | try: 24 | DB_PW = os.environ['DB_PW'] 25 | except KeyError: 26 | pw_msg = 'DB Password not set. Will attempt to use ~/.pgpass.' 27 | print(pw_msg) 28 | DB_PW = None 29 | 30 | try: 31 | DB_PORT = os.environ['DB_PORT'] 32 | except KeyError: 33 | DB_PORT = 5432 34 | msg = 'DB Port not set. Defaulting to 5432' 35 | print(msg) 36 | 37 | APP_NAME = 'PgOSM' 38 | 39 | def get_db_string(): 40 | """ Builds the database connection string based on set parameters. 41 | 42 | Returns 43 | -------------------- 44 | database_string : str 45 | Database string to use to establish psycopg2 connection. 46 | """ 47 | if DB_PW is None: 48 | database_string = 'postgresql://{user}@{host}:{port}/{dbname}?application_name={app_name}' 49 | 50 | return database_string.format(user=DB_USER, host=DB_HOST, 51 | port=DB_PORT, dbname=DB_NAME, 52 | app_name=APP_NAME) 53 | 54 | database_string = 'postgresql://{user}:{pw}@{host}:{port}/{dbname}?application_name={app_name}' 55 | return database_string.format(user=DB_USER, pw=DB_PW, host=DB_HOST, 56 | port=DB_PORT, dbname=DB_NAME, 57 | app_name=APP_NAME) 58 | 59 | 60 | DATABASE_STRING = get_db_string() 61 | 62 | -------------------------------------------------------------------------------- /pgosm/db.py: -------------------------------------------------------------------------------- 1 | """PgOSM database functions to easily interface with Postgres.""" 2 | import psycopg2 3 | import pandas as pd 4 | from pgosm import config 5 | 6 | 7 | def return_dataframe(sql_query, params=None, **kwargs): 8 | """Queries Postgres to return data in DataFrame. 9 | 10 | Parameters 11 | ---------------------- 12 | sql_query : str 13 | Query string to execute against database. Can be parameterized using dict 14 | format. 15 | 16 | params : list 17 | (Optional) Parameters to securely pass in to execute query. 18 | 19 | index_column : str 20 | Column to use as the Index of the returned DataFrame. 21 | 22 | Returns 23 | ---------------------- 24 | df : pandas.DataFrame 25 | Data returned from the query. 26 | """ 27 | conn = _get_conn() 28 | 29 | index_column = kwargs.get('index_column') 30 | 31 | if index_column: 32 | df = pd.read_sql(sql_query, conn, params=params, index_col=index_column) 33 | else: 34 | df = pd.read_sql(sql_query, conn, params=params) 35 | 36 | conn.close() 37 | return df 38 | 39 | 40 | def execute_no_results(sql_query, params=None): 41 | """Executes a DML query and commits the results, returning no records. 42 | 43 | Parameters 44 | ------------------- 45 | sql_query : str 46 | Query string to execute. 47 | 48 | params : list 49 | (Optional) Parameters to securely pass in to execute query. List format. 50 | """ 51 | conn = _get_conn() 52 | cur = conn.cursor() 53 | cur.execute(sql_query, params) 54 | conn.commit() 55 | conn.close() 56 | 57 | 58 | def _get_conn(): 59 | """Establishes Postgres connection to execute SQL queries. 60 | 61 | Returns 62 | --------------- 63 | conn : psycopg2.connection 64 | """ 65 | try: 66 | conn = psycopg2.connect(config.DATABASE_STRING) 67 | except psycopg2.OperationalError as e: 68 | subject = 'DB Connection Error - App: {}'.format(config.APP_NAME) 69 | body = 'Database connection error. {}'.format(e) 70 | err_msg = '{}\n{}'.format(subject, body) 71 | print(err_msg) 72 | return False 73 | return conn 74 | -------------------------------------------------------------------------------- /pgosm/file_manager.py: -------------------------------------------------------------------------------- 1 | """Simple file management for PgOSM.""" 2 | import os 3 | 4 | 5 | def remove_file(file_path): 6 | """ Ensures SQL Output file doesn't exist. 7 | 8 | Should be executed before building SQL output. 9 | 10 | Parameters 11 | -------------------- 12 | file_path : str 13 | Path of the file to remove. 14 | """ 15 | try: 16 | os.remove(file_path) 17 | except OSError: 18 | print('File "{}" did not exist, nothing to remove.'.format(file_path)) 19 | 20 | 21 | def write_to_file(file_path, txt, extra_lb=True): 22 | """Used to write SQL command to SQL output file. 23 | 24 | Uses append mode (`a+`). Writes line breaks before and after the `txt`. 25 | 26 | Parameters 27 | -------------------- 28 | file_path : str 29 | File path to write, should include extension (e.g. `/path/to/file.sql`) 30 | 31 | txt : str 32 | Text to write to file. 33 | 34 | extra_lb : boolean 35 | Default `True`. Write extra preceeding line break before the text block. 36 | """ 37 | with open(file_path, 'a+') as f: 38 | lb = '\n' 39 | if extra_lb: 40 | f.write(lb) 41 | f.write(txt) 42 | f.write(lb) 43 | 44 | 45 | def read_file(file_path): 46 | """Reads file at `file_path` in read-only mode. 47 | 48 | Parameters 49 | ----------------- 50 | file_path : str 51 | Path of file to read. 52 | 53 | data : str 54 | Data read from file. 55 | """ 56 | with open(file_path, 'r') as f: 57 | data = f.read() 58 | 59 | return data 60 | -------------------------------------------------------------------------------- /pgosm/layers.py: -------------------------------------------------------------------------------- 1 | '''Generates SQL queries to build OSM layer tables from Geofabrik export loaded via osm2pgsql. 2 | 3 | Module to create OSM layers as defined in the layers table in the database. 4 | 5 | Execute `process_layers()` to run module. 6 | ''' 7 | import time 8 | import datetime 9 | from pgosm import file_manager, db 10 | 11 | 12 | OUTPUT_DIR = 'output/' 13 | SQL_OUTPUT_FILENAME = 'create_pgosm_layers.sql' 14 | SQL_OUTPUT_PATH = OUTPUT_DIR + SQL_OUTPUT_FILENAME 15 | 16 | print('Output Path: {}'.format(SQL_OUTPUT_PATH)) 17 | 18 | def process_layers(schema='osm', generate_only=False): 19 | """ Main Entry point to run process to run PgOSM module. 20 | 21 | Parameters 22 | ----------------- 23 | schema : str 24 | Schema name to create. Will DROP if exists. Default='osm'. 25 | 26 | generate_only : boolean 27 | When False (default) the generated SQL script is executed. 28 | """ 29 | start_time = time.time() 30 | print('Starting PgOSM processing...') 31 | 32 | file_manager.remove_file(SQL_OUTPUT_PATH) 33 | 34 | create_osm_schema(schema=schema) 35 | generate_layers(schema=schema, generate_only=generate_only) 36 | 37 | end_time = time.time() 38 | 39 | msg = 'Finished PgOSM processing. Total time elapsed: {} seconds.' 40 | elapsed = round((end_time - start_time), 1) 41 | print(msg.format(elapsed)) 42 | 43 | 44 | def create_osm_schema(schema): 45 | """Generates SQL to create an empty schema. 46 | 47 | WARNING: Drops existing schema! 48 | 49 | Parameters 50 | ------------------ 51 | schema : str 52 | Schema name to drop (if exists) and create. 53 | """ 54 | sql = 'DROP SCHEMA IF EXISTS {} CASCADE;'.format(schema) 55 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql) 56 | sql = 'CREATE SCHEMA {};'.format(schema) 57 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql) 58 | 59 | created = datetime.datetime.now() 60 | created = created.strftime("%A %Y-%m-%d") 61 | schema_comment = 'PgOSM generated on {}. '.format(created) 62 | schema_comment += 'Contains reformatted OpenStreetMap data.' 63 | sql = "COMMENT ON SCHEMA {schema} IS '{comment}';" 64 | sql = sql.format(schema=schema, comment=schema_comment) 65 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql) 66 | 67 | 68 | def generate_layers(schema='osm', generate_only=False): 69 | """Generates and (optionally) executes SQL to transform OpenStreetMap data. 70 | 71 | Parameters 72 | -------------------- 73 | schema : str 74 | Schema name (e.g. `osm`) to save transformed data. 75 | 76 | generate_only : boolean 77 | Default False. If True, the SQL to perform the transformation is 78 | generated but **not** executed. 79 | """ 80 | generate_sql_for_layers(schema=schema) 81 | 82 | if generate_only: 83 | print('Generate only. NOT executing scipt.') 84 | else: 85 | print('Executing SQL Script...') 86 | raw_sql = file_manager.read_file(SQL_OUTPUT_PATH) 87 | db.execute_no_results(raw_sql) 88 | print('Executing SQL Script completed.') 89 | 90 | def generate_sql_for_layers(schema='osm'): 91 | """Queries the `pgosm` schema and generates the SQL to transform OpenStreetMap data. 92 | 93 | Parameters 94 | -------------------- 95 | schema : str 96 | Schema name (e.g. `osm`) to save transformed data. 97 | """ 98 | layers = get_layers() 99 | print('{} layers returned'.format(len(layers))) 100 | 101 | for layer_group_id, data in layers.iterrows(): 102 | layer_columns = data['osm_columns'] 103 | layer_name = data['name'] 104 | description = data['description'] 105 | 106 | process_layer_classes(layer_group_id, schema, layer_name, 107 | layer_columns, description) 108 | 109 | 110 | def get_layers(): 111 | """Queries the `pgosm.layer_group` table for details needed to generate transformations. 112 | 113 | Returns 114 | --------------- 115 | layers : pandas.DataFrame 116 | """ 117 | sql = 'SELECT layer_group_id, class AS name, osm_columns, description ' 118 | sql += ' FROM pgosm.layer_group ' 119 | layers = db.return_dataframe(sql, index_column='layer_group_id') 120 | return layers 121 | 122 | 123 | def process_layer_classes(layer_group_id, schema, layer_name, 124 | layer_columns, description): 125 | """FIXME: Add docblock!""" 126 | print('Processing layer %s (layer_group_id=%s).' % (layer_name, layer_group_id)) 127 | layer_classes = get_layer_classes(layer_group_id) 128 | 129 | combined_filter = dict() 130 | geom_point = False 131 | geom_line = False 132 | geom_polygon = False 133 | 134 | for layer_cat_id, lc in layer_classes.iterrows(): 135 | combined_filter[lc['code']] = lc['osm_tag_filter'] 136 | if lc['geom_point']: 137 | geom_point = True 138 | if lc['geom_line']: 139 | geom_line = True 140 | if lc['geom_polygon']: 141 | geom_polygon = True 142 | 143 | if (len(combined_filter) < 1): 144 | print('Stopping process_layer_classes(), no combined_filter.') 145 | return 146 | 147 | sql_filter = build_combined_filter_OR(combined_filter) 148 | sql_case_stmt = build_combined_case_statement(combined_filter) 149 | 150 | columns = str(layer_columns) + ', ' + str(sql_case_stmt) 151 | 152 | table_base = '%s.%s_%s' 153 | 154 | # Create as many layers as are specified 155 | if geom_point: 156 | geom_type = 'point' 157 | table_name = table_base % (schema, layer_name, geom_type) 158 | create_layer_sql(table_name, columns, sql_filter, 159 | geom_type, description) 160 | if geom_line: 161 | geom_type = 'line' 162 | table_name = table_base % (schema, layer_name, geom_type) 163 | create_layer_sql(table_name, columns, sql_filter, 164 | geom_type, description) 165 | if geom_polygon: 166 | geom_type = 'polygon' 167 | table_name = table_base % (schema, layer_name, geom_type) 168 | create_layer_sql(table_name, columns, sql_filter, 169 | geom_type, description) 170 | 171 | 172 | def create_layer_sql(table_name, columns, sql_filter, 173 | geom_type, description): 174 | """FIXME: Add docblock!""" 175 | sql = 'SELECT ' + str(columns) 176 | 177 | if geom_type == 'point': 178 | sql += ' FROM public.planet_osm_point WHERE ' 179 | if geom_type == 'line': 180 | sql += ' FROM public.planet_osm_line WHERE ' 181 | if geom_type == 'polygon': 182 | sql += ' FROM public.planet_osm_polygon WHERE ' 183 | 184 | sql += ' ' + str(sql_filter) 185 | 186 | sql_create = 'CREATE TABLE {} AS '.format(table_name) 187 | sql_create += sql + ';' 188 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql_create) 189 | 190 | index_name = 'gix_{}'.format(table_name.replace('.', '_')) 191 | sql_index = 'CREATE INDEX {index_name} ON {table_name} USING GIST (way);' 192 | sql_index = sql_index.format(index_name=index_name, table_name=table_name) 193 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql_index) 194 | 195 | created = datetime.datetime.now() 196 | created = created.strftime("%A %Y-%m-%d") 197 | table_comment = 'PgOSM generated on {}. {}'.format(created, description) 198 | sql_comment = "COMMENT ON TABLE {table_name} is '{comment}'; " 199 | sql_comment = sql_comment.format(table_name=table_name, 200 | comment=table_comment) 201 | file_manager.write_to_file(SQL_OUTPUT_PATH, sql_comment) 202 | 203 | def get_layer_classes(layer_group_id): 204 | """FIXME: Add docblock!""" 205 | sql = 'SELECT layer_detail_id, code, subclass, geom_point, geom_line, ' 206 | sql += ' geom_polygon, osm_tag_filter, description ' 207 | sql += ' FROM pgosm.layer_detail ' 208 | sql += ' WHERE layer_group_id = %(layer_group_id)s' 209 | params = {'layer_group_id': layer_group_id} 210 | 211 | layer_classes = db.return_dataframe(sql, params, index_column='layer_detail_id') 212 | return layer_classes 213 | 214 | 215 | def build_combined_filter_OR(filter_sets): 216 | """FIXME: Add docblock!""" 217 | i = 0 218 | rows = list(filter_sets.values()) 219 | for row in rows: 220 | if i == 0: 221 | sql = '(' + row + ')' 222 | else: 223 | sql += ' OR (' + row + ') ' 224 | i += 1 225 | return sql 226 | 227 | 228 | def build_combined_case_statement(filter_sets): 229 | """FIXME: Add docblock!""" 230 | sql = 'CASE ' 231 | for key, value in filter_sets.items(): 232 | sql += " WHEN (%s) THEN '%s' " % (value, key) 233 | 234 | sql += ' END AS code ' 235 | return sql 236 | -------------------------------------------------------------------------------- /pgosm/travel_time_grid.py: -------------------------------------------------------------------------------- 1 | """Provides custom processing for calculating travel times across a grid of points. 2 | 3 | See pgosm/travel_time_grid.md for details. 4 | """ 5 | import datetime 6 | from pgosm import db 7 | 8 | 9 | def get_sql(): 10 | """Returns the raw SQL for the query needed. 11 | 12 | Returns 13 | ----------------------- 14 | sql_raw : str 15 | """ 16 | sql_raw = """ 17 | -- Building on CTE above, adding in process of getting agg cost 18 | WITH start_point AS ( 19 | SELECT a.id 20 | FROM pgosm.routing_roads_noded_vertices_pgr a 21 | INNER JOIN pgosm.travel_start b ON True 22 | ORDER BY a.the_geom <-> b.way 23 | LIMIT 1 24 | ), grid_end AS ( 25 | SELECT id, way 26 | FROM pgosm.travel_grid 27 | WHERE travel_minutes IS NULL 28 | AND route 29 | LIMIT 1 -- Only one grid point at a time 30 | ), end_point AS ( 31 | SELECT b.id AS grid_id, a.id 32 | FROM pgosm.routing_roads_noded_vertices_pgr a 33 | INNER JOIN pgosm.travel_grid b ON b.id = %s 34 | ORDER BY a.the_geom <-> b.way 35 | LIMIT 1 -- KNN for single grid point 36 | ), points AS ( 37 | SELECT s.id AS start_id, e.id AS end_id, e.grid_id 38 | FROM end_point e 39 | INNER JOIN start_point s ON True 40 | ), calc_cost AS ( 41 | SELECT p.*, c.agg_cost, 42 | CASE WHEN c.agg_cost IS NOT NULL THEN True 43 | ELSE False 44 | END AS route 45 | FROM points p 46 | LEFT JOIN pgr_dijkstraCost('SELECT id, source, target, 47 | cost_minutes AS cost 48 | FROM pgosm.routing_roads_noded ', 49 | p.start_id, 50 | p.end_id, 51 | False) c 52 | ON True 53 | ) 54 | UPDATE pgosm.travel_grid grid 55 | SET travel_minutes = agg_cost, 56 | route = c.route 57 | FROM calc_cost c 58 | WHERE grid.id = c.grid_id 59 | ; 60 | """ 61 | return sql_raw 62 | 63 | 64 | def record_count(): 65 | """Queries `pgosm.travel_grid` for count of available points not yet calculated. 66 | 67 | Returns 68 | ------------------- 69 | remaining_rows : int 70 | Number of remaining rows to process from pgosm.travel_grid table. 71 | """ 72 | check_query_sql = """SELECT COUNT(*) cnt 73 | FROM pgosm.travel_grid 74 | WHERE travel_minutes IS NULL AND route AND not_claimed; 75 | """ 76 | results = db.return_dataframe(check_query_sql) 77 | remaining_rows = results['cnt'][0] 78 | return remaining_rows 79 | 80 | 81 | def record_remaining(print_interval): 82 | """Checks for remaining records, printing every N (`print_interval`) rows. 83 | 84 | Parameters 85 | ------------------ 86 | print_interval : int 87 | 88 | Returns 89 | ------------------ 90 | status : boolean 91 | """ 92 | remaining_rows = record_count() 93 | if remaining_rows % print_interval == 0: 94 | print(remaining_rows) 95 | if remaining_rows > 0: 96 | return True 97 | return False 98 | 99 | 100 | def _grid_id(): 101 | """Claims grid record for processing. 102 | 103 | Returns 104 | --------------- 105 | grid_id : int 106 | Primary key id for point to process 107 | """ 108 | claim_grid_sql = """ 109 | WITH claim AS ( 110 | SELECT id 111 | FROM pgosm.travel_grid 112 | WHERE travel_minutes IS NULL 113 | AND route 114 | AND not_claimed 115 | LIMIT 1 -- Only one grid point at a time 116 | ) 117 | UPDATE pgosm.travel_grid gg 118 | SET not_claimed = False 119 | FROM claim c 120 | WHERE c.id = gg.id 121 | RETURNING c.id 122 | ; 123 | """ 124 | results = db.return_dataframe(claim_grid_sql) 125 | grid_id = int(results['id'][0]) 126 | return grid_id 127 | 128 | def _process_points(print_interval): 129 | while record_remaining(print_interval): 130 | grid_id = _grid_id() 131 | params = [grid_id] 132 | db.execute_no_results(get_sql(), params) 133 | 134 | def run(print_interval=250): 135 | starttime = datetime.datetime.now() 136 | print(f'Started: {starttime}') 137 | num_records = record_count() 138 | print(f'Starting record count: {num_records}') 139 | if num_records == 0: 140 | raise ValueError('No records to process.') 141 | 142 | print(f'Starting processing...') 143 | _process_points(print_interval) 144 | 145 | endtime = datetime.datetime.now() 146 | delta = endtime - starttime 147 | elapsed = delta.total_seconds() 148 | print(f'Completed: {endtime}') 149 | print(f'{elapsed} seconds') 150 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | coverage==5.1 2 | ipython==7.15.0 3 | numpy==1.18.4 4 | pandas==1.0.4 5 | psycopg2==2.8.5 6 | psycopg2-binary==2.8.5 7 | python-dateutil==2.8.1 8 | pytest==5.4.2 9 | pytz==2020.1 10 | six==1.15.0 11 | Sphinx==3.2.1 12 | sphinx-autoapi==1.3.0 13 | sphinx-git==11.0.0 14 | sphinx-rtd-theme==0.5.0 15 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Unit Tests 2 | 3 | More unit tests will be added. 4 | 5 | Run unit tests w/ Coverage 6 | 7 | ```bash 8 | source ~/venv/pgosm/bin/activate 9 | cd ~/git/pgosm 10 | coverage run -m unittest tests/*.py 11 | 12 | coverage report -m pgosm/*.py 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustprooflabs/pgosm/aa5cf808119ede1a5089d051baeb637f11e6d7e2/tests/__init__.py -------------------------------------------------------------------------------- /tests/pgosm_file_manager_test.py: -------------------------------------------------------------------------------- 1 | """ Unit tests to cover the Arduino Station module.""" 2 | import unittest 3 | from pgosm import file_manager 4 | 5 | 6 | class PgOSMFileManagerTests(unittest.TestCase): 7 | 8 | def test_write_to_file_and_read_file_match_results(self): 9 | ## FIXME: Testing three functions as one 10 | file_path = 'test_file_write_read.txt' 11 | content = 'ZZ This is a Test ZZ :-)' 12 | 13 | #Ensure clean starting 14 | file_manager.remove_file(file_path) 15 | file_manager.write_to_file(file_path, content) 16 | returned = file_manager.read_file(file_path) 17 | 18 | #Cleanup after yourself 19 | file_manager.remove_file(file_path) 20 | expected = '\n{}\n'.format(content) 21 | self.assertEqual(expected, returned) 22 | 23 | -------------------------------------------------------------------------------- /travel_time_grid.md: -------------------------------------------------------------------------------- 1 | # PgOSM: Travel time grid 2 | 3 | Use OSM roads data to generate drive time grid around a central point. 4 | 5 | Assumes starting data is in SRID 3857, end result is 3857. 6 | 7 | Assumes OSM data has already been ran 8 | through the main PgOSM process with data saved in the default 9 | `osm` schema. If you loaded data into a different schema you 10 | must the following code accordingly. 11 | 12 | ## Determine radius for grid 13 | 14 | First you must determine how far out to create the grid from 15 | the center point. Converting max MPH to max number of meters able to travel in given amount of minutes. 16 | 17 | This step handles converting a target max MPH (assuming U.S.) 18 | and converts that into the number of meters that could be traveled 19 | in a given time. 20 | 21 | ```sql 22 | -- Determine how far to make grid for 15 minute travel time 23 | SELECT 75 /*mph*/ 24 | * 0.25 /* Convert to miles per 15 min */ 25 | * 1.609344 /* Convert to km */ 26 | * 1000 /* Convert to meters */ 27 | ; 28 | -- 30175 is the max # of meters to travel in 15 minutes at 75 mph. 29 | ``` 30 | 31 | Now convert into # of grids, based on prior result and distance between grid points. Reduced by a percentage of total distance, constant max speed is unlikely in most analysis. 32 | 33 | ```sql 34 | -- # OF grids to extend, result goes into generate_series as min (-) and max (+) 35 | SELECT 30175 /* Result from prior query */ 36 | / 250 /* meters between points in grid, value re-used later */ 37 | * .90 /* Only go out 90% of max, optional time-saving reduction */ 38 | ; 39 | ``` 40 | 41 | ## Setup 42 | 43 | 44 | Create Start point and Grid 45 | 46 | ```sql 47 | -- Ensure start point and grid tables don't exist 48 | DROP TABLE IF EXISTS pgosm.travel_start; 49 | DROP TABLE IF EXISTS pgosm.travel_grid; 50 | ``` 51 | 52 | ### Start Point 53 | 54 | ```sql 55 | -- Example showing creating point from specific building polygon 56 | CREATE TABLE pgosm.travel_start AS 57 | SELECT ST_Centroid(way) AS way 58 | FROM osm.building_polygon b 59 | WHERE b.name = 'Coors Field' 60 | ; 61 | ``` 62 | 63 | 64 | ### Grid 65 | 66 | First step transforms to SRID 4326 so it can be casted to GEOGRAPHY in order to take advantage of ST_Project(). 67 | 68 | ```sql 69 | -- Create grid 70 | CREATE TABLE pgosm.travel_grid AS 71 | WITH start_point AS ( 72 | SELECT ST_Transform(ST_Centroid(way), 4326)::GEOGRAPHY AS way 73 | FROM pgosm.travel_start 74 | ), west_grid AS ( 75 | SELECT ST_Project(way, s.a * 250, PI() / 2) AS way 76 | FROM start_point sp 77 | JOIN generate_series(-10, 10, 1) AS s(a) ON True 78 | ) 79 | SELECT ROW_NUMBER() OVER () AS id, 80 | ST_Transform(ST_Project(wg.way, s.a * 250, 0)::GEOMETRY, 3857) AS way 81 | FROM west_grid wg 82 | JOIN generate_series(-10, 10, 1) AS s(a) ON True 83 | ; 84 | 85 | ALTER TABLE pgosm.travel_grid 86 | ADD CONSTRAINT PK_pgosm_travel_grid 87 | PRIMARY KEY (id); 88 | 89 | CREATE INDEX GIX_pgosm_travel_grid ON pgosm.travel_grid 90 | USING GIST (way); 91 | ``` 92 | 93 | 94 | Add additional columns 95 | 96 | ```sql 97 | -- Add columns GRID 98 | ALTER TABLE pgosm.travel_grid ADD route BOOLEAN DEFAULT True; 99 | ALTER TABLE pgosm.travel_grid ADD travel_minutes INT NULL; 100 | ALTER TABLE pgosm.travel_grid ADD not_claimed BOOLEAN DEFAULT True; 101 | ``` 102 | 103 | 104 | ## Roads for Routing 105 | 106 | > Note: Load data from `db/data/routable.sql` before running this code! 107 | 108 | ```sql 109 | DROP TABLE IF EXISTS pgosm.routing_roads; 110 | CREATE TABLE pgosm.routing_roads AS 111 | SELECT r.osm_id AS id, r.name, r.traffic, r.highway, r.ref, 112 | ld.layer_detail_id, r.code, 113 | ST_Length(r.way)::DOUBLE PRECISION AS cost_length, 114 | r.way AS the_geom 115 | FROM (SELECT ST_Envelope(ST_Union(way)) AS way 116 | FROM pgosm.travel_grid g 117 | WHERE g.route 118 | ) b 119 | INNER JOIN osm.road_line r 120 | ON ST_Contains(b.way, r.way) 121 | OR ST_Intersects(b.way, r.way) 122 | INNER JOIN pgosm.layer_group lg ON lg.class = 'road' 123 | INNER JOIN pgosm.layer_detail ld 124 | ON ld.layer_group_id = lg.layer_group_id 125 | AND r.code = ld.code 126 | INNER JOIN pgosm.routable rbl 127 | ON ld.layer_detail_id = rbl.layer_detail_id 128 | AND rbl.route_motor 129 | ; 130 | 131 | CREATE INDEX GIX_pgosm_routing_roads ON pgosm.routing_roads 132 | USING GIST (the_geom); 133 | ``` 134 | 135 | 136 | Identify obvious non-route 137 | Numeric value in `ST_DWithin()` is distance between grid minus 1. 138 | 139 | ```sql 140 | -- Find not-routable roads 141 | UPDATE pgosm.travel_grid 142 | SET route = False 143 | WHERE id IN ( 144 | SELECT g.id 145 | FROM pgosm.travel_grid g 146 | LEFT JOIN pgosm.routing_roads r 147 | ON ST_DWithin(r.the_geom, g.way, 249) 148 | WHERE r.id IS NULL 149 | ) 150 | ; 151 | ``` 152 | 153 | > Note: The number used in `ST_DWithin()` should be grid distance (N) minus one (N-1). 154 | 155 | ### Prepare Routing 156 | 157 | ```sql 158 | DROP TABLE IF EXISTS pgosm.routing_roads_noded; 159 | DROP TABLE IF EXISTS pgosm.routing_roads_noded_vertices_pgr; 160 | ``` 161 | 162 | ```sql 163 | -- Expensive step! 164 | SELECT pgr_nodeNetwork('pgosm.routing_roads', 1); 165 | 166 | -- Expensive step! 167 | SELECT pgr_createTopology('pgosm.routing_roads_noded', 0.1); 168 | SELECT pgr_analyzegraph('pgosm.routing_roads_noded', 0.1); 169 | ``` 170 | 171 | Add columns 172 | 173 | ```sql 174 | ALTER TABLE pgosm.routing_roads_noded ADD cost_length DOUBLE PRECISION NULL; 175 | ALTER TABLE pgosm.routing_roads_noded ADD layer_detail_id INT NULL; 176 | ALTER TABLE pgosm.routing_roads_noded ADD code TEXT NULL; 177 | ALTER TABLE pgosm.routing_roads_noded ADD cost_minutes DOUBLE PRECISION NULL; 178 | 179 | -- Update noded with costs and sub-class code 180 | UPDATE pgosm.routing_roads_noded rn 181 | SET cost_length = ST_Length(rn.the_geom)::DOUBLE PRECISION, 182 | code = r.code, 183 | layer_detail_id = r.layer_detail_id, 184 | cost_minutes = ST_Length(rn.the_geom)::DOUBLE PRECISION / (rbl.max_speed / 60 * 1.609344 * 1000) 185 | FROM pgosm.routing_roads r 186 | INNER JOIN pgosm.routable rbl ON r.layer_detail_id = rbl.layer_detail_id 187 | WHERE rn.old_id = r.id 188 | ; 189 | ``` 190 | 191 | Remove nodes without routes (missing source) or costs. 192 | 193 | 194 | ```sql 195 | DELETE FROM pgosm.routing_roads_noded WHERE source IS NULL; 196 | DELETE FROM pgosm.routing_roads_noded WHERE cost_minutes IS NULL; 197 | ``` 198 | 199 | 200 | 201 | 202 | ## Run 203 | 204 | 205 | 206 | ```bash 207 | python -c "import pgosm; pgosm.travel_time_grid.run();" 208 | ``` 209 | 210 | --------------------------------------------------------------------------------