* /trunk/tests/ og de 28 *.t-filene under der
[gpstools.git] / Patch / gpst-xmlsimple
blob1014755df5e6b7a508fa29868dba49a0a9d8e7d5
1 #!/usr/bin/perl -w
3 #=======================================================================
4 # $Id$
5 # Converts between various GPS formats
7 # Character set: UTF-8
8 # ©opyleft 2002– Øyvind A. Holm <sunny@sunbase.org>
9 # License: GNU General Public License, see end of file for legal stuff.
10 #=======================================================================
12 use strict;
13 use Getopt::Long;
14 use Time::Local qw { timegm_nocheck };
15 use XML::Simple;
16 use Data::Dumper;
18 $| = 1;
20 our $Debug = 0;
22 our %Opt = (
23 # Initial values for command line arguments {{{
24 'chronology' => 0,
25 'comment-out-dups' => 0,
26 'create-breaks' => 0,
27 'debug' => 0,
28 'double-y-scale' => 0,
29 'epoch' => 0,
30 'fix' => 0,
31 'help' => 0,
32 'inside' => 0,
33 'near' => "",
34 'output-format' => "gpsml",
35 'outside' => 0,
36 'pos1' => "",
37 'pos2' => "",
38 'print-comments' => 0,
39 'require' => "",
40 'save-to-file' => "\n", # \n = undefined, it’s banned in filenames anyway.
41 'short-date' => 0,
42 'skip-dups' => 0,
43 'strip-whitespace' => 0,
44 'undefined' => "",
45 'use-comma' => 0,
46 'version' => 0,
47 # }}}
50 our $progname = $0;
51 $progname =~ s#^.*/(.*?)$#$1#;
53 my $rcs_id = '$Id$';
54 my $id_date = $rcs_id;
55 $id_date =~ s/^.*?\d+ (\d\d\d\d-.*?\d\d:\d\d:\d\d\S+).*/$1/;
57 Getopt::Long::Configure("bundling");
58 GetOptions(
59 # Command line options {{{
60 "chronology" => \$Opt{'chronology'},
61 "comment-out-dups|u" => \$Opt{'comment-out-dups'},
62 "create-breaks|t" => \$Opt{'create-breaks'},
63 "debug" => \$Opt{'debug'},
64 "double-y-scale|y" => \$Opt{'double-y-scale'},
65 "epoch|e" => \$Opt{'epoch'},
66 "fix" => \$Opt{'fix'},
67 "help|h" => \$Opt{'help'},
68 "inside" => \$Opt{'inside'},
69 "near" => \$Opt{'near'},
70 "output-format|o=s" => \$Opt{'output-format'},
71 "outside" => \$Opt{'outside'},
72 "pos1=s" => \$Opt{'pos1'},
73 "pos2=s" => \$Opt{'pos2'},
74 "print-comments|C" => \$Opt{'print-comments'},
75 "require|r=s" => \$Opt{'require'},
76 "save-to-file|S=s" => \$Opt{'save-to-file'},
77 "short-date|s" => \$Opt{'short-date'},
78 "skip-dups|d" => \$Opt{'skip-dups'},
79 "strip-whitespace|w" => \$Opt{'strip-whitespace'},
80 "undefined|n=s" => \$Opt{'undefined'},
81 "use-comma|c" => \$Opt{'use-comma'},
82 "verbose|v" => \$Opt{'verbose'},
83 "version" => \$Opt{'version'},
84 # }}}
85 ) || die("$progname: Option error. Use -h for help.\n");
87 my %Dat;
89 my $PAUSE_LIMIT = 2 * 60; # Antall sekunder mellom to punkter det må til før en move legges inn.
90 my $Des = $Opt{'use-comma'} ? "," : ".";
91 my $Udef = "?";
92 my $DIGIT = '[0-9\.\-\+]'; # Used in regexps
93 my $Spc = $Opt{'strip-whitespace'} ? "" : " ";
94 my $in_dupskip = 0; # Er 1 hvis vi holder på med ignorering av duplikater
95 my $found_move = 0; # Settes til 1 hvis en /^# move$/ blir funnet.
96 my $first_time = 0;
97 my $last_time = 0;
98 my ($last_lon, $last_lat, $last_ele, $last_line) =
99 ( 1000, 1000, 100000, ""); # Vi kan jo teoretisk sett være i Greenwich eller på ekvator
100 my ($lat1, $lon1, $lat2, $lon2) =
101 (-1000, -1000, 1000, 1000);
103 my %Poscount = ();
105 my %Req = (
106 'altitude' => ($Opt{'require'} =~ /a/) ? 1 : 0,
107 'time' => ($Opt{'require'} =~ /t/) ? 1 : 0
109 $Opt{'require'} =~ /[^at]/ && die("$0: Unknown flag in --require (-r) value\n");
111 $Opt{'debug'} && ($Debug = 1);
112 $Opt{'help'} && usage(0);
113 $Opt{'version'} && print_version();
115 if ($Opt{'pos1'} =~ /^($DIGIT+),($DIGIT+)$/) {
116 $lat1 = $1;
117 $lon1 = $2;
119 if ($Opt{'pos2'} =~ /^($DIGIT+),($DIGIT+)$/) {
120 $lat2 = $1;
121 $lon2 = $2;
123 if ($lat1 > $lat2) {
124 my $Tmp = $lat1;
125 $lat1 = $lat2;
126 $lat2 = $Tmp;
128 if ($lon1 > $lon2) {
129 my $Tmp = $lon1;
130 $lon1 = $lon2;
131 $lon2 = $Tmp;
134 if ($Opt{'inside'} && $Opt{'outside'}) {
135 die("$progname: Cannot mix the --inside and --outside options\n");
138 my $waypoint_file = "/home/sunny/gps/waypoints.gpx";
140 # To avoid printing out extra "/> at the start of svg output:
141 my $svg_start_thing = "";
143 length($Opt{'undefined'}) && ($Udef = $Opt{'undefined'});
144 # Kunne vært et eget script på grunn av at det gjør sine helt egne
145 # greier, men like greit å samle det på en plass.
146 # FIXME: Fjerner ikke første duplikatentryen.
147 # FIXME: Se om det går å få flytta den inn i print_entry() så man
148 # slipper å ha to gptrans_conv’er i pipen.
149 # FIXME: Legg inn alle formatene.
150 if ($Opt{'comment-out-dups'}) {
151 # Comment out areas without reception {{{
152 my ($start_date, $end_date, $found_dup) = ("", "", 0);
153 my @Dup = ();
154 while (<>) {
155 if (m#^1 (\S+) (\S+) (\S+) (\S+) (\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)#) {
156 # {{{
157 my ($lat_val, $lon_val, $Speed, $Unkn, $Month, $Day, $Year, $Hour, $Min, $Sec) =
158 ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
159 if (($lat_val eq $last_lat) && ($lon_val eq $last_lon)) {
160 unless ($found_dup) {
161 $start_date = "$Year$Month${Day}T$Hour$Min$Sec";
162 @Dup = ();
163 $found_dup = 1;
165 push(@Dup, "# $_");
166 $end_date = "$Year$Month${Day}T$Hour$Min$Sec";
167 } else {
168 if ($found_dup) {
169 print("# $start_date-$end_date: CO: No signal \x7B\x7B\x7B\n");
170 for (@Dup) {
171 print($_);
173 print("# $start_date-$end_date: CO: No signal \x7D\x7D\x7D\n# move\n$_");
174 $found_dup = 0;
175 } else {
176 print($_);
179 $last_lat = $lat_val;
180 $last_lon = $lon_val;
181 # }}}
182 } else {
183 if ($found_dup) {
184 push(@Dup, $_);
185 } else {
186 print($_);
190 if ($found_dup) {
191 print("# $start_date-$end_date: CO: No signal \x7B\x7B\x7B\n");
192 for (@Dup) {
193 print($_);
195 print("# $start_date-$end_date: CO: No signal \x7D\x7D\x7D\n# move\n");
196 $found_dup = 0;
198 exit(0);
199 # }}}
202 $Opt{'save-to-file'} eq "\n" && print_header(*STDOUT);
204 my @first_lines;
205 my $xml_data;
206 my $data_line = "";
207 my $curr_file = "";
209 my $from_stdin = scalar(@ARGV) ? 0 : 1;
211 $from_stdin && push(@ARGV, "-");
213 for $curr_file (@ARGV) {
214 # Scan through stdin or specified files and send every GPS entry to
215 # print_entry()
216 # {{{
217 D("Opening \"$curr_file\" for read");
218 if (open(CurrFP, "<$curr_file")) {
219 # {{{
220 while (<CurrFP>) {
221 $data_line = $_;
222 %Dat = (
223 'year' => '', 'month' => '', 'day' => '',
224 'hour' => '', 'min' => '', 'sec' => '',
225 'lat' => '', 'lon' => '',
226 'ele' => '',
227 'desc' => '',
228 'error' => 0,
229 'type' => 'tp',
232 if ($Opt{'save-to-file'} ne "\n") {
233 push(@first_lines, $_);
234 $_ =~ s/^# ?//; # Also read commented-out lines.
236 $xml_data = "";
237 if (m#^<(e?tp)\b.*?>(.*?)</(e?tp)>$#) {
238 # gpsml — The main storage format {{{
239 my ($Elem, $Data) =
240 ( $1, $2);
241 $Elem eq "etp" && ($Dat{'error'} = 1);
242 my $Time = "";
243 $Data =~ m#<time>(.*?)</time># && ($Time = $1);
244 $Time =~ s{
245 (\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?([\d\.]+?)Z
247 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
248 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
249 ( $1, $2, $3,
250 $4, $5, $6);
252 }ex;
253 $Data =~ m#<lat>($DIGIT*?)</lat># && ($Dat{'lat'} = $1);
254 $Data =~ m#<lon>($DIGIT*?)</lon># && ($Dat{'lon'} = $1);
255 $Data =~ m#<ele>($DIGIT*?)</ele># && ($Dat{'ele'} = $1);
256 $Data =~ m#<desc>(.*?)</desc># && ($Dat{'desc'} = xml_to_txt($1));
257 print_entry(%Dat);
258 # }}}
259 } elsif (m#^<break\b.*?/>#) {
260 $found_move = 1;
261 } elsif (m#^<(desc|title|pause)\b.*?>(.*?)</(desc|title|pause)>#) {
262 $Dat{'type'} = $1;
263 $Dat{$1} = xml_to_txt($2);
264 print_entry(%Dat);
265 } elsif (/^<gpx\b/) {
266 $xml_data = $_;
267 $xml_data .= join("", <CurrFP>);
268 if (!length($Opt{'output-format'})) {
269 $Opt{'output-format'} = "gpx";
270 print_header(*STDOUT);
272 read_xmlfile($xml_data);
273 last;
274 } elsif (/^# Pause: /) {
275 $Opt{'print-comments'} && print;
276 } elsif (/^# move$/) {
277 $found_move = 1;
278 } elsif (/^#/) {
279 $Opt{'print-comments'} && print;
280 } elsif (m#^(\d+)\t($DIGIT+)\t($DIGIT+)\t($DIGIT)#) {
281 # CSV format, epoch style {{{
282 my ($ep_time, $lon_val, $lat_val, $Alt) =
283 ( $1, $2, $3, $4);
284 ($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'},
285 $Dat{'day'}, $Dat{'month'}, $Dat{'year'},
286 $Dat{'wday'}, $Dat{'yday'}) = gmtime($ep_time);
287 $Dat{'month'}++; # Urgh Ⅰ
288 $Dat{'year'} += 1900; # Urgh Ⅱ
289 print_entry(%Dat);
290 # }}}
291 } elsif (m#^(\d\d\d\d)-?(\d\d)-?(\d\d)[T ](\d\d):?(\d\d):?(\d\d)Z?\t($DIGIT+)\t($DIGIT+)\t($DIGIT)#) {
292 # CSV format, human-readable date format {{{
293 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
294 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'},
295 $Dat{'lon'}, $Dat{'lat'}, $Dat{'ele'}) =
296 ($1, $2, $3,
297 $4, $5, $6,
298 $7, $8, $9);
299 print_entry(%Dat);
300 # }}}
301 } elsif (/^Trackpoint\t/) {
302 # 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 {{{
304 # Trackpoint\t
305 # N60.41630 E5.31675\t
306 # 09.02.2006 20:24:37 (UTC)\t
307 # 13.6 m\t
308 # \t
309 # 93.9 m\t
310 # 00:00:06\t
311 # 56 kph\t
312 # 123° true
313 my $Orig = $_;
314 $Orig =~ s/[\r\n]+$//;
315 my ($Marker_f, $Position_f, $Time_f, $Alt_f, $Depth_f,
316 $Leglength_f, $Legtime_f, $Legspeed_f, $Legcourse_f) =
317 split(/\t/, $Orig .
318 # Nødløsning for å unngå at variabler blir
319 # udefinert.
320 "\t\t\t\t\t\t\t\t\t\t"
322 D(join("",
323 "Position_f=\"$Position_f\" \x7B\x7B\x7B\n",
324 "Time_f=\"$Time_f\"\n",
325 "Alt_f=\"$Alt_f\"\n",
326 "Depth_f=\"$Depth_f\"\n",
327 "Leglength_f=\"$Leglength_f\"\n",
328 "Legtime_f=\"$Legtime_f\"\n",
329 "Legspeed_f=\"$Legspeed_f\"\n",
330 "Legcourse_f=\"$Legcourse_f\" \x7D\x7D\x7D\n",
332 my ($NS, $WE,
333 $Alt_unit,
334 $Leglength,
335 $Legtime_hour, $Legtime_min, $Legtime_sec,
336 $Legspeed, $Legspeed_unit,
337 $Legcourse
338 ) = ("", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
339 "", "", "", "", "", "", "", "");
340 ($Position_f =~ /^(N|S)([\d\.]+) (W|E)([\d\.]+)/) &&
341 ($NS = $1, $Dat{'lat'} = $2, $WE = $3, $Dat{'lon'} = $4);
342 ($Time_f =~ /^(\d+)\.(\d+)\.(\d+) (\d+):(\d+):(\d+) \((.+?)\)/) &&
343 ($Dat{'day'} = $1, $Dat{'month'} = $2, $Dat{'year'} = $3,
344 $Dat{'hour'} = $4, $Dat{'min'} = $5, $Dat{'sec'} = $6);
345 ($Alt_f =~ /^([\d+\.]+) (.*?)/) &&
346 ($Dat{'ele'} = $1, $Alt_unit = $2);
347 D("ele = \"$Dat{'ele'}\"");
348 ($NS eq "S") && ($Dat{'lat'} = 0-$Dat{'lat'});
349 ($WE eq "W") && ($Dat{'lon'} = 0-$Dat{'lon'});
350 # MapSource in win xp writes YYYY, but YY in win98se.
351 (defined($Dat{'year'}) && $Dat{'year'} =~ /\d/ && $Dat{'year'} < 1900) && ($Dat{'year'} += 2000);
352 print_entry(%Dat);
353 # }}}
354 } elsif (m#^T\t(\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)\t(.+)\xB0(.+)'(.+)"\t(.+)\xB0(.+)'(.+)"#) {
355 # T 09/01/2002 11:51:26 60°23'36.3" 5°19'35.9" {{{
356 my ($lat_d, $lat_m, $lat_s, $lon_d, $lon_m, $lon_s);
357 ($Dat{'month'}, $Dat{'day'}, $Dat{'year'},
358 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $lat_d,
359 $lat_m, $lat_s, $lon_d,
360 $lon_m, $lon_s) =
361 ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
362 $Dat{'lat'} = sprintf("%.5f", 1*($lat_d+($lat_m/60)+($lat_s/3600)));
363 $Dat{'lon'} = sprintf("%.5f", $lon_d+($lon_m/60)+($lon_s/3600));
364 print_entry(%Dat);
365 # }}}
366 } elsif (m#^1 (\S+) (\S+) (\S+) (\S+) (\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)#) {
367 # 1 60.3938222 5.3238754 17.3 0 09/01/2002 14:18:23 {{{
368 ($Dat{'lat'}, $Dat{'lon'}, $Dat{'speed'},
369 $Dat{'unkn'},
370 $Dat{'month'}, $Dat{'day'}, $Dat{'year'},
371 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}) =
372 ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
373 print_entry(%Dat);
374 # }}}
375 } elsif (/^
376 # @020721221336N6048353E00701826S015-00001E4859N1673U0000 {{{
377 # Regexp {{{
378 (@) # @
379 (\d\d) # Year
380 (\d\d) # Month
381 (\d\d) # Day
382 (\d\d) # Hours
383 (\d\d) # Minutes
384 (\d\d) # Seconds
385 ([NS]) # N|S
386 (\d\d) # Latitude degree
387 (\d\d) # Latitude minute
388 (\d\d\d) # Latitude minute decimals
389 ([EW]) # E|W
390 (\d\d\d) # Longitude degree
391 (\d\d) # Longitude minute
392 (\d\d\d) # Longitude minute degree
393 (....) # Accurancy
394 (......) # Altitude
395 (...............)
397 # }}}
398 /x) {
399 my ($NS, $EW, $lat_deg, $lat_degmin, $lat_mindec, $lon_deg,
400 $lon_degmin, $lon_mindec);
401 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'}, $Dat{'hour'},
402 $Dat{'min'}, $Dat{'sec'}, $NS, $lat_deg,
403 $lat_degmin, $lat_mindec, $EW,
404 $lon_deg, $lon_degmin, $lon_mindec,
405 $Dat{'accur'}, $Dat{'ele'}, $Dat{'unknown'}) =
406 ($2+2000, $3, $4, $5, $6, $7, $8, $9, $10, $11,
407 $12, $13, $14, $15, $16, $17, $18);
408 my $ep_time = timegm_nocheck($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'}, $Dat{'day'}, $Dat{'month'}-1, $Dat{'year'});
409 $last_time = $ep_time;
410 my $tmp_lon = sprintf("%.5f", $lon_deg + $lon_degmin/60 + $lon_mindec/60000);
411 my $tmp_lat = sprintf("%.5f", $lat_deg + $lat_degmin/60 + $lat_mindec/60000);
412 $tmp_lon =~ s/\./$Des/;
413 $tmp_lat =~ s/\./$Des/;
414 ($NS eq "S") && ($tmp_lat = 0-$tmp_lat);
415 ($EW eq "W") && ($tmp_lon = 0-$tmp_lon);
416 $Dat{'lat'} = $tmp_lat;
417 $Dat{'lon'} = $tmp_lon;
418 print_entry(%Dat);
419 # }}}
420 } elsif (/^(@)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(__________________________________________)/) {
421 # @020721221336__________________________________________ {{{
422 my ($Alfa, $Year, $Month, $Day, $Hour, $Min, $Sec, $Rest) =
423 ( $1, $2+2000, $3, $4, $5, $6, $7, $8);
424 $Opt{'output-format'} eq "csv" && print("\n");
425 $found_move = 1;
426 # }}}
427 } elsif (/^xmaplog /) {
428 ($Opt{'output-format'} eq "csv") && ($Opt{'save-to-file'} eq "\n") && print("\n");
429 } elsif (/^$/) {
430 ($Opt{'output-format'} eq "csv") && ($Opt{'save-to-file'} eq "\n") && print("\n");
431 } else {
432 if ($Opt{'print-comments'}) {
433 print("# $_");
434 chomp;
436 $Opt{'verbose'} && warn("Line $.: Unknown: \"$_\"\n");
439 # }}}
440 } else {
441 warn("$progname: $curr_file: Cannot open file for read: $!\n");
443 # }}}
446 print_footer(*STDOUT);
448 exit(0);
450 sub read_xmlfile {
451 # {{{
452 D("Inn i read_xmlfile()");
453 my $Txt = XMLin(@_);
454 D("Etter XMLin()");
455 # print(Dumper($Txt->{trk}->{trkseg}->{trkpt}->[0]->{time}));
456 D(Dumper($Txt));
457 D("Etter Dumper");
458 my $Loop = 1;
459 for (my $a = 0; $Loop; $a++) {
460 D("a = $a");
461 my $Date = $Txt->{trk}->{trkseg}->{trkpt}->[$a]->{time};
462 $Dat{'lat'} = $Txt->{trk}->{trkseg}->{trkpt}->[$a]->{lat};
463 $Dat{'lon'} = $Txt->{trk}->{trkseg}->{trkpt}->[$a]->{lon};
464 $Dat{'ele'} = $Txt->{trk}->{trkseg}->{trkpt}->[$a]->{ele};
465 if ($Date =~ m#(\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?(\d\d)\.?(\d*?)Z#) {
466 ($Dat{'year'}, $Dat{'mon'}, $Dat{'day'},
467 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'secfrac'}) =
468 ( $1, $2, $3,
469 $4, $5, $6, $7);
471 print_entry(%Dat);
472 # print($Txt->{trk}->{trkseg}->{trkpt}->{time}->[$a]);
474 # FIXME: The sequential stuff here is probably bad, but easy.
475 # $Txt =~ s#(<gpx\b.*?>.*?</gpx>)#print_gpx($1)#gse;
476 # $Txt =~ s#(<gps\b.*?>.*?</gps>)#print_xml_gps($1)#gse;
477 # }}}
480 sub print_gpx {
481 # {{{
482 my $Orig = shift;
483 my $Str = $Orig;
484 D("print_xml_gps(\"$Orig\")\n");
485 $Str =~
487 <trk\b(.*?)>(.*?)</trk>
490 my $el_trk = $2;
491 $el_trk =~
493 <trkseg\b(.*?)>(.*?)</trkseg>
496 my $el_trkseg = $2;
497 $el_trkseg =~
499 <trkpt\b(.*?)>(.*?)</trkpt>
502 my ($attr_trkpt, $el_trkpt) =
503 ( $1, $2);
504 ($attr_trkpt =~ /\blon="(.*?)"/) && ($Dat{'lon'} = $1);
505 ($attr_trkpt =~ /\blat="(.*?)"/) && ($Dat{'lat'} = $1);
506 ($el_trkpt =~ m#<ele\b.*?>(.*?)</ele>#) && ($Dat{'ele'} = $1);
507 if ($el_trkpt =~ m#<time>(\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?(\d\d)\.?(\d*?)Z</time>#) {
508 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
509 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'secfrac'}) =
510 ($1, $2, $3, $4, $5, $6, $7);
512 print_entry(%Dat);
514 }gsex;
515 $found_move = 1;
516 }gsex;
517 $found_move = 1;
518 }gsex;
519 # }}}
522 sub print_xml_gps {
523 # {{{
524 my $Orig = shift;
525 my $Str = $Orig;
526 D("print_xml_gps(\"$Orig\")\n");
527 if ($Str =~ m#<date>(\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?(\d\d)\.?(\d*?)Z</date>#) {
528 ($Dat{'year'}, $Dat{'mon'}, $Dat{'day'}, $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'secfrac'}) =
529 ( $1, $2, $3, $4, $5, $6, $7);
531 if ($Str =~ m#<pos>(.*?)</pos>#s) {
532 my $Txt = $1;
533 ($Txt =~ m#<x\b.*?>(.*?)</x>#) && ($Dat{'lon'} = $1);
534 ($Txt =~ m#<y\b.*?>(.*?)</y>#) && ($Dat{'lat'} = $1);
535 ($Txt =~ m#<z\b.*?>(.*?)</z>#) && ($Dat{'ele'} = $1);
537 defined($Dat{'lon'}) || ($Dat{'lon'} = "");
538 defined($Dat{'lat'}) || ($Dat{'lat'} = "");
539 defined($Dat{'ele'}) || ($Dat{'ele'} = "");
540 print_entry(%Dat);
541 # }}}
544 sub print_header {
545 # {{{
546 local *OutFP = shift;
547 if ($Opt{'output-format'} eq "gpsml") {
548 print(OutFP join("",
549 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
550 "<gpsml>\n",
551 "<track>\n",
553 } elsif ($Opt{'output-format'} eq "gpstrans") {
554 print(OutFP "Format: DMS UTC Offset: 0.00 hrs Datum[100]: WGS 84\n");
555 } elsif ($Opt{'output-format'} eq "gpx") {
556 print(OutFP join("",
557 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
558 "<gpx>\n",
559 "$Spc$Spc<trk>\n",
560 "$Spc$Spc$Spc$Spc<trkseg>\n",
562 } elsif ($Opt{'output-format'} eq "ps") {
563 print(OutFP ps_header(532, 6034, 533, 6040));
564 print(OutFP "*u\n");
565 } elsif ($Opt{'output-format'} eq "xml") {
566 print(OutFP join("",
567 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
568 "<gpslog>\n",
570 } elsif ($Opt{'output-format'} eq "svg") {
571 print(OutFP join("",
572 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
573 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
574 "$Spc$Spc\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
575 "<svg height=\"1000\" width=\"1000\" viewBox=\"23 70 2 2\"\n",
576 "$Spc${Spc}xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
577 "$Spc$Spc<title></title>\n",
578 "$Spc$Spc<desc></desc>\n",
581 # }}}
584 sub print_footer {
585 # Print footer {{{
586 local *OutFP = shift;
587 if ($Opt{'output-format'} eq "gpsml") {
588 print(OutFP join("",
589 "</track>\n",
590 "</gpsml>\n",
592 } elsif ($Opt{'output-format'} eq "gpx") {
593 print(OutFP join("",
594 "$Spc$Spc$Spc$Spc</trkseg>\n",
595 "$Spc$Spc</trk>\n",
596 "</gpx>\n",
598 } elsif ($Opt{'output-format'} eq "poscount") {
599 while (my ($l_name, $l_val) = each %Poscount) {
600 $l_name =~ /^(.+?),(.+?)$/ && print(OutFP "$1\t$2\t$l_val\n");
602 } elsif ($Opt{'output-format'} eq "ps") {
603 print(OutFP join("",
604 "*U\n",
605 "%%Trailer\n",
606 "%%EOF\n",
608 } elsif ($Opt{'output-format'} eq "svg") {
609 print(OutFP "\"/>\n</svg>\n");
610 } elsif ($Opt{'output-format'} eq "xml") {
611 print(OutFP "</gpslog>\n");
613 # }}}
616 sub print_entry {
617 # Print a GPS entry with time, latitude, longitude and altitude in
618 # various formats
619 # {{{
620 my %Dat = @_;
621 my $print_time = length($Dat{'year'}) ? 1 : 0;
622 my $print_ele = length($Dat{'ele'}) ? 1 : 0;
623 my $print_desc = length($Dat{'desc'}) ? 1 : 0;
624 my $Line = "";
625 D("print_entry(\"" . join("\", \"", @_) . "\");");
626 my $ep_time;
628 if ($Opt{'near'}) {
629 $Line .= sprintf("%s ", list_nearest_waypoints($Dat{'lat'}, $Dat{'lon'}));
632 if ($Opt{'output-format'} eq "poscount") {
633 my ($Lat_str, $Lon_str) =
634 ( "", "");
635 $Dat{'lon'} =~ /^(\d+\.\d\d)/ && ($Lon_str = $1);
636 $Dat{'lat'} =~ /^(\d+\.\d\d)/ && ($Lat_str = $1);
637 my $Name = "${Lon_str},${Lat_str}";
638 defined($Poscount{$Name}) || ($Poscount{$Name} = 0);
639 $Poscount{$Name}++;
640 return;
643 if ($print_time) {
644 $ep_time = timegm_nocheck($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'}, $Dat{'day'}, $Dat{'month'} - 1, $Dat{'year'});
645 $Dat{'year'} = sprintf("%04u", $Dat{'year'});
646 $Dat{'month'} = sprintf("%02u", $Dat{'month'});
647 $Dat{'day'} = sprintf("%02u", $Dat{'day'});
648 $Dat{'hour'} = sprintf("%02u", $Dat{'hour'});
649 $Dat{'min'} = sprintf("%02u", $Dat{'min'});
650 $Dat{'sec'} = sprintf("%02u", $Dat{'sec'});
651 if ($Opt{'chronology'}) {
652 if ($last_time > $ep_time) {
653 warn(sprintf(
654 "%s: \"%sZ\": Next date is %s in the past (%sZ)\n",
655 $progname, sec_to_string($last_time, "T"),
656 sec_to_readable($last_time-$ep_time),
657 sec_to_string($ep_time, "T")
659 # FIXME: Make --fix work with gpx and xml.
660 if ($Opt{'fix'} && ($Opt{'output-format'} !~ /^(gpx|xml)$/)) {
661 ($Line .= "# error ");
665 } else {
666 $Req{'time'} && return;
667 $ep_time = 0;
668 $Dat{'year'} = 0;
669 $Dat{'month'} = 0;
670 $Dat{'day'} = 0;
671 $Dat{'hour'} = 0;
672 $Dat{'min'} = 0;
673 $Dat{'sec'} = 0;
676 if ($Opt{'save-to-file'} ne "\n") {
677 # {{{
678 my $base_name = "$Dat{'year'}$Dat{'month'}$Dat{'day'}T$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z$Opt{'save-to-file'}";
679 my $file_name = $base_name;
680 if (-e $file_name) {
681 for (my $a = 1; (-e $file_name) && ($a < 1000); $a++) {
682 $file_name = "$base_name.dup_$a";
684 if (-e $file_name) {
685 die("$progname: $base_name: File already exists, and ran " .
686 "out of attempts to create unique file name\n");
688 if ($Opt{'verbose'}) {
689 warn("$progname: $base_name: File already exists, using " .
690 "unique name \"$file_name\" instead\n");
693 if (open(ToFP, ">", $file_name)) {
694 print_header(*ToFP);
695 print(ToFP ($from_stdin ? @first_lines : ()), (length($xml_data) ? $xml_data : <>)) ||
696 die("$progname: $file_name: Cannot write to file: $!\n");
697 print_footer(*ToFP);
698 close(ToFP);
699 if ($Opt{'output-format'} eq "gpsml") {
700 printf("<include>%s</include>\n",
701 txt_to_xml($file_name));
702 } elsif ($Opt{'output-format'} eq "gpx") {
703 printf("<!-- Saved unconverted data to \"%s\" -->\n",
704 txt_to_xml($file_name));
705 } else {
706 print("$progname: Saved unconverted data to \"$file_name\"\n");
708 exit 0;
709 } else {
710 die("$progname: $file_name: Cannot create file: $!\n");
712 # }}}
715 my $pause_len = 0;
716 my $do_print = 1;
717 ($Req{'altitude'} && !$print_ele) && return;
719 if ($Opt{'inside'} || $Opt{'outside'}) {
720 if (
721 ($Dat{'lat'} < $lat1) ||
722 ($Dat{'lat'} > $lat2) ||
723 ($Dat{'lon'} < $lon1) ||
724 ($Dat{'lon'} > $lon2)
726 $Opt{'inside'} && return;
727 } else {
728 $Opt{'outside'} && return;
732 if ($Opt{'output-format'} eq "ps") {
733 $Dat{'lon'} *= 100;
734 $Dat{'lat'} *= 100;
736 if ($Opt{'skip-dups'} && ($Dat{'lon'} eq $last_lon) && ($Dat{'lat'} eq $last_lat) && ($Dat{'ele'} eq $last_ele)) {
737 if ($in_dupskip) {
738 $do_print = 0;
739 } else {
740 $do_print = 1;
742 $in_dupskip = 1;
743 } else {
744 $do_print = 1;
745 $in_dupskip && ($Line .= $last_line);
746 $in_dupskip = 0;
749 if ($Opt{'create-breaks'} && $ep_time-$last_time > $PAUSE_LIMIT && $last_time) {
750 $pause_len = $ep_time-$last_time;
751 D("pause_len set to '$pause_len'");
754 if ($pause_len) {
755 if ($Opt{'output-format'} eq "gpsml") {
756 $Line .= sprintf("<pause>%s</pause>\n",
757 sec_to_readable($ep_time-$last_time));
758 } elsif ($Opt{'output-format'} eq "csv") {
759 $Line .= sprintf("# Pause: %s\n# move\n",
760 sec_to_readable($ep_time-$last_time));
764 if ($do_print) {
765 # Valid data was found, send to stdout {{{
766 unless ($first_time) {
767 $first_time = $ep_time;
769 if ($Opt{'double-y-scale'}) {
770 $Dat{'lat'} *= 2;
772 if ($Opt{'output-format'} eq "gpsml") {
773 if ($Dat{'type'} eq "tp") {
774 my $Elem = $Dat{'error'} ? "etp" : "tp";
775 $Line .= join("",
776 "<$Elem> ",
777 $print_time
778 ? "<time>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T" .
779 "$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</time> "
780 : "",
781 (length($Dat{'lat'}))
782 ? "<lat>" . $Dat{'lat'}*1.0 . "</lat> "
783 : "",
784 (length($Dat{'lon'}))
785 ? "<lon>" . $Dat{'lon'}*1.0 . "</lon> "
786 : "",
787 ($print_ele)
788 ? "<ele>" . $Dat{'ele'}*1.0 . "</ele> "
789 : "",
790 ($print_desc)
791 ? sprintf("<desc>%s</desc> ",
792 txt_to_xml($Dat{'desc'}))
793 : "",
794 "</$Elem>\n"
796 } elsif ($Dat{'type'} =~ /^(pause|desc|title)$/) {
797 $Line .= sprintf("<%s>%s</%s>\n",
799 txt_to_xml($Dat{$1}),
800 $1);
802 } elsif ($Opt{'output-format'} eq "xgraph") {
803 $pause_len && ($Line .= "move ");
804 ($Line .= "$Dat{'lon'} $Dat{'lat'}\n");
805 } elsif($Opt{'output-format'} eq "gpstrans") {
806 my ($gpt_lat, $gpt_lon) = (ddd_to_dms($Dat{'lat'}), ddd_to_dms($Dat{'lon'}));
807 if ($print_time) {
808 $Line .= "T\t$Dat{'month'}/$Dat{'day'}/$Dat{'year'} $Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}\t$gpt_lat\t$gpt_lon\n";
809 } else {
810 $Line .= "T\t00/00/00 00:00:00\t$gpt_lat\t$gpt_lon\n";
812 } elsif($Opt{'output-format'} eq "gpx") {
813 $Line .= join("",
814 "$Spc$Spc$Spc$Spc$Spc$Spc<trkpt lat=\"$Dat{'lat'}\" lon=\"$Dat{'lon'}\">$Spc",
815 $print_time
816 ? "<time>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</time>$Spc"
817 : "",
818 $print_ele
819 ? "<ele>$Dat{'ele'}</ele>$Spc"
820 : "",
821 "</trkpt>\n"
823 } elsif ($Opt{'output-format'} eq "clean") {
824 $pause_len && ($Line .= "\n");
825 ($Line .= "$Dat{'lon'}\t$Dat{'lat'}" . ($print_ele ? "\t$Dat{'ele'}" : "") . "\n");
826 } elsif ($Opt{'output-format'} eq "ps") {
827 $Line .= ($pause_len ? "f\n$Dat{'lon'} $Dat{'lat'} m\n" : "$Dat{'lon'} $Dat{'lat'} l\n");
828 } elsif ($Opt{'output-format'} eq "svg") {
829 $Line .= (
830 ($last_lon == 1000) || $pause_len
831 ? join("",
832 "$svg_start_thing<path\n",
833 " stroke=\"blue\"\n",
834 " stroke-width=\"0.001\"\n",
835 " fill=\"none\"\n",
836 " d=\"\n",
837 "M $Dat{'lon'} $Dat{'lat'}\n",
839 : "L $Dat{'lon'} $Dat{'lat'}\n"
841 } elsif ($Opt{'output-format'} eq "xml") {
842 $Line .= join("",
843 "$Spc$Spc<gps>$Spc",
844 $print_time
845 ? "<date>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</date>$Spc"
846 : "",
847 "<pos>$Spc",
848 (length($Dat{'lon'})) ? "<x>$Dat{'lon'}</x>$Spc" : "",
849 (length($Dat{'lat'})) ? "<y>$Dat{'lat'}</y>$Spc" : "",
850 ($print_ele) ? "<z>$Dat{'ele'}</z>$Spc" : "",
851 "</pos>$Spc",
852 "</gps>\n"
854 } elsif ($Opt{'output-format'} eq "ygraph") {
855 my $Time = $print_time ? ($ep_time - $first_time) * 1 : 0;
856 $Line .= "\"Time = $Time.0\n$Dat{'lon'} $Dat{'lat'}\n\n";
857 } elsif ($Opt{'output-format'} eq "csv") {
858 # {{{
859 $Dat{'lon'} =~ s/\./$Des/;
860 $Dat{'lat'} =~ s/\./$Des/;
861 # $do_print || print("skipping ");
862 $Line .= join("\t",
863 $print_time
864 ? $Opt{'epoch'}
865 ? $ep_time
866 : $Opt{'short-date'}
867 ? "$Dat{'year'}$Dat{'month'}$Dat{'day'}T$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z"
868 : "$Dat{'year'}-$Dat{'month'}-$Dat{'day'} $Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}"
869 : "",
870 $Dat{'lon'},
871 $Dat{'lat'},
872 $print_ele ? $Dat{'ele'} : "", # Elevation
873 "\n"
875 # }}}
876 } else {
877 die("$progname: \"$Opt{'output-format'}\": Unknown output format\n");
879 # }}}
882 if (!$last_time && $Opt{'output-format'} eq "ps") {
883 $Line .= "$Dat{'lon'} $Dat{'lat'} m\n";
886 if ($do_print) {
887 if ($found_move) {
888 if ($Opt{'output-format'} eq "gpsml") {
889 $Line = "<break/>\n$Line";
891 (!$pause_len && ($Opt{'output-format'} eq "xgraph")) && ($Line .= "move $Line");
892 ($Opt{'output-format'} eq "clean") && ($Line .= "\n");
893 if ($Opt{'output-format'} eq "gpx") {
894 $Line .= "$Spc$Spc$Spc$Spc</trkseg>\n$Spc$Spc$Spc$Spc<trkseg>\n";
896 $found_move = 0;
898 print($Line);
900 $last_time = $ep_time;
901 $last_lon = $Dat{'lon'};
902 $last_lat = $Dat{'lat'};
903 $last_ele = $Dat{'ele'};
904 $last_line = $data_line;
905 $svg_start_thing = "\"/>\n";
906 # }}}
909 sub list_nearest_waypoints {
910 # {{{
911 my ($Lat, $Lon, $Count) = @_;
912 # FIXME: Incredible unfinished and kludgy.
913 if (open(WaypFP, "gpsbabel -i gpx -f $waypoint_file -x radius,lat=$Lat,lon=$Lon,distance=1000 -o gpx -F - |")) {
914 my $Str = join("", <WaypFP>);
915 $Str =~ s{
916 ^.*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*?
917 .*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*?
918 .*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*$
920 "($1, $2, $3)";
921 }sex;
922 return($Str);
923 } else {
924 die("$progname: Cannot open gpsbabel pipe: $!\n");
926 # }}}
929 sub sec_to_string {
930 # Convert seconds since 1970 to "yyyy-mm-dd hh:mm:ss" with optional
931 # separator
932 # {{{
933 my ($Seconds, $Sep) = @_;
934 defined($Sep) || ($Sep = " ");
935 my @TA = gmtime($Seconds);
936 my($DateString) = sprintf("%04u-%02u-%02u%s%02u:%02u:%02u", $TA[5]+1900, $TA[4]+1, $TA[3], $Sep, $TA[2], $TA[1], $TA[0]);
937 return($DateString);
938 # }}}
941 sub sec_to_readable {
942 # Convert seconds since 1970 to human-readable format (d:hh:mm:ss)
943 # {{{
944 my $secs = shift;
945 D("sec_to_readable(\"$secs\")\n");
946 my ($Day, $Hour, $Min, $Sec) =
947 ( 0, 0, 0, 0);
949 $Day = int($secs/86400);
950 $secs -= $Day * 86400;
952 $Hour = int($secs/3600);
953 $secs -= $Hour * 3600;
955 $Min = int($secs/60);
956 $secs -= $Min * 60;
958 $Sec = $secs;
960 return(sprintf("%u:%02u:%02u:%02u", $Day, $Hour, $Min, $Sec));
961 # }}}
964 sub ps_header {
965 # Send a Postscript header to stdout {{{
966 my ($bl_lon, $bl_lat, $br_lon, $br_lat) = @_;
967 my $Date = sec_to_string(time);
968 return(join("",
969 "%!PS-Adobe-3.0 EPSF-3.0\n",
970 "%%Creator: $rcs_id\n",
971 "%%Title:\n",
972 "%%CreationDate: $Date\n",
973 "%%BoundingBox: $bl_lon $bl_lat $br_lon $br_lat\n",
974 "%%DocumentData: Clean7Bit\n",
975 "%%EndComments\n",
976 "%%BeginProlog\n",
977 "/bd { bind def } bind def\n",
978 "/incompound false def\n",
979 "/m { moveto } bd\n",
980 "/l { lineto } bd\n",
981 "/c { curveto } bd\n",
982 "/F { incompound not {fill} if } bd\n",
983 "/f { closepath F } bd\n",
984 "/S { stroke } bd\n",
985 "/*u { /incompound true def } bd\n",
986 "/*U { /incompound false def f} bd\n",
987 "/k { setcmykcolor } bd\n",
988 "/K { k } bd\n",
989 "%%EndProlog\n",
990 "%%BeginSetup\n",
991 "%%EndSetup\n",
993 # }}}
996 sub ddd_to_dms {
997 # Convert floating-point degrees into D°M'S.S" (ISO-8859-1).
998 # Necessary for import into GPSman. Based on toDMS() from
999 # gpstrans-0.39 to ensure compatibility.
1000 # {{{
1001 my $ddd = shift;
1002 my $Neg = 0;
1003 my ($Hour, $Min, $Sec) =
1004 ( 0, 0, 0);
1005 my $Retval = "";
1007 if ($ddd < 0.0) {
1008 $ddd = 0 - $ddd;
1009 $Neg = 1;
1011 $Hour = int($ddd);
1012 $ddd = ($ddd - $Hour) * 60.0;
1013 $Min = int($ddd);
1014 $Sec = ($ddd - $Min) * 60.0;
1016 if ($Sec > 59.5) {
1017 $Sec = 0.0;
1018 $Min += 1.0;
1020 if ($Min > 59.5) {
1021 $Min = 0.0;
1022 $Hour += 1.0;
1024 if ($Neg) {
1025 $Hour = 0 - $Hour;
1027 D("Neg = $Neg , D = $Hour , M = $Min , S = $Sec\n");
1028 $Retval = sprintf("%s%.0f\xB0%02.0f'%04.1f\"", $Neg ? "-" : "", $Hour, $Min, $Sec);
1029 return $Retval;
1030 # }}}
1033 sub txt_to_xml {
1034 # Convert plain text to XML {{{
1035 my $Txt = shift;
1036 $Txt =~ s/&/&amp;/gs;
1037 $Txt =~ s/</&lt;/gs;
1038 $Txt =~ s/>/&gt;/gs;
1039 return($Txt);
1040 # }}}
1043 sub xml_to_txt {
1044 # Convert XML data to plain text {{{
1045 my $Txt = shift;
1046 $Txt =~ s/&lt;/</gs;
1047 $Txt =~ s/&gt;/>/gs;
1048 $Txt =~ s/&amp;/&/gs;
1049 return($Txt);
1050 # }}}
1053 sub print_version {
1054 # Print program version {{{
1055 print("$rcs_id\n");
1056 exit(0);
1057 # }}}
1058 } # print_version()
1060 sub usage {
1061 # Send the help message to stdout {{{
1062 my $Retval = shift;
1064 print(<<END);
1066 $rcs_id
1068 Converts between various GPS formats.
1070 Usage: $progname [options] [file [files [...]]]
1071 $progname -S [file [files [...]]]
1072 $progname -u [file [files [...]]]
1074 Options:
1076 -c, --comment-out-dups
1077 Use comma instead of period as decimal point (For Gnumeric etc).
1078 -C, --print-comments
1079 Print existing comment lines (starting with "#") and prefix unknown
1080 lines with "# ".
1081 --chronology
1082 Check for broken chronology, warn about entries with an old
1083 timestamp.
1084 -d, --skip-dups
1085 Skip duplicated coordinates, only print first and last.
1086 -e, --epoch
1087 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1088 --fix
1089 Comment out entries which is obviously wrong. Use together with
1090 --chronology to fix those kind of errors. Does not work with GPX or
1091 XML output yet.
1092 -h, --help
1093 Show this help.
1094 --inside
1095 Print only trackpoints inside a rectangle specified by --pos1 and
1096 --pos2.
1097 -n x, --undefined x
1098 Use x as undefined value. Default: "$Udef".
1099 --near
1100 Add names of the three closest waypoints to the trackpoint.
1101 Unfinished and experimental, needs gpsbabel.
1102 -o x, --output-format x
1103 Use output format x:
1104 clean
1106 gpsml (Default)
1107 gpstrans
1108 gpx (Not complete)
1109 poscount (Experimental)
1110 ps (Unfinished)
1111 svg (Unfinished)
1112 xgraph
1114 ygraph
1115 --outside
1116 Print only trackpoints outside a rectangle specified by --pos1 and
1117 --pos2.
1118 --pos1 x, --pos2 x
1119 Specifies one corner where x is in "lat,lon" format (decimal
1120 degrees, negative for west or south) of area rectangle used by the
1121 --inside and --outside options.
1122 -r x, --require x
1123 Specify requirements for trackpoints to be written. x is a string
1124 with the following flags:
1126 Print only waypoints which have an altitude.
1128 Print only waypoints which have a timestamp.
1129 -s, --short-date
1130 Use short date format.
1131 -S x, --save-to-file x
1132 Save the unconverted data to a file with a filename starting with
1133 the timestamp of the first trackpoint. The parameter string x is
1134 added at the end of the filename. For the time being this option
1135 will ignore all other options. Note: If several files are specified
1136 on the command line, all data will be saved into only one file. This
1137 behaviour may change in the future.
1138 -t, --create-breaks
1139 Create breaks in track between points with a difference more than
1140 $PAUSE_LIMIT seconds.
1141 -u, --comment-out-dups
1142 Comment out following data with identical position values, only
1143 print first entry.
1144 -v, --verbose
1145 Verbose, warn about unknown lines.
1146 --version
1147 Print version information.
1148 -w, --strip-whitespace
1149 Strip all unnecessary whitespace.
1150 -y, --double-y-scale
1151 Double Y scale (latitude) to get it right in gnuplot.
1152 --debug
1153 Print debugging messages.
1156 exit($Retval);
1157 # }}}
1158 } # usage()
1160 sub D {
1161 # Print a debugging message {{{
1162 $Debug || return;
1163 my @call_info = caller;
1164 chomp(my $Txt = shift);
1165 my $File = $call_info[1];
1166 $File =~ s#\\#/#g;
1167 $File =~ s#^.*/(.*?)$#$1#;
1168 print(STDERR "$File:$call_info[2] $$ $Txt\n");
1169 return("");
1170 # }}}
1171 } # D()
1173 __END__
1175 # Plain Old Documentation (POD) {{{
1177 =pod
1179 =head1 NAME
1181 gptrans_conv
1183 =head1 REVISION
1185 $Id$
1187 =head1 SYNOPSIS
1189 B<gptrans_conv> [options] [file [files [...]]]
1191 B<gptrans_conv> -S [options] [file [files [...]]]
1193 B<gptrans_conv> -u [options] [file [files [...]]]
1195 =head1 DESCRIPTION
1197 Converts between various GPS formats.
1199 =head1 OPTIONS
1201 =over 4
1203 =item B<-c>, B<--comment-out-dups>
1205 Use comma instead of period as decimal point (For Gnumeric etc).
1207 =item B<-C>, B<--print-comments>
1209 Print existing comment lines (starting with "#") and prefix unknown
1210 lines with "# ".
1212 =item B<--chronology>
1214 Check for broken chronology, warn about entries with an old timestamp.
1216 =item B<-d>, B<--skip-dups>
1218 Skip duplicated coordinates, only print first and last.
1220 =item B<-e>, B<--epoch>
1222 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1224 item B<--fix>
1226 Comment out entries which is obviously wrong. Use together with
1227 --chronology to fix those kind of errors. Does not work with GPX or XML
1228 output yet.
1230 =item B<-h>, B<--help>
1232 Show this help.
1234 =item B<--inside>
1236 Print only trackpoints inside a rectangle specified by --pos1 and
1237 --pos2.
1239 =item B<--near>
1241 Add names of the three closest waypoints to the trackpoint. Unfinished
1242 and experimental, needs gpsbabel.
1244 =item B<-n x>, B<--undefined x>
1246 Use x as undefined value.
1248 =item B<-o x>, B<--output-format x>
1250 Use output format x:
1252 =over 4
1254 =over 4
1256 =item clean
1258 =item csv
1260 =item gpsml (Default)
1262 This is the format which is meant to be used when storing the track
1263 logs.
1264 It is line-based XML which makes it easy to edit and grep. Probably not
1265 finished yet.
1267 =item gpstrans
1269 =item gpx (Not complete)
1271 =item poscount (Experimental)
1273 Creates a 3D plot where areas with many trackpoints are higher than
1274 areas with less track points.
1276 =item ps (Unfinished)
1278 =item svg (Unfinished)
1280 =item xgraph
1282 =item xml
1284 =item ygraph
1286 =back
1288 =back
1292 =item B<--outside>
1294 Print only trackpoints outside a rectangle specified by --pos1 and
1295 --pos2.
1297 =item B<--pos1 x>, B<--pos2 x>
1299 Specifies corners of an area rectangle used by the --inside and
1300 --outside options. The x value is in "lat,lon" format (decimal degrees,
1301 negative for west or south) .
1303 =item B<-r x>, B<--require x>
1305 Specify requirements for trackpoints to be written. x is a string with
1306 the following flags:
1308 =over 4
1310 =over 4
1312 =item a
1314 =over 4
1316 =item Print only waypoints which have an altitude.
1318 =back
1320 =back
1322 =over 4
1324 =item t
1326 =over 4
1328 =item Print only waypoints which have a timestamp.
1330 =back
1332 =back
1334 =back
1338 =item B<-s>, B<--short-date>
1340 Use short date format.
1342 =item B<-S x>, B<--save-to-file x>
1344 Save the unconverted data to a file with a filename starting with the
1345 timestamp of the first trackpoint. The parameter string x is added at
1346 the end of the filename. For the time being this option will ignore all
1347 other options.
1349 Note: If several files are specified on the command line, all data will
1350 be saved into only one file. This behaviour may change in the future.
1352 =item B<-t>, B<--create-breaks>
1354 Create breaks in track between points with a difference more than the
1355 number of seconds specified by the C<$PAUSE_LIMIT> variable.
1357 =item B<-u>, B<--comment-out-dups>
1359 Comment out following data with identical position values, only print
1360 first entry.
1362 =item B<-v>, B<--verbose>
1364 Verbose, warn about unknown lines.
1366 =item B<-w>, B<--strip-whitespace>
1368 Strip all unnecessary whitespace.
1370 =item B<-x>, B<--xml>
1372 Create XML output.
1374 =item B<-y>, B<--double-y-scale>
1376 Double Y scale (latitude) to get it right in gnuplot.
1378 =item B<-h>, B<--help>
1380 Print a brief help summary.
1382 =item B<--version>
1384 Print version information.
1386 =item B<--debug>
1388 Print debugging messages.
1390 =back
1392 =head1 BUGS
1394 Pretty incomplete in some areas. Some of the source formats are
1395 undocumented and thus incomplete. Some functionality is not working
1396 properly, for example the Postscript output.
1398 =head1 AUTHOR
1400 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
1402 =head1 COPYRIGHT
1404 Copyleft © Øyvind A. Holm &lt;sunny@sunbase.org&gt;
1405 This is free software; see the file F<COPYING> for legalese stuff.
1407 =head1 LICENCE
1409 This program is free software; you can redistribute it and/or modify it
1410 under the terms of the GNU General Public License as published by the
1411 Free Software Foundation; either version 2 of the License, or (at your
1412 option) any later version.
1414 This program is distributed in the hope that it will be useful, but
1415 WITHOUT ANY WARRANTY; without even the implied warranty of
1416 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1417 See the GNU General Public License for more details.
1419 You should have received a copy of the GNU General Public License along
1420 with this program; if not, write to the Free Software Foundation, Inc.,
1421 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1423 =head1 SEE ALSO
1425 gpsbabel(1)
1427 =cut
1429 # }}}
1431 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :
1432 # End of file $Id$