#!/usr/bin/perl -w
# (C) Jochen Puchalla 2005-2010
$steigdist=200; # minimum distance for climbing percentage calculation
# $deltat=20; # seconds between points
$g=9.81; # gravitation
$cw=0.4; # air resistance
$rho=1.2; # air density
$roll=0.003; # roll resistance
$minspeed=1.4; # ignore lower speeds than 1.4 m/s (5 km/h)
$mindeltah=1.5; # ignore height noise
use GD::Simple;
foreach $file (@ARGV)
{
if (! open(INPUT,"<$file") )
{
print STDERR "Can't open input file $file\n";
next;
}
$filecore=$file;
$filecore =~ s/.tour$//g;
if ($file eq $filecore)
{
print STDERR "$file is not a tour file\n";
$bad++;
next;
}
# open output file:
if (! open(OUTPUT,">$filecore.png") ) { print STDERR "Can't open output file $filecore.png\n"; $bad++; next; }
print "Generating $filecore.png\n";
# open gnuplot data file:
if (! open(GOUTPUT,">gnuplot.dat") ) { print STDERR "Can't open output file gnuplot.dat\n"; $bad++; next; }
printf GOUTPUT ("#Dist Alt Speed Power Rollpower Climbpower Accelpower Airpower\n");
print "Generating $filecore-data.png\n";
$distdiff=2000; # resolution for numbered length scale
# set values to 0 for every new file:
$sums=0;
$sumt=0;
$sumh=0;
$work=0;
$count=0;
$maxcount=0;
$h_max=10;
$s_max=0;
$shift=0;
$minus=-1;
# initialize some values:
$v[1]=0;
$power[1]=0;
$rollp[1]=0;
$airp[1]=0;
$climbp[1]=0;
$accelp[1]=0;
$seconds[0]=0;
$maxspeed=50; # km/h to display
while ($line=)
{
if ($line =~ /^Date=/)
{
@temp = split(/=/, $line);
$date=$temp[1];
chop $date;
if ($date =~ /^$/) {$date="unknown date";}
}
if ($line =~ /^Title=/)
{
@temp = split(/=/, $line);
$title=$temp[1];
chop $title;
if ($title =~ /^$/) {$title="untitled";}
}
if ($line =~ /^Start=/)
{
@temp = split(/=/, $line);
$start=$temp[1];
chop $start;
if ($start =~ /^$/) {$start="untitled";}
}
if ($line =~ /^Finish=/)
{
@temp = split(/=/, $line);
$finish=$temp[1];
chop $finish;
if ($finish =~ /^$/) {$finish="untitled";}
}
if ($line =~ /^Weight=/)
{
@temp = split(/=/, $line);
$W=$temp[1];
chop $W;
}
if ($line =~ /^Speed=/)
{
@temp = split(/=/, $line);
@temp2 = split(/;/, $temp[1]);
$topspeed=$temp2[0];
if ($topspeed > $maxspeed) {$maxspeed = sprintf ("%.0f", $topspeed/10)*11;}
# print "$maxspeed";
}
if ($line =~ /^Temperature=/)
{
@temp = split(/=/, $line);
@temp = split(/;/, $temp[1]);
$celsius=$temp[1]; # take medium value
}
if ($line =~ /#Pulse/) # data starts
{
while ($line=) # read all data into buffer
{
# if ($line =~ /\d/) {printf("%s hallo\n",$line);last;}
@value = split(/\t/, $line); #split at tabs
if ($line =~ /^$/) {last;}
$count++;
$h[$count]=$value[3]; # Höhe
$s[$count]=$value[7]; # Strecke
$time[$count]=$value[12]; # Zeitinfo
@part = split(/\:/, $time[$count]); #split at :
$seconds[$count]=$part[0]*3600+$part[1]*60+$part[2]; # Sekunden
# print $seconds[$count]." ";
$deltat=$seconds[$count]-$seconds[$count-1];
$s_max=$s[$count]; # total distance
if($h[$count]>$h_max){$h_max=$h[$count];} # maximum height
if($h[$count]<$minus*$shift) {$shift=$minus*$h[$count];} # negative heights?
if ($count>1) # ab 2. Datenpunkt
{
$v[$count]=($s[$count]-$s[$count-1])/$deltat; # speed
if ($v[$count]>$minspeed){$sums=$sums+($s[$count]-$s[$count-1]);$sumt=$sumt+$deltat;} # if v > minimum speed sum up distance
if ($h[$count]-$h[$count-1]>$mindeltah){$sumh=$sumh+($h[$count]-$h[$count-1]);} # if delta h > x m count height
$climbp[$count]=($h[$count]-$h[$count-1])*$g*$W/$deltat; # climb
$accelp[$count]=$W/2*($v[$count]**2-$v[$count-1]**2)/$deltat; # accel
$airp[$count]=$cw/2*$rho*$v[$count]**3; # air
$rollp[$count]=$roll*$W*$g*$v[$count]; # roll
$power[$count]=$climbp[$count]+$accelp[$count]+$airp[$count]+$rollp[$count]; # total power
if ($power[$count]<0){$power[$count]=0;} # negative power means braking!
if ($v[$count]>$minspeed){$work=$work+$power[$count]*20;} # if v > minimum speed sum up work
}
printf GOUTPUT ("%.2f $h[$count] %.2f $power[$count] $rollp[$count] $climbp[$count] $accelp[$count] $airp[$count] \n",$s[$count]/1000,$v[$count]*3.6);
}
}
}
if($sumt<600){unlink("$filecore.png"); printf STDOUT "Too little data to plot\n"; next;} # too little data to plot!
# Durchschnittsgeschw.:
$geschw=int($sums/$sumt*360)/100;
# Durchschnittsleistung:
$leistung=int($work/$sumt);
# NO NEGATIVE HEIGHTS!
$i=0;
while ($i < $count) { $i++; $h[$i]=$h[$i]+$shift; }
$h_max=$h_max+$shift;
########################### print with libgd here:
# Picture Sizes:
$xoff=20; # left offset
$legend=110; # key width
$xres=$s_max/50+$xoff+$legend; # picture width
if ($xres<$xoff+$legend+360){$xres=$xoff+$legend+360;} # minimum picture width
$xpart=$xres-$xoff-$legend; # drawing width
$ypart=sqrt($h_max)*20; # drawing height
$yres=$ypart+80; # picture height
if ($yres<260){$yres=260;} # minimum picture height
$yoff=$yres-40; # bottom offset
# create a new image
$img = GD::Simple->new($xres,$yres);
$img->bgcolor('white');
$img->fgcolor('blue');
# allocate some colors
$col1= $img->colorAllocate(0,16,48); #<-11
$col2= $img->colorAllocate(0,8,128); #-10
$col3= $img->colorAllocate(0,0,255); #-8
$col4= $img->colorAllocate(0,128,255); #-6
$col5= $img->colorAllocate(0,192,224); #-4
$col6= $img->colorAllocate(48,224,224); #-2
$col7= $img->colorAllocate(224,224,224); #0
$col8= $img->colorAllocate(224,224,48); #+2 gelb
$col9= $img->colorAllocate(224,192,0); #+4 orange
$col10= $img->colorAllocate(255,128,0); #+6
$col11= $img->colorAllocate(255,0,0); #+8 rot
$col12= $img->colorAllocate(128,8,0); #+10
$col13= $img->colorAllocate(48,16,0); #>+11
#START NAME AND HEIGHT:
$img->angle(-90);
$img->fgcolor('black');$img->bgcolor('black');
$img->moveTo($xoff-1,$yoff+22);
$img->string('- ' . $start . " - " . $h[1] . "m");
$img->angle(0);
#TITLE AND HM:
$img->fgcolor('black');$img->bgcolor('black');
$img->moveTo($xres*0.5-210,15);
$img->string($date . " - " . $title . " - " . $sumh . " Hm" . " " . $geschw . " km/h" . " " . $leistung . " W" . " " . $celsius . " C");
$h_finish=$h[$count];
$maxcount=$count;
$count=0;
$minsteig=0;
$maxsteig=0;
$h[0]=$h[1];
$s[0]=$s[1];
$olds=$s[1];
$oldh=$h[1];
#PRINT PROFILE:
while ($count < $maxcount)
{
$count++;
if($s[$count]-$olds < $steigdist){next;} # Teilstrecke lang genug f�r Plot?
$steig[$count] = ($h[$count]-$oldh) / ($s[$count]-$olds) *100 ; # Steigung
if($steig[$count] < $minsteig){$minsteig=$steig[$count]} # maximales Gef�lle
if($steig[$count] > $maxsteig){$maxsteig=$steig[$count]} # maximale Steigung
$img->fgcolor($col1);$img->bgcolor($col1);
if ($steig[$count]>-11){$img->fgcolor($col2);$img->bgcolor($col2);}
if ($steig[$count]>-9){$img->fgcolor($col3);$img->bgcolor($col3);}
if ($steig[$count]>-7){$img->fgcolor($col4);$img->bgcolor($col4);}
if ($steig[$count]>-5){$img->fgcolor($col5);$img->bgcolor($col5);}
if ($steig[$count]>-3){$img->fgcolor($col6);$img->bgcolor($col6);}
if ($steig[$count]>-1){$img->fgcolor($col7);$img->bgcolor($col7);}
if ($steig[$count]>1){$img->fgcolor($col8);$img->bgcolor($col8);}
if ($steig[$count]>3){$img->fgcolor($col9);$img->bgcolor($col9);}
if ($steig[$count]>5){$img->fgcolor($col10);$img->bgcolor($col10);}
if ($steig[$count]>7){$img->fgcolor($col11);$img->bgcolor($col11);}
if ($steig[$count]>9){$img->fgcolor($col12);$img->bgcolor($col12);}
if ($steig[$count]>11){$img->fgcolor($col13);$img->bgcolor($col13);}
my $poly = new GD::Polygon;
# print "s_max=$s_max xpart=$xpart h_max=$h_max ypart=$ypart s(count)=$s[$count]\n"; # debug
$poly->addPt($xoff+($s[$count]/$s_max*$xpart),$yoff-($h[$count]/$h_max*$ypart)); #ro
$poly->addPt($xoff+($olds/$s_max*$xpart),$yoff-($oldh/$h_max*$ypart)); #lo
$poly->addPt($xoff+($olds/$s_max*$xpart),$yoff); #lu
$poly->addPt($xoff+($s[$count]/$s_max*$xpart),$yoff); #ru
$img->penSize(1,1);
$img->polygon($poly);
$olds=$s[$count]; $oldh=$h[$count];
}
#PRINT SPEED 0-$maxspeed km/h:
$img->fgcolor($col12);
$count=1;
$olds=$s[1];
$oldv=$v[1];
while ($count < $maxcount)
{
$count++;
$img->moveTo($xoff+($olds/$s_max*$xpart),$yoff-($oldv/$maxspeed*3.6*$ypart));
$img->lineTo($xoff+($s[$count]/$s_max*$xpart),$yoff-($v[$count]/$maxspeed*3.6*$ypart)); # speed
# print "s_max=$s_max xpart=$xpart h_max=$h_max ypart=$ypart s(count)=$s[$count]\n"; # debug
$olds=$s[$count]; $oldv=$v[$count];
}
#HIGHT LINES AND SPEED:
$img->fgcolor('black');
$height=0;
$hdiff=20; # Linienabstand Höhenmeter
if($h_max>200){$hdiff=int($h_max/100)*10;}
if($h_max>1000){$hdiff=int($h_max/1000)*100;}
while ($height < $h_max-$hdiff/2)
{
$img->moveTo($xoff+0,$yoff-($height/$h_max*$ypart));
$img->string($height . 'm' . ' ' . int($height/$h_max*$maxspeed) . 'km/h');
$img->lineTo($xres-$legend,$yoff-($height/$h_max*$ypart));
$height=$height+$hdiff;
}
#PRINT HIGHEST AND LOWEST SLOPES
$count=0;
$alt=1;
$h[0]=$h[1];
$s[0]=$s[1];
$olds=$s[1];
$oldh=$h[1];
$img->angle(-90);
while ($count < $maxcount)
{
$count++;
if($s[$count]-$olds < $steigdist){next;}
$steig[$count] = ($h[$count]-$oldh) / ($s[$count]-$olds) *100 ; #Steigung
if($steig[$count]>$maxsteig*0.9 || $steig[$count]<$minsteig*0.9 || abs($steig[$count])>9.9999)
{
$steig=abs(int($steig[$count]*10)/10);
# if($steig<2){break;}
$img->fgcolor('white');
$img->moveTo($xoff+9+($olds/$s_max*$xpart),$yoff-1);
$img->string($steig . '%');
$img->moveTo($xoff+7+($olds/$s_max*$xpart),$yoff-1);
$img->string($steig . '%');
$img->moveTo($xoff+9+($olds/$s_max*$xpart),$yoff+1);
$img->string($steig . '%');
$img->moveTo($xoff+7+($olds/$s_max*$xpart),$yoff+1);
$img->string($steig . '%');
$img->fgcolor('black');
$img->moveTo($xoff+8+($olds/$s_max*$xpart),$yoff);
$img->string($steig . '%');
$alt=$alt*(-1);
}
$olds=$s[$count]; $oldh=$h[$count];
}
$img->angle(0);
#H_MAX:
$img->moveTo($xoff+0,$yoff-($ypart));
$img->string($h_max . 'm' . ' ' . $maxspeed . 'km/h');
$img->lineTo($xres-$legend,$yoff-($ypart));
#KM:
$img->fgcolor('black');
$img->angle(-90);
$dist=0;
$bw=1;
while ($dist < $s_max-$distdiff)
{
#LINIE UND ZAHL:
$img->fgcolor('black');$img->bgcolor('black');
$img->moveTo($xoff+$dist/$s_max*$xpart,$yoff+32);
$img->string($dist/1000);
$img->moveTo($xoff+$dist/$s_max*$xpart,$yoff+28); #unten
$img->lineTo($xoff+$dist/$s_max*$xpart,$yoff); #oben
#EISENBAHNFELD:
my $poly = new GD::Polygon;
if($bw<0){$img->bgcolor('white');}
$poly->addPt($xoff+$dist/$s_max*$xpart,$yoff); #lo
$poly->addPt($xoff+($dist+$distdiff)/$s_max*$xpart,$yoff); #ro
$poly->addPt($xoff+($dist+$distdiff)/$s_max*$xpart,$yoff+5); #ru
$poly->addPt($xoff+$dist/$s_max*$xpart,$yoff+5); #lu
$img->penSize(1,1);
$img->polygon($poly);
$bw=$bw*(-1); #B/W-Flag
#WEITERGEHEN:
$dist=$dist+$distdiff;
}
#LETZTE LINIE UND ZAHL:
$img->fgcolor('black');$img->bgcolor('black');
$img->moveTo($xoff+$dist/$s_max*$xpart,$yoff+32);
$img->string($dist/1000);
$img->moveTo($xoff+$dist/$s_max*$xpart,$yoff+28); #unten
$img->lineTo($xoff+$dist/$s_max*$xpart,$yoff); #oben
#LETZTES EISENBAHNFELD:
my $poly = new GD::Polygon;
if($bw<0){$img->bgcolor('white');}
$poly->addPt($xoff+$dist/$s_max*$xpart,$yoff); #lo
$poly->addPt($xoff+$s_max/$s_max*$xpart,$yoff); #ro
$poly->addPt($xoff+$s_max/$s_max*$xpart,$yoff+5); #ru
$poly->addPt($xoff+$dist/$s_max*$xpart,$yoff+5); #lu
$img->penSize(1,1);
$img->polygon($poly);
#S_MAX UND FINISH NAME AND HEIGHT:
$img->fgcolor('black');$img->bgcolor('black');
$img->moveTo($xoff+14+$xpart,$yoff+32);
$img->string($s_max/1000 . 'km - ' . $finish . " - " . $h_finish . "m");
$img->moveTo($xoff+$s_max/$s_max*$xpart,$yoff+28);
$img->lineTo($xoff+$s_max/$s_max*$xpart,$yoff);
#LEGENDE:
$img->angle(0);
my $poly2 = new GD::Polygon;
$img->fgcolor($col1);$img->bgcolor($col1);
$poly2->addPt($xres-20,0);
$poly2->addPt($xres,0);
$poly2->addPt($xres,20);
$poly2->addPt($xres-20,20);
$img->polygon($poly2);
$img->fgcolor('black');
$img->moveTo( $xres-60,17 );
$img->string('< -11%');
my $poly3 = new GD::Polygon;
$img->fgcolor($col2);$img->bgcolor($col2);
$poly3->addPt($xres-20,20);
$poly3->addPt($xres,20);
$poly3->addPt($xres,40);
$poly3->addPt($xres-20,40);
$img->polygon($poly3);
$img->fgcolor('black');
$img->moveTo( $xres-90,37 );
$img->string('-11% - -9%');
my $poly4 = new GD::Polygon;
$img->fgcolor($col3);$img->bgcolor($col3);
$poly4->addPt($xres-20,40);
$poly4->addPt($xres,40);
$poly4->addPt($xres,60);
$poly4->addPt($xres-20,60);
$img->polygon($poly4);
$img->fgcolor('black');
$img->moveTo( $xres-90,57 );
$img->string('-9% - -7%');
my $poly5 = new GD::Polygon;
$img->fgcolor($col4);$img->bgcolor($col4);
$poly5->addPt($xres-20,60);
$poly5->addPt($xres,60);
$poly5->addPt($xres,80);
$poly5->addPt($xres-20,80);
$img->polygon($poly5);
$img->fgcolor('black');
$img->moveTo( $xres-84,77 );
$img->string('-7% - -5%');
my $poly6 = new GD::Polygon;
$img->fgcolor($col5);$img->bgcolor($col5);
$poly6->addPt($xres-20,80);
$poly6->addPt($xres,80);
$poly6->addPt($xres,100);
$poly6->addPt($xres-20,100);
$img->polygon($poly6);
$img->fgcolor('black');
$img->moveTo( $xres-84,97 );
$img->string('-5% - -3%');
my $poly7 = new GD::Polygon;
$img->fgcolor($col6);$img->bgcolor($col6);
$poly7->addPt($xres-20,100);
$poly7->addPt($xres,100);
$poly7->addPt($xres,120);
$poly7->addPt($xres-20,120);
$img->polygon($poly7);
$img->fgcolor('black');
$img->moveTo( $xres-84,117 );
$img->string('-3% - -1%');
my $poly8 = new GD::Polygon;
$img->fgcolor($col7);$img->bgcolor($col7);
$poly8->addPt($xres-20,120);
$poly8->addPt($xres,120);
$poly8->addPt($xres,140);
$poly8->addPt($xres-20,140);
$img->polygon($poly8);
$img->fgcolor('black');
$img->moveTo( $xres-84,137 );
$img->string('-1% - +1%');
my $poly9 = new GD::Polygon;
$img->fgcolor($col8);$img->bgcolor($col8);
$poly9->addPt($xres-20,140);
$poly9->addPt($xres,140);
$poly9->addPt($xres,160);
$poly9->addPt($xres-20,160);
$img->polygon($poly9);
$img->fgcolor('black');
$img->moveTo( $xres-84,157 );
$img->string('+1% - +3%');
my $poly10 = new GD::Polygon;
$img->fgcolor($col9);$img->bgcolor($col9);
$poly10->addPt($xres-20,160);
$poly10->addPt($xres,160);
$poly10->addPt($xres,180);
$poly10->addPt($xres-20,180);
$img->polygon($poly10);
$img->fgcolor('black');
$img->moveTo( $xres-84,177 );
$img->string('+3% - +5%');
my $poly11 = new GD::Polygon;
$img->fgcolor($col10);$img->bgcolor($col10);
$poly11->addPt($xres-20,180);
$poly11->addPt($xres,180);
$poly11->addPt($xres,200);
$poly11->addPt($xres-20,200);
$img->polygon($poly11);
$img->fgcolor('black');
$img->moveTo( $xres-84,197 );
$img->string('+5% - +7%');
my $poly12 = new GD::Polygon;
$img->fgcolor($col11);$img->bgcolor($col11);
$poly12->addPt($xres-20,200);
$poly12->addPt($xres,200);
$poly12->addPt($xres,220);
$poly12->addPt($xres-20,220);
$img->polygon($poly12);
$img->fgcolor('black');
$img->moveTo( $xres-84,217 );
$img->string('+7% - +9%');
my $poly13 = new GD::Polygon;
$img->fgcolor($col12);$img->bgcolor($col12);
$poly13->addPt($xres-20,220);
$poly13->addPt($xres,220);
$poly13->addPt($xres,240);
$poly13->addPt($xres-20,240);
$img->polygon($poly13);
$img->fgcolor('black');
$img->moveTo( $xres-90,237 );
$img->string('+9% - +11%');
my $poly14 = new GD::Polygon;
$img->fgcolor($col13);$img->bgcolor($col13);
$poly14->addPt($xres-20,240);
$poly14->addPt($xres,240);
$poly14->addPt($xres,260);
$poly14->addPt($xres-20,260);
$img->polygon($poly14);
$img->fgcolor('black');
$img->moveTo( $xres-60,257 );
$img->string('> +11%');
print OUTPUT $img->png;
close OUTPUT;
close GOUTPUT;
close INPUT;
if (-z "$filecore.png"){remove("$filecore.png")};
########################### print with gnuplot here:
open(GNUPLOT,"|gnuplot ") || die("can't call gnuplot \n");
GNUPLOT->autoflush(1);
print GNUPLOT <<"--END--";
set term png enhanced large size 1280,800
set out "gnuplot.png"
set grid
set mxtics 5
set lmargin 5
set rmargin 4
set tmargin 0
set bmargin 2
set style data lines
set multiplot
set size 1,0.32
set origin 0,0
plot "gnuplot.dat" using 1:4 title "Leistung [W]" linewidth 3 lt 2
replot "gnuplot.dat" using 1:4 smooth bezier title "ca. Leistung [W]" linewidth 3 lt 1
#unset xtics
set origin 0,0.32
plot "gnuplot.dat" using 1:3 title "Geschw. [km/h]" linewidth 3 lt 3
set origin 0,0.64
set title "$date $title (von $start nach $finish) $sumh Hm $geschw km/h $leistung W $celsius C" 0,-1
plot "gnuplot.dat" using 1:2 title 'Hoehe [m]' linewidth 3 lt -1
#replot "gnuplot.dat" using 1:5 title "Rollwiderstand [W]" linewidth 3
#replot "gnuplot.dat" using 1:6 title "Steigleistung [W]" linewidth 3
#replot "gnuplot.dat" using 1:7 title "Beschl.leistung [W]" linewidth 3
#replot "gnuplot.dat" using 1:8 title "Luftwiderstand [W]" linewidth 3
--END--
close(GNUPLOT);
rename "gnuplot.png","$filecore-data.png";
unlink("gnuplot.dat");
}
exit(0);