QVINTVS · SCRIBET

Große OpenStreetMap-Karten selbst rendern

OpenStreetMap ist ein wunderbares Projekt, zu dem beizutragen jedem nur zu empfehlen ist. Die Qualität der Karten lässt mittlerweile manch kommerziellen Anbieter alt aussehen, allerdings stellt sich das Rendern einer etwas größer als üblichen Karte als ein wenig schwierig heraus. In diesem Artikel beschreibe ich, wie man eine Karte im Format A1 erstellt.

Wer regelmäßig die OpenStreetMap-Website nutzt, der kennt diese Fehlermeldung:

The gateway did not receive a timely response from the upstream server or application.

Oder alternativ:

The load on the servers is too high currently. Please try again in a few minutes.

Für Karten, die in etwa die Größe eines A4-Blattes nicht überschreiten, ist diese Meldung noch verhältnismäßig selten. Sobald man aber größere Areale in eine druckbare Form bringen möchte (man denke etwa an Informationstafeln), ist die OpenStreetMap-Website nicht mehr zu gebrauchen. Die einzige Lösung dieses Problems besteht darin, die Rohdaten von OpenStreetMap selbst auf dem heimischen Rechner zu rendern, was ich nun näher erläutern möchte.

Voraussetzungen

Ich bin von den Anforderungen des Renderings selbst ein wenig überrascht gewesen. Es empfiehlt sich ein Computer mit mindestens 8 GiB Arbeitsspeicher, dazu ein möglichst schneller Prozessor. Jedenfalls konnte ich nicht beobachten, dass die Rendering-Software auf meine Graphikkarte zugegriffen hätte, was der benötigten Zeit sicherlich gut getan hätte, so aber sind ein paar Minuten 100%-ige CPU-Auslastung schonmal drin.

Die Rohdaten

Das OpenStreetMap-Projekt bietet die Rohdaten der gesamten Erde direkt selbst zum Download an, mit einer Größe von momentan etwa 24 GiB im PBF- und 34 GiB im OSM-Format ist von einem vollständigen Download allerdings eher abzuraten. Stattdessen gibt es Spiegelseiten, die auch Teile des Gesamtmaterials anbieten. Für diesen Artikel nutze ich die Nordrhein-Westfalen-Karte von Geofabrik. Zu beachten ist, dass es wie erwähnt zwei Formate gibt: Das traditionelle XML-basierte OSM-Format, das aufgrund seiner schieren Größe bei derartigen Datenmengen momentan auf dem Rückzug ist, sowie das neuere platzsparende Binärformat PBF. Es ist empfehlenswert, sich für PBF zu entscheiden. (Direktlink zum NRW-PBF).

PostgreSQL und PostGIS

Die Daten können nicht roh von der Rendering-Software (dazu sogleich) eingelesen werden. Stattdessen wird eine PostgreSQL-Datenbank mit der PostGIS-Erweiterung benötigt; dabei handelt es sich um ein speziell für Geodaten ausgelegtes Format sowie dazugehörige Abfragebefehle, mit denen an die Datenbank Fragen wie „Welche Straßen liegen in diesem so und so umgrenzten Gebiet?“ gestellt werden können. Perfekt etwa auch für die Erstellung von Straßenkarten, bei denen ein Index für die Zuordnung von Straßenname und Kartenquadrant vorgenommen werden soll – das soll hier aber nicht Thema sein.

Die meisten Distributionen haben PostgreSQL und PostGIS in ihren Repositorien, sodass ich auf die Installation nicht weiter einzugehen brauche. Allerdings wird empfohlen, die Ressourcenlimits für PostgreSQL anzuheben:

# postgresql.conf
shared_buffers = 128MB
checkpoint_segments = 20
maintenance_work_mem = 256MB

Dazu muss auch eine Kernel-Variable erhöht werden:

# sysctl kernel.shmmax=268435456

Selbstverständlich kann man diese Änderung auch in /etc/sysctl.d bzw. /etc/sysctl.conf festschreiben, um sie nicht nach jedem Reboot wiederholen zu müssen.

Nun benötigen wir noch einen Nutzer und eine Datenbank mit PostGIS-Erweiterung. Der Standard-Openstreetmap-Stil erfordert zwingend den Datenbanknamen gis. Zunächst als Superuser am Datenbankserver anmelden:

# su - postgres
$ psql
psql (9.3.4)
Geben Sie „help“ für Hilfe ein.

Einen Nutzer (hier quintus) und eine Datenbank (zwingend gis) erstellen:

CREATE USER quintus WITH PASSWORD 'supergeheimespasswort';
CREATE DATABASE gis WITH OWNER quintus;

Das Passwort ist im Grunde egal, da PostgreSQL lokalen Verbindungen standardmäßig ohnehin vertraut. Dies ist auch erforderlich, da ansonsten die Datenbankverbindung im Openstreetmap-Carto-Stil (dazu gleich mehr) geändert werden müsste.

Nun müssen wir die PostGIS-Erweiterung aktivieren. Dazu die SQL-Shell verlassen (\q) und neu anmelden, diesmal auf der gis-Datenbank:

$ psql -d gis

Erweiterung aktivieren:

CREATE EXTENSION postgis;

Von anderer Seite wird zudem die Aktivierung der plpgsql-Erweiterung gefordert, allerdings musste ich bei mir folgendes feststellen:

CREATE EXTENSION plpgsql;
FEHLER:  Erweiterung plpgsql existiert bereits

Daraus schließe ich, dass dies bei neueren Versionen von PostgreSQL nicht mehr erforderlich ist. Zuletzt noch die Zugriffsrechte anpassen (weil wir mit dem postgres-Nutzer gearbeitet haben):

ALTER TABLE geometry_columns OWNER TO quintus;
ALTER TABLE spatial_ref_sys OWNER TO quintus;

Kontrollergebnis:

gis=# \d
               Liste der Relationen
 Schema |       Name        |   Typ   | Eigentümer 
--------+-------------------+---------+------------
 public | geography_columns | Sicht   | postgres
 public | geometry_columns  | Sicht   | quintus
 public | raster_columns    | Sicht   | postgres
 public | raster_overviews  | Sicht   | postgres
 public | spatial_ref_sys   | Tabelle | quintus
(5 Zeilen)

Die OpenStreetMap-Daten liegen im Format 900913 vor, das in meiner PostGIS-Version jedoch ebenfalls bereits enthalten war. Ansonsten kann das zur Erstellung notwendige SQL hier eingesehen werden.

osm2pgsql

Der Import der Daten aus dem PBF in die Postgres-Datenbank wird mithilfe des Programms osm2pgsql durchgeführt. Dieses steht unter ArchLinux im AUR zur Verfügung.

Mapnik

Herzstück des gesamten Prozesses ist die Rendering-Software Mapnik. Diese Library (es handelt sich nicht um ein Endnutzer-Programm) übernimmt die eigentliche Rendering-Arbeit und wird sehr aktiv entwickelt. Zum erfolgreichen Einsatz mit der anderen in diesem Artikel vorgestellten Software ist mindestens Version 2.2.0 erforderlich, insbesondere TileMill (siehe unten) verweigert ansonsten den Dienst. Mapnik ist in C++ geschrieben und wird primär über ein Python-API angesprochen, das jedoch auch in einer Weise verwendet werden kann, die den Python-Code im Wesentlichen auf das Laden einer XML-Datei reduziert. Es stehen auch Bindings für andere Programmiersprachen zur Verfügung, darunter JavaScript und Ruby.

Mapnik ist unter Arch Linux als reguläres Paket im community-Repository verfügbar.

TileMill

Gewissermaßen das „Gesicht“, sprich die UI, mit der vordringlich gearbeitet wird, stellt TileMill da. Die in NodeJS geschriebene Software entwickelt sich so rasant, dass man dort nicht einmal ernsthafte Gedanken an stabile Relases verschwendet – das letzte war vor zwei Jahren und ist hoffnungslos veraltet. Stattdessen wird darauf verwiesen, man möge sich stets den aktuellen master herunterladen. Der ganz offensichtliche Fokus auf Mac OS X erleichtert einem Linuxer den Umgang mit der Software nur sehr bedingt.

Die im OpenStreetMap-Wiki genannten Alternativen werden (freilich mit Ausnahme von „custom python script for mapnik“) nicht mehr entwickelt, sodass es sich bei TileMill gewissermaßen nun um den „offiziellen“ Renderer handelt. Es gibt zurzeit noch das Kommandozeilen-Programm Nik2img, das aber seit 2011 nicht mehr entwickelt wird und dessen Verwendung von Mapnik durch „Deprecated“-Meldungen quittiert wird. Es stellt sich mithin die Frage, wie lange dieses Programm noch verwendbar sein wird; spätestens mit dem Release von Mapnik 3 wird TileMill der einzig verbliebene Renderer sein.

Die nicht etwa in der README dokumentierte Installation von TileMill ist für Leute, die sich mit NodeJS nicht auskennen, ein wenig ungewöhnlich, daher gehe ich hier darauf ein. Zunächst wird das Git-Repository geklont:

$ git clone git://github.com/mapbox/tilemill.git
$ cd tilemill

Die für den Bau erforderlichen Abhängigkeiten können der oben verlinkten Installationsanleitung entnommen werden. Auf Arch Linux ist es nicht erforderlich, wie dort beschrieben Boost, Mapnik und NodeJS aus dem Quellcode zu bauen – alle Programme liegen bereits in einer ausreichend aktuellen Version vor. Konzentrieren wir uns stattdessen auf den Bau von TileMill:

$ npm install

Das downloaded und kompiliert eine ganze Reihe von Software und kann einige Zeit in Anspruch nehmen. Nach Abschluss der Installation kann TileMill wie folgt gestartet werden:

$ node index.js

Datenimport

Der Import der OSM-Daten in die PostgreSQL/PostGIS-Datenbank erfolgt grundsätzlich mit osm2pgsql. Am konkreten Aufruf des Programms aber scheiden sich die Geister – ich habe es schließlich so aufgerufen, ohne irgendwelche Nachteile feststellen zu können:

$ osm2pgsql --slim -d gis --number-processes 3 ~/Downloads/nordrhein-westfalen-latest.osm.pbf

Dises Prozess dauert relativ lange, bei mir war es relativ genau eine Stunde. Größere Datenmengen benötigen freilich länger.

Rendering

Für ein erfolgreiches Rendering ist es zunächst wichtig zu verstehen, wie der Prozess eigentlich abläuft. Für Mapnik existieren im Wesentlichen zwei Datenquellen: Shapefiles und Geodaten. Bei letzteren handelt es sich um das, was wir vorhin in PostGIS importiert haben, Shapefiles sind reine Konturdaten. Das kanonische Beispiel sind die Küstenlinien an den Weltmeeren, die OpenStreetMap nicht selbst erfasst, sondern über eine Shapefile von Natural Earth verwaltet. Sowohl von Shapefiles als auch von PostGIS-Daten können beliebig viele (lies: Solange der RAM reicht) in eine Karte importiert werden, man spricht oberbegrifflich von Datenquellen (engl. data sources).

         Datenquelle
        /           \
  Shapefile        Geodaten

Diese Datenquellen werden nun als Ebenen in eine bestimmte Reihenfolge gebracht (jede Ebene hat genau eine Datenquelle); beim finalen Rendering werden die Ebenen dann „aufeinander gepresst“. So könnte man beispielsweise ein sehr rohe Straßenkarte erstellen, indem man die Küstenlinien-Shapefile unter den Straßen-Geodaten anordnet:

          Straßen-Geodaten
          Küsten-Shapefile
                ↓↓
           Gesamtkarte

Die OpenStreetMap-Daten liefern insgesamt sieben Geodatenquellen:

gis=# \d
                Liste der Relationen
 Schema |        Name        |   Typ   | Eigentümer 
--------+--------------------+---------+------------
 public | geography_columns  | Sicht   | postgres
 public | geometry_columns   | Sicht   | postgres
 public | planet_osm_line    | Tabelle | quintus
 public | planet_osm_nodes   | Tabelle | quintus
 public | planet_osm_point   | Tabelle | quintus
 public | planet_osm_polygon | Tabelle | quintus
 public | planet_osm_rels    | Tabelle | quintus
 public | planet_osm_roads   | Tabelle | quintus
 public | planet_osm_ways    | Tabelle | quintus
 public | raster_columns     | Sicht   | postgres
 public | raster_overviews   | Sicht   | postgres
 public | spatial_ref_sys    | Tabelle | postgres

Alle Tabellen, die im obigen Listing mit „planet_“ anfangen, sind in Mapnik verwertbare Geodatenquellen unterschiedlichen Umfangs. So enthält planet_osm_roads etwa nur Straßen, planet_osm_polygon nur in sich abgeschlossene Objekte (z.B. Gebäude).

Jede Ebene kann zudem gestyled werden (z.B. Wege auf dieser Ebene blau, Hintergrund grün); die gesamte Kartenstruktur wird Mapnik in Form eines komplexen XML-Kontrukts mitgeteilt. Da insbesondere das Styling der verschiedenen Kartenelemente in XML eine ausgesprochen leidige Arbeit ist, hat TileMill hierfür einen Abkömmling von CSS einführt, CartoCSS. CartoCSS ist sehr mächtig und kann zur besonderen individuellen Gestaltung von Karten verwandt werden, für den Moment begnügen wir uns aber mit dem CartoCSS, das das OpenStreetMap-Projekt für seine eigene Online-Karte verwendet, openstreetmap-carto.

Hinweis: TileMill-Projekte können mithilfe des in Tilemill enthaltenden Programms carto (unter node_modules/carto/bin/carto) direkt in Mapnik-XML konvertiert werden. So ist es möglich, ein TileMill-Projekt außerhalb des UIs von TileMill zu bearbeiten, zu stylen und auch zu rendern.

Openstreetmap-Carto kommt als TileMill-Projekt daher, welches in den Projektordner von TileMill kopiert werden muss. Damit dieser überhaupt existiert, muss TileMill wie weiter oben gezeigt zumindest einmal gestartet werden. Dieses TileMill-Projekt ist wie schon weiter oben erwähnt der Grund dafür, dass die Datenbank gis heißen muss – bei einem anderen Datenbanknamen müssten für jede Ebene im TileMill-Projekt, die auf die Geodaten zugreift, die Verbindungsdaten geändert werden. Dies ist zwar möglich, aber ausgesprochen aufwendig.

Nach dem erstmaligen Start sollte ein Ordner ~/Documents/MapBox/project existieren (sic, von XDG hat TileMill bisher noch nicht gehört), in den das Openstreetmap-Projekt geklont werden kann:

$ cd ~/Documents/MapBox/project
$ git clone git://github.com/gravitystorm/openstreetmap-carto.git
$ cd openstreetmap-carto

Die Instruktionen in der README können größtenteils ignoriert werden, weil wir die notwendigen Vorbereitungen bereits getroffen haben. Insbesondere entfällt der Fix von ne_10m_populated_places, weil aktuelle Versionen von Mapnik das Problem bereits behoben haben. Stattdessen können wir nun den Fix fixen, d.h. in der Datei get_shapefiles.sh folgende Zeilen auskommentieren:

#process populated places
echo "processing ne_10m_populated_places..."
rm -f data/ne_10m_populated_places/ne_10m_populated_places_fixed.*
ogr2ogr --config SHAPE_ENCODING UTF8 data/ne_10m_populated_places/ne_10m_populated_places_fixed.shp data/ne_10m_populated_places/ne_10m_populated_places.shp

und den darauf folgenden shapeindex-Befehl wie folgt abändern:

shapeindex --shape_files \
data/simplified-land-polygons-complete-3857/simplified_land_polygons.shp \
data/land-polygons-split-3857/land_polygons.shp \
data/ne_10m_populated_places/ne_10m_populated_places.shp \
data/ne_110m_admin_0_boundary_lines_land/ne_110m_admin_0_boundary_lines_land.shp

