|
GPX-Tracks lesen und konvertieren mit Perl- Alle Angaben ohne Gewähr - 1. Das gpx-DateiformatDas gpx-Dateiformat ist eine Ausprägung von xml, die dazu gemacht ist, Ortsmarkierungen und "Tracks", die ein gps-Logger liefert, zu speichern. Zu jedem Ortspunkt eines Tracks werden in der gpx-Datei Längen- und Breitengrad, Höhe über Normalnull und Zeit gespeichert. In der Praxis sieht ein solcher Punkt dann so aus: <trkpt lat="50.633218288" lon="6.476848125"> <ele>200.091675</ele> <time>2011-10-30T13:21:55Z</time> </trkpt> 2. Das ProblemUm eine als gpx-Datei (eine fiktive Musterdatei steht hier zum Download bereit - bitte als Muster.gpx abspeichern) gespeicherte Bewegung analysieren zu können, soll sie in ein Format gebracht werxen, dass mit jeder beliebigen Tabellenkalkulation eingelesen werden kann; das csv-Format ist hier besonders geeignet. Für die Umwandlung soll ein Perl-Skript sorgen, das leicht an die besonderen Anforderungen des Nutzers angepasst werden kann. 3. Zugriff auf eine gpx-Datei mit XML::Twig1)Es gibt eine Reihe von Perl-Modulen, die Perl-Skripte in die Lage versetzen, einfach mit xml-, also insbesondere auch mit gpx-Daten umzugehen. Hier ist - letztlich mehr oder minder zufällig - die Entscheidung zugunsten von XML::Twig gefallen. Ein erstes Beispiel zeigt den Zugriff auf eine gpx-Datei mit XML::Twig: #!/usr/bin/perl -w # gpx2con.pl # Aufruf: perl gpx2con.pl Muster.gpx use strict; use XML::Twig; use Date::Parse; # my $datei = $ARGV[0]; my $twig_handlers = {'trkpt' => \&behandlung}; my $twig = new XML::Twig(TwigRoots => {trkpt => 1}, TwigHandlers => $twig_handlers); $twig->parsefile($datei); # sub behandlung{ my ($twig, $wert) = @_; my $lat = $wert->att('lat'); print $lat . ";"; my $lon = $wert->att('lon'); print $lon . ";"; my $ele = $wert->first_child('ele')->text(); print $ele . ";"; my $isotime = $wert->first_child('time')->text(); my $time = str2time($isotime); print $time . "\n"; } Das Skript (hier zum Download) gibt Längengrad, Breitengrad, Höhe und Zeit (in Sekunden seit ...) im Terminal (Standardausgabe) aus. Auf den ersten Blick fällt auf, dass Längen- und Breitengrad prinzipiell anders behandelt werden als Höhe und Zeit: Breiten- und Längengrad werden als Attribute (att) des jeweiligen TRKPTs (Trackpoints) behandelt, Höhe und Zeit sind Kinder (first_child) des jeweiligenTRKPTs bzw. GPS-Punktes. 4. Die Rundum-sorglos-LösungDas eben dargestellte Skript tut eigentlich schon alles, was notwendig ist, um eine csv-Datei und damit eine Tabellenkalkulationsdatei zu erzeugen. Speichert man die (Standard-)Ausgabe per Ausgabeumleitung oder mittels Copy&Paste als Datei ab, ist man schon am Ziel. Nun ist aber Perl dazu gemacht, Textdateien - und csv-Dateien sind letztlich Texte - komfortabel zu bearbeiten; so liegt es also nahe gleich beim Übertragen der Daten das zu erledigen, was eine Tabellenkalkulation auch nicht besser kann:
All das leistet das nachfolgende Perl-Skript: #!/usr/bin/perl -w # gpx2csv.pl, Stand 06.01.2013 # --------------------------------- # Aufruf: perl gpx2csv Muster.gpx # # --------------------------------- use strict; use XML::Twig; use Date::Parse; use Math::BigFloat; use Math::Trig; # our $count=0; our $lat; our $latrad; our $lat0rad; our $lon; our $lonrad; our $lon0rad; our $ele; our $time; our $time0; our $zeit=0; our $zeit0=0; our $isotime; our $vzeit=0; our $weg=0; our $dweg=0; our $v; # open ZIEL, ">", $ARGV[0] . ".csv"; print ZIEL "lat;lon;ele;time;t[s];s[m];t_v[s];v[m/s]" . "\n"; my $datei = $ARGV[0]; # my $twig_handlers = {'trkpt' => \&behandlung}; my $twig = new XML::Twig(TwigRoots => {trkpt => 1}, TwigHandlers => $twig_handlers); $twig->parsefile($datei); print $datei . " in csv-Datei konvertiert\n"; #---# sub behandlung{ my ($twig, $wert) = @_; $lat = $wert->att('lat'); $lon = $wert->att('lon'); if ($count>0){ $lat0rad=$latrad; $lon0rad=$lonrad; $zeit0=$zeit; }; $latrad=pi*($lat/180); $lonrad=pi*($lon/180); if ($count>0){ $dweg=6378388*acos(sin($lat0rad)*sin($latrad) +cos($lat0rad)*cos($latrad)*cos($lonrad-$lon0rad)); $weg=$weg+$dweg } $_ = $lat; s/\./,/g; print "."; print ZIEL $_ . ";"; $_ = $lon; s/\./,/g; print "."; print ZIEL $_ . ";"; $ele = $wert->first_child('ele')->text(); $_ = $ele; s/\./,/g; print "."; print ZIEL $_ . ";"; $isotime = $wert->first_child('time')->text(); $time = str2time($isotime); if ($count==0){$time0 = $time}; $zeit=$time-$time0; $_ = $time; s/\./,/g; print "."; print ZIEL $_ . ";"; $_ = $zeit; s/\./,/g; print "."; print ZIEL $_ . ";"; $_ = $weg; s/\./,/g; print "."; print ZIEL $_ . ";"; if (($count>0) && ($zeit != $zeit0)){ $vzeit=($zeit+$zeit0)/2; $_ = $vzeit; s/\./,/g; print ZIEL $_ . ";"; $v=$dweg/($zeit-$zeit0); $_ = $v; s/\./,/g; print "..\n"; print ZIEL $_ . "\n" } else { print "..\n"; print ZIEL ";\n" }; if ($count==0){$count++}; } Das Skript (hier zum Download) liefert folgende Werte:
Das Ergebnis der Umwandlung kann problemlos mit einer Tabellenkalkulation, etwa mit LibreOffice oder OpenOffice, weiterbearbeitet werden. (Das Ergebnis kann z.B. so aussehen, wie es die hier hinterlegte pdf-Datei zeigt. Dass das erstellte Diagramm sich so "sauber" darstellt, liegt daran, dass die gpx-Datei fiktiv, also am Schreibtisch "zusammengebastelt" ist.) 5. Literaturhinweise
1) Diese Darstellung fasst im Wesentlichen nur zusammen, was in verschiedenen Internetquellen (siehe Literaturliste) zum Thema zu finden ist; den Autoren verdanke ich die Vorschläge zur Lösung meines Problems - mögliche Fehler und Ungenauigkeiten habe ich verursacht. |