gencircuit.pl to HTML.

index -|- end

Generated: Sat Oct 24 16:35:19 2020 from gencircuit.pl 2020/01/26 41.2 KB. text copy

#!/usr/bin/perl -w
# NAME: gencircuit.pl
# AIM: Experiments with generating a flight circuit for an airport.
# Inistially for YGIL, then YSDU airport, but want to expand that...
# given a GPS point, plot a TRACK, to join the VFR circuit, ....
# 2020-01-24 - review...
# 27/06/2015 geoff mclane http://geoffair.net/mperl
use strict;
use warnings;
use File::Basename;  # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] )
use Math::Trig;
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";
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 = $temp_dir.$PATH_SEP."temp.$pgmname.txt";
open_log($outfile);

# user variables
my $VERS = "0.0.6 2020-01-24";
# $VERS = "0.0.5 2015-01-09";
my $load_log = 0;
my $in_file = '';
my $verbosity = 0;
my $out_file = '';
my ($start_lat,$start_lon);
my ($next_targ_lat,$next_targ_lon);
# ### DEBUG ###
my $debug_on = 0;
my $def_file = 'def_file';

my $tmp_circuit = $perl_dir."\\tempcircuit2.txt";
my $tmp_circuit_xg = $perl_dir."\\tempcircuit2.xg";

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

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

my $dbg_01 = 0;
my $dbg_02 = 0;

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

### 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;

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 - will be replaced by CALCULATED values
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;
my $use_pattern = 1; # adjust the above values to the computed circuit
my $add_text_count = 1; # add text count
my $try_dash_line = 1;
##############################################################
my $switch_circuit = 0; # should DEPEND on the targeted RUNWAY
my $active_key = 'YGIL';
my $active_runway = '33';
# Access to RUNWAY INFORMATION, like
#    ${$rrwys}[$off][$RW_LLAT] = $elat1;
#    ${$rrwys}[$off][$RW_LLON] = $elon1;
#    ${$rrwys}[$off][$RW_RLAT] = $elat2;
#    ${$rrwys}[$off][$RW_RLON] = $elon2;
my ($active_ref_rwys,$active_off_rwys);

# 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_rwys = ( [3984,  162.22, 0, '15', '33', -31.69656323, 148.6363057, 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; }

my ($ref_circuit_hash);


sub set_dist_stg($) {
    my ($rd) = @_;
    my $dist = ${$rd};
    my ($sc);
    if ($dist < 1000) {
        $dist = int($dist);
        $sc = 'm';
    } else {
        $dist = (int(($dist / 1000) * 10) / 10);
        $sc = 'Km';
    }
    ${$rd} = "$dist$sc";
}

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_decimal2_stg($) {
    my $r = shift;
    ${$r} =  int((${$r} + 0.005) * 100) / 100;
    ${$r} = "0.0" if (${$r} == 0);
    ${$r} .= ".0" if !(${$r} =~ /\./);
}
sub set_decimal3_stg($) {
    my $r = shift;
    ${$r} =  int((${$r} + 0.0005) * 1000) / 1000;
    ${$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_dist_m2kmnm_stg($) {
    my ($rd) = @_;
    my $distm = ${$rd};
    my $km = $distm;
    set_dist_stg(\$km);
    $km .= '/';
    $km .= get_dist_stg_nm($distm);
    ${$rd} = $km;
}

sub set_hdg_stg1($) {
    my ($rh) = @_;
    my $hdg = ${$rh};
    $hdg = (int(($hdg+0.05) * 10) / 10);
    ${$rh} = $hdg;
}

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

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

sub set_hdg_stg($) {
    my ($rh) = @_;
    my $hdg = ${$rh};
    $hdg = 360 if ($hdg == 0); # always replace 000 with 360 ;=))
    $hdg = sprintf("%03d",int($hdg+0.5));
    ${$rh} = $hdg;
}

sub set_hdg_stg3($) {
    my $r = shift;
    set_int_stg($r);
    my $r3 = sprintf("%3d",${$r});
    ${$r} = $r3;
}

sub set_int_dist_stg5($) {
    my $r = shift;
    set_int_stg($r);
    my $r5 = sprintf("%5d",${$r});
    ${$r} = $r5;
}

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

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 get_mid_pt($$$$) {
    my ($elat1,$elon1,$elat2,$elon2) = @_;
    my ($az1,$az2,$dist,$rclat,$rclon,$az3);
    fg_geo_inverse_wgs_84($elat1,$elon1,$elat2,$elon2,\$az1,\$az2,\$dist);
    fg_geo_direct_wgs_84($elat2,$elon2,$az2,($dist / 2),\$rclat,\$rclon,\$az3 );
    return ($rclat,$rclon,$az3);
}


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);
    return \%h;
}

