Google Maps + KML Dateien

Raspberry Pi

In einem anderen Artikel habe ich euch bereits gezeigt wie ihr ein GPS Modul an das Raspberry Pi anschließen und auslesen könnt. Jetzt zeige ich euch, wie ihr ein Programm entwickelt, welches automatisch Daten (z.B. von einem GPS Modul) in eine KML-Datei schreibt, welche ihr dann in Google Maps importieren könnt.

-> Was ist eine KML-Datei?:

Schauen wir uns erst einmal an, wie die KML-Datei erstellt wird. Bei einer KML-Datei handelt es sich im Grunde um eine einfache XML-Datei, welche Koordinatenpunkte oder komplette Strecken als Daten beinhaltet. Diese KML-Dateien können dann z.B. in Google-Maps oder Google-Earth importiert werden um die darin gespeicherten Koordinaten auf einer Karte sichtbar zu machen.
Eine einfache KML-Datei, welche nur einen Punkt auf der Karte markiert, sieht z.B. so aus:

Jeder Koordinateneintrag wird dabei durch ein <Placemark>-Tag eingeleitet, welches seinerseits aus einem <name>-Tag, welches den Namen des Eintrages enthält, und aus einem <Point>– oder einem <LineString>-Tag besteht.
Möchte man einen Koordinatenpunkt speichern, so nimmt man ein <Point>-Tag und dessen <coordinates>-Tag beinhaltet die Koordinaten des Punktes (Länge, Breite, Höhe).
Soll hingegen eine Strecke gezeichnet werden, so nimmt man ein <LineString>-Tag und innerhalb dieses Tags werden die Koordinaten innerhalb eines <coordinates>-Tag untereinander übermittelt:

Vorsicht!: Ein GPS Modul gibt die Koordinaten im falschen Format aus. Für eine KML-Datei werden die geografische Länge und Breite, sowie die Höhe über dem Meeresspiegel benötigt. Die meisten GPS-Module geben die Daten aber nur in Winkelminuten aus. Diese Koordinaten müssen dem entsprechend umgerechnet werden.

-> Das Python Programm:

Bevor ich mit den Anpassungen des GPS-Programms beginne, erkläre ich das Python Programm, welches die Koordinaten in das KML-File übertragen soll.
Das fertige Programm besteht eigentlich nur aus drei Unterprogrammen:

  • Ein Unterprogramm um den Dokumentkopf zu erzeugen
  • Ein Unterprogramm um einen Punkt einzutragen
  • Ein Unterprogramm um eine Strecke einzutragen

Für die Erzeugung der XML Struktur habe ich das Pythonmodul minidom verwendet. In diesem Modul wird Stück für Stück ein XML-Baum aufgebaut:

  1. Als erstes definiert man das Grundgerüst, welches als Basis für das gesamte XML Dokument gilt
  2. Dann kann man ein Element definieren und es dem Baum zuordnen. Das Ergebnis sieht dann so aus:
    <Baum>
       <Element>
       </Element>
    </Baum>
  3. Diesem Element kann man nun Attribute oder weitere Elemente zuordnen. Auf diese Weise entsteht im Laufe des Programms ein XML-Baum, welcher dann am Ende des Programms einfach in eine Datei geschrieben werden kann.

Schauen wir uns das ganze jetzt mal in der Software an…
Das erste Unterprogramm, welches am Anfang des Programms aufgerufen werden muss, ist das Unterprogramm um den XML-Baum und den Kopf anzulegen. Dieses Unterprogramm heißt CreateHead().

– Das Unterprogramm CreateHead():

Dieses Unterprogramm dient zur Erzeugung des Dokumentkopfs und der notwendigen Objekte zum erstellen eines XML-Baums.
Es gibt als Rückgabewert ein XML-Baum Objekt und ein Objekt für das Wurzelelement, also das höchste Element, zurück (bei den beiden oberen Beispielen wäre <Document> </Document> das Wurzelelement, da die beiden anderen Elemente nur Definitionen für Google Maps sind):

Der Name des Wurzelelements ist wichtig, da dieses Element als Ausgangsbasis dient und dort die Punkte oder Strecken „angeknüpft“ werden. Der komplette Baum ist anschließend in der Variable Mein_Baum gespeichert.

Wichtig: Jedes Unterprogramm zum Erzeugen eines Punktes oder einer Linie gibt den aktualisierten Baum zurück. Einerseits muss der vorhandene XML-Baum in die Unterprogramme übergeben werden und auf der anderen Seite muss der vorhandene XML-Baum mit dem zurück gegebenen Baum der Unterprogramme aktualisiert werden, da sonst die Punkte oder Strecken nicht gespeichert werden.

Wenn man mit der Erschaffung seines XML-Baums fertig ist, kann der Baum in eine Datei geschrieben werden. Dazu aber am Ende der Beschreibung mehr…
Aber was macht dieses Programm nun genau?
Als erstes wird mit der Zeile

der eigentliche XML-Baum mit dem Namen Baum erzeugt. Dieser XML-Baum dient ab jetzt als Basis für das komplette KML-File.
Damit eine KML-Datei richtig erkannt wird, wird die Zeile:

bzw. die Zeile

benötigt. Um diese Zeile zu erzeugen, erstelle ich ein neues Element mit dem Namen Attr.
Dieses Element soll dann später den Namen kml besitzen:

Der Ausdruck xmls des Elements ist eine Variable, welches die URL als Inhalt besitzt. Um eine Variable, bzw. genauer gesagt ein Attribut, einem Element zuzuordnen wird die Methode setAttribute(Variable, Inhalt) benutzt.
Diese Methode ist ein Objekt des Elements dem die Variable zugeordnet werden soll. Da die Variable dem Element Attr zugeordnet werden soll, lautet die komplette Zeile also wie folgt:

Jetzt kann das fertige Element mit der Variable an ein übergeordnetes Objekt angehängt werden. Da dieses Element das Format der XML-Datei bestimmt, muss dieses Element an den XML-Baum angehängt werden (nur so bekommt das Element die höchste Position).
Um ein Element an ein Objekt anzuhängen wird die Methode
appendChild(Element) benutzt.
Diese Methode gehört zu dem Objekt wo das Element angehängt werden soll, sprich um das Element Attr an den XML-Baum anzuhängen, muss die Zeile so geschrieben werden:

Jetzt wird das Element Attr an den XML-Baum Baum angehängt und ihm untergeordnet. Der fertige XML-Baum nimmt nun bereits diese Form an:

Genau nach diesem Schema wird jetzt das Wurzelelement, also das Element wo später die ganzen Punkte und/oder Strecken angefügt werden, erzeugt.
Als erstes wird wieder ein neues Element, welches den Namen Document bekommt, erzeugt. Das Objekt nenne ich Wurzel:

Jetzt muss dieses Element (bzw. das Wurzelelement) noch in dem XML-Baum angeordnet werden. Durch die Zeile

ordne ich das Element unter dem Element namens Attr an, sodass der XML-Baum nun folgende Gestalt besitzt:

Zum Schluss übergebe ich den bisherigen XML-Baum und das Wurzelelement (also das Element namens Document) an das Hauptprogramm, damit auf mit dieser Grundlage weiter gearbeitet werden kann.

– Das Unterprogramm WritePoint() und WriteLine():

Da das Grundgerüst für die KML-Datei nun steht, können nun Punkte und Strecken in die Datei eingetragen werden. Da sich die Unterprogramme in ihrer Funktionsweise kaum unterscheiden, erkläre ich nur das Unterprogramm um einen Punkt zu erzeugen. Das Unterprogramm um eine Strecke zu speichern unterscheidet sich nur durch die eingebaute Schleife um mehrere Koordinatenpunkte zu speichern.
Wenn man sich die obigen Beispiele für eine KML-Datei anschaut, stellt man fest, dass ein Punkt bzw. eine Strecke immer mit einem <Placemark>-Element eingeleitet wird, welches unter dem Wurzelelement Document angeordnet ist.
Dem <Placemark>-Element sind wiederum die Elemente <name> und <Point> bzw. <LineString> untergeordnet.
Dabei gibt es für jeden Punkt und jede Linie ein einzelnes <Placemark>-Element, sprich wenn eine KML-Datei zwei Punkte und eine Strecke speichern soll, werden drei <Placemark>-Elemente benötigt. Daher macht es Sinn, für die Erzeugung dieser Elemente neutrale Funktionen zu verwenden, da man so nur einmal die Funktion zur Erzeugung definieren muss. Die fertige Funktion kann man dann einfach mit verschiedenen Parametern aufrufen und das entsprechende Element erzeugen.
Das Unterprogramm zum Erzeugen eines Punktes oder einer Strecke erwarten folgende Übergabeparameter:

  • Den XML-Baum, der erweitert werden soll
  • Das Wurzel Element, an dem die Punkte oder Strecken angehängt werden sollen
  • Ein Name für den Eintrag
  • Bei Punkten: Die drei Koordinaten des Punktes
    Bei Strecken: Eine dreidimensionale Liste, welche jeden Punkt einer Strecke mit seinen drei Koordinatenpunkten beinhaltet

