]> git.mxchange.org Git - flightgear.git/blob - scripts/perl/dafif/dafift2ils.pl
08139d5fffc42d2011828cc7663f3f5c38225dea
[flightgear.git] / scripts / perl / dafif / dafift2ils.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($output_file) = shift(@ARGV);
14
15 die "Usage: $0 " .
16     "<faa_ils_file> <dafift_arpt_file> <dafift_ils_file> <fgfs_ils_file> <output_file>\n"
17     if !defined($faa_ils_file) || !defined($dafift_arpt_file)
18        || !defined($dafift_ils_file) || !defined($fgfs_ils_file)
19        || !defined($output_file);
20
21 my( %Airports );
22 my( %ILS );
23
24
25 &load_dafift( $dafift_arpt_file, $dafift_ils_file );
26 &load_faa( $faa_ils_file );
27 # &load_fgfs( $fgfs_ils_file );
28 &write_result( $output_file );
29
30 exit;
31
32
33 ########################################################################
34 # Process FAA data
35 ########################################################################
36
37 sub load_faa() {
38     my( $file ) = shift;
39
40     open( FAA_ILS, "<$file" ) || die "Cannot open FAA data: $file\n";
41
42     <FAA_ILS>;                          # skip header line
43
44     while ( <FAA_ILS> ) {
45         chomp;
46
47         my ( $rec_type, $faa_id, $rwy, $type, $faa_date,
48              $faa_apt_name, $faa_city, $faa_st, $faa_state,
49              $faa_region, $id, $faa_len, $faa_wid, $faa_cat,
50              $faa_owner, $faa_operator, $faa_bearing, $faa_magvar,
51              $loc_type, $loc_id, $loc_freq, $faa_loc_latd,
52              $faa_loc_lats, $faa_loc_lond, $faa_loc_lons, $loc_width,
53              $faa_stop_dist, $faa_app_dist, $faa_gs_type, $gs_angle,
54              $faa_gs_freq, $faa_gs_latd, $faa_gs_lats, $faa_gs_lond,
55              $faa_gs_lons, $faa_gs_dist, $gs_elev, $faa_im_type,
56              $faa_im_latd, $faa_im_lats, $faa_im_lond, $faa_im_lons,
57              $faa_im_dist, $faa_mm_type, $faa_mm_id, $faa_mm_name,
58              $faa_mm_freq, $faa_mm_latd, $faa_mm_lats, $faa_mm_lond,
59              $faa_mm_lons, $faa_mm_dist, $faa_om_type, $faa_om_id,
60              $faa_om_name, $faa_om_freq, $faa_om_latd, $faa_om_lats,
61              $faa_om_lond, $faa_om_lons, $faa_om_dist,
62              $faa_om_backcourse, $faa_dme_channel, $faa_dme_latd,
63              $faa_dme_lats, $faa_dme_lond, $faa_dme_lons, $faa_dme_app_dist,
64              $faa_dme_stop_dist, $blank)
65             = $_ =~
66             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})/;
67
68         $id = &strip_ws( $id );
69         $rwy = &strip_ws( $rwy );
70         $loc_id =~ s/I-//;
71         my( $loc_hdg ) = $faa_bearing + make_dmagvar($faa_magvar);
72         my( $loc_lat ) = make_dcoord($faa_loc_lats) / 3600.0;
73         my( $loc_lon ) = make_dcoord($faa_loc_lons) / 3600.0;
74         print "$loc_lon $loc_lat $faa_loc_lons $faa_loc_lats\n";
75         my( $gs_lat ) = make_dcoord($faa_gs_lats) / 3600.0;
76         my( $gs_lon ) = make_dcoord($faa_gs_lons) / 3600.0;
77         my( $im_lat ) = make_dcoord($faa_im_lats) / 3600.0;
78         my( $im_lon ) = make_dcoord($faa_im_lons) / 3600.0;
79         my( $mm_lat ) = make_dcoord($faa_mm_lats) / 3600.0;
80         my( $mm_lon ) = make_dcoord($faa_mm_lons) / 3600.0;
81         my( $om_lat ) = make_dcoord($faa_om_lats) / 3600.0;
82         my( $om_lon ) = make_dcoord($faa_om_lons) / 3600.0;
83         my( $dme_lat ) = make_dcoord($faa_dme_lats) / 3600.0;
84         my( $dme_lon ) = make_dcoord($faa_dme_lons) / 3600.0;
85
86         # my( $key );
87         # print "$id - $rwy\n";
88         # $key = $id . $rwy;
89         # print "-> $key -> $ILS{$key}\n";
90         # $key = "K" . $id . $rwy;
91         # print "-> $key -> $ILS{$key}\n";
92
93         if ( $rec_type eq "ILS1" ) {
94             if ( $ILS{$id . $rwy} ne "" ) {
95                 print "FAA updating: $id - $rwy $type\n";
96                 &update_type( $id, $rwy, $type );
97             } elsif ( $ILS{ "K" . $id . $rwy} ne "" ) {
98                 print "FAA updating: [K]$id - $rwy $type\n";
99                 &update_type( "K" . $id, $rwy, $type );
100             } else {
101                 print "FAA adding: $id - $rwy\n";
102                 &safe_add_record( $id, $rwy, $type, $loc_freq, $loc_id,
103                                   $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
104                                   $gs_angle, $gs_lat, $gs_lon, $dme_lat,
105                                   $dme_lon, $om_lat, $om_lon, $mm_lat,
106                                   $mm_lon, $im_lat, $im_lon );
107             }
108         }
109     }
110 }
111
112
113 ########################################################################
114 # Process DAFIFT data
115 ########################################################################
116
117 sub load_dafift() {
118     my( $arpt_file ) = shift;
119     my( $ils_file ) = shift;
120
121     my( $record );
122
123     my( $id, $rwy, $type );
124     my( $has_dme, $has_gs, $has_loc, $has_im, $has_mm, $has_om );
125     my( $dme_lon, $dme_lat, $dme_elev, $dme_bias );
126     my( $gs_lon, $gs_lat, $gs_elev, $gs_angle );
127     my( $loc_type, $loc_lon, $loc_lat, $loc_elev, $loc_freq, $loc_hdg,
128         $loc_width, $loc_id );
129     my( $im_lon, $im_lat, $mm_lon, $mm_lat, $om_lon, $om_lat );
130
131     # load airport file so we can lookup ICAO from internal ID
132
133     open( ARPT, "<$arpt_file" ) || die "Cannot open DAFIFT: $arpt_file\n";
134
135     <ARPT>;                          # skip header line
136
137     while ( <ARPT> ) {
138         chomp;
139         my(@F) = split(/\t/);
140         my($icao) = $F[3];
141         if ( length($icao) < 3 ) {
142             if ( length( $F[4] ) >= 3 ) {
143                 $icao = $F[4];
144             } else {
145                 $icao = "[none]";
146             }
147         }
148         $Airports{$F[0]} = $icao;
149         # print "$F[0] - $icao\n";
150     }
151
152     # Load the DAFIFT ils file
153
154     my( $last_id, $last_rwy ) = ("", "");
155
156     open( DAFIFT_ILS, "<$ils_file" ) || die "Cannot open DAFIFT: $ils_file\n";
157
158     <DAFIFT_ILS>;                   # skip header line
159
160     while ( <DAFIFT_ILS> ) {
161         chomp;
162         my @F = split(/\t/);
163         $id = $F[0];
164         $rwy = $F[1];
165
166         if ( $last_id ne "" && ($last_id ne $id || $last_rwy ne $rwy) ) {
167             # just hist the start of the next record, dump the current data
168
169             if ( ! $has_gs ) {
170                 ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
171             }
172             if ( ! $has_dme ) {
173                 ( $dme_lat, $dme_lon ) = ( 0, 0 );
174             }
175             if ( ! $has_om ) {
176                 ( $om_lat, $om_lon ) = ( 0, 0 );
177             }
178             if ( ! $has_mm ) {
179                 ( $mm_lat, $mm_lon ) = ( 0, 0 );
180             }
181             if ( ! $has_im ) {
182                 ( $im_lat, $im_lon ) = ( 0, 0 );
183             }
184             if ( $ILS{$Airports{$last_id} . $last_rwy} eq "" ) {
185                 print "DAFIFT adding: $Airports{$last_id} - $last_rwy\n";
186                 &safe_add_record( $Airports{$last_id}, $last_rwy, "ILS", 
187                                   $loc_freq, $loc_id, $loc_hdg, $loc_lat,
188                                   $loc_lon, $gs_elev, $gs_angle, $gs_lat,
189                                   $gs_lon, $dme_lat, $dme_lon, $om_lat,
190                                   $om_lon, $mm_lat, $mm_lon, $im_lat,
191                                   $im_lon );
192             }
193
194             $has_dme = 0;
195             $has_gs = 0;
196             $has_loc = 0;
197             $has_im = 0;
198             $has_mm = 0;
199             $has_om = 0;
200         }
201
202         $type = $F[2];
203         if ( $type eq "D" ) {
204             # DME entry
205             $has_dme = 1;
206             $dme_lon = make_dcoord( $F[16] );
207             $dme_lat = make_dcoord( $F[14] );
208             $dme_elev = $F[10];
209             if ( $dme_elev !~ m/\d/ ) {
210                 $dme_elev = "";
211             } else {
212                 $dme_elev += 0;
213             }
214             $dme_bias = $F[27];
215             # print "$id DME $dme_lon $dme_lat $dme_elev $dme_bias\n";
216         } elsif ( $type eq "G" ) {
217             # GlideSlope entry
218             $has_gs = 1;
219             $gs_lon = make_dcoord( $F[16] );
220             $gs_lat = make_dcoord( $F[14] );
221             $gs_elev = $F[10];
222             if ( $gs_elev !~ m/\d/ ) {
223                 $gs_elev = "";
224             } else {
225                 $gs_elev += 0;
226             }
227             $gs_angle = $F[7];
228             # print "$id GS $gs_lon $gs_lat $gs_elev $gs_angle\n";
229         } elsif ( $type eq "Z" ) {
230             # Localizer entry
231             $has_loc = 1;
232             $loc_lon = make_dcoord( $F[16] );
233             $loc_lat = make_dcoord( $F[14] );
234             $loc_elev = $F[10];
235             if ( $loc_elev !~ m/\d/ ) {
236                 $loc_elev = "";
237             } else {
238                 $loc_elev += 0;
239             }
240             ($loc_freq) = $F[5] =~ m/(\d\d\d\d\d\d)/;
241             $loc_freq /= 1000.0;
242             my( $magvar ) = make_dmagvar( $F[22] );
243             # print "mag var = $F[22] (" . $magvar . ")\n";
244             $loc_hdg = $F[24] + make_dmagvar( $F[22] );
245             $loc_width = $F[25];
246             $loc_id = $F[18];
247             if ( length( $loc_id ) >= 4 ) {
248                 $loc_id =~ s/^I//;
249             }
250             # print "$id LOC $loc_lon $loc_lat $loc_elev $loc_freq $loc_hdg $loc_width\n";
251         } elsif ( $type eq "I" ) {
252             # Inner marker entry
253             $has_im = 1;
254             $im_lon = make_dcoord( $F[16] );
255             $im_lat = make_dcoord( $F[14] );
256             # print "$id IM $im_lon $im_lat\n";
257         } elsif ( $type eq "M" ) {
258             # Middle marker entry
259             $has_mm = 1;
260             $mm_lon = make_dcoord( $F[16] );
261             $mm_lat = make_dcoord( $F[14] );
262             # print "$id MM $mm_lon $mm_lat\n";
263         } elsif ( $type eq "O" ) {
264             # Outer marker entry
265             $has_om = 1;
266             $om_lon = make_dcoord( $F[16] );
267             $om_lat = make_dcoord( $F[14] );
268             # print "$id OM $om_lon $om_lat\n";
269         }
270
271         $last_id = $id;
272         $last_rwy = $rwy;
273         # printf("%-5s %10.6f %11.6f\n",  $F[0], $F[14], $F[16]);
274     }
275
276     if ( ! $has_gs ) {
277         ( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
278     }
279     if ( ! $has_dme ) {
280         ( $dme_lat, $dme_lon ) = ( 0, 0 );
281     }
282     if ( ! $has_om ) {
283         ( $om_lat, $om_lon ) = ( 0, 0 );
284     }
285     if ( ! $has_mm ) {
286         ( $mm_lat, $mm_lon ) = ( 0, 0 );
287     }
288     if ( ! $has_im ) {
289         ( $im_lat, $im_lon ) = ( 0, 0 );
290     }
291     if ( $ILS{$Airports{$last_id} . $last_rwy} eq "" ) {
292         print "DAFIFT adding (last): $Airports{$last_id} - $last_rwy\n";
293         &safe_add_record( $Airports{$last_id}, $last_rwy, "ILS", $loc_freq,
294                           $loc_id, $loc_hdg, $loc_lat, $loc_lon,
295                           $gs_elev, $gs_angle, $gs_lat, $gs_lon,
296                           $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat,
297                           $mm_lon, $im_lat, $im_lon );
298     }
299 }
300
301
302 ########################################################################
303 # Process FlightGear ILS data
304 ########################################################################
305
306 sub load_fgfs() {
307     my( $ils_file ) = shift;
308
309     open( FGILS, "zcat $ils_file|" ) || die "Cannot open FGFS: $ils_file\n";
310
311     <FGILS>;                          # skip header line
312
313     while ( <FGILS> ) {
314         chomp;
315         if ( ! m/\[End\]/ && length($_) > 1 ) {
316             # print "$_\n";
317             my( $type_code, $type_name, $icao, $rwy, $loc_freq, $loc_id,
318                 $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
319                 $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
320                 $im_lat, $im_lon ) = split(/\s+/);
321             if ( $ILS{$icao . $rwy} eq "" ) {
322                 print "FGFS adding: $icao $rwy\n";
323                 $ILS{$icao . $rwy} = $_;
324             }
325         } else {
326             print "FGFS discarding: $_\n";
327         }
328     }
329 }
330
331
332 ########################################################################
333 # Write out the accumulated combined result
334 ########################################################################
335
336 sub write_result() {
337     my( $outfile ) = shift;
338
339     open( OUT, ">$outfile" )  || die "Cannot write to: $outfile\n";
340
341     # dump out the final results
342     print OUT "// FlightGear ILS data, generated from DAFIFT ARPT/ILS.TXT and FAA data\n";
343
344     my( $key );
345     foreach $key ( sort (keys %ILS) ) {
346         print OUT "$ILS{$key}\n";
347     }
348     print OUT "[End]\n";
349 }
350
351
352 ########################################################################
353 # Utility functions
354 ########################################################################
355
356
357 # add a record to the master list if it doesn't already exist
358
359 sub safe_add_record() {
360     my( $apt_id ) = shift;
361     my( $rwy ) = shift;
362     my( $type ) = shift;
363     my( $loc_freq ) = shift;
364     my( $loc_id ) = shift;
365     my( $loc_hdg ) = shift;
366     my( $loc_lat ) = shift;
367     my( $loc_lon ) = shift;
368     my( $gs_elev ) = shift;
369     my( $gs_angle ) = shift;
370     my( $gs_lat ) = shift;
371     my( $gs_lon ) = shift;
372     my( $dme_lat ) = shift;
373     my( $dme_lon ) = shift;
374     my( $om_lat ) = shift;
375     my( $om_lon ) = shift;
376     my( $mm_lat ) = shift;
377     my( $mm_lon ) = shift;
378     my( $im_lat ) = shift;
379     my( $im_lon ) = shift;
380
381     if ( $ILS{$apt_id . $rwy} eq "" ) {
382         # print "Safe adding (common): $apt_id - $rwy\n";
383         &update_record( $apt_id, $rwy, $type, $loc_freq, $loc_id,
384                         $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
385                         $gs_angle, $gs_lat, $gs_lon, $dme_lat,
386                         $dme_lon, $om_lat, $om_lon, $mm_lat,
387                         $mm_lon, $im_lat, $im_lon );
388     }
389 }
390
391
392 # replace a record in the master list (or add it if it doesn't exist)
393
394 sub update_record() {
395     my( $apt_id ) = shift;
396     my( $rwy ) = shift;
397     my( $type ) = shift;
398     my( $loc_freq ) = shift;
399     my( $loc_id ) = shift;
400     my( $loc_hdg ) = shift;
401     my( $loc_lat ) = shift;
402     my( $loc_lon ) = shift;
403     my( $gs_elev ) = shift;
404     my( $gs_angle ) = shift;
405     my( $gs_lat ) = shift;
406     my( $gs_lon ) = shift;
407     my( $dme_lat ) = shift;
408     my( $dme_lon ) = shift;
409     my( $om_lat ) = shift;
410     my( $om_lon ) = shift;
411     my( $mm_lat ) = shift;
412     my( $mm_lon ) = shift;
413     my( $im_lat ) = shift;
414     my( $im_lon ) = shift;
415
416     my( $record );
417
418     # remap $type as needed
419     $type = &strip_ws( $type );
420     if ( $type eq "LOCALIZER" ) {
421         $type = "LOC";
422     } elsif ( $type eq "ILS/DME" ) {
423         $type = "ILS";
424     } elsif ( $type eq "SDF/DME" ) {
425         $type = "SDF";
426     } elsif ( $type eq "LOC/DME" ) {
427         $type = "ILS";
428     } elsif ( $type eq "LOC/GS" ) {
429         $type = "LOC";
430     } elsif ( $type eq "LDA/DME" ) {
431         $type = "LDA";
432     }
433
434     $record = sprintf( "%1s %-5s %-4s %-3s  %06.2f %-4s %06.2f %10.6f %11.6f ",
435                        substr( $type, 0, 1 ), $type, $apt_id, $rwy,
436                        $loc_freq, $loc_id, $loc_hdg, $loc_lat, $loc_lon );
437     $record .= sprintf( "%5d %5.2f %10.6f %11.6f ",
438                         $gs_elev, $gs_angle, $gs_lat, $gs_lon );
439     $record .= sprintf( "%10.6f %11.6f ", $dme_lat, $dme_lon );
440     $record .= sprintf( "%10.6f %11.6f ", $om_lat, $om_lon );
441     $record .= sprintf( "%10.6f %11.6f ", $mm_lat, $mm_lon );
442     $record .= sprintf( "%10.6f %11.6f ", $im_lat, $im_lon );
443
444     # print "Updating (common): $apt_id - $rwy\n";
445     $ILS{$apt_id . $rwy} = $record;
446 }
447
448
449 # update the $type of the record
450 sub update_type() {
451     my( $apt_id ) = shift;
452     my( $rwy ) = shift;
453     my( $new_type ) = shift;
454
455     my( $record );
456
457     if ( $ILS{$apt_id . $rwy} ne "" ) {
458         my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
459             $loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
460             $gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
461             $im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
462         print "Updating type: $apt_id $rwy: $type_name -> $new_type\n";
463         $type_name = $new_type;
464         &update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
465                         $loc_hdg, $loc_lat, $loc_lon, $gs_elev,
466                         $gs_angle, $gs_lat, $gs_lon, $dme_lat,
467                         $dme_lon, $om_lat, $om_lon, $mm_lat,
468                         $mm_lon, $im_lat, $im_lon );
469     } else {
470         die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
471     }
472 }
473
474
475 # convert a lon/lat coordinate in various formats to signed decimal
476
477 sub make_dcoord() {
478     my($coord) = shift;
479     my( $dir, $deg, $min, $sec );
480     my( $value ) = 0.0;
481
482     $coord = &strip_ws( $coord );
483
484     if ( $coord =~ m/^[WE]/ ) {
485         ( $dir, $deg, $min, $sec )
486             = $coord =~ m/^([EW])(\d\d\d)(\d\d)(\d\d\d\d)/;
487         $value = $deg + $min/60.0 + ($sec/100)/3600.0;
488         if ( $dir eq "W" ) {
489             $value = -$value;
490         }
491     } elsif ( $coord =~ m/^[NS]/ ) {
492         ( $dir, $deg, $min, $sec )
493             = $coord =~ m/^([NS])(\d\d)(\d\d)(\d\d\d\d)/;
494         $value = $deg + $min/60.0 + ($sec/100)/3600.0;
495         if ( $dir eq "S" ) {
496             $value = -$value;
497         }
498     } elsif ( $coord =~ m/[EW]$/ ) {
499         ($value, $dir) = $coord =~ m/([\d\s\.]+)([EW])/;
500         if ( $dir eq "W" ) {
501             $value = -$value;
502         }
503     } elsif ( $coord =~ m/[NS]$/ ) {
504         ($value, $dir) = $coord =~ m/([\d\s\.]+)([NS])/;
505         if ( $dir eq "S" ) {
506             $value = -$value;
507         }
508     }
509     # print "$dir $deg:$min:$sec = $value\n";
510     return $value;
511 }
512
513 # convert a magnetic variation in various formats to signed decimal
514
515 sub make_dmagvar() {
516     my( $coord ) = shift;
517     my( $value );
518
519     if ( $coord =~ m/^[EW]/ ) {
520         my( $dir, $deg, $min, $date )
521             = $coord =~ m/^([EW])(\d\d\d)(\d\d\d) (\d\d\d\d)/;
522         $value = $deg + ($min/10)/60.0;
523         if ( $dir eq "W" ) {
524             $value = -$value;
525         }
526     } elsif ( $coord =~ m/[EW]$/ ) {
527         my( $deg, $dir )
528             = $coord =~ m/^(\d\d)([EW])/;
529         $value = $deg;
530         if ( $dir eq "W" ) {
531             $value = -$value;
532         }
533     }
534     # print "$dir $deg:$min = $value\n";
535
536     return $value;
537 }
538
539 # strip white space off front and back of string
540
541 sub strip_ws() {
542     my( $string ) = shift;
543     $string =~ s/^\s+//;
544     $string =~ s/\s+$//;
545     return $string;
546 }