Skip to main content

Example: Building Map

Map with buildings of a section of Brasília

You need at least osm2pgsql version 1.7.0 for this example.

You don’t always have to load all the OSM data into the database to create something useful (or beautiful). In this example we take the data from a city and only load the building footprints into the database. The whole process only takes a few seconds and we can show a pretty map.

As example city we are using Brasília here, the capital of Brazil. As I write this, it isn’t fully mapped yet, some buildings are missing. But the distinctive shape of this planned city shows up nevertheless.

Getting and Preparing the Data

First, we need some data. The smallest extract available from the Geofabrik Download server containing the city is the “centro-oeste” region. Lets download that:

wget https://download.geofabrik.de/south-america/brazil/centro-oeste-latest.osm.pbf

A quick search on the OSM web site find the Distrito Federal as a good boundary of the area of interest. If we scroll down to the end of the box on the left side of that page we find a link “Download XML”. We get the URL from that and add “/full” to the end. Downloading that gives use the relation containing the boundary including all ways and nodes needed:

wget -O federal-district.osm https://www.openstreetmap.org/api/0.6/relation/421151/full

We can now use Osmium to create an extract containing only the data inside the Distrito Federal from the “centro-oeste” region:

osmium extract -p federal-district.osm -o brasilia.osm.pbf centro-oeste-latest.osm.pbf

The result is the file brasilia.osm.pbf containing all OSM data for the federal district.

Running Osm2pgsql

Now we import this data into the database with osm2pgsql. First we need a style file for the flex output that only imports the buildings. We need a single table with a polygon geometry. Because we don’t need any tags in the database, we don’t import them.

Download Lua config
local buildings = osm2pgsql.define_area_table('buildings', {
    -- Define an autoincrementing id column, QGIS likes a unique id on the table
    { column = 'id', sql_type = 'serial', create_only = true },
    { column = 'geom', type = 'polygon', not_null = true },
}, { indexes = {
    -- So we get an index on the id column
    { column = 'id', method = 'btree', unique = true },
    -- If we define any indexes we don't get the default index on the geometry
    -- column, so we add it here.
    { column = 'geom', method = 'gist' }
}})

function osm2pgsql.process_way(object)
    if object.is_closed and object.tags.building then
        buildings:insert({
            geom = object:as_polygon()
        })
    end
end

function osm2pgsql.process_relation(object)
    if object.tags.type == 'multipolygon' and object.tags.building then
        -- From the relation we get multipolygons...
        local mp = object:as_multipolygon()
        -- ...and split them into polygons which we insert into the table
        for geom in mp:geometries() do
            buildings:insert({
                geom = geom
            })
        end
    end
end

Now we load the data:

osm2pgsql -d mbuildings -O flex -S buildings.lua brasilia.osm.pbf

Visualizing

There are many ways to visualize the data now. In this case I loaded the data into QGIS which has excellent support for PostgreSQL/PostGIS layers. After a few clicks loading the database table and changing the style, I got this:

Building map of Brasília