Generated: Sat Oct 24 16:35:28 2020 from shwaptdatver.pl 2017/07/19 21.9 KB. text copy
#!/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 = <INF>) { $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 = <INF>) { $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 <file> (-o) = Write output to this file.\n"); } sub row_codes { my $txt = <<EOF; ROW CODES Each row of data begins with an integer code that defines the type of data: Row Code Meaning Comment 1 Land airport header 16 Seaplane base header 17 Heliport header 100 Runway 101 Water runway 102 Helipad 110 Pavement (taxiway or ramp) header Must form a closed loop. 120 Linear feature (painted line or light string) header Can form closed loop or simple string 130 Airport boundary header Must form a closed loop 111 Node All nodes can also include a “style” (line or lights) 112 Node with Bezier control point Bezier control points define smooth curves 113 Node with implicit close of loop Implied join to first node in chain 114 Node with Bezier control point, with implicit close of loop Implied join to first node in chain 115 Node terminating a string (no close loop) No “styles” used 116 Node with Bezier control point, terminating a string (no close loop) No “styles” used 14 Airport viewpoint One or none for each airport 15 Aeroplane startup location *** Convert these to new row code 1300 *** 18 Airport light beacon One or none for each airport 19 Windsock Zero, one or many for each airport 20 Taxiway sign (inc. runway distance-remaining signs) Zero, one or many for each airport 21 Lighting object (VASI, PAPI, Wig-Wag, etc.) Zero, one or many for each airport 1000 Airport traffic flow Zero, one or many for an airport. Used if following rules met (rules of same type use ‘or’ logic, rules of a different type use ‘and’ logic). First flow to pass all rules is used. 1001 Traffic flow wind rule Zero, one or many for a flow. Multiple rules use ‘or’ logic. 1002 Traffic flow minimum ceiling rule Zero or one rule for each flow 1003 Traffic flow minimum visibility rule Zero or one rule for each flow 1004 Traffic flow time rule Zero, one or many for a flow. Multiple rules use ‘or’ logic. 1100 Runway-in-use arrival/departure constraints First constraint met is used. Sequence matters! 1101 VFR traffic pattern Zero or one pattern for each traffic flow 1200 Header indicating that taxi route network data follows 1201 Taxi route network node Sequencing must be 0 based, ascending by ID. Must be part of one or more edges. 1202 Taxi route network edge Must connect two nodes. Also takes one of 6 sizes (A-F). 1204 Taxi route edge active zone Can refer to up to 4 runway ends 1300 Airport location (deprecates code 15) Not explicitly connected to taxi route network 1301 Ramp start metadata. Includes width, operations type, equipment type, & airlines. 1302 Metadata records Zero or many for each airport. 1400 Truck Parking Location Not explicitly connected to taxi route network. 1401 Truck Destination Location Not explicitly connected to taxi route network. 50 – 56 Communication frequencies Zero, one or many for each airport EOF return $txt; } # eof - shwaptdatver.pl