Landvermesser (Linux-Magazin, Dezember 2011)

Mit GPS-Geräten schreiten Freiwillige die Straßen ihrer Heimatorte ab und erfassen Daten für die freie Weltkarte Openstreetmap. Ganz pedantische kartografieren gar die Parkzonen ihres Viertels.

(Notiz: Bitte "Ways" und "Nodes" nicht übersetzen).

Ein Blick auf die aktuelle Openstreetmap-Karte der Münchner Innenstadt (Abbildung 1) offenbart, dass genügend Freiwillige in akribischer Kleinstarbeit Kartendaten per GPS sammeln und auf dem neuesten Stand halten. Dabei glänzt das Projekt nicht nur mit Straßenverläufen und -namen, sondern auch mit Bushaltestellen, Bahnlinien und Radwegen. Bei Geschäften und Restaurants, die ihre Namen oft von einem Monat auf den anderen ändern ist Openstreetmap (OSM) mit seinem sogenannten Crowdsource-Verfahren mittlerweile aktueller als manch professioneller Anbieter.

Abbildung 1: Das Openstreetmap-Projekt zeigt die freie Karte der Münchner Innenstadt.

Freie Daten statt Google Maps

Ebenfalls ein Vorteil gegenüber kommerziellen Anbietern ist der freie Datenexport. Per Knopfdruck auf der Webseite oder programmatisch per API auf api.openstreetmap.org darf jedermann die XML-Daten herunterladen, auf der die Karten basieren. Damit öffnet sich die Tür für kreative Basteleien. Das Datenmodell ist denkbar simpel: Sogenannte "Nodes" bezeichnen Wegpunkte, die ihren Standort in der realen Welt mittels Koordinaten in geographischer Breite und Länge angeben. Nodes werden meist mit einem tragbaren GPS an markanten Punkten wie Straßenkreuzungen erfasst.

Abbildung 2: Straßen bestehen aus Wegpunkten (Nodes), die durch Strecken (Ways) verbunden sind.

Der Verlauf einer Straße ergibt sich dann durch das Verbinden dieser Nodes mit Wegstrecken, sogenannten "Ways". Eine Straße setzt sich oft aus mehreren Ways zusammen, und jeder Way kann dutzende von Nodes beinhalten, zum Beispiel weil eine Straße nicht gerade verläuft oder über Kreuzungen führt. Dort teilt sich der Way einer Straße oft einen Node mit einem Way der Querstraße (Abbildung 2).

Reality-Check

Abbildung 4 zeigt die XML-Darstellung der OSM-Daten der Sonnenstraße am Stachus in München. Ein Klick auf den Reiter "Export" in der Kartendarstellung bringt den Dialog in Abbildung 3 hoch und nach dem Auswählen der Option "XML" und dem Drücken des Submit-Buttons lädt der Web-Browser eine XML-Datei des angezeigten Bereiches herunter. Die Way-Definition im unteren Bereich von Abbildung 4 enthält Referenzen auf insgesamt elf Nodes. Die letzten beiden, 1156387191 und 361792, sind im oberen Teil der Datei als Node-Definitionen sichtbar. Neben den geographischen Koordinaten lat und lon für die geographische Breite und Länge im Digitalformat listet ein Node auch noch auf wer (user) ihn wann (timestamp) erfasst hat, und in welchem changeset die Daten an den OSM-Server hochgeladen wurden. Letztere Bündelung erlaubt es den OSM-Verwaltern, oft tausende von kleinen Änderungen in einem Rutsch zu überprüfen oder rückgängig zu machen, falls sich nach dem Hochladen herausstellt, dass die Daten falsch sind oder mit unlauteren Methoden kopiert wurden.

Abbildung 3: Die hinter der Karte stehenden XML-Daten darf jedermann herunterladen und weiterverwenden.

Abbildung 4: Der Openstreetmap-Server exportiert die Kartendaten auf Wunsch als XML unter einer freien Lizenz.

Wie genau stimmen die OSM-Daten mit der Realität überein? Als Test lassen sich die Lat/Lon-Geodaten einfach in Google-Maps eingeben, und, wie Abbildung 4 zeigt, liegen die von Freiwilligen per GPS ermittelten Koordinaten der zwei Nodes des Ways mit dem Tag "Sonnenstraße" genau im erwarteten Bereich des kommerziellen Anbieters, von dem Google die Daten kauft.

Abbildung 5: Realitäts-Check: Die Lat/Long-Koordinaten aus der Openstreetmap-Datei bezeichnen auf Google Maps einen Teil der Sonnenstraße in München.

Ways formen Straßen

Eine Straße setzt sich im XML der OSM-Datenbank aus einem oder mehreren Ways zusammen. Den Namen der Straße, zu dem ein Way gehört, führt dieser als Tag unter dem Attribut name. Die drittletzte Zeile in Abbildung 4 weist deshalb im XML-Tag <tag> des Ways dem Schlüssel k="name" den Wert v="Sonnenstraße" zu. Zu beachten ist, dass der dort gezeigte Way mit der ID 3654453 keineswegs den gesamten Verlauf der Sonnenstraße in München zeigt, sondern nur einen kleinen Abschnitt. Besonders bei längeren Straßen ist es üblich, dass mehrere Ways mit dem gleichen Tag name den Gesamtverlauf festlegen. Oft lassen sich diese Einzelabschnitte auf höherer Ebene zu etwas Sinnvollem bündeln, um etwa den Verlauf einer Trambahnlinie zu modellieren. Es ist auch nicht ungewöhnlich, dass ein Helfer im OSM-Projekt einen Way in mehrere Teile aufspalten muss, um die gewünschte Strukturierung zu ermöglichen, falls zum Beispiel zwei Teilstrecken eines Ways unterschiedlichen Geschwindigkeitsbeschränkungen unterliegen.

Flexible Strategie

Die im XML in Abbildung 4 sichtbaren Ways-Tags highway (Straßenart), lanes (Anzahl der Spuren), name (Straßenname) und oneway (Einbahnstraße) hat das Projekt über die Jahre standardisiert, doch es erlaubt praktisch beliebige Erweiterungen. Das Design wurde bewusst so flexibel ausgelegt, damit freiwillige Helfer schnell und unbürokratisch neue Funktionen hinzufügen können, ohne sich in langwierigen Gremiendiskussionen zur Erweiterung von Standards aufzureiben.

Der Nachteil dieses flexiblen Ansatzes ist ein gewisser Wildwuchs, der Anhängern normalisierter Datenbankschemata das Wasser in die Augen treibt. Damit Applikationen neu erfasste Daten weltweit verarbeiten können, müssen sich die Helfer aber irgendendwie zusammenraufen, und das geschieht üblicherweise auf dem OSM-Wiki und dessen Talk-Seiten ([7]). Schlägt dort zum Beispiel jemand ein neues Schema für Briefkästen oder Geschäftsöffnungszeiten vor, entwickelt sich nach reger Diskussion oft ein neuer Standard.

Selbst ist der Mapper

Damit Mapper selbst Änderungen in der OSM-Datenbank vornehmen können, helfen eine Reihe von Tools, allen voran die Online-Editoren JOSM ([9]) und Potlatch ([10]). JOSM ist schon etwas in die Jahre gekommen und seine im Cross-Plattform-Java-Look erscheinende Bedienoberfläche stößt Ästheten ab, doch er bietet alle notwendigen Funktionen. Betritt man exotisches Neuland mit bislang unbekannten Tags, ist JSOM sogar oft der einzige Editor mit der geforderten Funktion. Potlatch hingegen ist eine direkt im Browser laufende Flash-Applikation, die poliert daherkommt und sich mittlerweile zum Standard fürs Editieren der Karte gemausert hat.

Abbildung 6: Der JSOM-Editor lädt die Kartendaten eines ausgewählten Bereiches in den Arbeitsspeicher.

Die heute vorgestellten Änderungen, Straßensäuberungsdaten in meiner Wahlheimat San Francisco, fallen in die Kategorie "exotisch" und deswegen kommt JOSM zum Einsatz. Die in den Repositories aktueller Distributionen lungernden JSOM-Versionen sind meist veraltet, es empfiehlt sich daher, die aktuelle "josm-tested" Jar-Datei direkt von der Projektseite [9] zu laden und mit

    java -jar josm-tested.jar

