gpsfold: Remove $Id$ at EOF.
[gpstools.git] / branches / gpst.gpsman-format / Patch / gpst-replace
blob634570d5c5d1902ef8d595337063c3f6a1805952
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 };
16 $| = 1;
18 our $Debug = 0;
20 our %Opt = (
21 # Initial values for command line arguments {{{
22 'chronology' => 0,
23 'comment-out-dups' => 0,
24 'create-breaks' => 0,
25 'debug' => 0,
26 'double-y-scale' => 0,
27 'epoch' => 0,
28 'fix' => 0,
29 'help' => 0,
30 'inside' => 0,
31 'near' => "",
32 'output-format' => "gpsml",
33 'outside' => 0,
34 'pos1' => "",
35 'pos2' => "",
36 'print-comments' => 0,
37 'replace' => "",
38 'require' => "",
39 'save-to-file' => "\n", # \n = undefined, it’s banned in filenames anyway.
40 'short-date' => 0,
41 'skip-dups' => 0,
42 'strip-whitespace' => 0,
43 'undefined' => "",
44 'use-comma' => 0,
45 'version' => 0,
46 # }}}
49 our $progname = $0;
50 $progname =~ s#^.*/(.*?)$#$1#;
52 my $rcs_id = '$Id$';
53 my $id_date = $rcs_id;
54 $id_date =~ s/^.*?\d+ (\d\d\d\d-.*?\d\d:\d\d:\d\d\S+).*/$1/;
56 Getopt::Long::Configure("bundling");
57 GetOptions(
58 # Command line options {{{
59 "chronology" => \$Opt{'chronology'},
60 "comment-out-dups|u" => \$Opt{'comment-out-dups'},
61 "create-breaks|t" => \$Opt{'create-breaks'},
62 "debug" => \$Opt{'debug'},
63 "double-y-scale|y" => \$Opt{'double-y-scale'},
64 "epoch|e" => \$Opt{'epoch'},
65 "fix" => \$Opt{'fix'},
66 "help|h" => \$Opt{'help'},
67 "inside" => \$Opt{'inside'},
68 "near" => \$Opt{'near'},
69 "output-format|o=s" => \$Opt{'output-format'},
70 "outside" => \$Opt{'outside'},
71 "pos1=s" => \$Opt{'pos1'},
72 "pos2=s" => \$Opt{'pos2'},
73 "print-comments|C" => \$Opt{'print-comments'},
74 "replace" => \$Opt{'replace'},
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 my $Txt = join("", @_);
453 # FIXME: The sequential stuff here is probably bad, but easy.
454 $Txt =~ s#(<gpx\b.*?>.*?</gpx>)#print_gpx($1)#gse;
455 $Txt =~ s#(<gps\b.*?>.*?</gps>)#print_xml_gps($1)#gse;
456 # }}}
459 sub print_gpx {
460 # {{{
461 my $Orig = shift;
462 my $Str = $Orig;
463 D("print_xml_gps(\"$Orig\")\n");
464 $Str =~
466 <trk\b(.*?)>(.*?)</trk>
469 my $el_trk = $2;
470 $el_trk =~
472 <trkseg\b(.*?)>(.*?)</trkseg>
475 my $el_trkseg = $2;
476 $el_trkseg =~
478 <trkpt\b(.*?)>(.*?)</trkpt>
481 my ($attr_trkpt, $el_trkpt) =
482 ( $1, $2);
483 ($attr_trkpt =~ /\blon="(.*?)"/) && ($Dat{'lon'} = $1);
484 ($attr_trkpt =~ /\blat="(.*?)"/) && ($Dat{'lat'} = $1);
485 ($el_trkpt =~ m#<ele\b.*?>(.*?)</ele>#) && ($Dat{'ele'} = $1);
486 if ($el_trkpt =~ m#<time>(\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?(\d\d)\.?(\d*?)Z</time>#) {
487 ($Dat{'year'}, $Dat{'month'}, $Dat{'day'},
488 $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'secfrac'}) =
489 ($1, $2, $3, $4, $5, $6, $7);
491 print_entry(%Dat);
493 }gsex;
494 $found_move = 1;
495 }gsex;
496 $found_move = 1;
497 }gsex;
498 # }}}
501 sub print_xml_gps {
502 # {{{
503 my $Orig = shift;
504 my $Str = $Orig;
505 D("print_xml_gps(\"$Orig\")\n");
506 if ($Str =~ m#<date>(\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):?(\d\d):?(\d\d)\.?(\d*?)Z</date>#) {
507 ($Dat{'year'}, $Dat{'mon'}, $Dat{'day'}, $Dat{'hour'}, $Dat{'min'}, $Dat{'sec'}, $Dat{'secfrac'}) =
508 ( $1, $2, $3, $4, $5, $6, $7);
510 if ($Str =~ m#<pos>(.*?)</pos>#s) {
511 my $Txt = $1;
512 ($Txt =~ m#<x\b.*?>(.*?)</x>#) && ($Dat{'lon'} = $1);
513 ($Txt =~ m#<y\b.*?>(.*?)</y>#) && ($Dat{'lat'} = $1);
514 ($Txt =~ m#<z\b.*?>(.*?)</z>#) && ($Dat{'ele'} = $1);
516 defined($Dat{'lon'}) || ($Dat{'lon'} = "");
517 defined($Dat{'lat'}) || ($Dat{'lat'} = "");
518 defined($Dat{'ele'}) || ($Dat{'ele'} = "");
519 print_entry(%Dat);
520 # }}}
523 sub print_header {
524 # {{{
525 local *OutFP = shift;
526 if ($Opt{'output-format'} eq "gpsml") {
527 print(OutFP join("",
528 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
529 "<gpsml>\n",
530 "<track>\n",
532 } elsif ($Opt{'output-format'} eq "gpstrans") {
533 print(OutFP "Format: DMS UTC Offset: 0.00 hrs Datum[100]: WGS 84\n");
534 } elsif ($Opt{'output-format'} eq "gpx") {
535 print(OutFP join("",
536 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
537 "<gpx>\n",
538 "$Spc$Spc<trk>\n",
539 "$Spc$Spc$Spc$Spc<trkseg>\n",
541 } elsif ($Opt{'output-format'} eq "ps") {
542 print(OutFP ps_header(532, 6034, 533, 6040));
543 print(OutFP "*u\n");
544 } elsif ($Opt{'output-format'} eq "xml") {
545 print(OutFP join("",
546 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
547 "<gpslog>\n",
549 } elsif ($Opt{'output-format'} eq "svg") {
550 print(OutFP join("",
551 "<?xml version=\"1.0\" standalone=\"no\"?>\n",
552 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
553 "$Spc$Spc\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
554 "<svg height=\"1000\" width=\"1000\" viewBox=\"23 70 2 2\"\n",
555 "$Spc${Spc}xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
556 "$Spc$Spc<title></title>\n",
557 "$Spc$Spc<desc></desc>\n",
560 # }}}
563 sub print_footer {
564 # Print footer {{{
565 local *OutFP = shift;
566 if ($Opt{'output-format'} eq "gpsml") {
567 print(OutFP join("",
568 "</track>\n",
569 "</gpsml>\n",
571 } elsif ($Opt{'output-format'} eq "gpx") {
572 print(OutFP join("",
573 "$Spc$Spc$Spc$Spc</trkseg>\n",
574 "$Spc$Spc</trk>\n",
575 "</gpx>\n",
577 } elsif ($Opt{'output-format'} eq "poscount") {
578 while (my ($l_name, $l_val) = each %Poscount) {
579 $l_name =~ /^(.+?),(.+?)$/ && print(OutFP "$1\t$2\t$l_val\n");
581 } elsif ($Opt{'output-format'} eq "ps") {
582 print(OutFP join("",
583 "*U\n",
584 "%%Trailer\n",
585 "%%EOF\n",
587 } elsif ($Opt{'output-format'} eq "svg") {
588 print(OutFP "\"/>\n</svg>\n");
589 } elsif ($Opt{'output-format'} eq "xml") {
590 print(OutFP "</gpslog>\n");
592 # }}}
595 sub print_entry {
596 # Print a GPS entry with time, latitude, longitude and altitude in
597 # various formats
598 # {{{
599 my %Dat = @_;
600 my $print_time = length($Dat{'year'}) ? 1 : 0;
601 my $print_ele = length($Dat{'ele'}) ? 1 : 0;
602 my $print_desc = length($Dat{'desc'}) ? 1 : 0;
603 my $Line = "";
604 D("print_entry(\"" . join("\", \"", @_) . "\");");
605 my $ep_time;
607 if ($Opt{'near'}) {
608 $Line .= sprintf("%s ", list_nearest_waypoints($Dat{'lat'}, $Dat{'lon'}));
611 if ($Opt{'output-format'} eq "poscount") {
612 my ($Lat_str, $Lon_str) =
613 ( "", "");
614 $Dat{'lon'} =~ /^(\d+\.\d\d)/ && ($Lon_str = $1);
615 $Dat{'lat'} =~ /^(\d+\.\d\d)/ && ($Lat_str = $1);
616 my $Name = "${Lon_str},${Lat_str}";
617 defined($Poscount{$Name}) || ($Poscount{$Name} = 0);
618 $Poscount{$Name}++;
619 return;
622 if ($print_time) {
623 $ep_time = timegm_nocheck($Dat{'sec'}, $Dat{'min'}, $Dat{'hour'}, $Dat{'day'}, $Dat{'month'} - 1, $Dat{'year'});
624 $Dat{'year'} = sprintf("%04u", $Dat{'year'});
625 $Dat{'month'} = sprintf("%02u", $Dat{'month'});
626 $Dat{'day'} = sprintf("%02u", $Dat{'day'});
627 $Dat{'hour'} = sprintf("%02u", $Dat{'hour'});
628 $Dat{'min'} = sprintf("%02u", $Dat{'min'});
629 $Dat{'sec'} = sprintf("%02u", $Dat{'sec'});
630 if ($Opt{'chronology'}) {
631 if ($last_time > $ep_time) {
632 warn(sprintf(
633 "%s: \"%sZ\": Next date is %s in the past (%sZ)\n",
634 $progname, sec_to_string($last_time, "T"),
635 sec_to_readable($last_time-$ep_time),
636 sec_to_string($ep_time, "T")
638 # FIXME: Make --fix work with gpx and xml.
639 if ($Opt{'fix'} && ($Opt{'output-format'} !~ /^(gpx|xml)$/)) {
640 ($Line .= "# error ");
644 } else {
645 $Req{'time'} && return;
646 $ep_time = 0;
647 $Dat{'year'} = 0;
648 $Dat{'month'} = 0;
649 $Dat{'day'} = 0;
650 $Dat{'hour'} = 0;
651 $Dat{'min'} = 0;
652 $Dat{'sec'} = 0;
655 if ($Opt{'save-to-file'} ne "\n") {
656 # {{{
657 my $base_name = "$Dat{'year'}$Dat{'month'}$Dat{'day'}T$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z$Opt{'save-to-file'}";
658 my $file_name = $base_name;
659 if (-e $file_name) {
660 for (my $a = 1; (-e $file_name) && ($a < 1000); $a++) {
661 $file_name = "$base_name.dup_$a";
663 if (-e $file_name) {
664 die("$progname: $base_name: File already exists, and ran " .
665 "out of attempts to create unique file name\n");
667 if ($Opt{'verbose'}) {
668 warn("$progname: $base_name: File already exists, using " .
669 "unique name \"$file_name\" instead\n");
672 if (open(ToFP, ">", $file_name)) {
673 print_header(*ToFP);
674 print(ToFP ($from_stdin ? @first_lines : ()), (length($xml_data) ? $xml_data : <>)) ||
675 die("$progname: $file_name: Cannot write to file: $!\n");
676 print_footer(*ToFP);
677 close(ToFP);
678 if ($Opt{'output-format'} eq "gpsml") {
679 printf("<include>%s</include>\n",
680 txt_to_xml($file_name));
681 } elsif ($Opt{'output-format'} eq "gpx") {
682 printf("<!-- Saved unconverted data to \"%s\" -->\n",
683 txt_to_xml($file_name));
684 } else {
685 print("$progname: Saved unconverted data to \"$file_name\"\n");
687 exit 0;
688 } else {
689 die("$progname: $file_name: Cannot create file: $!\n");
691 # }}}
694 my $pause_len = 0;
695 my $do_print = 1;
696 ($Req{'altitude'} && !$print_ele) && return;
698 if ($Opt{'inside'} || $Opt{'outside'}) {
699 if (
700 ($Dat{'lat'} < $lat1) ||
701 ($Dat{'lat'} > $lat2) ||
702 ($Dat{'lon'} < $lon1) ||
703 ($Dat{'lon'} > $lon2)
705 $Opt{'inside'} && return;
706 } else {
707 $Opt{'outside'} && return;
711 if ($Opt{'output-format'} eq "ps") {
712 $Dat{'lon'} *= 100;
713 $Dat{'lat'} *= 100;
715 if ($Opt{'skip-dups'} && ($Dat{'lon'} eq $last_lon) && ($Dat{'lat'} eq $last_lat) && ($Dat{'ele'} eq $last_ele)) {
716 if ($in_dupskip) {
717 $do_print = 0;
718 } else {
719 $do_print = 1;
721 $in_dupskip = 1;
722 } else {
723 $do_print = 1;
724 $in_dupskip && ($Line .= $last_line);
725 $in_dupskip = 0;
728 if ($Opt{'create-breaks'} && $ep_time-$last_time > $PAUSE_LIMIT && $last_time) {
729 $pause_len = $ep_time-$last_time;
730 D("pause_len set to '$pause_len'");
733 if ($pause_len) {
734 if ($Opt{'output-format'} eq "gpsml") {
735 $Line .= sprintf("<pause>%s</pause>\n",
736 sec_to_readable($ep_time-$last_time));
737 } elsif ($Opt{'output-format'} eq "csv") {
738 $Line .= sprintf("# Pause: %s\n# move\n",
739 sec_to_readable($ep_time-$last_time));
743 if ($do_print) {
744 # Valid data was found, send to stdout {{{
745 unless ($first_time) {
746 $first_time = $ep_time;
748 if ($Opt{'double-y-scale'}) {
749 $Dat{'lat'} *= 2;
751 if ($Opt{'output-format'} eq "gpsml") {
752 if ($Dat{'type'} eq "tp") {
753 my $Elem = $Dat{'error'} ? "etp" : "tp";
754 $Line .= join("",
755 "<$Elem> ",
756 $print_time
757 ? "<time>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T" .
758 "$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</time> "
759 : "",
760 (length($Dat{'lat'}))
761 ? "<lat>" . $Dat{'lat'}*1.0 . "</lat> "
762 : "",
763 (length($Dat{'lon'}))
764 ? "<lon>" . $Dat{'lon'}*1.0 . "</lon> "
765 : "",
766 ($print_ele)
767 ? "<ele>" . $Dat{'ele'}*1.0 . "</ele> "
768 : "",
769 ($print_desc)
770 ? sprintf("<desc>%s</desc> ",
771 txt_to_xml($Dat{'desc'}))
772 : "",
773 "</$Elem>\n"
775 } elsif ($Dat{'type'} =~ /^(pause|desc|title)$/) {
776 $Line .= sprintf("<%s>%s</%s>\n",
778 txt_to_xml($Dat{$1}),
779 $1);
781 } elsif ($Opt{'output-format'} eq "xgraph") {
782 $pause_len && ($Line .= "move ");
783 ($Line .= "$Dat{'lon'} $Dat{'lat'}\n");
784 } elsif($Opt{'output-format'} eq "gpstrans") {
785 my ($gpt_lat, $gpt_lon) = (ddd_to_dms($Dat{'lat'}), ddd_to_dms($Dat{'lon'}));
786 if ($print_time) {
787 $Line .= "T\t$Dat{'month'}/$Dat{'day'}/$Dat{'year'} $Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}\t$gpt_lat\t$gpt_lon\n";
788 } else {
789 $Line .= "T\t00/00/00 00:00:00\t$gpt_lat\t$gpt_lon\n";
791 } elsif($Opt{'output-format'} eq "gpx") {
792 $Line .= join("",
793 "$Spc$Spc$Spc$Spc$Spc$Spc<trkpt lat=\"$Dat{'lat'}\" lon=\"$Dat{'lon'}\">$Spc",
794 $print_time
795 ? "<time>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</time>$Spc"
796 : "",
797 $print_ele
798 ? "<ele>$Dat{'ele'}</ele>$Spc"
799 : "",
800 "</trkpt>\n"
802 } elsif ($Opt{'output-format'} eq "clean") {
803 $pause_len && ($Line .= "\n");
804 ($Line .= "$Dat{'lon'}\t$Dat{'lat'}" . ($print_ele ? "\t$Dat{'ele'}" : "") . "\n");
805 } elsif ($Opt{'output-format'} eq "ps") {
806 $Line .= ($pause_len ? "f\n$Dat{'lon'} $Dat{'lat'} m\n" : "$Dat{'lon'} $Dat{'lat'} l\n");
807 } elsif ($Opt{'output-format'} eq "svg") {
808 $Line .= (
809 ($last_lon == 1000) || $pause_len
810 ? join("",
811 "$svg_start_thing<path\n",
812 " stroke=\"blue\"\n",
813 " stroke-width=\"0.001\"\n",
814 " fill=\"none\"\n",
815 " d=\"\n",
816 "M $Dat{'lon'} $Dat{'lat'}\n",
818 : "L $Dat{'lon'} $Dat{'lat'}\n"
820 } elsif ($Opt{'output-format'} eq "xml") {
821 $Line .= join("",
822 "$Spc$Spc<gps>$Spc",
823 $print_time
824 ? "<date>$Dat{'year'}-$Dat{'month'}-$Dat{'day'}T$Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}Z</date>$Spc"
825 : "",
826 "<pos>$Spc",
827 (length($Dat{'lon'})) ? "<x>$Dat{'lon'}</x>$Spc" : "",
828 (length($Dat{'lat'})) ? "<y>$Dat{'lat'}</y>$Spc" : "",
829 ($print_ele) ? "<z>$Dat{'ele'}</z>$Spc" : "",
830 "</pos>$Spc",
831 "</gps>\n"
833 } elsif ($Opt{'output-format'} eq "ygraph") {
834 my $Time = $print_time ? ($ep_time - $first_time) * 1 : 0;
835 $Line .= "\"Time = $Time.0\n$Dat{'lon'} $Dat{'lat'}\n\n";
836 } elsif ($Opt{'output-format'} eq "csv") {
837 # {{{
838 $Dat{'lon'} =~ s/\./$Des/;
839 $Dat{'lat'} =~ s/\./$Des/;
840 # $do_print || print("skipping ");
841 $Line .= join("\t",
842 $print_time
843 ? $Opt{'epoch'}
844 ? $ep_time
845 : $Opt{'short-date'}
846 ? "$Dat{'year'}$Dat{'month'}$Dat{'day'}T$Dat{'hour'}$Dat{'min'}$Dat{'sec'}Z"
847 : "$Dat{'year'}-$Dat{'month'}-$Dat{'day'} $Dat{'hour'}:$Dat{'min'}:$Dat{'sec'}"
848 : "",
849 $Dat{'lon'},
850 $Dat{'lat'},
851 $print_ele ? $Dat{'ele'} : "", # Elevation
852 "\n"
854 # }}}
855 } else {
856 die("$progname: \"$Opt{'output-format'}\": Unknown output format\n");
858 # }}}
861 if (!$last_time && $Opt{'output-format'} eq "ps") {
862 $Line .= "$Dat{'lon'} $Dat{'lat'} m\n";
865 if ($do_print) {
866 if ($found_move) {
867 if ($Opt{'output-format'} eq "gpsml") {
868 $Line = "<break/>\n$Line";
870 (!$pause_len && ($Opt{'output-format'} eq "xgraph")) && ($Line .= "move $Line");
871 ($Opt{'output-format'} eq "clean") && ($Line .= "\n");
872 if ($Opt{'output-format'} eq "gpx") {
873 $Line .= "$Spc$Spc$Spc$Spc</trkseg>\n$Spc$Spc$Spc$Spc<trkseg>\n";
875 $found_move = 0;
877 print($Line);
879 $last_time = $ep_time;
880 $last_lon = $Dat{'lon'};
881 $last_lat = $Dat{'lat'};
882 $last_ele = $Dat{'ele'};
883 $last_line = $data_line;
884 $svg_start_thing = "\"/>\n";
885 # }}}
888 sub list_nearest_waypoints {
889 # {{{
890 my ($Lat, $Lon, $Count) = @_;
891 # FIXME: Incredible unfinished and kludgy.
892 if (open(WaypFP, "gpsbabel -i gpx -f $waypoint_file -x radius,lat=$Lat,lon=$Lon,distance=1000 -o gpx -F - |")) {
893 my $Str = join("", <WaypFP>);
894 $Str =~ s{
895 ^.*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*?
896 .*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*?
897 .*?<wpt\s.*?>.*?<name>(.+?)</name>.*?</wpt>.*$
899 "($1, $2, $3)";
900 }sex;
901 return($Str);
902 } else {
903 die("$progname: Cannot open gpsbabel pipe: $!\n");
905 # }}}
908 sub sec_to_string {
909 # Convert seconds since 1970 to "yyyy-mm-dd hh:mm:ss" with optional
910 # separator
911 # {{{
912 my ($Seconds, $Sep) = @_;
913 defined($Sep) || ($Sep = " ");
914 my @TA = gmtime($Seconds);
915 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]);
916 return($DateString);
917 # }}}
920 sub sec_to_readable {
921 # Convert seconds since 1970 to human-readable format (d:hh:mm:ss)
922 # {{{
923 my $secs = shift;
924 D("sec_to_readable(\"$secs\")\n");
925 my ($Day, $Hour, $Min, $Sec) =
926 ( 0, 0, 0, 0);
928 $Day = int($secs/86400);
929 $secs -= $Day * 86400;
931 $Hour = int($secs/3600);
932 $secs -= $Hour * 3600;
934 $Min = int($secs/60);
935 $secs -= $Min * 60;
937 $Sec = $secs;
939 return(sprintf("%u:%02u:%02u:%02u", $Day, $Hour, $Min, $Sec));
940 # }}}
943 sub ps_header {
944 # Send a Postscript header to stdout {{{
945 my ($bl_lon, $bl_lat, $br_lon, $br_lat) = @_;
946 my $Date = sec_to_string(time);
947 return(join("",
948 "%!PS-Adobe-3.0 EPSF-3.0\n",
949 "%%Creator: $rcs_id\n",
950 "%%Title:\n",
951 "%%CreationDate: $Date\n",
952 "%%BoundingBox: $bl_lon $bl_lat $br_lon $br_lat\n",
953 "%%DocumentData: Clean7Bit\n",
954 "%%EndComments\n",
955 "%%BeginProlog\n",
956 "/bd { bind def } bind def\n",
957 "/incompound false def\n",
958 "/m { moveto } bd\n",
959 "/l { lineto } bd\n",
960 "/c { curveto } bd\n",
961 "/F { incompound not {fill} if } bd\n",
962 "/f { closepath F } bd\n",
963 "/S { stroke } bd\n",
964 "/*u { /incompound true def } bd\n",
965 "/*U { /incompound false def f} bd\n",
966 "/k { setcmykcolor } bd\n",
967 "/K { k } bd\n",
968 "%%EndProlog\n",
969 "%%BeginSetup\n",
970 "%%EndSetup\n",
972 # }}}
975 sub ddd_to_dms {
976 # Convert floating-point degrees into D°M'S.S" (ISO-8859-1).
977 # Necessary for import into GPSman. Based on toDMS() from
978 # gpstrans-0.39 to ensure compatibility.
979 # {{{
980 my $ddd = shift;
981 my $Neg = 0;
982 my ($Hour, $Min, $Sec) =
983 ( 0, 0, 0);
984 my $Retval = "";
986 if ($ddd < 0.0) {
987 $ddd = 0 - $ddd;
988 $Neg = 1;
990 $Hour = int($ddd);
991 $ddd = ($ddd - $Hour) * 60.0;
992 $Min = int($ddd);
993 $Sec = ($ddd - $Min) * 60.0;
995 if ($Sec > 59.5) {
996 $Sec = 0.0;
997 $Min += 1.0;
999 if ($Min > 59.5) {
1000 $Min = 0.0;
1001 $Hour += 1.0;
1003 if ($Neg) {
1004 $Hour = 0 - $Hour;
1006 D("Neg = $Neg , D = $Hour , M = $Min , S = $Sec\n");
1007 $Retval = sprintf("%s%.0f\xB0%02.0f'%04.1f\"", $Neg ? "-" : "", $Hour, $Min, $Sec);
1008 return $Retval;
1009 # }}}
1012 sub txt_to_xml {
1013 # Convert plain text to XML {{{
1014 my $Txt = shift;
1015 $Txt =~ s/&/&amp;/gs;
1016 $Txt =~ s/</&lt;/gs;
1017 $Txt =~ s/>/&gt;/gs;
1018 return($Txt);
1019 # }}}
1022 sub xml_to_txt {
1023 # Convert XML data to plain text {{{
1024 my $Txt = shift;
1025 $Txt =~ s/&lt;/</gs;
1026 $Txt =~ s/&gt;/>/gs;
1027 $Txt =~ s/&amp;/&/gs;
1028 return($Txt);
1029 # }}}
1032 sub print_version {
1033 # Print program version {{{
1034 print("$rcs_id\n");
1035 exit(0);
1036 # }}}
1037 } # print_version()
1039 sub usage {
1040 # Send the help message to stdout {{{
1041 my $Retval = shift;
1043 print(<<END);
1045 $rcs_id
1047 Converts between various GPS formats.
1049 Usage: $progname [options] [file [files [...]]]
1050 $progname -S [file [files [...]]]
1051 $progname -u [file [files [...]]]
1053 Options:
1055 -c, --comment-out-dups
1056 Use comma instead of period as decimal point (For Gnumeric etc).
1057 -C, --print-comments
1058 Print existing comment lines (starting with "#") and prefix unknown
1059 lines with "# ".
1060 --chronology
1061 Check for broken chronology, warn about entries with an old
1062 timestamp.
1063 -d, --skip-dups
1064 Skip duplicated coordinates, only print first and last.
1065 -e, --epoch
1066 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1067 --fix
1068 Comment out entries which is obviously wrong. Use together with
1069 --chronology to fix those kind of errors. Does not work with GPX or
1070 XML output yet.
1071 -h, --help
1072 Show this help.
1073 --inside
1074 Print only trackpoints inside a rectangle specified by --pos1 and
1075 --pos2.
1076 -n x, --undefined x
1077 Use x as undefined value. Default: "$Udef".
1078 --near
1079 Add names of the three closest waypoints to the trackpoint.
1080 Unfinished and experimental, needs gpsbabel.
1081 -o x, --output-format x
1082 Use output format x:
1083 clean
1085 gpsml (Default)
1086 gpstrans
1087 gpx (Not complete)
1088 poscount (Experimental)
1089 ps (Unfinished)
1090 svg (Unfinished)
1091 xgraph
1093 ygraph
1094 --outside
1095 Print only trackpoints outside a rectangle specified by --pos1 and
1096 --pos2.
1097 --pos1 x, --pos2 x
1098 Specifies one corner where x is in "lat,lon" format (decimal
1099 degrees, negative for west or south) of area rectangle used by the
1100 --inside and --outside options.
1101 -r x, --require x
1102 Specify requirements for trackpoints to be written. x is a string
1103 with the following flags:
1105 Print only waypoints which have an altitude.
1107 Print only waypoints which have a timestamp.
1108 --replace
1109 Replace the processed files with the output. Useful with things like
1110 --fix. WARNING: May fuck up the files at the moment, keep a backup.
1111 -s, --short-date
1112 Use short date format.
1113 -S x, --save-to-file x
1114 Save the unconverted data to a file with a filename starting with
1115 the timestamp of the first trackpoint. The parameter string x is
1116 added at the end of the filename. For the time being this option
1117 will ignore all other options. Note: If several files are specified
1118 on the command line, all data will be saved into only one file. This
1119 behaviour may change in the future.
1120 -t, --create-breaks
1121 Create breaks in track between points with a difference more than
1122 $PAUSE_LIMIT seconds.
1123 -u, --comment-out-dups
1124 Comment out following data with identical position values, only
1125 print first entry.
1126 -v, --verbose
1127 Verbose, warn about unknown lines.
1128 --version
1129 Print version information.
1130 -w, --strip-whitespace
1131 Strip all unnecessary whitespace.
1132 -y, --double-y-scale
1133 Double Y scale (latitude) to get it right in gnuplot.
1134 --debug
1135 Print debugging messages.
1138 exit($Retval);
1139 # }}}
1140 } # usage()
1142 sub D {
1143 # Print a debugging message {{{
1144 $Debug || return;
1145 my @call_info = caller;
1146 chomp(my $Txt = shift);
1147 my $File = $call_info[1];
1148 $File =~ s#\\#/#g;
1149 $File =~ s#^.*/(.*?)$#$1#;
1150 print(STDERR "$File:$call_info[2] $$ $Txt\n");
1151 return("");
1152 # }}}
1153 } # D()
1155 __END__
1157 # Plain Old Documentation (POD) {{{
1159 =pod
1161 =head1 NAME
1163 gptrans_conv
1165 =head1 REVISION
1167 $Id$
1169 =head1 SYNOPSIS
1171 B<gptrans_conv> [options] [file [files [...]]]
1173 B<gptrans_conv> -S [options] [file [files [...]]]
1175 B<gptrans_conv> -u [options] [file [files [...]]]
1177 =head1 DESCRIPTION
1179 Converts between various GPS formats.
1181 =head1 OPTIONS
1183 =over 4
1185 =item B<-c>, B<--comment-out-dups>
1187 Use comma instead of period as decimal point (For Gnumeric etc).
1189 =item B<-C>, B<--print-comments>
1191 Print existing comment lines (starting with "#") and prefix unknown
1192 lines with "# ".
1194 =item B<--chronology>
1196 Check for broken chronology, warn about entries with an old timestamp.
1198 =item B<-d>, B<--skip-dups>
1200 Skip duplicated coordinates, only print first and last.
1202 =item B<-e>, B<--epoch>
1204 Use seconds since 1970-01-01 00:00:00 GMT as date format.
1206 item B<--fix>
1208 Comment out entries which is obviously wrong. Use together with
1209 --chronology to fix those kind of errors. Does not work with GPX or XML
1210 output yet.
1212 =item B<-h>, B<--help>
1214 Show this help.
1216 =item B<--inside>
1218 Print only trackpoints inside a rectangle specified by --pos1 and
1219 --pos2.
1221 =item B<--near>
1223 Add names of the three closest waypoints to the trackpoint. Unfinished
1224 and experimental, needs gpsbabel.
1226 =item B<-n x>, B<--undefined x>
1228 Use x as undefined value.
1230 =item B<-o x>, B<--output-format x>
1232 Use output format x:
1234 =over 4
1236 =over 4
1238 =item clean
1240 =item csv
1242 =item gpsml (Default)
1244 This is the format which is meant to be used when storing the track
1245 logs.
1246 It is line-based XML which makes it easy to edit and grep. Probably not
1247 finished yet.
1249 =item gpstrans
1251 =item gpx (Not complete)
1253 =item poscount (Experimental)
1255 Creates a 3D plot where areas with many trackpoints are higher than
1256 areas with less track points.
1258 =item ps (Unfinished)
1260 =item svg (Unfinished)
1262 =item xgraph
1264 =item xml
1266 =item ygraph
1268 =back
1270 =back
1274 =item B<--outside>
1276 Print only trackpoints outside a rectangle specified by --pos1 and
1277 --pos2.
1279 =item B<--pos1 x>, B<--pos2 x>
1281 Specifies corners of an area rectangle used by the --inside and
1282 --outside options. The x value is in "lat,lon" format (decimal degrees,
1283 negative for west or south) .
1285 =item B<-r x>, B<--require x>
1287 Specify requirements for trackpoints to be written. x is a string with
1288 the following flags:
1290 =over 4
1292 =over 4
1294 =item a
1296 =over 4
1298 =item Print only waypoints which have an altitude.
1300 =back
1302 =back
1304 =over 4
1306 =item t
1308 =over 4
1310 =item Print only waypoints which have a timestamp.
1312 =back
1314 =back
1316 =back
1320 =item B<-s>, B<--short-date>
1322 Use short date format.
1324 =item B<-S x>, B<--save-to-file x>
1326 Save the unconverted data to a file with a filename starting with the
1327 timestamp of the first trackpoint. The parameter string x is added at
1328 the end of the filename. For the time being this option will ignore all
1329 other options.
1331 Note: If several files are specified on the command line, all data will
1332 be saved into only one file. This behaviour may change in the future.
1334 =item B<-t>, B<--create-breaks>
1336 Create breaks in track between points with a difference more than the
1337 number of seconds specified by the C<$PAUSE_LIMIT> variable.
1339 =item B<-u>, B<--comment-out-dups>
1341 Comment out following data with identical position values, only print
1342 first entry.
1344 =item B<-v>, B<--verbose>
1346 Verbose, warn about unknown lines.
1348 =item B<-w>, B<--strip-whitespace>
1350 Strip all unnecessary whitespace.
1352 =item B<-x>, B<--xml>
1354 Create XML output.
1356 =item B<-y>, B<--double-y-scale>
1358 Double Y scale (latitude) to get it right in gnuplot.
1360 =item B<-h>, B<--help>
1362 Print a brief help summary.
1364 =item B<--version>
1366 Print version information.
1368 =item B<--debug>
1370 Print debugging messages.
1372 =back
1374 =head1 BUGS
1376 Pretty incomplete in some areas. Some of the source formats are
1377 undocumented and thus incomplete. Some functionality is not working
1378 properly, for example the Postscript output.
1380 =head1 AUTHOR
1382 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
1384 =head1 COPYRIGHT
1386 Copyleft © Øyvind A. Holm &lt;sunny@sunbase.org&gt;
1387 This is free software; see the file F<COPYING> for legalese stuff.
1389 =head1 LICENCE
1391 This program is free software; you can redistribute it and/or modify it
1392 under the terms of the GNU General Public License as published by the
1393 Free Software Foundation; either version 2 of the License, or (at your
1394 option) any later version.
1396 This program is distributed in the hope that it will be useful, but
1397 WITHOUT ANY WARRANTY; without even the implied warranty of
1398 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1399 See the GNU General Public License for more details.
1401 You should have received a copy of the GNU General Public License along
1402 with this program; if not, write to the Free Software Foundation, Inc.,
1403 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1405 =head1 SEE ALSO
1407 gpsbabel(1)
1409 =cut
1411 # }}}
1413 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :
1414 # End of file $Id$