Nach dem Aufruf des Unterprogramms wird als erstes ein neues Element namens Placemark erzeugt und dem Wurzelelement angefügt:

Dadurch nimmt der XML-Baum folgende Gestalt an:

Dem <Placemark>-Element können nun die Informationen zu dem Punkt oder der Strecke angehängt werden.
Dafür wird als erstes der Name abgelegt. Hierfür wird ein neues Element mit dem Namen name geschaffen:

Dieses Element wird gleich dem <Placemark>-Element untergeordnet.
Dieses Element soll jetzt aber Informationen speichern. Damit das Element Daten speichern kann, muss ein Unterelement, ein sogenanntes Child, geschaffen werden, welches die Daten, also den Namen und später die Koordinaten, enthält.
Den Namen habe ich aus dem Hauptprogramm in das Unterprogramm übergeben, wo er unter der Variable Mein_Name verfügbar ist.
Das Child mit dem Namen wird nun wie folgt generiert:

Das Child ist nun unter dem Namen Inhalt verfügbar und kann nun einem Element untergeordnet werden. Da das Child dem Element name untergeordnet werden soll, sieht die Codezeile so aus:

Das <name>-Element wird jetzt, zusammen mit seinem Child, welches den Namen des Punktes enthält, an das <Placemark>-Element angehängt:

Nach dieser Zeile sieht der XML-Baum bereits so aus:

Das selbe vorgehen wird nun verwendet um die Koordinaten zu speichern:

  • Als erstes wird das Element Point erstellt und dem <Placemark>-Element angehängt:
    Point = Baum.createElement("Point")
    Placemark.appendChild(Point)
    Falls ihr eine Strecke speichern wollt, so heißt das Element nicht Point sondern LineString
  • Jetzt wird das <coordinates>-Element erzeugt:
    Coordinates = Baum.createElement(coordinates)
  • Danach wird das Child mit den Koordinaten erzeugt und dem Element <coordinates> angehängt:
    Inhalt = Baum.createTextNode(....)
    Coordinates.appendChild(Inhalt)
    Die Koordinaten wurden dabei ebenfalls vom Hauptprogramm in das Unterprogramm übergeben und werden einfach als Text dem Child zugeordnet.
  • Dieses Child mit den Koordinaten wird nun dem <coordinates>-Element angehängt:
    Point.appendChild(Coordinates)

Wichtig: Bei einer Strecke werden alle Koordinaten in einem <coordinates>-Element gespeichert!

Am  Ende des Unterprogramms wird der aktualisierte XML-Baum wieder zurück in das Hauptprogramm übergeben. Er ist nun komplett und sieht so aus:

Jetzt muss der XML-Baum nur noch in eine Datei geschrieben werden. Dies geschieht über eine einfache Datei Ein- und Ausgabe:

Die Methode „writexml()“ könnt ihr direkt so übernehmen. Sie schreibt den XML-Baum, welcher unter dem Objekt „Mein_Baum“ gespeichert ist in die Datei „Datei“. Als Resultat erhaltet ihr dann eine fertige KML-Datei, welche ihr direkt in Google Maps importieren könnt:

KML_1

Am Ende der Seite könnt ihr euch das fertige KML-Programm von mir downloaden. Jetzt könnt ihr z.B. mein GPS-Programm so umschreiben, dass es die GPS Koordinaten in eine Textdatei schreibt.
Anschließend erweitert ihr das KML-Programm so, dass es diese Textdatei ausließt, die Koordinaten extrahiert und diese Koordinaten dann in eine KML-Datei schreibt. So könnt ihr ganz einfach die Daten aus eurem GPS-Modul in Google Maps darstellen lassen.

 

Dokumentation:

 

-> Zurück zu den Basteleien mit dem Raspberry Pi

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Time limit is exhausted. Please reload CAPTCHA.