Custom OSM maps with TileMill
Spent the morning working on creating custom maps of Haida Gwaii. One workflow for doing this involves pulling down OSM data for BC, subsetting it to Haida Gwaii, building up a PostgreSQL database and then building a TileMill project from there.
postgres@basalt /tmp/osmosis $ createdb bc_osm postgres@basalt /tmp/osmosis $ psql -d bc_osm psql (9.3.5) Type "help" for help. bc_osm=# create extension postgis; CREATE EXTENSION bc_osm=# create extension hstore; CREATE EXTENSION bc_osm=# grant all privileges on database bc_osm to james; GRANT bc_osm=# \q postgres@basalt /tmp/osmosis $ exit james@basalt /tmp/osmosis $ psql -d bc_osm -f script/pgsnapshot_schema_0.6.sql psql:script/pgsnapshot_schema_0.6.sql:4: NOTICE: table "actions" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:5: NOTICE: table "users" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:6: NOTICE: table "nodes" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:7: NOTICE: table "ways" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:8: NOTICE: table "way_nodes" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:9: NOTICE: table "relations" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:10: NOTICE: table "relation_members" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:11: NOTICE: table "schema_info" does not exist, skipping DROP TABLE psql:script/pgsnapshot_schema_0.6.sql:14: NOTICE: function osmosisupdate() does not exist, skipping DROP FUNCTION CREATE TABLE CREATE TABLE CREATE TABLE addgeometrycolumn ------------------------------------------------ public.nodes.geom SRID:4326 TYPE:POINT DIMS:2 (1 row) CREATE TABLE CREATE TABLE CREATE TABLE CREATE TABLE INSERT 0 1 ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE CREATE INDEX CREATE INDEX CREATE INDEX CLUSTER CREATE FUNCTION CREATE FUNCTION james@basalt /tmp/osmosis $ psql -d bc_osm -f script/pgsnapshot_schema_0.6_linestring.sql addgeometrycolumn -------------------------------------------------------- public.ways.linestring SRID:4326 TYPE:GEOMETRY DIMS:2 (1 row) CREATE INDEX CLUSTER james@basalt /tmp/osmosis $ psql -d bc_osm -f script/pgsnapshot_schema_0.6_bbox.sql addgeometrycolumn -------------------------------------------------- public.ways.bbox SRID:4326 TYPE:GEOMETRY DIMS:2 (1 row) CREATE INDEX CLUSTER CREATE FUNCTION CREATE AGGREGATE james@basalt /tmp/osmosis $ bin/osmosis --read-pbf file="/home/james/data/gis/osm/british-columbia-latest.osm.pbf" --bounding-box left="134.2529297" right="-130.3857422" top="54.5083265" bottom="51.6316573" --write-pgsql user="james" database="bc_osm" password='****' Oct 05, 2014 10:22:23 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Osmosis Version 0.43.1 Oct 05, 2014 10:22:23 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Preparing pipeline. Oct 05, 2014 10:22:23 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Launching pipeline execution. Oct 05, 2014 10:22:23 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Pipeline executing, waiting for completion. Oct 05, 2014 10:23:53 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Pipeline complete. Oct 05, 2014 10:23:53 AM org.openstreetmap.osmosis.core.Osmosis run INFO: Total execution time: 89892 milliseconds. james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f assemble_multipolygon.sql CREATE FUNCTION james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f build_multipolygon.sql CREATE FUNCTION james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f make_multipolygon.sql CREATE FUNCTION james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f tags_merge.sql CREATE FUNCTION CREATE FUNCTION CREATE FUNCTION CREATE FUNCTION james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f update.sql CREATE FUNCTION james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f create.sql psql:create.sql:1: NOTICE: table "multipolygons" does not exist, skipping DROP TABLE CREATE TABLE addgeometrycolumn ----------------------------------------------------------- public.multipolygons.geom SRID:4326 TYPE:GEOMETRY DIMS:2 (1 row) CREATE INDEX
Mostly works great, until you run into rendering a multi-polygon that is actually a single polygon with more than one outer linestring (due to the constraint of 2000 nodes per way). You can try and use osmosis-multipolygon:
james@basalt ~/code/git/osmosis-multipolygon $ psql -d bc_osm -f assemble.sql psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: 0 elements input array CONTEXT: PL/pgSQL function make_multipolygon(geometry[]) line 55 at RETURN PL/pgSQL function build_multipolygon(geometry[],geometry[]) line 17 at assignment SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment psql:assemble.sql:4: NOTICE: multipolygon consists of 2827 (more then 256) inner members ... ignore CONTEXT: SQL statement "SELECT build_multipolygon( (select array_agg((select linestring from ways where ways.id=outer_id)) from unnest(outer_members) outer_id), (select array_agg((select linestring from ways where ways.id=member_id)) from relation_members where relation_id=id and member_type='W' and member_role in ('inner', 'enclave') group by relation_id))" PL/pgSQL function assemble_multipolygon(bigint) line 40 at assignment
But it appears to fail on the large polygons anyways. At least, after running this and switching store to the new table, none of the large polygons even rendered (probably b/c they were not inserted).
Let’s try a different tack and use osm2pgsql. It seem to be more modern and more maintained.
postgres@basalt /home/james/code/git/osmosis-multipolygon $ createdb hg_osm postgres@basalt /home/james/code/git/osmosis-multipolygon $ psql -d hg_osm psql (9.3.5) Type "help" for help. hg_osm=# create extension postgis; CREATE EXTENSION hg_osm=# create extension hstore; CREATE EXTENSION hg_osm=# grant all privileges on database hg_osm to james; GRANT hg_osm=# \q james@basalt ~/code/git/osmosis-multipolygon $ osm2pgsql --create --database hg_osm -j -l --bbox -134.2529272,51.6316573,-130.3857422,54.5083265 /home/james/data/gis/osm/british-columbia-latest.osm.pbf osm2pgsql SVN version 0.84.0 (64bit id space) Using projection SRS 4326 (Latlong) Applying Bounding box: -134.252927,51.631657 to -130.385742,54.508327 Setting up table: planet_osm_point NOTICE: table "planet_osm_point" does not exist, skipping NOTICE: table "planet_osm_point_tmp" does not exist, skipping Setting up table: planet_osm_line NOTICE: table "planet_osm_line" does not exist, skipping NOTICE: table "planet_osm_line_tmp" does not exist, skipping Setting up table: planet_osm_polygon NOTICE: table "planet_osm_polygon" does not exist, skipping NOTICE: table "planet_osm_polygon_tmp" does not exist, skipping Setting up table: planet_osm_roads NOTICE: table "planet_osm_roads" does not exist, skipping NOTICE: table "planet_osm_roads_tmp" does not exist, skipping Using built-in tag processing pipeline Allocating memory for dense node cache Allocating dense node cache in one big chunk Allocating memory for sparse node cache Sharing dense sparse Node-cache: cache=800MB, maxblocks=102400*8192, allocation method=3 Mid: Ram, scale=10000000 Reading in file: /home/james/data/gis/osm/british-columbia-latest.osm.pbf Processing: Node(2352k 470.4k/s) Way(2107k 175.60k/s) Relation(17870 2552.86/s) parse time: 24s Node stats: total(2352081), max(3040762750) in 5s Way stats: total(2107220), max(306291660) in 12s Relation stats: total(17871), max(4085024) in 7s Committing transaction for planet_osm_point Committing transaction for planet_osm_line Committing transaction for planet_osm_polygon Committing transaction for planet_osm_roads Writing way (2107k) Committing transaction for planet_osm_point Committing transaction for planet_osm_line Committing transaction for planet_osm_polygon Committing transaction for planet_osm_roads Writing relation (17858) Sorting data and creating indexes for planet_osm_point Sorting data and creating indexes for planet_osm_line node cache: stored: 2352081(100.00%), storage efficiency: 63.23% (dense blocks: 2050, sparse nodes: 810237), hit rate: 5.25% Sorting data and creating indexes for planet_osm_roads Sorting data and creating indexes for planet_osm_polygon Analyzing planet_osm_roads finished Analyzing planet_osm_point finished Copying planet_osm_roads to cluster by geometry finished Creating geometry index on planet_osm_roads Creating indexes on planet_osm_roads finished All indexes on planet_osm_roads created in 0s Completed planet_osm_roads Copying planet_osm_point to cluster by geometry finished Creating geometry index on planet_osm_point Creating indexes on planet_osm_point finished All indexes on planet_osm_point created in 0s Completed planet_osm_point Analyzing planet_osm_polygon finished Copying planet_osm_polygon to cluster by geometry finished Creating geometry index on planet_osm_polygon Creating indexes on planet_osm_polygon finished All indexes on planet_osm_polygon created in 0s Completed planet_osm_polygon Analyzing planet_osm_line finished Copying planet_osm_line to cluster by geometry finished Creating geometry index on planet_osm_line Creating indexes on planet_osm_line finished All indexes on planet_osm_line created in 2s Completed planet_osm_line Osm2pgsql took 40s overall
blog comments powered by Disqus