OpenStreetMap-Karten mit dem deutschen Stil selbst rendern

Marvin Gülker · 10.12.2016

Dieser Artikel erläutert die Erstellung von druckfähigen Karten auf der Basis des OpenStreetMap-Kartenmaterials mit dem sog. „deutschen“ OpenStreetMap-Stil.

Kategorien: OpenStreetMap, Software

Ein früherer Artikel hat sich damit beschäftigt, wie man auf unterschiedliche Arten aus den OpenStreetMap-Daten auf seinem eigenen Rechner Kartengraphiken beliebiger Größe erstellen kann. Dazu kam der internationale OpenStreetMap-Stil, openstreetmap-carto, zum Einsatz. Hier soll es nunmehr darum gehen, nach derselben Methode den deutschen OpenStreetMap-Stil — wie er etwa auf der Karte von openstreetmap.de zu sehen ist — für eigene Karten einzusetzen.

Vorbereitungen

Wie üblich empfiehlt es sich, ein eigenes Verzeichnis für die folgenden Arbeiten anzulegen.

$ mkdir ~/osmtest
$ cd ~/osmtest

Danach sollte man sogleich den Download des Kartenmaterials anstoßen, da dies erfahrungsgemäß sehr lange dauern kann. Auch dieses Mal kommen wieder die OSM-Auszüge von Geofabrik zum Einsatz.

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

Virtuelenv

Da einige Python-Software zum Einsatz kommt, empfiehlt es sich, zur sauberen Abschottung von Software virtualenv zu benutzen.

$ virtualenv -p /usr/bin/python2.7 env
$ . ./env/bin/activate

Mapnik

Ohne Mapnik kein OpenStreetMap. Mapnik muss daher installiert werden, sollte aber auch in den Repositories aller gängigen Linux-Distributionen enthalten sein. Für die Zwecke dieses Artikels wurde mit Mapnik 3.0.9 gearbeitet.

PostgreSQL + PostGIS

Für die Arbeit mit dem Kartenmaterial ist PostgreSQL mit der Erweiterung PostGIS erforderlich. Beides ist in den Repositories der üblichen Linux-Distributionen enthalten; speziell im Falle von Gentoo ist es allerdings erforderlich, das PostGIS-Paket von seiner Keyword-Markierung zu befreien, da das als stabil markierte dev-db/postgis nicht mit der als stabil markierten PostgreSQL-Version 9.5 zusammenarbeitet.

Die Standardeinstellungen von PostgreSQL sollten verändert werden, da sie auf Systeme mit eher kleinen Arbeitsspeichern zugeschnitten zu sein scheinen; im Zweifel sollten sie eher zu groß als zu klein bemessen werden. Dabei sollte man aber nicht aus den Augen verlieren, dass Mapnik beim Rendern der Karten ebenfalls erhebliche Mengen Arbeitsspeicher für sich beanspricht.

Die relevanten Einstellungen befinden sich in der Konfigurationsdatei postgresql.conf:

work_mem=16MB
maintenance_work_mem=128MB

Noch Memory Overcomitting zulassen und PostgreSQL neu starten:

# sysctl -w vm/overcommit_memory=1
# /etc/init.d/postgresql-9.5 restart

Abhängigkeiten des deutschen OSM-Stils

An dieser Stelle ging der vorige Artikel bereits zur Erstellung der Datenbank über. Dies ist hier noch nicht ratsam, da zunächst einige spezielle Abhängigkeiten des deutschen OpenStreetMap-Stils berücksichtigt werden müssen. Die offizielle Installationsanleitung fällt eher mau aus, weshalb der Installationsprozess hier im Einzelnen festgehalten wird.

Zunächst ergibt sich folgender Abhängigkeitsbaum:

  • openstreetmap-carto-de
    • mapnik-german-l10n
      • PostgreSQL
      • PostGIS
      • kakasi
      • icu
      • utf8proc (nicht wirklich dokumentiert)
      • pandoc (nicht wirklich dokumentiert)
    • pyyaml (undokumentiert)
    • carto
      • NodeJS

Diese Abhängigkeiten sind nicht alle dokumentiert und nicht immer einfach zu installieren. Insbesondere kakasi und utf8proc sind nicht immer in den Repositorien der gängigen Linux-Distributionen enthalten. Schlimmer noch, Gentoo liefert eine derart veraltete Version von utf8proc aus, dass eine Verwendung mit dem deutschen OSM-Stil unmöglich ist. Es scheint, als ob utf8proc irgendwann einmal wegen Inaktivität geforkt wurde und Gentoo noch das alte, inaktive Projekt im Portage-Tree hat. kakasi im Portage-Tree ist aber aktuell.

