Removed legacy interactive approach ATC
This commit is contained in:
parent
86505fd8bc
commit
4c288398cb
9 changed files with 1 additions and 1640 deletions
|
@ -31,7 +31,6 @@
|
||||||
#include "commlist.hxx"
|
#include "commlist.hxx"
|
||||||
#include "ATCDialog.hxx"
|
#include "ATCDialog.hxx"
|
||||||
#include "ATCutils.hxx"
|
#include "ATCutils.hxx"
|
||||||
#include "transmissionlist.hxx"
|
|
||||||
#include "ground.hxx"
|
#include "ground.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,14 +96,6 @@ void FGATCMgr::init() {
|
||||||
// -EMH-
|
// -EMH-
|
||||||
|
|
||||||
// Initialise the ATC Dialogs
|
// Initialise the ATC Dialogs
|
||||||
//cout << "Initing Transmissions..." << endl;
|
|
||||||
SG_LOG(SG_ATC, SG_INFO, " ATC Transmissions");
|
|
||||||
current_transmissionlist = new FGTransmissionList;
|
|
||||||
SGPath p_transmission( globals->get_fg_root() );
|
|
||||||
p_transmission.append( "ATC/default.transmissions" );
|
|
||||||
current_transmissionlist->init( p_transmission );
|
|
||||||
//cout << "Done Transmissions" << endl;
|
|
||||||
|
|
||||||
SG_LOG(SG_ATC, SG_INFO, " ATC Dialog System");
|
SG_LOG(SG_ATC, SG_INFO, " ATC Dialog System");
|
||||||
current_atcdialog = new FGATCDialog;
|
current_atcdialog = new FGATCDialog;
|
||||||
current_atcdialog->Init();
|
current_atcdialog->Init();
|
||||||
|
@ -147,12 +138,6 @@ void FGATCMgr::update(double dt) {
|
||||||
|
|
||||||
// Search the tuned frequencies every now and then - this should be done with the event scheduler
|
// Search the tuned frequencies every now and then - this should be done with the event scheduler
|
||||||
static int i = 0; // Very ugly - but there should only ever be one instance of FGATCMgr.
|
static int i = 0; // Very ugly - but there should only ever be one instance of FGATCMgr.
|
||||||
/*** Area search is defeated. Why?
|
|
||||||
if(i == 7) {
|
|
||||||
//cout << "About to AreaSearch()" << endl;
|
|
||||||
AreaSearch();
|
|
||||||
}
|
|
||||||
***/
|
|
||||||
if(i == 15) {
|
if(i == 15) {
|
||||||
//cout << "About to search navcomm1" << endl;
|
//cout << "About to search navcomm1" << endl;
|
||||||
FreqSearch("comm", 0);
|
FreqSearch("comm", 0);
|
||||||
|
@ -459,7 +444,6 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
|
||||||
|| data.type == AWOS) (*atc_list)[svc_name] = new FGATIS;
|
|| data.type == AWOS) (*atc_list)[svc_name] = new FGATIS;
|
||||||
else if (data.type == TOWER) (*atc_list)[svc_name] = new FGTower;
|
else if (data.type == TOWER) (*atc_list)[svc_name] = new FGTower;
|
||||||
else if (data.type == GROUND) (*atc_list)[svc_name] = new FGGround;
|
else if (data.type == GROUND) (*atc_list)[svc_name] = new FGGround;
|
||||||
else if (data.type == APPROACH) (*atc_list)[svc_name] = new FGApproach;
|
|
||||||
FGATC* svc = (*atc_list)[svc_name];
|
FGATC* svc = (*atc_list)[svc_name];
|
||||||
svc->SetData(&data);
|
svc->SetData(&data);
|
||||||
svc->active_on[ncunit] = 1;
|
svc->active_on[ncunit] = 1;
|
||||||
|
@ -471,64 +455,3 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) {
|
||||||
ZapOtherService(ncunit, "x x x");
|
ZapOtherService(ncunit, "x x x");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AREA_SEARCH
|
|
||||||
/* I don't think AreaSearch ever gets called */
|
|
||||||
// Search ATC stations by area in order that we appear 'on the radar'
|
|
||||||
void FGATCMgr::AreaSearch() {
|
|
||||||
const string AREA("AREA");
|
|
||||||
// Search for Approach stations
|
|
||||||
comm_list_type approaches;
|
|
||||||
comm_list_iterator app_itr;
|
|
||||||
|
|
||||||
lon = lon_node->getDoubleValue();
|
|
||||||
lat = lat_node->getDoubleValue();
|
|
||||||
elev = elev_node->getDoubleValue() * SG_FEET_TO_METER;
|
|
||||||
for (atc_list_iterator svc = atc_list->begin(); svc != atc_list->end(); svc++) {
|
|
||||||
MSI &actv = svc->second->active_on;
|
|
||||||
if (actv.count(AREA)) actv[AREA] = 0; // Mark all as maybe not in range
|
|
||||||
}
|
|
||||||
|
|
||||||
// search stations in range
|
|
||||||
int num_app = current_commlist->FindByPos(lon, lat, elev, 100.0, &approaches, APPROACH);
|
|
||||||
if (num_app != 0) {
|
|
||||||
//cout << num_app << " approaches found in area search !!!!" << endl;
|
|
||||||
|
|
||||||
for(app_itr = approaches.begin(); app_itr != approaches.end(); app_itr++) {
|
|
||||||
FGATC* app = FindInList(app_itr->ident, app_itr->type);
|
|
||||||
string svc_name = app_itr->ident+decimalNumeral(app_itr->type);
|
|
||||||
if(app != NULL) {
|
|
||||||
// The station is already in the ATC list
|
|
||||||
app->AddPlane("Player");
|
|
||||||
} else {
|
|
||||||
// Generate the station and put in the ATC list
|
|
||||||
FGApproach* a = new FGApproach;
|
|
||||||
a->SetData(&(*app_itr));
|
|
||||||
a->AddPlane("Player");
|
|
||||||
(*atc_list)[svc_name] = a;
|
|
||||||
//cout << "New area service: " << svc_name << endl;
|
|
||||||
}
|
|
||||||
FGATC* svc = (*atc_list)[svc_name];
|
|
||||||
svc->active_on[AREA] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (atc_list_iterator svc = atc_list->begin(); svc != atc_list->end(); svc++) {
|
|
||||||
MSI &actv = svc->second->active_on;
|
|
||||||
if (!actv.count(AREA)) continue;
|
|
||||||
if (!actv[AREA]) actv.erase(AREA);
|
|
||||||
if (!actv.size()) { // this service no longer active at all
|
|
||||||
cout << "Eradicating area service: " << svc->first << endl;
|
|
||||||
svc->second->SetNoDisplay();
|
|
||||||
svc->second->Update(0);
|
|
||||||
delete (svc->second);
|
|
||||||
atc_list->erase(svc);
|
|
||||||
// Reset the persistent iterator, since any erase() makes it invalid:
|
|
||||||
atc_list_itr = atc_list->begin();
|
|
||||||
// Hope we only move out of one approach-area;
|
|
||||||
// others will not be noticed until next update:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "tower.hxx"
|
#include "tower.hxx"
|
||||||
#include "approach.hxx"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::list;
|
using std::list;
|
||||||
|
@ -108,8 +107,6 @@ private:
|
||||||
//FGATIS atis;
|
//FGATIS atis;
|
||||||
//FGGround ground;
|
//FGGround ground;
|
||||||
FGTower tower;
|
FGTower tower;
|
||||||
FGApproach approach;
|
|
||||||
//FGDeparture departure;
|
|
||||||
|
|
||||||
// Voice related stuff
|
// Voice related stuff
|
||||||
bool voice; // Flag - true if we are using voice
|
bool voice; // Flag - true if we are using voice
|
||||||
|
@ -173,12 +170,6 @@ private:
|
||||||
|
|
||||||
// Search the specified radio for stations on the same frequency and in range.
|
// Search the specified radio for stations on the same frequency and in range.
|
||||||
void FreqSearch(const string navcomm, const int unit);
|
void FreqSearch(const string navcomm, const int unit);
|
||||||
|
|
||||||
#ifdef AREA_SEARCH
|
|
||||||
// Search ATC stations by area in order that we appear 'on the radar'
|
|
||||||
void AreaSearch();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_ATCMGR_HXX
|
#endif // _FG_ATCMGR_HXX
|
||||||
|
|
|
@ -4,15 +4,12 @@ libATCDCL_a_SOURCES = \
|
||||||
ATC.hxx ATC.cxx \
|
ATC.hxx ATC.cxx \
|
||||||
atis.hxx atis.cxx \
|
atis.hxx atis.cxx \
|
||||||
tower.hxx tower.cxx \
|
tower.hxx tower.cxx \
|
||||||
approach.hxx approach.cxx \
|
|
||||||
ground.hxx ground.cxx \
|
ground.hxx ground.cxx \
|
||||||
commlist.hxx commlist.cxx \
|
commlist.hxx commlist.cxx \
|
||||||
ATCDialog.hxx ATCDialog.cxx \
|
ATCDialog.hxx ATCDialog.cxx \
|
||||||
ATCVoice.hxx ATCVoice.cxx \
|
ATCVoice.hxx ATCVoice.cxx \
|
||||||
ATCmgr.hxx ATCmgr.cxx \
|
ATCmgr.hxx ATCmgr.cxx \
|
||||||
ATCutils.hxx ATCutils.cxx \
|
ATCutils.hxx ATCutils.cxx \
|
||||||
ATCProjection.hxx ATCProjection.cxx \
|
ATCProjection.hxx ATCProjection.cxx
|
||||||
transmission.hxx transmission.cxx \
|
|
||||||
transmissionlist.hxx transmissionlist.cxx
|
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
|
@ -1,750 +0,0 @@
|
||||||
// FGApproach - a class to provide approach control at larger airports.
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2002 Alexander Kappes
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "approach.hxx"
|
|
||||||
#include "transmission.hxx"
|
|
||||||
#include "transmissionlist.hxx"
|
|
||||||
#include "ATCDialog.hxx"
|
|
||||||
|
|
||||||
#include <Airports/runways.hxx>
|
|
||||||
#include <Airports/simple.hxx>
|
|
||||||
|
|
||||||
#include <simgear/constants.h>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
#include <Environment/environment_mgr.hxx>
|
|
||||||
#include <Environment/environment.hxx>
|
|
||||||
|
|
||||||
|
|
||||||
#include <GUI/gui.h>
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
|
|
||||||
//Constructor
|
|
||||||
FGApproach::FGApproach(){
|
|
||||||
comm1_node = fgGetNode("/instrumentation/comm[0]/frequencies/selected-mhz", true);
|
|
||||||
comm2_node = fgGetNode("/instrumentation/comm[1]/frequencies/selected-mhz", true);
|
|
||||||
|
|
||||||
_type = APPROACH;
|
|
||||||
|
|
||||||
num_planes = 0;
|
|
||||||
lon_node = fgGetNode("/position/longitude-deg", true);
|
|
||||||
lat_node = fgGetNode("/position/latitude-deg", true);
|
|
||||||
elev_node = fgGetNode("/position/altitude-ft", true);
|
|
||||||
hdg_node = fgGetNode("/orientation/heading-deg", true);
|
|
||||||
speed_node = fgGetNode("/velocities/airspeed-kt", true);
|
|
||||||
etime_node = fgGetNode("/sim/time/elapsed-sec", true);
|
|
||||||
|
|
||||||
first = true;
|
|
||||||
active_runway = "";
|
|
||||||
int i;
|
|
||||||
for ( i=0; i<max_planes; i++) {
|
|
||||||
planes[i].contact = 0;
|
|
||||||
planes[i].wpn = 0;
|
|
||||||
planes[i].dnwp = -999.;
|
|
||||||
planes[i].on_crs = true;
|
|
||||||
planes[i].turn_rate = 10.0;
|
|
||||||
planes[i].desc_rate = 1000.0;
|
|
||||||
planes[i].clmb_rate = 500.0;
|
|
||||||
planes[i].tlm = 0.0;
|
|
||||||
planes[i].lmc.c1 = 0;
|
|
||||||
planes[i].lmc.c2 = 0;
|
|
||||||
planes[i].lmc.c3 = -1;
|
|
||||||
planes[i].wp_change = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Destructor
|
|
||||||
FGApproach::~FGApproach(){
|
|
||||||
}
|
|
||||||
|
|
||||||
void FGApproach::Init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// the main update function
|
|
||||||
// ============================================================================
|
|
||||||
void FGApproach::Update(double dt) {
|
|
||||||
|
|
||||||
const int max_trans = 20;
|
|
||||||
FGTransmission tmissions[max_trans];
|
|
||||||
int wpn;
|
|
||||||
atc_type station = APPROACH;
|
|
||||||
TransCode code;
|
|
||||||
TransPar TPar;
|
|
||||||
int i,j;
|
|
||||||
//double course, d,
|
|
||||||
double adif, datp;
|
|
||||||
//char buf[10];
|
|
||||||
string message;
|
|
||||||
//static string atcmsg1[10];
|
|
||||||
//static string atcmsg2[10];
|
|
||||||
string mentry;
|
|
||||||
string transm;
|
|
||||||
TransPar tpars;
|
|
||||||
//static bool TransDisplayed = false;
|
|
||||||
|
|
||||||
update_plane_dat();
|
|
||||||
if ( active_runway == "" ) get_active_runway();
|
|
||||||
|
|
||||||
double comm1_freq = comm1_node->getDoubleValue();
|
|
||||||
|
|
||||||
//bool DisplayTransmissions = true;
|
|
||||||
|
|
||||||
for (i=0; i<num_planes; i++) {
|
|
||||||
if ( planes[i].ident == "Player") {
|
|
||||||
station = APPROACH;
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
tpars.airport = ident;
|
|
||||||
|
|
||||||
//cout << "ident = " << ident << " name = " << name << '\n';
|
|
||||||
|
|
||||||
int num_trans = 0;
|
|
||||||
// is the frequency of the station tuned in?
|
|
||||||
if ( freq == (int)(comm1_freq*100.0 + 0.5) ) {
|
|
||||||
current_transmissionlist->query_station( station, tmissions, max_trans, num_trans );
|
|
||||||
// loop over all transmissions for station
|
|
||||||
for ( j=0; j<=num_trans-1; j++ ) {
|
|
||||||
code = tmissions[j].get_code();
|
|
||||||
//cout << "code is " << code.c1 << " " << code.c2 << " " << code.c3 << '\n';
|
|
||||||
// select proper transmissions
|
|
||||||
if(code.c3 != 2) { // DCL - hack to prevent request crossing airspace being displayed since this isn't implemented yet.
|
|
||||||
if ( ( code.c2 == -1 && planes[i].lmc.c3 == 0 ) ||
|
|
||||||
( code.c1 == 0 && code.c2 == planes[i].lmc.c2 ) ) {
|
|
||||||
mentry = current_transmissionlist->gen_text(station, code, tpars, false);
|
|
||||||
transm = current_transmissionlist->gen_text(station, code, tpars, true);
|
|
||||||
// is the transmission already registered?
|
|
||||||
if (!current_atcdialog->trans_reg( ident, transm, APPROACH )) {
|
|
||||||
current_atcdialog->add_entry( ident, transm, mentry, APPROACH, 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i=0; i<num_planes; i++ ) {
|
|
||||||
//cout << "TPar.airport = " << TPar.airport << " TPar.station = " << TPar.station << " TPar.callsign = " << TPar.callsign << '\n';
|
|
||||||
//if ( planes[i].ident == TPar.callsign && name == TPar.airport && TPar.station == "approach" ) {
|
|
||||||
//if ( TPar.request && TPar.intention == "landing" && ident == TPar.intid) {
|
|
||||||
if(planes[i].ident == "Player" && fgGetBool("/sim/atc/opt0")) {
|
|
||||||
//cout << "Landing requested\n";
|
|
||||||
fgSetBool("/sim/atc/opt0", false);
|
|
||||||
planes[i].wpn = 0;
|
|
||||||
// ===========================
|
|
||||||
// === calculate waypoints ===
|
|
||||||
// ===========================
|
|
||||||
calc_wp( i );
|
|
||||||
update_param( i );
|
|
||||||
wpn = planes[i].wpn-1;
|
|
||||||
planes[i].aalt = planes[i].wpts[wpn-1][2];
|
|
||||||
planes[i].ahdg = planes[i].wpts[wpn][4];
|
|
||||||
|
|
||||||
// generate the message
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 1;
|
|
||||||
code.c3 = 0;
|
|
||||||
adif = angle_diff_deg( planes[i].hdg, planes[i].ahdg );
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
if ( adif < 0 ) tpars.tdir = 1;
|
|
||||||
else tpars.tdir = 2;
|
|
||||||
tpars.heading = planes[i].ahdg;
|
|
||||||
if (planes[i].alt-planes[i].aalt > 100.0) tpars.VDir = 1;
|
|
||||||
else if (planes[i].alt-planes[i].aalt < -100.0) tpars.VDir = 3;
|
|
||||||
else tpars.VDir = 2;
|
|
||||||
tpars.alt = planes[i].aalt;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true );
|
|
||||||
//cout << message << '\n';
|
|
||||||
set_message(message);
|
|
||||||
planes[i].lmc = code;
|
|
||||||
planes[i].tlm = etime_node->getDoubleValue();
|
|
||||||
planes[i].on_crs = true;
|
|
||||||
planes[i].contact = 1;
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if(1) {
|
|
||||||
if ( planes[i].contact == 1 ) {
|
|
||||||
// =========================
|
|
||||||
// === update parameters ===
|
|
||||||
// =========================
|
|
||||||
update_param( i );
|
|
||||||
//cout << planes[i].brg << " " << planes[i].dist << " " << planes[i].wpts[wpn+1][0]
|
|
||||||
//<< " " << planes[i].wpts[wpn+1][1] << " " << planes[i].wpts[wpn+1][4]
|
|
||||||
//cout << wpn << " distance to current course = " << planes[i].dcc << endl;
|
|
||||||
//cout << etime_node->getDoubleValue() << endl;
|
|
||||||
|
|
||||||
// =========================
|
|
||||||
// === reached waypoint? ===
|
|
||||||
// =========================
|
|
||||||
wpn = planes[i].wpn-2;
|
|
||||||
adif = angle_diff_deg( planes[i].hdg, planes[i].wpts[wpn][4] )
|
|
||||||
* SGD_DEGREES_TO_RADIANS;
|
|
||||||
datp = 2*sin(fabs(adif)/2.0)*sin(fabs(adif)/2.0) *
|
|
||||||
planes[i].spd/3600. * planes[i].turn_rate +
|
|
||||||
planes[i].spd/3600. * 3.0;
|
|
||||||
//cout << adif/SGD_DEGREES_TO_RADIANS << " "
|
|
||||||
// << datp << " " << planes[i].dnc << " " << planes[i].dcc <<endl;
|
|
||||||
if ( fabs(planes[i].dnc) < datp ) {
|
|
||||||
//if ( fabs(planes[i].dnc) < 0.3 && planes[i].dnwp < 1.0 ) {
|
|
||||||
//cout << "Reached next waypoint!\n";
|
|
||||||
planes[i].wpn -= 1;
|
|
||||||
wpn = planes[i].wpn-1;
|
|
||||||
planes[i].ahdg = planes[i].wpts[wpn][4];
|
|
||||||
planes[i].aalt = planes[i].wpts[wpn-1][2];
|
|
||||||
planes[i].wp_change = true;
|
|
||||||
|
|
||||||
// generate the message
|
|
||||||
adif = angle_diff_deg( planes[i].hdg, planes[i].ahdg );
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
if ( adif < 0 ) tpars.tdir = 1;
|
|
||||||
else tpars.tdir = 2;
|
|
||||||
tpars.heading = planes[i].ahdg;
|
|
||||||
|
|
||||||
if ( wpn-1 != 0) {
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 1;
|
|
||||||
code.c3 = 0;
|
|
||||||
if (planes[i].alt-planes[i].aalt > 100.0) tpars.VDir = 1;
|
|
||||||
else if (planes[i].alt-planes[i].aalt < -100.0) tpars.VDir = 3;
|
|
||||||
else tpars.VDir = 2;
|
|
||||||
tpars.alt = planes[i].aalt;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true );
|
|
||||||
//cout << "Approach transmitting...\n";
|
|
||||||
//cout << message << endl;
|
|
||||||
set_message(message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 3;
|
|
||||||
code.c3 = 0;
|
|
||||||
tpars.runway = active_runway;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true);
|
|
||||||
//cout << "Approach transmitting 2 ...\n";
|
|
||||||
//cout << message << endl;
|
|
||||||
set_message(message);
|
|
||||||
}
|
|
||||||
planes[i].lmc = code;
|
|
||||||
planes[i].tlm = etime_node->getDoubleValue();
|
|
||||||
planes[i].on_crs = true;
|
|
||||||
|
|
||||||
update_param( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================
|
|
||||||
// === come off course ? ===
|
|
||||||
// =========================
|
|
||||||
if ( fabs(planes[i].dcc) > 1.0 &&
|
|
||||||
( !planes[i].wp_change || etime_node->getDoubleValue() - planes[i].tlm > tbm ) ) {
|
|
||||||
//cout << "Off course!\n";
|
|
||||||
if ( planes[i].on_crs ) {
|
|
||||||
if ( planes[i].dcc < 0) {
|
|
||||||
planes[i].ahdg += 30.0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
planes[i].ahdg -= 30.0;
|
|
||||||
}
|
|
||||||
if (planes[i].ahdg > 360.0) planes[i].ahdg -= 360.0;
|
|
||||||
else if (planes[i].ahdg < 0.0) planes[i].ahdg += 360.0;
|
|
||||||
}
|
|
||||||
//cout << planes[i].on_crs << " "
|
|
||||||
// << angle_diff_deg( planes[i].hdg, planes[i].ahdg) << " "
|
|
||||||
// << etime_node->getDoubleValue() << " "
|
|
||||||
// << planes[i].tlm << endl;
|
|
||||||
// generate the message
|
|
||||||
if ( planes[i].on_crs ||
|
|
||||||
( fabs(angle_diff_deg( planes[i].hdg, planes[i].ahdg )) > 30.0 &&
|
|
||||||
etime_node->getDoubleValue() - planes[i].tlm > tbm) ) {
|
|
||||||
// generate the message
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 4;
|
|
||||||
code.c3 = 0;
|
|
||||||
adif = angle_diff_deg( planes[i].hdg, planes[i].ahdg );
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
tpars.miles = fabs(planes[i].dcc);
|
|
||||||
if ( adif < 0 ) tpars.tdir = 1;
|
|
||||||
else tpars.tdir = 2;
|
|
||||||
tpars.heading = planes[i].ahdg;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true);
|
|
||||||
//cout << "Approach transmitting 3 ...\n";
|
|
||||||
//cout << message << '\n';
|
|
||||||
set_message(message);
|
|
||||||
planes[i].lmc = code;
|
|
||||||
planes[i].tlm = etime_node->getDoubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
planes[i].on_crs = false;
|
|
||||||
}
|
|
||||||
else if ( !planes[i].on_crs ) {
|
|
||||||
//cout << "Off course 2!\n";
|
|
||||||
wpn = planes[i].wpn-1;
|
|
||||||
adif = angle_diff_deg( planes[i].hdg, planes[i].wpts[wpn][4] )
|
|
||||||
* SGD_DEGREES_TO_RADIANS;
|
|
||||||
datp = 2*sin(fabs(adif)/2.0)*sin(fabs(adif)/2.0) *
|
|
||||||
planes[i].spd/3600. * planes[i].turn_rate +
|
|
||||||
planes[i].spd/3600. * 3.0;
|
|
||||||
if ( fabs(planes[i].dcc) < datp ) {
|
|
||||||
planes[i].ahdg = fabs(planes[i].wpts[wpn][4]);
|
|
||||||
|
|
||||||
// generate the message
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 2;
|
|
||||||
code.c3 = 0;
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
if ( adif < 0 ) tpars.tdir = 1;
|
|
||||||
else tpars.tdir = 2;
|
|
||||||
tpars.heading = planes[i].ahdg;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true);
|
|
||||||
//cout << "Approach transmitting 4 ...\n";
|
|
||||||
//cout << message << '\n';
|
|
||||||
set_message(message);
|
|
||||||
planes[i].lmc = code;
|
|
||||||
planes[i].tlm = etime_node->getDoubleValue();
|
|
||||||
|
|
||||||
planes[i].on_crs = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( planes[i].wp_change ) {
|
|
||||||
planes[i].wp_change = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================================================================
|
|
||||||
// === Less than two minutes away from touchdown? -> Contact Tower ===
|
|
||||||
// ===================================================================
|
|
||||||
if ( planes[i].wpn == 2 && planes[i].dnwp < planes[i].spd/60.*2.0 ) {
|
|
||||||
|
|
||||||
double freq = 121.95; // Hardwired - FIXME
|
|
||||||
// generate message
|
|
||||||
code.c1 = 1;
|
|
||||||
code.c2 = 5;
|
|
||||||
code.c3 = 0;
|
|
||||||
tpars.station = name;
|
|
||||||
tpars.callsign = "Player";
|
|
||||||
tpars.freq = freq;
|
|
||||||
message = current_transmissionlist->gen_text(station, code, tpars, true);
|
|
||||||
//cout << "Approach transmitting 5 ...\n";
|
|
||||||
//cout << message << '\n';
|
|
||||||
set_message(message);
|
|
||||||
planes[i].lmc = code;
|
|
||||||
planes[i].tlm = etime_node->getDoubleValue();
|
|
||||||
|
|
||||||
planes[i].contact = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// update course parameters
|
|
||||||
// ============================================================================
|
|
||||||
void FGApproach::update_param( const int &i ) {
|
|
||||||
|
|
||||||
double course, d;
|
|
||||||
|
|
||||||
int wpn = planes[i].wpn-1; // this is the current waypoint
|
|
||||||
|
|
||||||
planes[i].dcc = calc_psl_dist(planes[i].brg, planes[i].dist,
|
|
||||||
planes[i].wpts[wpn][0], planes[i].wpts[wpn][1],
|
|
||||||
planes[i].wpts[wpn][4]);
|
|
||||||
planes[i].dnc = calc_psl_dist(planes[i].brg, planes[i].dist,
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
planes[i].wpts[wpn-1][4]);
|
|
||||||
calc_hd_course_dist(planes[i].brg, planes[i].dist,
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
&course, &d);
|
|
||||||
planes[i].dnwp = d;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// smallest difference between two angles in degree
|
|
||||||
// difference is negative if a1 > a2 and positive if a2 > a1
|
|
||||||
// ===========================================================================
|
|
||||||
double FGApproach::angle_diff_deg( const double &a1, const double &a2) {
|
|
||||||
|
|
||||||
double a3 = a2 - a1;
|
|
||||||
if (a3 < 180.0) a3 += 360.0;
|
|
||||||
if (a3 > 180.0) a3 -= 360.0;
|
|
||||||
|
|
||||||
return a3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// calculate waypoints
|
|
||||||
// ============================================================================
|
|
||||||
void FGApproach::calc_wp( const int &i ) {
|
|
||||||
|
|
||||||
int j;
|
|
||||||
double course, d, cd, a1, az2;
|
|
||||||
|
|
||||||
int wpn = planes[i].wpn;
|
|
||||||
// waypoint 0: Threshold of active runway
|
|
||||||
SGGeod activeRunway(SGGeod::fromDeg(active_rw_lon, active_rw_lat));
|
|
||||||
SGGeodesy::inverse(_geod, activeRunway, course, az2, d);
|
|
||||||
|
|
||||||
double d1 = active_rw_hdg+180.0;
|
|
||||||
if ( d1 > 360.0 ) d1 -=360.0;
|
|
||||||
calc_cd_head_dist(360.0-course, d/SG_NM_TO_METER,
|
|
||||||
d1, active_rw_len/SG_NM_TO_METER/2.0,
|
|
||||||
&planes[i].wpts[wpn][0], &planes[i].wpts[wpn][1]);
|
|
||||||
planes[i].wpts[wpn][2] = _geod.getElevationM();
|
|
||||||
planes[i].wpts[wpn][4] = 0.0;
|
|
||||||
planes[i].wpts[wpn][5] = 0.0;
|
|
||||||
wpn += 1;
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// horizontal navigation
|
|
||||||
// ======================
|
|
||||||
// waypoint 1: point for turning onto final
|
|
||||||
calc_cd_head_dist(planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1], d1, lfl,
|
|
||||||
&planes[i].wpts[wpn][0], &planes[i].wpts[wpn][1]);
|
|
||||||
calc_hd_course_dist(planes[i].wpts[wpn][0], planes[i].wpts[wpn][1],
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
&course, &d);
|
|
||||||
planes[i].wpts[wpn][4] = course;
|
|
||||||
planes[i].wpts[wpn][5] = d;
|
|
||||||
wpn += 1;
|
|
||||||
|
|
||||||
// calculate course and distance from plane position to waypoint 1
|
|
||||||
calc_hd_course_dist(planes[i].brg, planes[i].dist, planes[i].wpts[1][0],
|
|
||||||
planes[i].wpts[1][1], &course, &d);
|
|
||||||
// check if airport is not between plane and waypoint 1 and
|
|
||||||
// DCA to airport on course to waypoint 1 is larger than 10 miles
|
|
||||||
double zero = 0.0;
|
|
||||||
if ( fabs(angle_diff_deg( planes[i].wpts[1][0], planes[i].brg )) < 90.0 ||
|
|
||||||
calc_psl_dist( zero, zero, planes[i].brg, planes[i].dist, course ) > 10.0 ) {
|
|
||||||
// check if turning angle at waypoint 1 would be > max_ta
|
|
||||||
if ( fabs(angle_diff_deg( planes[i].wpts[1][4], course )) > max_ta ) {
|
|
||||||
cd = calc_psl_dist(planes[i].brg, planes[i].dist,
|
|
||||||
planes[i].wpts[1][0], planes[i].wpts[1][1],
|
|
||||||
planes[i].wpts[1][4]);
|
|
||||||
a1 = atan2(cd,planes[i].wpts[1][1]);
|
|
||||||
planes[i].wpts[wpn][0] = planes[i].wpts[1][0] - a1/SGD_DEGREES_TO_RADIANS;
|
|
||||||
if ( planes[i].wpts[wpn][0] < 0.0) planes[i].wpts[wpn][0] += 360.0;
|
|
||||||
if ( planes[i].wpts[wpn][0] > 360.0) planes[i].wpts[wpn][0] -= 360.0;
|
|
||||||
planes[i].wpts[wpn][1] = fabs(cd) / sin(fabs(a1));
|
|
||||||
calc_hd_course_dist(planes[i].wpts[wpn][0], planes[i].wpts[wpn][1],
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
&course, &d);
|
|
||||||
planes[i].wpts[wpn][4] = course;
|
|
||||||
planes[i].wpts[wpn][5] = d;
|
|
||||||
wpn += 1;
|
|
||||||
|
|
||||||
calc_hd_course_dist(planes[i].brg, planes[i].dist, planes[i].wpts[wpn-1][0],
|
|
||||||
planes[i].wpts[wpn-1][1], &course, &d);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
double leg = 10.0;
|
|
||||||
a1 = atan2(planes[i].wpts[1][1], leg );
|
|
||||||
|
|
||||||
if ( angle_diff_deg(planes[i].brg,planes[i].wpts[1][0]) < 0 )
|
|
||||||
planes[i].wpts[wpn][0] = planes[i].wpts[1][0] + a1/SGD_DEGREES_TO_RADIANS;
|
|
||||||
else planes[i].wpts[wpn][0] = planes[i].wpts[1][0] - a1/SGD_DEGREES_TO_RADIANS;
|
|
||||||
|
|
||||||
planes[i].wpts[wpn][1] = sqrt( planes[i].wpts[1][1]*planes[i].wpts[1][1] + leg*leg );
|
|
||||||
calc_hd_course_dist(planes[i].wpts[wpn][0], planes[i].wpts[wpn][1],
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
&course, &d);
|
|
||||||
planes[i].wpts[wpn][4] = course;
|
|
||||||
planes[i].wpts[wpn][5] = d;
|
|
||||||
wpn += 1;
|
|
||||||
|
|
||||||
calc_hd_course_dist(planes[i].brg, planes[i].dist,
|
|
||||||
planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1],
|
|
||||||
&course, &d);
|
|
||||||
}
|
|
||||||
|
|
||||||
planes[i].wpts[wpn][0] = planes[i].brg;
|
|
||||||
planes[i].wpts[wpn][1] = planes[i].dist;
|
|
||||||
planes[i].wpts[wpn][2] = planes[i].alt;
|
|
||||||
planes[i].wpts[wpn][4] = course;
|
|
||||||
planes[i].wpts[wpn][5] = d;
|
|
||||||
wpn += 1;
|
|
||||||
|
|
||||||
planes[i].wpn = wpn;
|
|
||||||
|
|
||||||
// Now check if legs are too short or if legs can be shortend
|
|
||||||
// legs must be at least 2 flight minutes long
|
|
||||||
double mdist = planes[i].spd / 60.0 * 2.0;
|
|
||||||
for ( j=2; j<wpn-1; ++j ) {
|
|
||||||
if ( planes[i].wpts[j][1] < mdist) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================
|
|
||||||
// vertical navigation
|
|
||||||
// ====================
|
|
||||||
double alt = _geod.getElevationM()+3000.0;
|
|
||||||
planes[i].wpts[1][2] = round_alt( true, alt );
|
|
||||||
for ( j=2; j<wpn-1; ++j ) {
|
|
||||||
double dalt = planes[i].alt - planes[i].wpts[j-1][2];
|
|
||||||
if ( dalt > 0 ) {
|
|
||||||
alt = planes[i].wpts[j-1][2] +
|
|
||||||
(planes[i].wpts[j][5] / planes[i].spd) * 60.0 * planes[i].desc_rate;
|
|
||||||
planes[i].wpts[j][2] = round_alt( false, alt );
|
|
||||||
if ( planes[i].wpts[j][2] > planes[i].alt )
|
|
||||||
planes[i].wpts[j][2] = round_alt( false, planes[i].alt );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
planes[i].wpts[j][2] = planes[i].wpts[1][2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Plane position: " << planes[i].brg << " " << planes[i].dist << endl;
|
|
||||||
for ( j=0; j<wpn; ++j ) {
|
|
||||||
cout << "Waypoint " << j << endl;
|
|
||||||
cout << "------------------" << endl;
|
|
||||||
cout << planes[i].wpts[j][0] << " " << planes[i].wpts[j][1]
|
|
||||||
<< " " << planes[i].wpts[j][2] << " " << planes[i].wpts[j][5];
|
|
||||||
cout << endl << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// round altitude value to next highest/lowest 500 feet
|
|
||||||
// ============================================================================
|
|
||||||
double FGApproach::round_alt( const bool hl, double alt ) {
|
|
||||||
|
|
||||||
alt = alt/1000.0;
|
|
||||||
if ( hl ) {
|
|
||||||
if ( alt > (int)(alt)+0.5 ) alt = ((int)(alt)+1)*1000.0;
|
|
||||||
else alt = ((int)(alt)+0.5)*1000.0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( alt > (int)(alt)+0.5 ) alt = ((int)(alt)+0.5)*1000.0;
|
|
||||||
else alt = ((int)(alt))*1000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return alt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// get active runway
|
|
||||||
// ============================================================================
|
|
||||||
void FGApproach::get_active_runway() {
|
|
||||||
//cout << "Entering FGApproach::get_active_runway()\n";
|
|
||||||
|
|
||||||
const FGAirport* apt = fgFindAirportID(ident);
|
|
||||||
assert(apt);
|
|
||||||
FGRunway* runway = apt->getActiveRunwayForUsage();
|
|
||||||
|
|
||||||
active_runway = runway->ident();
|
|
||||||
active_rw_hdg = runway->headingDeg();
|
|
||||||
active_rw_lon = runway->longitude();
|
|
||||||
active_rw_lat = runway->latitude();
|
|
||||||
active_rw_len = runway->lengthFt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// update infos about plane
|
|
||||||
// ========================================================================
|
|
||||||
void FGApproach::update_plane_dat() {
|
|
||||||
|
|
||||||
//cout << "Update Approach " << ident << " " << num_planes << " registered" << endl;
|
|
||||||
// update plane positions
|
|
||||||
int i;
|
|
||||||
for (i=0; i<num_planes; i++) {
|
|
||||||
planes[i].lon = lon_node->getDoubleValue();
|
|
||||||
planes[i].lat = lat_node->getDoubleValue();
|
|
||||||
planes[i].alt = elev_node->getDoubleValue();
|
|
||||||
planes[i].hdg = hdg_node->getDoubleValue();
|
|
||||||
planes[i].spd = speed_node->getDoubleValue();
|
|
||||||
|
|
||||||
double course, distance, az2;
|
|
||||||
SGGeod plane(SGGeod::fromDeg(planes[1].lon, active_rw_lat));
|
|
||||||
SGGeodesy::inverse(_geod, plane, course, az2, distance);
|
|
||||||
planes[i].dist = distance * SG_METER_TO_NM;
|
|
||||||
planes[i].brg = 360.0-course;
|
|
||||||
|
|
||||||
//cout << "Plane Id: " << planes[i].ident << " Distance to " << ident
|
|
||||||
// << " is " << planes[i].dist << " miles " << "Bearing " << planes[i].brg << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Add plane to Approach list
|
|
||||||
// =======================================================================
|
|
||||||
void FGApproach::AddPlane(const string& pid) {
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for ( i=0; i<num_planes; i++) {
|
|
||||||
if ( planes[i].ident == pid) {
|
|
||||||
//cout << "Plane already registered: " << planes[i].ident << ' ' << ident << ' ' << num_planes << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
planes[num_planes].ident = pid;
|
|
||||||
++num_planes;
|
|
||||||
//cout << "Plane added to list: " << ident << " " << num_planes << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================================================================================
|
|
||||||
// closest distance between a point (h1,d1) and a straigt line (h2,d2,h3) in 2 dim.
|
|
||||||
// ================================================================================
|
|
||||||
double FGApproach::calc_psl_dist(const double &h1, const double &d1,
|
|
||||||
const double &h2, const double &d2,
|
|
||||||
const double &h3)
|
|
||||||
{
|
|
||||||
double a1 = h1 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double a2 = h2 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double a3 = h3 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double x1 = cos(a1) * d1;
|
|
||||||
double y1 = sin(a1) * d1;
|
|
||||||
double x2 = cos(a2) * d2;
|
|
||||||
double y2 = sin(a2) * d2;
|
|
||||||
double x3 = cos(a3);
|
|
||||||
double y3 = sin(a3);
|
|
||||||
|
|
||||||
// formula: dis = sqrt( (v1-v2)**2 - ((v1-v2)*v3)**2 ); vi = (xi,yi)
|
|
||||||
double val1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
|
|
||||||
double val2 = ((x1-x2)*x3 + (y1-y2)*y3) * ((x1-x2)*x3 + (y1-y2)*y3);
|
|
||||||
double dis = val1 - val2;
|
|
||||||
// now get sign for offset
|
|
||||||
//cout << x1 << " " << x2 << " " << y1 << " " << y2 << " "
|
|
||||||
// << x3 << " " << y3 << " "
|
|
||||||
// << val1 << " " << val2 << " " << dis << endl;
|
|
||||||
x3 *= sqrt(val2);
|
|
||||||
y3 *= sqrt(val2);
|
|
||||||
double da = fabs(atan2(y3,x3) - atan2(y1-y2,x1-x2));
|
|
||||||
if ( da > SGD_PI ) da -= SGD_2PI;
|
|
||||||
if ( fabs(da) > SGD_PI_2) {
|
|
||||||
//if ( x3*(x1-x2) < 0.0 && y3*(y1-y2) < 0.0) {
|
|
||||||
x3 *= -1.0;
|
|
||||||
y3 *= -1.0;
|
|
||||||
}
|
|
||||||
//cout << x3 << " " << y3 << endl;
|
|
||||||
double dis1 = x1-x2-x3;
|
|
||||||
double dis2 = y1-y2-y3;
|
|
||||||
dis = sqrt(dis);
|
|
||||||
da = atan2(dis2,dis1);
|
|
||||||
if ( da < 0.0 ) da += SGD_2PI;
|
|
||||||
if ( da < a3 ) dis *= -1.0;
|
|
||||||
//cout << dis1 << " " << dis2 << " " << da*SGD_RADIANS_TO_DEGREES << " " << h3
|
|
||||||
// << " " << sqrt(dis1*dis1 + dis2*dis2) << " " << dis << endl;
|
|
||||||
//cout << atan2(dis2,dis1)*SGD_RADIANS_TO_DEGREES << " " << dis << endl;
|
|
||||||
|
|
||||||
return dis;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Calculate new bear/dist given starting bear/dis, and offset radial,
|
|
||||||
// and distance.
|
|
||||||
// ========================================================================
|
|
||||||
void FGApproach::calc_cd_head_dist(const double &h1, const double &d1,
|
|
||||||
const double &course, const double &dist,
|
|
||||||
double *h2, double *d2)
|
|
||||||
{
|
|
||||||
double a1 = h1 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double a2 = course * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double x1 = cos(a1) * d1;
|
|
||||||
double y1 = sin(a1) * d1;
|
|
||||||
double x2 = cos(a2) * dist;
|
|
||||||
double y2 = sin(a2) * dist;
|
|
||||||
|
|
||||||
*d2 = sqrt((x1+x2)*(x1+x2) + (y1+y2)*(y1+y2));
|
|
||||||
*h2 = atan2( (y1+y2), (x1+x2) ) * SGD_RADIANS_TO_DEGREES;
|
|
||||||
if ( *h2 < 0 ) *h2 = *h2+360;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// get heading and distance between two points; point1 ---> point2
|
|
||||||
// ========================================================================
|
|
||||||
void FGApproach::calc_hd_course_dist(const double &h1, const double &d1,
|
|
||||||
const double &h2, const double &d2,
|
|
||||||
double *course, double *dist)
|
|
||||||
{
|
|
||||||
double a1 = h1 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double a2 = h2 * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double x1 = cos(a1) * d1;
|
|
||||||
double y1 = sin(a1) * d1;
|
|
||||||
double x2 = cos(a2) * d2;
|
|
||||||
double y2 = sin(a2) * d2;
|
|
||||||
|
|
||||||
*dist = sqrt( (y2-y1)*(y2-y1) + (x2-x1)*(x2-x1) );
|
|
||||||
*course = atan2( (y2-y1), (x2-x1) ) * SGD_RADIANS_TO_DEGREES;
|
|
||||||
if ( *course < 0 ) *course = *course+360;
|
|
||||||
//cout << x1 << " " << y1 << " " << x2 << " " << y2 << " " << *dist << " " << *course << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int FGApproach::RemovePlane() {
|
|
||||||
|
|
||||||
// first check if anything has to be done
|
|
||||||
bool rmplane = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<num_planes; i++) {
|
|
||||||
if (planes[i].dist > range*SG_NM_TO_METER) {
|
|
||||||
rmplane = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!rmplane) return num_planes;
|
|
||||||
|
|
||||||
// now make a copy of the plane list
|
|
||||||
PlaneApp tmp[max_planes];
|
|
||||||
for (i=0; i<num_planes; i++) {
|
|
||||||
tmp[i] = planes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
int np = 0;
|
|
||||||
// now check which planes are still in range
|
|
||||||
for (i=0; i<num_planes; i++) {
|
|
||||||
if (tmp[i].dist <= range*SG_NM_TO_METER) {
|
|
||||||
planes[np] = tmp[i];
|
|
||||||
np += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
num_planes = np;
|
|
||||||
|
|
||||||
return num_planes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FGApproach::set_message(const string &msg)
|
|
||||||
{
|
|
||||||
fgSetString("/sim/messages/approach", msg.c_str());
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,215 +0,0 @@
|
||||||
// approach.hxx -- Approach class
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2002 Alexander Kappes
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FG_APPROACH_HXX
|
|
||||||
#define _FG_APPROACH_HXX
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
|
||||||
#include <simgear/misc/sgstream.hxx>
|
|
||||||
#include <simgear/magvar/magvar.hxx>
|
|
||||||
#include <simgear/timing/sg_time.hxx>
|
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
|
||||||
|
|
||||||
# include <iosfwd>
|
|
||||||
|
|
||||||
#include "ATC.hxx"
|
|
||||||
#include "transmission.hxx"
|
|
||||||
|
|
||||||
//DCL - a complete guess for now.
|
|
||||||
#define FG_APPROACH_DEFAULT_RANGE 100
|
|
||||||
|
|
||||||
// Contains all the information about a plane that the approach control needs
|
|
||||||
const int max_planes = 20; // max number of planes on the stack
|
|
||||||
const int max_wp = 10; // max number of waypoints for approach phase
|
|
||||||
const double max_ta = 130; // max turning angle for plane during approach
|
|
||||||
const double tbm = 2.0; // min time (in sec) between two messages
|
|
||||||
const double lfl = 10.0; // length of final leg
|
|
||||||
|
|
||||||
struct PlaneApp {
|
|
||||||
|
|
||||||
// variables for plane if it's on the radar
|
|
||||||
std::string ident; // indentification of plane
|
|
||||||
double lon; // longitude in degrees
|
|
||||||
double lat; // latitude in degrees
|
|
||||||
double alt; // Altitute above sea level in feet
|
|
||||||
double hdg; // heading of plane in degrees
|
|
||||||
double dist; // distance to airport in miles
|
|
||||||
double brg; // bearing relative to airport in degrees
|
|
||||||
double spd; // speed above ground
|
|
||||||
int contact; // contact with approach established?
|
|
||||||
// 0 = no contact yet
|
|
||||||
// 1 = in contact
|
|
||||||
// 2 = handed off to tower
|
|
||||||
double turn_rate; // standard turning rate of the plane in seconds per degree
|
|
||||||
double desc_rate; // standard descent rate of the plane in feets per minute
|
|
||||||
double clmb_rate; // standard climb rate of the plane in feets per minute
|
|
||||||
|
|
||||||
// additional variables if contact has been established
|
|
||||||
int wpn; // number of waypoints
|
|
||||||
double wpts[max_wp][6]; // assigned waypoints for approach phase
|
|
||||||
// first wp in list is airport
|
|
||||||
// last waypoint point at which contact was established
|
|
||||||
// second index: 0 = bearing to airport
|
|
||||||
// second index: 1 = distance to airport
|
|
||||||
// second index: 2 = alt
|
|
||||||
// second index: 3 = ETA
|
|
||||||
// second index: 4 = heading to next waypoint
|
|
||||||
// second index: 5 = distance to next waypoint
|
|
||||||
|
|
||||||
double dnwp; // distance to next waypoint
|
|
||||||
double dcc; // closest distance to current assigned course
|
|
||||||
double dnc; // closest distance to course from next to next to next wp
|
|
||||||
double aalt; // assigned altitude
|
|
||||||
double ahdg; // assigned heading
|
|
||||||
bool on_crs; // is the plane on course?
|
|
||||||
bool wp_change; // way point has changed
|
|
||||||
double tlm; // time when last message was sent
|
|
||||||
TransCode lmc; // code of last message
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FGApproach : public FGATC {
|
|
||||||
|
|
||||||
int bucket;
|
|
||||||
|
|
||||||
std::string active_runway;
|
|
||||||
double active_rw_hdg;
|
|
||||||
double active_rw_lon;
|
|
||||||
double active_rw_lat;
|
|
||||||
double active_rw_len;
|
|
||||||
|
|
||||||
int num_planes; // number of planes on the stack
|
|
||||||
PlaneApp planes[max_planes]; // Array of planes
|
|
||||||
std::string transmission;
|
|
||||||
bool first;
|
|
||||||
|
|
||||||
SGPropertyNode_ptr comm1_node;
|
|
||||||
SGPropertyNode_ptr comm2_node;
|
|
||||||
|
|
||||||
SGPropertyNode_ptr atcmenu_node;
|
|
||||||
SGPropertyNode_ptr atcopt0_node;
|
|
||||||
SGPropertyNode_ptr atcopt1_node;
|
|
||||||
SGPropertyNode_ptr atcopt2_node;
|
|
||||||
SGPropertyNode_ptr atcopt3_node;
|
|
||||||
SGPropertyNode_ptr atcopt4_node;
|
|
||||||
SGPropertyNode_ptr atcopt5_node;
|
|
||||||
SGPropertyNode_ptr atcopt6_node;
|
|
||||||
SGPropertyNode_ptr atcopt7_node;
|
|
||||||
SGPropertyNode_ptr atcopt8_node;
|
|
||||||
SGPropertyNode_ptr atcopt9_node;
|
|
||||||
|
|
||||||
// for failure modeling
|
|
||||||
std::string trans_ident; // transmitted ident
|
|
||||||
bool approach_failed; // approach failed?
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FGApproach(void);
|
|
||||||
~FGApproach(void);
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
void Update(double dt);
|
|
||||||
|
|
||||||
// Add new plane to stack if not already registered
|
|
||||||
// Input: pid - id of plane (name)
|
|
||||||
// Output: "true" if added; "false" if already existend
|
|
||||||
void AddPlane(const std::string& pid);
|
|
||||||
|
|
||||||
// Remove plane from stack if out of range
|
|
||||||
int RemovePlane();
|
|
||||||
|
|
||||||
inline double get_bucket() const { return bucket; }
|
|
||||||
inline int get_pnum() const { return num_planes; }
|
|
||||||
inline const std::string& get_trans_ident() { return trans_ident; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void calc_wp( const int &i);
|
|
||||||
|
|
||||||
void update_plane_dat();
|
|
||||||
|
|
||||||
void get_active_runway();
|
|
||||||
|
|
||||||
void update_param(const int &i);
|
|
||||||
|
|
||||||
double round_alt( bool hl, double alt );
|
|
||||||
|
|
||||||
double angle_diff_deg( const double &a1, const double &a2);
|
|
||||||
|
|
||||||
void set_message(const std::string &s);
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// get point2 given starting point1 and course and distance
|
|
||||||
// input: point1 = heading in degrees, distance
|
|
||||||
// input: course in degrees, distance
|
|
||||||
// output: point2 = heading in degrees, distance
|
|
||||||
// ========================================================================
|
|
||||||
void calc_cd_head_dist(const double &h1, const double &d1,
|
|
||||||
const double &course, const double &dist,
|
|
||||||
double *h2, double *d2);
|
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// get heading and distance between two points; point2 ---> point1
|
|
||||||
// input: point1 = heading in degrees, distance
|
|
||||||
// input: point2 = heading in degrees, distance
|
|
||||||
// output: course in degrees, distance
|
|
||||||
// ========================================================================
|
|
||||||
void calc_hd_course_dist(const double &h1, const double &d1,
|
|
||||||
const double &h2, const double &d2,
|
|
||||||
double *course, double *dist);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// closest distance between a point and a straigt line in 2 dim.
|
|
||||||
// the input variables are given in (heading, distance)
|
|
||||||
// relative to a common point
|
|
||||||
// input: point = heading in degrees, distance
|
|
||||||
// input: straigt line = anker vector (heading in degrees, distance),
|
|
||||||
// heading of direction vector
|
|
||||||
// output: distance
|
|
||||||
// ========================================================================
|
|
||||||
double calc_psl_dist(const double &h1, const double &d1,
|
|
||||||
const double &h2, const double &d2,
|
|
||||||
const double &h3);
|
|
||||||
|
|
||||||
// Pointers to current users position
|
|
||||||
SGPropertyNode_ptr lon_node;
|
|
||||||
SGPropertyNode_ptr lat_node;
|
|
||||||
SGPropertyNode_ptr elev_node;
|
|
||||||
SGPropertyNode_ptr hdg_node;
|
|
||||||
SGPropertyNode_ptr speed_node;
|
|
||||||
SGPropertyNode_ptr etime_node;
|
|
||||||
|
|
||||||
//Update the transmission string
|
|
||||||
void UpdateTransmission(void);
|
|
||||||
|
|
||||||
friend std::istream& operator>> ( std::istream&, FGApproach& );
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _FG_APPROACH_HXX
|
|
|
@ -1,103 +0,0 @@
|
||||||
// FGTransmission - a class to provide transmission control at larger airports.
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
// Based on ground.cxx by David Luff, started March 2002.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "transmission.hxx"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
|
|
||||||
//Constructor
|
|
||||||
FGTransmission::FGTransmission(){
|
|
||||||
}
|
|
||||||
|
|
||||||
//Destructor
|
|
||||||
FGTransmission::~FGTransmission(){
|
|
||||||
}
|
|
||||||
|
|
||||||
void FGTransmission::Init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// extract parameters from transmission
|
|
||||||
// ============================================================================
|
|
||||||
TransPar FGTransmission::Parse() {
|
|
||||||
TransPar tpar;
|
|
||||||
string tokens[20];
|
|
||||||
int msglen,toklen;
|
|
||||||
//char dum;
|
|
||||||
int i,j,k;
|
|
||||||
const char *capl = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
|
|
||||||
msglen = strlen( TransText.c_str() );
|
|
||||||
|
|
||||||
int tkn = 0;
|
|
||||||
for ( i=0; i < msglen; ++i ) {
|
|
||||||
if ( TransText.c_str()[i] != ' ' ) {
|
|
||||||
if ( TransText.c_str()[i] != ',' ) tokens[tkn] += TransText.c_str()[i];
|
|
||||||
} else if ( !tokens[tkn].empty() ) {
|
|
||||||
if ( tkn <= 20 ) {
|
|
||||||
tkn += 1;
|
|
||||||
} else {
|
|
||||||
SG_LOG(SG_ATC, SG_WARN,"Too many tokens");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i=0; i<20; ++i) {
|
|
||||||
|
|
||||||
if ( tokens[i] == "request" ) {
|
|
||||||
tpar.request = true;
|
|
||||||
} else if ( tokens[i] == "approach" ) {
|
|
||||||
tpar.station = "approach";
|
|
||||||
tpar.airport = tokens[i-1];
|
|
||||||
} else if ( tokens[i] == "landing" ) {
|
|
||||||
tpar.intention = "landing";
|
|
||||||
for ( j=i+1; j<=i+2; ++j ) {
|
|
||||||
if ( !tokens[j].empty() ) {
|
|
||||||
toklen = strlen( tokens[j].c_str() );
|
|
||||||
bool aid = true;
|
|
||||||
for ( k=0; k<toklen; ++k )
|
|
||||||
if ( ! strpbrk( &tokens[j].c_str()[k], capl )) {
|
|
||||||
aid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ( aid ) tpar.intid = tokens[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( tokens[i] == "Player" ) {
|
|
||||||
tpar.callsign = tokens[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//cout << tpar.airport << endl;
|
|
||||||
//cout << tpar.request << endl;
|
|
||||||
//cout << tpar.intention << endl;
|
|
||||||
//cout << tpar.intid << endl;
|
|
||||||
|
|
||||||
return tpar;
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
// transmission.hxx -- Transmission class
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
// Based on nav.hxx by Curtis Olson, started April 2000.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2001 David C. Luff - david.luff@nottingham.ac.uk
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FG_TRANSMISSION_HXX
|
|
||||||
#define _FG_TRANSMISSION_HXX
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
|
||||||
#include <simgear/misc/sgstream.hxx>
|
|
||||||
#include <simgear/magvar/magvar.hxx>
|
|
||||||
#include <simgear/timing/sg_time.hxx>
|
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
|
||||||
|
|
||||||
# include <istream>
|
|
||||||
|
|
||||||
#include "ATC.hxx"
|
|
||||||
|
|
||||||
struct TransCode {
|
|
||||||
int c1;
|
|
||||||
int c2;
|
|
||||||
int c3;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TransPar - a representation of the logic of a parsed speech transmission
|
|
||||||
struct TransPar {
|
|
||||||
std::string station;
|
|
||||||
std::string callsign;
|
|
||||||
std::string airport;
|
|
||||||
std::string intention; // landing, crossing
|
|
||||||
std::string intid; // (airport) ID for intention
|
|
||||||
bool request; // is the transmission a request or an answer?
|
|
||||||
int tdir; // turning direction: 1=left, 2=right
|
|
||||||
double heading;
|
|
||||||
int VDir; // vertical direction: 1=descent, 2=maintain, 3=climb
|
|
||||||
double alt;
|
|
||||||
double miles;
|
|
||||||
std::string runway;
|
|
||||||
double freq;
|
|
||||||
double time;
|
|
||||||
};
|
|
||||||
|
|
||||||
// FGTransmission - a class to encapsulate a speech transmission
|
|
||||||
class FGTransmission {
|
|
||||||
|
|
||||||
//int StationType; // Type of ATC station: 1 Approach
|
|
||||||
atc_type StationType;
|
|
||||||
TransCode Code; // DCL - no idea what this is.
|
|
||||||
std::string TransText; // The text of the spoken transmission
|
|
||||||
std::string MenuText; // An abbreviated version of the text for the menu entry
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FGTransmission(void);
|
|
||||||
~FGTransmission(void);
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
inline atc_type get_station() const { return StationType; }
|
|
||||||
inline const TransCode& get_code() { return Code; }
|
|
||||||
inline const std::string& get_transtext() { return TransText; }
|
|
||||||
inline const std::string& get_menutext() { return MenuText; }
|
|
||||||
|
|
||||||
// Return the parsed logic of the transmission
|
|
||||||
TransPar Parse();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
friend std::istream& operator>> ( std::istream&, FGTransmission& );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline std::istream&
|
|
||||||
operator >> ( std::istream& in, FGTransmission& a ) {
|
|
||||||
char ch;
|
|
||||||
int tmp;
|
|
||||||
|
|
||||||
static bool first_time = true;
|
|
||||||
static double julian_date = 0;
|
|
||||||
static const double MJD0 = 2415020.0;
|
|
||||||
if ( first_time ) {
|
|
||||||
julian_date = sgTimeCurrentMJD(0, 0) + MJD0;
|
|
||||||
first_time = false;
|
|
||||||
}
|
|
||||||
// Ugly hack alert - eventually we'll use xml format for the transmissions file
|
|
||||||
in >> tmp;
|
|
||||||
if(tmp == 1) {
|
|
||||||
a.StationType = APPROACH;
|
|
||||||
} else {
|
|
||||||
a.StationType = INVALID;
|
|
||||||
}
|
|
||||||
in >> a.Code.c1;
|
|
||||||
in >> a.Code.c2;
|
|
||||||
in >> a.Code.c3;
|
|
||||||
a.TransText = "";
|
|
||||||
in >> ch;
|
|
||||||
if ( ch != '"' ) a.TransText += ch;
|
|
||||||
while(1) {
|
|
||||||
//in >> noskipws
|
|
||||||
in.unsetf(ios::skipws);
|
|
||||||
in >> ch;
|
|
||||||
if ( ch != '"' ) a.TransText += ch;
|
|
||||||
if((ch == '"') || (ch == 0x0A)) {
|
|
||||||
break;
|
|
||||||
} // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
|
|
||||||
}
|
|
||||||
in.setf(ios::skipws);
|
|
||||||
|
|
||||||
a.MenuText = "";
|
|
||||||
in >> ch;
|
|
||||||
if ( ch != '"' ) a.MenuText += ch;
|
|
||||||
while(1) {
|
|
||||||
//in >> noskipws
|
|
||||||
in.unsetf(ios::skipws);
|
|
||||||
in >> ch;
|
|
||||||
if ( ch != '"' ) a.MenuText += ch;
|
|
||||||
if((ch == '"') || (ch == 0x0A)) {
|
|
||||||
break;
|
|
||||||
} // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
|
|
||||||
}
|
|
||||||
in.setf(ios::skipws);
|
|
||||||
|
|
||||||
//cout << "Code = " << a.Code << " Transmission text = " << a.TransText
|
|
||||||
// << " Menu text = " << a.MenuText << endl;
|
|
||||||
|
|
||||||
return in >> skipeol;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _FG_TRANSMISSION_HXX
|
|
|
@ -1,247 +0,0 @@
|
||||||
// transmissionlist.cxx -- transmission management class
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
// Based on navlist.cxx by Curtis Olson, started April 2000.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h> // bcopy()
|
|
||||||
#else
|
|
||||||
# include <string.h> // MSVC doesn't have strings.h
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
#include <simgear/misc/sgstream.hxx>
|
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
|
||||||
|
|
||||||
#include "transmissionlist.hxx"
|
|
||||||
|
|
||||||
#include <GUI/gui.h>
|
|
||||||
|
|
||||||
|
|
||||||
FGTransmissionList *current_transmissionlist;
|
|
||||||
|
|
||||||
|
|
||||||
FGTransmissionList::FGTransmissionList( void ) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FGTransmissionList::~FGTransmissionList( void ) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// load default.transmissions
|
|
||||||
bool FGTransmissionList::init( const SGPath& path ) {
|
|
||||||
FGTransmission a;
|
|
||||||
|
|
||||||
transmissionlist_station.erase( transmissionlist_station.begin(), transmissionlist_station.end() );
|
|
||||||
|
|
||||||
sg_gzifstream in( path.str() );
|
|
||||||
if ( !in.is_open() ) {
|
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read in each line of the file
|
|
||||||
|
|
||||||
// in >> skipeol;
|
|
||||||
// in >> skipcomment;
|
|
||||||
|
|
||||||
double min = 100000;
|
|
||||||
double max = 0;
|
|
||||||
|
|
||||||
while ( ! in.eof() ) {
|
|
||||||
in >> a;
|
|
||||||
transmissionlist_station[a.get_station()].push_back(a);
|
|
||||||
|
|
||||||
in >> skipcomment;
|
|
||||||
|
|
||||||
if ( a.get_station() < min ) {
|
|
||||||
min = a.get_station();
|
|
||||||
}
|
|
||||||
if ( a.get_station() > max ) {
|
|
||||||
max = a.get_station();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
cout << a.get_station() << " " << a.get_code().c1 << " " << a.get_code().c2 << " "
|
|
||||||
<< a.get_code().c3 << " " << a.get_transtext()
|
|
||||||
<< " " << a.get_menutext() << endl;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// init ATC menu
|
|
||||||
fgSetBool("/sim/atc/menu",false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// query the database for the specified station type;
|
|
||||||
// for station see FlightGear/ATC/default.transmissions
|
|
||||||
bool FGTransmissionList::query_station( const atc_type &station, FGTransmission *t,
|
|
||||||
int max_trans, int &num_trans )
|
|
||||||
{
|
|
||||||
transmission_list_type tmissions = transmissionlist_station[station];
|
|
||||||
transmission_list_iterator current = tmissions.begin();
|
|
||||||
transmission_list_iterator last = tmissions.end();
|
|
||||||
|
|
||||||
for ( ; current != last ; ++current ) {
|
|
||||||
if (num_trans < max_trans) {
|
|
||||||
t[num_trans] = *current;
|
|
||||||
num_trans += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "Transmissionlist error: Too many transmissions");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( num_trans != 0 ) return true;
|
|
||||||
else {
|
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "No transmission with station " << station << "found.");
|
|
||||||
string empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string FGTransmissionList::gen_text(const atc_type &station, const TransCode code,
|
|
||||||
const TransPar &tpars, const bool ttext )
|
|
||||||
{
|
|
||||||
const int cmax = 300;
|
|
||||||
string message;
|
|
||||||
char tag[4];
|
|
||||||
char crej = '@';
|
|
||||||
char mes[cmax];
|
|
||||||
char dum[cmax];
|
|
||||||
//char buf[10];
|
|
||||||
char *pos;
|
|
||||||
int len;
|
|
||||||
FGTransmission t;
|
|
||||||
|
|
||||||
// if (current_transmissionlist->query_station( station, &t ) ) {
|
|
||||||
transmission_list_type tmissions = transmissionlist_station[station];
|
|
||||||
transmission_list_iterator current = tmissions.begin();
|
|
||||||
transmission_list_iterator last = tmissions.end();
|
|
||||||
|
|
||||||
for ( ; current != last ; ++current ) {
|
|
||||||
if ( current->get_code().c1 == code.c1 &&
|
|
||||||
current->get_code().c2 == code.c2 &&
|
|
||||||
current->get_code().c3 == code.c3 ) {
|
|
||||||
|
|
||||||
if ( ttext ) message = current->get_transtext();
|
|
||||||
else message = current->get_menutext();
|
|
||||||
strcpy( &mes[0], message.c_str() );
|
|
||||||
|
|
||||||
// Replace all the '@' parameters with the actual text.
|
|
||||||
int check = 0; // If mes gets overflowed the while loop can go infinite
|
|
||||||
while ( strchr(&mes[0], crej) != NULL ) { // ie. loop until no more occurances of crej ('@') found
|
|
||||||
pos = strchr( &mes[0], crej );
|
|
||||||
memmove(&tag[0], pos, 3);
|
|
||||||
tag[3] = '\0';
|
|
||||||
int i;
|
|
||||||
len = 0;
|
|
||||||
for ( i=0; i<cmax; i++ ) {
|
|
||||||
if ( mes[i] == crej ) {
|
|
||||||
len = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strncpy( &dum[0], &mes[0], len );
|
|
||||||
dum[len] = '\0';
|
|
||||||
|
|
||||||
if ( strcmp ( tag, "@ST" ) == 0 )
|
|
||||||
strcat( &dum[0], tpars.station.c_str() );
|
|
||||||
else if ( strcmp ( tag, "@AP" ) == 0 )
|
|
||||||
strcat( &dum[0], tpars.airport.c_str() );
|
|
||||||
else if ( strcmp ( tag, "@CS" ) == 0 )
|
|
||||||
strcat( &dum[0], tpars.callsign.c_str() );
|
|
||||||
else if ( strcmp ( tag, "@TD" ) == 0 ) {
|
|
||||||
if ( tpars.tdir == 1 ) {
|
|
||||||
char buf[] = "left";
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char buf[] = "right";
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@HE" ) == 0 ) {
|
|
||||||
char buf[10];
|
|
||||||
sprintf( buf, "%i", (int)(tpars.heading) );
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@VD" ) == 0 ) {
|
|
||||||
if ( tpars.VDir == 1 ) {
|
|
||||||
char buf[] = "Descend and maintain";
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( tpars.VDir == 2 ) {
|
|
||||||
char buf[] = "Maintain";
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( tpars.VDir == 3 ) {
|
|
||||||
char buf[] = "Climb and maintain";
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@AL" ) == 0 ) {
|
|
||||||
char buf[10];
|
|
||||||
sprintf( buf, "%i", (int)(tpars.alt) );
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@MI" ) == 0 ) {
|
|
||||||
char buf[10];
|
|
||||||
sprintf( buf, "%3.1f", tpars.miles );
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@FR" ) == 0 ) {
|
|
||||||
char buf[10];
|
|
||||||
sprintf( buf, "%6.2f", tpars.freq );
|
|
||||||
strcat( &dum[0], &buf[0] );
|
|
||||||
}
|
|
||||||
else if ( strcmp ( tag, "@RW" ) == 0 )
|
|
||||||
strcat( &dum[0], tpars.runway.c_str() );
|
|
||||||
else {
|
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "Tag " << tag << " not found");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
strcat( &dum[0], &mes[len+3] );
|
|
||||||
strcpy( &mes[0], &dum[0] );
|
|
||||||
|
|
||||||
++check;
|
|
||||||
if(check > 10) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "WARNING: Possibly endless loop terminated in FGTransmissionlist::gen_text(...)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//cout << mes << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mes[0] ? mes : "No transmission found";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
// transmissionlist.hxx -- transmission management class
|
|
||||||
//
|
|
||||||
// Written by Alexander Kappes, started March 2002.
|
|
||||||
// Based on navlist.hxx by Curtis Olson, started April 2000.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
||||||
//
|
|
||||||
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FG_TRANSMISSIONLIST_HXX
|
|
||||||
#define _FG_TRANSMISSIONLIST_HXX
|
|
||||||
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "ATC.hxx"
|
|
||||||
#include "transmission.hxx"
|
|
||||||
|
|
||||||
using std::map;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
class FGTransmissionList {
|
|
||||||
|
|
||||||
// convenience types
|
|
||||||
typedef vector < FGTransmission > transmission_list_type;
|
|
||||||
typedef transmission_list_type::iterator transmission_list_iterator;
|
|
||||||
typedef transmission_list_type::const_iterator transmission_list_const_iterator;
|
|
||||||
|
|
||||||
// Map of transmission lists by station type
|
|
||||||
// typedef map < int, transmission_list_type, less<int> > transmission_map_type;
|
|
||||||
typedef map < atc_type, transmission_list_type > transmission_map_type;
|
|
||||||
typedef transmission_map_type::iterator transmission_map_iterator;
|
|
||||||
typedef transmission_map_type::const_iterator transmission_map_const_iterator;
|
|
||||||
|
|
||||||
transmission_map_type transmissionlist_station;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FGTransmissionList();
|
|
||||||
~FGTransmissionList();
|
|
||||||
|
|
||||||
// load the transmission data and build the map
|
|
||||||
bool init( const SGPath& path );
|
|
||||||
|
|
||||||
// query the database for the specified code,
|
|
||||||
bool query_station( const atc_type &station, FGTransmission *a, int max_trans, int &num_trans );
|
|
||||||
|
|
||||||
// generate the transmission text given the code of the message
|
|
||||||
// and the parameters
|
|
||||||
// Set ttext = true to generate the spoken transmission text,
|
|
||||||
// or false to generate the abridged menu entry text.
|
|
||||||
string gen_text(const atc_type &station, const TransCode code,
|
|
||||||
const TransPar &tpars, const bool ttext);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void mkATCMenuInit (void);
|
|
||||||
void mkATCMenu (void);
|
|
||||||
|
|
||||||
extern FGTransmissionList *current_transmissionlist;
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _FG_TRANSMISSIONLIST_HXX
|
|
Loading…
Reference in a new issue