sub set_circuit_values($$) {
    my ($rch,$show) = @_;
    my ($az1,$az2,$dist);
    my ($dwd,$dwa,$bsd,$bsa,$rwd,$rwa,$crd,$cra);
    my ($tllat,$tllon,$bllat,$bllon,$brlat,$brlon,$trlat,$trlon);
    my ($elat1,$elon1);  # nearest end

    fg_geo_inverse_wgs_84 (${$rch}{'tl_lat'},${$rch}{'tl_lon'},${$rch}{'bl_lat'},${$rch}{'bl_lon'},\$az1,\$az2,\$dist);
    ${$rch}{'l1_az1'} = $az1;
    ${$rch}{'l1_az2'} = $az2;
    ${$rch}{'l1_dist'} = $dist;
    ${$rch}{'TL'} = [$az1,$az2,$dist];

    fg_geo_inverse_wgs_84 (${$rch}{'bl_lat'},${$rch}{'bl_lon'},${$rch}{'br_lat'},${$rch}{'br_lon'},\$az1,\$az2,\$dist);
    ${$rch}{'l2_az1'} = $az1;
    ${$rch}{'l2_az2'} = $az2;
    ${$rch}{'l2_dist'} = $dist;
    ${$rch}{'BL'} = [$az1,$az2,$dist];

    fg_geo_inverse_wgs_84 (${$rch}{'br_lat'},${$rch}{'br_lon'},${$rch}{'tr_lat'},${$rch}{'tr_lon'},\$az1,\$az2,\$dist);
    ${$rch}{'l3_az1'} = $az1;
    ${$rch}{'l3_az2'} = $az2;
    ${$rch}{'l3_dist'} = $dist;
    ${$rch}{'BR'} = [$az1,$az2,$dist];

    fg_geo_inverse_wgs_84 (${$rch}{'tr_lat'},${$rch}{'tr_lon'},${$rch}{'tl_lat'},${$rch}{'tl_lon'},\$az1,\$az2,\$dist);
    ${$rch}{'l4_az1'} = $az1;
    ${$rch}{'l4_az2'} = $az2;
    ${$rch}{'l4_dist'} = $dist;
    ${$rch}{'TR'} = [$az1,$az2,$dist];

    ${$rch}{'rwy_ref'} = $active_ref_rwys;
    ${$rch}{'rwy_off'} = $active_off_rwys;

    # ================================================
    $tllat = ${$rch}{'tl_lat'};
    $tllon = ${$rch}{'tl_lon'};
    $bllat = ${$rch}{'bl_lat'};
    $bllon = ${$rch}{'bl_lon'};
    $brlat = ${$rch}{'br_lat'};
    $brlon = ${$rch}{'br_lon'};
    $trlat = ${$rch}{'tr_lat'};
    $trlon = ${$rch}{'tr_lon'};
    my $msg = "# $active_key circuit\n";
    $msg .= "[$active_key]\n";
    $msg .= "P1=$tllat,$tllon\n";
    $msg .= "P2=$bllat,$bllon\n";
    $msg .= "P3=$brlat,$brlon\n";
    $msg .= "P4=$trlat,$trlon\n";
    $msg .= "direction=anticlockwise\n";
    write2file($msg,$tmp_circuit);
    prt("Circuit written to $tmp_circuit file\n");
    # ================================================

    if ($show) {
        ### my ($elat2,$elon2);
        ### my ($az11,$az21,$dist1);

        $tllat = ${$rch}{'tl_lat'};
        $tllon = ${$rch}{'tl_lon'};
        $bllat = ${$rch}{'bl_lat'};
        $bllon = ${$rch}{'bl_lon'};
        $brlat = ${$rch}{'br_lat'};
        $brlon = ${$rch}{'br_lon'};
        $trlat = ${$rch}{'tr_lat'};
        $trlon = ${$rch}{'tr_lon'};

        # extract values
        $dwa = ${$rch}{'l1_az1'};
        $dwd = ${$rch}{'l1_dist'};
        $bsd = ${$rch}{'l2_dist'};
        $bsa = ${$rch}{'l2_az1'};
        $rwd = ${$rch}{'l3_dist'};
        $rwa = ${$rch}{'l3_az1'};
        $crd = ${$rch}{'l4_dist'};
        $cra = ${$rch}{'l4_az1'};

        # get NEAREST runway END
        $elat1 = ${$active_ref_rwys}[$active_off_rwys][$RW_LLAT];
        $elon1 = ${$active_ref_rwys}[$active_off_rwys][$RW_LLON];

        fg_geo_inverse_wgs_84 (${$rch}{'br_lat'},${$rch}{'br_lon'},$elat1,$elon1,\$az1,\$az2,\$dist);

        # get OTHER runway END
        # $elat2 = ${$active_ref_rwys}[$active_off_rwys][$RW_RLAT];
        # $elon2 = ${$active_ref_rwys}[$active_off_rwys][$RW_RLON];
        ### fg_geo_inverse_wgs_84 (${$rch}{'br_lat'},${$rch}{'br_lon'},$elat2,$elon2,\$az11,\$az21,\$dist1);

        # set for display - values DESTROYED for calculations
        # ===================================================

        set_dist_stg(\$dist);
        set_int_stg(\$az1);
        ### set_dist_stg(\$dist1);

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

        set_int_dist_stg5(\$dwd);
        set_hdg_stg3(\$dwa);
        set_int_dist_stg5(\$bsd);
        set_hdg_stg3(\$bsa);
        set_int_dist_stg5(\$rwd);
        set_hdg_stg3(\$rwa);
        set_int_dist_stg5(\$crd);
        set_hdg_stg3(\$cra);

        prt("l1 $dwd m, on $dwa (tl2bl) - downwind, turn $bsa to base\n");
        prt("l2 $bsd m, on $bsa (bl2br) - base,     turn $rwa to final $active_key $active_runway $dist on $az1\n");
        prt("l3 $rwd m, on $rwa (br2tr) - runway,   turn $cra to cross\n");
        prt("l4 $crd m, on $cra (tr2tl) - cross,    turn $dwa to downwind\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,$off,$key,$rpatts,$set) = @_;
    # set ENDS of runway
    my $rlen = ${$rrwys}[$off][$RW_LEN];
    my $rhdg = ${$rrwys}[$off][$RW_HDG];
    my $clat = ${$rrwys}[$off][$RW_CLAT];
    my $clon = ${$rrwys}[$off][$RW_CLON];
    my $rty1 = ${$rrwys}[$off][$RW_TT1];
    my $rty2 = ${$rrwys}[$off][$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}[$off][$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}[$off][$RW_LLAT] = $elat1;
    ${$rrwys}[$off][$RW_LLON] = $elon1;
    ${$rrwys}[$off][$RW_RLAT] = $elat2;
    ${$rrwys}[$off][$RW_RLON] = $elon2;
    ${$rrwys}[$off][$RW_DONE] = $off + 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:$set:$off: $key: $rty2 on $az1: $elat1,$elon1 and $rty1 on $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 ($use_pattern && ($key eq $active_key)) { # 'YGIL', 'YSDU'
    # if ($use_pattern && ($key eq 'YGIL')) {
        if ($switch_circuit) {
            # At YGIL, this is a 15 circuit (the prevailing wind! SSE...
            $tl_lat = $plat12;
            $tl_lon = $plon12;
            $bl_lat = $plat13;
            $bl_lon = $plon13;
            $br_lat = $plat21;
            $br_lon = $plon21;
            $tr_lat = $plat11;
            $tr_lon = $plon11;
            $active_runway = '05'; # '15';
        } else {
            # At YGIL, this is a 33 circuit
            $tl_lat = $plat22; #-31.684063;
            $tl_lon = $plon22; #148.614120;
            $bl_lat = $plat23; #-31.723495;
            $bl_lon = $plon23; #148.633003;
            $br_lat = $plat11; #-31.716778;
            $br_lon = $plon11; #148.666992;
            $tr_lat = $plat21; #-31.672960;
            $tr_lon = $plon21; #148.649139;
            $active_runway = '33';
        }
        prt("Set pattern as the rectangle for $key $active_runway...\n");
        $active_ref_rwys = $rrwys;
        $active_off_rwys = $off;
    }

    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);
        # This is the LONG downwind side 12 to 13
        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");
        #E.G. for YGIL - TO 15
        #On 162, at -31.7523059488988,148.65746239832 turn 72 to -31.7414611993009,148.696497359091
        #Is 2.1nm, on heading  72
        #On 72 at -31.7414611993009,148.696497359091, turn 342 to -31.630701184372,148.654359238954
        #Is 7.0nm, on heading 342
        #On 342 at -31.630701184372,148.654359238954 turn 252 to -31.6415460967825,148.615370603846
        #Is 2.1nm, on heading 252
        #On 252 at -31.6415460967825,148.615370603846 turn 162 to -31.7024233216057,148.638492502638
        #Is 3.8nm, on heading 165

        prt("On $hdgr at $plat21,$plon21 turn $hdg1R to $plat22,$plon22\n");
        show_distance_heading($plat21,$plon21,$plat22,$plon22);
        # This is the LONG downwind side 22 to 23
        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");
        #E.G. for YGIL, TO 33
        #On 342 at -31.6415460967825,148.615370603846 turn 252 to -31.6523790808638,148.576372922039
        #Is 2.1nm, on heading 252
        #On 252 at -31.6523790808638,148.576372922039 turn 162 to -31.7631387187979,148.618418340898
        #Is 7.0nm, on heading 162
        #On 162 at -31.7631387187979,148.618418340898 turn 72 to -31.7523059488988,148.65746239832
        #Is 2.1nm, on heading  72
        #On 72 at -31.7523059488988,148.65746239832 turn 342 to -31.6914326394609,148.634315743548
        #Is 3.8nm, on heading 342
    }

    @{$rpatts} = ();
    # add notional RIGHT side circuit first
    push(@{$rpatts}, [$plat11,$plon11,$plat12,$plon12,$plat13,$plon13,$plat21,$plon21,$clat,$clon,$rlen,$rhdg]);
    # then notional LEFT size circuit
    push(@{$rpatts}, [$plat21,$plon21,$plat22,$plon22,$plat23,$plon23,$plat11,$plon11,$clat,$clon,$rlen,$hdgr]);

}

