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