zu starten (Java 1.6 erforderlich). Ein Klick auf das Icon mit dem grünen nach unten weisenden Pfeil in der Kopfleiste des Applikationsfensters (oberer Rand in Abbildung 6) öffnet ein Dialogfenster, in dem der Hobbykartograph mit der Maus einen rechteckigen Bereich auswählen kann. Drückt der User auf den weiter unten liegenden "Download"-Button, holt JSOM die selektierten Kartendaten vom OSM-Server und lädt sie in den Arbeitsspeicher des Editors. Der Mapper sieht anschließend im "Data-Layer" bereits definierte städtische Strukturen und kann Änderungen vornehmen oder neue Daten hinzufügen. Einen angezeigten Way klickt man mit der Maus an, bis er hell aufleuchtet. Im Fenster "Properties" auf der rechten Seite in Abbildung 7 erscheinen dann alle auf dem Way definierten Tags (z.B. "name", das in Abbildung 7 auf "23rd Street" gesetzt ist), und ein Klick auf den "Add"-Button öffnet ein Dialogfenster, in dem der User neue Tagnamen und die zugehörigen Werte eintragen kann.

Abbildung 7: Mit JSOM trägt der Openstreetmap-Helfer die 2-Stunden-Parkzone auf der 23sten Straße ein.

Passt alles, lädt ein Klick auf das Icon mit dem grünen Pfeil nach oben (Kopfleiste in Abbildung 6) die Daten hoch auf den OSM-Server. Hierzu registriert sich der Mapper mit seiner Email-Addresse und legt einen Useraccount mit Passwort an. Die Daten sind, ähnlich wie bei Wikipedia, ohne Prüfschritt sofort auf dem Live-Server sichtbar.

Wildwest-Parkregeln

San Francisco ist wie alle größeren Städte der Welt vollständig auf OpenStreetMap erfasst. Allerdings stellt es mit seinen komplizierten Parkregeln einige Herausforderungen an touristische Autofahrer, und diese bürokratischen Vorschriften in die freie Weltkarte einzubinden schien mir als lohnendes Projekt.

Wer meint, geparkt würde hier nach Wildwestmanier, irrt sich. Auf der 23sten Straße bei mir um die Ecke dürfen Autos ohne Anwohnerplakette montags bis freitags von 8 bis 18 Uhr nur 2 Stunden lang parken. Anwohner mit der Parkmarke "Z" sind davon ausgenommen. Außerdem fährt in San Francisco auf den meisten Straßen an bestimmten Tagen das Kehrauto ([6]) durch und während der 2-stündigen Zeitspanne darf auf der betroffenen Straßenseite niemand parken. Wer's dennoch tut bekommt einen Strafzettel über 55 Dollar ausgestellt. Das Straßenschild in Abbildung 8 zeigt die Parkbedingungen im Detail. Sie variieren oft von Kreuzung zu Kreuzung und folgen einem geheimen Plan, den nur der Kehrautofahrer kennt.

Abbildung 8: Anwohnerparken mit zweiwöchentlicher Straßenreinigung

Bis San Franciscos Parkregeln stadtweit in der OSM-Datenbank stehen, wird aber noch einige Zeit ins Land ziehen. In deutschen Landen ist man da wesentlich weiter: Aus Abbildung 9 geht hervor, dass Mapper die Parkzonen der bayrischen Stadt Bamberg praktisch vollständig erfasst haben und der extra für Parkplatzinformationen aufgestellte Server parking.openstreetmap.org blendet Parkscheiben an den entsprechenden Stellen ein. Das Wiki mit dem Vorschlag für ein Straßenparktag-Format ([8]) listet noch weitere führende Städte auf.

Abbildung 9: Die Parkzonen der Bamberger Innenstadt sind schon relativ vollständig erfasst (parking.openstreetmap.org).

Parkbürokraten am Werk

Nach langwieriger Diskussion auf dem Park-Wiki auf OSM ([7]) kristallierten sich die Tags in Abbildung 10 für Straßenparkregeln auf der ganzen Welt heraus. Die ersten drei Tags beschreiben das Anwohnerparken, der zweite Block die Straßenreinigungszeit für die linke und der dritte Block für die rechte Straßenseite.

Abbildung 10: Nach dem Hochladen der Daten zum OSM-Server weiß die ganze Welt, wann man auf der 23rd Street in San Francisco parken darf.

Doch wo ist "left" und wo "right"? Ways in OSM weisen immer in eine Richtung, denn sie zeigen von einer Node zur anderen. Dies ist für die erfasste Straße oft irrelevant (mit Ausnahme von Einbahnstraßen) und spiegelt lediglich die oft willkürliche Wahl des Mappers wider. Im Fall der Parkregeln in San Francisco legt die Richtung bei einseitig definierten Reinigungszeiten jedoch genau fest, wann das Kehrauto auf welcher Seite fährt. Abbildung 7 zeigt den Editor JOSM beim Einfügen eines neuen Tags mit dem Namen parking:condition:left:maxstay in einen Way, der Abschnitte der 23th Street mit einer Maximalparkdauer von 2 Stunden für Autos ohne Anwohnerparkmarke auszeichnet.

Noch eine Komplikation: Die Regel, dass das Kehrauto nur jeden zweiten Dienstag im Monat kommt, lässt sich ebenfalls über einen bereits verabschiedeten OSM-Standard ausdrücken. Öffnungszeiten von Geschäften gehorchen ähnlichen Regeln und deswegen schlugen die OSM-Mapper kurzum vor, die existierende Syntax auch für Parkregeln zu verwenden ([11]) gibt Auskunft darüber, wer dafür verantwortlich zeichnet und wann es passiert ist. Der Ausdruck "Fr[2,4]" steht so für den zweiten und den vierten Freitag im Monat.

Abbildung 11: Hinter dem Reiter "History" verbirgt sich ein Log mit den neuesten Änderungen, die auch rechts in der Karte hell aufleuchten.

Sofort sichtbar

Nach dem Hochladen sieht die ganze Welt sofort die Änderung und im Reiter "History" (Abbildung 11). Doch der eigentliche Clou der Geschichte ist nun, dass beliebige Applikationen die neu erfassten Daten frei nutzen können. Wie wäre es mit einem Skript, das mir Bescheid gibt, wann das Kehrauto kommt, wenn ich ihm mitteile, dass ich auf der Chattanooga Street auf der rechten Seite zwischen 23. und 24. Straße geparkt habe? Listing 1 lädt sich hierzu die XML-Daten vom OSM-Server und spuckt nach nur Sekunden die richtige Antwort aus:

    $ ./street-cleaning "Chattanooga Street" "23rd Street" "24th Street" right
    Street Cleaning: We[2,4] 08:00-10:00

Listing 1 lädt sich hierzu zunächst eine XML-Datei des Stadteils Noe Valley in San Francisco vom OSM-Server. Nach Abbildung 3 liegt das Viertel zwischen -122.43738 und -122.42098 Grad geographischer (und wegen der negativen Werte westlicher) Länge und zwischen 37.74754 und 37.7589 Grad nördlicher Breite auf dem Globus. Zeile 9 formt daraus einen URL für die API des OSM-Servers und Zeile 23 spiegelt die komprimierte XML-Datei unter map.osm.gz auf der lokalen Festplatte. Die if-Bedingungen in Zeile 22 prüfen, ob die Datei schon existiert und nicht älter als eine Woche ist, und unterbindet eine erneute Übertragung relativ neuer Daten. Der Zusatzheader "Accept-Encoding" in Zeile 20 signalisiert dem Server, dass der Client eine gzip-komprimierte Datei wünscht.

OSM-Datenfresser vom CPAN

Die XML-Daten durchforstet das Modul Geo::Parse::OSM vom CPAN, dessen Methode parse() einen Callback entgegen nimmt, den sie jedes Mal anspringt, wenn sie ein gesuchtes Element findet. Zu beachten ist, dass parse() nichts mehr findet, falls es schon einmal durchgelaufen ist, und nur ein seek_to(0) den Parser wieder auf den Anfang der Datei setzt, damit eine neue Suche stattfindet.

