]> git.mxchange.org Git - flightgear.git/blob - scripts/perl/dafif/build_ils.pl
This script should be moved because it really isn't dafift specific. It
[flightgear.git] / scripts / perl / dafif / build_ils.pl
1 #!/usr/bin/perl
2
3 ########################################################################
4 # Convert DAFIFT ARPT/ILS.TXT to FlightGear format.
5 ########################################################################
6
7 use strict;
8
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);
15
16 my($calc_loc)
17     = "/home/curt/projects/FlightGear-0.9/source/src/Airports/calc_loc";
18
19 die "Usage: $0 " .
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);
24
25 my( %CODES );
26 my( %CodesByICAO );
27 my( %ILS );
28 my( %AIRPORTS );
29 my( %RUNWAYS );
30
31
32 &load_dafift( $dafift_arpt_file, $dafift_ils_file );
33 &load_faa( $faa_ils_file );
34 &load_fgfs( $fgfs_ils_file );
35 &load_fgfs_airports( $fgfs_apt_file );
36 &fix_localizer();
37
38 &write_result( $output_file );
39
40 exit;
41
42
43 ########################################################################
44 # Process DAFIFT data
45 ########################################################################
46
47 sub load_dafift() {
48     my( $arpt_file ) = shift;
49     my( $ils_file ) = shift;
50
51     my( $record );
52
53     my( $id, $rwy, $type );
54     my( $has_dme, $has_gs, $has_loc, $has_im, $has_mm, $has_om );
55     my( $dme_lon, $dme_lat, $dme_elev, $dme_bias );
56     my( $gs_lon, $gs_lat, $gs_elev, $gs_angle );
57     my( $loc_type, $loc_lon, $loc_lat, $loc_elev, $loc_freq, $loc_hdg,
58         $loc_width, $loc_id );
59     my( $im_lon, $im_lat, $mm_lon, $mm_lat, $om_lon, $om_lat );
60
61     # load airport file so we can lookup ICAO from internal ID
62
63     open( ARPT, "<$arpt_file" ) || die "Cannot open DAFIFT: $arpt_file\n";
64
65     <ARPT>;                          # skip header line
66
67     while ( <ARPT> ) {
68         chomp;
69         my(@F) = split(/\t/);
70         my($icao) = $F[3];
71         if ( length($icao) < 3 ) {
72             if ( length( $F[4] ) >= 3 ) {
73                 $icao = $F[4];
74             } else {
75                 $icao = "[none]";
76             }
77         }
78         $CODES{$F[0]} = $icao;
79         $CodesByICAO{$icao} = 1;
80         # print "$F[0] - $icao\n";
81     }
82
83     # Load the DAFIFT ils file
84
85     my( $last_id, $last_rwy ) = ("", "");
86
87     open( DAFIFT_ILS, "<$ils_file" ) || die "Cannot open DAFIFT: $ils_file\n";
88
89     <DAFIFT_ILS>;                   # skip header line
90
91     while ( <DAFIFT_ILS> ) {
92         chomp;
93         my @F = split(/\t/);
94         $id = $F[0];
95         $rwy = $F[1];
96
97         if ( $last_id ne "" && ($last_id ne $id || $last_rwy ne $rwy) ) {
98             # just hist the start of the next record, dump the current data
99
100             if ( ! $has_gs ) {
101                 ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
102             }
103             if ( ! $has_dme ) {
104                 ( $dme_lat, $dme_lon ) = ( 0, 0 );
105             }
106             if ( ! $has_om ) {
107                 ( $om_lat, $om_lon ) = ( 0, 0 );
108             }
109             if ( ! $has_mm ) {
110                 ( $mm_lat, $mm_lon ) = ( 0, 0 );
111             }
112             if ( ! $has_im ) {
113                 ( $im_lat, $im_lon ) = ( 0, 0 );
114             }
115             if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
116                 print "DAFIFT adding: $CODES{$last_id} - $last_rwy\n";
117                 &safe_add_record( $CODES{$last_id}, $last_rwy, "ILS", 
118                                   $loc_freq, $loc_id, $loc_hdg, $loc_lat,
119                                   $loc_lon, $gs_elev, $gs_angle, $gs_lat,
120                                   $gs_lon, $dme_lat, $dme_lon, $om_lat,
121                                   $om_lon, $mm_lat, $mm_lon, $im_lat,
122                                   $im_lon );
123             }
124
125             $has_dme = 0;
126             $has_gs = 0;
127             $has_loc = 0;
128             $has_im = 0;
129             $has_mm = 0;
130             $has_om = 0;
131         }
132
133         $type = $F[2];
134         if ( $type eq "D" ) {
135             # DME entry
136             $has_dme = 1;
137             $dme_lon = make_dcoord( $F[16] );
138             $dme_lat = make_dcoord( $F[14] );
139             $dme_elev = $F[10];
140             if ( $dme_elev !~ m/\d/ ) {
141                 $dme_elev = "";
142             } else {
143                 $dme_elev += 0;
144             }
145             $dme_bias = $F[27];
146             # print "$id DME $dme_lon $dme_lat $dme_elev $dme_bias\n";
147         } elsif ( $type eq "G" ) {
148             # GlideSlope entry
149             $has_gs = 1;
150             $gs_lon = make_dcoord( $F[16] );
151             $gs_lat = make_dcoord( $F[14] );
152             $gs_elev = $F[10];
153             if ( $gs_elev !~ m/\d/ ) {
154                 $gs_elev = "";
155             } else {
156                 $gs_elev += 0;
157             }
158             $gs_angle = $F[7];
159             # print "$id GS $gs_lon $gs_lat $gs_elev $gs_angle\n";
160         } elsif ( $type eq "Z" ) {
161             # Localizer entry
162             $has_loc = 1;
163             $loc_lon = make_dcoord( $F[16] );
164             $loc_lat = make_dcoord( $F[14] );
165             $loc_elev = $F[10];
166             if ( $loc_elev !~ m/\d/ ) {
167                 $loc_elev = "";
168             } else {
169                 $loc_elev += 0;
170             }
171             ($loc_freq) = $F[5] =~ m/(\d\d\d\d\d\d)/;
172             $loc_freq /= 1000.0;
173             my( $magvar ) = make_dmagvar( $F[22] );
174             # print "mag var = $F[22] (" . $magvar . ")\n";
175             $loc_hdg = $F[24] + make_dmagvar( $F[22] );
176             $loc_width = $F[25];
177             $loc_id = $F[18];
178             if ( length( $loc_id ) >= 4 ) {
179                 $loc_id =~ s/^I//;
180             }
181             # print "$id LOC $loc_lon $loc_lat $loc_elev $loc_freq $loc_hdg $loc_width\n";
182         } elsif ( $type eq "I" ) {
183             # Inner marker entry
184             $has_im = 1;
185             $im_lon = make_dcoord( $F[16] );
186             $im_lat = make_dcoord( $F[14] );
187             # print "$id IM $im_lon $im_lat\n";
188         } elsif ( $type eq "M" ) {
189             # Middle marker entry
190             $has_mm = 1;
191             $mm_lon = make_dcoord( $F[16] );
192             $mm_lat = make_dcoord( $F[14] );
193             # print "$id MM $mm_lon $mm_lat\n";
194         } elsif ( $type eq "O" ) {
195             # Outer marker entry
196             $has_om = 1;
197             $om_lon = make_dcoord( $F[16] );
198             $om_lat = make_dcoord( $F[14] );
199             # print "$id OM $om_lon $om_lat\n";
200         }
201
202         $last_id = $id;
203         $last_rwy = $rwy;
204         # printf("%-5s %10.6f %11.6f\n",  $F[0], $F[14], $F[16]);
205     }
206
207     if ( ! $has_gs ) {
208         ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
209     }
210     if ( ! $has_dme ) {
211         ( $dme_lat, $dme_lon ) = ( 0, 0 );
212     }
213     if ( ! $has_om ) {
214         ( $om_lat, $om_lon ) = ( 0, 0 );
215     }
216     if ( ! $has_mm ) {
217         ( $mm_lat, $mm_lon ) = ( 0, 0 );
218     }
219     if ( ! $has_im ) {
220         ( $im_lat, $im_lon ) = ( 0, 0 );
221     }
222     if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
223         print "DAFIFT adding (last): $CODES{$last_id} - $last_rwy\n";
224         &safe_add_record( $CODES{$last_id}, $last_rwy, "ILS", $loc_freq,
225                           $loc_id, $loc_hdg, $loc_lat, $loc_lon,
226                           $gs_elev, $gs_angle, $gs_lat, $gs_lon,
227                           $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat,
228                           $mm_lon, $im_lat, $im_lon );
229     }
230 }
231
232
233 ########################################################################
234 # Process FAA data
235 ########################################################################
236
237 sub load_faa() {
238     my( $file ) = shift;
239
240     open( FAA_ILS, "<$file" ) || die "Cannot open FAA data: $file\n";
241
242     <FAA_ILS>;                          # skip header line
243
244     while ( <FAA_ILS> ) {
245         chomp;
246
247         my ( $rec_type, $faa_id, $rwy, $type, $faa_date,
248              $faa_apt_name, $faa_city, $faa_st, $faa_state,
249              $faa_region, $id, $faa_len, $faa_wid, $faa_cat,
250              $faa_owner, $faa_operator, $faa_bearing, $faa_magvar,
251              $loc_type, $loc_id, $loc_freq, $faa_loc_latd,
252              $faa_loc_lats, $faa_loc_lond, $faa_loc_lons, $loc_width,
253              $faa_stop_dist, $faa_app_dist, $faa_gs_type, $gs_angle,
254              $faa_gs_freq, $faa_gs_latd, $faa_gs_lats, $faa_gs_lond,
255              $faa_gs_lons, $faa_gs_dist, $gs_elev, $faa_im_type,
256              $faa_im_latd, $faa_im_lats, $faa_im_lond, $faa_im_lons,
257              $faa_im_dist, $faa_mm_type, $faa_mm_id, $faa_mm_name,
258              $faa_mm_freq, $faa_mm_latd, $faa_mm_lats, $faa_mm_lond,
259              $faa_mm_lons, $faa_mm_dist, $faa_om_type, $faa_om_id,
260              $faa_om_name, $faa_om_freq, $faa_om_latd, $faa_om_lats,
261              $faa_om_lond, $faa_om_lons, $faa_om_dist,
262              $faa_om_backcourse, $faa_dme_channel, $faa_dme_latd,
263              $faa_dme_lats, $faa_dme_lond, $faa_dme_lons, $faa_dme_app_dist,
264              $faa_dme_stop_dist, $blank)
265             = $_ =~
266             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})/;
267
268         $id = &strip_ws( $id );
269         $rwy = &strip_ws( $rwy );
270         $rwy =~ s/\/$//;
271         $rwy =~ s/\/$//;
272         $loc_id =~ s/^I-//;
273         my( $loc_hdg ) = $faa_bearing + make_dmagvar($faa_magvar);
274         my( $loc_lat ) = make_dcoord($faa_loc_lats) / 3600.0;
275         my( $loc_lon ) = make_dcoord($faa_loc_lons) / 3600.0;
276         # print "$loc_lon $loc_lat $faa_loc_lons $faa_loc_lats\n";
277         my( $gs_lat ) = make_dcoord($faa_gs_lats) / 3600.0;
278         my( $gs_lon ) = make_dcoord($faa_gs_lons) / 3600.0;
279         my( $im_lat ) = make_dcoord($faa_im_lats) / 3600.0;
280         my( $im_lon ) = make_dcoord($faa_im_lons) / 3600.0;
281         my( $mm_lat ) = make_dcoord($faa_mm_lats) / 3600.0;
282         my( $mm_lon ) = make_dcoord($faa_mm_lons) / 3600.0;
283         my( $om_lat ) = make_dcoord($faa_om_lats) / 3600.0;
284         my( $om_lon ) = make_dcoord($faa_om_lons) / 3600.0;
285         my( $dme_lat ) = make_dcoord($faa_dme_lats) / 3600.0;
286         my( $dme_lon ) = make_dcoord($faa_dme_lons) / 3600.0;
287
288         # my( $key );
289         # print "$id - $rwy\n";
290         # $key = $id . $rwy;
291         # print "-> $key -> $ILS{$key}\n";
292         # $key = "K" . $id . $rwy;
293         # print "-> $key -> $ILS{$key}\n";
294
295         if ( $rec_type eq "ILS1" ) {
296             if ( length( $id ) < 4 ) {
297                 if ( $CodesByICAO{"K" . $id} ) {
298                     $id = "K" . $id;
299                 }
300             }
301             if ( $ILS{$id . $rwy} ne "" ) {
302                 print "FAA updating: $id - $rwy $type\n";
303                 &update_type( $id, $rwy, $type );
304             } else {
305                 print "FAA adding: $id - $rwy\n";
306                 &safe_add_record( $id, $rwy, $type, $loc_freq, $loc_id,
307                                   $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
308                                   $gs_angle, $gs_lat, $gs_lon, $dme_lat,
309                                   $dme_lon, $om_lat, $om_lon, $mm_lat,
310                                   $mm_lon, $im_lat, $im_lon );
311             }
312         }
313     }
314 }
315
316
317 ########################################################################
318 # Process FlightGear ILS data
319 ########################################################################
320
321 sub load_fgfs() {
322     my( $ils_file ) = shift;
323
324     open( FGILS, "zcat $ils_file|" ) || die "Cannot open FGFS: $ils_file\n";
325
326     <FGILS>;                          # skip header line
327
328     while ( <FGILS> ) {
329         chomp;
330         if ( ! m/\[End\]/ && length($_) > 1 ) {
331             # print "$_\n";
332             my( $type_code, $type_name, $icao, $rwy, $loc_freq, $loc_id,
333                 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
334                 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
335                 $im_lat, $im_lon ) = split(/\s+/);
336             my( $code ) = $icao;
337             $code =~ s/^K//;
338             if ( $ILS{$icao . $rwy} ne "" ) {
339                 print "FGFS: Skipping $icao - $rwy - already exists\n";
340                 # skip approaches already in FAA or DAFIFT data
341             } elsif ( length( $icao ) < 4 || $icao =~ m/^K/ ) {
342                 print "FGFS: Skipping $icao - $rwy - USA\n";
343                 # skip USA approaches not found in FAA or DAFIFT data
344             } else {
345                 print "FGFS adding: $icao $rwy\n";
346                 &safe_add_record( $icao, $rwy, $type_name, $loc_freq, $loc_id,
347                                   $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
348                                   $gs_angle, $gs_lat, $gs_lon, $dme_lat,
349                                   $dme_lon, $om_lat, $om_lon, $mm_lat,
350                                   $mm_lon, $im_lat, $im_lon );
351             }
352         } else {
353             print "FGFS discarding: $_\n";
354         }
355     }
356 }
357
358
359 ########################################################################
360 # Load the x-plane/flightgear airport/runway information
361 ########################################################################
362
363 sub load_fgfs_airports() {
364     my( $infile ) = shift;
365
366     my( $id );
367
368     open( IN, "zcat $infile|" ) || die "Cannot open: $infile\n";
369
370     <IN>;                       # skip header line
371
372     while ( <IN> ) {
373         chomp;
374         my(@F) = split(/\s+/);
375         if ( $F[0] eq "A" ) {
376             $id = $F[1];
377         } elsif ( $F[0] eq "R" ) {
378             my($recip) = &rwy_recip( $F[1] );
379             $RUNWAYS{ $id . $F[1] } = "FOR $_";
380             $RUNWAYS{ $id . $recip } = "REV $_";
381         }
382     }
383 }
384
385
386 ########################################################################
387 # Run through the final ils list and adjust the heading to match the runway
388 ########################################################################
389
390 sub fix_localizer() {
391     my( $key );
392     foreach $key ( sort (keys %ILS) ) {
393         my(@F) = split( /\s+/, $ILS{$key} );
394         print "FIXING: $key $F[2] $F[3] $F[4]\n";
395         if ( $RUNWAYS{$key} ) {
396             my(@G) = split( /\s+/, $RUNWAYS{$key} );
397             print "  LocPos = $F[7] $F[8]\n";
398             print "  RwyInfo = $G[0] $G[3] $G[4] $G[5] $G[6] $G[7]\n";
399             my($cmd)
400                 = "$calc_loc $F[7] $F[8] $G[0] $G[3] $G[4] $G[5] $G[6] $G[7]";
401             open( CALC, "$cmd |" ) || die "Cannot open $calc_loc\n";
402             my( $j, $lat, $lon );
403             while ( <CALC> ) {
404                 if ( m/New localizer/ ) {
405                     ($j, $j, $j, $lat, $lon) = split( /\s+/ );
406                 }
407             }
408             if ( $G[0] eq "REV" ) {
409                 $G[5] += 180.0;
410                 if ( $G[5] >= 360.0 ) {
411                     $G[5] -= 360.0;
412                 }
413             }
414             &update_loc( $F[2], $F[3], $lat, $lon, $G[5]);
415         }
416     }
417 }
418
419
420 ########################################################################
421 # Write out the accumulated combined result
422 ########################################################################
423
424 sub write_result() {
425     my( $outfile ) = shift;
426
427     open( OUT, ">$outfile" )  || die "Cannot write to: $outfile\n";
428
429     # dump out the final results
430     print OUT "// FlightGear ILS data, generated from DAFIFT ARPT/ILS.TXT and FAA data\n";
431
432     my( $key );
433     foreach $key ( sort (keys %ILS) ) {
434         print OUT "$ILS{$key}\n";
435     }
436     print OUT "[End]\n";
437 }
438
439
440 ########################################################################
441 # Utility functions
442 ########################################################################
443
444
445 # add a record to the master list if it doesn't already exist
446
447 sub safe_add_record() {
448     my( $apt_id ) = shift;
449     my( $rwy ) = shift;
450     my( $type ) = shift;
451     my( $loc_freq ) = shift;
452     my( $loc_id ) = shift;
453     my( $loc_hdg ) = shift;
454     my( $loc_lat ) = shift;
455     my( $loc_lon ) = shift;
456     my( $gs_elev ) = shift;
457     my( $gs_angle ) = shift;
458     my( $gs_lat ) = shift;
459     my( $gs_lon ) = shift;
460     my( $dme_lat ) = shift;
461     my( $dme_lon ) = shift;
462     my( $om_lat ) = shift;
463     my( $om_lon ) = shift;
464     my( $mm_lat ) = shift;
465     my( $mm_lon ) = shift;
466     my( $im_lat ) = shift;
467     my( $im_lon ) = shift;
468
469     if ( $ILS{$apt_id . $rwy} eq "" ) {
470         # print "Safe adding (common): $apt_id - $rwy\n";
471         &update_record( $apt_id, $rwy, $type, $loc_freq, $loc_id,
472                         $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
473                         $gs_angle, $gs_lat, $gs_lon, $dme_lat,
474                         $dme_lon, $om_lat, $om_lon, $mm_lat,
475                         $mm_lon, $im_lat, $im_lon );
476     }
477 }
478
479
480 # replace a record in the master list (or add it if it doesn't exist)
481
482 sub update_record() {
483     my( $apt_id ) = shift;
484     my( $rwy ) = shift;
485     my( $type ) = shift;
486     my( $loc_freq ) = shift;
487     my( $loc_id ) = shift;
488     my( $loc_hdg ) = shift;
489     my( $loc_lat ) = shift;
490     my( $loc_lon ) = shift;
491     my( $gs_elev ) = shift;
492     my( $gs_angle ) = shift;
493     my( $gs_lat ) = shift;
494     my( $gs_lon ) = shift;
495     my( $dme_lat ) = shift;
496     my( $dme_lon ) = shift;
497     my( $om_lat ) = shift;
498     my( $om_lon ) = shift;
499     my( $mm_lat ) = shift;
500     my( $mm_lon ) = shift;
501     my( $im_lat ) = shift;
502     my( $im_lon ) = shift;
503
504     my( $record );
505
506     # remap $type as needed
507     $type = &strip_ws( $type );
508     if ( $type eq "LOCALIZER" ) {
509         $type = "LOC";
510     } elsif ( $type eq "ILS/DME" ) {
511         $type = "ILS";
512     } elsif ( $type eq "SDF/DME" ) {
513         $type = "SDF";
514     } elsif ( $type eq "LOC/DME" ) {
515         $type = "ILS";
516     } elsif ( $type eq "LOC/GS" ) {
517         $type = "LOC";
518     } elsif ( $type eq "LDA/DME" ) {
519         $type = "LDA";
520     }
521
522     $record = sprintf( "%1s %-5s %-4s %-3s  %06.2f %-4s %06.2f %10.6f %11.6f ",
523                        substr( $type, 0, 1 ), $type, $apt_id, $rwy,
524                        $loc_freq, $loc_id, $loc_hdg, $loc_lat, $loc_lon );
525     $record .= sprintf( "%5d %5.2f %10.6f %11.6f ",
526                         $gs_elev, $gs_angle, $gs_lat, $gs_lon );
527     $record .= sprintf( "%10.6f %11.6f ", $dme_lat, $dme_lon );
528     $record .= sprintf( "%10.6f %11.6f ", $om_lat, $om_lon );
529     $record .= sprintf( "%10.6f %11.6f ", $mm_lat, $mm_lon );
530     $record .= sprintf( "%10.6f %11.6f ", $im_lat, $im_lon );
531
532     # print "Updating (common): $apt_id - $rwy\n";
533     $ILS{$apt_id . $rwy} = $record;
534     $AIRPORTS{$apt_id} = 1;
535 }
536
537
538 # update the $type of the record
539 sub update_type() {
540     my( $apt_id ) = shift;
541     my( $rwy ) = shift;
542     my( $new_type ) = shift;
543
544     my( $record );
545
546     if ( $ILS{$apt_id . $rwy} ne "" ) {
547         my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
548             $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
549             $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
550             $im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
551         # print "Updating type: $apt_id $rwy: $type_name -> $new_type\n";
552         $type_name = $new_type;
553         &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
554                         $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
555                         $gs_angle, $gs_lat, $gs_lon, $dme_lat,
556                         $dme_lon, $om_lat, $om_lon, $mm_lat,
557                         $mm_lon, $im_lat, $im_lon );
558     } else {
559         die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
560     }
561 }
562
563
564 # update the localizer position of the record
565 sub update_loc() {
566     my( $apt_id ) = shift;
567     my( $rwy ) = shift;
568     my( $nloc_lat ) = shift;
569     my( $nloc_lon ) = shift;
570     my( $nloc_hdg ) = shift;
571
572     my( $record );
573
574     if ( $ILS{$apt_id . $rwy} ne "" ) {
575         my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
576             $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
577             $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
578             $im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
579         print "    Old pos = " . $loc_lat . "," . $loc_lon . " " . $loc_hdg . "\n";
580         print "    New pos = " . $nloc_lat . "," . $nloc_lon . " " . $nloc_hdg . "\n";
581         $loc_lat = $nloc_lat;
582         $loc_lon = $nloc_lon;
583         $loc_hdg = $nloc_hdg;
584         &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
585                         $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
586                         $gs_angle, $gs_lat, $gs_lon, $dme_lat,
587                         $dme_lon, $om_lat, $om_lon, $mm_lat,
588                         $mm_lon, $im_lat, $im_lon );
589     } else {
590         die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
591     }
592 }
593
594
595 # convert a lon/lat coordinate in various formats to signed decimal
596
597 sub make_dcoord() {
598     my($coord) = shift;
599     my( $dir, $deg, $min, $sec );
600     my( $value ) = 0.0;
601
602     $coord = &strip_ws( $coord );
603
604     if ( $coord =~ m/^[WE]/ ) {
605         ( $dir, $deg, $min, $sec )
606             = $coord =~ m/^([EW])(\d\d\d)(\d\d)(\d\d\d\d)/;
607         $value = $deg + $min/60.0 + ($sec/100)/3600.0;
608         if ( $dir eq "W" ) {
609             $value = -$value;
610         }
611     } elsif ( $coord =~ m/^[NS]/ ) {
612         ( $dir, $deg, $min, $sec )
613             = $coord =~ m/^([NS])(\d\d)(\d\d)(\d\d\d\d)/;
614         $value = $deg + $min/60.0 + ($sec/100)/3600.0;
615         if ( $dir eq "S" ) {
616             $value = -$value;
617         }
618     } elsif ( $coord =~ m/[EW]$/ ) {
619         ($value, $dir) = $coord =~ m/([\d\s\.]+)([EW])/;
620         if ( $dir eq "W" ) {
621             $value = -$value;
622         }
623     } elsif ( $coord =~ m/[NS]$/ ) {
624         ($value, $dir) = $coord =~ m/([\d\s\.]+)([NS])/;
625         if ( $dir eq "S" ) {
626             $value = -$value;
627         }
628     }
629     # print "$dir $deg:$min:$sec = $value\n";
630     return $value;
631 }
632
633 # convert a magnetic variation in various formats to signed decimal
634
635 sub make_dmagvar() {
636     my( $coord ) = shift;
637     my( $value );
638
639     if ( $coord =~ m/^[EW]/ ) {
640         my( $dir, $deg, $min, $date )
641             = $coord =~ m/^([EW])(\d\d\d)(\d\d\d) (\d\d\d\d)/;
642         $value = $deg + ($min/10)/60.0;
643         if ( $dir eq "W" ) {
644             $value = -$value;
645         }
646     } elsif ( $coord =~ m/[EW]$/ ) {
647         my( $deg, $dir )
648             = $coord =~ m/^(\d\d)([EW])/;
649         $value = $deg;
650         if ( $dir eq "W" ) {
651             $value = -$value;
652         }
653     }
654     # print "$dir $deg:$min = $value\n";
655
656     return $value;
657 }
658
659 # strip white space off front and back of string
660
661 sub strip_ws() {
662     my( $string ) = shift;
663     $string =~ s/^\s+//;
664     $string =~ s/\s+$//;
665     return $string;
666 }
667
668
669 # return the reciprical runway number
670 sub rwy_recip() {
671     my( $input ) = shift;
672
673     my($num, $letter);
674
675     if ( length($input) == 3 ) {
676         ($num, $letter) = $input =~ m/(\d\d)(.)/;
677     } elsif ( length($input) == 2 ) {
678         $num = $input;
679         $letter = "";
680     } else {
681         $num = "";
682         $letter = $input;
683     }
684     # print "RWY: $num - $letter <==> ";
685
686     if ( $num ne "" ) {
687         $num += 18;
688         if ( $num > 35 ) {
689             $num -= 36;
690         }
691         if ( $num < 10 ) {
692             $num = "0$num";
693         }
694     }
695
696     if ( $letter eq "R" ) {
697         $letter = "L";
698     } elsif ( $letter eq "L" ) {
699         $letter = "R";
700     } elsif ( $letter eq "C" ) {
701         $letter = "C";
702     } elsif ( $letter eq "N" ) {
703         $letter = "S";
704     } elsif ( $letter eq "S" ) {
705         $letter = "N";
706     } elsif ( $letter eq "E" ) {
707         $letter = "W";
708     } elsif ( $letter eq "W" ) {
709         $letter = "E";
710     }
711     # print "$num - $letter\n";
712
713     return "$num$letter";
714 }