Generated: Mon Aug 29 19:34:54 2016 from plandevol01-ok.pl 2014/10/01 56.6 KB. text copy
#!/usr/bin/perl # 20140930 from : http://seb.marque.free.fr/fichiers/scripts/perl/plandevol # l'option -w a été enlevée pour éviter l'affichage des warnings inutiles décrits ci-dessous: # Use of implicit split to @_ is deprecated at fgfs/plandevol-dev line ... # main::construction_route() called too early to check prototype at fgfs/plandevol-dev line ... # main::construction_route() called too early to check prototype at fgfs/plandevol-dev line ... ####################################################################################################################################################### ## *********************************************** ## ***** TRES IMPORTANT ***** VERY IMPORTANT ***** ## *********************************************** ## ## CE SCRIPT NE PROPOSE PAS UNE SOLUTION DE VOL FIABLE POUR LA CONSTRUCTION D'UN PLAN DE VOL RÉEL!!!!!!!! ## IL N'EST QU'UNE SOLUTION POUR PROPOSER UN TRAJET DE _LOISIR_ AVEC FLIGHTGEAR FS ET NE GARANTIT EN AUCUN CAS LA FIABILITÉ DES INFORMATIONS ## QU'IL DÉLIVRE ## ####################################################################################################################################################### ###################################################################################################################################################### ## ## script écrit par seb marque, paris, france ## ## plandevol, version 0.5.9 qui s'approche dangereusement de la version 0.6.0 ## --help pour une aide sur l'utilisation du script ## ## script placé sous licence GPL par Sébastien MARQUE ## texte complet disponible sur http://www.gnu.org/licenses/gpl.txt ## # This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ####################################################################################################################################################### ## ## les fonctions connect, set_prop, get_prop et send proviennent du script telnet.pl trouvé dans le code source de fgfs 0.98 (de Curtis L. Olson, ## avec "courtesy" pour Melchior Franz. ## ## les fonctions round, ll2xyz, xyz2ll, llll2dir (dont provient llll2dir_), distance (dont provient distance_) et coord_dist_sqr proviennent du script ## de Melchior Franz "freq" trouvé sur http://members.aon.at/mfranz/freq, en attente de leur remplacement éventuel par les fonctions de Math::Trig ## ###################################################################################################################################################### ## ## bugs connus: si une balise est situé dans l'enceinte du point d'arrivée elle n'est pas détectée... c'est dommage ## fixé la compatibilité avec les différentes versions de nav.dat.gz ## ## version 0.6 -> réglage auto des instruments de vol ## -> intégration des fix dans le plan de vol si nécessaire ## -> gestion des sid/star ## -> nettoyage du code ## ###################################################################################################################################################### use strict; use POSIX qw(ceil floor); use Getopt::Long; # pour récupérer les options en ligne de commande use IO::Socket; # pour la connexion telnet avec FlightGear use Env qw(HOME FGROOT FGHOME); # pour lire HOME FGHOME et FGROOT ## DECLARATION DES VARIABLES GLOBALES ##################################### my @depart = (undef, "LFPG", undef, undef,undef); # tableau contenant des infos sur l'aéroport de départ (sid, ICAO, lat, lon, nom complet de l'aéroport) my @arrivee = (undef, "LFBD", undef, undef,undef, undef); # tableau contenant des infos sur l'aéroport d'arrivée (star, ICAO, lat, lon, nom complet de l'aéroport) my $fgfs; # socket de connexion à fgfs my @route; # contient la route à suivre my ($navaid, $fix); # pointent sur les tableaux contenant les aides à la navigation my $erreur; # contient les messages d'erreur éventuels my $version; # pour la compatibilité avec différentes version de nav.dat.gz my $sous_fonction; # pointe vers des sous fonctions anonymes définies localement my $quiet = 1; # extra output # VARIABLES DES OPTIONS DU SCRIPT ################################# my $FGROOT = (exists $ENV{FGROOT})? $FGROOT : "F:\\fgdata"; my $FGHOME = (exists $ENV{FGHOME})? $FGHOME : "$HOME/.fgfs"; my $vor_a_vor; # exclusivement du vor my $vor_preferes; # si on veut du vor, mais sinon du ndb my $deviation_max = 30; # virage maximal my $dist_min = 10; # distance minimale entre deux waypoints my $km; # affichage des distances en kilomètres my $help; # demande d'aide my $csv_conf=':,'; # les séparateurs pour les fichiers .csv my $no_stdout; # pas de sortie sur le terminal my ($sidx, $starx); # protocole sid/star demandé sans spécifier de piste my ($sid, $star); # protocole sid/star demandé en spécifiant une piste my $add_couleur; # applique des couleurs à la sortie standard my ($com, $com_dep, $com_app); # pour afficher les fréqences de communication my $INSTRFILE; # création d'un fichier .xml my $wpt; #enregistrer la route my $WPFILE; # le fichier dans lequel on enregistre les points de passage my $CSVFILE; # le fichier dans lequel on enregistre les points de passage my $XGFILE; # le fichier dans lequel on enregistre les points de passage my $options = GetOptions ( "v|vor-a-vor" => \$vor_a_vor, "preferer-vor"=> \$vor_preferes, "km" => \$km, "dev-max=i" => \$deviation_max, "dist-min=i" => \$dist_min, "fg-root=s" => \$FGROOT, "wpt" => \$wpt, "instr" => \$INSTRFILE, "csv=s" => \$CSVFILE, "xg=s" => \$XGFILE, "csv-conf=s" => \$csv_conf, "d|dep=s" => \$depart[1], "a|arr=s" => \$arrivee[1], "no-stdout" => \$no_stdout, "help" => \$help, "sidx" => \$sidx, "starx" => \$starx, "sid=s" => \$sid, "star=s" => \$star, "com" => \$com, "com-dep" => \$com_dep, "com-app" => \$com_app, "ansi" => \$add_couleur); ($com_dep, $com_app) = ($com, $com) if $com; ## FICHIERS UTILISÉS PAR LE SCRIPT ## à modifier selon sa propre configuration ## accepte les fichiers en clair, ou gzipés ########################################### my $NAVFILE = "$FGROOT/Navaids/nav.dat.gz"; # le fichier contenant les aides à la navigation my $FIXFILE = "$FGROOT/Navaids/fix.dat.gz"; # le fichier contenant les fix my $SIDFILE = "$FGROOT/NavAids/sid.dat"; # le fichier contenant les procédures SID my $STARFILE = "$FGROOT/NavAids/star.dat"; # le fichier contenant les procédure STAR my $APTFILE = "$FGROOT/Airports/apt.dat.gz"; # le fichier contenant les aéroports ## DÉCLARÉ COMME VARIABLE MAIS UTILISÉ COMME CONSTANTE ###################################################### my $texte_aide = <<EOH; plandevol, v. 0.6.0 trouve une route de balises entre deux points. syntaxe: plandevol [-v | --vor-a-vor] [--preferer-vor] [--km] [--fg-root </PATH/TO/FG_DATA_FILES>] [--wpt] [--csv </PATH/TO/CSV_FILE>] [--csv-conf <colonnedécimal>] [--xg </PATH/TO/XG_FILE>] [-d | --dep <point de départ>] [-a | --arr <point d'arrivée>] [--dev-max <angle en degrés>] [--dist-min <distance en km>] [--sid <nom de piste>][--star <nom de piste>] [--sidx][--starx] [--com-dep][--com-app][--com] [--ansi] [--help] -v | --vor-a-vor : ne sélectionne que les balises VOR et VOR-DME (pas de TACAN) --preferer-vor : route construite avec NDB et VOR, avec une préférence pour les balises VOR --km : affiche la distance en km (défaut: affichage en nm) --fg-root : chemin contenant les fichiers de FlightGear défaut: $FGROOTT --wpt : enregistre la route dans \$FGROOT/Routes (nommage auto) directory must exist. It will not be created. --csv : fichier CSV ( séparateur = : , virgule décimale = , ) pour affichage du trajet en graphique (via oocalc par exemple) --xg : fichier XG. Can be viewed by polyView2D. See https://sites.google.com/site/polyview2d/ --csv-conf : paramètre les séparateurs de colonne et de décimale pour la fabrication du fichier csv. format = séparateurdécimale (ex: --csv-conf=?ù) pour des colonnes séparées par le caractère '?', et la virgule représentée par le caractère 'ù'. par défaut --csv-conf=$csv_conff -d | --dep : point de départ. il est possible de spécifier: - soit le code oaci de l'aéroport (ex: --dep=lfqq), défaut --dep=lfpt --arr=lfbd - soit la position actuelle de l'avion dans fgfs (ex: --dep=telnet:5401) - soit une position exprimée en lat, long (ex: --dep=[45.564,-2.066]) -a | --arr : point d'arrivée. même possibilités que l'option --dep --dev-max : déviation maximale d'une balise à une autre par rapport au trajet en cours (défaut: $deviation_max°) --dist-min : distance minimale entre deux balises (défaut: $dist_min km) --sid --star : cherche le trajet en tenant compte de la procédure sid (ou star) de la piste <nom de la piste> codé sur deux ou trois caractères (ex: --sid 09 --star 23, ou --sid 09R --star 23) si aucun indicatif de piste (R, C ou L) n'est fourni ils seront tous les trois inclus dans la recherche de procédure --sidx, --starx : idem que --sid et --star, mais avec une piste choisie par le programme: - pour le moment, le choix se porte sur la piste dont la procédure rapproche du point de départ/arrivée - dans le futur, il est prévu une implémentation avec les METAR (décollage/atterrissage face au vent) - selon l'évolution du fichier apt.dat, on peut imaginer un choix en fonction des pistes réellement usitées --com-dep, --com-app : affichent respectivement les fréquences COM pour le départ (dep) ou l'approche (app) --com : affiche les fréquences COM pour le départ et l'arrivée (équi- valent de --com-dep --com-app) --ansi : affiche les étapes en couleurs, pour les terminaux qui ne supportent pas la norme ANSI, ou pour redirection du résultat --help : affiche ce message d'aide et quitte (même si d'autres options ont été spécifiées) EOH my $PI = 3.1415926535897932384626433832795029; my $D2R = $PI / 180; my $R2D = 180 / $PI; my $ERAD = 6378138.12; #my $ERAD = 6378; my $NDB = 2; my $VOR = 3; my $KM2FEET = 3280,84; sub prt($) { print shift; } # FONCTIONS DE CONNEXION AVEC FGFS PAR TELNET ############################################# sub get_prop($$) { my( $handle ) = shift; &send( $handle, "get " . shift ); eof $handle and die "\nconnection closed by host"; $_ = <$handle>; s/\015?\012$//; /^-ERR (.*)/ and die "\nfgfs error: $1\n"; return $_; } sub set_prop($$$) { my( $handle ) = shift; my( $prop ) = shift; my( $value ) = shift; &send( $handle, "set $prop $value"); # eof $handle and die "\nconnection closed by host"; } sub send($$) { my( $handle ) = shift; print $handle shift, "\015\012"; } sub connect($$$) { my( $host ) = shift; my( $port ) = shift; my( $timeout ) = (shift || 120); my( $socket ); STDOUT->autoflush(1); while ($timeout--) { if ($socket = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => $host, PeerPort => $port) ) { $socket->autoflush(1); return $socket; } print "Attempting to connect to $host ... " . $timeout . "\n"; sleep(1); } return 0; } # FONCTIONS DE CALCULS GEOGRAPHIQUES # par Frank Melchior #################################### sub round($) { my $i = shift; my $m = (shift or 1); $i /= $m; $i = $i - &floor($i) >= 0.5 ? &ceil($i) : &floor($i); $i *= $m; return $i; } sub coord_dist_sq($$$$$$) { my ($xa, $ya, $za, $xb, $yb, $zb) = @_; my $x = $xb - $xa; my $y = $yb - $ya; my $z = $zb - $za; return $x * $x + $y * $y + $z * $z; } sub ll2xyz($$) { my $lat = (shift) * $D2R; my $lon = (shift) * $D2R; my $cosphi = cos $lat; my $di = $cosphi * cos $lon; my $dj = $cosphi * sin $lon; my $dk = sin $lat; return ($di, $dj, $dk); } # return km distance sub distance_($) { my $t = shift; my @ll1 = ll2xyz($t->[0], $t->[1]); my @ll2 = ll2xyz($t->[2], $t->[3]); return $ERAD * sqrt(coord_dist_sq($ll1[0], $ll1[1], $ll1[2], $ll2[0], $ll2[1], $ll2[2])) / 1000; } sub llll2dir_($) { my $t = shift; my $latA = ($t->[0]) * $D2R; my $lonA = ($t->[1]) * $D2R; my $latB = ($t->[2]) * $D2R; my $lonB = ($t->[3]) * $D2R; my $xdist = sin($lonB - $lonA) * $ERAD * cos(($latA + $latB) / 2); my $ydist = sin($latB - $latA) * $ERAD; my $dir = atan2($xdist, $ydist) * $R2D; $dir += 360 if $dir < 0; return $dir; } # FONCTIONS DE CALCUL DU TRAJET # passed reference to # my @depart = (undef, "LFPG", undef, undef,undef); # or @arrivee ... ############################### sub configure_extremite ($$$) { my ($extremite, $proc, $procx) = @_; my $extremite_ok; # positionné à 1 si l'extrémité a pu être configuré, # sera la valeur de retour de la fonction sub getPositionParTelnet ($) { # si on est pas déjà connecté, alors on se connecte if (!$fgfs) { if ( !($fgfs = &connect("localhost", $_[0], 5)) ) { print "Impossible de se connecter\n"; } } # on récupère la position actuelle de l'appareil my $lat = get_prop ($fgfs,"/position/latitude-deg[0]"); my $lon = get_prop ($fgfs, "/position/longitude-deg[0]"); # si la postion est trouvée (limitation: ~ est différente de 0°00'00''N 0°00'00''E) if ($lat && $lon) { $extremite_ok = 1; return $lat, $lon; } else { $erreur = "Impossible de déterminer la position actuelle de l'appareil\n"; } } $sous_fonction = sub { my @donnees_aeroport; my ($ver,$rtype); # si le fichier de base d'aéroports existe, on l'ouvre sinon on termine le programme if ( -e $APTFILE ) { open (APT, "gzip -d -c $APTFILE|") or die "je ne peux pas ouvrir $APTFILE\n" ; while (<APT>) { if (/^(\d+)\s+Version\s+/) { $ver = $1; last; } } } else { print "fichier $APTFILE introuvable\n"; print "veuillez vérifier \$FGROOT\n"; print "ou utilisez l'option --fg-root=répertoire\n"; die "ou encore modifiez le script ligne 80\n"; } if ($ver) { prt("Searching file $APTFILE, version $ver, for ${$extremite}[1]... moment...\n") if (!$quiet); } else { close APT; die "Failed to find version in $APTFILE!\n"; } # on parcours le fichier à la recherche de l'aéroport souhaité while (<APT>) { if (/^1\s+-?\d+\s\d\s\d\s(\w+)\s(.+)/ && $1 eq $_[0]->[1]) { chomp; prt("Airport: $_\n") if (!$quiet); my @header = split (/\s+/, $_, 6); push @donnees_aeroport, \@header; my $autre_bout; foreach (<APT>) { last if /^\s*$/; my @donnee = split (/\s+/, $_); $rtype = $donnee[0]; # s'il s'agit d'une piste, on la renomme en ajoutant son autre extrémité if ($rtype == 10 && $donnee[3] ne 'xxx') { # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 # 10 36.962213 127.031071 14x 131.52 8208 1595.0620 0000.0000 150 321321 1 0 3 0.25 0 0300.0300 # 10 36.969145 127.020106 xxx 221.51 329 0.0 0.0 75 161161 1 0 0 0.25 0 $donnee[3] =~ /(..)(.)/; $autre_bout = ($1 > 18)? $1 - 18 : $1 + 18; $autre_bout = '0'.$autre_bout if ($autre_bout < 10); $autre_bout .= 'L' if ($2 eq 'R'); $autre_bout .= 'R' if ($2 eq 'L'); $autre_bout .= 'C' if ($2 eq 'C'); if ($2 eq 'x') { $donnee[3] = $1.' '; $autre_bout .= ' '; } $donnee[3] = $donnee[3].'/'.$autre_bout; push (@donnees_aeroport, \@donnee) } elsif ($rtype == 100) { # See version 1000 specs # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 100 29.87 3 0 0.00 1 2 1 16 43.91080605 004.90321905 0.00 0.00 2 0 0 0 34 43.90662331 004.90428974 0.00 0.00 2 0 0 0 my $rwy = $donnee[8]; my $rwynm = $rwy; $rwynm =~ /(..)(.)/; $autre_bout = ($1 > 18)? $1 - 18 : $1 + 18; $autre_bout = '0'.$autre_bout if ($autre_bout < 10); $autre_bout .= 'L' if ($2 eq 'R'); $autre_bout .= 'R' if ($2 eq 'L'); $autre_bout .= 'C' if ($2 eq 'C'); if ($2 eq 'x') { $rwy = $1.' '; $autre_bout .= ' '; } $rwynm = $rwy.'/'.$autre_bout; my $rlat1 = $donnee[9]; # $of_lat1 my $rlon1 = $donnee[10]; # $of_lon1 my $rlat2 = $donnee[18]; # $of_lat2 my $rlon2 = $donnee[19]; # $of_lon2 my $rlat = ($rlat1 + $rlat2) / 2; my $rlon = ($rlon1 + $rlon2) / 2; my $dist = distance_( [$rlat1, $rlon1, $rlat2, $rlon2] ); $dist = int( $dist * $KM2FEET ); # runway length, in feet my $az1 = llll2dir_( [$rlat1, $rlon1, $rlat2, $rlon2] ); $az1 = round( $az1 * 100 ) / 100; my @a = (); #push(@a,[10, $rlat, $rlon, $rwynm, $az1, $dist, 0.0, 0.0, 75, 161161, 1, 0, 0, 0.25, 0, 0]); @a = (10, $rlat, $rlon, $rwynm, $az1, $dist, 0.0, 0.0, 75, 161161, 1, 0, 0, 0.25, 0, 0); prt("Runway: 10, $rlat, $rlon, $rwynm, $az1, $dist, ...\n") if (!$quiet); push (@donnees_aeroport, \@a); } # on garde aussi les fréquences COM... push (@donnees_aeroport, \@donnee) if (($rtype >= 50)&&($rtype <= 56)); } } } close (APT); prt("Closed $APTFILE...\n") if (!$quiet); # on récupère ses coordonnées de la première piste listée... pour l'instant my $lcnt = scalar @donnees_aeroport; if ($lcnt > 0) { my ($i,$ra,$alat,$alon); for ($i = 0; $i < $lcnt; $i++) { $ra = $donnees_aeroport[$i]; $rtype = ${$ra}[0]; ### prt("$i: rtype $rtype\n"); if ($rtype == 10) { $alat = ${$ra}[1]; $alon = ${$ra}[2]; $extremite_ok = 1; last; } } if ($extremite_ok) { prt("Success: lat/lon $alat,$alon, $lcnt records...\n") if (!$quiet); # return @{$donnees_aeroport[1]}[1], @{$donnees_aeroport[1]}[2], \@donnees_aeroport; return $alat,$alon,\@donnees_aeroport; } $erreur = 'No runways found for '.$_[0]->[1]."..."; } else { # ces lignes ne atteintes que si aucun aéroport a été trouvé dans la base $erreur = $_[0]->[1]." n'a pas été trouvé dans la base de données aéroports..."; } }; # to UPPER case $extremite->[1] =~ tr/a-z/A-Z/; if ($extremite->[1] =~ /^TELNET:(\d+)/) { # position actuelle de l'appareil, connue par telnet $extremite->[1] = "ici"; ($extremite->[2], $extremite->[3]) = getPositionParTelnet ($1); $extremite->[4] = [[0, undef, undef, undef, undef, "position au ".`date`]]; ($extremite->[0], $$proc, $$procx) = (undef, undef, undef); } elsif ($extremite->[1] =~ /^\[(.+),(.+)\]$/) { # position exprimée en coordonnées cartésiennes $extremite->[1] = "pos"; ($extremite->[2], $extremite->[3]) = ($1, $2); $extremite->[4] = [[0, undef, undef, undef,undef, $1.", ".$2]]; if (abs($extremite->[2])<=90 && abs($extremite->[3])<=180) { $extremite_ok = 1; } else { $erreur = "format de coordonnées inconnu...: ".$extremite->[2]." ".$extremite->[3]; } ($extremite->[0], $$proc, $$procx) = (undef, undef, undef); } else { # position par nom de l'aéroport # set positions and runway array ($extremite->[2], $extremite->[3], $extremite->[4]) = &$sous_fonction ($extremite); } # on ferme la connexion avec fgfs close ($fgfs) if $fgfs; # on retourne le résultat de nos recherches return $extremite_ok; } # NAV_TO_RAM ############ sub nav_to_ram ($$$) { my ($fichier, $phrase, $decale) = @_; prt("Loading file ${$fichier}, p=$phrase d=$decale\n") if (!$quiet); my @selection; # tableau qui va contenir les aides à la navigation utiles my $marge = 2; my $lat_sup = (($depart[2] >= $arrivee[2])? $depart[2]:$arrivee[2]) + $marge; my $lat_inf = (($depart[2] <= $arrivee[2])? $depart[2]:$arrivee[2]) - $marge; my $long_sup = (($depart[3] >= $arrivee[3])? $depart[3]:$arrivee[3]) + $marge; my $long_inf = (($depart[3] <= $arrivee[3])? $depart[3]:$arrivee[3]) - $marge; prt("For lat/lon $lat_sup,$long_sup $lat_inf,$long_inf...\n") if (!$quiet); if ( -e $$fichier ) { $$fichier =~ /.+\.(.+)$/; my $fichier_traite = ($1 eq 'gz')? 'gzip -d -c '.$$fichier.'|' : $$fichier; open (NAV, $fichier_traite) or die "je ne peux pas ouvrir $$fichier\n" ; } else { die "fichier $$fichier introuvable\n"; } # on détermine la version du fichier nav.dat if ($$fichier eq $NAVFILE) { while (<NAV>) { if (/^(\d+) Version/) { $version = $1; last; } } # si la version est supérieure à 6.00 on incrémente de 1 les index des tableaux $version = ($version > 600)? 1 : 0; } my $ils = ($version)? '^(4|5)\s+\S+\s+\S+\s+\S+\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(\S+)\s+(...)\s*' : '^(4|5)\s+\S+\s+\S+\s+\S+\s+(\S+)\s+\S+\s+\S+\s+(\S+)\s+(...)\s*'; # on parcourt le fichier pour ne conserver que les balises intéressantes while (<NAV>) { chomp; if (/$phrase/) { push @selection, $_ if ($decale && $2 <= $lat_sup && $2 >= $lat_inf && $3 <= $long_sup && $3 >= $long_inf); push @selection, $_ if (!$decale && $1 <= $lat_sup && $1 >= $lat_inf && $2 <= $long_sup && $2 >= $long_inf); next; } # si par hasard on trouve des infos sur les balises ILS de notre aéroport d'arrivée, pourquoi se gêner? if (/$ils/ && $3 eq $arrivee[1]) { push (@{$arrivee[4]}, [$1, $4, $2/100]); } } close (NAV) or die "je ne peux pas fermer $$fichier"; prt("Close ${$fichier}, returing ".scalar @selection." items.\n") if (!$quiet); return @selection; } # FONCTIONS DE CALCUL DU TRAJET (HORS SID/STAR) ############################################### sub getNavAidNearestMidPoint ($$$) { my $leg = $_[0]; my $milieu = $_[1]; my @ref_dist = (undef, undef, $_[2], $_[2]); my @ref_navaid = (undef, undef, undef, undef); my $heading_from = llll2dir_ ( [$leg->[0], $leg->[1], $milieu->[0], $milieu->[1]] ); my $heading_to = llll2dir_ ( [$milieu->[0], $milieu->[1], $leg->[2], $leg->[3]] ); #RECHERCHE DE LA BALISE LA PLUS PROCHE prt("Searching ".scalar @$navaid."... hdgs from $heading_from to $heading_to...\n") if (!$quiet); for (my $index = 0; $index < @$navaid; $index++) { # on récupère le type et les coordonnées # $1: type de balise # $2: latitude # $3: longitude $navaid->[$index] =~ /^(.)\s+(\S+)\s+(\S+)\s/; # on saute à la prochaine itération si la balise testée est celle d'une des # extrémités du segment next if ( ($2 == $leg->[0] && $3 == $leg->[1]) || ($2 == $leg->[2] && $3 == $leg->[3]) ); # on calcule l'écart de route en degrés my $deviation_to = abs(llll2dir_ ([$leg->[0], $leg->[1], $2, $3]) - $heading_from); my $deviation_from = abs(llll2dir_ ([$2, $3, $leg->[2], $leg->[3]]) - $heading_to); # on saute à la prochaine itération si l'écart est supérieur à l'écart autorisé next if ($deviation_to > $deviation_max && $deviation_from > $deviation_max); # on calcule les distances... my $navaid_dist = distance_( [$milieu->[0], $milieu->[1], $2, $3] ); my $dist_to = distance_( [$leg->[0], $leg->[1], $2, $3] ); my $dist_from = distance_( [$2, $3, $leg->[2], $leg->[3]] ); # si c'est la plus proche et si la distance est suffisante if ( $navaid_dist < $ref_dist[$1] && $dist_to > $dist_min && $dist_from > $dist_min ) { # on retient cette option et on sauve la nouvelle distance de référence $ref_navaid[$1] = $index; $ref_dist[$1] = $navaid_dist; } } #RETOUR EN FONCTION DES CHOIX SWITCH : { #SI ON NE VEUT QUE DU VOR if ($vor_a_vor) { return $ref_navaid[$VOR]; last SWITCH; } #SI ON PREFERE LES VOR AUX NDB if ($vor_preferes && $ref_navaid[$NDB]) { return ($ref_navaid[$VOR])? $ref_navaid[$VOR] : $ref_navaid[$NDB]; last SWITCH; } #SI ON EST INDIFFERENT if ($ref_navaid[$VOR] && $ref_navaid[$NDB]) { return ($ref_dist[$VOR] < $ref_dist[$NDB])? $ref_navaid[$VOR] : $ref_navaid[$NDB]; last SWITCH; } #SI PAS DE VOR if (!$ref_navaid[$VOR] && $ref_navaid[$NDB]) { return $ref_navaid[$NDB]; last SWITCH; } #SI PAS DE NDB if ($ref_navaid[$VOR] && !$ref_navaid[$NDB]) { return $ref_navaid[$VOR]; } else { return $ref_navaid[0]; } } } sub construction_route ($$$$) { # on récupère les arguments de la fonction my ($depuis, $vers, $plan, $lev) = @_; my $lat1 = $depuis->[0]; my $lon1 = $depuis->[1]; my $lat2 = $vers->[0]; my $lon2 = $vers->[1]; # les coordonnées du segments [depuis-vers] # my $coord_leg = [$depuis->[0], $depuis->[1], $vers->[0], $vers->[1]]; my $coord_leg = [$lat1, $lon1, $lat2, $lon2]; # on calcule les coordonnées du milieu du segment [depuis-vers] # par une méthode peu orthodoxe... my $mi_trajet = [ $depuis->[0]+(($vers->[0]-$depuis->[0])/2), $depuis->[1]+(($vers->[1]-$depuis->[1])/2) ]; # on cherche la balise la plus proche du milieu du segment [depuis-vers] my $dist = distance_ ($coord_leg); #prt("Distance of this leg $dist...\n") if (!$quiet); prt("Leg: $lat1,$lon1 - $lat2,$lon2, dist ".(round($dist*100) / 100)." km\n") if (!$quiet); my $indexPlusProcheNavAid = getNavAidNearestMidPoint ($coord_leg, $mi_trajet, $dist/2); # si on en trouve une if ($indexPlusProcheNavAid) { # on récupère les coordonnées # $1 = latitude # $2 = longitude $navaid->[$indexPlusProcheNavAid] =~ /^.\s+(\S+)\s+(\S+)\s/; # on la nomme "waypoint" prt("waypoint $1,$2\n") if (!$quiet); my $waypoint = [$1,$2]; # on construit la route entre "depuis" et "waypoint" construction_route ($depuis, $waypoint, $plan, $lev + 1); # on sauve la balise la plus proche du milieu my @a = split /\s+/, $navaid->[$indexPlusProcheNavAid], 8 + $version; prt("Added: ".join(" ",@a)." to plan\n") if (!$quiet); push @$plan, \@a; # on construit la route entre "waypoint" et "vers" construction_route ($waypoint, $vers, $plan, $lev + 1); } else { prt("Failed to get any navaids on route!\n") if (($lev == 0) && !$quiet); } } # GESTION DES PROCÉDURES SID/STAR ################################# sub teste_existence_procedure ($$$) { # on récupère les arguments de la fonction my ($sidstar, $fichier, $marqueur) = @_; my @trouvailles; # si le fichier sid.dat ou star.dat n'existe pas on abandonne la procédure if (! -e $$fichier) { printf "le fichier %s n'existe pas, la procédure %s est abandonnée", $$fichier, ($marqueur == 60)? 'SID' : 'STAR'; return 0; } # on ouvre le fichier $$fichier =~ /.+\.(.+)$/; my $fichier_traite = ($1 eq 'gz')? 'gzip -d -c '.$$fichier.'|' : $$fichier; open (FICHIER, $fichier_traite) or die "impossible d'ouvrir le fichier $$fichier!!!"; # on parcourt le fichier à la recherche des procédures while (<FICHIER>) { chomp; if (/^$marqueur\s+(\S+)\s+(.+)/ && $1 eq $sidstar->[1]) { # ouverture de procédure qui correspond my @procedure; push @procedure, $2; while (<FICHIER>) { chomp; last if (/^\s*$/); # une ligne vide on arrête la recherche pour cette procédure push @procedure, $_; # tant qu'il y a des données on prend } # on place la procédure entière dans @trouvailles push @trouvailles, \@procedure; } } # on ferme le fichier close (FICHIER); # @trouvaille contient toutes les procédures connues pour notre aéroport # on sauve les résultats là où qu'il faut $sidstar->[0] = \@trouvailles; # on renvoie la taille du tableau @trouvailles (0 = rien trouvé) my $taille = @trouvailles; return $taille; } sub mise_en_forme_procedure ($$) { my ($procedure, $extremite) = @_; my @procedure_exploitable; # tableau contenant les étapes exploitables de la procédure entière my $nombre_d_entrees = 0; # pour contrôler le nombre d'entrées de la procédure rééellement exploitables # si il est nul, alors on abandonne # table de hachage utilisée par $sous_fonction my %type = ('F' => [$fix, '^\s*\S+\s+\S+\s+(\S+)\s*$'], 'V' => [$navaid, ($version)? '^3\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' : '^3\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' ], 'N' => [$navaid, ($version)? '^2\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' : '^2\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' ]); # retourne la ligne d'un fix ou d'une aide à la navigation depuis les bases de données correspondantes $sous_fonction = sub { my ($test, $nom) = @_; foreach my $element (@{$type{$test}->[0]}) { return $element if ($element =~ /$type{$test}->[1]/ && $1 eq $nom); } }; # pour vérifier si la procédure sera modifiée my $modifie = @{$procedure}; # on arrange chaque élément des procédures sid et star pour les incorporer à la route for (my $index = 1; $index < @{$procedure}; $index++) { $procedure->[$index] =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/; my $point_de_passage = $1; # si le point de passage est un fix, un vor ou un ndb... if ($point_de_passage == 65) { # on arrête si c'est l'arrivée (code A de la procédure star) # pour plus tard, les étapes de l'approche manquée seront sauvées quelque part pour traitement... last if ($2 eq 'A'); # on récupère toute l'info le concernant $procedure->[$index] = &$sous_fonction ($2, $3); # on continue pour le prochain point de passage si on ne trouve rien next if !$procedure->[$index]; # si c'est un vor ou un ndb on rajoute l'altitude minimale au dessus du point if ($2 eq 'V' || $2 eq 'N') { $procedure->[$index] .= " $4"; } # s'il s'agit d'un fix, on reformate pour que la taille corresponde avec les autres point du plan de vol else { my $altitude_mini = $4; $procedure->[$index] =~ /^\s*(\S+)\s+(\S+)\s+(\S+)\s*$/; $procedure->[$index] = ($version)? "65 $1 $2 fix fix fix fix $3 $altitude_mini" : "65 $1 $2 fix fix fix $3 $altitude_mini"; } } # ...ou si le point de passage est un gps, on reformate comme pour les fix elsif ($point_de_passage == 66) { my ($lat, $lon) = ($3/1000000, $4/1000000); $procedure->[$index] = ($version)? "66 $lat $lon gps gps gps gps gps $2" : "66 $lat $lon gps gps gps gps $2"; } # ...ou si c'est un trajet d'attente, on l'abandonne (pour l'instant) elsif ($point_de_passage == 64) { next; } # on découpe les points de passage my @etape = split (/\s+/, $procedure->[$index]); $nombre_d_entrees++; push @procedure_exploitable, \@etape; } # on ne retient dans $depart[0]/$arrivee[0] que le nom de la procédure # et on indique si elle a été modifiée my $a_ete_modifie = ($nombre_d_entrees != $modifie)? ' (modifiée)' : undef; $extremite->[0] = ($nombre_d_entrees)? @{$procedure}[0].$a_ete_modifie : undef; # on retourne la procédure exploitable return \@procedure_exploitable; } sub sid_star ($$$$$$) { # on récupère les paramètres my ($proc, $procx, $extremite, $fichier, $marqueur, $autre_extremite) = @_; my $ref_dist = 99999; # distance de référence pour comparer my $ref_index; # index de référence pour se souvenir my $dist; # la distance entre les deux extrémités my @retenues; # contiendra la liste des procédures correspondant à la demande d'une piste particulière my $phrase_a_matcher; # faute de meilleur nom... # table de hachage utilisée par $sous_fonction my %type = ('F' => [$fix, '^\s*(\S+)\s+(\S+)\s+(\S+)\s*$'], 'V' => [$navaid, ($version)? '^3\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' : '^3\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(\S+)' ], 'N' => [$navaid, ($version)? '^2\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)' : '^2\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+(\S+)' ]); # retourne les coordonnées d'un fix ou d'une aide à la navigation $sous_fonction = sub { my ($test, $nom) = @_; foreach my $element (@{$type{$test}->[0]}) { return ($1, $2) if ($element =~ /$type{$test}->[1]/ && $3 eq $nom); } }; # si on trouve au moins une procédure sid/star: # elle(s) est(sont) placées dans $depart[0]/$arrivee[0] # et on charge les données nav et fix. if (teste_existence_procedure ($extremite, $fichier, $marqueur)) { @$fix = nav_to_ram (\$FIXFILE, '^\s*(\S+)\s+(\S+)\s+\S+\s*$', 0) if (@{$fix} == 0); @$navaid = nav_to_ram (\$NAVFILE, '^(2|3)\s+(\S+)\s+(\S+)\s', 1) if (@{$navaid} == 0); } # sinon on annule la demande de procédure sid/star # et on sort de la fonction else { ($extremite->[0], $$proc, $$procx) = (undef, undef, undef); printf "Aucune procédure %s n'a été trouvée pour %s\n", ($marqueur == 60)? 'SID':'STAR', $extremite->[1]; return; } # on commence par chercher la ou les procédures voulues if ($$proc) { foreach my $procedure (@{$extremite->[0]}) { push @retenues, $procedure if ($procedure->[0] =~ /\[RW$$proc.\s*/); } # si on a trouvé les pistes correspondantes à la demande if (@retenues != 0) { $extremite->[0] = \@retenues; } # sinon on annule la demande --sid/--star qui devient une demande --sidx/--starx else { printf "Aucune procédure %s n'a été trouvée pour la piste $$proc sur $extremite->[1]\n", ($marqueur == 60)? 'SID':'STAR'; $$proc = undef; $$procx = 1; } } # on choisit la meilleure procédure, # pour l'instant le choix se fait par le calcul de la plus petite distance # pour chaque procédure connue for (my $index = @{$extremite->[0]}; $index--; ) { my $entree = 1; # $1 contient l'info du type de dernier(sid)/premier(star) point de passage de la procédure: # - 4, ou 7: trajet d'attente (uniquement pour star) # - 5: vor, ndb ou fix # - 6: coordonnées gps POINT_DE_PASSAGE : { # on atteint le dernier élément de la procédure sid numéro $index # ou le premier de la procédure star numéro $index $phrase_a_matcher = ($marqueur == 60)? $extremite->[0]->[$index]->[@{$extremite->[0]->[$index]} - $entree] : $extremite->[0]->[$index]->[$entree]; $phrase_a_matcher =~ /^6(.)\s+/; if ($1 == 4 || $1 == 7) { # c'est un trajet d'attente (holding pattern) # ben ça attendra encore un peu ... on lit l'étape suivante $entree++; next POINT_DE_PASSAGE; # je ne suis pas tout à fait certain de l'orthodoxie de cette syntaxe... } if ($1 == 5) { # c'est un fix ou un vor, ou un ndb... # ou un point d'arrivée (code A) de procédure star mais je considère cette possibilité comme nulle # on cherche le type et le nom $phrase_a_matcher =~ /^65\s+(\S)\s+(\S+)/; # on cherche ses coordonnées my ($lat, $lon) = &$sous_fonction ($1, $2); # on passe au point suivant si le point recherché n'est pas connu if (!$lat) { $entree++; next POINT_DE_PASSAGE; # je ne suis pas tout à fait certain de l'orthodoxie de cette syntaxe... } # on calcule la distance entre les deux extrémités $dist = distance_ ( [$lat, $lon, $autre_extremite->[1], $autre_extremite->[2]] ); # on retient la solution si la distance est inférieure à la distance de référence ($ref_dist, $ref_index) = ($dist, $index) if ($dist < $ref_dist); # on sort last POINT_DE_PASSAGE; } if ($1 == 6) { # c'est un point gps # on lit les coordonnées du point $phrase_a_matcher =~ /^66\s+\S+\s+(\S+)\s+(\S+)/; # on calcule la distance entre les deux extrémités $dist = distance_ ([$1/100000, $2/100000, $autre_extremite->[2], $autre_extremite->[3]]); # on retient la solution si la distance est inférieure à la distance de référence ($ref_dist, $ref_index) = ($dist, $index) if ($dist < $ref_dist); # on sort last POINT_DE_PASSAGE; # inutile mais c'est pour faire joli } } # POINT_DE_PASSAGE } # for (my $index = @{$extremite->[0]}; $index--; ) # on met en forme la procédure trouvée my $procedure_finale = mise_en_forme_procedure ($extremite->[0]->[$ref_index], $extremite); # on enregistre les coordonnées de l'extrémité sid/star, si trouvées $extremite->[2] = @{$procedure_finale->[@{$procedure_finale} - 1]}[1] if @{$procedure_finale->[@{$procedure_finale} - 1]}[1]; $extremite->[3] = @{$procedure_finale->[@{$procedure_finale} - 1]}[2] if @{$procedure_finale->[@{$procedure_finale} - 1]}[2]; # on retourne la procédure sid/star return $procedure_finale; } ## PLAN DE VOL ############## sub plan_de_vol { # les aides à la navigation my @NDBVOR; $navaid = \@NDBVOR; # les fix my @FIX; $fix = \@FIX; # l'aéroport de départ est le premier point push @route, ($version)? [1, $depart[2], $depart[3], @{$depart[4]->[0]}[1], $depart[4], 'apt', 'apt', $depart[1], @{$depart[4]->[0]}[5]] : [1, $depart[2], $depart[3], @{$depart[4]->[0]}[1], $depart[4], 'apt', $depart[1], @{$depart[4]->[0]}[5]]; # on trouve les coordonnées de sortie de la procedure sid, qui deviendront $depart[2] et $depart[3] # le trajet sera contenu dans $depart[0] my $procedure_sid = sid_star (\$sid, \$sidx, \@depart, \$SIDFILE, 60, \@arrivee) if ($sid || $sidx); # on trouve les coordonnées d'entrée de la procédure star, qui deviendront $arrivee[2] et $arrivee[3] # le trajet sera contenu dans $arrivee[0] my $procedure_star = sid_star (\$star, \$starx, \@arrivee, \$STARFILE, 61, \@depart) if ($star || $starx); # si ce n'est déjà fait on place les données nécessaires en mémoire pour aller plus vite # (@FIX seulement dans le cadre des procédures sid/star, pour le moment...) @FIX = nav_to_ram (\$FIXFILE, '^\s*(\S+)\s+(\S+)\s+\S+\s*$', 0) if (($sid || $sidx || $star || $starx) && (@{$fix} == 0)); my ($type_navaid, $decale) = ($vor_a_vor && !($sid || $sidx || $star || $starx))? ('^3', 0) : ('^(2|3)', 1); @NDBVOR = nav_to_ram (\$NAVFILE, $type_navaid.'\s+(\S+)\s+(\S+)\s', $decale) if (@{$navaid} == 0); # on ajoute tous ses points de passage sid dans le plan de vol push @route, @{$procedure_sid} if $depart[0]; # on construit la route entre les deux extrémités construction_route ( [$depart[2], $depart[3]], [$arrivee[2], $arrivee[3]], \@route, 0); # on ajoute tous les points de passage star dans le plan de vol push @route, @{$procedure_star} if $arrivee[0]; # on prend les coordonnées de la piste qui sera utilisée $sous_fonction = sub { my $extremite = shift; if ($extremite->[0] =~ /\[RW(...)\s*/) { my $piste = $1; foreach (@{$extremite->[4]}) { ($extremite->[2], $extremite->[3]) = ($_->[1], $_->[2]) if ($_->[3] =~ /$piste/) } } }; &$sous_fonction (\@depart); &$sous_fonction (\@arrivee); # IL RESTE À TROUVER LA DERNIÈRE BALISE (ÉVENTUELLE) SITUÉE SUR L'AÉROPORT D'ARRIVÉE # si aucune procédure star n'est demandée (ou valable) # l'aéroport d'arrivée est le dernier point push @route, ($version)? [1, $arrivee[2], $arrivee[3], @{$arrivee[4]->[0]}[1], $arrivee[4], 'apt', 'apt', $arrivee[1], @{$arrivee[4]->[0]}[5]] : [1, $arrivee[2], $arrivee[3], @{$arrivee[4]->[0]}[1], $arrivee[4], 'apt', $arrivee[1], @{$arrivee[4]->[0]}[5]]; # on détruit les listes des aides à la navigation désormais inutiles $navaid = undef; $fix = undef; } # FONCTIONS DE SORTIE DU RESULTAT ################################# sub fichier_csv () { $sous_fonction = sub { my $i = $_[0].$_[3].$_[1].$_[3].$_[2]; $i =~ s/\./$_[4]/g; return $i; }; # ouverture du fichier if (!open (CSV, ">$CSVFILE")) { prt("Error: Failed to open $CSVFILE!\n"); return; } # on configure les séparateurs my ($separateur, $decimal); if ($csv_conf =~ /^(.)(.)$/) { $separateur = $1; $decimal = $2; } # on écrit le contenu du fichier for (my $index = 0; $index < @route; $index++) { printf CSV "%s\n", &$sous_fonction ($route[$index]->[6 + $version], $route[$index]->[1], $route[$index]->[2], $separateur, $decimal); } # on ferme le fichier close (CSV); prt("CSV output written to $CSVFILE.\n"); } sub fichier_xg () { my ($name,$lat,$lon); # ouverture du fichier if (!open (XG, ">$XGFILE")) { prt("Error: Failed to open $XGFILE!\n"); return; } my ($max_lat,$max_lon,$min_lat,$min_lon); my ($waypointtype,$wpinfo,$max,$index); $max_lat = -400; $max_lon = -400; $min_lat = 400; $min_lon = 400; # on écrit le contenu du fichier $max = scalar @route; print XG "# plan de vol dep ".$depart[1]." to ".$arrivee[1]." in $max legs\n"; for ($index = 0; $index < $max; $index++) { $lat = $route[$index]->[1]; $lon = $route[$index]->[2]; $name = $route[$index]->[6 + $version].' '.$route[$index]->[7 + $version]; $waypointtype = "APT"; $wpinfo = "none"; if ($route[$index]->[0] == 2) { $wpinfo = "FREQ: ".$route[$index]->[4]; $waypointtype = "NDB"; } elsif ($route[$index]->[0] == 3) { $wpinfo = "FREQ: ".$route[$index]->[4]; $waypointtype = "VOR"; } elsif ($route[$index]->[0] == 65){ $waypointtype = "FIX"; } elsif ($route[$index]->[0] == 66){ $waypointtype = "GPS"; } if ($index == 0) { $wpinfo .= " BEGIN OF ROUTE"; } if ($index == @route - 1) { $wpinfo .= " END OF ROUTE"; } printf XG "anno %f %f %s\n", $lon, $lat, "$name $waypointtype $wpinfo"; printf XG "%f %f\n", $lon, $lat; # get bounding box $max_lat = $lat if ($lat > $max_lat); $max_lon = $lon if ($lon > $max_lon); $min_lat = $lat if ($lat < $min_lat); $min_lon = $lon if ($lon < $min_lon); } print XG "NEXT\n"; print XG "# bbox=$min_lon,$min_lat,$max_lon,$max_lat\n"; # on ferme le fichier close (XG); prt("XG output written to $XGFILE.\n"); } sub fichier_wp () { $WPFILE = $depart[1]."-".$arrivee[1]; my $WPFILE_test = $WPFILE; my $count = 1; if (! -d "$FGROOT/Routes") { prt("Error: Directory $FGROOT/Routes does NOT exist! Create it first...\n"); } while ( -e "$FGROOT/Routes/$WPFILE_test.xml" ) { $WPFILE_test = $WPFILE; $WPFILE_test .= $count; $count++; } $WPFILE = $WPFILE_test; # ouverture du fichier if (!open (WP, ">$FGROOT/Routes/$WPFILE.xml")) { prt("Error: Failed to open $FGROOT/Routes/$WPFILE.xml!\n"); return; } my $template = <<EOT; <Waypoint n="%s"> <ID type="string">%s</ID> <name type="string">%s</name> <latitude-deg type="double">%s</latitude-deg> <longitude-deg type="double">%s</longitude-deg> <altitude-ft type="double">0</altitude-ft> <waypoint-type type="string">%s</waypoint-type> <desc type="string">%s</desc> </Waypoint>\n EOT print WP "<PropertyList>\n"; # on écrit le contenu for (my $index = 1; $index < @route; $index++) { my $waypointtype = "APT"; my $wpinfo = "none"; if ($route[$index]->[0] == 2) { $wpinfo = "FREQ: ".$route[$index]->[4]; $waypointtype = "NDB"; } elsif ($route[$index]->[0] == 3) { $wpinfo = "FREQ: ".$route[$index]->[4]; $waypointtype = "VOR"; } elsif ($route[$index]->[0] == 65){ $waypointtype = "FIX"; } elsif ($route[$index]->[0] == 66){ $waypointtype = "GPS"; } if ($index == @route - 1) { $wpinfo .= " END OF ROUTE"; } printf WP $template, $index - 1, $route[$index]->[6 + $version], $route[$index]->[7 + $version], $route[$index]->[1], $route[$index]->[2], $waypointtype, $wpinfo; } print WP "</PropertyList>"; # fermeture du fichier close (WP); prt("File $FGROOT/Routes/$WPFILE.xml written.\n"); } sub sortie_standard () { # cette procédure est de la bouillie pour les chats et pour les chiens! my $div = ($km)?1:1.852; my ($leg, $distance, $distance_totale, $heading); $sous_fonction = sub { print "\033[30;1m" if $add_couleur; print "$_[0]\n"; print "\033[m" if $add_couleur; }; if ($com_dep) { &$sous_fonction ("Fréquences utiles pour le départ"); foreach (@{$depart[4]}) { printf ("$_->[@{$_}-1]: %s\n", $_->[1]/100) if ($_->[0] >= 50 && $_->[@{$_}-1] ne 'APP');} } print "procédure SID : $depart[0]\n" if $depart[0]; print "procédure STAR : $arrivee[0]\n" if $arrivee[0]; &$sous_fonction ("\nCode - Nom complet"); printf "\t| Frequences | Heading | Course/RNW | Distance en %s\n", ($km)? 'km':'nm'; &$sous_fonction ("$depart[4]->[0]->[4] - $depart[4]->[0]->[5]"); printf "%s", ($depart[0] =~ /\RW(...)\s+/)? "décollage piste $1\n" : ''; for (my $index = 1; $index < @route; $index++) { $leg = [@{$route[$index-1]}[1],@{$route[$index-1]}[2],@{$route[$index]}[1],@{$route[$index]}[2]]; $heading = round (llll2dir_ ($leg)); $distance = distance_ ($leg) / $div; $distance_totale += $distance; $distance = round ($distance); ETAPE : { if (@{$route[$index]}[0] == 2) { # étape ndb if ($version && $distance * $div > @{$route[$index]}[5] && (@{$route[$index-1]}[0] == 2 || @{$route[$index-1]}[0] == 3)) { $distance -= round (@{$route[$index]}[5] / $div); printf "\t| ADF %-7s| %-6s | -- | $distance\n", @{$route[$index-1]}[4], $heading if @{$route[$index-1]}[0] == 2; printf "\t| NAV %-7s| %-6s | %-10s | $distance\n", @{$route[$index-1]}[4], $heading, round ($heading - @{$route[$index-1]}[5+$version]) if @{$route[$index-1]}[0] == 3; $distance = round (@{$route[$index]}[5] / $div); } printf "\t| ADF %-7s| %-6s | -- | $distance\n", @{$route[$index]}[4], $heading; &$sous_fonction ("@{$route[$index]}[6 + $version] - @{$route[$index]}[7 + $version]"); last ETAPE; } if (@{$route[$index]}[0] == 3) { # étape vor @{$route[$index]}[4] /= 100; if ($version && $distance * $div> (@{$route[$index]}[5]-5) && (@{$route[$index-1]}[0] == 2 || @{$route[$index-1]}[0] == 3)) { $distance -= round (@{$route[$index]}[5] / $div); printf "\t| ADF %-7s| %-6s | -- | $distance\n", @{$route[$index-1]}[4], $heading if @{$route[$index-1]}[0] == 2; printf "\t| NAV %-7s| %-6s | %-10s | $distance\n", @{$route[$index-1]}[4], $heading, round ($heading - @{$route[$index-1]}[5+$version]) if @{$route[$index-1]}[0] == 3; $distance = round (@{$route[$index]}[5] / $div); } printf "\t| NAV %-7s| %-6s | %-10s | $distance\n", @{$route[$index]}[4], $heading, round ($heading - @{$route[$index]}[5+$version]); &$sous_fonction ("@{$route[$index]}[6 + $version] - @{$route[$index]}[7 + $version]"); last ETAPE; } if (@{$route[$index]}[0] == 65) { # étape fix printf "\t| FIX | %-6s | -- | $distance\n", $heading; &$sous_fonction ("@{$route[$index]}[6 + $version]"); last ETAPE; } if (@{$route[$index]}[0] == 66) { # étape gps printf "\t| GPS | %-6s | -- | $distance\n", $heading; &$sous_fonction ("GPS - [@{$route[$index]}[1] , @{$route[$index]}[2]]"); last ETAPE; } if (@{$route[$index]}[0] == 1) { # aéroport de d'arrivée my ($localizer, $piste); if ($arrivee[0] =~ /\[RW(...)\s*/) { $piste = $1; $localizer = "RW $piste"; foreach (@{$arrivee[4]}) { $localizer = "ILS $_->[2]" if (($_->[0] == 4 || $_->[0] == 5) && $_->[1] eq $piste); } printf "\t| %-10s | %-6s | %-10s | $distance\n", $localizer, $heading, "RW $piste"; } else { foreach (@{$arrivee[4]}) { if ($_->[0] == 10) { $piste = "RW $_->[3]" ; printf "\t| %-10s | %-6s | %-10s | $distance\n", $piste, $heading, $piste; } elsif ($_->[0] == 4 || $_->[0] == 5) { ($localizer, $piste) = ("ILS $_->[2]", "RW $_->[1]"); printf "\t| %-10s | %-6s | %-10s | $distance\n", $localizer, $heading, $piste; } } } &$sous_fonction ("$arrivee[4]->[0]->[4] - $arrivee[4]->[0]->[5]"); last ETAPE; } } } $leg = [$depart[2], $depart[3], $arrivee[2], $arrivee[3]]; printf "\ndistance totale parcourue: %s %s (vol direct: %s)\n\n", round ($distance_totale), ($km)? 'km':'nm', round (distance_ ($leg) / $div); if ($com_app) { &$sous_fonction ("Fréquences utiles pour l'approche"); foreach (@{$arrivee[4]}) { printf ("$_->[@{$_}-1]: %s\n", $_->[1]/100) if ($_->[0] >= 50 && $_->[@{$_}-1] ne 'DEP'); } } } ####################### # FONCTION PRINCIPALE # ####################### sub main () { # si aucune option n'est demandée ou si l'option -h est appelée, on affiche l'aide et on quitte if (!$options || $help) { print $texte_aide; exit; } prt("Plan de vol ".$depart[1]." to ".$arrivee[1]."... moment...\n"); if ($wpt ) { if (! -d "$FGROOT/Routes") { prt("Error: Directory $FGROOT/Routes does NOT exist! Create it first...\n"); exit 1; } } # si le départ et l'arrivée ont été trouvés on commence la construction # du plan de vol, sinon on affiche un message d'erreur. (configure_extremite (\@depart, \$sid, \$sidx ) && configure_extremite (\@arrivee,\$star,\$starx)) ? plan_de_vol : printf $erreur; # redirection du résultat selon les choix sortie_standard if (!$no_stdout ); fichier_csv if ($CSVFILE ); fichier_wp if ($wpt ); fichier_xg if ($XGFILE ); } main; # eof