Listing 1: street-cleaning

    001 #!/usr/local/bin/perl -w
    002 use strict;
    003 use Geo::Parse::OSM;
    004 use Graph::Directed;
    005 use LWP::UserAgent;
    006 
    007 my @bbox = qw( -122.4374  37.74754
    008                -122.42096 37.75894 );
    009 my $url = "http://api.openstreetmap.org/" .
    010   "api/0.6/map?bbox=" . join ',', @bbox;
    011 
    012 my $mapfile = "map.osm.gz";
    013 
    014 my( $street_on, $street_cross1, 
    015     $street_cross2, $side ) = @ARGV;
    016 die "usage: $0 street cross1 cross2 side" 
    017   if !defined $side;
    018 
    019 my $ua = LWP::UserAgent->new();
    020 $ua->default_header("Accept-Encoding", 
    021                     "gzip");
    022 if( ! -f $mapfile or -M $mapfile > 7 ) {
    023   my $rsp = $ua->mirror( $url, $mapfile );
    024   $rsp->is_success or die $rsp->message();
    025 }
    026 
    027 my $osm = Geo::Parse::OSM->new( $mapfile );
    028 
    029 my %on_nodes = ();
    030 
    031 street_nodes( $osm, $street_on, sub { 
    032   $on_nodes{ $_[0] } = 1;
    033 } );
    034 
    035 my $cross1_node = cross_find( $osm, 
    036       \%on_nodes, $street_cross1 );
    037 my $cross2_node = cross_find( $osm, 
    038       \%on_nodes, $street_cross2 );
    039 
    040 my( $nodes, $flip_order) = 
    041   find_path_on_way( $osm, $street_on, 
    042          $cross1_node, $cross2_node );
    043 
    044 $side = flipside( $side, $flip_order );
    045 
    046 my $parking = parking($osm, $nodes, $side);
    047 
    048 print "Street Cleaning: ", 
    049       street_cleaning( $parking ), "\n";
    050 
    051 ###########################################
    052 sub street_nodes {
    053 ###########################################
    054   my( $osm, $name, $cb ) = @_;
    055 
    056   $osm->seek_to( 0 );
    057   $osm->parse( sub {
    058     my($n) = @_;
    059     if( exists $n->{tag}->{name} and
    060       $n->{tag}->{name} eq $name ) {
    061       for my $n ( @{ $n->{chain} } ) {
    062         $cb->( $n ) or last;
    063       }
    064     }
    065   }, only => "way");
    066 }
    067 
    068 ###########################################
    069 sub cross_find {
    070 ###########################################
    071   my($osm, $on_nodes, $cross_street) = @_;
    072 
    073   my $found;
    074   street_nodes( $osm, $cross_street, sub {
    075     my($n) = @_;
    076     if( exists $on_nodes->{ $n } ) {
    077       $found = $n;
    078       return 0; # stop iteration
    079     }
    080     return 1; # continue iteration
    081   });
    082 
    083   return $found;
    084 }
    085 
    086 ###########################################
    087 sub find_path_on_way {
    088 ###########################################
    089   my( $osm, $way_name, @nodes ) = @_;
    090 
    091   my $g = Graph::Directed->new();
    092 
    093   $osm->seek_to(0);
    094   $osm->parse(sub {
    095     my($n) = @_;
    096     if( exists $n->{tag}->{name} and
    097         $n->{tag}->{name} eq $way_name ) {
    098       $g->add_path( @{ $n->{chain} } );
    099     }
    100   }, only => "way" );
    101 
    102   my $flip_order = 0;
    103 
    104   my @path = $g->SP_Dijkstra( @nodes );
    105 
    106   if( !@path ) {
    107       @nodes = reverse @nodes;
    108       @path = $g->SP_Dijkstra( @nodes );
    109       $flip_order = 1;
    110   }
    111 
    112   return( \@path, $flip_order );
    113 }
    114 
    115 ###########################################
    116 sub parking {
    117 ###########################################
    118   my( $osm, $nodes, $side ) = @_;
    119 
    120   my %to_match = map { $_ => 1 } @$nodes;
    121   my %results  = ();
    122 
    123   $osm->seek_to( 0 );
    124   $osm->parse( sub {
    125     my($w) = @_;
    126 
    127     my @matches = 
    128       grep { exists $to_match{$_} }
    129            @{ $w->{chain} };
    130 
    131     return if @matches < 2;
    132 
    133     for my $tag ( keys %{ $w->{tag} } ) {
    134       if( $tag =~ 
    135           /parking:condition:$side:.*/ ) {
    136         $results{$tag} = $w->{tag}->{$tag};
    137       }
    138     }
    139   }, only => "way");
    140 
    141   return \%results;
    142 }
    143 
    144 ###########################################
    145 sub street_cleaning {
    146 ###########################################
    147   my( $parking ) = @_;
    148 
    149   for my $key ( keys %$parking ) {
    150     if( $key =~ /(.*)\:reason/ ) {
    151       if( $parking->{ $key } eq 
    152           "street_cleaning" ) {
    153         return $parking->{ $1 . 
    154             ":time_interval" };
    155       }
    156     }
    157   }
    158 
    159   return undef;
    160 }
    161 
    162 ###########################################
    163 sub flipside {
    164 ###########################################
    165   my($side, $flip_order) = @_;
    166 
    167   if( $flip_order ) {
    168     if( $side eq "left" ) {
    169       $side = "right";
    170     } else {
    171       $side = "left";
    172     }
    173   }
    174 
    175   return $side;
    176 }

