1
0
Fork 0
flightgear/scripts/perl/dafif/dafift2ils.pl
curt 206b10d400 Tweaks to handle odd data cases. Load existing flightgear data at end
to preserve any non-usa approaches that are missing from the FAA data or
the DAFIFT data (these should be checked against current charts to verify
that these still exist and aren't being incorrectly carried along.)
2003-04-16 20:41:12 +00:00

564 lines
19 KiB
Perl
Executable file

#!/usr/bin/perl
########################################################################
# Convert DAFIFT ARPT/ILS.TXT to FlightGear format.
########################################################################
use strict;
my($faa_ils_file) = shift(@ARGV);
my($dafift_arpt_file) = shift(@ARGV);
my($dafift_ils_file) = shift(@ARGV);
my($fgfs_ils_file) = shift(@ARGV);
my($output_file) = shift(@ARGV);
die "Usage: $0 " .
"<faa_ils_file> <dafift_arpt_file> <dafift_ils_file> <fgfs_ils_file> <output_file>\n"
if !defined($faa_ils_file) || !defined($dafift_arpt_file)
|| !defined($dafift_ils_file) || !defined($fgfs_ils_file)
|| !defined($output_file);
my( %CODES );
my( %CodesByICAO );
my( %ILS );
my( %AIRPORTS );
&load_dafift( $dafift_arpt_file, $dafift_ils_file );
&load_faa( $faa_ils_file );
&load_fgfs( $fgfs_ils_file );
&write_result( $output_file );
exit;
########################################################################
# Process DAFIFT data
########################################################################
sub load_dafift() {
my( $arpt_file ) = shift;
my( $ils_file ) = shift;
my( $record );
my( $id, $rwy, $type );
my( $has_dme, $has_gs, $has_loc, $has_im, $has_mm, $has_om );
my( $dme_lon, $dme_lat, $dme_elev, $dme_bias );
my( $gs_lon, $gs_lat, $gs_elev, $gs_angle );
my( $loc_type, $loc_lon, $loc_lat, $loc_elev, $loc_freq, $loc_hdg,
$loc_width, $loc_id );
my( $im_lon, $im_lat, $mm_lon, $mm_lat, $om_lon, $om_lat );
# load airport file so we can lookup ICAO from internal ID
open( ARPT, "<$arpt_file" ) || die "Cannot open DAFIFT: $arpt_file\n";
<ARPT>; # skip header line
while ( <ARPT> ) {
chomp;
my(@F) = split(/\t/);
my($icao) = $F[3];
if ( length($icao) < 3 ) {
if ( length( $F[4] ) >= 3 ) {
$icao = $F[4];
} else {
$icao = "[none]";
}
}
$CODES{$F[0]} = $icao;
$CodesByICAO{$icao} = 1;
# print "$F[0] - $icao\n";
}
# Load the DAFIFT ils file
my( $last_id, $last_rwy ) = ("", "");
open( DAFIFT_ILS, "<$ils_file" ) || die "Cannot open DAFIFT: $ils_file\n";
<DAFIFT_ILS>; # skip header line
while ( <DAFIFT_ILS> ) {
chomp;
my @F = split(/\t/);
$id = $F[0];
$rwy = $F[1];
if ( $last_id ne "" && ($last_id ne $id || $last_rwy ne $rwy) ) {
# just hist the start of the next record, dump the current data
if ( ! $has_gs ) {
( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
}
if ( ! $has_dme ) {
( $dme_lat, $dme_lon ) = ( 0, 0 );
}
if ( ! $has_om ) {
( $om_lat, $om_lon ) = ( 0, 0 );
}
if ( ! $has_mm ) {
( $mm_lat, $mm_lon ) = ( 0, 0 );
}
if ( ! $has_im ) {
( $im_lat, $im_lon ) = ( 0, 0 );
}
if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
print "DAFIFT adding: $CODES{$last_id} - $last_rwy\n";
&safe_add_record( $CODES{$last_id}, $last_rwy, "ILS",
$loc_freq, $loc_id, $loc_hdg, $loc_lat,
$loc_lon, $gs_elev, $gs_angle, $gs_lat,
$gs_lon, $dme_lat, $dme_lon, $om_lat,
$om_lon, $mm_lat, $mm_lon, $im_lat,
$im_lon );
}
$has_dme = 0;
$has_gs = 0;
$has_loc = 0;
$has_im = 0;
$has_mm = 0;
$has_om = 0;
}
$type = $F[2];
if ( $type eq "D" ) {
# DME entry
$has_dme = 1;
$dme_lon = make_dcoord( $F[16] );
$dme_lat = make_dcoord( $F[14] );
$dme_elev = $F[10];
if ( $dme_elev !~ m/\d/ ) {
$dme_elev = "";
} else {
$dme_elev += 0;
}
$dme_bias = $F[27];
# print "$id DME $dme_lon $dme_lat $dme_elev $dme_bias\n";
} elsif ( $type eq "G" ) {
# GlideSlope entry
$has_gs = 1;
$gs_lon = make_dcoord( $F[16] );
$gs_lat = make_dcoord( $F[14] );
$gs_elev = $F[10];
if ( $gs_elev !~ m/\d/ ) {
$gs_elev = "";
} else {
$gs_elev += 0;
}
$gs_angle = $F[7];
# print "$id GS $gs_lon $gs_lat $gs_elev $gs_angle\n";
} elsif ( $type eq "Z" ) {
# Localizer entry
$has_loc = 1;
$loc_lon = make_dcoord( $F[16] );
$loc_lat = make_dcoord( $F[14] );
$loc_elev = $F[10];
if ( $loc_elev !~ m/\d/ ) {
$loc_elev = "";
} else {
$loc_elev += 0;
}
($loc_freq) = $F[5] =~ m/(\d\d\d\d\d\d)/;
$loc_freq /= 1000.0;
my( $magvar ) = make_dmagvar( $F[22] );
# print "mag var = $F[22] (" . $magvar . ")\n";
$loc_hdg = $F[24] + make_dmagvar( $F[22] );
$loc_width = $F[25];
$loc_id = $F[18];
if ( length( $loc_id ) >= 4 ) {
$loc_id =~ s/^I//;
}
# print "$id LOC $loc_lon $loc_lat $loc_elev $loc_freq $loc_hdg $loc_width\n";
} elsif ( $type eq "I" ) {
# Inner marker entry
$has_im = 1;
$im_lon = make_dcoord( $F[16] );
$im_lat = make_dcoord( $F[14] );
# print "$id IM $im_lon $im_lat\n";
} elsif ( $type eq "M" ) {
# Middle marker entry
$has_mm = 1;
$mm_lon = make_dcoord( $F[16] );
$mm_lat = make_dcoord( $F[14] );
# print "$id MM $mm_lon $mm_lat\n";
} elsif ( $type eq "O" ) {
# Outer marker entry
$has_om = 1;
$om_lon = make_dcoord( $F[16] );
$om_lat = make_dcoord( $F[14] );
# print "$id OM $om_lon $om_lat\n";
}
$last_id = $id;
$last_rwy = $rwy;
# printf("%-5s %10.6f %11.6f\n", $F[0], $F[14], $F[16]);
}
if ( ! $has_gs ) {
( $gs_elev, $gs_angle, $gs_lat, $gs_lon ) = ( 0, 0, 0, 0 );
}
if ( ! $has_dme ) {
( $dme_lat, $dme_lon ) = ( 0, 0 );
}
if ( ! $has_om ) {
( $om_lat, $om_lon ) = ( 0, 0 );
}
if ( ! $has_mm ) {
( $mm_lat, $mm_lon ) = ( 0, 0 );
}
if ( ! $has_im ) {
( $im_lat, $im_lon ) = ( 0, 0 );
}
if ( $ILS{$CODES{$last_id} . $last_rwy} eq "" ) {
print "DAFIFT adding (last): $CODES{$last_id} - $last_rwy\n";
&safe_add_record( $CODES{$last_id}, $last_rwy, "ILS", $loc_freq,
$loc_id, $loc_hdg, $loc_lat, $loc_lon,
$gs_elev, $gs_angle, $gs_lat, $gs_lon,
$dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat,
$mm_lon, $im_lat, $im_lon );
}
}
########################################################################
# Process FAA data
########################################################################
sub load_faa() {
my( $file ) = shift;
open( FAA_ILS, "<$file" ) || die "Cannot open FAA data: $file\n";
<FAA_ILS>; # skip header line
while ( <FAA_ILS> ) {
chomp;
my ( $rec_type, $faa_id, $rwy, $type, $faa_date,
$faa_apt_name, $faa_city, $faa_st, $faa_state,
$faa_region, $id, $faa_len, $faa_wid, $faa_cat,
$faa_owner, $faa_operator, $faa_bearing, $faa_magvar,
$loc_type, $loc_id, $loc_freq, $faa_loc_latd,
$faa_loc_lats, $faa_loc_lond, $faa_loc_lons, $loc_width,
$faa_stop_dist, $faa_app_dist, $faa_gs_type, $gs_angle,
$faa_gs_freq, $faa_gs_latd, $faa_gs_lats, $faa_gs_lond,
$faa_gs_lons, $faa_gs_dist, $gs_elev, $faa_im_type,
$faa_im_latd, $faa_im_lats, $faa_im_lond, $faa_im_lons,
$faa_im_dist, $faa_mm_type, $faa_mm_id, $faa_mm_name,
$faa_mm_freq, $faa_mm_latd, $faa_mm_lats, $faa_mm_lond,
$faa_mm_lons, $faa_mm_dist, $faa_om_type, $faa_om_id,
$faa_om_name, $faa_om_freq, $faa_om_latd, $faa_om_lats,
$faa_om_lond, $faa_om_lons, $faa_om_dist,
$faa_om_backcourse, $faa_dme_channel, $faa_dme_latd,
$faa_dme_lats, $faa_dme_lond, $faa_dme_lons, $faa_dme_app_dist,
$faa_dme_stop_dist, $blank)
= $_ =~
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})/;
$id = &strip_ws( $id );
$rwy = &strip_ws( $rwy );
$rwy =~ s/\/$//;
$loc_id =~ s/^I-//;
my( $loc_hdg ) = $faa_bearing + make_dmagvar($faa_magvar);
my( $loc_lat ) = make_dcoord($faa_loc_lats) / 3600.0;
my( $loc_lon ) = make_dcoord($faa_loc_lons) / 3600.0;
# print "$loc_lon $loc_lat $faa_loc_lons $faa_loc_lats\n";
my( $gs_lat ) = make_dcoord($faa_gs_lats) / 3600.0;
my( $gs_lon ) = make_dcoord($faa_gs_lons) / 3600.0;
my( $im_lat ) = make_dcoord($faa_im_lats) / 3600.0;
my( $im_lon ) = make_dcoord($faa_im_lons) / 3600.0;
my( $mm_lat ) = make_dcoord($faa_mm_lats) / 3600.0;
my( $mm_lon ) = make_dcoord($faa_mm_lons) / 3600.0;
my( $om_lat ) = make_dcoord($faa_om_lats) / 3600.0;
my( $om_lon ) = make_dcoord($faa_om_lons) / 3600.0;
my( $dme_lat ) = make_dcoord($faa_dme_lats) / 3600.0;
my( $dme_lon ) = make_dcoord($faa_dme_lons) / 3600.0;
# my( $key );
# print "$id - $rwy\n";
# $key = $id . $rwy;
# print "-> $key -> $ILS{$key}\n";
# $key = "K" . $id . $rwy;
# print "-> $key -> $ILS{$key}\n";
if ( $rec_type eq "ILS1" ) {
if ( length( $id ) < 4 ) {
if ( $CodesByICAO{"K" . $id} ) {
$id = "K" . $id;
}
}
if ( $ILS{$id . $rwy} ne "" ) {
print "FAA updating: $id - $rwy $type\n";
&update_type( $id, $rwy, $type );
} else {
print "FAA adding: $id - $rwy\n";
&safe_add_record( $id, $rwy, $type, $loc_freq, $loc_id,
$loc_hdg, $loc_lat, $loc_lon, $gs_elev,
$gs_angle, $gs_lat, $gs_lon, $dme_lat,
$dme_lon, $om_lat, $om_lon, $mm_lat,
$mm_lon, $im_lat, $im_lon );
}
}
}
}
########################################################################
# Process FlightGear ILS data
########################################################################
sub load_fgfs() {
my( $ils_file ) = shift;
open( FGILS, "zcat $ils_file|" ) || die "Cannot open FGFS: $ils_file\n";
<FGILS>; # skip header line
while ( <FGILS> ) {
chomp;
if ( ! m/\[End\]/ && length($_) > 1 ) {
# print "$_\n";
my( $type_code, $type_name, $icao, $rwy, $loc_freq, $loc_id,
$loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
$gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
$im_lat, $im_lon ) = split(/\s+/);
my( $code ) = $icao;
$code =~ s/^K//;
if ( $ILS{$icao . $rwy} ne "" ) {
# skip approaches already in FAA or DAFIFT data
} elsif ( $AIRPORTS{$icao} != 1 && $AIRPORTS{$code} != 1 ) {
# skip approaches if the FAA or DAFIFT data has any other
# approach already for this airport. (Avoids carrying over
# extraneous data if an approach was deactivated or runway
# numbers were changed.)
} elsif ( length( $icao ) < 4 || $icao =~ m/^K/ ) {
# skip USA approaches not found in FAA or DAFIFT data
} else {
print "FGFS adding: $icao $rwy\n";
$ILS{$icao . $rwy} = $_;
}
} else {
print "FGFS discarding: $_\n";
}
}
}
########################################################################
# Write out the accumulated combined result
########################################################################
sub write_result() {
my( $outfile ) = shift;
open( OUT, ">$outfile" ) || die "Cannot write to: $outfile\n";
# dump out the final results
print OUT "// FlightGear ILS data, generated from DAFIFT ARPT/ILS.TXT and FAA data\n";
my( $key );
foreach $key ( sort (keys %ILS) ) {
print OUT "$ILS{$key}\n";
}
print OUT "[End]\n";
}
########################################################################
# Utility functions
########################################################################
# add a record to the master list if it doesn't already exist
sub safe_add_record() {
my( $apt_id ) = shift;
my( $rwy ) = shift;
my( $type ) = shift;
my( $loc_freq ) = shift;
my( $loc_id ) = shift;
my( $loc_hdg ) = shift;
my( $loc_lat ) = shift;
my( $loc_lon ) = shift;
my( $gs_elev ) = shift;
my( $gs_angle ) = shift;
my( $gs_lat ) = shift;
my( $gs_lon ) = shift;
my( $dme_lat ) = shift;
my( $dme_lon ) = shift;
my( $om_lat ) = shift;
my( $om_lon ) = shift;
my( $mm_lat ) = shift;
my( $mm_lon ) = shift;
my( $im_lat ) = shift;
my( $im_lon ) = shift;
if ( $ILS{$apt_id . $rwy} eq "" ) {
# print "Safe adding (common): $apt_id - $rwy\n";
&update_record( $apt_id, $rwy, $type, $loc_freq, $loc_id,
$loc_hdg, $loc_lat, $loc_lon, $gs_elev,
$gs_angle, $gs_lat, $gs_lon, $dme_lat,
$dme_lon, $om_lat, $om_lon, $mm_lat,
$mm_lon, $im_lat, $im_lon );
}
}
# replace a record in the master list (or add it if it doesn't exist)
sub update_record() {
my( $apt_id ) = shift;
my( $rwy ) = shift;
my( $type ) = shift;
my( $loc_freq ) = shift;
my( $loc_id ) = shift;
my( $loc_hdg ) = shift;
my( $loc_lat ) = shift;
my( $loc_lon ) = shift;
my( $gs_elev ) = shift;
my( $gs_angle ) = shift;
my( $gs_lat ) = shift;
my( $gs_lon ) = shift;
my( $dme_lat ) = shift;
my( $dme_lon ) = shift;
my( $om_lat ) = shift;
my( $om_lon ) = shift;
my( $mm_lat ) = shift;
my( $mm_lon ) = shift;
my( $im_lat ) = shift;
my( $im_lon ) = shift;
my( $record );
# remap $type as needed
$type = &strip_ws( $type );
if ( $type eq "LOCALIZER" ) {
$type = "LOC";
} elsif ( $type eq "ILS/DME" ) {
$type = "ILS";
} elsif ( $type eq "SDF/DME" ) {
$type = "SDF";
} elsif ( $type eq "LOC/DME" ) {
$type = "ILS";
} elsif ( $type eq "LOC/GS" ) {
$type = "LOC";
} elsif ( $type eq "LDA/DME" ) {
$type = "LDA";
}
$record = sprintf( "%1s %-5s %-4s %-3s %06.2f %-4s %06.2f %10.6f %11.6f ",
substr( $type, 0, 1 ), $type, $apt_id, $rwy,
$loc_freq, $loc_id, $loc_hdg, $loc_lat, $loc_lon );
$record .= sprintf( "%5d %5.2f %10.6f %11.6f ",
$gs_elev, $gs_angle, $gs_lat, $gs_lon );
$record .= sprintf( "%10.6f %11.6f ", $dme_lat, $dme_lon );
$record .= sprintf( "%10.6f %11.6f ", $om_lat, $om_lon );
$record .= sprintf( "%10.6f %11.6f ", $mm_lat, $mm_lon );
$record .= sprintf( "%10.6f %11.6f ", $im_lat, $im_lon );
# print "Updating (common): $apt_id - $rwy\n";
$ILS{$apt_id . $rwy} = $record;
$AIRPORTS{$apt_id} = 1;
}
# update the $type of the record
sub update_type() {
my( $apt_id ) = shift;
my( $rwy ) = shift;
my( $new_type ) = shift;
my( $record );
if ( $ILS{$apt_id . $rwy} ne "" ) {
my( $type_code, $type_name, $apt_id, $rwy, $loc_freq, $loc_id,
$loc_hdg, $loc_lat, $loc_lon, $gs_elev, $gs_angle, $gs_lat,
$gs_lon, $dme_lat, $dme_lon, $om_lat, $om_lon, $mm_lat, $mm_lon,
$im_lat, $im_lon ) = split( /\s+/, $ILS{$apt_id . $rwy} );
# print "Updating type: $apt_id $rwy: $type_name -> $new_type\n";
$type_name = $new_type;
&update_record( $apt_id, $rwy, $type_name, $loc_freq, $loc_id,
$loc_hdg, $loc_lat, $loc_lon, $gs_elev,
$gs_angle, $gs_lat, $gs_lon, $dme_lat,
$dme_lon, $om_lat, $om_lon, $mm_lat,
$mm_lon, $im_lat, $im_lon );
} else {
die "Error, trying to update $apt_id - $rwy which doesn't exist\n";
}
}
# convert a lon/lat coordinate in various formats to signed decimal
sub make_dcoord() {
my($coord) = shift;
my( $dir, $deg, $min, $sec );
my( $value ) = 0.0;
$coord = &strip_ws( $coord );
if ( $coord =~ m/^[WE]/ ) {
( $dir, $deg, $min, $sec )
= $coord =~ m/^([EW])(\d\d\d)(\d\d)(\d\d\d\d)/;
$value = $deg + $min/60.0 + ($sec/100)/3600.0;
if ( $dir eq "W" ) {
$value = -$value;
}
} elsif ( $coord =~ m/^[NS]/ ) {
( $dir, $deg, $min, $sec )
= $coord =~ m/^([NS])(\d\d)(\d\d)(\d\d\d\d)/;
$value = $deg + $min/60.0 + ($sec/100)/3600.0;
if ( $dir eq "S" ) {
$value = -$value;
}
} elsif ( $coord =~ m/[EW]$/ ) {
($value, $dir) = $coord =~ m/([\d\s\.]+)([EW])/;
if ( $dir eq "W" ) {
$value = -$value;
}
} elsif ( $coord =~ m/[NS]$/ ) {
($value, $dir) = $coord =~ m/([\d\s\.]+)([NS])/;
if ( $dir eq "S" ) {
$value = -$value;
}
}
# print "$dir $deg:$min:$sec = $value\n";
return $value;
}
# convert a magnetic variation in various formats to signed decimal
sub make_dmagvar() {
my( $coord ) = shift;
my( $value );
if ( $coord =~ m/^[EW]/ ) {
my( $dir, $deg, $min, $date )
= $coord =~ m/^([EW])(\d\d\d)(\d\d\d) (\d\d\d\d)/;
$value = $deg + ($min/10)/60.0;
if ( $dir eq "W" ) {
$value = -$value;
}
} elsif ( $coord =~ m/[EW]$/ ) {
my( $deg, $dir )
= $coord =~ m/^(\d\d)([EW])/;
$value = $deg;
if ( $dir eq "W" ) {
$value = -$value;
}
}
# print "$dir $deg:$min = $value\n";
return $value;
}
# strip white space off front and back of string
sub strip_ws() {
my( $string ) = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}