Sofern die eigene Linux-Distribution kakasi und utf8proc also nicht oder nicht in der aktuellen Version bereitstellt, sind sie aus den Quellen zu kompilieren und zu installieren. Dabei bitte darauf achten, ein stabiles Release zu installieren. ldconfig nicht vergessen.

$ git clone git://github.com/JuliaLang/utf8proc.git
Cloning into 'utf8proc'...
remote: Counting objects: 1050, done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 1050 (delta 5), reused 0 (delta 0), pack-reused 1031
Receiving objects: 100% (1050/1050), 3.57 MiB | 1.03 MiB/s, done.
Resolving deltas: 100% (635/635), done.
Checking connectivity... done.
$ cd utf8proc
$ git checkout v2.0.2
Note: checking out 'v2.0.2'.
$ make
cc -O2 -fPIC -std=c99 -Wall -pedantic -DUTF8PROC_EXPORTS -c -o utf8proc.o utf8proc.c
rm -f libutf8proc.a
ar rs libutf8proc.a utf8proc.o
ar: creating libutf8proc.a
cc  -shared -o libutf8proc.so.2.0.2 -Wl,-soname -Wl,libutf8proc.so.2 utf8proc.o
chmod a-x libutf8proc.so.2.0.2
ln -f -s libutf8proc.so.2.0.2 libutf8proc.so
ln -f -s libutf8proc.so.2.0.2 libutf8proc.so.2
# make install
mkdir -m 755 -p /usr/local/include
install -m 644 utf8proc.h /usr/local/include
mkdir -m 755 -p /usr/local/lib
install -m 644 libutf8proc.a /usr/local/lib
install -m 755 libutf8proc.so.2.0.2 /usr/local/lib
ln -f -s libutf8proc.so.2.0.2 /usr/local/lib/libutf8proc.so
ln -f -s libutf8proc.so.2.0.2 /usr/local/lib/libutf8proc.so.2
# ldconfig
# emerge app-i18n/kakasi
[...Portage installiert kakasi...]

mapnik-german-l10n ist eine Erweiterung (extension) für PostgreSQL, die insbesondere Transkriptionsfunktionen für asiatische Ortsnamen zur Verfügung stellt. Zwar ist es wohl möglich, den Stil irgendwie ohne sie zu verwenden und so die Abhängigkeiten von kakasi und utf8proc zu vermeiden (wenn man auf Karten asiatischer Lande verzichten kann), aber dieses Vorgehen ist nicht dokumentiert (im Gegensatz zum hier vorgestellten, das zumindest in Ansätzen dokumentiert ist) und wird daher hier nicht weiter verfolgt.

Die README von mapnik-german-l10n ist auf Nicht-Debian-Systemen vollständig zu ignorieren. Die korrekte Installationsanleitung befindet sich in der Datei INSTALL.md. Dabei ist zwingend darauf zu achten, eine stabile Version von mapnik-german-l10n zu installieren und nicht einfach das zu bauen, was aktuell in master ist. Als dieser Artikel verfasst wurde, war Version 2.1.5 aktuell.

Den Inhalt und die Implikationen der INSTALL-Datei kurz zusammengefasst läuft die Installation so ab:

$ git clone git://github.com/giggls/mapnik-german-l10n.git
$ cd mapnik-german-l10n.git
$ git checkout v2.1.5
$ make
# make install

Das installiert die PostgreSQL-Erweiterung unmittelbar nach /usr/share/postgresql-9.5/extension, was recht misslich ist, wenn man sie irgendwann einmal wieder deinstallieren möchte. So bleibt es jedem überlassen, die Ausgabe von make install kleinlich zu verfolgen oder die Paketeigentumsverhältnisse unterhalb des Verzeichnisses /usr/share/postgresql-9.5/extension manuell festzustellen. Die installierten Dateien sind dann eben diejenigen, die keinem Paket zugeordnet sind.

Zu pyyaml und carto sogleich.

Datenbank erstellen

Jetzt kann mit der Erstellung der Datenbank weitergemacht werden. Dazu zunächst zum Datenbank-Superuser wechseln:

$ su -
# su - postgres
$ psql

