QVINTVS · SCRIBET

OpenStreetMap-Karten II

Dieser Artikel beschäftigt sich (erneut) mit der Erstellung von druckfähigen Karten aus dem OpenStreetMap-Material. Zum Einsatz kommt Mapnik, mit dem eine Karte im A4-Format erstellt werden soll.

Vor etwas mehr als einem Jahr habe ich mich zuletzt mit der Frage beschäftigt, wie man OpenStreetMap-Material in ein druckbares Format überführt. Damals ging es speziell um besonders große Karten (konkret im Format A1), die man auf der OpenStreetMap-Website nicht rendern lassen kann. Diesmal soll es um kleinere Karten im handelsüblichen A4-Format gehen. Diese kann man zwar grundsätzlich über die OSM-Website erzeugen, allerdings sind die erzeugten Karten meiner Erfahrung nach meist ziemlich unförmig und müssen immer noch auf A4 heruntergeschnitten werden; oftmals leiden sie auch unter Skalierproblemen. Kurz, ich denke, dass die OSM-Website für die Erstellung von Druckmaterial schlicht ungeeignet ist.

Auch diesmal wird es folglich darum gehen, Teile des OpenStreetMap-Kartenmaterials lokal zu benutzen. Die im o. g. Artikel beschriebene Methode enthält eine Menge Handarbeit unter Nutzung von Tilemill und Inkscape, seitdem gibt es durch ein neues Programm aber die Möglichkeit, diese Handarbeit erheblich zu verringern. Vermutlich ließe sich mit der hier beschriebenen Methode ebenfalls eine Karte im Format A1 erstellen, allerdings habe ich das mangels Bedarf nicht getestet.

Vorbereitungen

Es empfiehlt sich, für die Arbeiten zunächst ein eigenes Verzeichnis anzulegen. Ich werde in diesem Artikel ~/maptest benutzen.

$ mkdir ~/maptest
$ cd ~/maptest

Nun muss das OpenStreetMap-Kartenmaterial heruntergeladen werden (vgl. dazu auch den früheren Artikel). Das Material steht auf diversen Spiegelservern sowohl im alten XML-basierten OSM- als auch im neueren binären PBF-Format zur Verfügung. PBF ist erheblich platzsparender und daher empfohlen. Wie zuletzt auch sollte man lediglich den Teil des OSM-Planeten herunterladen, den man auch annähernd benötigt, da sich alle Prozesse sonst erheblich in die Länge ziehen können; ich bleibe bei den Deutschlandkarten von Geofrabrik, genauer bei der Nordrhein-Westfalen-Karte.

$ wget http://download.geofabrik.de/europe/germany/nordrhein-westfalen-latest.osm.pbf

Die nun folgenden Vorbereitungen erscheinen auf den ersten Blick ziemlich umfangreich. Das ist ein wohl auch nicht ganz abwegiger Eindruck, der schwerlich von der Hand zu weisen ist. Auf der anderen Seite muss man all diese Programminstallationen nur ein einziges Mal vornehmen, später kann man sich dann auf aktuelle Versionen des Kartenmaterials beschränken bzw. sogar einfach nur mit dem vorhandenen Kartenmaterial unterschiedliche Gebiete rendern.

PostgreSQL + PostGIS

Während dieser umfangreiche Download läuft, können die übrigen Voraussetzungen erfüllt werden. Benötigt werden eine PostgreSQL-Datenbank mit PostGIS- und seit neustem auch HStore-Erweiterung; zumindest unter ArchLinux ist „postgis“ als eigenständiges Paket verfügbar und nicht im Paket „postgresql“ enthalten. Die Installation von PostgreSQL soll hier nicht dokumentiert werden, für ArchLinux-Nutzer empfiehlt sich ein Blick in das ArchWiki. Nach der Installation muss zunächst die Konfiguration angepasst werden. Dazu die Datei /var/lib/postgres/data/postgresql.conf bearbeiten und folgende Werte setzen:

work_mem=16MB
maintenance_work_mem=128MB

