gpligc/perl/GPLIGCfunctions.pm

941 lines
26 KiB
Perl

# (c) 2001-2016 Hannes Krueger
# This file is part of the GPLIGC/ogie package
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
package GPLIGCfunctions;
#-------------------------------------------------------------------------------
sub igc2dec {
# converts igc-file-formatted coordinates (D)DDMMMMM(N|S|E|W) into decimal form
# DD MM.MMM
my $igck=shift;
if (length($igck)==8) { #Latitude DDMMMMM(N|S)
my $D=substr($igck,0,2);
my $M1=substr($igck,2,2);
my $M2=substr($igck,4,3);
my $M=$M1.".".$M2;
my $hemissphere=substr($igck,7,1);
my $latitude=($D+($M/60));
if ($hemissphere eq 'S') {$latitude=$latitude*(-1);}
return ($latitude);
}
if (length($igck)==9) { #Longitude DDDMMMMM(E|W)
my $D=substr($igck,0,3);
my $M1=substr($igck,3,2);
my $M2=substr($igck,5,3);
my $M=$M1.".".$M2;
my $hemissphere=substr($igck,8,1);
my $longitude=($D+($M/60));
if ($hemissphere eq 'W') {$longitude=$longitude*(-1);}
return ($longitude);
}
return ("Fehler in GPLIGCfunctions::igc2dec");
}
sub zan2dec {
# converts zan-file-formatted coordinates (D)DDMMSS(N|S|E|W) into decimal form
my $igck=shift;
if (length($igck)==7) { #Latitude DDMMSS(N|S)
my $D=substr($igck,0,2);
my $M=substr($igck,2,2);
my $S=substr($igck,4,2);
my $hemissphere=substr($igck,6,1);
my $latitude=($D+($M/60)+($S/3600));
if ($hemissphere eq 'S') {$latitude=$latitude*(-1);}
return ($latitude);
}
if (length($igck)==8) { #Longitude DDDMMSS(E|W)
my $D=substr($igck,0,3);
my $M=substr($igck,3,2);
my $S=substr($igck,5,2);
my $hemissphere=substr($igck,7,1);
my $longitude=($D+($M/60)+($S/3600));
if ($hemissphere eq 'W') {$longitude=$longitude*(-1);}
return ($longitude);
}
return ("Fehler in GPLIGCfunctions::zan2dec");
}
sub MaxKoor {
# gibt maximum und minimum des array (ref) zurueck
my $arrayref = shift;
my $max=${$arrayref}[0];
my $min=$arrayref->[0]; #Verschiedene Moeglichkeiten auf Element eines Arrays ber Referenz zuzugreifen
foreach (@$arrayref) {
if ($max < $_) {$max=$_;}
if ($min > $_) {$min=$_;}
}
return ($max, $min);
}
### calculates distance between two points on 'FAI-spheroid'
sub dist {
use Math::Trig;
my ($lat1, $lon1, $lat2 ,$lon2) = @_;
my $rho = 6371;
return ($rho * (acos(cos( deg2rad($lat1) ) * cos( deg2rad($lat2) ) * cos( deg2rad($lon2) - deg2rad($lon1) ) + sin( deg2rad($lat1) ) * sin( deg2rad($lat2) ) ) ) );
}
sub setpwd {
use File::Basename;
return File::Basename::dirname(shift);
}
#-------------------------------------------------------------------------------
sub time2human {
### converts time (HHMMSS) to HH:MM:SS
### or date DDMMYY to DD.MM.YY
### p=t -> time , p=d -> date
my ($time, $p) = @_;
if ($p eq 't') {my $htime = substr($time,0,2).":".substr($time,2,2).":".substr($time,4,2); return $htime;}
if ($p eq 'd') {my $htime = substr($time,0,2).".".substr($time,2,2).".".substr($time,4,2); return $htime;}
}
#########################################################
sub pointdist {
#calculates triangular distance of 3 points given by number in arrays of coordinates
my ($declat, $declon, $p1, $p2, $p3) = @_;
my $km=dist(${$declat}[$p1],${$declon}[$p1],${$declat}[$p2],${$declon}[$p2])+dist(${$declat}[$p2],${$declon}[$p2],${$declat}[$p3],${$declon}[$p3])+dist(${$declat}[$p3],${$declon}[$p3],${$declat}[$p1],${$declon}[$p1]);
return $km;
}
#-------------------------------------------------------------------------------
sub zufall {
### random integer between $min and $max
my ($min, $max) = @_;
return (int(rand $max-$min+1)+$min);
}
#--------------------------------------------------------------------------------
sub zufall2 {
### random integer between $min and $max (steps of devisor)
my ($min, $max, $devisor) = @_;
return ( (int(rand(($max-$min+1)/$devisor))* $devisor)+$min );
}
#-------------------------------------------------------------------------------
sub takeoff_detect {
### detects takeoff and landing!
my ($speedarrayref, $start_ldg) = @_;
my $lasttime=0;
my $times=0;
# check average speed...
my $speedsum = 0;
my $counter = 0;
foreach (@$speedarrayref) {
if ($_ > 5 && $_ < 500) {
$speedsum += $_;
$counter++;
}
}
if ($counter == 0) {print STDERR "GPLIGC: Warning: no data with speed between 5 and 500 km/h!\n"; $counter=1;}
my $avspeed=$speedsum/$counter;
my $limit = 2;
if ($avspeed > 30) {
$limit = 10;
}
if ($avspeed > 80) {
$limit = 40;
}
# get take-off time and return
if ($start_ldg eq 's'){
for (my $z=0; $z<=$#$speedarrayref; $z++) {
# 4x speed > 40 == takeoff... (takeofftime == time of first point > 40)
if ($speedarrayref->[$z]>$limit) {
if ($lasttime == 1) {$times++;} else {$lasttime=1;}
if ($times == 4) {return($z-4);}
} else { $lasttime=0;}
}
}
# get landing time and return
if ($start_ldg eq 'l'){
for (my $z=$#$speedarrayref; $z>=0; $z--) {
if ($speedarrayref->[$z]>$limit) {
if ($lasttime == 1) {$times++;} else {$lasttime=1;}
if ($times == 4) {return($z+4);}
} else { $lasttime=0;}
}
}
# if nothing was detected (slow paraglider etc...)
#
# hier muss noch ein algorithmus rein, der drachen flieger etc abdeckt...
# analyse der overall durchschnitsgeschwindigkeit?
#
if ($start_ldg eq 's') {return (0);}
if ($start_ldg eq 'l') {return ($#$speedarrayref);}
}
#-------------------------------------------------------------------------------
sub releaseDetect {
### tries to detect releaseTime
my ($altarrayref, $takeoff_index) = @_;
my $counter = $takeoff_index;
$takeoff_alt = $altarrayref->[$takeoff_index];
# skip until we climbed at least 150m
while ($altarrayref->[$counter] < $altarrayref->[$takeoff_index]+150) {
$counter++;
if ($counter >= $#$altarrayref) {return $takeoff_index;}
}
my $sinkcounter = 0;
for (my $c = $counter; $c <= $#$altarrayref; $c++) {
if ($altarrayref->[$c] < $altarrayref->[$c-1]) {$sinkcounter++;}
else {$sinkcounter = 0;}
if ($sinkcounter == 2) {return $c-2;}
}
}
sub OxygenStatistics {
### determines the Oxygen use according to FAA 91.211 1l/min / 10.000ft
my ($altarrayref, $dectimearrayref, $qnh) = @_;
my $time_100=0;
my $time_125=0; # minutes total
my $time_125acc=0; # minutes total
my $time_140=0;
my $time_180=0;
my $limit_100=3028;
my $limit_125=3810;
my $limit_140=4267; # 14.000ft
my $limit_180=5486; #FL180
my $free_flag = 1; # once above FL125 there is no free time between 100 an 125 any more
my $free_time=0;
my $maxalt=0;
my $maxpalt=0;
my $liters_100=0;
my $liters_125=0;
my $liters_125acc=0;
my $liters_140=0;
my $liters_180=0;
#loop
for (my $c = 0; $c <= $#$altarrayref; $c++) {
# check max
if ($altarrayref->[$c] > $maxalt) {$maxalt=$altarrayref->[$c]}
if (altitude(pressure($altarrayref->[$c],$qnh),1013.25) > $maxpalt) {$maxpalt=altitude(pressure($altarrayref->[$c],$qnh),1013.25)}
# recommended liumit FL100
if (altitude(pressure($altarrayref->[$c],$qnh),1013.24) > $limit_100 && altitude(pressure($altarrayref->[$c],$qnh),1013.24) <= $limit_125) {
$time_100 += ($dectimearrayref->[$c+1]-$dectimearrayref->[$c]);
$liters_100 += (($dectimearrayref->[$c+1]-$dectimearrayref->[$c])*60) * ((altitude(pressure($altarrayref->[$c],$qnh),1013.24)/0.3048)/10000);
}
# softlimit 125
if (altitude(pressure($altarrayref->[$c],$qnh),1013.24) > $limit_125 && altitude(pressure($altarrayref->[$c],$qnh),1013.24) <= $limit_140) {
if ($free_flag) {
if ($free_time < 0.5) {
$free_time += $dectimearrayref->[$c+1]-$dectimearrayref->[$c];
$free_flag=0 if ($free_time >= 0.5);
}
} else {
$time_125acc += ($dectimearrayref->[$c+1]-$dectimearrayref->[$c]);
$liters_125acc += (($dectimearrayref->[$c+1]-$dectimearrayref->[$c])*60) * ((altitude(pressure($altarrayref->[$c],$qnh),1013.24)/0.3048)/10000);
}
$time_125 += ($dectimearrayref->[$c+1]-$dectimearrayref->[$c]);
$liters_125 += (($dectimearrayref->[$c+1]-$dectimearrayref->[$c])*60) * ((altitude(pressure($altarrayref->[$c],$qnh),1013.24)/0.3048)/10000);
}
if (altitude(pressure($altarrayref->[$c],$qnh),1013.24) > $limit_140 && altitude(pressure($altarrayref->[$c],$qnh),1013.24) <= $limit_180) {
$free_flag=0;
$time_140 += ($dectimearrayref->[$c+1]-$dectimearrayref->[$c]);
$liters_140 += (($dectimearrayref->[$c+1]-$dectimearrayref->[$c])*60) * ((altitude(pressure($altarrayref->[$c],$qnh),1013.24)/0.3048)/10000);
}
if (altitude(pressure($altarrayref->[$c],$qnh),1013.24) > $limit_180) {
$free_flag=0;
$time_180 += ($dectimearrayref->[$c+1]-$dectimearrayref->[$c]);
$liters_180 += (($dectimearrayref->[$c+1]-$dectimearrayref->[$c])*60) * ((altitude(pressure($altarrayref->[$c],$qnh),1013.24)/0.3048)/10000);
}
}
$free_time = 0.5 if ($free_time > 0.5);
#print "Oxygen statistics:\n";
#print "above $softlimit m (min): ".($time_above_sl*60)."\n";
#print "above $hardlimit m (min): ".($time_above_hl*60)."\n";
#print "Liters to be used :".$liters_FAA." ".$liters_Oxymizer."\n";
return ($maxalt,$maxpalt,$time_100,$time_125,$time_125acc,$time_140,$time_180,$liters_100,$liters_125,$liters_125acc,$liters_140,$liters_180,$free_time);
}
#-------------------------------------------------------------------------------
sub dec2time {
### converts decimal time in (h)h:mm:ss
my $dectime= shift;
my $hh = int $dectime;
my $rest = $dectime - int $dectime;
my $mm = int(60 * $rest);
$rest= 60 * $rest - $mm;
my $ss = int (60*$rest);
$rest=60 * $rest -$ss;
if ($rest > 0.5) {$ss++;}
if ($ss == 60) {$ss=0;$mm++;}
# why was hh not 0 padded?
# I added this now 100809, side effects?
if (length($hh) == 1) {$hh = "0"."$hh";}
if (length($mm) == 1) {$mm = "0"."$mm";}
if (length($ss) == 1) {$ss = "0"."$ss";}
return ("$hh:$mm:$ss");
}
#-------------------------------------------------------------------------------
sub Ausschnitt2 {
# only for zoomfunction of FlightViewWindow!
use Math::Trig;
my ($height, $width, $lat, $lon, $kl) = @_;
my $halbkilometer=0.004496608;
my $sideratio=$width/$height;
my $xmin=$lon-($kl*$halbkilometer* ( 1/cos(deg2rad($lat)) ));
my $xmax=$lon+($kl*$halbkilometer* ( 1/cos(deg2rad($lat)) ));
my $ymin=$lat-($kl*$halbkilometer / $sideratio );
my $ymax=$lat+($kl*$halbkilometer / $sideratio );
return ($xmax, $xmin, $ymax, $ymin);
}
#-------------------------------------------------------------------------------
# calculates data for cylinders viewing in FVW...
sub zylinder2 {
use Math::Trig;
my ($lat, $lon, $r, $startangle, $angularrange) = @_; ###r=durchmesser
my $gpx;
my $start = deg2rad($startangle);
my $range = deg2rad($angularrange);
my @dlat=();
my @dlon=();
$gpx= $r * 0.0089932161;
my $step = 0.0314;
for (my $a=$start;$a<=$start+$range;$a=$a+$step) { # step 0.0314 gives 200 points on full circle
push(@dlat, cos($a)*$gpx);
push(@dlon, sin($a)*$gpx*(1/cos(deg2rad($lat))));
}
return (\@dlat, \@dlon);
} ###ende zylinder2 andere version fuer FVWindow!
#-------------------------------------------------------------------------------
# calculates sectors or starting line...
#
# NOT NEEDED, TO BE DELETED..........
sub sector {
use Math::Trig;
my ($n, $lat, $lon, $lat_after, $lon_after, $lat_before, $lon_before)= @_;
# n = 0 -> starting point
# n = 1 -> finish
# n = 2 -> wp
# n < 5 -> n km long starting-line
my $direction
}
#-------------------------------------------------------------------------------
#Calculates coordianates of a point which is in direction, distance
# from a given point
sub go {
use Math::Trig;
my ($lat, $lon, $heading, $distance) = @_;
#distance needs to be in degrees...
my $c =
(360 / (6371 * 2 * 3.141592654) ) * $distance ;
my $a = 90 - $lat;
my $beta = $heading;
# berechnung nach Seitenkosinussatz
my $b = rad2deg(acos(
cos(deg2rad($c)) * cos(deg2rad($a))
+ sin(deg2rad($c)) * sin(deg2rad($a)) * cos(deg2rad($beta))
));
my $gamma = rad2deg(asin(
( sin(deg2rad($c)) / sin(deg2rad($b)) ) * sin(deg2rad($beta))
));
return ( 90 -$b , $lon + $gamma);
}
#-------------------------------------------------------------------------------
sub sectordirection {
#berechnet den gegenkurs zur winkelhalbierenden
my ($head1, $head2) = @_;
if ($head1 < $head2) {
my $zw = $head1;
$head1 = $head2;
$head2 = $zw;
}
my $delta = $head1 - $head2;
if ($delta > 180) {
$delta = 360 - $delta;
#print "d < 180 ! \n";
return gegenkurs($head1)+$delta/2;
} else {
#print "nicht groesser \n";
my $secdir = gegenkurs($head1)-$delta/2;
if ($secdir < 0) { $secdir = $secdir + 360; }
return $secdir;
}
}
#-------------------------------------------------------------------------------
sub gegenkurs {
my $kurs = shift;
my $gegenk = $kurs - 180;
if ($gegenk < 0) {$gegenk = $gegenk + 360;}
return $gegenk;
}
#-------------------------------------------------------------------------------
sub kurs {
# calculates the heading from point 1 to point 2
# at point 1
#
#
#
#
# IV I
# -------------
# III II
#
my ($lat1, $lon1, $lat2, $lon2) = @_;
my $b = 90 - $lat1;
my $a = 90 - $lat2;
my $gamma = $lon1 - $lon2;
if ($gamma < 0) { $gamma = $gamma * -1} ;
my $c = rad2deg(acos(
cos(deg2rad($a)) * cos(deg2rad($b))
+ sin(deg2rad($a)) * sin(deg2rad($b)) * cos(deg2rad($gamma))
));
my $alpha = 0;
if ($c != 0) { # c == 0 if there is no movement ?
my $zwischenrechnung = (sin(deg2rad($a)) / sin(deg2rad($c)) ) * sin(deg2rad($gamma));
if ($zwischenrechnung > 1) {$zwischenrechnung =1;}
$alpha = rad2deg(asin($zwischenrechnung));
}
if ($lat1 >= $lat2 && $lon2 >= $lon1) { $alpha = 180-$alpha ; goto endmarke;} # quadrant 2
if ($lat1 >= $lat2 && $lon2 <= $lon1) { $alpha = 180+$alpha ; goto endmarke;} # quadrant 3
if ($lat1 <= $lat2 && $lon1 >= $lon2) { $alpha = 360-$alpha ; goto endmarke;} # quadrant 4
endmarke:
return $alpha;
}
#-------------------------------------------------------------------------------
sub coorconvert {
# converts decimal coordinates into different formats
my ($cor, $lorl, $outformat)=@_;
#lorl = lat _ or _ lon
#outformat:
# 'igc' 'igch' 'zan' 'zanh'
my $wesn;
my $deg_digits;
if ($outformat eq 'deg') {
return (sprintf("%.6f",$cor));
}
# determination of hemisphere s,n,w,e
if ($lorl eq 'lat') {
$deg_digits=2;
if (substr($cor,0,1) eq '-') {
$wesn='S'; $cor=$cor*(-1);
}
else
{$wesn='N'; }
}
if ($lorl eq 'lon') {
$deg_digits=3;
if (substr($cor,0,1) eq '-') {
$wesn='W'; $cor=$cor*(-1);
}
else
{$wesn='E'; }
}
my $deg = int $cor; #degrees
while ((length $deg) < $deg_digits) { $deg = "0".$deg;}
#pre-zeros
my $minigc = ($cor - $deg)*60; #minutes decimal
my $minzan = int (($cor - $deg)*60); #only minutes (integer)
if ((length $minzan) < 2) {$minzan="0".$minzan;} #zanderformatminutes gets filled up with zeros to 2digits
my $seczan = int(($minigc - $minzan)*60); #only seconds
#print "laenge ".(length $seczan)."\n";
my $rest_zan_sec=((($minigc-$minzan)*60)-$seczan); #rest after decimal
#print "restzansecs $rest_zan_sec \n";
if ($rest_zan_sec > 0.5) {$seczan++;}
#round up seconds if necessary
#print "igc min : $minigc \n";
my $igc_min_3stell = sprintf("%.3f",$minigc); #igc-minutes m.mmm
#print "igc_3stell $igc_min_3stell \n";
if ((substr($igc_min_3stell,2,1)) ne '.') {$igc_min_3stell="0".$igc_min_3stell;}
my $rest_igc_min = int($minigc * 1000); #cutted rest
#if ($rest_igc_min > 0.5) { $igc_min_3stell += 0.001;print "igc gerundet\n";} #round up if necessary
if ((length $seczan) < 2) {$seczan="0".$seczan;}
if ($outformat eq 'igc') {
my $igc_min_without_decimal = substr($igc_min_3stell,0,2).substr($igc_min_3stell,3,3);
return ("$deg$igc_min_without_decimal$wesn");
}
if ($outformat eq 'igch') {
return ("${deg} $igc_min_3stell\' $wesn");
}
if ($outformat eq 'zan') {
return ("$deg$minzan$seczan$wesn");
}
if ($outformat eq 'zanh') {
return ("${deg} $minzan\' $seczan\" $wesn");
}
return ("no valid outformat in GPLIGCfunctions::coorconv!!! $outformat");
}
#-------------------------------------------------------------------------------
sub pressure {
# calculates the pressure for given altitude and reference pressure, Std-Atmosphere
my $stdpress = 1013.25;
my $alt = shift;
my $p0 = shift;
if (defined $p0 && $p0 != 0) {$stdpress=$p0;}
return ( $stdpress * (1-(0.0065*$alt/288.15))**5.255 );
}
sub referencepressure {
# calculates the referencepressure p0 for given altitude and pressure, Std-Atmosphere
# my $stdpress = 1013.25;
my $alt = shift;
my $p = shift;
# if (defined $p0 && $p0 != 0) {$stdpress=$p0;}
return ( $p / ((1-(0.0065*$alt/288.15))**5.255) );
}
sub altitude {
# calculates an altitude from given pressure and reference pressue, std-atmosphere
my $stdpress = 1013.25;
my $p = shift;
my $p0 = shift;
if (defined $p0 && $p0 != 0) {$stdpress=$p0;}
return ((( 1-($p/$stdpress)**(1/5.255) ) * 288.15)/0.0065);
}
#-------------------------------------------------------------------------------
sub time2dec {
my $time = shift;
my $H=substr($time,0,2);
my $M=substr($time,2,2);
my $S=substr($time,4,2);
if (!defined $H || !defined $M || !defined $S) {
print "wrong string in time2dec: >$time<\n";
}
return ($H+(($M+($S/60))/60));
}
#-------------------------------------------------------------------------------
sub retArrayRef {
#anonymous arrayreferenz erzeugen
my @Array=();
return \@Array;
}
#-------------------------------------------------------------------------------
# this will evaluate the time of a JPEG from exif.
# single argument is a jpeg-file and return value is decimal time
# or zero in case of an error
sub getJPEGtime {
my $file = shift;
require Image::ExifTool;
my $info = Image::ExifTool::ImageInfo($file);
# for full exif tags output!
# while ( ($k,$v) = each %$info ) {
# print "$k => $v\n";
# }
if (!defined $info) {
print "GPLIGCfunctions::getJPEGtime: cant open file $file!\n";
return 0;
}
#my $image = $exif -> get_image_info();
# my $camera = $exif -> get_camera_info();
# my $other = $exif -> get_other_info();
# my %complete = (%$other, %$camera, %$image); # merging hashes into one
#my %complete = (%$info); # merging hashes into one
#print $complete."\n";
my $val;
my @times = ();
foreach $val ("DateTimeOriginal","CreateDate","Image Created", "Image Generated", "Image Digitized",
"DateTime", "Date Time", "Date and Time","ModifyDate", "FileModifyDate") {
if (exists $info->{$val}) {
# print $val." found: =>";
if ($info->{$val} =~ /(\d+):(\d+):(\d+)\s+(\d+):(\d+):(\d+)/ ){
push (@times, "$4$5$6");
# print "$4$5$6 \n";
}
}
}
# now we return the first value we found...
# maybe we can check here for multiple different times? ===15===
return (time2dec($times[0])) if ($#times >= 0);
if ($#times < 0) { return 0;}
}
# very simple geotagging!
sub geotag {
require Image::ExifTool;
my $file = shift;
my $lat = shift;
my $lon = shift;
my $alt = shift;
my $decutc = shift;
my $tzshift = shift;
my $force_overwrite = shift;
my $tagsset = 0;
my $succ=0;
my $err="no error";
#print "geotag: $file to be treated\n";
#maybe we should update the time too?
my $thingy = new Image::ExifTool;
$tagsset += $thingy -> SetNewValue('GPSLatitude', $lat);
$tagsset += $thingy -> SetNewValue('GPSLongitude', $lon);
$tagsset += $thingy -> SetNewValue('GPSLatitudeRef', 'N');
$tagsset += $thingy -> SetNewValue('GPSLongitudeRef', 'E');
if ($lat < 0) { $thingy -> SetNewValue('GPSLatitudeRef', 'S'); }
if ($lon < 0) { $thingy -> SetNewValue('GPSLongitudeRef', 'W'); }
$tagsset += $thingy -> SetNewValue('GPSAltitude', $alt);
# complains...
#$thingy -> SetNewValue('GPSAltitudeRef', '0');
# write GPS timeStamp
while ($decutc > 24) {$decutc=$decutc-24;}
$tagsset += $thingy -> SetNewValue('GPSTimeStamp', $decutc);
my $local=$decutc+$tzshift;
while ($local < 0 ) {$local=$local+24;}
while ($local > 24) {$local=$local-24;}
print "geo-tag: not enough tags set: $tagsset\n" if ($tagsset < 6) ;
# intercept error messages!
# check for existence of tags! HERE
if ($force_overwrite == 0) {
my $thingx = new Image::ExifTool;
my $info = $thingx->ImageInfo($file, 'GPSLatitude','GPSLongitude','GPSAltitude','GPSTimeStamp');
foreach (sort keys %$info) {
#print "$_ => $$info{$_}\n";
if ($_ eq "GPSLatitude" || $_ eq "GPSLongitude" ||$_ eq "GPSAltitude" || $_ eq "GPSTimeStamp") {
return 2; # tags exists!
}
}
}
($succ, $err) = $thingy ->WriteInfo($file);
if ($succ > 0) {return 1};
print "geo-tag: error: $err \n";
return 0;
}
sub getFiletime {
#require File::stat;
my $file = shift;
# print "GetFileTime: $file\n";
$x= (stat($file))[9];
my ($ss,$mm,$hh) = localtime($x);
#print "$hh : $mm : $ss \n";
my $ret = sprintf("%02d%02d%02d",$hh,$mm,$ss);
#print "$ret<===\n";
return(time2dec($ret));
}
#-------------------------------------------------------------------------------
sub get_name_date {
my ($ss, $mm, $hh, $dd, $mon, $yyyy) = gmtime ();
$mon++; # (dd: 1-31, mon: 0-11, y: yyyy -1900)
$yyyy+=1900;
$lfn= sprintf("%4d-%02d-%02d", $yyyy,$mon,$dd);
return ($lfn);
}
sub guessdatefromfilename {
my $fn = shift;
my $y = 0;
my $m = 0;
my $d = 0;
my ($name, $p, $suf) = File::Basename::fileparse($fn);
if (length($name) == 12 && lc(substr ($name,-3)) eq "igc") {
if ( substr($name,0,1) =~ /^\d+$/ ) {$y += substr($name,0,1);
$y+=2010;
}
if ( substr($name,1,1) =~ /^\d+$/ ) {$m = substr($name ,1,1)}
else {
$m = ord(lc(substr($name,1,1)))-87;
$m = 1 if ($m<10 || $m>12);
}
if ( substr($name,2,1) =~ /^\d+$/ ) {$d = substr($name ,2,1)}
else {
$d = ord(lc(substr($name,2,1)))-87;
$d = 1 if ($d<10 || $d>31);
}
}
# igc long format
if (length($name) == 25 && lc(substr ($name,-3)) eq "igc") {
if ( substr($name,0,4) =~ /^\d+$/ ) {$y = substr($name,0,4)}
if ( substr($name,5,2) =~ /^\d+$/ ) {$m = substr($name,5,2)}
if ( substr($name,8,2) =~ /^\d+$/ ) {$d = substr($name,8,2)}
}
#printf("%4d-%02d-%02d \n", $y,$m,$d);
return ($y,$m,$d);
}
# some stuff for maps:
# code from
# http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
sub getTileNumber {
my ($lat,$lon,$zoom) = @_;
my $xtile = int( ($lon+180)/360 *2**$zoom ) ;
my $ytile = int( (1 - log(tan(deg2rad($lat)) + sec(deg2rad($lat)))/pi)/2 *2**$zoom ) ;
return ($xtile, $ytile);
}
sub Project {
my ($X,$Y, $Zoom) = @_;
my $Unit = 1 / (2 ** $Zoom);
my $relY1 = $Y * $Unit;
my $relY2 = $relY1 + $Unit;
# note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi
# note: degrees(atan(sinh(pi))) = 85.051128..
#my $LimitY = ProjectF(85.0511);
# so stay simple and more accurate
my $LimitY = pi;
my $RangeY = 2 * $LimitY;
$relY1 = $LimitY - $RangeY * $relY1;
$relY2 = $LimitY - $RangeY * $relY2;
my $Lat1 = ProjectMercToLat($relY1);
my $Lat2 = ProjectMercToLat($relY2);
$Unit = 360 / (2 ** $Zoom);
my $Long1 = -180 + $X * $Unit;
return ($Lat2, $Long1, $Lat1, $Long1 + $Unit); # S,W,N,E
}
sub ProjectMercToLat($){
my $MercY = shift;
return rad2deg(atan(sinh($MercY)));
}
sub ProjectF
{
my $Lat = shift;
$Lat = deg2rad($Lat);
my $Y = log(tan($Lat) + sec($Lat));
return $Y;
}
1;