Anschließend mit den folgenden Befehlen einen Nutzer erstellen und die Datebank namens osm einrichten. Der Datenbankname ist zwingend, es sei denn, man möchte alle Vorkomnisse dieses Datenbanknamens im Stil ändern (was vermutlich wegen der „Allerweltszeichenfolge“ osm, die in OpenStreetMap-Projekten überall vorkommen dürfte, nicht ganz einfach wäre).

CREATE USER quintus WITH PASSWORD 'geheimespasswort';
CREATE DATABASE osm WITH OWNER quintus;
\q

Die verschiedenen CREATE EXTENSION-Anweisungen gehen zum Teil auf die letzte Anleitung, zum anderen Teil auf die Installationsbeschreibung von mapnik-german-l10n zurück, wobei die unaccent-Extension vermutlich zZt. noch unnötig ist, da sie erst im master-Branch erwähnt wird. Sie wird hier dokumentiert, um sie für die nähere Zukunft präsent zu haben.

$ psql osm
CREATE EXTENSION hstore;
CREATE EXTENSION postgis;
CREATE EXTENSION unaccent;
CREATE EXTENSION osml10n;
\q

Python-Software

Die erforderliche Python-Software lässt sich wie folgt installieren (bitte darauf achten, dass das oben eingerichtete Virtualenv aktiv ist):

$ pip install pyyaml lxml mapnik nik4

Wie oben schon erwähnt, ist pyyaml erforderlich, aber nicht dokumentiert. Es wird vom später aufzurufenden Skript yaml2mml.py des deutschen OSM-Stils benötigt. Die übrige Python-Software ist Nik4 mit seinem Abhängigkeiten, dazu schon im letzten Artikel.

carto

Das offizielle carto

Auch der deutsche OpenStreetMap-Stil ist in CartoCSS realisiert, also einem Format, das durch Übersetzen zunächst in das von Mapnik verstandene XML-Format übersetzt werden muss. Dies erfolgt herkömmlicherweise mit dem NodeJS-Werkzeug carto, einer für NodeJS geschriebenen Software. Installation wie gehabt:

$ git clone git://github.com/mapbox/carto.git
$ cd carto
$ git checkout v0.16.3
$ npm install
$ export PATH="$PWD/bin:$PATH"

Magnacarto?

Alternativ soll es möglich sein, eine Alternativimplementation von CartoCSS, Magnacarto, zu benutzen, die aber schon laut Selbstbeschreibung Probleme mit dem offiziellen OSM-Stil hat, und zwar insbesondere im Bereich der Variablennamensubstitution. Versucht man die Anwendung, quittiert Magnacarto auch tatsächlich mit den folgenden Warnungen:

$ magnacarto -mml project-de.mml -builder mapnik3 > de.xml
2016/12/10 12:29:23 File not found: symbols-de/shields/motorway_[width]x[height].svg
2016/12/10 12:29:23 File not found: symbols-de/shields/motorway_[width]x[height]_z16.svg
2016/12/10 12:29:23 File not found: symbols-de/shields/motorway_[width]x[height]_z18.svg
2016/12/10 12:29:23 File not found: symbols-de/shields/primary_[width]x[height].svg
2016/12/10 12:29:23 File not found: symbols-de/shields/primary_[width]x[height]_z16.svg
2016/12/10 12:29:23 File not found: symbols-de/shields/primary_[width]x[height]_z18.svg
2016/12/10 12:29:23 File not found: symbols-de/shields/secondary_[width]x[height].svg
2016/12/10 12:29:23 File not found: symbols-de/shields/secondary_[width]x[height]_z16.svg
2016/12/10 12:29:23 File not found: symbols-de/shields/secondary_[width]x[height]_z18.svg

Es schließt aber trotzdem erfolgreich ab. Auf den ersten Blick konnte ich keine Fehler in den generierten Karten entdecken, aber um subtile Probleme zu vermeiden, rate ich daher bis auf weiteres von der Verwendung ab. Magnacarto ist in Go geschrieben, weshalb es für jemanden, der unter der unfassbar schnellen Entwicklung von NodeJS leidet, durchaus seinen Charme hat. Solange dieses Problem aber nicht gelöst ist, soll darauf nicht weiter eingegangen werden. Der Rest des Artikels benutzt das offizielle carto.

Deutschen OpenStreetMap-Stil herunterladen

Der deutsche OpenStreetMap-Stil ist ein Fork vom internationalen openstreetmap-carto, der versucht, mit ihm möglichst Schritt zu halten. Es sei in diesem Kontext besonders darauf hinweisen, dass die auf GitHub angegebenen Releases nichts mit dem deutschen Stil zu tun haben, sondern einfach nur die Tags aus dem internationalen Stil sind. Sie zu verwenden, würde dazu führen, dass man den internationalen Stil benutzt (das ist der Eigenart von Git geschuldet). Der deutsche Stil ist daher zumindest momentan immer vom Branch master aus zu benutzen; er tätigt keine eigenen Releases.

$ git clone git://github.com/giggls/openstreetmap-carto-de.git
$ cd openstreetmap-carto-de

Daten importieren

Nun kann dazu übergegangen werden, die OpenStreetMap-Daten in die neue Datenbank osm zu importieren. Da der deutsche Stil einen anderen Gebrauch von HSTORE-Spalten in PostgreSQL macht, unterscheidet sich das Import-Kommando von demjenigen für den internationalen Stil; Details dazu finden sich in der Installationsbeschreibung des Stils. Zusammen mit den Angaben aus dem vorigen Artikel ergibt sich folgendes Bild:

$ osm2pgsql --style hstore-only.style \
  --database osm --hstore --hstore-match-only \
  --prefix planet_osm_hstore --number-processes 3 \
  arnsberg-regbez-latest.osm.pbf

Im Gegensatz zu den Erklärungen im letzten Artikel sollte man erwägen, die Option --slim (und die davon abhängige Option --cache) wegzulassen, wenn man genug Arbeitsspeicher (vermutlich ab ca. 8 GiB) hat; dies führt zu einem überaus erheblichen Geschwindigkeitszuwachs beim Import. Die im letzten Artikel noch verwandte Option --multi-geometry scheint zwischenzeitlich aus osm2pgsql entfernt worden zu sein und muss daher wohl nicht mehr übergeben werden.

Die Shapefiles können ganz normal (also wie beim internationalen Stil) heruntergeladen werden (dafür einige Zeit einplanen, es werden ca. 700 MiB an Daten heruntergeladen):

$ ./get-shapefiles.sh

Views erzeugen

Der deutsche OSM-Stil benutzt SQL-Views (eine Art virtuelle Tabellen), die erst erstellt werden müssen. Dafür liefert er einige Skripte mit, die nunmehr auszuführen sind:

$ psql -d osm -f osm_tag2num.sql
$ psql -d osm -f views_osmde/view-line.sql
$ psql -d osm -f views_osmde/view-point.sql
$ psql -d osm -f views_osmde/view-polygon.sql
$ psql -d osm -f views_osmde/view-roads.sql

Das sollte anstandslos funktionieren. Taucht dagegen die folgende Fehlermeldung auf, dann wurde mapnik-german-l10n nicht in einer stabilen, sondern in einer Entwicklerversion installiert. Die Lösung des Problems besteht darin, es wieder zu deinstallieren und die letzte stabile Version zu installieren.

$ psql -d osm -f views_osmde/view-line.sql

psql:views_osmde/view-line.sql:55: FEHLER:  ungültige Eingabesyntax für Typ boolean: »de«
ZEILE 48: osml10n_get_placename_from_tags(tags,true,'de',way) as local...
                                                    ^
psql:views_osmde/view-line.sql:57: FEHLER:  Relation »planet_osm_line« existiert nicht

Anwendung

Jetzt kann der deutsche OSM-Stil in Mapnik-XML übersetzt werden. Dazu genügt ein schlichter Aufruf von make; dieser ruft dann das Skript yaml2mml.py auf, um die MML-Datei zu erzeugen, die Carto benötigt, und sodann Carto selbst, um das Mapnik-XML zu erzeugen, welches dann in der Datei osm-de.xml abgelegt wird.

$ make
scripts/yaml2mml.py --yaml project.yaml --check >project-de.mml
carto -a 3.0.9 project-de.mml > /tmp/tmp.13CgCx3nzp
mv /tmp/tmp.13CgCx3nzp osm-de.xml

Nun kann die eigentliche Kartenerstellung beginnen. An Nik4 hat sich seit dem letzten Artikel nichts maßgeblich verändert, sodass auf ihn verwiesen werden kann. Zu beachten ist lediglich, dass das zu übergebene XML das in der soeben erzeugten osm-de.xml ist. Beispielaufruf:

$ nik4.py -s 60000 --ppi 600 -a 4 \
  -c 7.6829 51.5329 --margin 10 \
  osm-de.xml print.png

Das Ergebnis sieht dann so aus wie dieses Bild (Stadt Unna und Umgebung im Maßstab 1:60000 bei 600 DPI).