Die Werte dürfen auch größer ausfallen, wenn ausreichend Arbeitsspeicher vorhanden ist; ich habe sie diesem Konfigurationsvorschlag entnommen. Je größer sie sind, desto schneller wird der Import und die Abfrage der OpenStreetMap-Daten vonstatten gehen. Derselbe Artikel empfiehlt auch die Aktivierung der Kernel-Funktion overcommit_memory, die ich daher hier wiedergebe:

# sysctl -w vm/overcommit_memory=1

PostgreSQL (neu) starten:

# systemctl restart postgresql

Danach eine Datenbank mit dem Namen gis anlegen und einem Nutzer zuordnen:

$ sudo su - postgres
Passwort:
$ psql
CREATE USER quintus WITH PASSWORD 'geheimespasswort';
CREATE DATABASE gis WITH OWNER quintus;

Der Datenbankname gis ist zwingend, wenn man wie unten noch erwähnt den OpenStreetMap-Standard-Kartenstil benutzen will, der diesen Datenbanknamen (leider) hardkodiert enthält.

In die erstellte Datenbank wechseln und die PostGIS- und HStore-Erweiterungen aktivieren:

$ psql gis
CREATE EXTENSION hstore;
CREATE EXTENSION postgis;

Shell für den Nutzer postgres wieder verlassen.

$ exit

OpenStreetMap-Software

Weiter werden das Herzstück des OpenStreetMap-Projekts, Mapnik, und ein Skript zum Import der OpenStreetMap-Daten in die PostgreSQL/PostGIS-Datenbank, osm2pgsql, benötigt. Mapnik ist in den ArchLinux-Repositorien enthälten, osm2pgsql im AUR (osm2pgsql-git), beides sollte jetzt installiert werden. Andere Distributionen haben möglicherweise beides in den Repositories; zu achten ist unbedingt darauf, dass Mapnik in einer Version größer 2 zum Einsatz kommt, da mit dieser Veröffentlichung diverse Inkompatbilitäten zum alten 0.x-XML-Format eingeführt wurden.

Da es in diesem Artikel darum geht, mit dem Standard-OpenStreetMap-Stil zu rendern, wird derselbe ebenfalls benötigt. Er kann per Git heruntergeladen werden:

$ git clone git://github.com/gravitystorm/openstreetmap-carto.git

MapBox-Software

Die Rendering-Bibliothek Mapnik erwartet seine Rendering-Parameter eigentlich als XML-Dokument, dessen Format eher schlecht als recht dokumentiert ist1. Bis vor ein paar Jahren wurde der offizielle OSM-Stil auch tatsächlich in diesem Format gehalten. Weil XML aber ein etwas unhandliches Format ist, hat das OSM-Projekt stattdessen auf eine andere Auszeichnungssprache, das von der Firma Mapbox entwickelte CartoCSS, gewechselt, in welcher der oben heruntergeladene OpenStreetMap-Standardstil daher abgefasst ist. CartoCSS wird dann in einem Zwischenschritt in das von Mapnik erwartete XML übersetzt.

(Vorsicht, Meinungseinschub) Sich derartig von einer bestimmten Firma abhängig zu machen, gehört sich für ein freies Projekt eigentlich nicht. Wenn Mapbox die Software einstellt, steht das OSM-Projekt im Regen und kann wieder zurück auf XML-Stylesheets wechseln oder noch etwas anderes versuchen. Wenn man unbedingt CartoCSS einsetzen will, dann sollte man den Parser doch direkt in Mapnik selbst einbauen, statt sich auf von unbekannten Dritten entwickelte Software zu verlassen, wenn es doch faktisch um die Darstellung des eigenen „Gesichts“ geht. Tatsächlich prangt auf der Dokumentationsseite von TileMill, dem Projekt, dessen wesentlicher Teil CartoCSS ist, mittlerweile sogar tatsächlich ein Hinweis darauf, dass die Entwicklung eingestellt wurde. Chaos voraus.

Die Umwandlung von CartoCSS in XML-Mapnik-Stylesheets erfolgt mithilfe des Programms carto, welches ebenfalls mithilfe von Git heruntergeladen werden kann:

$ git clone git://github.com/mapbox/carto.git

