środa, 20 sierpnia 2008

Przewyższenie i profil śladu

Etrex mimo, że nie ma barometru dość sensownie podaje wysokość npm. Jakoś do tej pory umknęło to mojej uwadze.

Poniżej skrypt wyznaczający długość trasy, łączną sumę wysokości podjazdów (przewyższenie, aka cumulative elevation gain) oraz rysujący profil w postaci pliku PNG. To ostatnie niekoniecznie jest sensowne, bo GD::Graph::lines traktuje dane z osi OX jako napisy a nie liczby i w związku z tym odstępy między poszczególnymi punktami na tej osi są równe. Zamiast GD::Graph::lines trzeba użyć czegoś innego, np. Chart::Graph::Gnuplot.


#!/usr/bin/perl
#
# Tworzy plik PNG przedstawiający profil śladu (wysokość mnpm)
# z danych podanych (jako argument skryptu) w pliku GPX
# tprzechlewski[_at_]gmail.com sierpień/2008
#
use XML::LibXML;
use Geo::Distance;
use Getopt::Long;

GetOptions( 'log' => \$print_log, 'pic' => \$print_pic, );

$usage = "Usage: $0 [-p | -l] plik.gpx ;; -p generate PNG file ; -l show log.\n";

my $geo = new Geo::Distance;

my $file = shift || die "$usage";

my $parser = XML::LibXML->new;

open my $fh, $file || die "problems...";

$doc = $parser->parse_fh($fh);

my @tracks = $doc->getElementsByTagName('trk');
my $ptnum=0;

for $tx (@tracks) {

@segments = $tx->getChildrenByTagName('trkseg');
if ( $name = $tx->getChildrenByTagName('name')->[0] ) { # pierwszy element to nazwa śladu
if ($print_log) { print "<!-- track:: ", $name->textContent(), " -->\n"; }
}

for $sx (@segments) {

@points = $sx->getChildrenByTagName('trkpt');

for $px (@points) {
@data = $px->getChildrenByTagName('*');
@attrs = $px->attributes();

if ($print_log) { print "-> " ; }

for $dx (@data) {
if ($print_log) { print $dx->nodeName, " = ", $dx->textContent(), " ; " ; }
if ($dx->nodeName eq 'ele') { $ele = $dx->textContent();
push @Elevations, $ele;
}
}

for $ax (@attrs) {
if ($print_log) { print " ", $ax->nodeName, " = ", $ax->getValue() ; }
if ($ax->nodeName eq 'lon') { $lon = $ax->textContent() }
elsif ($ax->nodeName eq 'lat') { $lat = $ax->textContent() }
}

if ($print_log) { print " ;;\n"; }

if ( $ptnum > 0 ) {
$curr_dist = $geo->distance( "meter", $plon, $plat => $lon, $lat );
$dist += $curr_dist ;
push @Distances, $curr_dist;
if (($ele_diff = $ele - $pele ) > 0) { $totalEleGain += $ele_diff ; }

} else {
push @Distances, 0;
}

$plon = $lon; $plat = $lat ; $pele = $ele ; $ptnum++;
}
}
}

# http://en.wikipedia.org/wiki/Cumulative_elevation_gain (przewyższenie):
printf "*** Dist: %.1f meters *** EleGain: $totalEleGain ***\n", $dist;

## Drukowanie profilu trasy

unless ( $print_pic ) { exit 0 }

use GD::Graph::lines;
use POSIX; # floor

my $img_file = "${file}.png" ;

my @data = (\@Distances, \@Elevations, );

my $mygraph = GD::Graph::lines->new(400, 300);

# skip some dates to avoid label overlapping on X-axis:
my $x_factor = floor (($#Distances + 1) / 10 ) + 2;
print "$#Distances observations. X-axis labels printed evey ${x_factor}th one!\n";

$mygraph->set_text_clr('black');
$mygraph->set(
x_label => 'Dist',
y_label => '#',
title => "# Elev",
# Draw datasets in 'solid', 'dashed' and 'dotted-dashed' lines
line_types => [1, 1, ],
# Set the thickness of line
line_width => 2,
# Set colors for datasets
dclrs => ['blue', 'red', 'cyan'],
#x_tick_number => 'auto',
x_label_skip => $x_factor,
transparent => 0, ## non-transparent
bgclr => 'white',
fgclr => 'black',
borderclrs => 'black',
boxclr => '#ede7e7',
labelclr => 'black',
#axislabelclr,
legendclr => 'black',
) or warn $mygraph->error;

$mygraph->set_legend_font(GD::gdMediumBoldFont);
$mygraph->set_legend('ele', 'ele2', '???');

my $myimage = $mygraph->plot(\@data) or die $mygraph->error;

## for cgi script uncomment:
##print "Content-type: image/png\n\n";

open ( IMG, ">$img_file") or die " *** Problems opening: $img_file ***" ;

print IMG $myimage->png;

close (IMG);

##print "@Distances\n"; ## debug

##

Wykorzystuję od jakiegoś czasu XML::LibXML. W skryptach do obsługi flickr.com korzystałem z XML::Simple ale do parsowania plików GPX ten pakiet się nie nadaje -- nie zachowuje porządku elementów (bo je czyta do hasza). W oczywisty sposób porządek punktów na śladzie nie może być dowolny.

A tutaj ktoś zrobił coś podobnego tyle, że używając Pythona.

Brak komentarzy:

Prześlij komentarz