* /trunk/Tools/dtd/gpx/gpx-1.1.dtd
[gpstools.git] / branches / old / utv / gptrans_conv
blobf65452ab6a3b6a10d51ed06ae6cc4cd7e3d6d412
1 #!/usr/bin/perl -w
3 # ╔══════════════════════════════════════════════════════════════
4 # ║ $Id$
5 # ║ Converts between various GPS formats
6 # ║ Character set: UTF-8
7 # ║ License: GNU General Public License
8 # ║ Made by Øyvind A. Holm — sunny@sunbase.org
9 # ╚══════════════════════════════════════════════════════════════
11 use strict;
12 use utf8;
13 use Getopt::Std;
14 use Time::Local qw { timegm_nocheck };
16 my $Debug = 0;
18 my $rcs_str = '$Id$';
20 our ($opt_c, $opt_d, $opt_e, $opt_h, $opt_o, $opt_s, $opt_t, $opt_u) =
21 ( 0, 0, 0, 0, "", 0, 0, 0);
22 getopts('cdeho:stu');
24 $| = 1;
26 my $PAUSE_LIMIT = 2 * 60; # Antall sekunder mellom to punkter det må til før en move legges inn.
27 my $Des = $opt_c ? "," : ".";
28 my $in_dupskip = 0; # Er 1 hvis vi holder på med ignorering av duplikater
29 my $found_move = 0; # Settes til 1 hvis en /^# move$/ blir funnet.
30 my $last_time = 0;
31 my ($last_lon, $last_lat, $last_alt, $last_line) =
32 ( 1000, 1000, 100000, ""); # Vi kan jo teoretisk sett være i Greenwich eller på ekvator
34 if ($opt_h) {
35 # Syntax screen to stdout and exit gracefully {{{
36 print(<<END);
38 Syntax: gptrans_conv [options] [files [...]]
39 gptrans_conv -u [files [...]]
41 -c Use comma instead of period as decimal point (For Gnumeric etc)
42 -d Skip duplicated coordinates, only print first and last
43 -e Use seconds since 1970-01-01 00:00:00 GMT as date format
44 -h Help me ...---...
45 -o x Use output format x:
46 clean
47 gpstrans
48 ps (Unfinished)
49 xgraph
50 -s Short date format
51 -t Create breaks in track between points with a difference
52 more than $PAUSE_LIMIT seconds
53 -u Comment out following data with identical position values,
54 only print first entry
56 END
57 exit(0);
58 # }}}
61 # Kunne vært et eget script på grunn av at det gjør sine helt egne greier, men like greit å samle det på en plass.
62 # FIXME: Fjerner ikke første duplikatentryen.
63 # FIXME: Se om det går å få flytta den inn i print_entry() så man slipper å ha to gptrans_conv’er i pipen.
64 # FIXME: Legg inn alle formatene.
65 if ($opt_u) {
66 # Comment out areas without reception {{{
67 my ($start_date, $end_date, $found_dup) = ("", "", 0);
68 my @Dup = ();
69 while (<>) {
70 if (m#^1 (\S+) (\S+) (\S+) (\S+) (\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)#) {
71 # {{{
72 my ($lat_val, $lon_val, $Speed, $Unkn, $Month, $Day, $Year, $Hour, $Min, $Sec) =
73 ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
74 if (($lat_val eq $last_lat) && ($lon_val eq $last_lon)) {
75 unless ($found_dup) {
76 $start_date = "$Year$Month${Day}T$Hour$Min$Sec";
77 @Dup = ();
78 $found_dup = 1;
80 push(@Dup, "# $_");
81 $end_date = "$Year$Month${Day}T$Hour$Min$Sec";
82 } else {
83 if ($found_dup) {
84 print("# $start_date-$end_date: CO: No signal \x7B\x7B\x7B\n");
85 for (@Dup) {
86 print($_);
88 print("# $start_date-$end_date: CO: No signal \x7D\x7D\x7D\n# move\n$_");
89 $found_dup = 0;
90 } else {
91 print($_);
94 $last_lat = $lat_val;
95 $last_lon = $lon_val;
96 # }}}
97 } else {
98 if ($found_dup) {
99 push(@Dup, $_);
100 } else {
101 print($_);
105 if ($found_dup) {
106 print("# $start_date-$end_date: CO: No signal \x7B\x7B\x7B\n");
107 for (@Dup) {
108 print($_);
110 print("# $start_date-$end_date: CO: No signal \x7D\x7D\x7D\n# move\n");
111 $found_dup = 0;
113 exit(0);
114 # }}}
117 if ($opt_o eq "gpstrans") {
118 print("Format: DMS UTC Offset: 0.00 hrs Datum[100]: WGS 84\n");
119 } elsif ($opt_o eq "ps") {
120 print(ps_header(532, 6034, 533, 6040));
121 print("*u\n");
124 while (<>) {
125 # Scan through stdin or specified files and send every GPS entry to print_entry() {{{
126 my $bck_line = $_;
127 if (/^# Pause: /) {
128 } elsif (/^# move$/) {
129 $found_move = 1;
130 } elsif (/^#/) {
131 print unless ($opt_o =~ /^(xgraph|gpstrans)$/);
132 } elsif (m#^(\d+)\t([0-9\.\-,?]+)\t([0-9\.\-,?]+)\t([+\-\d?])#) {
133 # Author’s format, epoch style {{{
134 my ($ep_time, $lon_val, $lat_val, $Alt) =
135 ( $1, $2, $3, $4);
136 my ($Sec, $Min, $Hour, $Day, $Month, $Year, $Wday, $Yday) = gmtime($ep_time);
137 $Month++; # Urgh Ⅰ
138 $Year += 1900; # Urgh Ⅱ
139 print_entry($Year, $Month, $Day, $Hour, $Min, $Sec, $lon_val, $lat_val, $Alt);
140 # }}}
141 } elsif (m#^(\d\d\d\d)-?(\d\d)-?(\d\d)[T ](\d\d):?(\d\d):?(\d\d)Z?\t([0-9\.\-,?]+)\t([0-9\.\-,?]+)\t([+\-\d?])#) {
142 # Author’s format, human-readable date format {{{
143 my ($Year, $Month, $Day, $Hour, $Min, $Sec, $lon_val, $lat_val, $Alt) =
144 ( $1, $2, $3, $4, $5, $6, $7, $8, $9);
145 print_entry($Year, $Month, $Day, $Hour, $Min, $Sec, $lon_val, $lat_val, "?");
146 # }}}
147 } elsif (m#^T\t(\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)\t(.+)\xB0(.+)'(.+)"\t(.+)\xB0(.+)'(.+)"#) {
148 # T 09/01/2002 11:51:26 60°23'36.3" 5°19'35.9" {{{
149 my ($Month, $Day, $Year, $Hour, $Min, $Sec, $lat_d, $lat_m, $lat_s, $lon_d, $lon_m, $lon_s) =
150 ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
151 my $lat_val = sprintf("%.5f", 1*($lat_d+($lat_m/60)+($lat_s/3600)));
152 my $lon_val = sprintf("%.5f", $lon_d+($lon_m/60)+($lon_s/3600));
153 print_entry($Year, $Month, $Day, $Hour, $Min, $Sec, $lon_val, $lat_val, "?");
154 # }}}
155 } elsif (m#^1 (\S+) (\S+) (\S+) (\S+) (\d\d)/(\d\d)/(\d\d\d\d) (\d\d):(\d\d):(\d\d)#) {
156 # 1 60.3938222 5.3238754 17.3 0 09/01/2002 14:18:23 {{{
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 print_entry($Year, $Month, $Day, $Hour, $Min, $Sec, $lon_val, $lat_val, "?");
160 # }}}
161 } elsif (/^
162 # @020721221336N6048353E00701826S015-00001E4859N1673U0000 {{{
163 # Regexp {{{
164 (@) # @
165 (\d\d) # Year
166 (\d\d) # Month
167 (\d\d) # Day
168 (\d\d) # Hours
169 (\d\d) # Minutes
170 (\d\d) # Seconds
171 (.) # N|S
172 (..) # Latitude degree
173 (..) # Latitude minute
174 (\d\d\d) # Latitude minute decimals
175 (.) # E|W
176 (\d\d\d) # Longitude degree
177 (\d\d) # Longitude minute
178 (\d\d\d) # Longitude minute degree
179 (....) # Accurancy
180 (......) # Altitude
181 (...............)
182 # }}}
183 /x) {
184 my ($Alfa, $Year, $Month, $Day, $Hour, $Min, $Sec, $NS, $Y_deg, $Y_degmin, $Y_mindec, $EW, $X_deg, $X_degmin, $X_mindec, $Accur, $Alt, $Rest) =
185 ( $1, $2+2000, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18);
186 my $ep_time = timegm_nocheck($Sec, $Min, $Hour, $Day, $Month-1, $Year);
187 $last_time = $ep_time;
188 my $tmp_x = sprintf("%.5f", $X_deg + $X_degmin/60 + $X_mindec/60000);
189 my $tmp_y = sprintf("%.5f", $Y_deg + $Y_degmin/60 + $Y_mindec/60000);
190 $tmp_x =~ s/\./$Des/;
191 $tmp_y =~ s/\./$Des/;
192 print_entry($Year, $Month, $Day, $Hour, $Min, $Sec, $tmp_x, $tmp_y, $Alt);
193 # }}}
194 } elsif (/^(@)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(__________________________________________)/) {
195 # @020721221336__________________________________________ {{{
196 my ($Alfa, $Year, $Month, $Day, $Hour, $Min, $Sec, $Rest) =
197 ( $1, $2+2000, $3, $4, $5, $6, $7, $8);
198 print("\n") unless ($opt_o =~ /^(xgraph|gpstrans)$/);
199 $found_move = 1;
200 # }}}
201 } elsif (/^xmaplog /) {
202 print("\n") unless ($opt_o =~ /^(xgraph|gpstrans)$/);
203 } elsif (/^$/) {
204 print("\n") unless ($opt_o =~ /^(xgraph|gpstrans)$/);
205 } else {
206 print("# $_");
207 chomp;
208 warn("Line $.: Unknown: \"$_\"\n");
210 # }}}
213 if ($opt_o eq "ps") {
214 print(<<END);
216 %%Trailer
217 %%EOF
221 exit(0);
223 sub print_entry {
224 # Print a GPS entry with time, latitude, longitude and altitude in various formats {{{
225 my ($Year, $Month, $Day, $Hour, $Min, $Sec, $Lon, $Lat, $Alt) = @_;
226 my $ep_time = timegm_nocheck($Sec, $Min, $Hour, $Day, $Month-1, $Year);
227 $Year = sprintf("%04u", $Year);
228 $Month = sprintf("%02u", $Month);
229 $Day = sprintf("%02u", $Day);
230 $Hour = sprintf("%02u", $Hour);
231 $Min = sprintf("%02u", $Min);
232 $Sec = sprintf("%02u", $Sec);
233 my $pause_len = 0;
234 my $do_print = 1;
235 my $Line = "";
236 if ($opt_o eq "ps") {
237 $Lon *= 100;
238 $Lat *= 100;
240 if ($opt_d && ($Lon eq $last_lon) && ($Lat eq $last_lat) && ($Alt eq $last_alt)) {
241 if ($in_dupskip) {
242 $do_print = 0;
243 } else {
244 $do_print = 1;
246 $in_dupskip = 1;
247 } else {
248 $do_print = 1;
249 $in_dupskip && print($last_line);
250 $in_dupskip = 0;
253 if ($opt_t && $ep_time-$last_time > $PAUSE_LIMIT && $last_time) {
254 $pause_len = $ep_time-$last_time;
257 if ($pause_len && ($opt_o !~ /^(xgraph|gpstrans)$/)) {
258 printf("# Pause: %s\n# move\n", sec_to_readable($ep_time-$last_time));
261 if ($do_print) {
262 # Valid data was found, send to stdout {{{
263 if ($opt_o eq "xgraph") {
264 $pause_len && ($Line = "move ");
265 ($Line .= "$Lon $Lat\n");
266 } elsif($opt_o eq "gpstrans") {
267 my ($gpt_lat, $gpt_lon) = (ddd_to_dms($Lat), ddd_to_dms($Lon));
268 $Line = "T\t$Month/$Day/$Year $Hour:$Min:$Sec\t$gpt_lat\t$gpt_lon\n";
269 } elsif ($opt_o eq "clean") {
270 $pause_len && ($Line = "\n");
271 ($Line .= "$Lon $Lat\n");
272 } elsif ($opt_o eq "ps") {
273 $Line = ($pause_len ? "f\n$Lon $Lat m\n" : "$Lon $Lat l\n");
274 } else {
275 # Default format used by the author. Yes, the Universe evolves around him. ☺ {{{
276 # Seriously, up to "gptrans_conv,v 1.11 2003/08/03 02:35:51 sunny" the script was only
277 # used by myself, and I found this format was the easiest to live with — Perl scripts and
278 # shell utilities made conversion pretty painless. If GPX or something other useful is
279 # implemented, that will be the default.
280 $Lon =~ s/\./$Des/;
281 $Lat =~ s/\./$Des/;
282 # $do_print || print("skipping ");
283 $Line = join("\t",
284 $opt_e ? $ep_time : ($opt_s ? "${Year}${Month}${Day}T${Hour}${Min}${Sec}Z" : "$Year-$Month-$Day $Hour:$Min:$Sec"),
285 $Lon, # X-axis
286 $Lat, # Y-axis
287 $Alt, # Altitude
288 "\n"
290 # }}}
292 # }}}
295 if (!$last_time && $opt_o eq "ps") {
296 print("$Lon $Lat m\n");
299 if ($do_print) {
300 if ($found_move) {
301 (!$pause_len && ($opt_o eq "xgraph")) && ($Line = "move $Line");
302 $found_move = 0;
304 print($Line);
306 $last_time = $ep_time;
307 $last_lon = $Lon;
308 $last_lat = $Lat;
309 $last_alt = $Alt;
310 $last_line = $Line;
311 # }}}
314 sub sec_to_string {
315 # Convert seconds since 1970 to "yyyy-mm-dd hh:mm:ss" with optional separator {{{
316 my ($Seconds, $Sep) = @_;
317 defined($Sep) || ($Sep = " ");
318 my @TA = gmtime($Seconds);
319 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]);
320 return($DateString);
321 # }}}
324 sub sec_to_readable {
325 # Convert seconds since 1970 to human-readable format (d:hh:mm:ss) {{{
326 my $secs = shift;
327 my ($Day, $Hour, $Min, $Sec) =
328 ( 0, 0, 0, 0);
330 $Day = int($secs/86400);
331 $secs -= $Day * 86400;
333 $Hour = int($secs/3600);
334 $secs -= $Hour * 3600;
336 $Min = int($secs/60);
337 $secs -= $Min * 60;
339 $Sec = $secs;
341 return(sprintf("%u:%02u:%02u:%02u", $Day, $Hour, $Min, $Sec));
342 # }}}
345 sub ps_header {
346 # Send a Postscript header to stdout {{{
347 my ($bl_x, $bl_y, $br_x, $br_y) = @_;
348 my $Date = sec_to_string(time);
349 return(<<END);
350 %!PS-Adobe-3.0 EPSF-3.0
351 %%Creator: $rcs_str
352 %%Title:
353 %%CreationDate: $Date
354 %%BoundingBox: $bl_x $bl_y $br_x $br_y
355 %%DocumentData: Clean7Bit
356 %%EndComments
357 %%BeginProlog
358 /bd { bind def } bind def
359 /incompound false def
360 /m { moveto } bd
361 /l { lineto } bd
362 /c { curveto } bd
363 /F { incompound not {fill} if } bd
364 /f { closepath F } bd
365 /S { stroke } bd
366 /*u { /incompound true def } bd
367 /*U { /incompound false def f} bd
368 /k { setcmykcolor } bd
369 /K { k } bd
370 %%EndProlog
371 %%BeginSetup
372 %%EndSetup
374 # }}}
377 sub ddd_to_dms {
378 # Convert floating-point degrees into D°M'S.S" (ISO-8859-1). Necessary for import into GPSman. {{{
379 # Based on toDMS() from gpstrans-0.39 to ensure compatibility.
380 my $ddd = shift;
381 my $Neg = 0;
382 my ($Hour, $Min, $Sec) =
383 ( 0, 0, 0);
384 my $Retval = "";
386 if ($ddd < 0.0) {
387 $ddd = 0 - $ddd;
388 $Neg = 1;
390 $Hour = int($ddd);
391 $ddd = ($ddd - $Hour) * 60.0;
392 $Min = int($ddd);
393 $Sec = ($ddd - $Min) * 60.0;
395 if ($Sec > 59.5) {
396 $Sec = 0.0;
397 $Min += 1.0;
399 if ($Min > 59.5) {
400 $Min = 0.0;
401 $Hour += 1.0;
403 if ($Neg) {
404 $Hour = 0 - $Hour;
406 D("Neg = $Neg , D = $Hour , M = $Min , S = $Sec\n");
407 $Retval = sprintf("%s%.0f\xB0%02.0f'%04.1f\"", $Neg ? "-" : "", $Hour, $Min, $Sec);
408 return $Retval;
409 # }}}
412 sub D {
413 # Send debug messages to stderr if $Debug {{{
414 $Debug && print(STDERR @_);
415 # }}}
418 # vim: set fdm=marker ft=perl fenc=utf-8 :
419 # End of file $Id$