Um nun im Straßenlabyrinth einen oder mehrere OSM-Ways zu finden, die sich zwischen zwei Querstraßen auf einer Hauptstraße befinden, legt der Aufruf von street_nodes in Zeile 31 erst einmal alle Node-Nummern der Hauptstraße als Schlüssel im Hash %on_street ab. Die Funktion street_nodes ist ab Zeile 52 definiert und klappert mit der Einschränkung only => "way" alle Ways der XML-Datei ab, sucht nach einem, der im name-Tag den Wert der Hauptstraße führt, und springt mit seiner Referenznummer den hereingereichten Callback an.

Edsger Dijkstra hilft

Gewappnet mit den Nodes der Hauptstraße bestimmen nun die Aufrufe von cross_find() (definiert ab Zeile 69) in den Zeilen 35 und 37 diejenigen Nodes, auf denen die auf der Kommandozeile angegebenen Querstraßen sich mit der Hauptstraße schneiden. Nun stehen etwa in Abbildung 12 die Nodes N2 und N5 fest. Allerdings kommt es vor, dass sich die Verbindungsstrecke zwischen zwei Kreuzungen aus mehreren Ways zusammensetzt, wie in der Abbildung 12 aus way2, way3 und way4. Von N2 ausgehend muss der Algorithmus sich nun in eine Richtung in Bewegung setzen, hoffend, dass er bei N5 ankommt und nicht in der Sackgasse bei N1 endet. Zum Glück hat Algorithmus-Urgestein Edsger W. Dijkstra dieses Problem schon 1959 gelöst ([13]) und das Modul Graph vom CPAN bietet das Verfahren mit der Methode SP_Dijkstra() an. Letztere nimmt nur die zwei zu verbindenden Nodes entgegen und berechnet auf der Basis des bislang definierten gerichteten Grafen ("Directed Acyclic Graph", DAG) den kürzesten Weg von N2 nach N5.

Abbildung 12: Die Nodes zwischen zwei Querstraßen ermittelt der "Shortes-Path"-Algorithmus von Edsger W. Dijkstra.