Carto ist für NodeJS geschrieben, eine Implementation von JavaScript außerhalb von Webbrowsern und weist darüber hinaus noch einige andere Abhängigkeiten auf, die mithilfe des Node-Paketmanegers, NPM, installiert werden müssen. NodeJS und NPM sollten sich in den Repositorien der eingesetzten Linux-Distribution befinden und sollten nunmehr installiert werden. Anschließend können die Abhängigkeiten installiert werden:

$ cd carto
$ npm install
$ cd ..

TileMill selbst wird wie erwähnt nicht mehr weiterentwickelt und funktioniert auch nicht mehr mit dem aktuellen NodeJS (>= 0.12.0). Wer das Programm weiterhin einsetzen möchte, sollte ein NodeJS in Version 0.10.x installieren, das Kommandozeilenprogramm carto funktioniert dagegen (noch) mit einer 0.12.x-Version von NodeJS. Da in diesem Artikel nur das Kommandozeilenprogramm zum Einsatz kommt, stellt die Problematik sich nicht; 0.12.x funktioniert einwandfrei.

nik4

Die letzte Voraussetzung ist das von mir neu entdeckte Programm nik4, welches mit aktuellen Versionen von Mapnik funktioniert, scheinbar noch aktiv entwickelt wird, und erfreulich umfangreiche Optionen besitzt. nik4 ist ein Python2-Programm, sodass die Installation von Python2 und zwecks weiterer Abhängigkeiten pip und virtualenv erforderlich ist. Alle erwähnten Python-Programme sind bei ArchLinux in den Repositorien enthalten.

Ich bin ja eigentlich kein Pythonista, aber virtualenv habe ich mittlerweile auch kennen und schätzen gelernt. Das Programm ermöglicht das Management von Abhängigkeiten in der Python-Welt (ähnlich wie Rubys Bundler) in solcher Weise, dass man sie nicht gleich global installieren muss, sondern sie einfach in einem Verzeichnis auf der Platte halten kann. Damit werden Versions- und Namenskonflikte angenehm vermieden. Für die Funktionsweise von virtualenv sei auf dessen Website verweisen, hier ist nur die bloße Anwendung wichtig. Zunächst wird eine virtuelle Umgebung eingerichtet und aktiviert:

$ virtualenv env
$ . ./env/bin/activate

Der zweite Schritt, die Aktivierung, muss jedesmal wiederholt werden, wenn eine neue Shell benutzt wird, weil sie Änderungen an der PATH-Variablen vornimmt. Danach gestaltet sich die Installation der Abhängigkeiten einfach:

$ pip install mapnik lxml nik4

Import des OSM-Kartenmaterials

Damit sind alle Vorbereitungen erledigt. Ich gebe zu, dass man von dem Konglomerat an C++-, NodeJS- und Python-Software förmlich erschlagen wird. Wie erwähnt sind das aber einmalige Vorgänge, durch die man sich später nicht mehr kämpfen muss.

Nachdem also alles installiert ist und der Download der PBF-Daten abgeschlossen ist, kann man das OpenStreetMap-Kartenmaterial in die PostgreSQL-Datenbank importieren. Dazu dient das Programm osm2pgsql, welches anhand einer .style-Datei entscheidet, welche Daten aus den Unmengen an Informationen, die in den OpenStreetMap-Materialien stecken, in die Datenbank zu importieren sind. Der Aufruf erfolgt wie folgt:

$ osm2pgsql --database gis --create --slim \
  --cache 1000 --number-processes 3 --hstore \
  --style openstreetmap-carto/openstreetmap-carto.style \
  --multi-geometry \
  nordrhein-westfalen-latest.osm.pbf

Eine umfangreiche Erklärung der einzelnen Parameter befindet sich in diesem Artikel. Es empfiehlt sich, --number-processes so anzupassen, dass die maximale Anzahl an CPU-Kernen verwendet wird, da dies den Importvorgang erheblich beschleunigt. Die Dateien openstreetmap-carto/openstreetmap-carto.style und nordrhein-westfalen-latest.osm.pbf wurden während der Vorbereitungen bereits heruntergeladen und bedürfen hier daher keiner weiteren Erläuterung.

Der Import solcher Datenmengen dauert recht lang. Das obige Kommando benötigte bei mir etwa eineinhalb Stunden.

Shapefiles

Neben dem eigentlichen Kartenmaterial verarbeitet Mapnik auch sog. Shapefiles. Dabei handelt es sich vornehmlich um Küstenlinien; für eine ausführlichere Erklärung sei auf meinen früheren Artikel verwiesen. Erfreulicherweise ist das Skript zum Download der Shapefiles seitdem repariert worden, sodass die in jenem Artikel angesprochene Frickelei entfällt. Es genügt nunmehr, das Skript auszuführen, das die für den Standardkartenstil von OpenStreetMap benötigten Shapefiles herunterlädt:

$ cd openstreetmap-carto
$ ./get-shapefiles.sh
$ cd ..

Auch hier werden nicht unwesentliche Datenmengen heruntergeladen, Geduld ist also angebracht.

Anwendung

Nach all diesem Vorgeplänkel kann nun zur eigentlichen Arbeit übergegangen werden, dem Rendern der Karten. Zunächst wird das CartoCSS des OpenStreetMap-Projekts in Mapnik-XML übersetzt:

$ cd openstreetmap-carto
$ ../carto/bin/carto project.mml > openstreetmap-carto.xml
$ cd ..

Das dauert etwas länger, ca. 5 Minuten. Danach kann Nik4 aufgerufen werden, um etwa eine Karte der Kreisstadt Unna im A4-Format zu erzeugen:

$ nik4.py -s 5000 --ppi 300 -a 4 \
  -c 7.6867 51.5357 --margin 10 \
  openstreetmap-carto/osm-carto.xml print.png

Das ergibt eine Karte im Maßstab 1:5000, die bei einer Druckauflösung von 300 DPI auf einem A4-Blatt das gesamte Blatt einnimmt, aber runderherum 10mm Rand lässt. -c 7.6867 51.5357 gibt die Kartenmitte in Form einer Längen- und Breitengradangabe an. Es ist darauf zu achten, dass die Längengradangabe zuerst kommt. Ich habe ein paar Stunden damit verbracht, mich über leere Karten zu wundern, bis ich festgestellt habe, dass ich die Längen- und Breitengrade vertauscht hatte. Herausfinden kann man diese Angaben ganz bequem, indem man die Karte auf https://www.openstreetmap.org aufruft, den gewünschten Ort ansteuert und die „Teilen“-Funktion auswählt. Dort hat man die Möglichkeit, einen Marker auf der Karte zu platzieren. Diesen stellt man dorthin, wo sich die spätere Kartenmitte befinden soll, anschließend kann man die Koordinaten in dem Feld „Geo-URI“ ablesen (die Zoom-Stufe, z, ist unerheblich; nik4 berechnet den korrekten Zoom aus der Angabe der Papiermaße, der gewünschten DPI, Skalierung und Ränder).

300 DPI ist noch ein relativ mittelmäßiger Wert. Viele Drucker sind auch in der Lage, wenigstens 600 DPI zu drucken, was auch tatsächlich in einem wahrnehmbar größeren Detailreichtum auf der Karte resultiert und daher sehr empfehlenswert ist; der Parameter --ppi ist dementsprechend anzupassen. Mein Drucker vermag laut Eigenwerbung sogar 2400 DPI zu drucken, allerdings hat Mapnik beim Rendering eines solch großen Bildes die Waffen gestreckt. Es gibt allerdings wohl eine Möglichkeit, dies mit der Option --tiles trotzdem hinzubekommen; allerdings entstehen dann Einzelbilder, die ihrerseits wieder erst per Imagemagick zusammengebaut werden müssen. Das habe ich noch nicht probiert, wer aber mutig ist, darf gern seine Erfahrungen in den Kommentaren posten.

Ergebnis

Das Ergebnis sieht dann so aus wie dieses Bild (Zentrum der Kreisstadt Unna bei 300 DPI). Den Copyright-Hinweis verlangen die Lizenzbedingungen, man kann ihn leicht mithilfe des GIMPs hinzufügen.

Valete.

  1. Für unzählige Projekte scheint es die denkbar allerschwerste Aufgabe überhaupt zu sein, ihre Verwendung zu dokumentieren. Es ist eine Schande! Da gibt es so tolle Projekte, aber außer den Entwicklern kann faktisch niemand sie benutzen, weil sie keine Dokumentation, oder noch schlimmer, veraltete Dokumentation enthalten.