#!/usr/bin/perl -w
# NAME: math_trig.pl
# AIM:
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;
use Math::Trig;
my $perl_dir = 'C:\GTools\perl';
unshift(@INC, $perl_dir);
require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl'! Check location and \@INC content.\n";
require 'fg_wsg84.pl' or die "Unable to load fg_wsg84.pl ...\n";
require "Bucket2.pm" or die "Unable to load Bucket2.pm ...\n";
# log file stuff
our ($LF);
my $pgmname = $0;
if ($pgmname =~ /(\\|\/)/) {
    my @tmpsp = split(/(\\|\/)/,$pgmname);
    $pgmname = $tmpsp[-1];
}
my $outfile = $perl_dir."\\temp.$pgmname.txt";
open_log($outfile);

# user variables
my $load_log = 0;
my $in_file = '';

#   935 YSDU Dubbo                    -32.217486500,148.577270000 
# 05/23 (53.61) 5600 ft. (s=Asphalt) -32.218265,148.576145
# 05: -32.2136987804606,148.583432501246 23: -32.2228307960945,148.568856770273
# 11/29 (119.17) 3494 ft. (s=Asphalt) -32.216708,148.578395
# 11: -32.2190483614171,148.583327271364 29: -32.2143674452924,148.573462981327
# rt:2 [ ATIS: 114.4 (AWIS) Unicom: 134 (CTAF)] fg=e140s40/e148s33
#  1807 YSDU Dubbo (-32.2174865,148.57727) (3)
# Type  Latitude     Logitude        Alt.  Freq.  Range  Frequency2    ID  Name
# VOR  -32.21952800,  148.57770800,   935, 11440,    50,       11.0,   DU, DUBBO VOR-DME            (0.23Km on 169.7, ap1) (SGDist: 230 m, <1km on 169.6)
# VDME -32.21968100,  148.57766100,   935, 11440,    50,        0.0,   DU, DUBBO VOR-DME DME        (0.25Km on 171.4, ap1) (SGDist: 246 m, <1km on 171.3)
# NDB  -32.21753100,  148.55909400,     0,   251,    70,        0.0,   DU, DUBBO NDB                (1.71Km on 269.8, ap1) (SGDist: 1.7 km on 269.8)

# from : http://www.airservicesaustralia.com/publications/pending/dap/SDUDG01-115.pdf
# AD ELEV 935 feet - Altitudes below are MEAN SEA LEVEL (MSL)
my $elev_YSDU = 935;
# sector A - 007 - 281 in SE to NW
my @distancesA = qw( 7.8  7     6    5    4    3    2.4 2.1  2    1.5 );
my @altitudesA = qw( 3700 3440 3120 2800 2480 2160 1960 1880 1850 1700 );
# sector B - 096 - 163 in NW to SE
my @distancesB = qw( 9.1  8    7    6    5    4    3.6  3.4  3    2.7 );
my @altitudesB = qw( 3700 3350 3030 2710 2390 2080 1960 1880 1760 1650 );
# sector C - 217 - 219 in NE to SW - in on rwy 23
my @distancesC = qw( 9.1  8    7    6    5    4    3.6  3.4  3    2.7 );
my @altitudesC = qw( 3700 3350 3030 2710 2390 2080 1960 1880 1760 1650);

my $debug_on = 0;
my $def_file = 'def_file';

### SIMGEAR constants
my $SGD_PI = 3.1415926535;
my $SGD_DEGREES_TO_RADIANS = $SGD_PI / 180.0;
my $SGD_RADIANS_TO_DEGREES = 180.0 / $SGD_PI;
# /** Feet to Meters */
my $SG_FEET_TO_METER = 0.3048;
# /** Meters to Feet */
my $SG_METER_TO_FEET = 3.28083989501312335958;
#/** Meters to Nautical Miles.  1 nm = 6076.11549 feet */
my $SG_METER_TO_NM = 0.0005399568034557235;
#/** Nautical Miles to Meters */
my $SG_NM_TO_METER = 1852.0000;
#/** Meters to Statute Miles. */
my $SG_METER_TO_SM = 0.0006213699494949496;
#/** Statute Miles to Meters. */
my $SG_SM_TO_METER = 1609.3412196;

### DATA
my $a_gil_lat = -31.697287500;
my $a_gil_lon = 148.636942500;
my $a_dub_lat = -32.2174865;
my $a_dub_lon = 148.57727;

# RUNWAY ARRARY OFFSETS
my $RW_HDG = 0;
my $RW_LEN = 1;
my $RW_TT1 = 2;
my $RW_TT2 = 3;
my $RW_CLAT = 4;
my $RW_CLON = 5;
my $RW_DONE = 6;
my $RW_LLAT = 7;
my $RW_LLON = 8;
my $RW_RLAT = 9;
my $RW_RLON = 10;
#                 Hdg    Len   Title  RTit Ctr Lat     Ctr Lon
#                 0      1      2    3     4           5
my @gil_rwys = ( [162.0, 4204, '15', '33', -31.696928, 148.636404, 0, 0, 0, 0, 0] );
#my @gil_navs = ( ["", 0 ] );
my @gil_navs = ( [ ] );
#my @gil_rwys = ( [162.0, 4204], [93.0, 1902] );
my @dub_rwys = ( [53.61, 5600, '05', '23', -32.218265, 148.576145, 0, 0, 0, 0, 0] );
my @dub_navs = ( ["VOR", 114.4], ["NDB", 251] );

my $OL_LAT = 0;
my $OL_LON = 1;
my $OL_NAV = 2;
my $OL_RWY = 3;
my %apt_locations = (
    # ICAO       Center LAT, LON       NAVAIDS      RUNWAYS
    'YGIL' => [$a_gil_lat, $a_gil_lon, \@gil_navs, \@gil_rwys ],
    'YSDU' => [$a_dub_lat, $a_dub_lon, \@dub_navs, \@dub_rwys ]
    );

sub get_locations() { return \%apt_locations; }

### program variables
my @warnings = ();
my $cwd = cwd();
my $os = $^O;

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" );
    }
}

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 set_decimal1_stg($) {
    my $r = shift;
    ${$r} =  int((${$r} + 0.05) * 10) / 10;
    ${$r} = "0.0" if (${$r} == 0);
    ${$r} .= ".0" if !(${$r} =~ /\./);
}

sub set_int_stg($) {
    my $r = shift;
    ${$r} =  int(${$r} + 0.5);
}

sub get_dist_stg_nm($) {
    my ($dist) = @_;
    my $nm = $dist * $SG_METER_TO_NM;
    set_decimal1_stg(\$nm);
    $nm .= "nm";
    return $nm;
}

sub set_runway_ends($$$) {
    my ($rrwys,$i,$key) = @_;
    # set ENDS of runway
    my $rhdg = ${$rrwys}[$i][$RW_HDG];
    my $rlen = ${$rrwys}[$i][$RW_LEN];
    my $clat = ${$rrwys}[$i][$RW_CLAT];
    my $clon = ${$rrwys}[$i][$RW_CLON];
    my $rty1 = ${$rrwys}[$i][$RW_TT1];
    my $rty2 = ${$rrwys}[$i][$RW_TT2];
    my $rwlen2 = ($rlen * $SG_FEET_TO_METER) / 2;
    my ($elat1,$elon1,$eaz1,$elat2,$elon2,$eaz2);
    my $hdgr = $rhdg + 180;
    $hdgr -= 360 if ($hdgr >= 360);
    fg_geo_direct_wgs_84( $clat, $clon, $rhdg, $rwlen2, \$elat1, \$elon1, \$eaz1 );
    fg_geo_direct_wgs_84( $clat, $clon, $hdgr, $rwlen2, \$elat2, \$elon2, \$eaz2 );
    ${$rrwys}[$i][$RW_DONE] = 1;
    ${$rrwys}[$i][$RW_LLAT] = $elat1;
    ${$rrwys}[$i][$RW_LLON] = $elon1;
    ${$rrwys}[$i][$RW_RLAT] = $elat2;
    ${$rrwys}[$i][$RW_RLON] = $elon2;
    my ($az1,$az2,$dist);
    fg_geo_inverse_wgs_84 ($elat1,$elon1,$elat2,$elon2,\$az1,\$az2,\$dist);
    $dist = $dist * $SG_METER_TO_FEET;
    set_int_stg(\$az1);
    set_int_stg(\$az2);
    set_int_stg(\$dist);
    # init: YSDU: 23: -32.2136987804606,148.583432501246 05: -32.2228307960945,148.568856770273 234 5600 54 vs 53.61 5600
    # init: YGIL: 33: -31.7024233216057,148.638492502638 15: -31.6914326394609,148.634315743548 342 4204 162 vs 162 4204
    #prt("init: $key: $rty2: $elat1,$elon1 $az1 $rty1: $elat2,$elon2 $az1 $dist $az2 vs $rhdg $rlen\n");
    prt("init: $key: $rty2:$az1: $elat1,$elon1 $rty1:$az2: $elat2,$elon2\n");
}

sub init_runway_array() {
    my $rl = get_locations();
    my ($key,$i,$cnt,$rrwys);
    foreach $key (keys %{$rl}) {
        $rrwys = ${$rl}{$key}[$OL_RWY];
        $cnt = scalar @{$rrwys};
        for ($i = 0; $i < $cnt; $i++) {
            set_runway_ends($rrwys,$i,$key);
        }
    }
}

sub get_dist_nm_for_alt_ft($) {
    my $alt_ft = shift;
    my $tan3 = tan( 3 * $SGD_DEGREES_TO_RADIANS );
    my $alt_m = $alt_ft * $SG_FEET_TO_METER;
    my $dist_m = $alt_m / $tan3;
    my $dist_nm = $dist_m * $SG_METER_TO_NM;
    return $dist_nm;
}

sub show_calcs() {
    my ($alt_ft,$alt_m,$dist_m,$dist_nm,$tmp1,$tmp2);
    my $tan3 = tan( 3 * $SGD_DEGREES_TO_RADIANS );

    $alt_ft = 0; # start from the deck
    prt("Computed distances (nm), at 3 degrees, for 0 to 2500 feet.\n");
    while ($alt_ft <= 2500) {
        $alt_m = $alt_ft * $SG_FEET_TO_METER;
        $dist_m = $alt_m / $tan3;
        $dist_nm = $dist_m * $SG_METER_TO_NM;
        $tmp2 = get_dist_nm_for_alt_ft($alt_ft);

        set_decimal1_stg(\$dist_nm);
        set_decimal1_stg(\$tmp2);
        $tmp1 = $alt_ft;
        set_int_stg(\$tmp1);
        set_int_stg(\$alt_m);
        $tmp1 = " $tmp1" while (length($tmp1) < 4);
        prt("Dist $dist_nm nm, alt $tmp1 feet ($alt_m m) ($tmp2)\n");
        $alt_ft += 250;
    }
    prt("Computed altitude (ft), at 3 degrees, for distances 1 - 9 nm.\n");
    $dist_nm = 1;
    while ($dist_nm < 10) {
        $dist_m = $dist_nm * $SG_NM_TO_METER;
        $alt_m = $dist_m * $tan3;
        $alt_ft = $alt_m * $SG_METER_TO_FEET;
        $tmp1 = $dist_nm;
        set_int_stg(\$alt_ft);
        $alt_ft = " $alt_ft" while (length($alt_ft) < 4);
        set_int_stg(\$alt_m);
        prt("Dist $dist_nm nm, alt $alt_ft feet ($alt_m m)\n");
        $dist_nm += 1;
    }
}

sub show_tan3() {
    my $tan3 = tan( 3 * $SGD_DEGREES_TO_RADIANS );
    my $angle = atan($tan3) * $SGD_RADIANS_TO_DEGREES;
    set_int_stg(\$angle);
    prt("tan ( $angle ) = $tan3\n");
}


