shwaptdatver.pl to HTML.

index -|- end

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

index -|- top

checked by tidy  Valid HTML 4.01 Transitional