3 #=======================================================================
5 # Converts between various GPS formats
8 # ©opyleft 2002– Øyvind A. Holm <sunny@sunbase.org>
9 # License: GNU General Public License, see end of file for legal stuff.
10 #=======================================================================
14 use Time
::Local qw
{ timegm_nocheck
};
17 push(@INC, "$ENV{'HOME'}/bin/src/gpstools");
32 # Initial values for command line arguments {{{
34 'comment-out-dups' => 0,
37 'double-y-scale' => 0,
43 'output-format' => "gpsml",
49 'save-to-file' => "\n", # \n = undefined, it’s banned in filenames anyway.
52 'strip-whitespace' => 0,
59 $progname =~ s
#^.*/(.*?)$#$1#;
62 my $id_date = $rcs_id;
63 $id_date =~ s/^.*?\d+ (\d\d\d\d-.*?\d\d:\d\d:\d\d\S+).*/$1/;
65 push(@main::version_array
, $rcs_id);
67 Getopt
::Long
::Configure
("bundling");
69 # Command line options {{{
70 "chronology" => \
$Opt{'chronology'},
71 "comment-out-dups|u" => \
$Opt{'comment-out-dups'},
72 "create-breaks|t" => \
$Opt{'create-breaks'},
73 "debug" => \
$Opt{'debug'},
74 "double-y-scale|y" => \
$Opt{'double-y-scale'},
75 "epoch|e" => \
$Opt{'epoch'},
76 "fix" => \
$Opt{'fix'},
77 "help|h" => \
$Opt{'help'},
78 "inside" => \
$Opt{'inside'},
79 "near" => \
$Opt{'near'},
80 "output-format|o=s" => \
$Opt{'output-format'},
81 "outside" => \
$Opt{'outside'},
82 "pos1=s" => \
$Opt{'pos1'},
83 "pos2=s" => \
$Opt{'pos2'},
84 "require|r=s" => \
$Opt{'require'},
85 "round|R=s" => \
$Opt{'round'},
86 "save-to-file|S=s" => \
$Opt{'save-to-file'},
87 "short-date|s" => \
$Opt{'short-date'},
88 "skip-dups|d" => \
$Opt{'skip-dups'},
89 "strip-whitespace|w" => \
$Opt{'strip-whitespace'},
90 "undefined|n=s" => \
$Opt{'undefined'},
91 "verbose|v" => \
$Opt{'verbose'},
92 "version" => \
$Opt{'version'},
94 ) || die("$progname: Option error. Use -h for help.\n");
98 my $PAUSE_LIMIT = 2 * 60; # Antall sekunder mellom to punkter det må til før en move legges inn.
100 our $DIGIT = '[0-9\.\-\+]'; # Used in regexps
101 $GPST::Spc
= $Opt{'strip-whitespace'} ?
"" : " ";
102 my $Spc = $GPST::Spc
; # FIXME
103 my $found_move = 0; # Settes til 1 hvis en /^# move$/ blir funnet.
106 my ($last_lon, $last_lat, $last_line) =
107 ( 1000, 1000, ""); # Vi kan jo teoretisk sett være i Greenwich eller på ekvator
108 my ($lat1, $lon1, $lat2, $lon2) =
109 (-1000, -1000, 1000, 1000);
112 'gpsbabel' => '/usr/local/bin/gpsbabel',
118 'ele' => ($Opt{'require'} =~ /e/) ?
1 : 0,
119 'position' => ($Opt{'require'} =~ /p/) ?
1 : 0,
120 'time' => ($Opt{'require'} =~ /t/) ?
1 : 0,
122 $Opt{'require'} =~ /[^ept]/
123 && die("$0: Unknown flag in --require (-r) value\n");
125 $Opt{'debug'} && ($Debug = 1);
126 $Opt{'help'} && usage
(0);
127 $Opt{'version'} && print_version
();
129 if ($Opt{'pos1'} =~ /^($DIGIT+),($DIGIT+)$/) {
133 if ($Opt{'pos2'} =~ /^($DIGIT+),($DIGIT+)$/) {
148 if ($Opt{'inside'} && $Opt{'outside'}) {
149 die("$progname: Cannot mix the --inside and --outside options\n");
152 # To avoid printing out extra "/> at the start of svg output:
153 my $svg_start_thing = "";
157 if (defined($Opt{'round'})) {
158 my $R = $Opt{'round'};
159 $R =~ s/([a-z]+)=(\d+)/($Round{$1}=$2, "")/eg;
162 length($Opt{'undefined'}) && ($Udef = $Opt{'undefined'});
163 # Kunne vært et eget script på grunn av at det gjør sine helt egne
164 # greier, men like greit å samle det på en plass.
165 # FIXME: Fjerner ikke første duplikatentryen.
166 # FIXME: Se om det går å få flytta den inn i print_entry() så man
167 # slipper å ha to gptrans_conv’er i pipen.
168 # FIXME: Legg inn alle formatene.
169 if ($Opt{'comment-out-dups'}) {
170 # Comment out areas without reception {{{
171 my ($start_date, $end_date, $found_dup) = ("", "", 0);
181 (\d\d
)/(\d\d)/(\d\d\d\d
)\x20 # Month/Day/Year — urgh
182 (\d\d
):(\d\d
):(\d\d
) # Hour:Min:Sec
186 my ($lat_val, $lon_val, $Speed, $Unkn,
187 $Month, $Day, $Year, $Hour, $Min, $Sec) =
189 $5, $6, $7, $8, $9, $10);
190 if (($lat_val eq $last_lat) && ($lon_val eq $last_lon)) {
191 unless ($found_dup) {
192 $start_date = "$Year$Month${Day}T$Hour$Min$Sec";
197 $end_date = "$Year$Month${Day}T$Hour$Min$Sec";
200 print("# $start_date-$end_date: " .
201 "CO: No signal \x7B\x7B\x7B\n");
205 print("# $start_date-$end_date: " .
206 "CO: No signal \x7D\x7D\x7D\n# move\n$_");
212 $last_lat = $lat_val;
213 $last_lon = $lon_val;
224 print("# $start_date-$end_date: " .
225 "CO: No signal \x7B\x7B\x7B\n");
229 print("# $start_date-$end_date: " .
230 "CO: No signal \x7D\x7D\x7D\n# move\n");
237 $Opt{'save-to-file'} eq "\n" && print_header
(*STDOUT
);
244 my $from_stdin = scalar(@ARGV) ?
0 : 1;
246 $from_stdin && push(@ARGV, "-");
248 for $curr_file (@ARGV) {
249 # Scan through stdin or specified files and send every GPS entry to
252 print(STDERR
"$progname: Opening \"$curr_file\" for read\n") if $Opt{'verbose'};
253 if (open(CurrFP
, "<$curr_file")) {
258 'year' => '', 'month' => '', 'day' => '',
259 'hour' => '', 'min' => '', 'sec' => '',
260 'lat' => '', 'lon' => '',
267 if ($Opt{'save-to-file'} ne "\n") {
268 push(@first_lines, $_);
270 s/^# error // && ($Dat{'error'} = "error");
271 s/^# ?// && ($Dat{'error'} = "desc");
273 if (m
#^<(e?tp)\b(.*?)>(.*?)</(e?tp)>\s*$#) {
274 # gpsml — The main storage format {{{
275 my ($Elem, $Props, $Data) =
277 my $err_str = ($Props =~ /\berr="(.*?)"/) ?
$1 : "error";
278 $Elem eq "etp" && ($Dat{'error'} = $err_str);
280 $Data =~ m
#<time>(.*?)</time># && ($Time = $1);
282 (\d\d\d\d
)-?
(\d\d
)-?
(\d\d
)T
(\d\d
):?
(\d\d
):?
([\d\
.]+?
)Z
284 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
285 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
290 $Data =~ m
#<lat>($DIGIT*?)</lat># && ($Dat{'lat'} = $1);
291 $Data =~ m
#<lon>($DIGIT*?)</lon># && ($Dat{'lon'} = $1);
292 $Data =~ m
#<ele>($DIGIT*?)</ele># && ($Dat{'ele'} = $1);
293 $Data =~ m
#<desc>(.*?)</desc># && ($Dat{'desc'} = $1);
296 } elsif (m
#^<break\b.*?/>#) {
298 } elsif (m
#^<(title|pause)\b.*?>(.*?)</(title|pause)>#) {
302 } elsif (m
#^<desc\b.*?>(.*$)#s) {
303 $Dat{'type'} = "desc";
305 until ($Txt =~ m
#</desc>#s) {
308 $Txt =~ s
#^(.*)(</desc>.*$)#$1#s;
313 $xml_data .= join("", <CurrFP
>);
314 if (!length($Opt{'output-format'})) {
315 $Opt{'output-format'} = "gpx";
316 print_header
(*STDOUT
);
318 read_xmlfile
($xml_data);
322 } elsif (m
#^(\d+)\t($DIGIT+)\t($DIGIT+)\t($DIGIT)#) {
323 # CSV format, epoch style {{{
324 my ($ep_time, $lon_val, $lat_val, $Alt) =
326 ($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'},
327 $Dat{'day'}, $Dat{'month'}, $Dat{'year'},
328 $Dat{'wday'}, $Dat{'yday'}) = gmtime($ep_time);
329 $Dat{'month'}++; # Urgh Ⅰ
330 $Dat{'year'} += 1900; # Urgh Ⅱ
335 (\d\d\d\d
)-?
(\d\d
)-?
(\d\d
)[T\
](\d\d
):?
(\d\d
):?
(\d\d
)Z?
\t
336 ($DIGIT+)\t($DIGIT+)\t($DIGIT)
339 # CSV format, human-readable date format {{{
340 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
341 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'},
342 $Dat{'lon'}, $Dat{'lat'}, $Dat{'ele'}) =
348 } elsif (/^Trackpoint\t/) {
349 # Trackpoint\tN60.41630 E5.31675\t09.02.2006 20:24:37 (UTC)\t13.6 m\t\t93.9 m\t00:00:06\t56 kph\t123° true {{{
352 # N60.41630 E5.31675\t
353 # 09.02.2006 20:24:37 (UTC)\t
361 $Orig =~ s/[\r\n]+$//;
362 my ($Marker_f, $Position_f, $Time_f, $Alt_f, $Depth_f,
363 $Leglength_f, $Legtime_f, $Legspeed_f, $Legcourse_f) =
365 # Nødløsning for å unngå at variabler
367 "\t\t\t\t\t\t\t\t\t\t"
370 "Position_f=\"$Position_f\" \x7B\x7B\x7B\n",
371 "Time_f=\"$Time_f\"\n",
372 "Alt_f=\"$Alt_f\"\n",
373 "Depth_f=\"$Depth_f\"\n",
374 "Leglength_f=\"$Leglength_f\"\n",
375 "Legtime_f=\"$Legtime_f\"\n",
376 "Legspeed_f=\"$Legspeed_f\"\n",
377 "Legcourse_f=\"$Legcourse_f\" \x7D\x7D\x7D\n",
382 $Legtime_hour, $Legtime_min, $Legtime_sec,
383 $Legspeed, $Legspeed_unit,
385 ) = ("", "", "", "", "", "", "", "", "", "", "", "", "",
386 "", "", "", "", "", "", "", "", "", "");
387 ($Position_f =~ /^(N|S)([\d\.]+) (W|E)([\d\.]+)/) &&
388 ($NS = $1, $Dat{'lat'} = $2, $WE = $3, $Dat{'lon'} = $4);
389 ($Time_f =~ /^(\d+)\.(\d+)\.(\d+) (\d+):(\d+):(\d+) \((.+?)\)/) &&
390 ($Dat{'day'} = $1, $Dat{'month'} = $2, $Dat{'year'} = $3,
391 $Dat{'hour'} = $4, $Dat{'min'} = $5, $Dat{'sec'} = $6);
392 ($Alt_f =~ /^($DIGIT+) (.*?)/) &&
393 ($Dat{'ele'} = $1, $Alt_unit = $2);
394 D
("ele = \"$Dat{'ele'}\"");
395 ($NS eq "S") && ($Dat{'lat'} = 0-$Dat{'lat'});
396 ($WE eq "W") && ($Dat{'lon'} = 0-$Dat{'lon'});
397 # MapSource in win xp writes YYYY, but YY in win98se.
399 defined($Dat{'year'})
400 && $Dat{'year'} =~ /\d/
401 && $Dat{'year'} < 1900
402 ) && ($Dat{'year'} += 2000);
405 } elsif (/^Track\t(.*?)\t/) {
406 $Dat{'title'} = txt_to_xml
($1);
407 $Dat{'type'} = "title";
413 (\d\d
)/(\d\d)/(\d\d\d\d
)\
(\d\d
):(\d\d
):(\d\d
)\t
418 # T 09/01/2002 11:51:26 60°23'36.3" 5°
19'35.9" {{{
419 my ($lat_d, $lat_m, $lat_s, $lon_d, $lon_m, $lon_s);
420 ($Dat{'month
'}, $Dat{'day
'}, $Dat{'year
'},
421 $Dat{'hour
'}, $Dat{'min
'}, $Dat{'sec
'},
422 $lat_d, $lat_m, $lat_s,
423 $lon_d, $lon_m, $lon_s) =
428 my $Flat = defined($Round{'lat
'}) ? ".$Round{'lat
'}" : "";
429 my $Flon = defined($Round{'lon
'}) ? ".$Round{'lon
'}" : "";
430 $Dat{'lat
'} = sprintf("%${Flat}f",
431 1.0*($lat_d+($lat_m/60)+($lat_s/3600)));
432 $Dat{'lon
'} = sprintf("%${Flon}f",
433 1.0*$lon_d+($lon_m/60)+($lon_s/3600));
438 1\ (\S+)\ (\S+)\ (\S+)\ (\S+)\x20
439 (\d\d)/(\d\d)/(\d\d\d\d)\ (\d\d):(\d\d):(\d\d)
442 # 1 60.3938222 5.3238754 17.3 0 09/01/2002 14:18:23 {{{
443 ($Dat{'lat
'}, $Dat{'lon
'}, $Dat{'speed
'},
445 $Dat{'month
'}, $Dat{'day
'}, $Dat{'year
'},
446 $Dat{'hour
'}, $Dat{'min
'}, $Dat{'sec
'}) =
454 # @020721221336N6048353E00701826S015-00001E4859N1673U0000 {{{
464 (\d\d) # Latitude degree
465 (\d\d) # Latitude minute
466 (\d\d\d) # Latitude minute decimals
468 (\d\d\d) # Longitude degree
469 (\d\d) # Longitude minute
470 (\d\d\d) # Longitude minute degree
476 my ($NS, $EW, $lat_deg, $lat_degmin, $lat_mindec, $lon_deg,
477 $lon_degmin, $lon_mindec);
478 ($Dat{'year
'}, $Dat{'month
'}, $Dat{'day
'}, $Dat{'hour
'},
479 $Dat{'min
'}, $Dat{'sec
'}, $NS, $lat_deg,
480 $lat_degmin, $lat_mindec, $EW,
481 $lon_deg, $lon_degmin, $lon_mindec,
482 $Dat{'accur
'}, $Dat{'ele
'}, $Dat{'unknown
'}) =
483 ($2+2000, $3, $4, $5,
488 my $ep_time = timegm_nocheck(
489 $Dat{'sec
'}, $Dat{'min
'}, $Dat{'hour
'},
490 $Dat{'day
'}, $Dat{'month
'}-1, $Dat{'year
'}
492 $last_time = $ep_time;
493 my $Flat = defined($Round{'lat
'}) ? ".$Round{'lat
'}" : "";
494 my $Flon = defined($Round{'lon
'}) ? ".$Round{'lon
'}" : "";
495 my $tmp_lon = sprintf(
500 my $tmp_lat = sprintf("%${Flat}f",
504 ($NS eq "S") && ($tmp_lat = 0-$tmp_lat);
505 ($EW eq "W") && ($tmp_lon = 0-$tmp_lon);
506 $Dat{'lat
'} = $tmp_lat;
507 $Dat{'lon
'} = $tmp_lon;
510 } elsif (/^(@)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(_{42})/) {
511 # @020721221336__________________________________________ {{{
512 ($Dat{'year
'}, $Dat{'month
'}, $Dat{'day
'},
513 $Dat{'hour
'}, $Dat{'min
'}, $Dat{'sec
'}, $Dat{'rest
'}) =
516 $Dat{'error
'} = "nosignal";
519 } elsif (/^xmaplog /) {
520 ($Opt{'output
-format
'} eq "csv")
521 && ($Opt{'save
-to
-file
'} eq "\n")
524 ($Opt{'output
-format
'} eq "csv")
525 && ($Opt{'save
-to
-file
'} eq "\n")
527 } elsif (/^Pause: /) {
528 # NOP, is here to cope with old files I’ve lying around.
529 } elsif ($Dat{'error
'} eq "desc") {
531 if (defined($Comment)) {
532 $Comment =~ s/^\s*(.*?)\s*$/$1/;
533 if ($Opt{'output
-format
'} eq "gpsml") {
534 $Dat{'desc
'} = txt_to_xml($Comment);
535 $Dat{'type
'} = "desc";
540 $Opt{'verbose
'} && warn("Line $.: Unknown: \"$_\"\n");
545 warn("$progname: $curr_file: Cannot open file for read: $!\n");
550 print_footer(*STDOUT);
556 my $Txt = join("", @_);
557 $Txt =~ s/<!--(.*?)-->//gs;
558 $Txt =~ s#(<gpx\b.*?>.*?</gpx>)#print_gpx($1)#gse;
566 D("print_xml_gps(\"$Orig\")\n");
567 $Str =~ s/<!--(.*?)-->//gs;
570 <trk\b(.*?)>(.*?)</trk>
576 <name\b(.*?)>(.*?)</name>
579 $tmp_dat{'title
'} = $2;
580 $tmp_dat{'type
'} = "title";
581 print_entry(%tmp_dat);
586 <trkseg\b(.*?)>(.*?)</trkseg>
592 <trkpt\b(.*?)>(.*?)</trkpt>
595 my ($attr_trkpt, $el_trkpt) =
598 'year
' => '', 'month
' => '', 'day
' => '',
599 'hour
' => '', 'min
' => '', 'sec
' => '',
600 'lat
' => '', 'lon
' => '',
606 ($attr_trkpt =~ /\blon="(.*?)"/) && ($Dat{'lon
'} = $1);
607 ($attr_trkpt =~ /\blat="(.*?)"/) && ($Dat{'lat
'} = $1);
608 ($el_trkpt =~ m#<($wpt_elems)\b.*?>(.*?)</($wpt_elems)>#)
613 <time>(\d\d\d\d)-?(\d\d)-?(\d\d)T
614 (\d\d):?(\d\d):?([\d\.]+)Z</time>
617 ($Dat{'year
'}, $Dat{'month
'}, $Dat{'day
'},
618 $Dat{'hour
'}, $Dat{'min
'}, $Dat{'sec
'}) =
619 ($1, $2, $3, $4, $5, $6);
633 local *OutFP = shift;
634 if ($Opt{'output
-format
'} eq "gpsml") {
636 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
640 } elsif ($Opt{'output
-format
'} eq "gpstrans") {
641 print(OutFP "Format: DMS UTC Offset: 0.00 hrs " .
642 "Datum[100]: WGS 84\n");
643 } elsif ($Opt{'output
-format
'} eq "gpx") {
645 qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n},
647 qq{$Spc${Spc}version="1.1"\n},
648 qq{$Spc${Spc}creator="gpst - http://svn.sunbase.org/repos/utils/trunk/src/gpstools/"\n},
649 qq{$Spc${Spc}xmlns="http://www.topografix.com/GPX/1/1"\n},
650 qq{$Spc${Spc}xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n},
651 qq{$Spc${Spc}xsi:schemaLocation="http://www.topografix.com/GPX/1/1 },
652 qq{http://www.topografix.com/GPX/1/1/gpx.xsd"\n},
655 qq{$Spc$Spc$Spc$Spc<trkseg>\n},
657 } elsif ($Opt{'output
-format
'} eq "ps") {
658 print(OutFP ps_header(532, 6034, 533, 6040));
660 } elsif ($Opt{'output
-format
'} eq "svg") {
662 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
663 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
664 "$Spc$Spc\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
665 "<svg height=\"1000\" width=\"1000\" viewBox=\"23 70 2 2\"\n",
666 "$Spc${Spc}xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
667 "$Spc$Spc<title></title>\n",
668 "$Spc$Spc<desc></desc>\n",
676 local *OutFP = shift;
677 if ($Opt{'output
-format
'} eq "gpsml") {
682 } elsif ($Opt{'output
-format
'} eq "gpx") {
684 "$Spc$Spc$Spc$Spc</trkseg>\n",
688 } elsif ($Opt{'output
-format
'} eq "poscount") {
689 while (my ($l_name, $l_val) = each %Poscount) {
690 $l_name =~ /^(.+?),(.+?)$/
691 && print(OutFP "$1\t$2\t$l_val\n");
693 } elsif ($Opt{'output
-format
'} eq "ps") {
699 } elsif ($Opt{'output
-format
'} eq "svg") {
700 print(OutFP "\"/>\n</svg>\n");
706 # Print a GPS entry with time, latitude, longitude and elevation in
710 defined($Dat{'desc
'}) || ($Dat{'desc
'} = "");
711 defined($Dat{'ele
'}) || ($Dat{'ele
'} = "");
712 defined($Dat{'lat
'}) || ($Dat{'lat
'} = "");
713 defined($Dat{'lon
'}) || ($Dat{'lon
'} = "");
714 defined($Dat{'year
'}) || ($Dat{'year
'} = "");
715 my $print_time = length($Dat{'year
'}) ? 1 : 0;
716 my $print_pos = (length($Dat{'lat
'}) && length($Dat{'lon
'})) ? 1 : 0;
718 $Dat{'lat
'} = $Dat{'lon
'} = "";
720 my $print_ele = length($Dat{'ele
'}) ? 1 : 0;
721 my $print_desc = length($Dat{'desc
'}) ? 1 : 0;
723 D("print_entry(\"" . join("\", \"", @_) . "\");");
726 if ($Opt{'near
'} && $print_pos) {
727 $Dat{'extensions
'} .= sprintf("%s ",
728 list_nearest_waypoints($Dat{'lat
'}, $Dat{'lon
'}, 3));
731 if (length($Opt{'round
'})) {
732 for my $Tmp (qw{ lat lon ele }) {
733 if (defined($Round{$Tmp}) && length($Dat{$Tmp})) {
735 ($Dat{$Tmp} = 1.0 * sprintf("%.$Round{$Tmp}f", $Dat{$Tmp}));
740 if ($Opt{'output
-format
'} eq "poscount") {
741 my $Name = "$Dat{'lon
'},$Dat{'lat
'}";
742 defined($Poscount{$Name}) || ($Poscount{$Name} = 0);
748 $ep_time = timegm_nocheck(
749 $Dat{'sec
'}, $Dat{'min
'}, $Dat{'hour
'},
750 $Dat{'day
'}, $Dat{'month
'} - 1, $Dat{'year
'}
752 $Dat{'year
'} = sprintf("%04u", $Dat{'year
'});
753 $Dat{'month
'} = sprintf("%02u", $Dat{'month
'});
754 $Dat{'day
'} = sprintf("%02u", $Dat{'day
'});
755 $Dat{'hour
'} = sprintf("%02u", $Dat{'hour
'});
756 $Dat{'min
'} = sprintf("%02u", $Dat{'min
'});
757 $Dat{'sec
'} = sprintf("%02u", $Dat{'sec
'});
758 if ($Opt{'chronology
'}) {
759 if ($last_time > $ep_time && !length($Dat{'error
'})) {
761 "%s: \"%sZ\": Next date is %s in the past (%sZ)\n",
762 $progname, sec_to_string($last_time, "T"),
763 sec_to_readable($last_time-$ep_time),
764 sec_to_string($ep_time, "T")
766 # FIXME: Make --fix work with gpx.
767 if ($Opt{'fix
'} && ($Opt{'output
-format
'} !~ /^gpx$/)) {
768 $Dat{'error
'} = "chrono";
782 if ($Opt{'save
-to
-file
'} ne "\n") {
784 $print_time || return;
785 my $base_name = "$Dat{'year
'}$Dat{'month
'}$Dat{'day
'}T" .
786 "$Dat{'hour
'}$Dat{'min
'}$Dat{'sec
'}Z" .
787 "$Opt{'save
-to
-file
'}";
788 my $file_name = $base_name;
790 for (my $a = 1; (-e $file_name) && ($a < 1000); $a++) {
791 $file_name = "$base_name.dup_$a";
794 die("$progname: $base_name: File already exists, and ran " .
795 "out of attempts to create unique file name\n");
797 if ($Opt{'verbose
'}) {
798 warn("$progname: $base_name: File already exists, using " .
799 "unique name \"$file_name\" instead\n");
802 if (open(ToFP, ">", $file_name)) {
811 ) || die("$progname: $file_name: Cannot write to file: $!\n");
814 if ($Opt{'output
-format
'} eq "gpsml") {
815 printf("<include>%s</include>\n",
816 txt_to_xml($file_name));
817 } elsif ($Opt{'output
-format
'} eq "gpx") {
818 printf("<!-- Saved unconverted data to \"%s\" -->\n",
819 txt_to_xml($file_name));
821 print("$progname: Saved unconverted data to \"$file_name\"\n");
825 die("$progname: $file_name: Cannot create file: $!\n");
833 if ($Dat{'type
'} eq "tp") {
835 if ($Opt{'require'}) {
836 $Req{'time'} && !$print_time && return;
837 $Req{'position
'} && !$print_pos && return;
838 $Req{'ele
'} && !$print_ele && return;
841 if ($Opt{'inside
'} || $Opt{'outside
'}) {
843 ($Dat{'lat
'} < $lat1) ||
844 ($Dat{'lat
'} > $lat2) ||
845 ($Dat{'lon
'} < $lon1) ||
846 ($Dat{'lon
'} > $lon2)
848 $Opt{'inside
'} && return;
850 $Opt{'outside
'} && return;
854 if ($Opt{'output
-format
'} eq "ps") {
861 && ($Dat{'lon
'} eq $last_lon)
862 && ($Dat{'lat
'} eq $last_lat)
864 $Dat{'error
'} = "dup";
870 $Opt{'create
-breaks
'}
871 && $ep_time-$last_time > $PAUSE_LIMIT
874 $pause_len = $ep_time-$last_time;
875 D("pause_len set to '$pause_len'");
879 if ($Opt{'output
-format
'} eq "gpsml") {
880 $Line .= sprintf("<pause>%s</pause>\n",
881 sec_to_readable($ep_time-$last_time));
882 } elsif ($Opt{'output
-format
'} eq "csv") {
883 $Line .= sprintf("# Pause: %s\n# move\n",
884 sec_to_readable($ep_time-$last_time));
891 # Valid data was found, send to stdout {{{
892 unless ($first_time) {
893 $first_time = $ep_time;
895 if ($Opt{'double
-y
-scale
'}) {
898 if ($Opt{'output
-format
'} eq "gpsml") {
899 if ($Dat{'type
'} eq "tp") {
900 $Dat{'format
'} = "gpsml";
901 $Line .= trackpoint(%Dat);
902 } elsif ($Dat{'type
'} =~ /^(pause|desc|title)$/) {
903 $Line .= sprintf("<%s>%s</%s>\n",
908 } elsif ($Opt{'output
-format
'} eq "xgraph") {
909 $pause_len && ($Line .= "move ");
910 ($Line .= "$Dat{'lon
'} $Dat{'lat
'}\n");
911 } elsif($Opt{'output
-format
'} eq "gpstrans") {
912 my ($gpt_lat, $gpt_lon) =
913 (ddd_to_dms($Dat{'lat
'}), ddd_to_dms($Dat{'lon
'}));
915 $Line .= "T\t$Dat{'month
'}/$Dat{'day
'}/$Dat{'year
'} " .
916 "$Dat{'hour
'}:$Dat{'min
'}:$Dat{'sec
'}\t" .
917 "$gpt_lat\t$gpt_lon\n";
919 $Line .= "T\t00/00/00 00:00:00\t$gpt_lat\t$gpt_lon\n";
921 } elsif($Opt{'output
-format
'} eq "gpx") {
922 if ($Dat{'type
'} eq "tp") {
923 $Dat{'format
'} = "gpx";
924 $Line .= trackpoint(%Dat);
926 } elsif ($Opt{'output
-format
'} eq "clean") {
927 $pause_len && ($Line .= "\n");
928 ($Line .= "$Dat{'lon
'}\t$Dat{'lat
'}" .
933 } elsif ($Opt{'output
-format
'} eq "ps") {
936 ? "f\n$Dat{'lon
'} $Dat{'lat
'} m\n"
937 : "$Dat{'lon
'} $Dat{'lat
'} l\n"
939 } elsif ($Opt{'output
-format
'} eq "svg") {
941 ($last_lon == 1000) || $pause_len
943 "$svg_start_thing<path\n",
944 " stroke=\"blue\"\n",
945 " stroke-width=\"0.001\"\n",
948 "M $Dat{'lon
'} $Dat{'lat
'}\n")
949 : "L $Dat{'lon
'} $Dat{'lat
'}\n"
951 } elsif ($Opt{'output
-format
'} eq "ygraph") {
952 my $Time = $print_time ? ($ep_time - $first_time) * 1 : 0;
953 $Line .= "\"Time = $Time.0\n$Dat{'lon
'} $Dat{'lat
'}\n\n";
954 } elsif ($Opt{'output
-format
'} eq "csv") {
956 # $do_print || print("skipping ");
962 ? "$Dat{'year
'}$Dat{'month
'}$Dat{'day
'}T" .
963 "$Dat{'hour
'}$Dat{'min
'}$Dat{'sec
'}Z"
964 : "$Dat{'year
'}-$Dat{'month
'}-$Dat{'day
'}T" .
965 "$Dat{'hour
'}:$Dat{'min
'}:$Dat{'sec
'}Z"
969 $print_ele ? $Dat{'ele
'} : "", # Elevation
974 die("$progname: \"$Opt{'output
-format
'}\": " .
975 "Unknown output format\n");
980 if (!$last_time && $Opt{'output
-format
'} eq "ps") {
981 $Line .= "$Dat{'lon
'} $Dat{'lat
'} m\n";
986 if ($Opt{'output
-format
'} eq "gpsml") {
987 $Line = "<break/>\n$Line";
989 (!$pause_len && ($Opt{'output
-format
'} eq "xgraph"))
990 && ($Line .= "move $Line");
991 ($Opt{'output
-format
'} eq "clean") && ($Line .= "\n");
992 if ($Opt{'output
-format
'} eq "gpx") {
993 $Line .= "$Spc$Spc$Spc$Spc</trkseg>\n" .
994 "$Spc$Spc$Spc$Spc<trkseg>\n";
1000 $print_time && ($last_time = $ep_time);
1002 $last_lon = $Dat{'lon
'};
1003 $last_lat = $Dat{'lat
'};
1005 $last_line = $data_line;
1006 $svg_start_thing = "\"/>\n";
1011 # Send a Postscript header to stdout {{{
1012 my ($bl_lon, $bl_lat, $br_lon, $br_lat) = @_;
1013 my $Date = sec_to_string(time);
1015 "%!PS-Adobe-3.0 EPSF-3.0\n",
1016 "%%Creator: $rcs_id\n",
1018 "%%CreationDate: $Date\n",
1019 "%%BoundingBox: $bl_lon $bl_lat $br_lon $br_lat\n",
1020 "%%DocumentData: Clean7Bit\n",
1023 "/bd { bind def } bind def\n",
1024 "/incompound false def\n",
1025 "/m { moveto } bd\n",
1026 "/l { lineto } bd\n",
1027 "/c { curveto } bd\n",
1028 "/F { incompound not {fill} if } bd\n",
1029 "/f { closepath F } bd\n",
1030 "/S { stroke } bd\n",
1031 "/*u { /incompound true def } bd\n",
1032 "/*U { /incompound false def f} bd\n",
1033 "/k { setcmykcolor } bd\n",
1043 # Print program version {{{
1044 for (@main::version_array) {
1052 # Send the help message to stdout {{{
1059 Converts between various GPS formats.
1061 Usage: $progname [options] [file [files [...]]]
1062 $progname -S [file [files [...]]]
1063 $progname -u [file [files [...]]]
1068 Check for broken chronology, warn about entries with an old
1071 Skip duplicated coordinates.
1073 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1075 Comment out entries which is obviously wrong. Use together with
1076 --chronology to fix those kind of errors. Does not work with GPX
1081 Print only trackpoints inside a rectangle specified by --pos1 and
1084 Use x as undefined value. Default: "$Udef".
1086 Add names of the three closest waypoints to the trackpoint.
1087 Unfinished and experimental, needs gpsbabel, which is called from
1088 the program as "$Cmd{'gpsbabel
'}".
1089 -o x, --output-format x
1090 Use output format x:
1102 Print only trackpoints outside a rectangle specified by --pos1 and
1105 Specifies one corner where x is in "lat,lon" format (decimal
1106 degrees, negative for west or south) of area rectangle used by the
1107 --inside and --outside options.
1109 Specify requirements for trackpoints to be written. x is a string
1110 with the following flags:
1112 Print only waypoints which have an elevation.
1114 Print only waypoints which have a position.
1116 Print only waypoints which have a timestamp.
1118 Round trackpoint element x to y decimals. Example:
1119 --round lat=4,lon=5,ele=1
1121 Use short date format.
1122 -S x, --save-to-file x
1123 Save the unconverted data to a file with a filename starting with
1124 the timestamp of the first trackpoint. The parameter string x is
1125 added at the end of the filename. For the time being this option
1126 will ignore all other options. Note: If several files are specified
1127 on the command line, all data will be saved into only one file. This
1128 behaviour may change in the future.
1130 Create breaks in track between points with a difference more than
1131 $PAUSE_LIMIT seconds.
1132 -u, --comment-out-dups
1133 Comment out following data with identical position values, only
1138 Print version information.
1139 -w, --strip-whitespace
1140 Strip all unnecessary whitespace.
1141 -y, --double-y-scale
1142 Double Y scale (latitude) to get it right in gnuplot.
1144 Print debugging messages.
1153 # Plain Old Documentation (POD) {{{
1167 B<gptrans_conv> [options] [file [files [...]]]
1169 B<gptrans_conv> -S [options] [file [files [...]]]
1171 B<gptrans_conv> -u [options] [file [files [...]]]
1175 Converts between various GPS formats.
1181 =item B<--chronology>
1183 Check for broken chronology, warn about entries with an old timestamp.
1185 =item B<-d>, B<--skip-dups>
1187 Skip duplicated coordinates.
1189 =item B<-e>, B<--epoch>
1191 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1195 Comment out entries which is obviously wrong. Use together with
1196 --chronology to fix those kind of errors. Does not work with GPX output
1199 =item B<-h>, B<--help>
1205 Print only trackpoints inside a rectangle specified by --pos1 and
1210 Add names of the three closest waypoints to the trackpoint. Unfinished
1211 and experimental, needs gpsbabel.
1213 =item B<-n x>, B<--undefined x>
1215 Use x as undefined value.
1217 =item B<-o x>, B<--output-format x>
1219 Use output format x:
1229 =item gpsml (Default)
1231 This is the format which is meant to be used when storing the track
1233 It is line-based XML which makes it easy to edit and grep. Probably not
1238 =item gpx (Not complete)
1242 Creates a 3D plot where areas with many trackpoints are higher than
1243 areas with less track points.
1245 =item ps (Unfinished)
1247 =item svg (Unfinished)
1261 Print only trackpoints outside a rectangle specified by --pos1 and
1264 =item B<--pos1 x>, B<--pos2 x>
1266 Specifies corners of an area rectangle used by the --inside and
1267 --outside options. The x value is in "lat,lon" format (decimal degrees,
1268 negative for west or south) .
1270 =item B<-r x>, B<--require x>
1272 Specify requirements for trackpoints to be written. x is a string with
1273 the following flags:
1283 =item Print only waypoints which have an elevation.
1295 =item Print only waypoints which have a position.
1301 =item Print only waypoints which have a timestamp.
1311 =item -R x=y[,x2=y2[...]]
1313 Round trackpoint element x to y decimals.
1317 --round lat=4,lon=5,ele=1
1319 =item B<-s>, B<--short-date>
1321 Use short date format.
1323 =item B<-S x>, B<--save-to-file x>
1325 Save the unconverted data to a file with a filename starting with the
1326 timestamp of the first trackpoint. The parameter string x is added at
1327 the end of the filename. For the time being this option will ignore all
1330 Note: If several files are specified on the command line, all data will
1331 be saved into only one file. This behaviour may change in the future.
1333 =item B<-t>, B<--create-breaks>
1335 Create breaks in track between points with a difference more than the
1336 number of seconds specified by the C<$PAUSE_LIMIT> variable.
1338 =item B<-u>, B<--comment-out-dups>
1340 Comment out following data with identical position values, only print
1343 =item B<-v>, B<--verbose>
1347 =item B<-w>, B<--strip-whitespace>
1349 Strip all unnecessary whitespace.
1351 =item B<-y>, B<--double-y-scale>
1353 Double Y scale (latitude) to get it right in gnuplot.
1355 =item B<-h>, B<--help>
1357 Print a brief help summary.
1361 Print version information.
1365 Print debugging messages.
1371 Pretty incomplete in some areas. Some of the source formats are
1372 undocumented and thus incomplete. Some functionality is not working
1373 properly, for example the Postscript output.
1377 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
1381 Copyleft © Øyvind A. Holm <sunny@sunbase.org>
1382 This is free software; see the file F<COPYING> for legalese stuff.
1386 This program is free software; you can redistribute it and/or modify it
1387 under the terms of the GNU General Public License as published by the
1388 Free Software Foundation; either version 2 of the License, or (at your
1389 option) any later version.
1391 This program is distributed in the hope that it will be useful, but
1392 WITHOUT ANY WARRANTY; without even the implied warranty of
1393 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1394 See the GNU General Public License for more details.
1396 You should have received a copy of the GNU General Public License along
1397 with this program; if not, write to the Free Software Foundation, Inc.,
1398 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1408 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :