Generated: Sun Mar 2 17:19:42 2014 from cntnavtypes.pl 2014/02/27 19.3 KB. text copy
#!/usr/bin/perl -w # NAME: cntnavtypes.pl # AIM: *** VERY SPECIFIC *** Count x-plane navaids in earth_nav_dat 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 2014-01-13"; my $load_log = 0; my $in_file = 'D:\FG\xplane\1000\earth_nav.dat'; my $verbosity = 0; my $out_file = $temp_dir.$PATH_SEP."earth_nav.csv"; my $out_file2 = $temp_dir.$PATH_SEP."clean-nav.csv"; # ### DEBUG ### my $debug_on = 0; my $def_file = 'def_file'; ### program variables my @warnings = (); my $cwd = cwd(); 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); } my %navtypes = ( 2 => 'NDB', 3 => 'VOR', 4 => 'ILS', 5 => 'LOC', 6 => 'GS', 7 => 'OM', 8 => 'MM', 9 => 'IM', 12 => 'V-DME', 13 => 'O-DME' ); # sort by type sub mycmp_ascend_n0 { return -1 if (${$a}[0] < ${$b}[0]); return 1 if (${$a}[0] > ${$b}[0]); return 0; } # sort by ID text sub mycmp_ascend_t7 { return -1 if (${$a}[7] lt ${$b}[7]); return 1 if (${$a}[7] gt ${$b}[7]); return 0; } # sort by freq number sub mycmp_ascend_n4 { return -1 if (${$a}[4] < ${$b}[4]); return 1 if (${$a}[4] > ${$b}[4]); return 0; } # 0 1 2 3 4 5 6 7 8 # typ latitude longitude elev freq rng brng id name # 2 38.08777778 -077.32491667 0 396 50 0.0 APH A P HILL NDB sub party_with_navaids($) { my $rn = shift; ###my @navs = sort mycmp_ascend_n4 @{$rn}; my $max = scalar @{$rn}; prt("Partying with $max navaids... outing where freq and id are equal...\n"); my ($typ,$lat,$lon,$alt,$frq,$rng,$brg,$id,$name); my ($i,$ra,$j,$ra2,$fnd,$i2); my ($typ2,$lat2,$lon2,$alt2,$frq2,$rng2,$brg2,$id2,$name2); my ($ret,$az1,$az2,$dist,$km,$rak); my ($nlen,$nlen2); my %done = (); my @nnavs = (); my %had = (); for ($i = 0; $i < $max; $i++) { $ra = ${$rn}[$i]; $typ = ${$ra}[0]; $lat = ${$ra}[1]; $lon = ${$ra}[2]; $alt = ${$ra}[3]; $frq = ${$ra}[4]; $rng = ${$ra}[5]; $brg = ${$ra}[6]; $id = ${$ra}[7]; $name = ${$ra}[8]; if ($id eq '----') { push(@nnavs,$ra); # push this ONE to keep next; } if ($frq == 0) { push(@nnavs,$ra); # push this ONE to keep next; } next if (defined $done{$i}); if (($typ == 4)||($typ == 5)||($typ == 6)) { push(@nnavs,$ra); # push this ONE to keep next; } $done{$i} = 1; $fnd = 0; $rak = $ra; %had = (); $had{$typ} = 1; # had this type for ($j = $i + 1; $j < $max; $j++) { next if (defined $done{$j}); $ra2 = ${$rn}[$j]; $typ2 = ${$ra2}[0]; $lat2 = ${$ra2}[1]; $lon2 = ${$ra2}[2]; $alt2 = ${$ra2}[3]; $frq2 = ${$ra2}[4]; $rng2 = ${$ra2}[5]; $brg2 = ${$ra2}[6]; $id2 = ${$ra2}[7]; $name2 = ${$ra2}[8]; next if ($id2 eq '----'); next if ($frq2 == 0); next if (($typ2 == 4)||($typ2 == 5)||($typ2 == 6)); if ( ($id eq $id2) && ($frq == $frq2) ) { $ret = fg_geo_inverse_wgs_84($lat, $lon, $lat2, $lon2, \$az1, \$az2, \$dist); $km = $dist / 1000; if ($km < 10) { $km = (int(($km+0.005) * 100) / 100); if ($fnd == 0) { $nlen = length($name); prt("\n1:$i: $typ,$lat,$lon,$alt,$frq,$rng,$brg,$id,$name,$km\n"); } $fnd++; $i2 = $fnd + 1; $nlen2 = length($name2); prt("$i2:$j: $typ2,$lat2,$lon2,$alt2,$frq2,$rng2,$brg2,$id2,$name2,$km\n"); $done{$j} = 1; $had{$typ2} = 1; if ($typ == $typ2) { if ($nlen2 > $nlen) { $nlen = $nlen2; $rak = $ra2; } } elsif ($typ == 3) { if ($typ2 == 12) { $rak = $ra2; } elsif ($typ2 == 13) { if (!defined $had{12}) { $rak = $ra2; } } else { prtw("WARNING: Type $typ and $typ2 duplication NOT checked. *FIX ME*\n"); } } elsif (($typ == 12)&&($typ2 == 13)) { # have aleady selected the 12, so nothing to do here } else { prtw("WARNING: Type $typ and $typ2 duplication NOT checked. *FIX ME*\n"); } } } } push(@nnavs,$rak); # push the ONE to keep } # ======================================== # output the new records @nnavs = sort mycmp_ascend_n0 @nnavs; $max = scalar @nnavs; prt("Done $i records... kept $max...\n"); my $csv = "type,lat,lon,feet,freq,rng,bear,id,name\n"; for ($i = 0; $i < $max; $i++) { $ra = $nnavs[$i]; $typ = ${$ra}[0]; $lat = ${$ra}[1]; $lon = ${$ra}[2]; $alt = ${$ra}[3]; $frq = ${$ra}[4]; $rng = ${$ra}[5]; $brg = ${$ra}[6]; $id = ${$ra}[7]; $name = ${$ra}[8]; $csv .= "$typ,$lat,$lon,$alt,$frq,$rng,$brg,$id,$name\n"; } if (-f $out_file2) { my $msg = "WARNING: $out_file2 ALREADY exists! Delete or rename to write a new one.\n"; if (open INF, "<$out_file2") { my @lines = <INF>; close INF; $max = scalar @lines; $msg .= "It contains $max lines.\n"; } else { $msg .= "But am unable to open it...\n"; } prtw($msg); } else { write2file($csv,$out_file2); prt("Clean navaids written to $out_file2\n"); } $load_log = 1; } sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = <INF>; close INF; my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); my %types = (); my %navids = (); my %navfreqs = (); my ($i,$line,$inc,$lnn,$len,@arr,$typ,$nc); my ($lat,$lon,$alt,$frq,$rng,$brg,$id,$name); my ($off,$ra); $lnn = 0; my $csv = "type,lat,lon,feet,freq,rng,bear,id,name\n"; my @navaids = (); for ($i = 0; $i < $lncnt; $i++) { $lnn++; $line = $lines[$i]; chomp $line; $line = trim_all($line); $len = length($line); next if ($len < 10); # arbitrary - skip first 'I' and last '99' lines if ($line =~ /\s+Version\s+/i) { prt(substr($line,0,50)."\n"); next; } @arr = split(/\s+/,$line); $nc = scalar @arr; $typ = $arr[0]; if ($nc < 8) { prt("Type: [$typ] - Handle this line [$line] - count = $nc...\n"); pgm_exit(1,"ERROR: FIX ME FIRST!\n"); } $lat = $arr[1]; $lon = $arr[2]; $alt = $arr[3]; $frq = $arr[4]; $rng = $arr[5]; $brg = $arr[6]; $id = $arr[7]; $name = join(' ', splice(@arr,8)); $name =~ s/,/ /g; $csv .= "$typ,$lat,$lon,$alt,$frq,$rng,$brg,$id,$name\n"; $off = scalar @navaids; push(@navaids,[$typ,$lat,$lon,$alt,$frq,$rng,$brg,$id,$name]); if (!defined $types{$typ}) { $types{$typ} = 1; } else { $types{$typ}++; } if (!defined $navids{$id}) { $navids{$id} = 1; } else { $navids{$id}++; } if (!defined $navfreqs{$frq}) { $navfreqs{$frq} = 1; } else { $navfreqs{$frq}++; } } @arr = keys %types; $i = scalar @arr; prt("Types $i "); $len = 0; foreach $typ (@arr) { $lnn = $types{$typ}; $line = '???'; if (defined $navtypes{$typ}) { $line = $navtypes{$typ}; #$line .= ' ' while (length($line) < 5); } # prt("$typ=$lnn "); prt("$typ $line=$lnn, "); $len += $lnn; } prt(" Total $len navaids\n"); @arr = sort keys %navids; $lnn = 0; # count of ids repeated $typ = 0; # most used $line = ''; foreach $id (@arr) { next if ($id eq '----'); $len = $navids{$id}; if ($len > 1) { $lnn++; if ($len > $typ) { $typ = $len; $line = $id; } } } prt("There are $lnn ID repeated, first most used $line with count of $typ\n"); @arr = sort keys %navfreqs; $lnn = 0; # count of freq repeated $typ = 0; # most used $line = ''; foreach $frq (@arr) { next if ($frq == 0); $len = $navfreqs{$frq}; if ($len > 1) { $lnn++; if ($len > $typ) { $typ = $len; $line = $frq; } } } prt("There are $lnn freq repeated, first most used $line with count of $typ\n"); party_with_navaids(\@navaids); if (! -f $out_file) { write2file($csv,$out_file); prt("Nav csv wirtten 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); 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_file = $arg; prt("Set input to [$in_file]\n") if ($verb); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $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 get_nav_spec() { my $txt = <<EOF; from : http://data.x-plane.com/file_specs/XP\%20NAV810\%20Spec.pdf 2 NDB (Non-Directional Beacon) Includes NDB component of Locator Outer Markers (LOM) 3 VOR (including VOR-DME and VORTACs) Includes VORs, VOR-DMEs and VORTACs 4 Localiser component of an ILS (Instrument Landing System) 5 Localiser component of a localiser-only approach Includes for LDAs and SDFs 6 Glideslope component of an ILS Frequency shown is paired frequency, not the DME channel 7 Outer markers (OM) for an ILS Includes outer maker component of LOMs 8 Middle markers (MM) for an ILS 9 Inner markers (IM) for an ILS 12 DME, including the DME component of an ILS, VORTAC or VOR-DME Frequency display suppressed on X-Plane’s charts 13 Stand-alone DME, or the DME component of an NDB-DME Frequency will displayed on X-Plane’s charts 2 NDB Non-directional beacon 2 Row code for an NDB 2 47.63252778 Latitude of NDB in decimal degrees Eight decimal places supported -122.38952778 Longitude of NDB in decimal degrees Eight decimal places supported 0 Elevation in feet above MSL Integer. Used to calculate service volumes. 362 Frequency in KHz Integer. Decimal frequencies not supported. 50 Maximum reception range in nautical miles Integer 0.0 Not used for NDBs 0.0 BF NDB identifier Up to four characters. Not unique NOLLA NDB NDB name Text, suffix with "NDB" 3 VOR Includes VOR-DMEs and VORTACs 3 Row code for a VOR 3 47.43538889 Latitude of VOR in decimal degrees Eight decimal places supported -122.30961111 Longitude of VOR in decimal degrees Eight decimal places supported 354 Elevation in feet above MSL Integer. Used to calculate service volumes. 11680 Frequency in MHZ (multiplied by 100) Integer - MHz multiplied by 100 (eg. 123.45MHz = 12345) 130 Maximum reception range in nautical miles Integer 19.0 Slaved variation for VOR Up to three decimal places supported SEA VOR identifier Up to four characters. Not unique SEATTLE VORTAC VOR name Text, suffix with "VOR", "VORTAC" or "VOR-DME" 4, 5 LOC Includes localisers (inc. LOC-only), LDAs and SDFs 4 Row code for a localizer associated with an ILS 4=ILS localizer, 5=stand-alone localizer (inc LOC, LDA & SDF) 47.42939200 Latitude of localiser in decimal degrees Eight decimal places supported. -122.30805600 Longitude of localiser in decimal degrees Eight decimal places supported. 338 Elevation in feet above MSL Integer. 11030 Frequency in MHZ (multiplied by 100) Integer - MHz multiplied by 100 (eg. 123.45MHz = 12345) 18 Maximum reception range in nautical miles Integer 180.343 Localiser bearing in true degrees Up to three decimal places supported ISNQ Localiser identifier Up to four characters. Usually start with "I". Not unique KSEA Airport ICAO code Up to four characters. Must be valid airport code 16L Associated runway number Up to three characters ILS-cat-I Localiser name Use "ILS-cat-I", "ILS-cat-II", "ILS-cat-III", "LOC", "LDA" or "SDF" 6 Glideslope Glideslope associated with an ILS 6 Row code for a glideslope 6 47.46081700 Latitude of glideslope aerial in decimal degrees Eight decimal places supported -122.30939400 Longitude of glideslope aerial in decimal degrees Eight decimal places supported 425 Elevation in feet above MSL Integer. 11030 Frequency in MHZ (multiplied by 100) Integer - MHz multiplied by 100 (eg. 123.45MHz = 12345) 10 Maximum reception range in nautical miles Integer 300180.343 Associated localiser bearing in true degrees prefixed by glideslope angle Up to three decimal places supported. Glideslope angle multiplied by 100,000 and added (eg. Glideslope of 3.25 degrees on heading of 123.456 becomes 325123.456) ISNQ Glideslope identifier Up to four characters. Usually start with "I". Not unique KSEA Airport ICAO code Up to four characters. Must be valid airport code 16L Associated runway number Up to three characters GS Name "GS" 7, 8, 9 Marker beacons Outer (OM), Middle (MM) and Inner (IM) Markers 8 Row code for a middle marker 7=OM, 8=MM, 9=IM 47.47223300 Latitude of marker in decimal degrees Eight decimal places supported -122.31102500 Longitude of marker in decimal degrees Eight decimal places supported 433 Elevation in feet above MSL Integer 0 Not used 0 0 Not used 0 180.343 Associated localiser bearing in true degrees Up to three decimal places supported ---- Not used Use "----" to indicate no associated ID KSEA Airport ICAO code Up to four characters. Must be valid airport code 16L Associated runway number Up to three characters MM Name "OM", "MM" or "IM" 12, 13 DME Distance Measuring Equipment 12 Row code for a DME 12=Suppress frequency, 13=display frequency 47.43433300 Latitude of DME in decimal degrees Eight decimal places supported -122.30630000 Longitude of DME in decimal degrees Eight decimal places supported 369 Elevation in feet above MSL Integer 11030 Frequency in MHZ (multiplied by 100) Integer - MHz multiplied by 100 (eg. 123.45MHz = 12345) 10 Minimum reception range in nautical miles Integer 0.000 DME bias in nautical miles. Default is 0.000 ISNQ Identifier Up to four characters. Not unique. KSEA Airport ICAO code (for DMEs associated with an ILS) Only used for DMEs associated with an ILS. Up to four characters. Must be valid ICAO code 16L Associated runway number (for DMEs associated with an ILS) Only used for DMEs associated with an ILS. Up to three characters DME-ILS DME name (all DMEs) "DME-ILS if associated with ILS Suffix "DME" to navaid name for VOR-DMEs, VORTACs & NDB-DMEs (eg. "SEATTLE VORTAC DME" in example data) For standalone DMEs just use DME name EOF return $txt; } # eof - cntnavtypes.pl