Jetzt kann man das Skript ausführen, das einige Shapefiles herunterladen wird, die Openstreetmap-Carto als Datenquellen dienen. Danach kann das Projekt in TileMill geöffnet werden, indem es einfach auf der Startseite von TileMill ausgewählt wird. Sollte TileMill beim Öffnen des Projekts „file-not-found“-Fehlermeldungen zeigen, sollten die Dateinamen im Verzeichnis „data“ überprüft werden – wenn auch nur eine Datenquelle nicht gefunden wird, verweigert TileMill komplett die Arbeit und zeigt nur eine leere Karte ohne weiteren Kommentar.

In TileMill kann man nun ganz normal arbeiten; das Benutzerinterface ist recht intuitiv, die genaue Bedienung kann in der Anleitung nachgelesen werden. Wichtig ist insbesondere, beim Export eine Zoomstufe auszuwählen – Zoomlevel 0 erzeugt nur leere Karten (jedenfalls dann, wenn man nicht das gesamte (!) OSM-Datenmaterial in der PostGIS-Datenbank hat). Je nach Verwendungszweck kann man sich für ein passendes Export-Format entscheiden; der besseren Weiterverarbeitung wegen habe ich mich für SVG entschieden.

Nachbearbeitung

Die exportierte Karte ist in der Regel völlig unförmig, d.h. liegt in einem Seitenformat vor, das man so überhaupt nicht drucken kann. Mithilfe von Inkscape kann man die Karte jedoch etwa auf A1 herunterschneiden, indem man zunächst ein neues Dokument anlegt, danach in den Dokumenteneinstellungen das Seitenformat A1 + Querformat auswählt und anschließend das aus TileMill exportierte SVG importiert. Dieses Prozess dauert sehr lange und benötigt große Mengen Arbeitsspeicher, daher sollte man für diesen Schritt Geduld mitbringen. Nach erfolgtem Import kann die Karte auf der Seite platziert werden, wobei Überschüssiges ruhig über den Rand hinausragen darf. Über „Datei → Kopie speichern unter“ kann man nun nur den Seitenbereich (also das A1-Blatt) als PDF exportieren, wobei Teile außerhalb des Seitenbereichs abgeschnitten werden. Das Ergebnis sieht etwa so wie hier aus und ist druckfertig. Selbstverständlich kann man in Inkscape auch noch weitere Nachbearbeitungen machen, z.B. ein Gitter über die Karte legen oder eine Legende hinzufügen. Dies sei der Kreativität des Lesers überlassen – allerdings mit dem Hinweis, dass die Lizenzbedingungen von OpenStreetMap vorschreiben, dass irgendwo der Hinweis „© OpenStreetMap-Mitwirkende“ angebracht wird.

Fazit

OpenStreetMap ist ganz große Klasse. Neben Online- lassen sich damit auch prima Druckkarten anfertigen, allerdings kränkt das Projekt in dieser Hinsicht an fehlender und zuweilen sogar widersprüchlicher, weil veralteter Dokumentation. Große Teile der im Internet (sogar im OSM-Wiki) auffindbaren Informationen beziehen sich auf Mapnik Version 0.x, mittlerweile jedoch ist die Software schon zwei Major-Releases weiter und damit schlicht nicht mehr kompatibel. Die alternativen Renderer neben TileMill werden nicht mehr entwickelt, und CartoCSS hat seinen Vorgänger MapCSS abgelöst. Auch PostgreSQL und PostGIS sind nicht stehengeblieben, insbesondere ist es zur Verwendung von PostGIS nicht mehr erforderlich, irgendwelche SQL-Skripte aus dem contrib/-Pfad von PostgreSQL auszuführen. Insgesamt bewegt sich die OSM-Software sehr schnell, sodass ich hoffe, mit diesem Artikel ein wenig Ordnung in dieses verwirrende Durcheinander gebracht zu haben. Wie lange er freilich aktuell bleiben wird, weiß ich nicht zu sagen.

Valete.