#!/usr/bin/perl -w # NAME: shwaptdatvers.pl # AIM: Given a valid apt.dat.gz file, show the version line # AIM: Chaned to given a valid x-palen apt.dat file, show the version line, AND # collect the airport lines and write a fg_apt.dat file... use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; 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.2 2017-07-18"; ##my $VERS = "0.0.1 2013-03-17"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; #my $out_file = ''; my $out_file = 'D:\FG\xplane\fg-nav-fixups\xplane-apts\out\fg_apt.dat'; my $max_lines = 10; my $max_len = 50; # use 102 to include copyright...; my $landcnt = 0; # 1 code my $seacnt = 0; # 16 code my $helecnt = 0; # 17 code # ### DEBUG ### my $debug_on = 1; my $def_file = 'D:\FG\xplane\fg-nav-fixups\xplane-apts\out\apt.dat'; ###my $def_file = 'X:/fgdata/Airports/apt.dat.gz'; ### program variables my @warnings = (); my $cwd = cwd(); my @g_naptlist = (); 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 not_in_world_range($$) { my ($lt,$ln) = @_; return 1 if ($lt < -90); return 1 if ($lt > 90); return 1 if ($ln < -180); return 1 if ($ln > 180); return 0; } sub ignore { } # put least first sub mycmp_ascend_n { return -1 if ($a < $b); return 1 if ($a > $b); return 0; } # sub load_apt_data { sub process_in_file($) { my ($inf) = @_; my ($cnt,$msg); prt("[v9] Loading $inf file ...\n") if (VERB9()); pgm_exit(1,"ERROR: Can NOT locate $inf ...$!...\n") if ( !( -f $inf) ); # these failed # $SIG{INT} = \&ignore; # $SIG{PIPE} = 'IGNORE'; # use gzip with -d decompress, -c write to stdout ###open INF, "gzip -d -c $inf|" or pgm_exit(1, "ERROR: CAN NOT OPEN $inf... $!...\n" ); open INF, $inf or pgm_exit(1, "ERROR: CAN NOT OPEN $inf... $!...\n" ); my ($line,$inc,$lnn,$len,$fnd,@arr,$code,$type,$ftyp,$add); my ($OF); $lnn = 0; $fnd = 0; my $lncnt = 0; my %codes = (); my $apt = ''; my $got_twr = 0; my ($alat,$alon,$trwycnt); my ($rlat1,$rlon1,$rlat2,$rlon2,$rlat,$rlon); my ($icao,$name); my $rwycnt = 0; my $wwcnt = 0; my $padcnt = 0; my $keep = 0; my @runways = (); # clear RUNWAY list my @waterways = (); # clear RUNWAY list my @heliways = (); # clear RUNWAY list my @freqs = (); # clear frequencies my $glat = 0; my $glon = 0; my $got_out = 0; if (length($out_file)) { rename_2_old_bak($out_file); open $OF, ">$out_file" or pgm_exit(1,"Error: Failed to open out file $out_file!\n"); $line = lu_get_YYYYMMDD_hhmmss_UTC(time()); print $OF "I\n"; print $OF "1100 Version - Generated by $pgmname, on $line\n"; $got_out = 1; } # http://developer.x-plane.com/?article=airport-data-apt-dat-file-format-specification while ( $line = ) { $lncnt++; chomp $line; $line = trim_all($line); $lnn++; $len = length($line); next if ($len == 0); # if ($line =~ /Version/i) { if ($line =~ /Generated/i) { $inc = ($len > $max_len) ? substr($line,0,$max_len) : $line; prt("$lnn: $inc\n"); $fnd = 1; last; } # last if $. > $max_lines; } while ($line = ) { $lncnt++; chomp $line; $line = trim_all($line); $lnn++; $len = length($line); next if ($len == 0); @arr = split(/\s+/,$line); $code = $arr[0]; if (defined $codes{$code}) { $codes{$code}++; } else { $codes{$code} = 1; } $type = $code; $keep = 0; if ($type == 99) { last; } elsif (($type == 1)||($type == 16)||($type == 17)) { # start with 1, 16, 17 if (length($apt)) { # add airport $trwycnt = $rwycnt; $trwycnt += $wwcnt; $trwycnt += $padcnt; if ($trwycnt > 0) { if (!$got_twr) { # average position $alat = $glat / $trwycnt; $alon = $glon / $trwycnt; } my @arr2 = split(/\s+/,$apt); my $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL my $actl = $arr2[2]; # control tower my $abld = $arr2[3]; # buildings my $diff = 0; $icao = $arr2[4]; # ICAO $name = join(' ', splice(@arr2,5)); # Name ##prt("$diff [$apt] (with $rwycnt runways at [$alat, $alon]) ...\n"); ##prt("$diff [$icao] [$name] ...\n"); my @ra = @runways; my @wa = @waterways; my @ha = @heliways; my @fa = @freqs; # 0 1 2 3 4 5 6 7 8 push(@g_naptlist, [$diff, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa ]); } else { prtw("Warning: Apt with NO RUNWAYS!\n$apt\n"); } } #################################################################### ### Start an airport record if ($type == 1) { $landcnt++; # 1 code } elsif ($type == 16) { $seacnt++; } elsif ($type == 17) { $helecnt++; } else { prt("$lnn: $line\n"); pgm_exit(1, "Can NOT happen!\n"); } $apt = $line; $got_twr = 0; $rwycnt = 0; $wwcnt = 0; $padcnt = 0; @runways = (); # clear RUNWAY list @waterways = (); # clear RUNWAY list @heliways = (); # clear RUNWAY list @freqs = (); # clear frequencies $glat = 0; $glon = 0; $keep = 1; } elsif (($type >= 50)&&($type <= 56)) { # frequencies $ftyp = $type - 50; #$cfrq = $arr[1]; #$frqn = $arr[2]; $add = 0; if ($ftyp == 0) { $add = 1; # ATIS } elsif ($ftyp == 1) { $add = 1; # Unicom } elsif ($ftyp == 2) { $add = 1; # clearance } elsif ($ftyp == 3) { $add = 1; # ground } elsif ($ftyp == 4) { $add = 1; # tower } elsif ($ftyp == 5) { $add = 1; # approach } elsif ($ftyp == 6) { $add = 1; # departure } else { pgm_exit(1,"$lnn: Unknown [$line] *** FIX ME ***\n"); } if ($add) { my @a2 = @arr; push(@freqs, \@a2); # save the freq array #} else { # pgm_exit(1, "WHAT IS THIS [5$ftyp $cfrq $frqn] [$line]\n FIX ME!!!"); } $keep = 1; } elsif ($type == 14) { # tower location # 14 52.911007 156.878342 0 0 Tower Viewpoint $got_twr = 1; $alat = $arr[1]; $alon = $arr[2]; $keep = 1; } elsif ($type == 100) { # Land Runway # See full version 1000 specs below # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 100 29.87 3 0 0.00 1 2 1 16 43.91080605 004.90321905 0.00 0.00 2 0 0 0 34 43.90662331 004.90428974 0.00 0.00 2 0 0 0 $rlat1 = $arr[9]; # $of_lat1 $rlon1 = $arr[10]; # $of_lon1 $rlat2 = $arr[18]; # $of_lat2 $rlon2 = $arr[19]; # $of_lon2 $rlat = ($rlat1 + $rlat2) / 2; $rlon = ($rlon1 + $rlon2) / 2; ###prt( "$line [$rlat, $rlon]\n" ); $glat += $rlat; $glon += $rlon; my @a2 = @arr; push(@runways, \@a2); $rwycnt++; $keep = 1; } elsif ($type == 101) { # Water runways # 0 1 2 3 4 5 6 7 8 # 101 243.84 0 16 29.27763293 -089.35826258 34 29.26458929 -089.35340410 # 101 22.86 0 07 29.12988952 -089.39561501 25 29.13389936 -089.38060001 $rlat1 = $arr[4]; $rlon1 = $arr[5]; $rlat2 = $arr[7]; $rlon2 = $arr[8]; $rlat = sprintf("%.8f",(($rlat1 + $rlat2) / 2)); $rlon = sprintf("%.8f",(($rlon1 + $rlon2) / 2)); if (not_in_world_range($rlat,$rlon)) { prtw( "WARNING: $.: $line [$rlat, $rlon] NOT IN WORLD\n" ); next; } $glat += $rlat; $glon += $rlon; my @a2 = @arr; push(@waterways, \@a2); $wwcnt++; $keep = 1; } elsif ($type == 102) { # Heliport # my $heli = '102'; # Helipad # 0 1 2 3 4 5 6 7 8 9 10 11 # 102 H2 52.48160046 013.39580674 355.00 18.90 18.90 2 0 0 0.00 0 # 102 H3 52.48071507 013.39937648 2.64 13.11 13.11 1 0 0 0.00 0 $rlat = sprintf("%.8f",$arr[2]); $rlon = sprintf("%.8f",$arr[3]); if (not_in_world_range($rlat,$rlon)) { prtw( "WARNING: $.: $line [$rlat, $rlon] NOT IN WORLD\n" ); next; } $glat += $rlat; $glon += $rlon; my @a2 = @arr; push(@heliways, \@a2); $padcnt++; $keep = 1; } elsif ($type == 10) { # 10 36.962213 127.031071 14x 131.52 8208 1595.0620 0000.0000 150 321321 1 0 3 0.25 0 0300.0300 prt("$lnn: $line\n"); pgm_exit(1, "Incompatible OLD 10 record!\n"); } elsif ($type == 15) { # ramp startup } elsif ($type == 18) { # Airport light beacon } elsif ($type == 19) { # Airport windsock $keep = 1; } elsif ($type == 20) { # 20 Signs Taxiway signs or runway distance-remaining signs # 20 22.32152700 114.19750500 224.10 0 3 {@Y,^l}31-13{^r} } elsif ($type == 21) { # 21 Lighting objects VASI, PAPI, wig-wags, etc. # 21 22.31928000 114.19800800 3 134.09 3.10 13 PAPI-4R } elsif ($type == 110) { # 110 2 0.00 134.10 runway sholder } elsif ($type == 111) { # 111 22.30419700 114.21613100 } elsif ($type == 112) { # 112 22.30449500 114.21644400 22.30480900 114.21677000 51 102 } elsif ($type == 113) { # 113 22.30370300 114.21561700 } elsif ($type == 114) { # 114 43.29914799 -008.38013558 43.29965322 -008.37970933 } elsif ($type == 115) { # 115 22.31009400 114.21038500 } elsif ($type == 116) { # 116 43.30240028 -008.37799316 43.30271076 -008.37878407 } elsif ($type == 120) { # 120 hold lines W A13 } elsif ($type == 130) { # 130 Airport Boundary } elsif ($type == 1000) { # 1000 Northerly flow } elsif ($type == 1001) { # 1001 KGRB 270 020 999 } elsif ($type == 1002) { # 1002 KGRB 0 } elsif ($type == 1003) { # 1003 KGRB 0 } elsif ($type == 1004) { # 1004 0000 2400 } elsif ($type == 1100) { # 1100 36 12654 all heavy|jets|turboprops|props 000360 000360 Northerly } elsif ($type == 1101) { # 1101 36 left } elsif ($type == 1200) { # 1200 Taxi routing network (for readability only) } elsif ($type == 1201) { # 1201 42.75457409 -073.80880021 both 2110 _start } elsif ($type == 1202) { # 1202 2110 2112 twoway taxiway } elsif ($type == 1204) { # 1204 arrival 01,19 } elsif ($type == 1205) { # 1205 44.21924185 043.10493366 } elsif ($type == 1206) { # 1206 Taxi routing edge (ground vehicles) Segment in taxi routing } elsif ($type == 1300) { # 1300 30.32875704 -009.41140596 323.85 misc jets|props Ramp } elsif ($type == 1301) { # 1301 For ramp start metadata } elsif ($type == 1302) { # 1302 - Airport metadata } elsif ($type == 1400) { # 1400 47.44374472 -122.30463464 88.1 baggage_train 3 Svc Baggage } elsif ($type == 1401) { # 1401 47.44103438 -122.30382493 0.0 baggage_train Luggage Train Destination South 2 } else { prt("$lnn: $line\n"); pgm_exit(1,"Error: Unparsed line! *** FIX ME ***\n"); } if ($got_out && $keep) { print $OF "$line\n"; } } close INF; if (length($apt)) { # add airport $trwycnt = $rwycnt; $trwycnt += $wwcnt; $trwycnt += $padcnt; if ($trwycnt > 0) { if (!$got_twr) { # average position $alat = $glat / $trwycnt; $alon = $glon / $trwycnt; } my @arr2 = split(/\s+/,$apt); my $aalt = $arr2[1]; # Airport (general) ALTITUDE AMSL my $actl = $arr2[2]; # control tower my $abld = $arr2[3]; # buildings my $diff = 0; $icao = $arr2[4]; # ICAO $name = join(' ', splice(@arr2,5)); # Name ##prt("$diff [$apt] (with $rwycnt runways at [$alat, $alon]) ...\n"); ##prt("$diff [$icao] [$name] ...\n"); my @ra = @runways; my @wa = @waterways; my @ha = @heliways; my @fa = @freqs; # 0 1 2 3 4 5 6 7 8 push(@g_naptlist, [$diff, $icao, $name, $alat, $alon, \@ra, \@wa, \@ha, \@fa ]); } else { prtw("Warning: Apt with NO RUNWAYS!\n$apt\n"); } } $len = $landcnt + $seacnt + $helecnt; prt("Done $lncnt lines... $len airports, $landcnt land, $seacnt sea, $helecnt heleports... "); if ($fnd) { prt("Found version...\n"); } else { # if (!$fnd) { prt("'Version' NOT found in first $max_lines of $inf!\n"); } @arr = sort mycmp_ascend_n keys(%codes); $lnn = scalar @arr; prt("Found $lnn different codes...\n"); if (VERB9()) { foreach $code (@arr) { $lnn = $codes{$code}; $len = sprintf("%4d",$code); prt("$len $lnn\n"); } } $len = scalar @g_naptlist; prt("Found $len airports...\n"); if (length($out_file) && $len && $got_out) { print $OF "99\n"; close $OF; prt("Results written to $out_file\n"); } } ######################################### ### MAIN ### parse_args(@ARGV); process_in_file($in_file); 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); 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); } } prt("Verbosity = $verbosity\n") if (VERB1()); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if (VERB1()); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = $arg; prt("Set input to [$in_file]\n") if (VERB1()); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if ((length($in_file) == 0) && $debug_on) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); } } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No input files found in command!\n"); } if (! -f $in_file) { pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-file\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"); } sub row_codes { my $txt = <