[osm-bnsu] Unterlagen zum Overpass-Seminar

Roland Olbricht roland.olbricht at gmx.de
Mi Sep 24 13:43:30 CEST 2014


Hallo zusammen,

die Folien habe ich als ODP und PDF abgelegt unter
http://overpass-api.de/misc/overpass_bonn_2014.pdf
http://overpass-api.de/misc/overpass_bonn_2014.odp

Anbei außerdem das Skript, an dem ich mich gestern orientiert habe. Ich 
habe versucht, es heute noch ein wenig nachzuarbeiten. Wenn ich noch was 
vergessen habe, bitte ergänzen:

= Einführung =

Die Overpass API erlaubt es, mit den Daten von OpenStreetMap eine Menge 
interessanter Projekte zu realisieren:

Ein Beispiel ist die Unterkunftskarte
http://unterkunftskarte.de
Dort werden die Hintergrundkacheln von einer externen Quelle bezogen, 
z.B. dem Standard-Tile-Server,
die Koordinaten und Daten der angezeigten Hotels, Campingplätze und Co. 
stammen von der Overpass API,
so dass für die Website nur noch eine einfache HTML-Seite erforderlich ist.

Ein zweites Beispiel ist Maperitive:
Es erstellt Kartenkacheln oder ein großes Kartenbild für die gewünschte 
Region,
indem es die Daten für einen frei wählbaren Ausschnitt von der Overpass 
API bezieht.
Der Endnutzer bekommt so einen recht bequemen Weg, sich mit 
Offline-Karten auszustatten.

Erwähnen möchte ich auch den Export nach QGIS
(oder in vergleichbare Tools wie ArcGIS, dieses ist aber nicht frei).
Damit kann man dann die professionellen Geodaten-Tools mit 
OpenStreetMap-Daten füttern.
Durch das Vorfiltern kann man auch sehr große Gebiete auswerten,
hier z.B. die Ringstraße von Island mit 1300 km Länge.
Denkbar wäre aber eben auch die Erstellung einer Straßenliste.

Um zu verstehen, wie alle diese Anwendungen entstehen, möchte ich die 
Overpass API mit Hilfe des Diagramms einordnen:
Der wichtigste Teil ist eigentlich die große OSM-Datenbank,
links dargestellt in der Wolke.
Dies sind die von den Mappern zusammengetragenen Daten und das 
eigentliche Wunder zu OpenStreetMap.
Diese Datenbank hat als Hauptaufgabe, die Edits zuverlässig 
entgegenzunehmen,
so dass Daten auch unter widrigen Umständen gespeichert bleiben,
wenn die Datenbank sie als gespeichert meldet.
Daher exponiert die Hauptdatenbank nur eine API zum Editieren und keine 
Schnittstelle für große Downloads.
Sie stellt Datennutzern die Daten als Planet-File und als einen stetigen 
Strom von Änderungen zur Verfügung.

Die Overpass API nimmt dagegen nur diese Änderungen entgegen,
ist daher per Konstruktion nur eine billige Kopie
und kann daher deutlich mutiger Funktionalität anbieten:
Sollte die Datenbank wirklich einmal kaputtgehen,
so sind keine wichtigen Daten verloren, denn sie können einfach neu 
kopiert werden.
Die OVerpass API ist also auf schnelle Antwortzeiten statt auf große 
Datensicherheit optimiert.

Sie beantwortet dann für die eigentlich menschen-tauglichen Werkzeuge 
wie Renderer oder die obigen Beispiele Anfragen,
so dass sich diese nicht mehr um die Verwaltung der Daten kümmern müssen:
sie können sie einfach immer aktuell von der Overpass API beziehen.