sub init_runway_array() {
    my $rl = get_locations(); # %apt_locations, with YGIL, YSDU, ...
    my ($key,$off,$cnt,$rrwys,$rpatts,$set);
    $set = 0;
    foreach $key (keys %{$rl}) {
        $set++;
        $rrwys = ${$rl}{$key}[$OL_RWY];
        $rpatts = ${$rl}{$key}[$OL_PAT];
        $cnt = scalar @{$rrwys};
        for ($off = 0; $off < $cnt; $off++) {
            prt("Key $key: Doing set $set, offset $off of $cnt\n");
            set_runway_ends_and_patt($rrwys,$off,$key,$rpatts,$set);
        }
    }
    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(); # %apt_locations, with YGIL, YSDU, ...
    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_runway_ends($$) {
    my ($rrwys,$off) = @_;
    my $rlen = ${$rrwys}[$off][$RW_LEN];
    my $rhdg = ${$rrwys}[$off][$RW_HDG];
    my $clat = ${$rrwys}[$off][$RW_CLAT];
    my $clon = ${$rrwys}[$off][$RW_CLON];
    my $rty1 = ${$rrwys}[$off][$RW_TT1];
    my $rty2 = ${$rrwys}[$off][$RW_TT2];
    my $rwlen2 = ($rlen * $SG_FEET_TO_METER) / 2;
    my ($elat1,$elon1,$eaz1,$elat2,$elon2,$eaz2);
    my $hdg1 = $rhdg + 90;
    $hdg1 -= 360 if ($hdg1 >= 360);
    my $hdg2 = $rhdg - 90;
    $hdg2 += 360 if ($hdg2 < 0);
    my $xg = "# Runway ".${$rrwys}[$off][$RW_DONE]."\n";
    $elat1 = ${$rrwys}[$off][$RW_LLAT];
    $elon1 = ${$rrwys}[$off][$RW_LLON];
    $elat2 = ${$rrwys}[$off][$RW_RLAT];
    $elon2 = ${$rrwys}[$off][$RW_RLON];
    ###my $width = 250 * $SG_FEET_TO_METER / 2;    # maybe this is BIT large for YGIL
    my $width = 150 * $SG_FEET_TO_METER / 2;    # maybe this is BIT large for YGIL
    $xg .= "color blue\n";
    $xg .= "$elon1 $elat1\n";
    $xg .= "$elon2 $elat2\n";
    $xg .= "NEXT\n";
    my ($clat1,$clon1,$clat2,$clon2,$clat3,$clon3,$clat4,$clon4);
    my ($az1,$az2,$dist);
    my ($rclat,$rclon,$az3);
    fg_geo_inverse_wgs_84($elat1,$elon1,$elat2,$elon2,\$az1,\$az2,\$dist);
    fg_geo_direct_wgs_84( $elat1,$elon1,$az1,($dist / 2),\$rclat,\$rclon,\$az3 );
    my $daz = sprintf("%03u", int($az1));
    my $draz = sprintf("%03u", int($az3));
    $xg .= "anno $rclon $rclat RW $rty1/$rty2 $draz/$daz\n";
    fg_geo_direct_wgs_84( $elat1, $elon1, $hdg1, $width, \$clat1, \$clon1, \$eaz1 );
    fg_geo_direct_wgs_84( $elat1, $elon1, $hdg2, $width, \$clat2, \$clon2, \$eaz2 );
    fg_geo_direct_wgs_84( $elat2, $elon2, $hdg1, $width, \$clat3, \$clon3, \$eaz1 );
    fg_geo_direct_wgs_84( $elat2, $elon2, $hdg2, $width, \$clat4, \$clon4, \$eaz2 );
    $xg .= "color red\n";
    $xg .= "$clon1 $clat1\n";
    $xg .= "$clon2 $clat2\n";
    $xg .= "$clon4 $clat4\n";
    $xg .= "$clon3 $clat3\n";
    $xg .= "$clon1 $clat1\n";
    $xg .= "NEXT\n";
    return $xg;
}


# set current distances
# circuit decribed as
# top left tl    top right tr
#      ---------------
#      |             |
#           ...
#      |             |
#      ---------------
# bottom left bl bottom right br
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 = ''# start a DEBUG message
    $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# distance to top-left
    set_int_dist_stg5(\$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# distance to bottom left
    set_int_dist_stg5(\$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# distance to bottom right
    set_int_dist_stg5(\$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# distance to top right
    set_int_dist_stg5(\$dist);
    $msg .= "TR $dist ";
    prt("Distances: $msg\n");
}

sub get_next_pointset($$$$$) {
    my ($rh,$ptset,$rlat,$rlon,$show) = @_;
    my $nxps = 'none';
    my ($nlat,$nlon);
    if ($ptset eq 'TL') {
        $nxps = 'BL';
        $nlat = ${$rh}{'bl_lat'};
        $nlon = ${$rh}{'bl_lon'};
    } elsif ($ptset eq 'BL') {
        $nxps = 'BR';
        $nlat = ${$rh}{'br_lat'};
        $nlon = ${$rh}{'br_lon'};
    } elsif ($ptset eq 'BR') {
        $nxps = 'TR';
        $nlat = ${$rh}{'tr_lat'};
        $nlon = ${$rh}{'tr_lon'};
    } elsif ($ptset eq 'TR') {
        $nxps = 'TL';
        $nlat = ${$rh}{'tl_lat'};
        $nlon = ${$rh}{'tl_lon'};
    } else {
        prtw("WARNING: point [$ptset] set NOT one of 'TL', 'BR', 'TR', or 'TL'!");
    }
    ${$rlat} = $nlat;
    ${$rlon} = $nlon;
    prt("get_next_pointset: from $ptset to $nxps $nlat,$nlon\n") if ($show);
    return $nxps;
}


sub get_closest_ptset($$$$$$) {
    my ($rch,$slat,$slon,$rpt,$rlat,$rlon) = @_;
    set_distances_bearings($rch,$slat,$slon,"Initial position");
    my $pt = "TL";
    my $dist = ${$rch}{'tl_dist'};  # distance to top-left
    my $tlat = ${$rch}{'tl_lat'};
    my $tlon = ${$rch}{'tl_lon'};
    if (${$rch}{'bl_dist'} < $dist) {  # distance to bottom left
        # BOTTOM LEFT
        $dist = ${$rch}{'bl_dist'};
        $pt = "BL";
        $tlat = ${$rch}{'bl_lat'};
        $tlon = ${$rch}{'bl_lon'};
    }
    if (${$rch}{'br_dist'} < $dist) {  # distance to bottom right
        # BOTTOM RIGHT
        $dist = ${$rch}{'br_dist'};
        $pt = "BR";
        $tlat = ${$rch}{'br_lat'};
        $tlon = ${$rch}{'br_lon'};
    }
    if (${$rch}{'tr_dist'} < $dist) {  # distance to top right
        # TOP RIGHT
        $dist = ${$rch}{'tr_dist'};
        $pt = "TR";
        $tlat = ${$rch}{'tr_lat'};
        $tlon = ${$rch}{'tr_lon'};
    }
    ${$rpt} = $pt;
    ${$rlat} = $tlat;
    ${$rlon} = $tlon;
}

# This will return the next target when joining a circuit from in or out of current circuit
sub get_next_in_circuit_targ($$) {
    my ($slat,$slon) = @_;
    my $rch = $ref_circuit_hash;

    # get_closest_ptset($$$$$$)
    my ($pt,$tlat,$tlon);
    get_closest_ptset($rch,$slat,$slon,\$pt,\$tlat,\$tlon);

    my ($nlat,$nlon,$nxps);
    ## get next ptset
    $nxps = get_next_pointset($rch,$pt,\$nlat,\$nlon,0);

    ### This seems the BEST ;=))
    my ($clat,$clon);
    $clat = ($tlat + $nlat) / 2;
    $clon = ($tlon + $nlon) / 2;
    ### $next_targ_lat = $clat;
    ### $next_targ_lon = $clon;
    ## prt("Set target lat, lon $clat,$clon\n");
    my ($distm,$az1,$az2);
    
    fg_geo_inverse_wgs_84 ($slat,$slon,$clat,$clon,\$az1,\$az2,\$distm);

    ${$rch}{'user_lat'} = $slat;
    ${$rch}{'user_lon'} = $slon;
    ${$rch}{'target_lat'} = $clat;   # $targ_lat;
    ${$rch}{'target_lon'} = $clon;   # $targ_lon;
    ${$rch}{'target_hgd'} = $az1;
    ${$rch}{'target_dist'} = $distm;
    ${$rch}{'targ_ptset'} = $nxps;   # current chosen point = TARGET point
    ${$rch}{'prev_ptset'} = $pt;   # previous to get TARGET TRACK

    my $distnm = get_dist_stg_nm($distm);
    set_hdg_stg(\$az1);
    #    Suggest HEAD for
    prt("Suggest head for $clat,$clon, on $az1, $distnm, prev $pt, next $nxps\n");

}

# TL -31.6523791,148.5763729
# BL -31.7631387,148.6184183
# BR -31.7523059,148.6574624
# TR -31.6415461,148.6153706
sub sel_track_to_circuit($$) {

    my ($slat,$slon) = @_;

    my $min_lat = $slat;
    my $max_lat = $slat;
    my $min_lon = $slon;
    my $max_lon = $slon;

    my $rch = $ref_circuit_hash;
    my $xg = "# start lon,lat\n";
    $xg .= "color white\n";
    $xg .= "$slon $slat # current pos (lon,lat)\n";
    $xg .= "NEXT\n";
    $xg .= "anno $slon $slat Curr. POS\n";

    # start TOP LEFT
    #get_closest_ptset($$$$$$)
    my ($pt,$tlat,$tlon);
    get_closest_ptset($rch,$slat,$slon,\$pt,\$tlat,\$tlon);
    $xg .= "# track to nearest $pt\n";
    $xg .= "color white\n";
    $xg .= "$slon $slat\n";
    $xg .= "$tlon $tlat\n";
    $xg .= "NEXT\n";
    $xg .= "color white\n";
    $xg .= "$tlon $tlat # nearest circuit.\n";
    $xg .= "NEXT\n";
    # max min
    $min_lat = $tlat if ($tlat < $min_lat);
    $max_lat = $tlat if ($tlat > $max_lat);
    $min_lon = $tlon if ($tlat < $min_lon);
    $min_lon = $tlon if ($tlon > $max_lon);

    my ($clat,$clon,$az3) = get_mid_pt($slat,$slon,$tlat,$tlon);
    $az3 = sprintf("%03u", int($az3 + 0.5));
    $xg .= "anno $clon $clat track $az3\n";


    return $xg;

}

sub sel_track_to_circuit_NOT_GOOD($$) {

    my ($slat,$slon) = @_;

    my $min_lat = $slat;
    my $max_lat = $slat;
    my $min_lon = $slon;
    my $max_lon = $slon;

    my $rch = $ref_circuit_hash;
    my $xg = "# start lon,lat\n";
    $xg .= "color white\n";
    $xg .= "$slon $slat # current pos (lon,lat)\n";
    $xg .= "NEXT\n";
    $xg .= "anno $slon $slat Curr. POS\n";

    # start TOP LEFT
    #get_closest_ptset($$$$$$)
    my ($pt,$tlat,$tlon);
    get_closest_ptset($rch,$slat,$slon,\$pt,\$tlat,\$tlon);
    $xg .= "# track to nearest $pt\n";
    $xg .= "color white\n";
    $xg .= "$slon $slat\n";
    $xg .= "$tlon $tlat\n";
    $xg .= "NEXT\n";
    $xg .= "color white\n";
    $xg .= "$tlon $tlat # nearest circuit.\n";
    $xg .= "NEXT\n";
    # max min
    $min_lat = $tlat if ($tlat < $min_lat);
    $max_lat = $tlat if ($tlat > $max_lat);
    $min_lon = $tlon if ($tlat < $min_lon);
    $min_lon = $tlon if ($tlon > $max_lon);

    my ($nlat,$nlon,$nxps);
    $nxps = get_next_pointset($rch,$pt,\$nlat,\$nlon,1);
    $xg .= "# track to next $nxps\n";
    $xg .= "color green\n";
    $xg .= "$slon $slat\n";
    $xg .= "$nlon $nlat\n";
    $xg .= "NEXT\n";
    $xg .= "color white\n";
    $xg .= "$nlon $nlat # next on circuit\n";
    $xg .= "NEXT\n";

    # max min
    $min_lat = $nlat if ($nlat < $min_lat);
    $max_lat = $nlat if ($nlat > $max_lat);
    $min_lon = $nlon if ($nlat < $min_lon);
    $min_lon = $nlon if ($nlon > $max_lon);

    #######################################
    ### This seems the BEST ;=))
    my ($clat,$clon);

    $clat = ($tlat + $nlat) / 2;
    $clon = ($tlon + $nlon) / 2;
    $xg .= "# track to center...\n";
    $xg .= "color blue\n";
    $xg .= "$slon $slat\n";
    $xg .= "$clon $clat\n";
    $xg .= "NEXT\n";
    $xg .= "color white\n";
    $xg .= "$clon $clat # leg center point target lon,lat\n";
    $xg .= "NEXT\n";
    $xg .= "anno $clon $clat Join pt\n";
    $next_targ_lat = $clat;
    $next_targ_lon = $clon;

    # max min
    # $min_lat = $clat if ($clat < $min_lat);
    # $max_lat = $clat if ($clat > $max_lat);
    # $min_lon = $clon if ($clat < $min_lon);
    # $min_lon = $clon if ($clon > $max_lon);

    my $tmp = "# bbox of scene\n";
    $tmp .= "color gray\n";
    $tmp .= "$min_lon $min_lat\n";
    $tmp .= "$min_lon $max_lat\n";
    $tmp .= "$max_lon $max_lat\n";
    $tmp .= "$max_lon $min_lat\n";
    $tmp .= "$min_lon $min_lat\n";
    $tmp .= "NEXT\n";

    return $tmp.$xg;
}

sub get_track_to_circuit() {

    if (! defined $start_lat || !defined $start_lon) {
        prt("No start lat,lon given...\n");
        return "# no start lat,lon\n";
    }

    get_next_in_circuit_targ($start_lat,$start_lon);

    undef $next_targ_lat;
    undef $next_targ_lon;
    my $xg = sel_track_to_circuit($start_lat,$start_lon);
    if ( defined $next_targ_lat && defined $next_targ_lon) {
        my ($clat,$clon,$az1,$distm,$nxps,$ppt);
        my $rch = $ref_circuit_hash;
        $clat = ${$rch}{'target_lat'};   # $targ_lat;
        $clon = ${$rch}{'target_lon'};   # $targ_lon;
        $az1 =  ${$rch}{'target_hgd'};
        $distm = ${$rch}{'target_dist'};
        $nxps =  ${$rch}{'targ_ptset'};   # NEXT target point
        $ppt  =  ${$rch}{'prev_ptset'};   # PREVIOUS
        my $distnm = get_dist_stg_nm($distm);
        set_hdg_stg(\$az1);
        # prt("Set target lat, lon $clat,$clon, on $az1, $distnm\n");
        prt("Suggest HEAD for $next_targ_lat,$next_targ_lon, on $az1, $distnm,  prev $ppt, next $nxps\n");
    } else {
        prt("No next lat,lon selected...\n");
    }

    return $xg;
}


sub tri_hypotenuse($$) {
    my ($side1, $side2) = @_;
    return sqrt( ($side1 ** 2) + ($side2 ** 2) );
}

sub gen_circle_2_pts_of_r($$$$$$) {
    my ($x,$y,$x1,$y1,$rad,$flag) = @_;
    # circle 1
    #  (x-x1)^2 + (y-y1)^2 = r^2
    # circle 2
    # (x-x2)^2 + (y-y2)^2 = r^2
    my $d1 = ($x-$x1) * ($x-$x1);
    my $d2 = ($y-$y1) * ($y-$y1);
    my $r2 = $d1 + $d2;
    my $r  = sqrt($r2);
}


sub write_xg() {
    my ($tllat,$tllon,$bllat,$bllon,$brlat,$brlon,$trlat,$trlon);
    my $rch = $ref_circuit_hash;    # current circuit

    $tllat = ${$rch}{'tl_lat'};
    $tllon = ${$rch}{'tl_lon'};

    $bllat = ${$rch}{'bl_lat'};
    $bllon = ${$rch}{'bl_lon'};

    $brlat = ${$rch}{'br_lat'};
    $brlon = ${$rch}{'br_lon'};

    $trlat = ${$rch}{'tr_lat'};
    $trlon = ${$rch}{'tr_lon'};

    my $msg = "# $active_key circuit\n";
    $msg .= "color green\n";
    $msg .= "$tllon $tllat # top left\n";
    $msg .= "$bllon $bllat # bottom left\n";
    $msg .= "$brlon $brlat # bottom right\n";
    $msg .= "$trlon $trlat # top right\n";
    $msg .= "$tllon $tllat # top left - close\n";
    $msg .= "NEXT\n";
    ################################################
    # add annotations
    my $anno = "# add corner labels\n";
    $anno .= "anno $tllon $tllat TL\n";
    $anno .= "anno $bllon $bllat BL\n";
    $anno .= "anno $brlon $brlat BR\n";
    $anno .= "anno $trlon $trlat TR\n";
    my ($clat,$clon,$az3) = get_mid_pt($tllat,$tllon,$bllat,$bllon);
    $az3 = sprintf("%03u", int($az3 + 0.5));
    $anno .= "anno $clon $clat downwind $az3\n";
    ($clat,$clon,$az3) = get_mid_pt($bllat,$bllon,$brlat,$brlon);
    $az3 = sprintf("%03u", int($az3 + 0.5));
    $anno .= "anno $clon $clat base $az3\n";
    ($clat,$clon,$az3) = get_mid_pt($brlat,$brlon,$trlat,$trlon);
    my ($lat4,$lon4,$az4) = get_mid_pt($brlat,$brlon,$clat,$clon);
    $az4 = sprintf("%03u", int($az4 + 0.5));
    $anno .= "anno $lon4 $lat4 FINAL $az4\n";
    ($lat4,$lon4,$az4) = get_mid_pt($clat,$clon,$trlat,$trlon);
    $az4 = sprintf("%03u", int($az4 + 0.5));
    $anno .= "anno $lon4 $lat4 upwind $az4\n";
    ($clat,$clon,$az3) = get_mid_pt($trlat,$trlon,$tllat,$tllon);
    $az3 = sprintf("%03u", int($az3 + 0.5));
    $anno .= "anno $clon $clat crosswind $az3\n";

    $msg .= $anno;
    ################################################

    # add the runways
    my ($rl,$key,$rrwys,$cnt,$off);
    $rl = get_locations(); # %apt_locations, with YGIL, YSDU, ...
    $key = $active_key; # 'YGIL' 'YSDU'
    if (defined ${$rl}{$key}) {
        $rrwys = ${$rl}{$key}[$OL_RWY];
        $cnt = scalar @{$rrwys};
        for ($off = 0; $off < $cnt; $off++) {
            $msg .= set_runway_ends($rrwys,$off);
        }
    }
    $msg .= get_track_to_circuit();
    write2file($msg,$tmp_circuit_xg);
    prt("Circuit written to $tmp_circuit_xg file... use pv to view\n");
}

#########################################
### MAIN ###
#$active_key = 'YGIL';
#$active_runway = '33';
$active_key = 'YSDU';
$active_runway = '11';

parse_args(@ARGV);
#process_in_file($in_file);
init_runway_array();
$ref_circuit_hash = get_circuit_hash();
# ${$rch}{'TL'} = [$az1,$az2,$dist]; etc...
#get_runways_and_pattern($ref_circuit_hash,'YGIL');
get_runways_and_pattern($ref_circuit_hash,$active_key);
write_xg();
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,@arr);
    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);
            } elsif ($sarg =~ /^p/) {
                need_arg(@av);
                shift @av;
                $sarg = $av[0];
                if ($sarg =~ /,/) {
                    @arr = split(",",$sarg);
                    if (scalar @arr == 2) {
                        $start_lat = $arr[0];
                        $start_lon = $arr[1];
                    } else {
                        pgm_exit(1,"Argument '$sarg' did not split in 2 lat,lon\n");
                    }
                } else {
                    $start_lat = $sarg;
                    need_arg(@av);
                    shift @av;
                    $sarg = $av[0];
                    $start_lon = $sarg;
                }
            } else {
                pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n");
            }
        } else {
            #$in_file = $arg;
            pgm_exit(1,"Unknown bear argument '$arg'!\n");
        }
        shift @av;
    }
    # test 1 = 3 Km West of TL
    # $start_lat = -31.6523751810451;
    # $start_lon = 148.54474331625;
    # test 2 = 3 Km East of TL
    #$start_lat = -31.6523751810451;
    #$start_lon = 148.60800248375;
    # test 3 = 2 Km South of BR
    #$start_lat = -31.7811757576552;
    #$start_lon = 148.6184183;
    # test 4 = 3 Km North of BR
    #$start_lat = -31.7360830176463;
    #$start_lon = 148.6184183;
    # test 5 = from YSDU
    #$start_lat = -32.218722;
    #$start_lon = 148.570877;
    # test 6 btw TL BL YSDU
    #148.608615657398 -32.15433436718 # top left
    #148.494691699897 -32.2256985481814 # bottom left
    $start_lat = -32.15433436718;
    $start_lon = 148.494691699897;


    #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]\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");
    prt(" --pos lat,lon (-p) = Start position. Find best location to head for\n");
    prt("                      to join the circuit.\n");
}

# eof - gencircuit.pl

index -|- top

checked by tidy  Valid HTML 4.01 Transitional