# atan() is the complementary function of tan(), 
# which means that a == tan(atan(a)) for every value of a
# that is within range...
sub do_calcs($$$$) {
    my ($rd,$ra,$elev,$sect) = @_;
    my ($dist_nm, $alt_ft,$angle,$tdist_nm);
    my $max = scalar @{$rd};
    my ($i,$dist_m,$alt_m,$ang_rad,$ratio,$ang_rad2);
    my $tan3 = tan( 3 * $SGD_DEGREES_TO_RADIANS );
    prt("Calulations for $sect...\n");
    my $l_elev = ${$ra}[-1];
    for ($i = 0; $i < $max; $i++) {
        $dist_nm = ${$rd}[$i];
        # WOW, look at this strangeness!!!
        $alt_ft = ${$ra}[$i] - $l_elev + $elev;
        # ========= ??????????? ==========

        $dist_m = $dist_nm * $SG_NM_TO_METER;
        $alt_m = $alt_ft * $SG_METER_TO_FEET;
        $ratio = ($alt_m / $dist_m);
        $ang_rad2 = atan($ratio);
        # OR
        $ang_rad = atan2($alt_m,$dist_m);
        $angle = $ang_rad * $SGD_RADIANS_TO_DEGREES;

        # *********** ??????????? *************
        $angle /= 10; # WHY THIS???
        # *********** ??????????? *************

        $tdist_nm = get_dist_nm_for_alt_ft($alt_ft);

        set_decimal1_stg(\$angle);
        set_int_stg(\$dist_m);
        set_int_stg(\$alt_m);
        $dist_nm .= ".0" if !($dist_nm =~ /\./);
        #prt( "Dist $dist_nm nm ($dist_m), alt $alt_ft ($alt_m), angle $angle deg ($ratio, $ang_rad)\n");
        $alt_ft = " $alt_ft" while (length($alt_ft) < 4);
        set_decimal1_stg(\$tdist_nm);
        prt( "Dist $dist_nm nm, alt $alt_ft ($alt_m), angle $angle deg ($tdist_nm - $ratio $ang_rad2)\n");
    }
}

sub get_feet_per_min($$$$) {
    my ($aspd_kt,$dist_km,$agl_ft,$dbg) = @_;
    my $mps  = $aspd_kt * $SG_NM_TO_METER / 3600; # convert speed to meters/second
    my $time = ($dist_km * 1000) / $mps;
    my $rate_mps = ( $agl_ft * $SG_FEET_TO_METER ) / $time;
    my $rate_fpm = ($rate_mps * $SG_METER_TO_FEET) * 60;
    if ($dbg) {
        my ($tmp1,$tmp2,$tmp3,$tmp4);
        $tmp1 = $mps;
        $tmp2 = $time;
        $tmp3 = $rate_fpm;
        $tmp4 = $dist_km;
        set_decimal1_stg(\$tmp1);
        set_decimal1_stg(\$tmp2);
        set_decimal1_stg(\$tmp3);
        set_decimal1_stg(\$tmp4);
        prt("An spd ${aspd_kt}Kt=${tmp1}mps, dist=${dist_km}KM. time=${tmp2}secs. rate ${tmp3}fpm\n");
    }
    return $rate_fpm;
}


sub do_calc2() {
    my $aspd = 100; # air speed - knots
    my $dist = 10;  # distance to a/p - KM
    my $agl = 1500; # current AGL - feet
    # so must decend x feet, in the time taken to cover the distance KM
    while ($dist <= 20) {
        get_feet_per_min($aspd,$dist,$agl,1);
        $dist += 2;
    }

}


#########################################
### MAIN ###
parse_args(@ARGV);
show_tan3();
init_runway_array();
#do_calc2();
#show_calcs();
#do_calcs(\@distancesC,\@altitudesC,$elev_YSDU,"Section C");
#do_calcs(\@distancesB,\@altitudesB,$elev_YSDU,"Section B");
#do_calcs(\@distancesA,\@altitudesA,$elev_YSDU,"Section A");
pgm_exit(0,"");
########################################
sub give_help {
    prt("$pgmname: version 0.0.1 2010-09-11\n");
    prt("Usage: $pgmname [options] in-file\n");
    prt("Options:\n");
    prt(" --help (-h or -?) = This help, and exit 0.\n");
}
sub need_arg {
    my ($arg,@av) = @_;
    pgm_exit(1,"ERROR: [$arg] must have 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)");
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            $in_file = $arg;
            prt("Set input to [$in_file]\n");
        }
        shift @av;
    }
}

# eof - template.pl
