#!/usr/bin/perl -w # NAME: runways.pl # AIM: Given an ICAO, list the runways of that airport (if found) use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; ##use PerlIO::gzip; # FAILED TO INSTALL use IO::Uncompress::Gunzip qw($GunzipError); use Env qw(FG_ROOT); # pour lire HOME FG_HOME et FG_ROOT use Time::HiRes qw( gettimeofday tv_interval ); use Socket; use LWP::Simple; use Geo::METAR; use Date::Parse; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; require 'fg_wsg84.pl' or die "Unable to load fg_wsg84.pl ...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.3 2014-11-19"; my $load_log = 0; my $in_icao = ''; my $verbosity = 0; my $out_file = ''; my $add_all_runways = 0; my $def_root = "F:\\fgdata"; $def_root = "X:\\fgdata" if (-d "X:\\fgdata"); my $FGROOT = (exists $ENV{FG_ROOT})? $FG_ROOT : $def_root; ###my $FGROOT = $def_root; my $APTFILE = "$FGROOT/Airports/apt.dat.gz"; # le fichier contenant les aéroports my $NAVFILE = "$FGROOT/Navaids/nav.dat.gz"; # le fichier contenant les aides à la navigation my $aptdat = $APTFILE; # ### DEBUG ### my $debug_on = 0; my $def_file = 'KSFO'; ### program variables my @warnings = (); my $cwd = cwd(); my $KM2FEET = 3280.84; my $FEET2M = 0.3048; my $METARBASE = 'http://weather.noaa.gov/pub/data/observations/metar/stations/'; my %apt_runways = (); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = ; close INF; my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); my ($line,$inc,$lnn); $lnn = 0; foreach $line (@lines) { chomp $line; $lnn++; if ($line =~ /\s*#\s*include\s+(.+)$/) { $inc = $1; prt("$lnn: $inc\n"); } } } my @runways = (); sub fetch_url($) { # see gettaf01.pl my ($url) = shift; prt( "Fetching: $url\n" ) if (VERB9()); my $txt = get($url); my $met = ''; if ($txt && length($txt)) { $met = trim_metar_txt($txt); #$met = trim_all($txt); if (length($met)) { prt( "METAR: $met\n" ); } else { prt( "No METAR available for $url!\n" ) if (VERB5()); } } else { prt( "No METAR available for $url!\n" ) if (VERB5()); } return $met; } sub trim_metar_txt($) { my $met = shift; $met =~ s/\n/ /gm; $met =~ s/\r/ /gm; $met =~ s/\t/ /gm; $met = trim_all($met); return $met; } # divide in 4 quarants sub hdg_to_dir4($) { my $hdg = shift; my $dir = ''; if (($hdg >= 315) && ($hdg < 45)) { $dir = 'N'; } elsif (($hdg >= 45) && ($hdg < 135)) { $dir = 'E'; } elsif (($hdg >= 135) && ($hdg < 225)) { $dir = 'S'; } elsif (($hdg >= 225) && ($hdg < 315)) { $dir = 'W'; } return $dir; } sub hdg_to_dir8($) { my $dir = shift; if (($dir >= 337.5) && ($dir < 22.5)) { $dir = 'N'; } elsif (($dir >= 22.5) && ($dir < 67.5)) { $dir = 'NE'; } elsif (($dir >= 67.5) && ($dir < 112.5)) { $dir = 'E'; } elsif (($dir >= 112.5) && ($dir < 157.5)) { $dir = 'SE'; } elsif (($dir >= 157.5) && ($dir < 202.5)) { $dir = 'S'; } elsif (($dir >= 202.5) && ($dir < 247.5)) { $dir = 'SW'; } elsif (($dir >= 247.5) && ($dir < 292.5)) { $dir = 'W'; } elsif (($dir >= 292.5) && ($dir < 337.5)) { $dir = 'NW'; } return $dir; } sub bearing_diff($$) { my ($b1,$b2) = @_; my $d = ($b1 > $b2) ? $b1 - $b2 : $b2 - $b1; $d = 360 - $d if ($d > 180); return $d; } # offset 10 in runway array my %runway_surface = ( 1 => 'Asphalt', 2 => 'Concrete', 3 => 'Turf/grass', 4 => 'Dirt', 5 => 'Gravel', 6 => 'H-Asphalt', # helepad (big 'H' in the middle). 7 => 'H-Concrete', # helepad (big 'H' in the middle). 8 => 'H-Turf', # helepad (big 'H' in the middle). 9 => 'H-Dirt', # helepad (big 'H' in the middle). 10 => 'T-Asphalt', # taxiway - with yellow hold line across long axis (not available from WorldMaker). 11 => 'T-Concrete', # taxiway - with yellow hold line across long axis (not available from WorldMaker). 12 => 'Dry Lakebed', # (eg. at KEDW Edwards AFB). 13 => 'Water' # runways (marked with bobbing buoys) for seaplane/floatplane bases (available in X-Plane 7.0 and later). ); sub get_metar_wind() { my $file = $perl_dir."\\temp.$in_icao.TXT"; my $url = $METARBASE.$in_icao.".TXT"; my $met = fetch_url($url); my %rwys = (); if (length($met)) { $met = trim_metar_txt($met); my $m = new Geo::METAR; $m->metar($met); ##my @arr = keys(%{$m}); # WIND_DIR_DEG = 280 # WIND_DIR_ENG = West # WIND_KTS = 03 kt 3.5 mph if (defined ${$m}{'WIND_DIR_DEG'}) { my $degs = ${$m}{'WIND_DIR_DEG'}; $degs = trim_all($degs); if ($degs =~ /^\d+$/) { prt(sprintf("Wind: %d degrees",$degs)); my $wdir = hdg_to_dir4($degs); my $wdir8 = hdg_to_dir8($degs); if ($wdir eq $wdir8) { prt(" ($wdir8)"); } else { prt(" ($wdir-$wdir8)"); } if (defined ${$m}{WIND_KTS}) { my $kts = ${$m}{WIND_KTS}; prt(", at $kts knots"); } prt("\n"); my $rcnt = scalar @runways; my ($ra); my ($rlen,$hdg,$rlet1,$rlet2,$hdgr,$surf); my ($rdir1,$rdir2,$i,$fnd); if ($rcnt) { ## 0 1 2 3 4 5 #push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf); for ($i = 0; $i < $rcnt; $i++) { # little choice - just choose end closes into wind $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $rlen = ${$ra}[4]; $surf = ${$ra}[5]; $surf = $runway_surface{$surf} if (defined $runway_surface{$surf}); $rdir1 = hdg_to_dir8($hdg); $rdir2 = hdg_to_dir8($hdgr); if ($wdir8 eq $rdir1) { $hdg = int($hdg + 0.5); prt("Rwy: $rlet1 ($hdg)"); if (! defined $rwys{$rlet1}) { prt(" $rlen ft. $surf"); } prt("\n"); $rwys{$rlet1} = 1; $rwys{$rlet2} = 1; $fnd++; } elsif ($wdir8 eq $rdir2) { $hdgr = int($hdgr + 0.5); prt("Rwy: $rlet2 ($hdgr)"); if (! defined $rwys{$rlet2}) { prt(" $rlen ft. $surf"); } prt("\n"); $rwys{$rlet1} = 1; $rwys{$rlet2} = 1; $fnd++; } } if (!$fnd) { for ($i = 0; $i < $rcnt; $i++) { # little choice - just choose end closes into wind $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $rlen = ${$ra}[4]; $surf = ${$ra}[5]; $surf = $runway_surface{$surf} if (defined $runway_surface{$surf}); $rdir1 = hdg_to_dir4($hdg); $rdir2 = hdg_to_dir4($hdgr); if ($wdir eq $rdir1) { $hdg = int($hdg + 0.5); prt("rwy: $rlet1 ($hdg)"); if (! defined $rwys{$rlet1}) { prt(" $rlen ft. $surf"); } prt("\n"); $rwys{$rlet1} = 1; $rwys{$rlet2} = 1; $fnd++; } elsif ($wdir eq $rdir2) { $hdgr = int($hdgr + 0.5); prt("rwy: $rlet2 ($hdgr)"); if (! defined $rwys{$rlet2}) { prt(" $rlen ft. $surf"); } prt("\n"); $rwys{$rlet1} = 1; $rwys{$rlet2} = 1; $fnd++; } } } if (!$fnd) { if ($add_all_runways) { for ($i = 0; $i < $rcnt; $i++) { # no choice - show all $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $rlen = ${$ra}[4]; $surf = ${$ra}[5]; $surf = $runway_surface{$surf} if (defined $runway_surface{$surf}); $rdir1 = hdg_to_dir4($hdg); $rdir2 = hdg_to_dir4($hdgr); if ($wdir eq $rdir1) { #prt(", rwy: $rlet1 ($hdg)"); } elsif ($wdir eq $rdir2) { #prt(", rwy: $rlet2 ($hdgr)"); } else { $rdir1 = hdg_to_dir8($hdg); $rdir2 = hdg_to_dir8($hdgr); if ($wdir8 eq $rdir1) { #prt(", rwy: $rlet1 ($hdg)"); } elsif ($wdir8 eq $rdir2) { #prt(", rwy: $rlet2 ($hdgr)"); } else { # cross wind $hdg = int($hdg + 0.5); $hdgr = int($hdgr + 0.5); prt("RWY: $rlet1 ($hdg) or $rlet2 ($hdgr)"); if (! defined $rwys{$rlet1}) { prt(" $rlen ft. $surf"); } prt("\n"); $rwys{$rlet1} = 1; $rwys{$rlet2} = 1; } } } } else { prt("no rwy matching! "); my $min_d = 360; my $min_i = 0; my $min_12 = 0; my ($d); for ($i = 0; $i < $rcnt; $i++) { $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $d = bearing_diff($degs,$hdg); if ($d < $min_d) { $min_d = $d; $min_i = $i; $min_12 = 1; } $d = bearing_diff($degs,$hdgr); if ($d < $min_d) { $min_d = $d; $min_i = $i; $min_12 = 2; } } $i = $min_i; $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $rdir1 = hdg_to_dir8($hdg); $rdir2 = hdg_to_dir8($hdgr); if ($min_12 == 1) { $hdg = int($hdg + 0.5); prt("closest $rlet1 $rdir1 $hdg "); } else { $hdgr = int($hdgr + 0.5); prt("closest $rlet2 $rdir2 $hdgr "); } prt("\n"); if (VERB1()) { my %dupes = (); for ($i = 0; $i < $rcnt; $i++) { # no choice - show all $ra = $runways[$i]; $rlet1 = ${$ra}[0]; $hdg = ${$ra}[1]; $rlet2 = ${$ra}[2]; $hdgr = ${$ra}[3]; $rdir1 = hdg_to_dir4($hdg); $rdir2 = hdg_to_dir4($hdgr); if (!defined $dupes{$rdir1}) { $hdg = int($hdg + 0.5); prt("$rlet1 $hdg $rdir1 "); $dupes{$rdir1} = 1; } if (!defined $dupes{$rdir2}) { $hdgr = int($hdgr + 0.5); prt("$rlet2 $hdgr $rdir2 "); $dupes{$rdir2} = 1; } $hdg = ${$ra}[1]; $hdgr = ${$ra}[3]; $rdir1 = hdg_to_dir8($hdg); $rdir2 = hdg_to_dir8($hdgr); if (!defined $dupes{$rdir1}) { $hdg = int($hdg + 0.5); prt("$rlet1 $hdg $rdir1 "); $dupes{$rdir1} = 1; } if (!defined $dupes{$rdir2}) { $hdgr = int($hdgr + 0.5); prt("$rlet2 $hdgr $rdir2 "); $dupes{$rdir2} = 1; } } prt("\n"); } } } } } else { prt("Wind: $degs NN\n"); } #prt("\n"); } } else { prt("Failed to get $url!\n") if (VERB9()); } } my %off2name2 = ( 0 => 'ATIS', 1 => 'UNICOM', 2 => 'CLR', 3 => 'GRD', 4 => 'TWR', 5 => 'APP', 6 => 'DEP' ); # 12345678901234567890123456 # -37.60451900,-122.38223600 sub get_ll_stg($$) { my ($lat,$lon) = @_; my $stg = sprintf("%.8f,%.8f",$lat,$lon); $stg .= ' ' while (length($stg) < 26); return $stg; } my @apt = (); # 0 1 2 3 4 5 6 7 8 # push(@g_navaids, [$typ, $nlat, $nlon, $nalt, $nfrq, $nrng, $nfrq2, $nid, $name, 0, 0, 0, 0] ); my @g_navaids = (); my %nav_types = ( 2 => 'NDB', 3 => 'VOR', 4 => 'ILS', 5 => 'LOC', 6 => 'GS', 7 => 'OM', 8 => 'MM', 9 => 'IM', 12 => 'VDME', 13 => 'NDME' ); sub search_nav_data() { my $icao = $in_icao; my $max = scalar @g_navaids; my ($i,$ra,$nid,$name,$typ,$nfrq,$msg); my ($nlat,$nlon,$nalt,$nrng,$line,@arr,$rlets,$rhdg); prt("Searching $max navaids for ICAO $icao\n") if (VERB5()); my %freq = (); # $apt_runways{$rlet1} = $hdg; # $apt_runways{$rlet2} = $hdgr; # ILS 37.60451900,-122.38223600 10 ft. 108.90 18 nm. ISIA KSFO 19L ILS-cat-I my $hdr = "typ latitude longitude alt ft. freq. range id name"; for ($i = 0; $i < $max; $i++) { $ra = $g_navaids[$i]; $typ = ${$ra}[0]; next if (($typ == 6)||($typ == 7)||($typ == 8)||($typ == 9)); # skip GS and Markers $nid = ${$ra}[7]; $name = ${$ra}[8]; if ($name =~ /^$icao/) { # ($nid eq $icao) { @arr = split(/\s+/,$name); $nfrq = ${$ra}[4]; next if (defined $freq{$nfrq}); $freq{$nfrq} = 1; $nlat = ${$ra}[1]; $nlon = ${$ra}[2]; $nalt = ${$ra}[3]; $nrng = ${$ra}[5]; $msg = ''; if ($typ == 4) { # ILS $rlets = $arr[1]; if (defined $apt_runways{$rlets}) { $rhdg = $apt_runways{$rlets}; $rhdg = int($rhdg + 0.5); $msg = "b=$rhdg"; } } # display # ILS 37.60451900,-122.38223600 10 ft. 108.90 18 nm. ISIA KSFO 19L ILS-cat-I # prt(join(" ",@{$ra})."\n"); $typ = $nav_types{$typ} if (defined $nav_types{$typ}); $typ .= ' ' while (length($typ) < 4); $nid .= ' ' while (length($nid) < 4); $line = "$typ "; $line .= get_ll_stg($nlat,$nlon); $line .= sprintf(" %4d ft. ",$nalt); $line .= sprintf("%6.2f",$nfrq / 100); $line .= sprintf(" %3d nm.",$nrng); $line .= " $nid $name $msg"; prt("$hdr\n") if (length($hdr)); $hdr = ''; prt("$line\n"); } } } sub load_nav_data() { my $t1 = [gettimeofday]; prt("\n[v5] Loading $NAVFILE file ...\n") if (VERB5()); die "ERROR: Can NOT stat '$NAVFILE'!\n" if ( !( -f $NAVFILE) ); open NIF, "gzip -d -c $NAVFILE|" or die "ERROR: CAN NOT OPEN $NAVFILE...$!...\n"; my @nav_lines = ; close NIF; my $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) ); prt("[v5] Got ".scalar @nav_lines." lines in $elap...\n") if (VERB5()); my ($line,@arr,$nc,$i,$len); my ($typ,$nlat,$nlon,$nalt,$nfrq,$nrng,$nfrq2,$nid,$name); foreach $line (@nav_lines) { chomp $line; $line = trim_all($line); $len = length($line); next if ($line =~ /\s+Version\s+/i); next if ($line =~ /^I/); next if ($len == 0); # 0 1 (lat) 2 (lon) 3(alt) 4(feq) 5(rng) 6 7 8++ # 2 38.087769 -077.324919 284 396 25 0.000 APH A P Hill NDB # 3 57.103719 009.995578 57 11670 100 1.000 AAL Aalborg VORTAC # 4 39.980911 -075.877814 660 10850 18 281.662 IMQS 40N 29 ILS-cat-I # 4 -09.458922 147.231225 128 11010 18 148.650 IWG AYPY 14L ILS-cat-I # 5 40.034606 -079.023281 2272 10870 18 236.086 ISOZ 2G9 24 LOC # 5 67.018506 -050.682072 165 10955 18 61.600 ISF BGSF 10 LOC # 6 39.977294 -075.860275 655 10850 10 300281.205 --- 40N 29 GS # 6 -09.432703 147.216444 128 11010 10 302148.785 --- AYPY 14L GS # 7 39.960719 -075.750778 660 0 0 281.205 --- 40N 29 OM # 7 -09.376150 147.176867 146 0 0 148.785 JSN AYPY 14L OM # 8 -09.421875 147.208331 91 0 0 148.785 MM AYPY 14L MM # 8 -09.461050 147.232544 146 0 0 328.777 PY AYPY 32R MM # 9 65.609444 -018.052222 32 0 0 22.093 --- BIAR 01 IM # 9 08.425319 004.475597 1126 0 0 49.252 IL DNIL 05 IM # 12 -09.432703 147.216444 11 11010 18 0.000 IWG AYPY 14L DME-ILS # 12 -09.449222 147.226589 11 10950 18 0.000 IBB AYPY 32R DME-ILS @arr = split(/\s+/,$line); $nc = scalar @arr; $typ = $arr[0]; last if ($typ == 99); if ($nc < 8) { prt("Type: [$typ] - Handle this line [$line] - count = $nc...\n"); pgm_exit(1,"ERROR: FIX ME FIRST!\n"); } $nlat = $arr[1]; $nlon = $arr[2]; $nalt = $arr[3]; $nfrq = $arr[4]; $nrng = $arr[5]; $nfrq2 = $arr[6]; $nid = $arr[7]; $name = ''; for ($i = 8; $i < $nc; $i++) { $name .= ' ' if length($name); $name .= $arr[$i]; } # 0 1 2 3 4 5 6 7 8 push(@g_navaids, [$typ, $nlat, $nlon, $nalt, $nfrq, $nrng, $nfrq2, $nid, $name, 0, 0, 0, 0] ); } $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) ); prt("[v5] Got ".scalar @g_navaids." navaids in $elap...\n") if (VERB5()); } sub show_apt() { my $icao = $in_icao; my ($i,$max,$ra,$typ,$line,@arr); my ($aalt,$actl,$abld,$anam,$rfa); my ($rlat1,$rlon1,$rlat2,$rlon2,$rlat,$rlon); my ($rlen,$hdg,$az2,$res,$s,$rlet1,$rlet2,$hdgr,$rwid,$surf); my ($alat,$alon,$tmp); my %freqs = (); my $glat = 0; my $glon = 0; my $rwcnt = 0; my $gottwr = 0; $max = scalar @apt; if (!$max) { prt("No airport to show...\n"); return; } for ($i = 0; $i < $max; $i++) { $ra = $apt[$i]; ###prt(join(" ",@{$ra})."\n"); $typ = ${$ra}[0]; if ($typ == 1) { $aalt = ${$ra}[1]; $actl = ${$ra}[2]; # control tower $abld = ${$ra}[3]; # buildings #$icao = ${$ra}[4]; $anam = join(' ', splice(@{$ra},5)); } elsif ($typ == 14) { # Tower viewpoints Example Usage # 14 Identifies this as a data line for a tower viewpoint (code 14).Only a single tower viewpoint is permitted. # 35.047005 Latitude (in decimal degrees) of the viewpoint. # -106.608162 Longitude (in decimal degrees) of the viewpoint. # 100 Height (in feet) above ground level of viewpoint. # 1 Flag to indicate if a control tower object should be drawn at this location in X-Plane. 0=no tower, 1=draw tower. # Tower viewpoint Name of this viewpoint $gottwr = 1; $alat = ${$ra}[1]; $alon = ${$ra}[2]; } elsif ($typ == 10) { # @runways reference # 0 1=lat 2=lon 3=s 4=hdg 5=len 6=offsets 7=stopway 8=wid 9=lights 10=surf 11 12 13 14 15 # 10 36.962213 127.031071 14x 131.52 8208 1595.0620 0000.0000 150 321321 1 0 3 0.25 0 0300.0300 # 11=shoulder 12=marks 13=smooth 14=signs 15=GS angles # 0 3 0.25 0 0300.0300 $rlet1 = ${$ra}[3]; $rlet1 =~ /(..)(.)/; $rlet2 = ($1 > 18) ? $1 - 18 : $1 + 18; $rlet2 = "0".$rlet2 if ($rlet2 < 10); if ($2) { $rlet2 .= 'L' if ($2 eq 'R'); $rlet2 .= 'R' if ($2 eq 'L'); $rlet2 .= 'C' if ($2 eq 'C'); } $hdg = ${$ra}[4]; $hdgr = $hdg + 180; $hdgr -= 360 if ($hdgr >= 360); $rlen = ${$ra}[5]; # length, in feet $rlat = ${$ra}[1]; $rlon = ${$ra}[2]; $glat += $rlat; $glon += $rlon; $rwcnt++; $surf = ${$ra}[10]; # add surface type fg_geo_direct_wgs_84( $rlat, $rlon, $hdg , ($rlen * $FEET2M), \$rlat1, \$rlon1, \$az2 ); fg_geo_direct_wgs_84( $rlat, $rlon, $hdgr, ($rlen * $FEET2M), \$rlat2, \$rlon2, \$az2 ); push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf]); $apt_runways{$rlet1} = $hdg; $apt_runways{$rlet2} = $hdgr; # build display $rlet1 .= ' ' while (length($rlet1) < 3); $rlet2 .= ' ' while (length($rlet2) < 3); $hdg = int($hdg + 0.5); $hdgr = int($hdgr + 0.5); $line = "$rlet1 ".get_ll_stg($rlat1,$rlon1); $line .= " $rlet2 ".get_ll_stg($rlat2,$rlon2); $line .= " b=$hdg/$az2 l=$rlen ft"; if (defined $runway_surface{$surf}) { $line .= " (".$runway_surface{$surf}.")"; } prt("$line\n"); } elsif ($typ == 100) { # 10L: 37.62872250,-122.39342127 28R: 37.61351918,-122.35716907 b=118/298 l=11870 ft (Asphalt) # 10R: 37.62527727,-122.39074787 28L: 37.61169441,-122.35837447 b=118/298 l=10601 ft (Asphalt) # 01R: 37.60620279,-122.38114713 19L: 37.62781186,-122.36681630 b=28/208 l=8896 ft (Asphalt) # 01L: 37.60897310,-122.38223043 19R: 37.62719258,-122.37015433 b=28/208 l=7500 ft (Asphalt) $rwid = ${$ra}[1]; # WIDTH in meters? NOT SHOWN $surf = ${$ra}[2]; # add surface type $rlet1 = ${$ra}[8]; $rlat1 = ${$ra}[9]; # $of_lat1 $rlon1 = ${$ra}[10]; # $of_lon1 $rlet2 = ${$ra}[17]; $rlat2 = ${$ra}[18]; # $of_lat2 $rlon2 = ${$ra}[19]; # $of_lon2 $rlat = ($rlat1 + $rlat2) / 2; $rlon = ($rlon1 + $rlon2) / 2; $glat += $rlat; $glon += $rlon; $rwcnt++; $res = fg_geo_inverse_wgs_84($rlat1, $rlon1, $rlat2, $rlon2, \$hdg, \$az2, \$s); $hdgr = $az2; $rlen = int(($s / 1000) * $KM2FEET ); # runway length, in feet # 0 1 2 3 4 5 push(@runways,[$rlet1,$hdg,$rlet2,$hdgr,$rlen,$surf]); $apt_runways{$rlet1} = $hdg; $apt_runways{$rlet2} = $hdgr; # build display # runway markings - magnetic azimuth of the centerline $rlet1 .= ' ' while (length($rlet1) < 3); $rlet2 .= ' ' while (length($rlet2) < 3); $hdg = int($hdg + 0.5); $hdgr = int($hdgr + 0.5); $line = "$rlet1 ".get_ll_stg($rlat1,$rlon1); $line .= " $rlet2 ".get_ll_stg($rlat2,$rlon2); $line .= " b=$hdg/$hdgr l=$rlen ft"; if (defined $runway_surface{$surf}) { $line .= " (".$runway_surface{$surf}.")"; } prt("$line\n"); } elsif (($typ >= 50) && ($typ <= 56)) { $typ -= 50; $typ = $off2name2{$typ}; $freqs{$typ} = [] if (!defined $freqs{$typ}); $rfa = $freqs{$typ}; push(@{$rfa}, (${$ra}[1] / 100)); } } my $max_line = 100; @arr = sort keys %freqs; $line = "frqs: "; foreach $typ (@arr) { $line .= "$typ: "; $rfa = $freqs{$typ}; $tmp = join(" ",@{$rfa}).' '; if (length($line.$tmp) > $max_line) { prt("$line\n"); $line = " "; } $line .= $tmp; } prt("$line\n"); get_metar_wind(); load_nav_data(); search_nav_data(); $line = "$icao $anam "; if ($gottwr) { $line .= "twr: ".get_ll_stg($alat,$alon).' '; } elsif ($rwcnt) { $alat = $glat / $rwcnt; $alon = $glon / $rwcnt; $line .= "rc: ".get_ll_stg($alat,$alon).' '; } $line .= "$aalt ft. "; prt("$line\n"); } sub find_icao($) { my $icao = shift; my $t1 = [gettimeofday]; my ($ver,@arr,$typ,$line,$max,$add,$i,$ra); my $gotapt = 0; if ($os =~ /win/i) { $aptdat = path_u2d($aptdat); } else { $aptdat = path_d2u($aptdat); } if ( ! -f $aptdat ) { prt("Can NOT 'stat' $aptdat!\n"); prt("Versify the root folder $FGROOT\n"); prt("or use the option -a apt-file\n"); prt("or modify the script ver line 39/40\n"); pgm_exit(1,""); } prt("Opening file $aptdat...\n") if (VERB9()); ##open( APT, "gzip -d -c $aptdat|" ) or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" ); ##open( APT, ":gzip", $aptdat ) or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" ); my $APT = IO::Uncompress::Gunzip->new( $aptdat ) or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" ); while (<$APT>) { chomp; if (/^(\d+)\s+Version\s+/) { $ver = $1; last; } } if ($ver) { prt("Searching file $aptdat, version $ver... moment...\n") if (VERB1()); } else { close $APT; prt("Failed to find version in $aptdat!\n"); pgm_exit(1,""); } while ($line = <$APT>) { chomp $line; next if ($line =~ /^\s*$/); @arr = split(/\s+/,$line); $typ = $arr[0]; last if ($typ == 99); if ($typ == 1) { if ($arr[4] eq $icao) { $gotapt = 1; prt(join(" ",@arr)."\n") if (VERB9()); my @a1 = @arr; push(@apt,\@a1); while ($line = <$APT>) { chomp $line; next if ($line =~ /^\s*$/); @arr = split(/\s+/,$line); $typ = $arr[0]; last if ($typ == 1); last if ($typ == 99); $add = 0; if ($typ == 10) { if ($arr[3] ne 'xxx') { $add = 1; } } elsif ($typ == 14) { $add = 1; } elsif ($typ == 100) { $add = 1; } elsif (($typ >= 50) && ($typ <= 56)) { $add = 1; } if ($add) { my @a2 = @arr; push(@apt,\@a2); } } last; } } } $i = $.; close $APT; $max = scalar @apt; my $elap = secs_HHMMSS( tv_interval( $t1, [gettimeofday] ) ); prt("Found $max airport components... $i lines in $elap\n") if (VERB2()); if (!$gotapt) { prt("Failed to find airport $icao!\n"); return; } show_apt(); } sub gen_dirs() { my $dir = 360; my $inc = 22.5; my $max = $dir + $inc; $max -= 360 if ($max > 350); prt("\tif ((\$dir >= ".($dir - $inc).") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'N';\n"); $dir += $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 *$inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'NE';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'E';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'SE';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'S';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'SW';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'W';\n"); $dir += 2 * $inc; $dir -= 360 if ($dir >= 360); $max = $dir + (2 * $inc); $max -= 360 if ($max > 350); prt("\t} elsif ((\$dir >= ".$dir.") && (\$dir < ".$max.")) {\n"); prt("\t\t\$dir = 'NW';\n"); $dir += $inc; $dir -= 360 if ($dir >= 360); exit(1); } ######################################### ### MAIN ### ### gen_dirs(); parse_args(@ARGV); find_icao($in_icao); pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg); my $verb = VERB2(); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } $verb = VERB2(); prt("Verbosity = $verbosity\n") if ($verb); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if ($verb); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if ($verb); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_icao = $arg; prt("Set input to [$in_icao]\n") if ($verb); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_icao) == 0) { $in_icao = $def_file; prt("Set DEFAULT input to [$in_icao]\n"); } } if (length($in_icao) == 0) { pgm_exit(1,"ERROR: No input ICAO found in command!\n"); } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-icao\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --out (-o) = Write output to this file.\n"); prt(" Givan an ICAO, will search $APTFILE, "); if (-f $APTFILE) { prt("ok,\n"); } else { prt("NOT FOUND!\n"); } prt("and list the runways for that airport\n"); } # eof - template.pl