#!/usr/bin/perl -w
# NAME: solve.pl
# AIM: Given a position, decide the track to take to best arrive at a 'circuit'
# Quite specialized!
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Cwd;
use IO::Socket;
use Term::ReadKey;
use Time::HiRes qw( usleep gettimeofday tv_interval );
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);

### constants
my $SGD_PI = 3.1415926535;
my $SGD_DEGREES_TO_RADIANS = $SGD_PI / 180.0;
my $SGD_RADIANS_TO_DEGREES = 180.0 / $SGD_PI;
my $DEF_GS = 3;
my $ATAN3 = atan( $DEF_GS * $SGD_DEGREES_TO_RADIANS );
# /** Feet to Meters */
my $SG_FEET_TO_METER = 0.3048;
# /** Meters to Feet */
my $SG_METER_TO_FEET = 3.28083989501312335958;
my $SG_NM_TO_METER = 1852;
my $SG_METER_TO_NM = 0.0005399568034557235;

# user variables
my $load_log = 1;
my $in_file = '';
my $bad_latlon = 200;
my $in_lat = $bad_latlon;
my $in_lon = $bad_latlon;
my $graf_file = "tempgraf.gif";
my $graf_bat = $perl_dir."\\tempgraf.bat";
my $debug_on = 1;
my $def_latlon = "-31.6,148.6";

my $stand_glide_degs = 3; # degrees
my $stand_patt_alt = 1000; # feet
my $stand_cross_nm = 2.1; # nm, but this will depend on the aircraft

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

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

# rough Gil circuit
my $tl_lat = -31.684063;
my $tl_lon = 148.614120;
my $bl_lat = -31.723495;
my $bl_lon = 148.633003;
my $br_lat = -31.716778;
my $br_lon = 148.666992;
my $tr_lat = -31.672960;
my $tr_lon = 148.649139;

# RUNWAY ARRAY OFFSETS
my $RW_LEN = 0;
my $RW_HDG = 1;
my $RW_REV = 2;
my $RW_TT1 = 3;
my $RW_TT2 = 4;
my $RW_CLAT = 5;
my $RW_CLON = 6;
my $RW_LLAT = 7;
my $RW_LLON = 8;
my $RW_RLAT = 9;
my $RW_RLON = 10;
my $RW_DONE = 11;
#                 Len    Hdg   Rev  Title  RTit Ctr Lat    Ctr Lon
#                 0      1     2    3     4     5          6           7  8  9  10 11
my @gil_patt = ();
my @gil_rwys = ( [4204,  162.0, 0, '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_patt = ( [ ] );
my @dub_rwys = ( [5600, 53.61, 0, '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 $OL_PAT = 4;
my %apt_locations = (
    # ICAO       Center LAT, LON       NAVAIDS      RUNWAYS
    'YGIL' => [$a_gil_lat, $a_gil_lon, \@gil_navs, \@gil_rwys, \@gil_patt ],
    'YSDU' => [$a_dub_lat, $a_dub_lon, \@dub_navs, \@dub_rwys, \@dub_patt ]
    );

sub get_locations() { return \%apt_locations; }

# DEBUG
my $dbg_01 = 0;
my $dbg_02 = 0;

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 in_world_range($$) {
    my ($lat,$lon) = @_;
    if (($lat < -90) ||
        ($lat >  90) ||
        ($lon < -180) ||
        ($lon > 180) ) {
        return 0;
    }
    return 1;
}

# ============================================================ #
# SimGear Services, rendered in perl
# ============================================================ #
# dot(const SGVec3<T>& v1, const SGVec3<T>& v2)
# { return v1(0)*v2(0) + v1(1)*v2(1) + v1(2)*v2(2); }
# Given 2 Vectors3, return the dot product
sub scalar_dot_product($$) {
    my ($rv1,$rv2) = @_;
    return ${$rv1}[0] * ${$rv2}[0] + ${$rv1}[1] * ${$rv2}[1] + ${$rv1}[2] * ${$rv2}[2];
}

# In dimension 2, the dot product of vectors [a,b] and [c,d] is ac + bd
sub scalar_dot_product2($$$$) {
    my ($v1x,$v1y,$v2x,$v2y) = @_;
    return ($v1x * $v2x) + ($v1y * $v2y);
}

# The euclidean norm of the vector, that is what most people call length
# norm(const SGVec3<T>& v)
# { return sqrt(dot(v, v)); }
# Given a Vector3, return length
sub norm_vector_length($) {
    my ($rv) = @_;
    return sqrt(scalar_dot_product($rv, $rv));
}

sub norm_vector_length2($$) {
    my ($vx,$vy) = @_;
    return sqrt(scalar_dot_product2($vx, $vy, $vx, $vy));
}


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 ($line,$inc,$lnn);
    $lnn = 0;
    foreach $line (@lines) {
        chomp $line;
        $lnn++;
        if ($line =~ /\s*#\s*include\s+(.+)$/) {
            $inc = $1;
            prt("$lnn: $inc\n");
        }
    }
}

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

sub set_dist_stg($) {
    my $r = shift;
    set_int_stg($r);
    my $r5 = sprintf("%5d",${$r});
    ${$r} = $r5;
}
sub set_hdg_stg($) {
    my $r = shift;
    set_int_stg($r);
    my $r3 = sprintf("%3d",${$r});
    ${$r} = $r3;
}

sub set_lat_stg($) {
    my ($rl) = @_;
    ${$rl} = sprintf("%2.7f",${$rl});
}
sub set_lon_stg($) {
    my ($rl) = @_;
    ${$rl} = sprintf("%3.7f",${$rl});
}

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 get_dist_stg_nm($) {
    my ($dist) = @_;
    my $nm = $dist * $SG_METER_TO_NM;
    set_decimal1_stg(\$nm);
    $nm .= "nm";
    return $nm;
}

# ============================================

sub show_distance_heading($$$$) {
    my ($lat1,$lon1,$lat2,$lon2) = @_;
    my ($az1,$az2,$dist);
    fg_geo_inverse_wgs_84 ($lat1,$lon1,$lat2,$lon2,\$az1,\$az2,\$dist);
    $dist = get_dist_stg_nm($dist);
    set_hdg_stg(\$az1);
    prt("Is $dist, on heading $az1\n");
}

sub show_rw_patt($$) {
    my ($key,$rpatts) = @_;
    my $cnt = scalar @{$rpatts};
    prt("Display of $cnt patterns/circuits for $key...\n");
    my ($i,$lat1,$lon1,$lat2,$lon2,$j);
    for ($i = 0; $i < $cnt; $i++) {
        for ($j = 0; $j < 8; $j += 2) {
            $lat1 = ${$rpatts}[$i][$j+0];
            $lon1 = ${$rpatts}[$i][$j+1];
            if ($j == 6) {
                $lat2 = ${$rpatts}[$i][0];
                $lon2 = ${$rpatts}[$i][1];
            } else {
                $lat2 = ${$rpatts}[$i][$j+2];
                $lon2 = ${$rpatts}[$i][$j+3];
            }
            prt("$i:$j: $lat1,$lon1  $lat2,$lon2\n");
            show_distance_heading($lat1,$lon1,$lat2,$lon2);
        }
    }
}

sub set_runway_ends_and_patt($$$$) {
    my ($rrwys,$i,$key,$rpatts) = @_;
    # set ENDS of runway
    my $rlen = ${$rrwys}[$i][$RW_LEN];
    my $rhdg = ${$rrwys}[$i][$RW_HDG];
    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);
    ${$rrwys}[$i][$RW_REV] = $hdgr;

    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_LLAT] = $elat1;
    ${$rrwys}[$i][$RW_LLON] = $elon1;
    ${$rrwys}[$i][$RW_RLAT] = $elat2;
    ${$rrwys}[$i][$RW_RLON] = $elon2;
    ${$rrwys}[$i][$RW_DONE] = 1;
    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");
    # We have the RUNWAY ends - now extend out to first turn to crosswind leg, and turn to final
    # but by how MUCH - ok decide from runway end, out to where it is a 3 degree glide from 1000 feet
    $dist = ($stand_patt_alt * $SG_FEET_TO_METER) / tan($stand_glide_degs * $SGD_DEGREES_TO_RADIANS);
    my ($plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$paz1);
    my ($plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$paz2);
    my ($hdg1L,$hdg1R,$crossd);
    fg_geo_direct_wgs_84( $clat, $clon, $rhdg, $rwlen2+$dist, \$plat11, \$plon11, \$paz1 );
    fg_geo_direct_wgs_84( $clat, $clon, $hdgr, $rwlen2+$dist, \$plat21, \$plon21, \$paz2 );
    $hdg1L = normalised_hdg($rhdg - 90);
    $hdg1R = normalised_hdg($rhdg + 90);
    $crossd = $stand_cross_nm * $SG_NM_TO_METER;
    # ON $rhdg to $elat1, $elon1 to ... turn point, go LEFT and to get NEXT points, this end
    fg_geo_direct_wgs_84( $plat11, $plon11, $hdg1L, $crossd, \$plat12, \$plon12, \$paz1 );
    fg_geo_direct_wgs_84( $plat21, $plon21, $hdg1L, $crossd, \$plat13, \$plon13, \$paz1 );

    # from the turn point, go LEFT and RIGHT to get NEXT points, this other end
    fg_geo_direct_wgs_84( $plat21, $plon21, $hdg1R, $crossd, \$plat22, \$plon22, \$paz2 );
    fg_geo_direct_wgs_84( $plat11, $plon11, $hdg1R, $crossd, \$plat23, \$plon23, \$paz2 );

    if ($dbg_01) {
        # now we have 4 points, either side of the runway
        prt("On $rhdg, at $plat11,$plon11 turn $hdg1L to $plat12,$plon12\n");
        show_distance_heading($plat11,$plon11,$plat12,$plon12);
        prt("On $hdg1L at $plat12,$plon12, turn $hdgr to $plat13,$plon13\n");
        show_distance_heading($plat12,$plon12,$plat13,$plon13);
        prt("On $hdgr at $plat13,$plon13 turn $hdg1R to $plat21,$plon21\n");
        show_distance_heading($plat13,$plon13,$plat21,$plon21);
        prt("On $hdg1R at $plat21,$plon21 turn $rhdg to $elat1,$elon1\n");
        show_distance_heading($plat21,$plon21,$elat1,$elon2);
        prt("\n");
        prt("On $hdgr at $plat21,$plon21 turn $hdg1R to $plat22,$plon22\n");
        show_distance_heading($plat21,$plon21,$plat22,$plon22);
        prt("On $hdg1R at $plat22,$plon22 turn $rhdg to $plat23,$plon23\n");
        show_distance_heading($plat22,$plon22,$plat23,$plon23);
        prt("On $rhdg at $plat23,$plon23 turn $hdg1L to $plat11,$plon11\n");
        show_distance_heading($plat23,$plon23,$plat11,$plon11);
        prt("On $hdg1L at $plat11,$plon11 turn $hdgr to $elat2,$elon2\n");
        show_distance_heading($plat11,$plon11,$elat2,$elon2);
        prt("\n");
    }
    @{$rpatts} = ();
    push(@{$rpatts}, [$plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$plat21,$plon21]);
    push(@{$rpatts}, [$plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$plat11,$plon11]);

}

sub init_runway_array() {
    my $rl = get_locations();
    my ($key,$i,$cnt,$rrwys,$rpatts);
    foreach $key (keys %{$rl}) {
        $rrwys = ${$rl}{$key}[$OL_RWY];
        $rpatts = ${$rl}{$key}[$OL_PAT];
        $cnt = scalar @{$rrwys};
        for ($i = 0; $i < $cnt; $i++) {
            set_runway_ends_and_patt($rrwys,$i,$key,$rpatts);
        }
    }
    if ($dbg_02) {
        foreach $key (keys %{$rl}) {
            $rpatts = ${$rl}{$key}[$OL_PAT];
            show_rw_patt($key,$rpatts);
        }
    }
    # pgm_exit(1,"Temp exit");
}

sub get_runways_and_pattern($$) {
    my ($rh,$key) = @_;
    my $rl = get_locations();
    my ($rrwys,$rpatts);
    if (defined ${$rl}{$key}) {
        $rrwys = ${$rl}{$key}[$OL_RWY];
        $rpatts = ${$rl}{$key}[$OL_PAT];
        ${$rh}{'runways'} = $rrwys;
        ${$rh}{'pattern'} = $rpatts;
        ${$rh}{'airport'} = $key;
    } else {
        pgm_exit(1,"ERROR: Key [$key] NOT in locations!\n");
    }
}

# ============================================

sub set_circuit_values($$) {
    my ($rh,$show) = @_;
    my ($az1,$az2,$dist);
    if ($show) {
        #prt("Set, show circuit...\nTL ".${$rh}{'tl_lat'}.",".${$rh}{'tl_lon'}."\nBL ".
        #    ${$rh}{'bl_lat'}.",".${$rh}{'bl_lon'}."\nBR ".
        #    ${$rh}{'br_lat'}.",".${$rh}{'br_lon'}."\nTR ".
        #    ${$rh}{'tr_lat'}.",".${$rh}{'tr_lon'}."\n");
        my ($tllat,$tllon,$bllat,$bllon,$brlat,$brlon,$trlat,$trlon);
        $tllat = ${$rh}{'tl_lat'};
        $tllon = ${$rh}{'tl_lon'};
        $bllat = ${$rh}{'bl_lat'};
        $bllon = ${$rh}{'bl_lon'};
        $brlat = ${$rh}{'br_lat'};
        $brlon = ${$rh}{'br_lon'};
        $trlat = ${$rh}{'tr_lat'};
        $trlon = ${$rh}{'tr_lon'};
        set_lat_stg(\$tllat);
        set_lat_stg(\$bllat);
        set_lat_stg(\$brlat);
        set_lat_stg(\$trlat);
        set_lon_stg(\$tllon);
        set_lon_stg(\$bllon);
        set_lon_stg(\$brlon);
        set_lon_stg(\$trlon);
        prt("Set, show circuit...\nTL $tllat,$tllon\nBL ".
            "$bllat,$bllon\nBR ".
            "$brlat,$brlon\nTR ".
            "$trlat,$trlon\n");
    }
    # anti-clockwise around circuit
    fg_geo_inverse_wgs_84 (${$rh}{'tl_lat'},${$rh}{'tl_lon'},${$rh}{'bl_lat'},${$rh}{'bl_lon'},\$az1,\$az2,\$dist);
    ${$rh}{'l1_az1'} = $az1;
    ${$rh}{'l1_az2'} = $az2;
    ${$rh}{'l1_dist'} = $dist;
    if ($show) {
        set_dist_stg(\$dist);
        set_hdg_stg(\$az1);
        prt("l1 $dist m, on $az1 (tl2bl)\n");
    }
    fg_geo_inverse_wgs_84 (${$rh}{'bl_lat'},${$rh}{'bl_lon'},${$rh}{'br_lat'},${$rh}{'br_lon'},\$az1,\$az2,\$dist);
    ${$rh}{'l2_az1'} = $az1;
    ${$rh}{'l2_az2'} = $az2;
    ${$rh}{'l2_dist'} = $dist;
    if ($show) {
        set_dist_stg(\$dist);
        set_hdg_stg(\$az1);
        prt("l2 $dist m, on $az1 (bl2br)\n");
    }
    fg_geo_inverse_wgs_84 (${$rh}{'br_lat'},${$rh}{'br_lon'},${$rh}{'tr_lat'},${$rh}{'tr_lon'},\$az1,\$az2,\$dist);
    ${$rh}{'l3_az1'} = $az1;
    ${$rh}{'l3_az2'} = $az2;
    ${$rh}{'l3_dist'} = $dist;
    if ($show) {
        set_dist_stg(\$dist);
        set_hdg_stg(\$az1);
        prt("l3 $dist m, on $az1 (br2tr)\n");
    }
    fg_geo_inverse_wgs_84 (${$rh}{'tr_lat'},${$rh}{'tr_lon'},${$rh}{'tl_lat'},${$rh}{'tl_lon'},\$az1,\$az2,\$dist);
    ${$rh}{'l4_az1'} = $az1;
    ${$rh}{'l4_az2'} = $az2;
    ${$rh}{'l4_dist'} = $dist;
    if ($show) {
        set_dist_stg(\$dist);
        set_hdg_stg(\$az1);
        prt("l4 $dist m, on $az1 (tr2tl)\n");
    }
}

sub set_most_values_plus($$$$$$) {
    my ($rh,$show,$u_lat,$u_lon,$t_lat,$t_lon) = @_;
    if (!defined ${$rh}{'user_points'}) {
        ${$rh}{'user_points'} = [];
    }
    my $ru = ${$rh}{'user_points'};
    push(@{$ru}, [$u_lat,$u_lon,$t_lat,$t_lon]);
}

sub set_min_max($$$$$$) {
    my ($rmaxlat,$rminlat,$rmaxlon,$rminlon,$lat,$lon) = @_;
    ${$rmaxlat} = $lat if ($lat > ${$rmaxlat});
    ${$rminlat} = $lat if ($lat < ${$rminlat});
    ${$rmaxlon} = $lon if ($lon > ${$rmaxlon});
    ${$rminlon} = $lon if ($lon < ${$rminlon});
}
    
sub add_img_line($$$$$) {
    my ($rh,$lat1,$lon1,$lat2,$lon2) = @_;
    my $rmsg = ${$rh}{'rmsg'};
    my ($w_ind1,$h_ind1,$w_ind2,$h_ind2);
    my ($maxlat,$minlat,$maxlon,$minlon);
    my ($w_dpp,$h_dpp);
    my ($sqwid,$sqhgt);
    $maxlat = ${$rh}{'max_lat'};
    $minlat = ${$rh}{'min_lat'};
    $maxlon = ${$rh}{'max_lon'};
    $minlon = ${$rh}{'min_lon'};
    $w_dpp = ${$rh}{'w_dpp'};
    $h_dpp = ${$rh}{'h_dpp'};
    $sqwid = ${$rh}{'sq_wid_adj'};
    $sqhgt = ${$rh}{'sq_hgt_adj'};

    $w_ind1 = int((($lon1 - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind1 = int((($lat1 - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind1 = $sqhgt - $h_ind1;
    $h_ind1 += 1 if ($h_ind1 == 0);
    $w_ind1 += 1 if ($w_ind1 == 0);
    $h_ind1 -= 1 if ($h_ind1 == $sqhgt);
    $w_ind1 -= 1 if ($w_ind1 == $sqwid);
    # ${$rmsg} .= "-draw \"circle ".($w_ind1-1).",$h_ind1 ".($w_ind1+1).",$h_ind1\" ";

    $w_ind2 = int((($lon2 - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind2 = int((($lat2 - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind2 = $sqhgt - $h_ind2;
    #$w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 += 1 if ($h_ind2 == 0);
    $w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 -= 1 if ($h_ind2 == $sqhgt);
    $w_ind2 -= 1 if ($w_ind2 == $sqwid);
    # ${$rmsg} .= "-draw \"circle ".($w_ind2-1).",$h_ind2 ".($w_ind2+1).",$h_ind2\" ";

    ${$rmsg} .= "-draw \"line $w_ind1,$h_ind1 $w_ind2,$h_ind2\" ";
}


sub paint_user_points($$) {
    my ($rh,$show) = @_;
    my ($tllat,$tllon,$bllat,$bllon,$brlat,$brlon,$trlat,$trlon);
    $tllat = ${$rh}{'tl_lat'};
    $tllon = ${$rh}{'tl_lon'};
    $bllat = ${$rh}{'bl_lat'};
    $bllon = ${$rh}{'bl_lon'};
    $brlat = ${$rh}{'br_lat'};
    $brlon = ${$rh}{'br_lon'};
    $trlat = ${$rh}{'tr_lat'};
    $trlon = ${$rh}{'tr_lon'};
    my ($minlat,$maxlat,$minlon,$maxlon);
    my ($latdegs,$londegs,$sqwid,$sqhgt);
    $minlat = $bad_latlon;
    $maxlat = -$bad_latlon;
    $minlon = $bad_latlon;
    $maxlon = -$bad_latlon;

    my ($u_lat,$u_lon,$t_lat,$t_lon,$i,$cnt,$ru);

    # TEST SET OF 4, PLUS USRE'S POSITION
    $maxlat = $tllat if ($tllat > $maxlat);
    $maxlat = $bllat if ($bllat > $maxlat);
    $maxlat = $brlat if ($brlat > $maxlat);
    $maxlat = $trlat if ($trlat > $maxlat);

    $minlat = $tllat if ($tllat < $minlat);
    $minlat = $bllat if ($bllat < $minlat);
    $minlat = $brlat if ($brlat < $minlat);
    $minlat = $trlat if ($trlat < $minlat);

    $maxlon = $tllon if ($tllon > $maxlon);
    $maxlon = $bllon if ($bllon > $maxlon);
    $maxlon = $brlon if ($brlon > $maxlon);
    $maxlon = $trlon if ($trlon > $maxlon);

    $minlon = $tllon if ($tllon < $minlon);
    $minlon = $bllon if ($bllon < $minlon);
    $minlon = $brlon if ($brlon < $minlon);
    $minlon = $trlon if ($trlon < $minlon);

    # expand by User points
    if (defined ${$rh}{'user_points'}) {
        $ru = ${$rh}{'user_points'};
        $cnt = scalar @{$ru};
        for ($i = 0; $i < $cnt; $i++) {
            $u_lat = ${$ru}[$i][0];
            $u_lon = ${$ru}[$i][1];
            $t_lat = ${$ru}[$i][2];
            $t_lon = ${$ru}[$i][3];
            $maxlat = $u_lat if ($u_lat > $maxlat);
            $minlat = $u_lat if ($u_lat < $minlat);
            $maxlon = $u_lon if ($u_lon > $maxlon);
            $minlon = $u_lon if ($u_lon < $minlon);
        }
    }
    my $key = '';
    my $rcnt = 0;
    my $pcnt = 0;
    my ($rrwys,$rpatts);
    my ($elat1,$elon1,$elat2,$elon2);
    my ($plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$plat21,$plon21);
    #my ($plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$plat11,$plon11);
    if ((defined ${$rh}{'runways'})&&(defined ${$rh}{'pattern'})&&(defined ${$rh}{'airport'})) {
        $rrwys = ${$rh}{'runways'};
        $rpatts = ${$rh}{'pattern'};
        $key = ${$rh}{'airport'};
        $rcnt = scalar @{$rrwys};
        $pcnt = scalar @{$rpatts};
        prt("Adding $rcnt runways, and $pcnt patterns...\n");
        for ($i = 0; $i < $rcnt; $i++) {
            $elat1 = ${$rrwys}[$i][$RW_LLAT];
            $elon1 = ${$rrwys}[$i][$RW_LLON];
            $elat2 = ${$rrwys}[$i][$RW_RLAT];
            $elon2 = ${$rrwys}[$i][$RW_RLON];
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$elat1,$elon1);
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$elat2,$elon2);
        }
        for ($i = 0; $i < $pcnt; $i++) {
            #                   0       1       2       3       4       5       6       7
            # push(@{$rpatts}, [$plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$plat21,$plon21]);
            # push(@{$rpatts}, [$plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$plat11,$plon11]);
            $plat11 = ${$rpatts}[$i][0];
            $plon11 = ${$rpatts}[$i][1];
            $plat12 = ${$rpatts}[$i][2];
            $plon12 = ${$rpatts}[$i][3];
            $plat13 = ${$rpatts}[$i][4];
            $plon13 = ${$rpatts}[$i][5];
            $plat21 = ${$rpatts}[$i][6];
            $plon21 = ${$rpatts}[$i][7];
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$plat11,$plon11);
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$plat12,$plon12);
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$plat13,$plon13);
            set_min_max(\$maxlat,\$minlat,\$maxlon,\$minlon,$plat21,$plon21);
        }
    }

    ${$rh}{'max_lat'} = $maxlat;
    ${$rh}{'min_lat'} = $minlat;
    ${$rh}{'max_lon'} = $maxlon;
    ${$rh}{'min_lon'} = $minlon;
    my $lon_factor = 2;
    $latdegs = $maxlat - $minlat;
    $londegs = ($maxlon - $minlon) * $lon_factor;
    ${$rh}{'lon_degs'} = $londegs;
    ${$rh}{'lat_degs'} = $latdegs;
    $sqhgt = int(($latdegs * 10000) + 0.5);
    $sqwid = int(($londegs * 10000) + 0.5);
    ${$rh}{'sq_wid'} = $sqwid;
    ${$rh}{'sq_hgt'} = $sqhgt;

    # scale the image DOWN/up
    my $targ_wid = 400;
    my $ratio = $sqwid / $sqhgt;
    #if (($sqwid > $targ_wid) || ($sqhgt > $targ_wid)) {
        if ($ratio > 1) {   # width > height
            $sqwid = $targ_wid; # set target width
            $sqhgt = int($targ_wid / $ratio); # and calculate NEW height
	    } else {
            # height > width = set target height, adjust width accordingly
			$sqwid = int($targ_wid * $ratio); # calculate width
			$sqhgt = $targ_wid; # and set target width
        }
    #}
    ${$rh}{'sq_wid_adj'} = $sqwid;
    ${$rh}{'sq_hgt_adj'} = $sqhgt;

    my ($w_dpp,$h_dpp,$w_ind1,$h_ind1,$w_ind2,$h_ind2,$w_ind3,$h_ind3,$w_ind4,$h_ind4,$msg);
    my ($h_indu,$w_indu,$h_indt,$w_indt);
    $w_dpp = ($sqwid / $londegs) * $lon_factor;
    $h_dpp = $sqhgt / $latdegs;
    ${$rh}{'w_dpp'} = $w_dpp;
    ${$rh}{'h_dpp'} = $h_dpp;
    ${$rh}{'rmsg'} = \$msg;
    # Imagmagick colors - http://www.imagemagick.org/script/color.php
    $msg = "convert -size ${sqwid}x${sqhgt} xc:wheat +antialias -fill white ";
    #      -stroke Gold        -draw "path 'M 20,70  A 1,1 0 0,1 80,50'" \
    #      -stroke DodgerBlue  -draw "line 30,10  50,80" \
    #      -stroke Red         -draw "circle 80,60  82,60" \
    #      test.gif

    if (length($key) && $rcnt) {
        if ($pcnt) {
            $msg .= "-stroke SlateGray ";
            for ($i = 0; $i < $pcnt; $i++) {
                #                   0       1       2       3       4       5       6       7
                # push(@{$rpatts}, [$plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$plat21,$plon21]);
                # push(@{$rpatts}, [$plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$plat11,$plon11]);
                $plat11 = ${$rpatts}[$i][0];
                $plon11 = ${$rpatts}[$i][1];
                $plat12 = ${$rpatts}[$i][2];
                $plon12 = ${$rpatts}[$i][3];
                $plat13 = ${$rpatts}[$i][4];
                $plon13 = ${$rpatts}[$i][5];
                $plat21 = ${$rpatts}[$i][6];
                $plon21 = ${$rpatts}[$i][7];
                if ($i == 1) {
                    add_img_line($rh,$plat11,$plon11,$plat12,$plon12);
                    add_img_line($rh,$plat12,$plon12,$plat13,$plon13);
                    add_img_line($rh,$plat13,$plon13,$plat21,$plon21);
                    add_img_line($rh,$plat21,$plon21,$plat11,$plon11);
                }
                
            }
        }
        # set color
        $msg .= "-stroke blue ";
        for ($i = 0; $i < $rcnt; $i++) {
            $elat1 = ${$rrwys}[$i][$RW_LLAT];
            $elon1 = ${$rrwys}[$i][$RW_LLON];
            $elat2 = ${$rrwys}[$i][$RW_RLAT];
            $elon2 = ${$rrwys}[$i][$RW_RLON];
            $w_ind1 = int((($elon1 - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
            $h_ind1 = int((($elat1 - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
            $h_ind1 = $sqhgt - $h_ind1;
            $h_ind1 += 1 if ($h_ind1 == 0);
            $w_ind1 += 1 if ($w_ind1 == 0);
            $h_ind1 -= 1 if ($h_ind1 == $sqhgt);
            $w_ind1 -= 1 if ($w_ind1 == $sqwid);
            $msg .= "-draw \"circle ".($w_ind1-1).",$h_ind1 ".($w_ind1+1).",$h_ind1\" ";

            $w_ind2 = int((($elon2 - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
            $h_ind2 = int((($elat2 - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
            $h_ind2 = $sqhgt - $h_ind2;
            #$w_ind2 += 1 if ($w_ind2 == 0);
            $h_ind2 += 1 if ($h_ind2 == 0);
            $w_ind2 += 1 if ($w_ind2 == 0);
            $h_ind2 -= 1 if ($h_ind2 == $sqhgt);
            $w_ind2 -= 1 if ($w_ind2 == $sqwid);
            $msg .= "-draw \"circle ".($w_ind2-1).",$h_ind2 ".($w_ind2+1).",$h_ind2\" ";

            $msg .= "-draw \"line $w_ind1,$h_ind1 $w_ind2,$h_ind2\" ";
        }
    }
    # set color
    $msg .= "-stroke black ";
    # tllat,$tllon on square
    $w_ind1 = int((($tllon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind1 = int((($tllat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind1 = $sqhgt - $h_ind1;
    $h_ind1 += 1 if ($h_ind1 == 0);
    $w_ind1 += 1 if ($w_ind1 == 0);
    $h_ind1 -= 1 if ($h_ind1 == $sqhgt);
    $w_ind1 -= 1 if ($w_ind1 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind1-1).",$h_ind1 ".($w_ind1+1).",$h_ind1\" ";

    # bllat,$bllon on square
    $w_ind2 = int((($bllon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind2 = int((($bllat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind2 = $sqhgt - $h_ind2;
    #$w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 += 1 if ($h_ind2 == 0);
    $w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 -= 1 if ($h_ind2 == $sqhgt);
    $w_ind2 -= 1 if ($w_ind2 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind2-1).",$h_ind2 ".($w_ind2+1).",$h_ind2\" ";

    # brlat,$brlon on square
    $w_ind3 = int((($brlon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind3 = int((($brlat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind3 = $sqhgt - $h_ind3;
    #$w_ind3 += 1 if ($w_ind3 == 0);
    $h_ind3 += 1 if ($h_ind3 == 0);
    $w_ind3 += 1 if ($w_ind3 == 0);
    $h_ind3 -= 1 if ($h_ind3 == $sqhgt);
    $w_ind3 -= 1 if ($w_ind3 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind3-1).",$h_ind3 ".($w_ind3+1).",$h_ind3\" ";

    # trlat,$trlon on square
    $w_ind4 = int((($trlon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind4 = int((($trlat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind4 = $sqhgt - $h_ind4;
    #$w_ind4 += 1 if ($w_ind4 == 0);
    $h_ind4 += 1 if ($h_ind4 == 0);
    $w_ind4 += 1 if ($w_ind4 == 0);
    $h_ind4 -= 1 if ($h_ind4 == $sqhgt);
    $w_ind4 -= 1 if ($w_ind4 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind4-1).",$h_ind4 ".($w_ind4+1).",$h_ind4\" ";

    $msg .= "-draw \"line $w_ind1,$h_ind1 $w_ind2,$h_ind2\" ";
    $msg .= "-draw \"line $w_ind2,$h_ind2 $w_ind3,$h_ind3\" ";
    $msg .= "-draw \"line $w_ind3,$h_ind3 $w_ind4,$h_ind4\" ";
    $msg .= "-draw \"line $w_ind4,$h_ind4 $w_ind1,$h_ind1\" ";

    if (defined ${$rh}{'user_points'}) {
        $ru = ${$rh}{'user_points'};
        $cnt = scalar @{$ru};
        # u_lat,$u_lon on square
        for ($i = 0; $i < $cnt; $i++) {
            $u_lat = ${$ru}[$i][0];
            $u_lon = ${$ru}[$i][1];
            $t_lat = ${$ru}[$i][2];
            $t_lon = ${$ru}[$i][3];
            $w_indu = int((($u_lon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
            $h_indu = int((($u_lat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
            $h_indu = $sqhgt - $h_indu;
            $h_indu += 1 if ($h_indu == 0);
            $w_indu += 1 if ($w_indu == 0);
            $h_indu -= 1 if ($h_indu == $sqhgt);
            $w_indu -= 1 if ($w_indu == $sqwid);
            $msg .= "-stroke blue ";
            $msg .= "-draw \"circle ".($w_indu-1).",$h_indu ".($w_indu+1).",$h_indu\" ";
            # t_lat,$t_lon on square
            $w_indt = int((($t_lon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
            $h_indt = int((($t_lat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
            $h_indt = $sqhgt - $h_indt;
            $h_indt += 1 if ($h_indt == 0);
            $w_indt += 1 if ($w_indt == 0);
            $h_indt -= 1 if ($h_indt == $sqhgt);
            $w_indt -= 1 if ($w_indt == $sqwid);
            $msg .= "-draw \"circle ".($w_indu-1).",$h_indu ".($w_indu+1).",$h_indu\" ";
            $msg .= "-stroke red -draw \"line $w_indu,$h_indu $w_indt,$h_indt\" ";
        }
    }

    $msg .= "$graf_file\n";
    $msg .= "imdisplay $graf_file\n";
    write2file($msg,$graf_bat);
    prt("Written $graf_bat\n");
    if ($show) {
        set_lat_stg(\$maxlat);
        set_lat_stg(\$minlat);
        set_lon_stg(\$maxlon);
        set_lon_stg(\$minlon);
        prt("Square wid=$londegs hgt=$latdegs ${sqwid}X${sqhgt}\n");
        prt("TL $maxlat,$minlon\n");
        prt("BL $minlat,$minlon\n");
        prt("BR $minlat,$maxlon\n");
        prt("TR $maxlat,$maxlon\n");
    }
}

sub set_most_values_plus2($$$$$$) {
    my ($rh,$show,$u_lat,$u_lon,$t_lat,$t_lon) = @_;
    my ($tllat,$tllon,$bllat,$bllon,$brlat,$brlon,$trlat,$trlon);
    $tllat = ${$rh}{'tl_lat'};
    $tllon = ${$rh}{'tl_lon'};
    $bllat = ${$rh}{'bl_lat'};
    $bllon = ${$rh}{'bl_lon'};
    $brlat = ${$rh}{'br_lat'};
    $brlon = ${$rh}{'br_lon'};
    $trlat = ${$rh}{'tr_lat'};
    $trlon = ${$rh}{'tr_lon'};
    my ($minlat,$maxlat,$minlon,$maxlon);
    my ($latdegs,$londegs,$sqwid,$sqhgt);
    $minlat = $bad_latlon;
    $maxlat = -$bad_latlon;
    $minlon = $bad_latlon;
    $maxlon = -$bad_latlon;

    # TEST SET OF 4, PLUS USRE'S POSITION
    $maxlat = $tllat if ($tllat > $maxlat);
    $maxlat = $bllat if ($bllat > $maxlat);
    $maxlat = $brlat if ($brlat > $maxlat);
    $maxlat = $trlat if ($trlat > $maxlat);
    $maxlat = $u_lat if ($u_lat > $maxlat);

    $minlat = $tllat if ($tllat < $minlat);
    $minlat = $bllat if ($bllat < $minlat);
    $minlat = $brlat if ($brlat < $minlat);
    $minlat = $trlat if ($trlat < $minlat);
    $minlat = $u_lat if ($u_lat < $minlat);

    $maxlon = $tllon if ($tllon > $maxlon);
    $maxlon = $bllon if ($bllon > $maxlon);
    $maxlon = $brlon if ($brlon > $maxlon);
    $maxlon = $trlon if ($trlon > $maxlon);
    $maxlon = $u_lon if ($u_lon > $maxlon);

    $minlon = $tllon if ($tllon < $minlon);
    $minlon = $bllon if ($bllon < $minlon);
    $minlon = $brlon if ($brlon < $minlon);
    $minlon = $trlon if ($trlon < $minlon);
    $minlon = $u_lon if ($u_lon < $minlon);

    ${$rh}{'max_lat'} = $maxlat;
    ${$rh}{'min_lat'} = $minlat;
    ${$rh}{'max_lon'} = $maxlon;
    ${$rh}{'min_lon'} = $minlon;

    $latdegs = $maxlat - $minlat;
    $londegs = $maxlon - $minlon;
    ${$rh}{'lon_degs'} = $londegs;
    ${$rh}{'lat_degs'} = $latdegs;
    $sqwid = int(($latdegs * 10000) + 0.5);
    $sqhgt = int(($londegs * 10000) + 0.5);
    ${$rh}{'sq_wid'} = $sqwid;
    ${$rh}{'sq_hgt'} = $sqhgt;

    # scale the image DOWN/up
    my $targ_wid = 400;
    my $ratio = $sqwid / $sqhgt;
    #if (($sqwid > $targ_wid) || ($sqhgt > $targ_wid)) {
        if ($ratio > 1) {   # width > height
            $sqwid = $targ_wid; # set target width
            $sqhgt = int($targ_wid / $ratio); # and calculate NEW height
	    } else {
            # height > width = set target height, adjust width accordingly
			$sqwid = int($targ_wid * $ratio); # calculate width
			$sqhgt = $targ_wid; # and set target width
        }
    #}

    my ($w_dpp,$h_dpp,$w_ind1,$h_ind1,$w_ind2,$h_ind2,$w_ind3,$h_ind3,$w_ind4,$h_ind4,$msg);
    my ($h_indu,$w_indu,$h_indt,$w_indt);
    $w_dpp = $sqwid / $londegs;
    $h_dpp = $sqhgt / $latdegs;
    $msg = "convert -size ${sqwid}x${sqhgt} xc:wheat +antialias -fill white ";
    #      -stroke Gold        -draw "path 'M 20,70  A 1,1 0 0,1 80,50'" \
    #      -stroke DodgerBlue  -draw "line 30,10  50,80" \
    #      -stroke Red         -draw "circle 80,60  82,60" \
    #      sparse_source.gif

    # tllat,$tllon on square
    $w_ind1 = int((($tllon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind1 = int((($tllat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind1 = $sqhgt - $h_ind1;
    $h_ind1 += 1 if ($h_ind1 == 0);
    $w_ind1 += 1 if ($w_ind1 == 0);
    $h_ind1 -= 1 if ($h_ind1 == $sqhgt);
    $w_ind1 -= 1 if ($w_ind1 == $sqwid);
    $msg .= "-stroke black -draw \"circle ".($w_ind1-1).",$h_ind1 ".($w_ind1+1).",$h_ind1\" ";

    # bllat,$bllon on square
    $w_ind2 = int((($bllon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind2 = int((($bllat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind2 = $sqhgt - $h_ind2;
    #$w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 += 1 if ($h_ind2 == 0);
    $w_ind2 += 1 if ($w_ind2 == 0);
    $h_ind2 -= 1 if ($h_ind2 == $sqhgt);
    $w_ind2 -= 1 if ($w_ind2 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind2-1).",$h_ind2 ".($w_ind2+1).",$h_ind2\" ";

    # brlat,$brlon on square
    $w_ind3 = int((($brlon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind3 = int((($brlat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind3 = $sqhgt - $h_ind3;
    #$w_ind3 += 1 if ($w_ind3 == 0);
    $h_ind3 += 1 if ($h_ind3 == 0);
    $w_ind3 += 1 if ($w_ind3 == 0);
    $h_ind3 -= 1 if ($h_ind3 == $sqhgt);
    $w_ind3 -= 1 if ($w_ind3 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind3-1).",$h_ind3 ".($w_ind3+1).",$h_ind3\" ";

    # trlat,$trlon on square
    $w_ind4 = int((($trlon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_ind4 = int((($trlat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_ind4 = $sqhgt - $h_ind4;
    #$w_ind4 += 1 if ($w_ind4 == 0);
    $h_ind4 += 1 if ($h_ind4 == 0);
    $w_ind4 += 1 if ($w_ind4 == 0);
    $h_ind4 -= 1 if ($h_ind4 == $sqhgt);
    $w_ind4 -= 1 if ($w_ind4 == $sqwid);
    $msg .= "-draw \"circle ".($w_ind4-1).",$h_ind4 ".($w_ind4+1).",$h_ind4\" ";

    # u_lat,$u_lon on square
    $w_indu = int((($u_lon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_indu = int((($u_lat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_indu = $sqhgt - $h_indu;
    $h_indu += 1 if ($h_indu == 0);
    $w_indu += 1 if ($w_indu == 0);
    $h_indu -= 1 if ($h_indu == $sqhgt);
    $w_indu -= 1 if ($w_indu == $sqwid);
    $msg .= "-draw \"circle ".($w_indu-1).",$h_indu ".($w_indu+1).",$h_indu\" ";

    # t_lat,$t_lon on square
    $w_indt = int((($t_lon - $minlon) * $w_dpp) + 0.5); # get degrees/pixels from left edge
    $h_indt = int((($t_lat - $minlat) * $h_dpp) + 0.5); # get degrees/pixels from bottom edge
    $h_indt = $sqhgt - $h_indt;
    $h_indt += 1 if ($h_indt == 0);
    $w_indt += 1 if ($w_indt == 0);
    $h_indt -= 1 if ($h_indt == $sqhgt);
    $w_indt -= 1 if ($w_indt == $sqwid);
    $msg .= "-draw \"circle ".($w_indu-1).",$h_indu ".($w_indu+1).",$h_indu\" ";

    $msg .= "-draw \"line $w_ind1,$h_ind1 $w_ind2,$h_ind2\" ";
    $msg .= "-draw \"line $w_ind2,$h_ind2 $w_ind3,$h_ind3\" ";
    $msg .= "-draw \"line $w_ind3,$h_ind3 $w_ind4,$h_ind4\" ";
    $msg .= "-draw \"line $w_ind4,$h_ind4 $w_ind1,$h_ind1\" ";
    $msg .= "-stroke red -draw \"line $w_indu,$h_indu $w_indt,$h_indt\" ";

    $msg .= "$graf_file\n";
    $msg .= "imdisplay $graf_file\n";
    write2file($msg,$graf_bat);
    prt("Writtem $graf_bat\n");
    if ($show) {
        set_lat_stg(\$maxlat);
        set_lat_stg(\$minlat);
        set_lon_stg(\$maxlon);
        set_lon_stg(\$minlon);
        prt("Square wid=$londegs hgt=$latdegs ${sqwid}X${sqhgt}\n");
        prt("TL $maxlat,$minlon\n");
        prt("BL $minlat,$minlon\n");
        prt("BR $minlat,$maxlon\n");
        prt("TR $maxlat,$maxlon\n");
    }
}

sub get_circuit_hash() {
    my %h = ();
    $h{'tl_lat'} = $tl_lat;
    $h{'tl_lon'} = $tl_lon;
    $h{'bl_lat'} = $bl_lat;
    $h{'bl_lon'} = $bl_lon;
    $h{'br_lat'} = $br_lat;
    $h{'br_lon'} = $br_lon;
    $h{'tr_lat'} = $tr_lat;
    $h{'tr_lon'} = $tr_lon;
    set_circuit_values(\%h,1);
    #set_most_values(\%h,1);
    return \%h;
}

sub normalised_hdg($) {
    my $hdg = shift;
    $hdg += 360 if ($hdg < 0);
    $hdg -= 360 if ($hdg >= 360);
    return $hdg;
}

sub get_mid_tl2bl($$) {
    my ($rlat,$rlon) = @_;
    my ($az1,$az2,$dist);
    fg_geo_inverse_wgs_84 ($tl_lat,$tl_lon,$bl_lat,$bl_lon,\$az1,\$az2,\$dist);
    my $dist2 = $dist / 2;  # get the center of this line
    my ($clat,$clon);
    #fg_geo_direct_wgs_84( $tl_lat, $tl_lon, $az1, $dist2, $rlat, $rlon, \$az2 );
    fg_geo_direct_wgs_84( $tl_lat, $tl_lon, $az1, $dist2, \$clat, \$clon, \$az2 );
    $az2 = normalised_hdg($az1 + 90); # turn 90 degrees, and get a point
    fg_geo_direct_wgs_84( $clat, $clon, $az2, $dist2, $rlat, $rlon, \$az1 );

}
sub get_mid_bl2br($$) {
    my ($rlat,$rlon) = @_;
    my ($az1,$az2,$dist);
    fg_geo_inverse_wgs_84 ($bl_lat,$bl_lon,$br_lat,$br_lon,\$az1,\$az2,\$dist);
    my $dist2 = $dist / 2;
    fg_geo_direct_wgs_84( $bl_lat, $bl_lon, $az1, $dist2, $rlat, $rlon, \$az2 );
}
sub get_mid_bl2br2($$) {
    my ($rlat,$rlon) = @_;
    my ($az1,$az2,$dist);
    fg_geo_inverse_wgs_84 ($bl_lat,$bl_lon,$br_lat,$br_lon,\$az1,\$az2,\$dist);
    my $dist2 = $dist / 2;
    my ($clat,$clon);
    fg_geo_direct_wgs_84( $bl_lat, $bl_lon, $az1, $dist2, \$clat, \$clon, \$az2 );
    $az2 = normalised_hdg($az1 + 90); # turn 90 degrees, and get a point
    fg_geo_direct_wgs_84( $clat, $clon, $az2, $dist2, $rlat, $rlon, \$az1 );
}

sub set_distances_bearings($$$$) {
    my ($rh,$lat,$lon,$msg) = @_;
    ${$rh}{'usr_lat'} = $lat;
    ${$rh}{'usr_lon'} = $lon;
    ${$rh}{'usr_msg'} = $msg;
    my ($tlat,$tlon);
    my ($az1,$az2,$dist);
    $msg = '';

    $tlat = ${$rh}{'tl_lat'}; # = -31.684063;
    $tlon = ${$rh}{'tl_lon'}; # = 148.614120;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'tl_az1'} = $az1;
    ${$rh}{'tl_az2'} = $az2;
    ${$rh}{'tl_dist'} = $dist;
    set_dist_stg(\$dist);
    $msg .= "TL $dist ";
    $tlat = ${$rh}{'bl_lat'}; # = -31.723495;
    $tlon = ${$rh}{'bl_lon'}; # = 148.633003;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'bl_az1'} = $az1;
    ${$rh}{'bl_az2'} = $az2;
    ${$rh}{'bl_dist'} = $dist;
    set_dist_stg(\$dist);
    $msg .= "BL $dist ";

    $tlat = ${$rh}{'br_lat'}; # = -31.716778;
    $tlon = ${$rh}{'br_lon'}; # = 148.666992;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'br_az1'} = $az1;    # from 'test' to BR point
    ${$rh}{'br_az2'} = $az2;
    ${$rh}{'br_dist'} = $dist;
    set_dist_stg(\$dist);
    $msg .= "BR $dist ";

    $tlat = ${$rh}{'tr_lat'}; # = -31.672960;
    $tlon = ${$rh}{'tr_lon'}; # = 148.649139;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'tr_az1'} = $az1;
    ${$rh}{'tr_az2'} = $az2;
    ${$rh}{'tr_dist'} = $dist;
    set_dist_stg(\$dist);
    $msg .= "TR $dist ";
    prt("Distances: $msg\n");

}

sub dist_less_or_equal5($$) {
    my ($dist,$min_dist) = @_;
    return 1 if ($dist <= $min_dist);
    my $d5 = $dist * 0.95;
    return 2 if ($d5 < $min_dist);
    return 0;
}


sub process_lat_lon($$$$) {
    my ($rh,$lat,$lon,$msg) = @_;
    prt("\nSolving lat=$lat, lon=$lon $msg\n");
    # get distances, and headings...
    my ($tlat,$tlon,$az1,$az2,$dist,$res);
    set_distances_bearings($rh,$lat,$lon,$msg);
    # 1: get closest point, on circuit
    # 1 Mile = 1609.344 Meters.
    my $min_dist = 12000 * 1700;
    my $hdto = 'unsolved';
    my $targ_lon = $bad_latlon;
    my $targ_lat = $bad_latlon;
    my $targ_dist = 1000000000;
    my ($hdg);

    $tlat = ${$rh}{'tl_lat'}; # = -31.684063;
    $tlon = ${$rh}{'tl_lon'}; # = 148.614120;
    $az1  = ${$rh}{'tl_az1'};
    $az2  = ${$rh}{'tl_az2'};
    $dist = ${$rh}{'tl_dist'};
    $res = 0;
    #if ($dist < $min_dist) {
        $min_dist = $dist;
        $hdto = "to top left ($res)";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    #}

    $tlat = ${$rh}{'bl_lat'}; # = -31.684063;
    $tlon = ${$rh}{'bl_lon'}; # = 148.614120;
    $az1  = ${$rh}{'bl_az1'};
    $az2  = ${$rh}{'bl_az2'};
    $dist = ${$rh}{'bl_dist'};
    #if ($dist <= $min_dist) {
    $res = dist_less_or_equal5($dist,$min_dist);
    if ($res) {
        $min_dist = $dist;
        $hdto = "to bottom left ($res)";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    $tlat = ${$rh}{'br_lat'}; # = -31.684063;
    $tlon = ${$rh}{'br_lon'}; # = 148.614120;
    $az1  = ${$rh}{'br_az1'};
    $az2  = ${$rh}{'br_az2'};
    $dist = ${$rh}{'br_dist'};
    #if ($dist < $min_dist) {
    $res = dist_less_or_equal5($dist,$min_dist);
    if ($res) {
        $min_dist = $dist;
        $hdto = "to bottom right ($res)";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    $tlat = ${$rh}{'tr_lat'}; # = -31.684063;
    $tlon = ${$rh}{'tr_lon'}; # = 148.614120;
    $az1  = ${$rh}{'tr_az1'};
    $az2  = ${$rh}{'tr_az2'};
    $dist = ${$rh}{'tr_dist'};
    #if ($dist <= $min_dist) {
    $res = dist_less_or_equal5($dist,$min_dist);
    if ($res) {
        $min_dist = $dist;
        $hdto = "to top right ($res)";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }

    $tlat = ${$rh}{'tl_lat'}; # = -31.684063;
    $tlon = ${$rh}{'tl_lon'}; # = 148.614120;
    $az1  = ${$rh}{'tl_az1'};
    $az2  = ${$rh}{'tl_az2'};
    $dist = ${$rh}{'tl_dist'};
    $res = dist_less_or_equal5($dist,$min_dist);
    if ($res) {
        $min_dist = $dist;
        $hdto = "to top left ($res)";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }

    set_most_values_plus($rh,1,$lat,$lon,$targ_lat,$targ_lon);

    # for display
    set_hdg_stg(\$hdg);
    set_dist_stg(\$targ_dist);
    set_lat_stg(\$targ_lat);
    set_lon_stg(\$targ_lon);
    prt("\nHeading: $hdto, hdg=$hdg, to $targ_lat,$targ_lon, at $targ_dist m.\n");

}

sub process_lat_lon2($$$$) {
    my ($rh,$lat,$lon,$msg) = @_;
    prt("\nSolving lat=$lat, lon=$lon $msg\n");
    # get distances, and headings...
    my ($tlat,$tlon);
    my ($az1,$az2,$dist,$diff);
    my ($mindif,$hdto,$hdg);
    my ($targ_lat,$targ_lon,$targ_dist);
    my ($mindif2,$hdto2,$hdg2);
    my ($targ_lat2,$targ_lon2,$targ_dist2);
    my $max_diff = 3;

    prt("Show distance, azmuth to circuit...\n");
    $mindif = 400;
    $hdto = 'unsolved';
    $targ_lon = $bad_latlon;
    $targ_lat = $bad_latlon;
    $targ_dist = 1000000000;
    $mindif2 = 400;
    $hdto2 = 'unsolved';
    $targ_lon2 = $bad_latlon;
    $targ_lat2 = $bad_latlon;
    $targ_dist2 = 1000000000;
    
    $tlat = ${$rh}{'tl_lat'}; # = -31.684063;
    $tlon = ${$rh}{'tl_lon'}; # = 148.614120;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'tl_az1'} = $az1;
    ${$rh}{'tl_az2'} = $az2;
    ${$rh}{'tl_dist'} = $dist;
    set_dist_stg(\$dist);
    set_hdg_stg(\$az1);
    prt("tl $dist m, on $az1 ");
    # check if from test pos to this point is close to the same track - +/- a degree or so
    # from TL to BL ${$rh}{'l1_az1'} = $az1;
    $az2 = ${$rh}{'l1_az1'};
    $diff = abs(${$rh}{'tl_az1'} - ${$rh}{'l1_az1'});
    ${$rh}{'tl2bl'} = $diff;
    if ($diff < $mindif) {
        $mindif = $diff;
        $hdto = "to top left";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    set_hdg_stg(\$az2);
    set_hdg_stg(\$diff);
    prt("to join $az2 (tl2bl) diff=$diff ");
    # diff of test -> TL and TR -> TL
    $diff = abs(${$rh}{'tl_az1'} - ${$rh}{'l4_az1'});
    if (($diff < $max_diff)&&($diff < $mindif2)) {
        $mindif2 = $diff;
        $hdto2 = "to bottom left";
        $hdg2 = $az1;
        $targ_lat2 = $tlat;
        $targ_lon2 = $tlon;
        $targ_dist2 = $dist;
    }
    set_hdg_stg(\$diff);
    prt("test->TL and TR->TL $diff");
    prt("\n");


    $tlat = ${$rh}{'bl_lat'}; # = -31.723495;
    $tlon = ${$rh}{'bl_lon'}; # = 148.633003;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'bl_az1'} = $az1;
    ${$rh}{'bl_az2'} = $az2;
    ${$rh}{'bl_dist'} = $dist;
    set_dist_stg(\$dist);
    set_hdg_stg(\$az1);
    prt("bl $dist m, on $az1 ");
    $az2 = ${$rh}{'l2_az1'};
    $diff = abs(${$rh}{'bl_az1'} - ${$rh}{'l2_az1'});
    ${$rh}{'bl2br'} = $diff;
    if ($diff < $mindif) {
        $mindif = $diff;
        $hdto = "to bottom left";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    set_hdg_stg(\$az2);
    set_hdg_stg(\$diff);
    prt("to join $az2 (bl2br) diff=$diff ");
    # diff of test -> BL and TL -> BL
    $diff = abs(${$rh}{'bl_az1'} - ${$rh}{'l1_az1'});
    if (($diff < $max_diff)&&($diff < $mindif2)) {
        $mindif2 = $diff;
        $hdto2 = "to bottom right";
        $hdg2 = $az1;
        $targ_lat2 = $tlat;
        $targ_lon2 = $tlon;
        $targ_dist2 = $dist;
    }
    set_hdg_stg(\$diff);
    prt("test->BL and TL->BL $diff");
    prt("\n");

    $tlat = ${$rh}{'br_lat'}; # = -31.716778;
    $tlon = ${$rh}{'br_lon'}; # = 148.666992;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'br_az1'} = $az1;    # from 'test' to BR point
    ${$rh}{'br_az2'} = $az2;
    ${$rh}{'br_dist'} = $dist;
    set_dist_stg(\$dist);
    set_hdg_stg(\$az1);
    prt("br $dist m, on $az1 ");
    $az2 = ${$rh}{'l3_az1'};
    $diff = abs(${$rh}{'br_az1'} - ${$rh}{'l3_az1'});
    ${$rh}{'br2tr'} = $diff;
    if ($diff < $mindif) {
        $mindif = $diff;
        $hdto = "to bottom right";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    set_hdg_stg(\$diff);
    set_hdg_stg(\$az2);
    prt("to join $az2 (br2tr) diff=$diff ");
    # diff of test -> BR and BL -> BR
    $diff = abs(${$rh}{'br_az1'} - ${$rh}{'l2_az1'});
    if (($diff < $max_diff)&&($diff < $mindif2)) {
        $mindif2 = $diff;
        $hdto2 = "to top right";
        $hdg2 = $az1;
        $targ_lat2 = $tlat;
        $targ_lon2 = $tlon;
        $targ_dist2 = $dist;
    }
    set_hdg_stg(\$diff);
    prt("test->BR and BL->BR $diff");
    prt("\n");


    $tlat = ${$rh}{'tr_lat'}; # = -31.672960;
    $tlon = ${$rh}{'tr_lon'}; # = 148.649139;
    fg_geo_inverse_wgs_84 ($lat,$lon,$tlat,$tlon,\$az1,\$az2,\$dist);
    ${$rh}{'tr_az1'} = $az1;
    ${$rh}{'tr_az2'} = $az2;
    ${$rh}{'tr_dist'} = $dist;
    set_dist_stg(\$dist);
    set_hdg_stg(\$az1);
    prt("tr $dist m, on $az1 ");
    $az2 = ${$rh}{'l4_az1'};
    $diff = abs(${$rh}{'tr_az1'} - ${$rh}{'l4_az1'});
    ${$rh}{'tr2tl'} = $diff;
    if ($diff < $mindif) {
        $mindif = $diff;
        $hdto = "to top right";
        $hdg = $az1;
        $targ_lat = $tlat;
        $targ_lon = $tlon;
        $targ_dist = $dist;
    }
    set_hdg_stg(\$diff);
    set_hdg_stg(\$az2);
    prt("to join $az2 (tr2tl) diff=$diff ");
    # diff of test -> TR and BR -> TR
    $diff = abs(${$rh}{'tr_az1'} - ${$rh}{'l3_az1'});
    if (($diff < $max_diff)&&($diff < $mindif2)) {
        $mindif2 = $diff;
        $hdto2 = "to top left";
        $hdg2 = $az1;
        $targ_lat2 = $tlat;
        $targ_lon2 = $tlon;
        $targ_dist2 = $dist;
    }
    set_hdg_stg(\$diff);
    prt("test->TR and BR->TR $diff");
    prt("\n");

    if ($hdto2 eq 'unsolved') {
        set_most_values_plus($rh,1,$lat,$lon,$targ_lat,$targ_lon);
        set_hdg_stg(\$mindif);
        prt("\nHeading: $hdto, hdg=$hdg, min diff $mindif, to $targ_lat,$targ_lon, at $targ_dist m.\n");
    } else {
        set_most_values_plus($rh,1,$lat,$lon,$targ_lat2,$targ_lon2);
        set_hdg_stg(\$mindif2);
        prt("\nHeading: $hdto2, hdg2=$hdg, min diff $mindif2, to $targ_lat2,$targ_lon2, at $targ_dist2 m.\n");
    }
}

#########################################
### MAIN ###
parse_args(@ARGV);
my $ref_hash = get_circuit_hash();
init_runway_array();
get_runways_and_pattern($ref_hash,'YGIL');
process_lat_lon($ref_hash,$in_lat,$in_lon,"User input.");
get_mid_tl2bl(\$in_lat,\$in_lon);
process_lat_lon($ref_hash,$in_lat,$in_lon,"Mid tl2bl point.");
#get_mid_bl2br(\$in_lat,\$in_lon);
get_mid_bl2br2(\$in_lat,\$in_lon);
process_lat_lon($ref_hash,$in_lat,$in_lon,"Mid bl2br point.");
paint_user_points($ref_hash,1);

pgm_exit(0,"");
########################################
sub give_help {
    prt("$pgmname: version 0.0.1 2010-09-11\n");
    prt("Usage: $pgmname [options] lat,lon\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,@arr,$lat,$lon);
    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 {
            @arr = split(",",$arg);
            if (scalar @arr == 2) {
                $lat = $arr[0];
                $lon = $arr[1];
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        }
        shift @av;
    }

    if ((($in_lat == $bad_latlon)||($in_lon == $bad_latlon)) && $debug_on) {
        @arr = split(",",$def_latlon);
        if (scalar @arr == 2) {
            $lat = $arr[0];
            $lon = $arr[1];
            if (in_world_range($lat,$lon)) {
                $in_lat = $lat;
                $in_lon = $lon;
                prt("Set lat=$in_lat, lon=$in_lon\n");
            } else {
                pgm_exit(1,"ERROR: lat=$lat, lon=$lon OUT OF WORLD RANGE!\n");
            }
        } else {
            pgm_exit(1,"ERROR: Default is invlalid\n");
        }
    }
    if (($in_lat == $bad_latlon)||($in_lon == $bad_latlon)) {
        pgm_exit(1,"ERROR: No lat,lon found in command!\n");
    }
}

# eof - solve.pl