Zur Erinnerung habe ich hier nocheinmal eingefügt, was von der Overpass 
API kommt:
Es ist formatierter Text, für die Facheute hier z.B. JSON.
Dort sind zwar alle Details zu erkennen, z.B.
dass es sich hier um eine Briefkasten mit diesen Koordinaten an dieser 
Referenz-Adresse handelt.
Aber für einen Menschen wäre es mühsam, seitenweise solche Inhalte 
auszuwerten.
Daher sind Tools wie Overpass Turbo
http://overpass-turbo.eu
so hilfreich, denn sie machen aus den Textdaten Karten, die für den 
Menschen intuitiv verständlich sind.


= Beispiele =

== Alle Objekte einer Art: z.B. Briefkästen ==

Wir wollen zunächst am Beispiel Briefkästen
eine Karte wie diese konstruieren
http://overpass-turbo.eu/map.html?Q=area[name%3D%22Troisdorf%22]%3Bnode%28area%29[amenity%3Dpost_box]%3Bout%3B

Dazu müssen wir im ersten Schritt herausfinden, wie Briefkästen 
eigentlich getaggt sind.

Erster Ansatz:
Suche im Wiki zu OpenStreetMap: http://wiki.openstreetmap.org/
führt uns zu
http://wiki.openstreetmap.org/wiki/Briefkasten

Für uns wichtig sind dabei neben der Tatsache, das die Seite in der Tat 
Briefkästen beschreibt,
vor allem die grüne Infobox rechts:

In der obersten Zeile steht, wie das Tag heißt, mit dem man Briefkästen 
erkennt:
amenity=post_box
Unter "für diese Elemente" finden wir die Bestätigung, dass wir nur 
Nodes berücksichtigen müssen.
Das dritte wichtige Detail ist der Link zu taginfo.
Wir brauchen ihn hier noch nicht,
aber er wird uns in den nächsten Beispielen helfen zu prüfen,
ob die Informationen im Wiki tatsächlich zutreffend sind.

Wir können damit anfangen, die Abfrage zusammenzusetzen:
Grunsätzlich reicht die Abfrage

node[amenity=post_box];
out;

Hier steht in Zeile 1: Sammele alle Nodes, die ein Tag "amenity" mit dem 
Wert "post_box" besitzen.
In Zeile 2 sagen wir, dass wir das Ergebnis auch ausgeben wollen.
Für den Anfang heißt dies bei uns immer "out;",
auf Ausgabevarianten gehen wir erst später ein.
Die eckigen Klammern sind ebenso wie das Gleichheitszeichen und 
Semikolon Teil der Syntax.
Die Zeileneinrückung und Leerzeichen sind dagegen beliebig.

Allerdings würde diese Abfrage alle Briefkästen weltweit finden.
Und dies sind etwa 165.000.
Das sind viel zu viele um sie alle anzuzeigen.

Um die Briefkästen auf Troisdorf zu begrenzen, ergänzen wir das 
Kriterium "(area)"

node(area)[amenity=post_box];
out;

Und um nur Resultate aus Troisdorf zu finden, stellen wir die Zeile

area[name="Troisdorf"];
node(area)[amenity=post_box];
out;

voran.
Hier bedeutet die erste Zeile:
Finde alle Areas, die für das Tag "name" den Wert "Troisdorf" haben.
Die Ausgabe dieser Anweisung, nämlich die eine Area, die Troisdorf 
repräsentiert,
ist die Eingabe der nächsten Anweisung.
Von allen Teilen der Anweisung liest nur "(area)" die Eingabe und 
verwendet daher die Area zum Filtern;
die Tag-Bedingung funktioniert unabhängig von vorhergehenden Anweisungen.
Auf die Besonderheiten des Datentyps "Area", der ja kein Grunddatentyp 
ist, gehen wir später ein.

Wir können die Abfrage einfach auf der Seite
http://overpass-turbo.eu
eintragen:
http://overpass-turbo.eu/s/58D
Mit "Ausführen" führen wir die Abfrage aus, mit der Lupe zentrieren wir 
auf das Ergebnis.

Mit "Export > Karte > Als interaktive Karte" gelangen wir zu der 
gewünschten Karte.


