📄 rideplot
字号:
#!/usr/bin/perl# # rideplot - convert a GPS track to a graph/map image# Copyright (c) 2000-2001 by Ian Kluft## This is copyrighted Open Source software. The author permits# redistribution under the terms of the GNU General Public License# (GPL) version 2. ( http://www.fsf.org/copyleft/gpl.html ) The# author requests that enhancements should be contributed back in# order to extend the original software distribution.## For details about rideplot see http://rideplot.sourceforge.net/## This software converts track and waypoint data downloaded from a # GPS into a PNG image which graphically represents the track# like a map. The resulting image may then be edited with GIMP or# another image editor to produce custom maps based on GPS-recorded# courses previously travelled.## Perl POD embedded documentation is included at the bottom of the file.# Simon G Modifications.# --------------------- # $date is now yyyy/mm/dd instead of mm/dd/yyyy. # cos 20020523 is bigger than 05232002 !! And# much easier with mathematic calculations.## Options that require an extra value if used were made a requirement# instead of an option. ;)# All units are metric but there is a nonmetric option. --nonmetric# All internal coordinates are now in DEGREES(dd.dddd...)## Multi-format input data added # -> GPSTRANS, GARDOWN, GD2 (deg mins), GD2d (-f 1 (Degrees)), PCX5.## Mapblast retrieval url for a background map ! with an# Option to get it and save it to a file. --map-get=str## Track has a transparent background for easy merging.# Option for inverted speed colors. --color=2# Option for an output file. --output=<FILE># Option to include the name beside the waypoints. --waypoint-name# Option to merge the Waypoints with the Track. --waypoint-merge# Help option --help that displays the embedded POD ducumentation.## FIXED: --brush-color option didn't work. Error with parsing of option value## by Simon G junk@simong.net May 2002.# Dated: 2002-05-27 yyyy-mm-dd#use GD; # Graphics libraryuse POSIX qw( atan asin cos sin sqrt strftime);use Date::Calc qw( Delta_DHMS Decode_Date_US Decode_Month Add_Delta_DHMS );use Getopt::Long; # Command line optionsuse Pod::Usage; # Help uses the embedded POD documentationuse Image::EXIF; # Extracts EXIF information from photorequire LWP::UserAgent; # Http GET etc.use Data::Dumper;use strict;use vars qw( $debug $deg $pi $km_per_mile $nonmetric $dist_m $x_scale $y_scale $image $max_x $max_y $white $black $blue $dot_brush $dot_fg $dot_bg $scale @data $avg_lat $lat_scale $maxlat $minlat $maxlon $minlon $point $mb_scale $mid_lat $mid_lon $data_format $img_x $img_y $londist $latdist $map_url $map_file $map_get $maxspeed $use_color @sp_color @sp_brush $maxwidth $maxheight $speed_cutoff $cutoff_count $brush_width $brush_color $output_file @waypoints $waypoint_file $waypoint_width $waypoint_fill $waypoint_name $waypoint_merge $photo_dir @photos @mapped_photos $photo_idx $imap_file $transparent);# convert degrees/min/sec to decimal degrees.sub dms2deg{ my ( $str ) = @_; $debug and print STDERR "dms2deg coordinate: $str\n"; if ( $data_format =~ /gpstrans/ ) { # GPSTRANS if ( $str =~ /^-{0,1}[0-9]+\.[0-9]+$deg$/o ) { return 0.0 + $str; } if ( $str =~ /^(-{0,1})([0-9]+)$deg([0-9]+\.[0-9]+)\'$/o ) { return ( 0.0 + $2 + $3/60.0) * (($1 eq "-") ? -1.0 : 1.0 ); } if ( $str =~ /^(-{0,1})([0-9]+)$deg([0-9]+)\'([0-9]+\.[0-9]+)\"$/o ) { return ( 0.0 + $2 + $3/60.0 + $4/3600.0 ) * (($1 eq "-") ? -1.0 : 1.0 ); } $debug and print STDERR "dms2deg: misformatted coordinate: $str\n"; return undef; # END GPSTRANS } else { die "$0 dms2deg: Unknown data_format $data_format\n"; }}# convert N S E W degrees/min to decimal degrees.sub dm2deg{ my ( $str ) = @_; $debug and print STDERR "dm2deg coordinate: $str\n"; if (( $data_format =~ /gd/ ) or ( $data_format =~ /gardown/ )) { # GD2 if ( $str =~ /^([NSEW])([0-9]+)$/o ) { return 0.0 + $2 * ((($1 eq "S") or ($1 eq "W")) ? -1.0 : 1.0 ); } if ( $str =~ /^([NSEW])([0-9]+)\s([0-9]+\.[0-9]+)$/o ) { return ( 0.0 + $2 + $3/60.0 ) * ((($1 eq "S") or ($1 eq "W")) ? -1.0 : 1.0 ); } $debug and print STDERR "dm2deg: misformatted coordinate: $str\n"; return undef; # END GD2 } else { die "$0 dm2deg: Unknown data_format $data_format\n"; }}# convert latitude/longitude to x/ysub ll2xy{ my ( $lat, $lon, $maxlat, $minlat, $maxlon, $minlon, $max_x, $max_y ) = @_; my ( $x, $y ); $x = int (( $lon - $minlon ) / ( $maxlon - $minlon ) * $max_x )+$brush_width+1; $y = $max_y - ( int (( $lat - $minlat ) / ( $maxlat - $minlat ) * $max_y ))+$brush_width+1; $debug and print STDERR "ll2xy: lat=$lat lon=$lon max_x=$max_x max_y=$max_y x=$x y=$y\n"; return ( $x, $y );}sub interpolate{ my ($prevtime, $timestr, $photo_time, $prevlat, $prevlon, $lat, $lon) = @_; my ($interplat, $interplon); # Do linear interpretation # Get total difference in seconds # compute time in seconds my @ttime = Delta_DHMS( datetime2array( $prevtime ), datetime2array( $timestr )); my $tsec = $ttime[0]*86400 + $ttime[1]*3600 + $ttime[2]*60 + $ttime[3]; # compute delta time in seconds my @dtime = Delta_DHMS( datetime2array( $prevtime ), datetime2array( $photo_time )); my $dsec = $dtime[0]*86400 + $dtime[1]*3600 + $dtime[2]*60 + $dtime[3]; $interplat = $prevlat + ( $lat - $prevlat ) * $dsec / $tsec; $interplon = $prevlon + ( $lon - $prevlon ) * $dsec / $tsec; return ($interplat, $interplon);}# convert degrees to radians for trig functionssub deg2rad{ $_[0] * $pi / 180.0;}# convert radians to degrees for trig functionssub rad2deg{ $_[0] * 180.0 / $pi;}# compute distancesub dist{ my ( $lat1, $lon1, $lat2, $lon2 ) = @_; $debug and print STDERR "debug: dist ( $lat1, $lon1, $lat2, $lon2 )\n"; # note: this great-circle forula should not be used near the poles # see http://users.netonecom.net/~rburtch/geodesy/datm_faq.html#2.1 # Earth radius is estimated for each leg (Why? Because we can!) my $earth_radius = 6378.0 - 21.0 * sin(deg2rad(($lat1+$lat2)/2.0)); # differences in lattitude and longitude my $dlat = abs($lat1-$lat2); my $dlon = abs($lon1-$lon2); # compute great-circle distance my $a = sin(deg2rad($dlat/2.0)) * sin(deg2rad($dlat/2.0)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin(deg2rad($dlon/2.0)) * sin(deg2rad($dlon/2.0)); my $c = 2.0 * asin(sqrt($a)); # convert distance in radians on Earth-surface arc to meters $debug and print STDERR "distance (m) = " .($earth_radius * $c * 1000.0) .", c = $c, a = $a, dlat = $dlat, dlon = $dlon\n"; return $earth_radius * $c * 1000.0;}# parse date and time into an array Date::Calc can use# yyyy/mm/dd hh:mm:sssub datetime2array{ my ( $datetime ) = @_; $datetime =~ /([0-9]{4})\/([0-9]{2})\/([0-9]{2})\s+([0-9]{2}):([0-9]{2}):([0-9]{2})/; return ( $1, $2, $3, $4, $5, $6 );}# Decode MMM text to month number nnsub decodemonth{ my ($txtmonth) = @_; $debug and print STDERR "Txtmonth = $txtmonth \n"; my $monthnum = Decode_Month($txtmonth); if ( length($monthnum) == 1 ) { $monthnum = "0$monthnum" } # Convert single digits to 2 digits return $monthnum;}sub get_photo_info{ my $strftime_offset = strftime "%z", localtime; my $tz_offset = ( $strftime_offset / 100.0 ) * (-1.0); my $dir = shift; chdir( $dir ) or die "Failed to chdir: $!"; my $exif = new Image::EXIF; my @file_names = glob("dsc*.jpg"); my @photos_tmp; # list of photo information my $file; foreach $file (@file_names) { $debug && print STDERR "Get photo: $file\n"; $exif->file_name($file); my $image_info = $exif->get_image_info(); # hash reference my $str_buffer = $image_info->{"Image Created"}; my ($date, $time) = split ' ', $str_buffer; $date =~ s/:/\//g; my $timestr = "$date $time"; my @ltime = datetime2array($timestr); # Photos have local timestamp. Change them to have GMT time # Get's the local timezone from the System or environment # The "-2" is the skew for the digital camera. Once again, this is hard coded and needs to # be changed. my @ntime = Add_Delta_DHMS( @ltime, 0,$tz_offset,-2,0); my $photo_timestr = sprintf ("%04d/%02d/%02d %02d:%02d:%02d" ,$ntime[0],$ntime[1],$ntime[2],$ntime[3],$ntime[4],$ntime[5]); $debug && print STDERR "$file |",$photo_timestr, "|\n"; push @photos_tmp, [$photo_timestr , $file]; } return @photos_tmp;}# Syncronizes photos based upon prevtime and current timestr# Accesses photo data based upon global information.sub sync_photos{ my ($prevtime, $timestr, $prevlat, $prevlon, $lat, $lon) = @_; # This subroutine is accessing global variables. And doesn't return anything. Should modularize this my $continue = 1; $debug && print STDERR "Continue: $continue. photo_idx $photo_idx \n"; while ( $photo_idx < $#photos && $continue == 1 ) { my $time_photo = ${$photos[$photo_idx]}[0]; my $photo_name = ${$photos[$photo_idx]}[1]; $debug && print STDERR "Prevtime: ", $prevtime ,"\n"; $debug && print STDERR "Photo timestamp: ", $time_photo ,"\n"; $debug && print STDERR "Timestr: ", $timestr ,"\n"; if ( $time_photo ge $prevtime && $time_photo lt $timestr ) { # We have a photo taken during tracklog collection. # Interpolate the lat and lon for this photo based upon time # prevtime, timestr, photo_time, prevlat, prevlon, lat, lon my ($interplat, $interplon) = interpolate( $prevtime, $timestr, ${$photos[$photo_idx]}[0], $prevlat, $prevlon, $lat, $lon); push @mapped_photos, [ $interplat, $interplon, $photo_name ]; $photo_idx++; } elsif ( $time_photo lt $prevtime ) { $photo_idx++; } elsif ( $time_photo gt $timestr ) { $continue = 0; } else { $continue = 0; } $debug && print STDERR "Incremented on photo_idx: $photo_idx. Total: $#photos\n"; } return;}sub get_map { my $ua = LWP::UserAgent->new; #$ua->agent('Mozilla/5.0'); # Set the user-agent. May not be needed. $ua->env_proxy(); # Set Proxy settings from enviornment HTTP_PROXY or CGI_HTTP_PROXY print STDERR "Getting background map ..."; my $request = HTTP::Request->new('GET', $map_url ); my $response = $ua->request($request, $map_get ); print STDERR " Done.\n";}# initialize constants$pi = 4.0 * atan(1);$deg='
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -