3 ########################################################################
4 # Convert DAFIFT ARPT/ILS.TXT to FlightGear format.
5 ########################################################################
9 my($faa_ils_file) = shift(@ARGV);
10 my($dafift_arpt_file) = shift(@ARGV);
11 my($dafift_ils_file) = shift(@ARGV);
12 my($fgfs_ils_file) = shift(@ARGV);
13 my($fgfs_apt_file) = shift(@ARGV);
14 my($output_file) = shift(@ARGV);
17 = "/home/curt/projects/FlightGear-0.9/source/src/Airports/calc_loc";
20 "<faa_ils_file> <dafift_arpt_file> <dafift_ils_file> <xplane_ils_file> <fgfs_apt_file> <output_file>\n"
21 if !defined($faa_ils_file) || !defined($dafift_arpt_file)
22 || !defined($dafift_ils_file) || !defined($fgfs_ils_file)
23 || !defined($fgfs_apt_file) || !defined($output_file);
33 &load_dafift( $dafift_arpt_file, $dafift_ils_file );
34 &load_faa( $faa_ils_file );
35 &load_fgfs( $fgfs_ils_file );
36 &load_fgfs_airports( $fgfs_apt_file );
38 &fudge_missing_gs_elev();
40 &write_result( $output_file );
45 ########################################################################
47 ########################################################################
50 my( $arpt_file ) = shift;
51 my( $ils_file ) = shift;
55 my( $id, $rwy, $type );
56 my( $has_dme, $has_gs, $has_loc, $has_im, $has_mm, $has_om );
57 my( $dme_lon, $dme_lat, $dme_elev, $dme_bias );
58 my( $gs_lon, $gs_lat, $gs_elev, $gs_angle );
59 my( $loc_type, $loc_lon, $loc_lat, $loc_elev, $loc_freq, $loc_hdg,
60 $loc_width, $loc_id );
61 my( $im_lon, $im_lat, $mm_lon, $mm_lat, $om_lon, $om_lat );
63 # load airport file so we can lookup ICAO from internal ID
65 open( ARPT, "<$arpt_file" ) || die "Cannot open DAFIFT: $arpt_file\n";
67 <ARPT>; # skip header line
73 if ( length($icao) < 3 ) {
74 if ( length( $F[4] ) >= 3 ) {
80 $CODES{$F[0]} = $icao;
81 $CodesByICAO{$icao} = 1;
82 # print "$F[0] - $icao\n";
83 $Elevations{$icao} = $F[11];
84 print "$icao $F[11]\n";
87 # Load the DAFIFT ils file
89 my( $last_id, $last_rwy ) = ("", "");
91 open( DAFIFT_ILS, "<$ils_file" ) || die "Cannot open DAFIFT: $ils_file\n";
93 <DAFIFT_ILS>; # skip header line
95 while ( <DAFIFT_ILS> ) {
101 if ( $last_id ne "" && ($last_id ne $id || $last_rwy ne $rwy) ) {
102 # just hist the start of the next record, dump the current data
105 ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
108 ( $dme_lat, $dme_lon ) = ( 0, 0 );
111 ( $om_lat, $om_lon ) = ( 0, 0 );
114 ( $mm_lat, $mm_lon ) = ( 0, 0 );
117 ( $im_lat, $im_lon ) = ( 0, 0 );
119 if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
120 print "DAFIFT adding: $CODES{$last_id} - $last_rwy\n";
121 &safe_add_record( $CODES{$last_id}, $last_rwy, "ILS",
122 $loc_freq, $loc_id, $loc_hdg, $loc_lat,
123 $loc_lon, $gs_elev, $gs_angle, $gs_lat,
124 $gs_lon, $dme_lat, $dme_lon, $om_lat,
125 $om_lon, $mm_lat, $mm_lon, $im_lat,
138 if ( $type eq "D" ) {
141 $dme_lon = make_dcoord( $F[16] );
142 $dme_lat = make_dcoord( $F[14] );
144 if ( $dme_elev !~ m/\d/ ) {
150 # print "$id DME $dme_lon $dme_lat $dme_elev $dme_bias\n";
151 } elsif ( $type eq "G" ) {
154 $gs_lon = make_dcoord( $F[16] );
155 $gs_lat = make_dcoord( $F[14] );
157 if ( $gs_elev !~ m/\d/ ) {
163 # print "$id GS $gs_lon $gs_lat $gs_elev $gs_angle\n";
164 } elsif ( $type eq "Z" ) {
167 $loc_lon = make_dcoord( $F[16] );
168 $loc_lat = make_dcoord( $F[14] );
170 if ( $loc_elev !~ m/\d/ ) {
175 ($loc_freq) = $F[5] =~ m/(\d\d\d\d\d\d)/;
177 my( $magvar ) = make_dmagvar( $F[22] );
178 # print "mag var = $F[22] (" . $magvar . ")\n";
179 $loc_hdg = $F[24] + make_dmagvar( $F[22] );
182 if ( length( $loc_id ) >= 4 ) {
185 # print "$id LOC $loc_lon $loc_lat $loc_elev $loc_freq $loc_hdg $loc_width\n";
186 } elsif ( $type eq "I" ) {
189 $im_lon = make_dcoord( $F[16] );
190 $im_lat = make_dcoord( $F[14] );
191 # print "$id IM $im_lon $im_lat\n";
192 } elsif ( $type eq "M" ) {
193 # Middle marker entry
195 $mm_lon = make_dcoord( $F[16] );
196 $mm_lat = make_dcoord( $F[14] );
197 # print "$id MM $mm_lon $mm_lat\n";
198 } elsif ( $type eq "O" ) {
201 $om_lon = make_dcoord( $F[16] );
202 $om_lat = make_dcoord( $F[14] );
203 # print "$id OM $om_lon $om_lat\n";
208 # printf("%-5s %10.6f %11.6f\n", $F[0], $F[14], $F[16]);
212 ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
215 ( $dme_lat, $dme_lon ) = ( 0, 0 );
218 ( $om_lat, $om_lon ) = ( 0, 0 );
221 ( $mm_lat, $mm_lon ) = ( 0, 0 );
224 ( $im_lat, $im_lon ) = ( 0, 0 );
226 if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
227 print "DAFIFT adding (last): $CODES{$last_id} - $last_rwy\n";
228 &safe_add_record( $CODES{$last_id}, $last_rwy, "ILS", $loc_freq,
229 $loc_id, $loc_hdg, $loc_lat, $loc_lon,
230 $gs_elev, $gs_angle, $gs_lat, $gs_lon,
231 $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat,
232 $mm_lon, $im_lat, $im_lon );
237 ########################################################################
239 ########################################################################
244 open( FAA_ILS, "<$file" ) || die "Cannot open FAA data: $file\n";
246 <FAA_ILS>; # skip header line
248 while ( <FAA_ILS> ) {
251 my ( $rec_type, $faa_id, $rwy, $type, $faa_date,
252 $faa_apt_name, $faa_city, $faa_st, $faa_state,
253 $faa_region, $id, $faa_len, $faa_wid, $faa_cat,
254 $faa_owner, $faa_operator, $faa_bearing, $faa_magvar,
255 $loc_type, $loc_id, $loc_freq, $faa_loc_latd,
256 $faa_loc_lats, $faa_loc_lond, $faa_loc_lons, $loc_width,
257 $faa_stop_dist, $faa_app_dist, $faa_gs_type, $gs_angle,
258 $faa_gs_freq, $faa_gs_latd, $faa_gs_lats, $faa_gs_lond,
259 $faa_gs_lons, $faa_gs_dist, $gs_elev, $faa_im_type,
260 $faa_im_latd, $faa_im_lats, $faa_im_lond, $faa_im_lons,
261 $faa_im_dist, $faa_mm_type, $faa_mm_id, $faa_mm_name,
262 $faa_mm_freq, $faa_mm_latd, $faa_mm_lats, $faa_mm_lond,
263 $faa_mm_lons, $faa_mm_dist, $faa_om_type, $faa_om_id,
264 $faa_om_name, $faa_om_freq, $faa_om_latd, $faa_om_lats,
265 $faa_om_lond, $faa_om_lons, $faa_om_dist,
266 $faa_om_backcourse, $faa_dme_channel, $faa_dme_latd,
267 $faa_dme_lats, $faa_dme_lond, $faa_dme_lons, $faa_dme_app_dist,
268 $faa_dme_stop_dist, $blank)
270 m/^(.{4})(.{11})(.{3})(.{10})(.{10})(.{42})(.{26})(.{2})(.{20})(.{3})(.{4})(.{5})(.{4})(.{9})(.{50})(.{50})(.{3})(.{3})(.{15})(.{5})(.{6})(.{14})(.{11})(.{14})(.{11})(.{5})(.{5})(.{6})(.{15})(.{4})(.{6})(.{14})(.{11})(.{14})(.{11})(.{6})(.{7})(.{15})(.{14})(.{11})(.{14})(.{11})(.{6})(.{15})(.{2})(.{5})(.{3})(.{14})(.{11})(.{14})(.{11})(.{6})(.{15})(.{2})(.{5})(.{3})(.{14})(.{11})(.{14})(.{11})(.{6})(.{9})(.{4})(.{14})(.{11})(.{14})(.{11})(.{6})(.{5})(.{34})/;
272 $id = &strip_ws( $id );
273 $rwy = &strip_ws( $rwy );
277 my( $loc_hdg ) = $faa_bearing + make_dmagvar($faa_magvar);
278 my( $loc_lat ) = make_dcoord($faa_loc_lats) / 3600.0;
279 my( $loc_lon ) = make_dcoord($faa_loc_lons) / 3600.0;
280 # print "$loc_lon $loc_lat $faa_loc_lons $faa_loc_lats\n";
281 my( $gs_lat ) = make_dcoord($faa_gs_lats) / 3600.0;
282 my( $gs_lon ) = make_dcoord($faa_gs_lons) / 3600.0;
283 my( $im_lat ) = make_dcoord($faa_im_lats) / 3600.0;
284 my( $im_lon ) = make_dcoord($faa_im_lons) / 3600.0;
285 my( $mm_lat ) = make_dcoord($faa_mm_lats) / 3600.0;
286 my( $mm_lon ) = make_dcoord($faa_mm_lons) / 3600.0;
287 my( $om_lat ) = make_dcoord($faa_om_lats) / 3600.0;
288 my( $om_lon ) = make_dcoord($faa_om_lons) / 3600.0;
289 my( $dme_lat ) = make_dcoord($faa_dme_lats) / 3600.0;
290 my( $dme_lon ) = make_dcoord($faa_dme_lons) / 3600.0;
293 # print "$id - $rwy\n";
295 # print "-> $key -> $ILS{$key}\n";
296 # $key = "K" . $id . $rwy;
297 # print "-> $key -> $ILS{$key}\n";
299 if ( $rec_type eq "ILS1" ) {
300 if ( length( $id ) < 4 ) {
301 if ( $CodesByICAO{"K" . $id} ) {
305 if ( $ILS{$id . $rwy} ne "" ) {
306 print "FAA updating: $id - $rwy $type\n";
307 &update_type( $id, $rwy, $type );
308 if ( $gs_elev > 0 ) {
309 &maybe_update_gs_elev( $id . $rwy, $gs_elev );
312 print "FAA adding: $id - $rwy\n";
313 &safe_add_record( $id, $rwy, $type, $loc_freq, $loc_id,
314 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
315 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
316 $dme_lon, $om_lat, $om_lon, $mm_lat,
317 $mm_lon, $im_lat, $im_lon );
324 ########################################################################
325 # Process FlightGear ILS data
326 ########################################################################
329 my( $ils_file ) = shift;
331 open( FGILS, "zcat $ils_file|" ) || die "Cannot open FGFS: $ils_file\n";
333 <FGILS>; # skip header line
337 if ( ! m/\[End\]/ && length($_) > 1 ) {
339 my( $type_code, $type_name, $icao, $rwy, $loc_freq, $loc_id,
340 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
341 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
342 $im_lat, $im_lon ) = split(/\s+/);
345 if ( $ILS{$icao . $rwy} ne "" ) {
346 print "FGFS: Skipping $icao - $rwy - already exists\n";
347 # skip approaches already in FAA or DAFIFT data
348 } elsif ( length( $icao ) < 4 || $icao =~ m/^K/ ) {
349 print "FGFS: Skipping $icao - $rwy - USA\n";
350 # skip USA approaches not found in FAA or DAFIFT data
352 print "FGFS adding: $icao $rwy\n";
353 &safe_add_record( $icao, $rwy, $type_name, $loc_freq, $loc_id,
354 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
355 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
356 $dme_lon, $om_lat, $om_lon, $mm_lat,
357 $mm_lon, $im_lat, $im_lon );
360 print "FGFS discarding: $_\n";
366 ########################################################################
367 # Load the x-plane/flightgear airport/runway information
368 ########################################################################
370 sub load_fgfs_airports() {
371 my( $infile ) = shift;
375 open( IN, "zcat $infile|" ) || die "Cannot open: $infile\n";
377 <IN>; # skip header line
381 my(@F) = split(/\s+/);
382 if ( $F[0] eq "A" ) {
384 } elsif ( $F[0] eq "R" ) {
385 my($recip) = &rwy_recip( $F[1] );
386 $RUNWAYS{ $id . $F[1] } = "FOR $_";
387 $RUNWAYS{ $id . $recip } = "REV $_";
393 ########################################################################
394 # Run through the final ils list and adjust the heading to match the runway
395 ########################################################################
397 sub fix_localizer() {
399 foreach $key ( sort (keys %ILS) ) {
400 my(@F) = split( /\s+/, $ILS{$key} );
401 print "FIXING: $key $F[2] $F[3] $F[4]\n";
402 if ( $RUNWAYS{$key} ) {
403 my(@G) = split( /\s+/, $RUNWAYS{$key} );
404 print " LocPos = $F[7] $F[8]\n";
405 print " RwyInfo = $G[0] $G[3] $G[4] $G[5] $G[6] $G[7]\n";
407 = "$calc_loc $F[7] $F[8] $G[0] $G[3] $G[4] $G[5] $G[6] $G[7]";
408 open( CALC, "$cmd |" ) || die "Cannot open $calc_loc\n";
409 my( $j, $lat, $lon );
411 if ( m/New localizer/ ) {
412 ($j, $j, $j, $lat, $lon) = split( /\s+/ );
415 if ( $G[0] eq "REV" ) {
417 if ( $G[5] >= 360.0 ) {
421 &update_loc( $F[2], $F[3], $lat, $lon, $G[5]);
427 ########################################################################
428 # Run through the final ils list and adjust the heading to match the runway
429 ########################################################################
431 sub fudge_missing_gs_elev() {
433 foreach $key ( sort (keys %ILS) ) {
434 my(@F) = split( /\s+/, $ILS{$key} );
436 print "FUDGING GS: $key $F[2] $F[3] $F[4] - $F[9]\n";
437 &maybe_update_gs_elev( $key, $Elevations{$F[2]});
443 ########################################################################
444 # Write out the accumulated combined result
445 ########################################################################
448 my( $outfile ) = shift;
450 open( OUT, ">$outfile" ) || die "Cannot write to: $outfile\n";
452 # dump out the final results
453 print OUT "// FlightGear ILS data, generated from DAFIFT ARPT/ILS.TXT and FAA data\n";
456 foreach $key ( sort (keys %ILS) ) {
457 print OUT "$ILS{$key}\n";
463 ########################################################################
465 ########################################################################
468 # add a record to the master list if it doesn't already exist
470 sub safe_add_record() {
471 my( $apt_id ) = shift;
474 my( $loc_freq ) = shift;
475 my( $loc_id ) = shift;
476 my( $loc_hdg ) = shift;
477 my( $loc_lat ) = shift;
478 my( $loc_lon ) = shift;
479 my( $gs_elev ) = shift;
480 my( $gs_angle ) = shift;
481 my( $gs_lat ) = shift;
482 my( $gs_lon ) = shift;
483 my( $dme_lat ) = shift;
484 my( $dme_lon ) = shift;
485 my( $om_lat ) = shift;
486 my( $om_lon ) = shift;
487 my( $mm_lat ) = shift;
488 my( $mm_lon ) = shift;
489 my( $im_lat ) = shift;
490 my( $im_lon ) = shift;
492 if ( $ILS{$apt_id . $rwy} eq "" ) {
493 # print "Safe adding (common): $apt_id - $rwy\n";
494 &update_record( $apt_id, $rwy, $type, $loc_freq, $loc_id,
495 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
496 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
497 $dme_lon, $om_lat, $om_lon, $mm_lat,
498 $mm_lon, $im_lat, $im_lon );
503 # replace a record in the master list (or add it if it doesn't exist)
505 sub update_record() {
506 my( $apt_id ) = shift;
509 my( $loc_freq ) = shift;
510 my( $loc_id ) = shift;
511 my( $loc_hdg ) = shift;
512 my( $loc_lat ) = shift;
513 my( $loc_lon ) = shift;
514 my( $gs_elev ) = shift;
515 my( $gs_angle ) = shift;
516 my( $gs_lat ) = shift;
517 my( $gs_lon ) = shift;
518 my( $dme_lat ) = shift;
519 my( $dme_lon ) = shift;
520 my( $om_lat ) = shift;
521 my( $om_lon ) = shift;
522 my( $mm_lat ) = shift;
523 my( $mm_lon ) = shift;
524 my( $im_lat ) = shift;
525 my( $im_lon ) = shift;
529 # remap $type as needed
530 $type = &strip_ws( $type );
531 if ( $type eq "LOCALIZER" ) {
533 } elsif ( $type eq "ILS/DME" ) {
535 } elsif ( $type eq "SDF/DME" ) {
537 } elsif ( $type eq "LOC/DME" ) {
539 } elsif ( $type eq "LOC/GS" ) {
541 } elsif ( $type eq "LDA/DME" ) {
545 $record = sprintf( "%1s %-5s %-4s %-3s %06.2f %-4s %06.2f %10.6f %11.6f ",
546 substr( $type, 0, 1 ), $type, $apt_id, $rwy,
547 $loc_freq, $loc_id, $loc_hdg, $loc_lat, $loc_lon );
548 $record .= sprintf( "%5d %5.2f %10.6f %11.6f ",
549 $gs_elev, $gs_angle, $gs_lat, $gs_lon );
550 $record .= sprintf( "%10.6f %11.6f ", $dme_lat, $dme_lon );
551 $record .= sprintf( "%10.6f %11.6f ", $om_lat, $om_lon );
552 $record .= sprintf( "%10.6f %11.6f ", $mm_lat, $mm_lon );
553 $record .= sprintf( "%10.6f %11.6f ", $im_lat, $im_lon );
555 # print "Updating (common): $apt_id - $rwy\n";
556 $ILS{$apt_id . $rwy} = $record;
557 $AIRPORTS{$apt_id} = 1;
561 # update the $type of the record
563 my( $apt_id ) = shift;
565 my( $new_type ) = shift;
569 if ( $ILS{$apt_id . $rwy} ne "" ) {
570 my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
571 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
572 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
573 $im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
574 # print "Updating type: $apt_id $rwy: $type_name -> $new_type\n";
575 $type_name = $new_type;
576 &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
577 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
578 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
579 $dme_lon, $om_lat, $om_lon, $mm_lat,
580 $mm_lon, $im_lat, $im_lon );
582 die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
587 # update the glide slope elevation of the record (but only if it is 0)
588 sub maybe_update_gs_elev() {
590 my( $new_gs_elev ) = shift;
594 if ( $ILS{$key} ne "" ) {
595 my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
596 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
597 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
598 $im_lat, $im_lon ) = split( /\s+/, $ILS{$key} );
599 if ( $gs_elev == 0 ) {
600 print "Updating gs elev: $apt_id $rwy: $gs_elev -> $new_gs_elev\n";
601 $gs_elev = $new_gs_elev;
602 &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
603 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
604 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
605 $dme_lon, $om_lat, $om_lon, $mm_lat,
606 $mm_lon, $im_lat, $im_lon );
609 die "Error, trying to update $key which doesn't exist\n";
614 # update the localizer position of the record
616 my( $apt_id ) = shift;
618 my( $nloc_lat ) = shift;
619 my( $nloc_lon ) = shift;
620 my( $nloc_hdg ) = shift;
624 if ( $ILS{$apt_id . $rwy} ne "" ) {
625 my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
626 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
627 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
628 $im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
629 print " Old pos = " . $loc_lat . "," . $loc_lon . " " . $loc_hdg . "\n";
630 print " New pos = " . $nloc_lat . "," . $nloc_lon . " " . $nloc_hdg . "\n";
631 $loc_lat = $nloc_lat;
632 $loc_lon = $nloc_lon;
633 $loc_hdg = $nloc_hdg;
634 &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
635 $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
636 $gs_angle, $gs_lat, $gs_lon, $dme_lat,
637 $dme_lon, $om_lat, $om_lon, $mm_lat,
638 $mm_lon, $im_lat, $im_lon );
640 die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
645 # convert a lon/lat coordinate in various formats to signed decimal
649 my( $dir, $deg, $min, $sec );
652 $coord = &strip_ws( $coord );
654 if ( $coord =~ m/^[WE]/ ) {
655 ( $dir, $deg, $min, $sec )
656 = $coord =~ m/^([EW])(\d\d\d)(\d\d)(\d\d\d\d)/;
657 $value = $deg + $min/60.0 + ($sec/100)/3600.0;
661 } elsif ( $coord =~ m/^[NS]/ ) {
662 ( $dir, $deg, $min, $sec )
663 = $coord =~ m/^([NS])(\d\d)(\d\d)(\d\d\d\d)/;
664 $value = $deg + $min/60.0 + ($sec/100)/3600.0;
668 } elsif ( $coord =~ m/[EW]$/ ) {
669 ($value, $dir) = $coord =~ m/([\d\s\.]+)([EW])/;
673 } elsif ( $coord =~ m/[NS]$/ ) {
674 ($value, $dir) = $coord =~ m/([\d\s\.]+)([NS])/;
679 # print "$dir $deg:$min:$sec = $value\n";
683 # convert a magnetic variation in various formats to signed decimal
686 my( $coord ) = shift;
689 if ( $coord =~ m/^[EW]/ ) {
690 my( $dir, $deg, $min, $date )
691 = $coord =~ m/^([EW])(\d\d\d)(\d\d\d) (\d\d\d\d)/;
692 $value = $deg + ($min/10)/60.0;
696 } elsif ( $coord =~ m/[EW]$/ ) {
698 = $coord =~ m/^(\d\d)([EW])/;
704 # print "$dir $deg:$min = $value\n";
709 # strip white space off front and back of string
712 my( $string ) = shift;
719 # return the reciprical runway number
721 my( $input ) = shift;
725 if ( length($input) == 3 ) {
726 ($num, $letter) = $input =~ m/(\d\d)(.)/;
727 } elsif ( length($input) == 2 ) {
734 # print "RWY: $num - $letter <==> ";
746 if ( $letter eq "R" ) {
748 } elsif ( $letter eq "L" ) {
750 } elsif ( $letter eq "C" ) {
752 } elsif ( $letter eq "N" ) {
754 } elsif ( $letter eq "S" ) {
756 } elsif ( $letter eq "E" ) {
758 } elsif ( $letter eq "W" ) {
761 # print "$num - $letter\n";
763 return "$num$letter";