== Alle Objekte einer Art: Banken ==

In unserem nächsten Beispiel wollen wir Banken in Bonn darstellen:
Wir geben wieder "Bank" in das Suchfeld im "Wiki" ein und landen bei den 
Seiten
http://wiki.openstreetmap.org/wiki/Bank
http://wiki.openstreetmap.org/wiki/DE:Tag:amenity%3Dbank

Dort interessiert uns wieder die grüne Infobox.
Wir finden in der obersten Zeile das zutreffende Tagging:
amenity=bank

In der Mitte sehen wir bei den Symbolen, dass im Gegensatz zu 
Briefkästen hier nicht nur Nodes infrage kommen.
Freigelassen sind Nodes und geschlossene Ways, was für uns heißt: Nodes 
und Ways.

Wie Nodes gefunden werden, wissen wir schon, also setzen wir erst einmal 
mit Ways an:

area[name="Bonn"];
way(area)[amenity=bank];
out;

Geändert hat sich bis hierhin nur ein kleines Detail: Wir schreiben 
"way" statt "node",
wenn wir nach Objekten vom Typ "way" suchen.
Hier stehen wir aber jetzt dem Problem gegenüber, dass Ways ihren 
Standort nicht kennen.
Sie enthalten nur die Ids der Nodes, auf die sie verweisen.
Für die Banken, bei denen die geschlossenen Ways ja nur halbwegs kleine 
Gebäude sind,
können wir das Problem recht leicht umgehen:

area[name="Bonn"];
way(area)[amenity=bank];
out center;

"center" sorgt hier dafür, dass zu jedem Weg eine Koordinate automatisch 
ergänzt wird.
Und zwar wird der Mittelpunkt des den Weg einschließenden Rechtecks 
ausgegeben.
Das ist zwar aus Sicht der Geoinformatik kein interessanter Punkt,
aber es funktioniert für geschlossene wie offene Wege und auch Relationen
und ist außerdem auch Laien leicht zu erklären.
Für den eigentlich interessanten Centroid gilt das nicht ohne weiteres,
weswegen ich ihn erst später in der Zukunft implementieren will.

Nun fehlen uns noch die Nodes,
denn Banken können sowohl als Nodes als auch als Ways eingetragen sein:
Ist die Bank nur eine von mehreren Einrichtungen in einem Gebäude, so 
ist sie sinnvollerweise nur eine Node.
Belegt die Bank das ganze Gebäude, wird zurecht das Gebäude als Bank 
getagged.

Der einfachste Weg wäre, einfach beide Abfragen hintereinander zu schreiben:

area[name="Bonn"];
way(area)[amenity=bank];
out center;
area[name="Bonn"];
way(area)[amenity=bank];
out center;

Wir wollen nun noch eine etwas elegantere Variante entwickeln.
Hier spart das nur zwei Zeilen, bei komplexeren Abfragen kann das aber 
deutlich mehr sein.
Zunächst müssen wir dazu das Ergebnis der ersten Zeile in eine Variable 
umleiten, hier ".bonn".
Dann können wir es später mehrfach wiederverwenden,
da es von den nachfolgenden Abfragen nicht überschrieben wird:

area[name="Bonn"]->.bonn;
way(area).bonn[amenity=bank];
out center;

Nun wollen wir noch die Ergebnisse zweier Anweisungen zusammenfassen.
Dafür gibt es den "oder"-Operator.
Er wird als runde Klammer vor der ersten Anweisung notiert
und als runde Klammer hinter der letzten Anweisung.
Jetzt können wir Nodes und Ways gemeinsam ausgeben:

area[name="Bonn"]->.bonn;
( node(area.bonn)[amenity=bank];
   way(area.bonn)[amenity=bank];
  );
out center;

Shortlink: http://overpass-turbo.eu/s/58N


== Alle Objekte einer Art: Tempo-30-Straßen ==

Wir wollen nun alle Straßen mit Geschwindigkeitsbegrenzung "Tempo 30" 
ausgeben:
Die Wiki-Seiten haben ich nicht mehr in die Präsentation eingefügt,
Suchwort ist diesmal "Tempo-30-Zone" gewesen:

http://wiki.openstreetmap.org/w/index.php?search=tempo-30-zone&title=Special%3ASearch
http://wiki.openstreetmap.org/wiki/Tag:highway%3Dliving_street#Tempo-30-Zone_.28Germany.29
http://wiki.openstreetmap.org/wiki/DE:Key:maxspeed

In der grünen Infobox finden wir das passende Tagging
maxspeed=30

Wir setzen an mit:

area[name="Troisdorf"];
way(area)[maxspeed=30];
out;

Hier haben wir wieder das Problem, dass Ways ihre Geometrie nicht kennen.
In diesem Fall kommen wir mit "center" aber nicht aus,
weil zu einer kilometerlangen Straße ein einzelner Punkt nicht mehr sehr 
aussagekräftig wäre.
Wir wollen also die volle Geometrie.

Weil dies ein sehr häufiges Problem ist, gibt es dafür auch gleich eine 
fertige Lösung:

area[name="Troisdorf"];
( way(area)[maxspeed=30];
   >;
);
out;

Shortlink: http://overpass-turbo.eu/s/58K

Zum einen haben wir wieder den Oder-Operator verwendet.
Er verbindet die Way-Anweisung mit der neuen Anweisung darunter.
Diese heißt "Recurse-Down", dies ist zugegebenermaßen schlechtes 
Englisch, und meint,
dass zu den Wegen oder Relationen in ihrer Eingabe alle nötigen Nodes 
und Wege gefunden werden,
um die Objekte in der Eingabe geometrisch darstellen zu können.

Das Bild in der Anzeige von Overpass Turbo ist noch sehr unruhig:
Dies liegt daran, dass Overpass Turbo seinerseits sehr kurze Wege zu 
Punkten zusammenzieht.
Das können wir abschalten:
Unter "Einstellungen > Karte"
macht dies der Haken "Kleine Features nicht wie POIs darstellen".


= Die Syntax der Overpass-API =

Anweisungen enden stets mit einem Semikolon, werden nacheinander ausgeführt
und stehen daher auch strikt nacheinander.
Die einzige Ausnahme ist die Oder-Anweisung:
diese hat die Anweisungen, die sie auswertet, in ihrem Inneren.

Leerraum, d.h. Leerzeichen und Zeilenwechsel, kann übrigens beliebig 
verteilt werden.

Anweisungen werden notiert wie folgt:
erst kommt der Typ, dann kommen eine oder mehrere Bedingungen.
Z.B. im Beispiel "(area)" oder die eckigen Klammer mit der Tag-Vorgabe.

Ausnahmen davon sind die Anweisungen "out" und die Recurse-Varianten 
">", ">>", "<" und "<<".
Diese haben keine weitere innere Struktur, können aber auch nicht mit 
Bedingungen verknüpft werden.

Die Daten fließen entlang der Anweisungen in dem Programm.
Die Ausgabe einer Anweisung ist die Eingabe der nächsten Anweisung.
Im Beispiel hat die erste Anweisung als Ergebnis eine einzelne Area und 
keine weiteren Elemente.

area[name="Troisdorf"];
( way(area)[maxspeed=30];
   >;
);
out;

In der zweiten Anweisung wird genau an einer Stelle eine Eingabe verwendet,
nämlich in der Bedingung "(area)".
Diese verwendet das Ergebnis von gerade.
Das neue Ergebnis ersetzt nun unser erstes Ergebnis.
Es besteht aus keiner Area mehr, dafür aber aus sehr vielen Ways.

Es wird von der nächsten Anweisung als Eingabe verwendet.
Da diese Anweisung ein Recurse-Down ist,
bestimmt sie zu den Wegen ihrer Eingabe die Nodes, auf die diese Wege 
verweisen.
Das Ergebnis enthält daher jetzt keine Ways mehr, sondern nur noch Nodes.

Nun wird die Oder-Anweisung fertiggestellt.
Sie sammelt die Ergebnisse aller Anweisungen aus ihrem Inneren.
Das ist das zweite Ergebnis, das viele Ways enthalten hat,
und das dritte Ergebnis, das die zugehörigen Nodes enthalten hat.
Das Ergebnis der Oder-Anweisung besteht daher sowohl aus Nodes als auch 
aus Ways.

Dieses Ergebnis dient nun als Eingabe für die letzte Anweisung, das "out".
Hier wird das Ergebnis nicht verändert, sondern nur komplett ausgegeben.


= mehrstufige Beispiele =

Diese habe ich nicht mehr im Detail ausgeführt.
Bitte den Titel lesen, das Ergebnis anschauen und bei Bedarf nachfragen.

== Hoher Berg neben Straße ==

http://wiki.osm.org/wiki/DE:How_to_map_a#G


node[natural=peak];
out;

area[name="Rhein-Sieg-Kreis"];
node(area)[natural=peak];
out;

http://overpass-turbo.eu/s/58Y


( area[name="Rhein-Sieg-Kreis"];
   area[name="Bonn"]; );
node(area)[natural=peak];
way[highway~"primary|secondary|tertiary|unclassified|residential"](around:50);
node[natural=peak](around:50);
out;

http://overpass-turbo.eu/s/591


== Adresse zu einem Node ==

node[amenity=restaurant][name="Mistral"][website="http://www.mistral-beuel.de/"]->.poi;
way(around.poi:10)["addr:housenumber"];
out center;
way(around.poi:20)["addr:housenumber"];
out center;
way(around.poi:50)["addr:housenumber"];
out center;
way(around.poi:100)["addr:housenumber"];
out center;

http://overpass-turbo.eu/s/592


== Eigene Änderungen finden ==

( node(user:"drolbr")(newer:"2014-01-01T00:00:00Z");
   way(user:"drolbr")(newer:"2014-01-01T00:00:00Z");>;
   rel(user:"drolbr")(newer:"2014-01-01T00:00:00Z");>;
);
out meta;

http://overpass-turbo.eu/s/596


== Ergebnisse einfärben: Linienzüge ==

area[name="Troisdorf"];
way(area)[maxspeed="30"];
out;
 >;
out skel;

http://overpass-turbo.eu/s/597

http://wiki.openstreetmap.org/wiki/Overpass_turbo/MapCSS

area[name="Troisdorf"];
way(area)[maxspeed="30"];
out;
 >;
out skel;

{{style:
way[highway=service] {
   color: green;
}
way[highway=residential] {
   color: black;
}
way[highway=unclassified] {
   color: red;
}
way[highway=tertiary] {
   color: orange;
}
way[highway=secondary] {
   color: yellow;
}
}}

http://overpass-turbo.eu/s/598


== Verdächtige Objekte finden ==

area[name="Troisdorf"];
way(area)[maxspeed="30"]
   [highway!=residential]
   [highway!=service]
   [highway!=unclassified]
   [highway!=tertiary]
   [highway!=secondary];
out;
 >;
out skel;

http://overpass-turbo.eu/s/599

http://wiki.openstreetmap.org/wiki/Tag:highway%3Dfootway


== Ergebnisse einfärben: Knoten ==

area[name="Troisdorf"];
node(area)[amenity=post_box];
out;

{{style:
node {
   color: black;
}
node[operator] {
   color: gold;
}
node[operator=Deutsche Post] {
   color: green;
}
}}

http://overpass-turbo.eu/s/59a

area[name="Troisdorf"];
node(area)[amenity=post_box]
   [operator]
   [operator!="Deutsche Post"]
   [operator!="Deutsche Post AG"];
out;

http://overpass-turbo.eu/s/59b

Viele Grüße,

Roland