Annotation of igc_tool.pl, Revision 1.1
1.0 philip 1: #! /usr/bin/perl -w
2: use Tk;
3: use Tk::widgets qw/Dialog ErrorDialog ROText/;
4: use Time::Local qw/timegm_nocheck timelocal/;
5: use strict;
6:
7: my $mw = MainWindow->new;
8: $mw->CmdLine;
9: $mw->title("IGC log tool");
10: $mw->configure(-menu => my $menubar = $mw->Menu);
11:
12: my $file = $menubar->cascade(qw/-label File -underline 0 -menuitems/ =>
13: [
1.1 ! philip 14: [command => 'Open IGC', -command => [\&load_igc]],
! 15: [command => 'Open DAT', -command => [\&load_dat]],
1.0 philip 16: [command => 'Exit', -command => [\&exit]],
17: ]);
18:
19: my $igc = $menubar->cascade(qw/-label Log -underline 0 -menuitems/ =>
20: [
1.1 ! philip 21: [command => 'Open IGC', -command => [\&load_igc]],
1.0 philip 22: [command => 'Barograph', -command => [\&baro]],
23: [command => 'Track map', -command => [\&map]],
24: [command => 'Generate Mapfile', -command => [\&generate_tab]],
25: [command => 'Split log', -command => [\&logsplit]],
26: ]);
27:
1.1 ! philip 28: my $turnpoints = $menubar->cascade(qw/-label Turnpoints -underline 0 -menuitems/ =>
! 29: [
! 30: [command => 'Open DAT', -command => [\&load_dat]],
! 31: [command => 'View list', -command => [\&tpdump]],
! 32: [command => 'View task', -command => [\&taskdump]],
! 33: [command => 'Turn/Task', -command => [\&tplist]],
! 34: ]);
! 35:
1.0 philip 36: my $help = $menubar->cascade(qw/-label Help -underline 0 -menuitems/ =>
37: [
38: [command => 'About'],
39: [command => 'Usage'],
40: [command => 'Barograph'],
41: [command => 'Track map'],
42: [command => 'Split log'],
43: ]);
44:
45: my $DIALOG_ABOUT = $mw->Dialog(
46: -title => 'About IGC tool',
47: -bitmap => 'info',
48: -default_button => 'OK',
49: -buttons => ['OK'],
50: -text => "IGC log tool\nWindows version\nPhilip Plane\n" .
51: "6 March 2006\n\nPerl Version $]" .
52: "\nTk Version $Tk::VERSION",
53: );
54:
55: $help->cget(-menu)->entryconfigure('About',
56: -command => [$DIALOG_ABOUT => 'Show'],
57: );
58:
59: my $DIALOG_USAGE = $mw->Dialog(
60: -title => 'Using IGC tool',
61: -bitmap => 'info',
62: -default_button => 'OK',
63: -buttons => ['OK'],
64: -text => "To use the IGC tool, first open an IGC log file " .
65: "from the File menu. The text of the log will " .
66: "be displayed in the main window. " .
67: "When a file has been loaded the actions in the Log " .
68: "menu can be applied to the log.",
69: );
70:
71: $help->cget(-menu)->entryconfigure('Usage',
72: -command => [$DIALOG_USAGE => 'Show'],
73: );
74:
75: my $DIALOG_BARO = $mw->Dialog(
76: -title => 'Barograph',
77: -bitmap => 'info',
78: -default_button => 'OK',
79: -buttons => ['OK'],
80: -text => "The barograph trace shows height in feet, " .
81: "and various information from the log. " ,
82: );
83:
84: $help->cget(-menu)->entryconfigure('Barograph',
85: -command => [$DIALOG_BARO => 'Show'],
86: );
87:
88: my $DIALOG_MAP = $mw->Dialog(
89: -title => 'Track map',
90: -bitmap => 'info',
91: -default_button => 'OK',
92: -buttons => ['OK'],
93: -text => "The track map shows the track from the log file, " .
94: "any turnpoints in the log file, " .
95: "and any task in the log file. " .
96: "Projection is straight xy." .
97: "Turnpoints are shown as 500 meter circles",
98: );
99:
100: $help->cget(-menu)->entryconfigure('Track map',
101: -command => [$DIALOG_MAP => 'Show'],
102: );
103:
104: my $DIALOG_SPLIT = $mw->Dialog(
105: -title => 'Split log',
106: -bitmap => 'info',
107: -default_button => 'OK',
108: -buttons => ['OK'],
109: -text => "Some IGC loggers and their software produce logs " .
110: "that have more than one flight in the log. " .
111: "The log splitter scans through the log and attempts " .
112: "to seperate the flights into individual logs. " .
113: "If the number of logs it finds sounds reasonable, " .
114: "save the new logs to disk. The log files are named " .
115: "using the original file name with the eighth character " .
116: "replaced with a sequence number. ",
117: );
118:
119: $help->cget(-menu)->entryconfigure('Split log',
120: -command => [$DIALOG_SPLIT => 'Show'],
121: );
122:
123: my $text = $mw->Scrolled("ROText")->pack();
124:
125: # Globals from IGC file
126: my $maxalt;
127: my $minalt;
128: my $maxpres;
129: my $minpres;
130: my $minlat;
131: my $maxlat;
132: my $minlon;
133: my $maxlon;
134: my $mday;
135: my $month;
136: my $mon;
137: my $year;
138: my $time;
139: my $glider;
140: my $cid;
141: my $pilot;
142: my $recorder;
143: my $igcfile;
144: my @log;
145: my @tp;
146: my @task;
147: my @track;
148:
1.1 ! philip 149: my $mindiff;
! 150: my $maxdiff;
! 151:
! 152: my $lbtask;
! 153: my $lbturn;
! 154: my @landings;
! 155:
! 156: my $initialdir = "/";
! 157:
1.0 philip 158: sub load_igc {
159: my $types = [
160: ['IGC Files','.igc'],
161: ['IGC Files','.IGC'],
162: ];
163:
1.1 ! philip 164: my $igc = $mw->getOpenFile(-initialdir=>$initialdir,
1.0 philip 165: -filetypes=>$types);
166: if ( defined $igc ){
167: my @igc = split /\//,$igc;
168: $igcfile = pop @igc;
169: open IGC, $igc or die "Can't open $igc : $!\n";
170: my @log = <IGC>;
171: close IGC;
172: $text->delete("1.0",'end');
173: @tp = ();
174: @task = ();
175: @track = ();
1.1 ! philip 176: @landings = ();
1.0 philip 177: $maxalt = 0;
178: $minalt = 99999;
179: $maxpres = 0;
180: $minpres = 99999;
181: $minlat = 90;
182: $maxlat = -90;
183: $minlon = 180;
184: $maxlon = 0;
1.1 ! philip 185: $mindiff = 9999;
! 186: $maxdiff = 0;
1.0 philip 187: my $oh = 0;
188: while ( $_ = shift @log ){
189: s/\r//;
190: SWITCH: {
191: if ( /^HFDTE/ ){
192: my $date = substr($_,5);
193: $mday = substr($date,0,2);
194: $month = substr($date,2,2);
195: $year = substr($date,-2,2);
196: $mon = $month - 1;
197: last SWITCH;
198: }
199: if ( /^H.GID/ ){
200: $glider = substr($_,5);
201: last SWITCH;
202: }
203: if ( /^H.CID/ ){
204: $cid = substr($_,5);
205: last SWITCH;
206: }
207: if ( /^H.PLT/ ){
208: $pilot = substr($_,5);
209: last SWITCH;
210: }
211: if ( /^H.FTY/ ){
212: $recorder = substr($_,5);
213: chop $recorder;
214: last SWITCH;
215: }
216: if ( /^L\D{4}?(\d{5}?)(\d{7}?[NS])(\d{8}?[WE])(\d{6})(.{8}?)(.*)/ ){
217: # [ lat, lon, id, name, type ]
218: # turnpoints
219: my $lat = latitude($2);
220: my $lon = longitude($3);
221: push @tp, [ $lat, $lon, $1, $6, $5 ];
222: last SWITCH;
223: }
224: if ( /^C(\d{7}?[NS])(\d{8}?[WE])(.*)/ ){
225: # [ lat, lon, name ]
226: # task
227: my $lat = latitude($1);
228: my $lon = longitude($2);
229: if ( $lat == 0 ){
230: last SWITCH;
231: }
232: push @task, [ $lat, $lon, $3 ];
233: last SWITCH;
234: }
1.1 ! philip 235: if ( /^B(\d{6})(\d{7}[NS])(\d{8}?[WE])A(\d{5})(\d{5})/ ){
! 236: $time = $1;
1.0 philip 237: my $lat = latitude($2);
238: my $lon = longitude($3);
239: my $alt = $4;
240: my $pres = $5;
1.1 ! philip 241: # keep track of the difference between GPS altitude
! 242: # and pressure altitude
! 243: my $diff = $pres - $alt;
! 244: if ( $diff < 0 ){
! 245: $diff = 0 - $diff;
! 246: }
! 247: if ( $diff > $maxdiff ){
! 248: $maxdiff = $diff;
! 249: }
! 250: if ( $diff < $mindiff ){
! 251: $mindiff = $diff;
! 252: }
1.0 philip 253:
254: # $time is HHMMSS
255: $time =~ /(\d{2})(\d{2})(\d{2})/;
256: my $hour = $1;
257: my $min = $2;
258: my $sec = $3;
259: if ( $hour < $oh ) {
260: $mday++;
261: }
262: $oh = $hour;
263: my $gt = timegm_nocheck($sec,$min,$hour,$mday,$mon,$year);
264:
265: if ( $lat > $maxlat ) {
266: $maxlat = $lat;
267: }
268: if ( $lat < $minlat ) {
269: $minlat = $lat;
270: }
271: if ( $lon > $maxlon ) {
272: $maxlon = $lon;
273: }
274: if ( $lon < $minlon ) {
275: $minlon = $lon;
276: }
277:
278: if ( $alt < $minalt ){
279: $minalt = $alt;
280: }
281: if ( $alt > $maxalt ){
282: $maxalt = $alt;
283: }
284: if ( $pres < $minpres ){
285: $minpres = $pres;
286: }
287: if ( $pres > $maxpres ){
288: $maxpres = $pres;
289: }
1.1 ! philip 290:
1.0 philip 291: push @track, [ $gt, $lat, $lon, $alt, $pres ];
292: last SWITCH;
293: }
294: }
295: $text->insert('end',$_);
296: }
297: }
298: }
299:
300: sub baro {
301: my $maxrec = scalar @track;
302: if ( $maxrec > 0 ) {
303: my $bwin = $mw->Toplevel();
304: $bwin->title($igcfile . " Barograph");
305: my $bg = $bwin->Scrolled('Canvas', -width => 850, -height => 500, -scrollregion => [-10,-10,1000,1000])->pack();
306: my $id;
307: my $date = sprintf("%02d/%02d/20%02d",$mday,$month,$year);
308: if ( not defined $glider ) {
309: $glider = $cid;
310: }
311: #clean up pilot name, remove extra whitespace
312: if ( defined $pilot ){
313: chop $pilot;
314: while ( $pilot =~ m/ / ){
315: $pilot =~ s/ / /;
316: }
317: }
318: if ( defined $glider ){
319: chop $glider;
320: }
321: my $gps = sprintf("GPS Low point: %5d ft High point: %5d ft",
322: feet($minalt),feet($maxalt));
323: my $pres = sprintf("Alt Low point: %5d ft High point: %5d ft",
324: feet($minpres),feet($maxpres));
325:
326: my @t = localtime($track[0][0]);
327: my $start = sprintf("Log started at %02d:%02d:%02d",$t[2],$t[1],$t[0]);
328: my @f = localtime($track[$maxrec - 1][0]);
329: my $finish = sprintf("Log ended at %02d:%02d:%02d",$f[2],$f[1],$f[0]);
330: my $duration = sprintf("Log duration %s",
331: sec2time($track[$maxrec - 1][0] - $track[0][0]));
1.1 ! philip 332: my $diff = sprintf("GPS/Pressure difference: max %4d ft / min %4d ft",
! 333: feet($maxdiff),feet($mindiff));
1.0 philip 334:
335: $id = $bg->createText(10,10, -text => $pilot, -anchor => "w");
336: $id = $bg->createText(410,10, -text => $recorder, -anchor => "w");
337: $id = $bg->createText(10,25, -text => $glider, -anchor => "w");
338: $id = $bg->createText(10,40, -text => $pres,-fill => "red", -anchor => "w");
339: $id = $bg->createText(10,55, -text => $gps, -fill => "blue", -anchor => "w");
340: $id = $bg->createText(10,70, -text => $date, -anchor => "w");
1.1 ! philip 341: $id = $bg->createText(410,70, -text => $diff, -anchor => "w");
! 342: $id = $bg->createText(10,85, -text => $start, -anchor => "w");
1.0 philip 343: $id = $bg->createText(10,100, -text => $finish, -anchor => "w");
344: $id = $bg->createText(10,115, -text => $duration, -anchor => "w");
345:
346: my $width = 800;
347: my $height = 450;
348:
349: my $hscale = ($track[$maxrec-1][0] - $track[0][0])/($width - 50);
350: my $vscale = 25;
351: if ($maxalt < 2000){
352: $vscale = 10;
353: }
354: elsif ($maxalt < 4000){
355: $vscale = 15;
356: }
357:
358: my $m = $maxalt / 305;
359:
360: # Draw lines at 1000ft (305m)
361: for(my $mil = 0;$mil < $m;$mil++){
362: my $ml = 400 - (($mil * 305)/$vscale);
363: $id = $bg->createLine(40,$ml,$width ,$ml, -dash => [6,4]);
364: $id = $bg->createText(35,$ml, -text => sprintf("%5d", 1000 * $mil), -anchor => "e");
365: }
366:
367: my $or = 400 - ( $track[0][4] / $vscale);
368: my $ob = 400 - ( $track[0][3] / $vscale);
369: my $ox = 30;
370: # munch through the track array [ $gt, $lat, $lon, $alt, $pres ]
371: my $osec = $track[0][0];
372: my $olat = $track[0][1];
373: my $olon = $track[0][2];
374: my $oalt = $track[0][3];
375: my $opres = $track[0][4];
376: my $launch = 0;
1.1 ! philip 377: my $land = 0;
1.0 philip 378: for (my $i = 0; $i < $maxrec; $i++) {
379: my $t_sec = $track[$i][0];
380: $t_sec = $t_sec - $track[0][0];
381: my $x = 50 + int($t_sec / $hscale);
382: my $pres = $track[$i][4];
383: my $alt = $track[$i][3];
1.1 ! philip 384: # figure out the takeoff/landing
1.0 philip 385: my $dlat = abs($track[$i][1] - $olat);
386: my $dlng = abs($track[$i][2] - $olon);
387: my $dist = sqrt(($dlat*$dlat) + ($dlng*$dlng));
388: my $speed = 0;
389: my $dsec = $t_sec - $osec;
390: $osec = $t_sec;
391: if ( ($dsec > 0) and ($dist > 0)){
392: $speed = $dist / $dsec;
393: }
394: if ( ($speed > 0.000100) and ($oalt < $alt)){
395: $launch++;
1.1 ! philip 396: $land = 0;
1.0 philip 397: }
398: if ( $launch == 3 ) {
399: $id = $bg->createLine($x,400,$x,150, -fill => "black");
400: $id = $bg->createText($x,140, -text => "takeoff");
401: $launch++;
402: }
1.1 ! philip 403: if ( ($speed < 0.0000001) and ($oalt == $alt) and ($launch > 0)){
! 404: $land++;
! 405: }
! 406: if ( $land == 3 ){
! 407: $land = 0;
1.0 philip 408: $launch = 0;
409: $id = $bg->createLine($x,400,$x,150,-fill => "black");
410: $id = $bg->createText($x,140, -text => "land");
1.1 ! philip 411: push @landings,$track[$i][0];
1.0 philip 412: }
1.1 ! philip 413:
1.0 philip 414: my $y = 400 - ( $pres/$vscale);
415: $id = $bg->createLine($x,$y,$ox,$or, -fill => "red");
416: $or = $y;
417: $y = 400 - ($alt/$vscale);
418: $id = $bg->createLine($x,$y,$ox,$ob, -fill => "blue");
419: $ob = $y;
420: $ox = $x;
421: $olat = $track[$i][1];
422: $olon = $track[$i][2];
423: $opres = $pres;
424: $oalt = $alt;
425: }
426: # add the timeticks
427: my @start = localtime($track[0][0]);
428: my @finish = localtime($track[$maxrec-1][0]);
429: for ( my $h = $start[2]+1;
430: $h <= $finish[2];
431: $h++ ){
432: @t = @start;
433: $t[2] = $h;
434: $t[0] = 0;
435: $t[1] = 0;
436: my $t = timelocal(@t);
437: my $x = 50 + int(($t - $track[0][0]) / $hscale);
438: $id = $bg->createText($x,410, -text => sprintf("%02d:00",$h));
439: $id = $bg->createLine($x,400,$x,350, -dash => [3,2],
440: -fill => "black");
441: }
442: }
443: }
444:
445: sub map {
446: my $maxrec = scalar @track;
447: if ( $maxrec > 0 ) {
448: my $zone;
449: my $ox;
450: my $oy;
451:
452: #use max vertical to set scale as most tracks are taller than wider.
453: my $scale = $maxlat - $minlat;
454:
455: my $bwin = $mw->Toplevel();
456: $bwin->title($igcfile . " Flight Track");
457: my $bg = $bwin->Scrolled('Canvas', -width => 850, -height => 600, -scrollregion => [-500,-500,1500,1500])->pack();
458:
459: my $width = 1000;
460: my $height = 1000;
461:
462: $scale = $height / $scale;
463:
464:
465: # 500 meter radius circle
466: my $r = .004 * $scale;
467:
468: #show the turnpoints
469: my $maxtp = scalar @tp;
470: for (my $t = 0; $t < $maxtp; $t++) {
471: my $y = $height - (($tp[$t][0] - $minlat) * $scale);
472: my $x = ($tp[$t][1] - $minlon) * $scale;
473: my $id = $bg->createText($x, $y + 10 + $r, -text => $tp[$t][3]);
474: $id = $bg->createOval($x - $r, $y - $r, $x + $r, $y + $r);
475: }
476: #show the task
477: my $maxtask = scalar @task;
478: if ( $maxtask > 0 ){
479: $oy = $height - (($task[0][0] - $minlat) * $scale);
480: $ox = ($task[0][1] - $minlon) * $scale;
481: }
482: for (my $t = 0; $t < $maxtask; $t++) {
483: my $y = $height - (($task[$t][0] - $minlat) * $scale);
484: my $x = ($task[$t][1] - $minlon) * $scale;
485: my $id = $bg->createText($x, $y + 10 + $r, -text => $task[$t][2]);
486: $id = $bg->createOval($x - $r, $y - $r, $x + $r, $y + $r, -outline => "green");
487: $id = $bg->createLine($x,$y,$ox,$oy, -dash => [6,4], -fill => "green");
488: $ox = $x;
489: $oy = $y;
490: }
491:
492: #prime the pump
493: $oy = $height - (($track[0][1] - $minlat) * $scale);
494: $ox = ($track[0][2] - $minlon) * $scale;
495:
496: #show the track
497: for (my $i = 0; $i < $maxrec; $i++) {
498: my $y = $height - (($track[$i][1] - $minlat) * $scale);
499: my $x = ($track[$i][2] - $minlon) * $scale;
500: my $id = $bg->createLine($ox,$oy,$x,$y, -fill => "blue");
501: $ox = $x;
502: $oy = $y;
503: }
504: }
505: }
506:
507: sub generate_tab {
508: my $header = "sTrackDescr\tiTrkID\tiColor\tsTimestamp\tfLat\tfLong\tfAlt\tfEasting\tfNorthing\n";
509: #IGClog 123 3:21 44.500000 170.200000 123.0
1.1 ! philip 510: my $tab = $mw->getSaveFile(-initialdir=>$initialdir,
1.0 philip 511: -initialfile=>'tracklog.txt');
512: if ( defined $tab ){
513: open TXT, "> " . $tab or die "Couldn't open file $tab: $!\n";
514: print TXT $header;
515: my $maxrec = scalar @track;
516: for (my $i = 0; $i < $maxrec; $i++) {
517: my @now = localtime($track[$i][0]);
518: print TXT "IGCLog\t001\t\t";
519: printf TXT ("%02d:%02d:%02d\t",$now[2], $now[1], $now[0]);
520: printf TXT ("%6f\t%6f\n",$track[$i][1], $track[$i][2]);
521: }
522: close TXT;
523: }
524: }
1.1 ! philip 525:
1.0 philip 526: sub logsplit {
527: my $maxrec = scalar @log;
528: my $osec = 0;
529: my $igccore;
530: my $igccount = 0;
531: my @logs =();
532:
533: for (my $i = 0; $i < $maxrec; $i++) {
534: if ( $log[$i] =~ /^B(\d{6})(\d{7}[NS])(\d{8}?[WE]).{1}(\d{5})(\d{5})/ ){
535: my $alt = $4;
536: my $time = $1;
537: $time =~ /(\d{2})(\d{2})(\d{2})/;
538: my $sec = ($1 *3600) + ($2 * 60) + $3;
539: # if the current second is less than the previous, time
540: # has gone backwards. This indicates you've crossed the
541: # boundry of a new day.
542: if ( $sec < $osec ) {
543: $osec -= 86400;
544: }
545: # if the gap in the log is more than sixty seconds assume that
546: # it's a new flight
547: if (( $sec - $osec ) > 60){
548: $logs[$igccount++] = $igccore;
549: $igccore = "";
550: }
551: $osec = $sec;
552: }
553: $igccore .= $log[$i];
554: }
555: $logs[$igccount] = $igccore;
556: my $split = $mw->Dialog(
557: -title => 'Split IGC log file',
558: -bitmap => 'question',
559: -default_button => 'OK',
560: -buttons => ['OK','Cancel'],
561: -text => "Found $igccount logs.\nWant to create seperate log files for them?\n",
562: )->Show();
563: if ($split eq 'OK'){
564: for (my $i = 1; $i <= $igccount; $i++) {
565: substr($igcfile,7,1) = $i;
1.1 ! philip 566: my $frag = $mw->getSaveFile(-initialdir=>$initialdir,
1.0 philip 567: -initialfile=>$igcfile);
568: if ( defined $frag ){
569: open TEMP, ">" . $frag or die "Couldn't open $frag: $!\n";
570: print TEMP $logs[0], $logs[$i];
571: close TEMP;
572: }
573: }
574: }
575: }
576:
1.1 ! philip 577:
! 578: sub load_dat {
! 579: # @tp
! 580: # [ lat, lon, id, name, type ]
! 581: # Cambridge turnpoints file
! 582: #1,44:29.080S,169:58.660E,1380F,TAH,01-Omarama ,*EastEnd Rwa
! 583: my $types = [
! 584: ['DAT Files','.dat'],
! 585: ['DAT Files','.DAT'],
! 586: ];
! 587:
! 588: my $dat = $mw->getOpenFile(-initialdir=>$initialdir,
! 589: -filetypes=>$types);
! 590: if ( defined $dat ){
! 591: my $count = 0;
! 592: @tp = ();
! 593: my @dat = split /\//,$dat;
! 594: my $datfile = pop @dat;
! 595: open DAT, $dat or die "Can't open $dat : $!\n";
! 596: my @log = <DAT>;
! 597: close DAT;
! 598: while ( $_ = shift @log ){
! 599: if ( $_ =~ /^\d/ ){
! 600: @dat = split(/\,/,$_);
! 601: if ( $dat[4] =~ /T|S|F/ ){
! 602: if ( $dat[5] eq "" ) {
! 603: $dat[5] = $dat[0];
! 604: }
! 605: $tp[$count][0] = datlat($dat[1]);
! 606: $tp[$count][1] = datlng($dat[2]);
! 607: $tp[$count][2] = $dat[0];
! 608: $tp[$count][3] = $dat[5];
! 609: $tp[$count][4] = $dat[4];
! 610: $count++;
! 611: }
! 612: }
! 613: }
! 614: }
! 615: }
! 616:
! 617: sub datlat{
! 618: #44:29.080S
! 619: my $lat = shift @_;
! 620: $lat =~ /(\d{2})\:(\d{2}\.\d{3})([SN])/;
! 621: my $degrees = $1;
! 622: my $min = $2;
! 623: my $hemi = $3;
! 624: $min = $min * 0.0166666667;
! 625: $degrees = $degrees + $min;
! 626: if ( $hemi eq 'S' ){
! 627: $degrees = 0 - $degrees;
! 628: }
! 629: return $degrees;
! 630: }
! 631:
! 632: sub datlng{
! 633: #169:58.660E
! 634: my $lng = shift @_;
! 635: $lng =~ /(\d{3})\:(\d{2}\.\d{3})([WE])/;
! 636: my $degrees = $1;
! 637: my $min = $2;
! 638: my $hemi = $3;
! 639: $min = $min * 0.0166666667;
! 640: $degrees = $degrees + $min;
! 641: if ( $hemi eq 'W' ){
! 642: $degrees = 0 - $degrees;
! 643: }
! 644: return $degrees;
! 645: }
! 646:
! 647: sub tpdump {
! 648: #show the turnpoints
! 649: my $maxtp = scalar @tp;
! 650: $text->delete("1.0",'end');
! 651: for (my $t = 0; $t < $maxtp; $t++) {
! 652: my $tmp = sprintf("%6.2f %6.2f %s\n",$tp[$t][0], $tp[$t][1], $tp[$t][3]);
! 653: $text->insert('end',$tmp);
! 654: }
! 655: }
! 656:
! 657: sub taskdump {
! 658: #show task
! 659: my $maxrec = scalar @task;
! 660: $text->delete("1.0".'end');
! 661: for (my $t = 0; $t < $maxrec; $t++) {
! 662: my $tmp = sprintf("%6.2f %6.2f %s\n",$task[$t][0], $task[$t][1], $task[$t][2]);
! 663: $text->insert('end',$tmp);
! 664: }
! 665: }
! 666:
! 667: sub tplist {
! 668: my $maxrec = scalar @tp;
! 669: if ( $maxrec > 0 ) {
! 670: my $bwin = $mw->Toplevel();
! 671: $bwin->title("Turnpoints");
! 672: $bwin->minsize(175,50);
! 673: $bwin->Label(-text=>"Turnpoints")->grid( "x", $bwin->Label(-text=>"Task"));
! 674:
! 675: $lbturn = $bwin->Scrolled("Listbox",
! 676: -scrollbars => "e",
! 677: -selectmode => "single")->grid(-row=> 0,
! 678: -column=> 0,
! 679: -rowspan=> 2,
! 680: -sticky=> "nsew");
! 681:
! 682: $bwin->Button(-text=>"Add ->",
! 683: -command=> \&add_to_task
! 684: )->grid(-row=> 0,
! 685: -column=> 1,
! 686: -sticky=> "sew");
! 687:
! 688: $lbtask = $bwin->Scrolled("Listbox",
! 689: -scrollbars => "e",
! 690: -selectmode => "single")->grid(-row=> 0,
! 691: -column=> 2,
! 692: -rowspan=> 2,
! 693: -sticky=> "nsew");
! 694:
! 695: $bwin->Button(-text=>"Del <-",
! 696: -command=> \&del_from_task
! 697: )->grid(-row=> 1,
! 698: -column=> 1,
! 699: -sticky=> "new");
! 700: #populate the turnpoint list
! 701: $lbturn->delete("1.0",'end');
! 702: for (my $t = 0; $t < $maxrec; $t++) {
! 703: $lbturn->insert('end',$tp[$t][3]);
! 704: }
! 705: # populate the task
! 706: $maxrec = scalar @task;
! 707: $lbtask->delete("1.0",'end');
! 708: for (my $t = 0; $t < $maxrec; $t++) {
! 709: $lbtask->insert('end',$task[$t][2]);
! 710: }
! 711:
! 712: }
! 713: }
! 714:
! 715: sub add_to_task {
! 716: my @selection = $lbturn->curselection();
! 717: foreach ( @selection ){
! 718: my $turnpoint = $lbturn->get($_);
! 719: $lbtask->insert('end',$turnpoint);
! 720: }
! 721: }
! 722:
! 723: sub del_from_task {
! 724: my @selection = $lbtask->curselection();
! 725: foreach ( @selection ){
! 726: $lbtask->delete($_);
! 727: }
! 728: }
1.0 philip 729:
730: sub feet{
731: my $meters = shift @_;
732: my $feet = $meters * 3.2808399;
733: return int($feet);
734: }
735:
736: sub duration{
737: # expects 2 parameters, start time and finish time
738: my $start = shift @_;
739: my $end = shift @_;
740: my $ss = seconds($start);
741: my $se = seconds($end);
742: # if we finished before we started, we crossed the day boundry
743: if ( $se < $ss ) {
744: $se += 60 * 60 * 24;
745: }
746: return $se - $ss;
747: }
748:
749: sub seconds{
750: my $time = shift @_;
751: my $hours = substr($time,0,2);
752: my $minutes = substr($time,2,2);
753: my $seconds = substr($time,4,2);
754: return $seconds + ($minutes * 60) + ($hours * 60 * 60);
755: }
756:
757: sub sec2time{
758: my $sec = shift @_;
759: my $hours = int($sec / 3600);
760: $sec = $sec % 3600;
761: my $minutes = int($sec / 60);
762: $sec = $sec % 60;
763: return sprintf("%02d:%02d:%02d",$hours,$minutes,$sec);
764: }
765:
766: sub latitude{
767: my $lat = shift @_;
768: my $degrees = substr($lat,0,2);
769: my $min = '0.' . substr($lat,2,5);
770: $min = $min * 1.66666667;
771: $degrees = $degrees + $min;
772: my $hemi = substr($lat,-1);
773: if ( $hemi eq 'S' ){
774: $degrees = 0 - $degrees;
775: }
776: return $degrees;
777: }
778:
779: sub longitude{
780: my $lon = shift @_;
781: my $degrees = substr($lon,0,3);
782: my $min = '0.' . substr($lon,3,5);
783: $min = $min * 1.66666667;
784: $degrees = $degrees + $min;
785: my $hemi = substr($lon,-1);
786: if ( $hemi eq 'W' ){
787: $degrees = 0 - $degrees;
788: }
789: return $degrees;
790: }
791:
792: MainLoop;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>