Die ab Zeile 87 definierte Funktion find_path_on_way() implementiert das Verfahren. Erst erzeugt sie ein neues Objekt vom Typ Graph::Directed und legt über den von parse() angesprungenen Callback für alle gefundenen Ways mit dem Straßennamen mit jeweils allen in der Datenstruktur chain enthaltenen Nodes einen Pfad im DAG an. Findet die Methode SP_Dijkstra() keinen Weg von A nach B, zeigen die willkürlich gewählten Richtungspfeile zwischen den Nodes wohl in die verkehrte Richtung und Zeile 107 dreht die Reihenfolge der Nodes um. In der Variablen flip_order merkt sich die Funktion diese Tatsache und später weiß das Hauptprogramm, dass "links" in diesem Fall nicht "links" in Richtung der Ways-Richtung meint, sondern "rechts". Die Funktion parking() stöbert durch den aus Nodes bestehenden Pfad und speichert das letzte auf den dabei durchschrittenen Ways gefundene Park-Tag. In der Annahme, dass sich die Parkzone nicht innerhalb eines Straßenblocks ändert, was für Straßenreinigungszeiten der Fall ist aber bei anderen Parkinformationen in die Hose ginge.

Fand eine Richtungsumkehr statt, ändert die Funktion flipside(), definiert ab Zeile 163 und aufgerufen in Zeile 44, den Sting "left" in "right" um und umgekehrt. Die Funktion street_cleaning() ab Zeile 145 braucht dann nur noch eventuell vorhandene Parking-Tags wie in Abbildung 10 aufzuspüren, die richtige Straßenseite ("left"/"right") zu extrahieren und auszugeben, und schon weiß der parkende Tourist wann die Kehrmaschine kommt.

Ausblick

Das Erstlingswerk "OpenStreetMap" [2] führt anschaulich in die Materie ein und stellt eine Reihe von Tools und Verfahren für den ambitionierten Streetmapper vor. Das gleichnamige Werk aus dem Packt-Verlag [3] ist sogar noch aktueller, bietet eine ausgezeichnete Einführung in die Community, zeigt viele praktische GPS-Tipps und erläutert anschaulich die OSM-Datenstrukuren und API-Funktionen.

Ich werde in den nächsten Wochen in meinem Viertel "Noe Valley" in San Francisco jedenfalls fleißig weiter Parkdaten sammeln und auf den OSM-Server hochladen. Mir schwebt eine Webapplikation vor, auf der ich den aktuellen Stellplatz meines Zweitautos Perly Perlman eintragen kann und die mich per Email warnt, falls am nächsten Tag das Kehrauto mit der Strafzettelwespe [12] im Schlepptau kommt. Das könnte sich bezahlt machen.

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2011/02/Perl

[2]

Frederik Ramm, Jochen Topf, "OpenStreetMap: Die freie Weltkarte nutzen und mitgestalten", Lehmanns Media; 3. Auflage, http://www.amazon.de/dp/3865413757

[3]

Jonathan Bennett, "OpenStreetMap", Packt Publishing (September 22, 2010), ISBN: 1847197507

[4]

Garmin GPSMAP 60CSx Handheld GPS Navigator, http://www.amazon.com/dp/B000CSOXTO

[5]

Michael Schilli, "Hinterm Horizont", GPS-Daten eines Garmin eTrex mit Perl auswerten und online in Karten einblenden, Linux-Magazin 07/2006

[6]

"Street Cleaning in San Francisco", http://www.youtube.com/watch?v=kLR0uxooEf8

[7]

Diskussion im Wiki um die neuen Park-Tags auf dem Openstreetmap-Wiki: http://wiki.openstreetmap.org/wiki/Talk:Proposed_features/parking:lane

[8]

Wiki mit dem Vorschlag für die neuen Park-Tags: http://wiki.openstreetmap.org/wiki/Proposed_features/parking:lane

[9]

Projektseite des OSM-Editors JOSM: http://josm.openstreetmap.de

[10]

Projektseite des OSM-Editors Potlatch: http://wiki.openstreetmap.org/wiki/Potlatch_2

[11]

Standards für Öffnungszeiten auf dem Openstreetmap-Wiki: http://wiki.openstreetmap.org/wiki/Key:opening_hours

[12]

Die Strafzettelwespe in San Francisco, die während der Straßenreinigungszeiten 55-Dollar-Knöllchen verteilt.

[13]

"Dijkstra-Algorithmus", http://de.wikipedia.org/wiki/Dijkstra-Algorithmus

Michael Schilli

arbeitet als Software-Engineer in der San Francisco Bay Area in Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.