-// Implementation of FGATC - ATC subsystem abstract base class.
-// Nothing in here should ever get called.
+// Implementation of FGATC - ATC subsystem base class.
//
// Written by David Luff, started February 2002.
//
void FGATC::SetNoDisplay() {
}
-const char* FGATC::GetIdent() {
- return("Error - base class function called in FGATC...");
-}
-
atc_type FGATC::GetType() {
return INVALID;
}
+void FGATC::SetData(ATCData* d) {
+ lon = d->lon;
+ lat = d->lat;
+ elev = d->elev;
+ x = d->x;
+ y = d->y;
+ z = d->z;
+ range = d->range;
+ ident = d->ident;
+ name = d->name;
+ freq = d->freq;
+}
+
ostream& operator << (ostream& os, atc_type atc) {
switch(atc) {
case(INVALID):
#define _FG_ATC_HXX
#include <simgear/compiler.h>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/debug/logstream.hxx>
#include STL_IOSTREAM
#include STL_STRING
SG_USING_STD(ostream);
SG_USING_STD(string);
+SG_USING_STD(ios);
// Possible types of ATC type that the radios may be tuned to.
// INVALID implies not tuned in to anything.
ENROUTE
};
+// DCL - new experimental ATC data store
+struct ATCData {
+ atc_type type;
+ float lon, lat, elev;
+ float x, y, z;
+ //int freq;
+ unsigned short int freq;
+ //int range;
+ unsigned short int range;
+ string ident;
+ string name;
+};
+
ostream& operator << (ostream& os, atc_type atc);
class FGATC {
// Indicate that this instance should not output to the display
virtual void SetNoDisplay();
- // Return the ATC station ident (generally the ICAO code of the airport)
- virtual const char* GetIdent();
-
// Return the type of ATC station that the class represents
virtual atc_type GetType();
+
+ // Set the core ATC data
+ void SetData(ATCData* d);
+
+ inline double get_lon() const { return lon; }
+ inline void set_lon(const double ln) {lon = ln;}
+ inline double get_lat() const { return lat; }
+ inline void set_lat(const double lt) {lat = lt;}
+ inline double get_elev() const { return elev; }
+ inline void set_elev(const double ev) {elev = ev;}
+ inline double get_x() const { return x; }
+ inline void set_x(const double ecs) {x = ecs;}
+ inline double get_y() const { return y; }
+ inline void set_y(const double why) {y = why;}
+ inline double get_z() const { return z; }
+ inline void set_z(const double zed) {z = zed;}
+ inline int get_freq() const { return freq; }
+ inline void set_freq(const int fq) {freq = fq;}
+ inline int get_range() const { return range; }
+ inline void set_range(const int rg) {range = rg;}
+ inline const char* get_ident() { return ident.c_str(); }
+ inline void set_ident(const string id) {ident = id;}
+ inline const char* get_name() {return name.c_str();}
+ inline void set_name(const string nm) {name = nm;}
+
+protected:
+
+ double lon, lat, elev;
+ double x, y, z;
+ int freq;
+ int range;
+ string ident; // Code of the airport its at.
+ string name; // Name transmitted in the broadcast.
};
+inline istream&
+operator >> ( istream& fin, ATCData& a )
+{
+ double f;
+ char ch;
+ char tp;
+
+ fin >> tp;
+
+ switch(tp) {
+ case 'I':
+ a.type = ATIS;
+ break;
+ case 'T':
+ a.type = TOWER;
+ break;
+ case 'G':
+ a.type = GROUND;
+ break;
+ case 'A':
+ a.type = APPROACH;
+ break;
+ case '[':
+ a.type = INVALID;
+ return fin >> skipeol;
+ default:
+ SG_LOG(SG_GENERAL, SG_ALERT, "Warning - unknown type \'" << tp << "\' found whilst reading ATC frequency data!\n");
+ a.type = INVALID;
+ return fin >> skipeol;
+ }
+
+ fin >> a.lat >> a.lon >> a.elev >> f >> a.range
+ >> a.ident;
+
+ a.name = "";
+ fin >> ch;
+ a.name += ch;
+ while(1) {
+ //in >> noskipws
+ fin.unsetf(ios::skipws);
+ fin >> ch;
+ a.name += ch;
+ if((ch == '"') || (ch == 0x0A)) {
+ break;
+ } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
+ }
+ fin.setf(ios::skipws);
+ //cout << "Comm name = " << a.name << '\n';
+
+ a.freq = (int)(f*100.0 + 0.5);
+
+ // cout << a.ident << endl;
+
+ // generate cartesian coordinates
+ Point3D geod( a.lon * SGD_DEGREES_TO_RADIANS, a.lat * SGD_DEGREES_TO_RADIANS, a.elev );
+ Point3D cart = sgGeodToCart( geod );
+ a.x = cart.x();
+ a.y = cart.y();
+ a.z = cart.z();
+
+ return fin >> skipeol;
+}
+
+
#endif // _FG_ATC_HXX
#include <simgear/debug/logstream.hxx>
#include "ATCmgr.hxx"
-#include "atislist.hxx"
+#include "commlist.hxx"
+//#include "atislist.hxx"
//#include "groundlist.hxx"
-#include "towerlist.hxx"
-#include "approachlist.hxx"
+//#include "towerlist.hxx"
+//#include "approachlist.hxx"
#include "ATCdisplay.hxx"
/*
FGATCMgr::FGATCMgr() {
- comm1_ident = "";
- comm1_atis_ident = "";
- comm1_tower_ident = "";
- comm1_approach_ident = "";
- last_comm1_ident = "";
- last_comm1_atis_ident = "";
- last_comm1_tower_ident = "";
- last_comm1_approach_ident = "";
+ comm_ident[0] = "";
+ comm_ident[1] = "";
+ last_comm_ident[0] = "";
+ last_comm_ident[1] = "";
approach_ident = "";
last_in_range = false;
- comm1_atis_valid = false;
- comm1_tower_valid = false;
- comm1_approach_valid = false;
- comm1_type = INVALID;
- comm1_atc_ptr = NULL;
- comm2_ident = "";
- comm2_atis_ident = "";
- comm2_tower_ident = "";
- comm2_approach_ident = "";
- last_comm2_ident = "";
- last_comm2_atis_ident = "";
- last_comm2_tower_ident = "";
- last_comm2_approach_ident = "";
- comm2_atis_valid = false;
- comm2_tower_valid = false;
- comm2_approach_valid = false;
- comm2_type = INVALID;
- comm2_atc_ptr = NULL;
+ comm_type[0] = INVALID;
+ comm_type[1] = INVALID;
+ comm_atc_ptr[0] = NULL;
+ comm_atc_ptr[1] = NULL;
}
FGATCMgr::~FGATCMgr() {
}
void FGATCMgr::init() {
- comm1_node = fgGetNode("/radios/comm[0]/frequencies/selected-mhz", true);
- comm2_node = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true);
+ comm_node[0] = fgGetNode("/radios/comm[0]/frequencies/selected-mhz", true);
+ comm_node[1] = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true);
lon_node = fgGetNode("/position/longitude-deg", true);
lat_node = fgGetNode("/position/latitude-deg", true);
elev_node = fgGetNode("/position/altitude-ft", true);
// fgEVENT::FG_EVENT_READY, 800);
// For some reason the above doesn't compile - including Time/event.hxx stops compilation.
+ // Initialise the frequency search map
+ current_commlist = new FGCommList;
+ SGPath p_comm( globals->get_fg_root() );
+ current_commlist->init( p_comm );
+
// Initialise the airport_atc_map - we'll cheat for now and just hardcode KEMT and any others that may be needed for development
AirportATC *a = new AirportATC;
a->lon = -118.034719;
}
void FGATCMgr::update(double dt) {
+ //cout << "Entering update..." << endl;
//Traverse the list of active stations.
//Only update one class per update step to avoid the whole ATC system having to calculate between frames.
//Eventually we should only update every so many steps.
if(atc_list_itr == atc_list.end()) {
atc_list_itr = atc_list.begin();
}
+ //cout << "Updating " << (*atc_list_itr)->get_ident() << ' ' << (*atc_list_itr)->GetType() << '\n';
+ //cout << "Freq = " << (*atc_list_itr)->get_freq() << '\n';
(*atc_list_itr)->Update();
+ //cout << "Done ATC update..." << endl;
++atc_list_itr;
}
// Search the tuned frequencies every now and then - this should be done with the event scheduler
static int i = 0;
+ if(i == 7) {
+ AreaSearch();
+ }
if(i == 15) {
- Search(1);
+ //cout << "About to search(1)" << endl;
+ FreqSearch(1);
}
if(i == 30) {
- Search(2);
+ //cout << "About to search(2)" << endl;
+ FreqSearch(2);
i = 0;
}
++i;
}
-/*
-// Remove from list only if not needed by the AI system
-void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp) {
- AirportATC a;
+
+// Remove from list only if not needed by the AI system or the other comm channel
+// TODO - implement me!!
+void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp, int chan) {
+ /*AirportATC a;
if(GetAirportATCDetails((string)id, &a)) {
if(a.set_by_AI) {
// Don't remove
} else {
// remove
}
- }
+ }*/
+
+ // Hack - need to implement this properly
+ RemoveFromList(id, tp);
}
-*/
+
// Remove from list - should only be called from above or similar
+// This function *will* remove it from the list regardless of who else might want it.
void FGATCMgr::RemoveFromList(const char* id, atc_type tp) {
//cout << "Requested type = " << tp << '\n';
//cout << "id = " << id << '\n';
atc_list_itr = atc_list.begin();
while(atc_list_itr != atc_list.end()) {
//cout << "type = " << (*atc_list_itr)->GetType() << '\n';
- //cout << "Ident = " << (*atc_list_itr)->GetIdent() << '\n';
- if( (!strcmp((*atc_list_itr)->GetIdent(), id))
+ //cout << "Ident = " << (*atc_list_itr)->get_ident() << '\n';
+ if( (!strcmp((*atc_list_itr)->get_ident(), id))
&& ((*atc_list_itr)->GetType() == tp) ) {
//Before removing it stop it transmitting!!
//cout << "OBLITERATING FROM LIST!!!\n";
}
-//DCL - this routine untested so far.
// Find in list - return a currently active ATC pointer given ICAO code and type
+// Return NULL if the given service is not in the list
+// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
FGATC* FGATCMgr::FindInList(const char* id, atc_type tp) {
atc_list_itr = atc_list.begin();
while(atc_list_itr != atc_list.end()) {
- if( (!strcmp((*atc_list_itr)->GetIdent(), id))
+ if( (!strcmp((*atc_list_itr)->get_ident(), id))
&& ((*atc_list_itr)->GetType() == tp) ) {
return(*atc_list_itr);
} // Note that that can upset where we are in the list but that shouldn't really matter
++atc_list_itr;
}
- // We need a fallback position
- SG_LOG(SG_GENERAL, SG_ALERT, "*** Failed to find FGATC* in FGATCMgr::FindInList - this should not happen!");
+ // If we get here it's not in the list
return(NULL);
}
return(FindInList(icao.c_str(), type)); // DCL - this untested so far.
} else {
FGTower* t = new FGTower;
- if(current_towerlist->query(a->lon, a->lat, a->elev, a->tower_freq, &tower)) {
- *t = tower;
+ ATCData data;
+ if(current_commlist->FindByFreq(a->lon, a->lat, a->elev, a->tower_freq, &data, TOWER)) {
+ t->SetData(&data);
atc_list.push_back(t);
a->tower_active = true;
airport_atc_map[icao] = a;
unsigned char* buf = v1.WriteMessage((char*)msg.c_str(), len, voice);
if(voice) {
FGSimpleSound* simple = new FGSimpleSound(buf, len);
- simple->set_volume(2.0);
+ // TODO - at the moment the volume is always set off comm1
+ // and can't be changed after the transmission has started.
+ simple->set_volume(5.0 * fgGetDouble("/radios/comm[0]/volume"));
globals->get_soundmgr()->add(simple, refname);
if(repeating) {
globals->get_soundmgr()->play_looped(refname);
//cout << "comm1_type = " << comm1_type << endl;
// Second - customise the dialog box
- switch(comm1_type) {
+ switch(comm_type[0]) {
case INVALID:
atcDialogCommunicationOptions->newList(NULL);
atcDialogMessage->setLabel("Not tuned in to any ATC service.");
// This is in ATCDialogOK()
}
-////////////////////////////////////////////////////////////////
-//
-// TODO - The whole ATC frequency storage and search is really
-// really ugly and needs reworking at some point.
-//
-////////////////////////////////////////////////////////////////
-// Search the specified comm channel (1 or 2)
-void FGATCMgr::Search(int chan) {
+// Search for ATC stations by frequency
+void FGATCMgr::FreqSearch(int channel) {
+ int chan = channel - 1; // Convert to zero-based for the arrays
+
+ ATCData data;
+ double freq = comm_node[chan]->getDoubleValue();
+ lon = lon_node->getDoubleValue();
+ lat = lat_node->getDoubleValue();
+ elev = elev_node->getDoubleValue() * SG_FEET_TO_METER;
- if(chan == 1) {
- ////////////////////////////////////////////////////////////////////////
- // Comm1.
- ////////////////////////////////////////////////////////////////////////
- //cout << "In FGATCMgr::Search() - atc_list.size = " << atc_list.size() << '\n';
-
- comm1_freq = comm1_node->getDoubleValue();
- //cout << "************* comm1_freq = " << comm1_freq << '\n';
- double lon = lon_node->getDoubleValue();
- double lat = lat_node->getDoubleValue();
- double elev = elev_node->getDoubleValue() * SG_FEET_TO_METER;
-
- // We must be able to generalise some of the repetetive searching below!
-
- //Search for ATIS first
- if(current_atislist->query(lon, lat, elev, comm1_freq, &atis)) {
- //cout << "atis found in radiostack search !!!!" << endl;
- //cout << "last_comm1_atis_ident = " << last_comm1_atis_ident << '\n';
- //cout << "comm1_type " << comm1_type << '\n';
- comm1_atis_ident = atis.GetIdent();
- comm1_atis_valid = true;
- if(last_comm1_atis_ident != comm1_atis_ident) {
- if(last_comm1_atis_ident != "") {
- RemoveFromList(last_comm1_atis_ident, ATIS);
- }
- last_comm1_atis_ident = comm1_atis_ident;
- //cout << "last_comm1_atis_ident = " << last_comm1_atis_ident << '\n';
- comm1_type = ATIS;
- comm1_elev = atis.get_elev();
- comm1_range = FG_ATIS_DEFAULT_RANGE;
- comm1_effective_range = comm1_range;
- comm1_x = atis.get_x();
- comm1_y = atis.get_y();
- comm1_z = atis.get_z();
- FGATIS* a = new FGATIS;
- *a = atis;
- comm1_atc_ptr = a;
- a->SetDisplay();
- a->set_refname("atis1");
- atc_list.push_back(a);
- //cout << "Found a new atis station in range" << endl;
- //cout << " id = " << atis.GetIdent() << endl;
- return; //This rather assumes that we never have more than one type of station in range.
- }
- } else {
- if(comm1_atis_valid) {
- //cout << "Removing ATIS " << comm1_atis_ident << " from list\n";
- RemoveFromList(comm1_atis_ident, ATIS);
- comm1_atis_valid = false;
- if(comm1_type == ATIS) {
- comm1_type = INVALID;
- }
- comm1_atis_ident = "";
- //comm1_trans_ident = "";
- last_comm1_atis_ident = "";
- comm1_atc_ptr = NULL;
+ // Query the data store and get the closest match if any
+ if(current_commlist->FindByFreq(lon, lat, elev, freq, &data)) {
+ // We have a match
+ // What's the logic?
+ // If this channel not previously valid then easy - add ATC to list
+ // If this channel was valid then - Have we tuned to a different service?
+ // If so - de-register one and add the other
+ if(comm_valid[chan]) {
+ if((comm_ident[chan] == data.ident) && (comm_type[chan] == data.type)) {
+ // Then we're still tuned into the same service so do nought and return
+ return;
+ } else {
+ // Something's changed - either the location or the service type
+ // We need to feed the channel in so we're not removing it if we're also tuned in on the other channel
+ CommRemoveFromList(comm_ident[chan], comm_type[chan], chan);
}
- //cout << "not picking up atis" << endl;
}
+ // At this point we can assume that we need to add the service.
+ comm_ident[chan] = (data.ident).c_str();
+ comm_type[chan] = data.type;
+ comm_x[chan] = (double)data.x;
+ comm_y[chan] = (double)data.y;
+ comm_z[chan] = (double)data.z;
+ comm_lon[chan] = (double)data.lon;
+ comm_lat[chan] = (double)data.lat;
+ comm_elev[chan] = (double)data.elev;
+ comm_valid[chan] = true;
- //Next search for tower
- //cout << "comm1_freq = " << comm1_freq << '\n';
- if(current_towerlist->query(lon, lat, elev, comm1_freq, &tower)) {
- //cout << "tower found in radiostack search !!!!" << endl;
- comm1_tower_ident = tower.GetIdent();
- //cout << "comm1_tower_ident = " << comm1_tower_ident << '\n';
- comm1_tower_valid = true;
- if(last_comm1_tower_ident != comm1_tower_ident) {
- if(last_comm1_tower_ident != "") {
- RemoveFromList(last_comm1_tower_ident, TOWER);
- }
- last_comm1_tower_ident = comm1_tower_ident;
- comm1_type = TOWER;
- comm1_elev = tower.get_elev();
- comm1_range = FG_TOWER_DEFAULT_RANGE;
- comm1_effective_range = comm1_range;
- comm1_x = tower.get_x();
- comm1_y = tower.get_y();
- comm1_z = tower.get_z();
+ // This was a switch-case statement but the compiler didn't like the new variable creation with it.
+ if(comm_type[chan] == ATIS) {
+ FGATIS* a = new FGATIS;
+ a->SetData(&data);
+ comm_atc_ptr[chan] = a;
+ a->SetDisplay();
+ //a->set_refname((chan) ? "atis2" : "atis1"); // FIXME - that line is limited to 2 channels
+ atc_list.push_back(a);
+ } else if (comm_type[chan] == TOWER) {
+ FGATC* app = FindInList(comm_ident[chan], TOWER);
+ if(app != NULL) {
+ // The station is already in the ATC list
+ app->SetDisplay();
+ } else {
+ // Generate the station and put in the ATC list
FGTower* t = new FGTower;
- *t = tower;
- comm1_atc_ptr = t;
+ t->SetData(&data);
+ comm_atc_ptr[chan] = t;
t->SetDisplay();
atc_list.push_back(t);
- //cout << "Found a new tower station in range" << endl;
- //cout << " id = " << tower.GetIdent() << endl;
- return; //This rather assumes that we never have more than one type of station in range.
- }
- } else {
- if(comm1_tower_valid) {
- //cout << "removing tower\n";
- RemoveFromList(comm1_tower_ident, TOWER);
- //comm1_valid = false;
- if(comm1_type == TOWER) {
- comm1_type = INVALID; // Only invalidate if we haven't switched it to something else
- }
- comm1_tower_valid = false;
- comm1_tower_ident = "";
- last_comm1_tower_ident = "";
- comm1_atc_ptr = NULL;
- //comm1_ident = "";
- //comm1_trans_ident = "";
- //last_comm1_ident = "";
- }
- //cout << "not picking up tower" << endl;
- }
- /*
- //Next search for Ground control
- if(current_groundlist->query(lon, lat, elev, comm1_freq, &ground)) {
- //cout << "Ground Control found in radiostack search !!!!" << endl;
- comm1_ident = ground.GetIdent();
- comm1_valid = true;
- if((last_comm1_ident != comm1_ident) || (comm1_type != GROUND)) {
- if(last_comm1_ident != "") {
- RemoveFromList(last_comm1_ident, GROUND);
- }
- last_comm1_ident = comm1_ident;
- comm1_type = GROUND;
- comm1_elev = ground.get_elev();
- comm1_range = FG_GROUND_DEFAULT_RANGE;
- comm1_effective_range = comm1_range;
- comm1_x = ground.get_x();
- comm1_y = ground.get_y();
- comm1_z = ground.get_z();
- FGGround* g = new FGGround;
- *g = ground;
- g->SetDisplay();
- atc_list.push_back(g);
- // For now we will automatically make contact with ground when the radio is tuned.
- // This rather assumes that the user tunes the radio at the appropriate place
- // (ie. having just turned off the runway) and only uses ground control on arrival
- // but its a start!
- g->NewArrival(current_plane);
- //cout << "Found a new ground station in range" << endl;
- //cout << " id = " << ground.GetIdent() << endl;
- return; //This rather assumes that we never have more than one type of station in range.
}
- } else {
- if((comm1_valid) && (comm1_type == GROUND)) {
- RemoveFromList(comm1_ident, GROUND);
- comm1_valid = false;
- comm1_type = INVALID;
- comm1_ident = "";
- //comm1_trans_ident = "";
- last_comm1_ident = "";
+ } /*else if (comm_type[chan] == APPROACH) {
+ // We have to be a bit more carefull here since approaches are also searched by area
+ FGATC* app = FindInList(comm_ident[chan], APPROACH);
+ if(app != NULL) {
+ // The station is already in the ATC list
+ app->AddPlane("Player");
+ app->SetDisplay();
+ } else {
+ // Generate the station and put in the ATC list
+ FGApproach* a = new FGApproach;
+ a->SetData(&data);
+ a->AddPlane("Player");
+ atc_list.push_back(a);
+ }
+ }*/
+ } else {
+ if(comm_valid[chan]) {
+ if(comm_type[chan] != APPROACH) {
+ // Currently approaches are removed by Alexander's out-of-range mechanism
+ CommRemoveFromList(comm_ident[chan], comm_type[chan], chan);
}
- //cout << "not picking up ground control" << endl;
+ // Note that we *don't* call SetNoDisplay() here because the other comm channel
+ // might be tuned into the same station - this is handled by CommRemoveFromList(...)
+ comm_type[chan] = INVALID;
+ comm_atc_ptr[chan] = NULL;
+ comm_valid[chan] = false;
}
- */
- // ================================================================================
- // Search for Approach stations
- // ================================================================================
- // init number of approach stations reachable by plane
- int num_app = 0;
+ }
+}
+
+
+// Search ATC stations by area in order that we appear 'on the radar'
+void FGATCMgr::AreaSearch() {
+ // 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;
+
+ // search stations in range
+ int num_app = current_commlist->FindByPos(lon, lat, elev, &approaches, APPROACH);
+ if (num_app != 0) {
+ //cout << num_app << " approaches found in radiostack search !!!!" << endl;
- // search stations in range
- current_approachlist->query_bck(lon, lat, elev, approaches, max_app, num_app);
- if (num_app != 0) {
- //cout << num_app << " approaches found in radiostack search !!!!" << endl;
+ for(app_itr = approaches.begin(); app_itr != approaches.end(); app_itr++) {
- for ( int i=0; i<num_app; i++ ) {
- bool new_app = true;
- approach_ident = approaches[i].GetIdent();
-
- // check if station already exists on ATC stack
- atc_list_itr = atc_list.begin();
- while(atc_list_itr != atc_list.end()) {
- //cout << "ATC list: " << (*atc_list_itr)->GetIdent() << endl;
- if((!strcmp((*atc_list_itr)->GetIdent(), approach_ident))
- && ((*atc_list_itr)->GetType() == APPROACH) ) {
- new_app = false;
- string pid = "Player";
- (*atc_list_itr)->AddPlane(pid);
- (*atc_list_itr)->Update();
- break;
- }
- ++atc_list_itr;
- }
- // generate new Approach on ATC stack
- if (new_app) {
- FGApproach* a = new FGApproach;
- *a = approaches[i];
- string pid = "Player";
- a->AddPlane(pid);
- a->Update();
- a->SetDisplay();
- comm1_atc_ptr = a;
- atc_list.push_back(a);
- //cout << "Found a new approach station in range: Id = "
- // << approaches[i].GetIdent() << endl;
- }
- }
- }
-
- // remove planes which are out of range
- atc_list_itr = atc_list.begin();
- while(atc_list_itr != atc_list.end()) {
- if((*atc_list_itr)->GetType() == APPROACH ) {
- int np = (*atc_list_itr)->RemovePlane();
- // if approach has no planes left remove it from ATC list
- if ( np == 0) {
- (*atc_list_itr)->SetNoDisplay();
- (*atc_list_itr)->Update();
- delete (*atc_list_itr);
- atc_list_itr = atc_list.erase(atc_list_itr);
- break; // the other stations will be checked next time
- }
- }
- ++atc_list_itr;
- }
-
- } else { // chan = 2
-
- ////////////////////////////////////////////////////////////////////////
- // Comm2.
- ////////////////////////////////////////////////////////////////////////
- //cout << "In FGATCMgr::Search() - atc_list.size = " << atc_list.size() << '\n';
-
- comm2_freq = comm2_node->getDoubleValue();
- //cout << "************* comm1_freq = " << comm1_freq << '\n';
- double lon = lon_node->getDoubleValue();
- double lat = lat_node->getDoubleValue();
- double elev = elev_node->getDoubleValue() * SG_FEET_TO_METER;
-
- if(current_atislist->query(lon, lat, elev, comm2_freq, &atis)) {
- comm2_atis_ident = atis.GetIdent();
- comm2_atis_valid = true;
- if(last_comm2_atis_ident != comm2_atis_ident) {
- if(last_comm2_atis_ident != "") {
- RemoveFromList(last_comm2_atis_ident, ATIS);
- }
- last_comm2_atis_ident = comm2_atis_ident;
- comm2_type = ATIS;
- comm2_elev = atis.get_elev();
- comm2_range = FG_ATIS_DEFAULT_RANGE;
- comm2_effective_range = comm2_range;
- comm2_x = atis.get_x();
- comm2_y = atis.get_y();
- comm2_z = atis.get_z();
- FGATIS* a = new FGATIS;
- *a = atis;
- comm2_atc_ptr = a;
- a->SetDisplay();
- a->set_refname("atis2");
+ FGATC* app = FindInList((app_itr->ident).c_str(), app_itr->type);
+ if(app != NULL) {
+ // The station is already in the ATC list
+ app->AddPlane("Player");
+ //app->Update();
+ } else {
+ // Generate the station and put in the ATC list
+ FGApproach* a = new FGApproach;
+ a->SetData(&(*app_itr));
+ a->AddPlane("Player");
+ //a->Update();
atc_list.push_back(a);
- //cout << "Found a new atis station in range" << endl;
- //cout << " id = " << atis.GetIdent() << endl;
- return; //This rather assumes that we never have more than one type of station in range.
- }
- } else {
- if(comm2_atis_valid) {
- RemoveFromList(comm2_atis_ident, ATIS);
- comm2_atis_valid = false;
- if(comm2_type == ATIS) {
- comm2_type = INVALID;
- }
- comm2_atis_ident = "";
- //comm2_trans_ident = "";
- last_comm2_atis_ident = "";
- comm2_atc_ptr = NULL;
}
}
-
- if(current_towerlist->query(lon, lat, elev, comm2_freq, &tower)) {
- //cout << "tower found in radiostack search !!!!" << endl;
- comm2_tower_ident = tower.GetIdent();
- comm2_tower_valid = true;
- if(last_comm2_tower_ident != comm2_tower_ident) {
- if(last_comm2_tower_ident != "") {
- RemoveFromList(last_comm2_tower_ident, TOWER);
- }
- last_comm2_tower_ident = comm2_tower_ident;
- comm2_type = TOWER;
- comm2_elev = tower.get_elev();
- comm2_range = FG_TOWER_DEFAULT_RANGE;
- comm2_effective_range = comm2_range;
- comm2_x = tower.get_x();
- comm2_y = tower.get_y();
- comm2_z = tower.get_z();
- FGTower* t = new FGTower;
- *t = tower;
- comm2_atc_ptr = t;
- t->SetDisplay();
- atc_list.push_back(t);
- return;
- }
- } else {
- if(comm2_tower_valid) {
- RemoveFromList(comm2_tower_ident, TOWER);
- if(comm2_type == TOWER) {
- comm2_type = INVALID; // Only invalidate if we haven't switched it to something else
- }
- comm2_tower_valid = false;
- comm2_tower_ident = "";
- last_comm2_tower_ident = "";
- comm2_atc_ptr = NULL;
+ }
+
+ // remove planes which are out of range
+ // TODO - I'm not entirely sure that this belongs here.
+ atc_list_itr = atc_list.begin();
+ while(atc_list_itr != atc_list.end()) {
+ if((*atc_list_itr)->GetType() == APPROACH ) {
+ int np = (*atc_list_itr)->RemovePlane();
+ // if approach has no planes left remove it from ATC list
+ if ( np == 0) {
+ (*atc_list_itr)->SetNoDisplay();
+ (*atc_list_itr)->Update();
+ delete (*atc_list_itr);
+ atc_list_itr = atc_list.erase(atc_list_itr);
+ break; // the other stations will be checked next time
}
}
+ ++atc_list_itr;
}
}
SG_USING_STD(list);
SG_USING_STD(map);
-const int max_app = 20;
-
// Structure for holding details of the ATC frequencies at a given airport, and whether they are in the active list or not.
// These can then be cross referenced with the [atis][tower][etc]lists which are stored by frequency.
// Non-available services are denoted by a frequency of zero.
double elev;
// Type of ATC control that the user's radios are tuned to.
- atc_type comm1_type;
- atc_type comm2_type;
+ atc_type comm_type[2];
// Pointer to the ATC station that the user is currently tuned into.
- FGATC* comm1_atc_ptr;
- FGATC* comm2_atc_ptr;
+ FGATC* comm_atc_ptr[2];
- double comm1_freq;
- double comm2_freq;
+ double comm_freq[2];
// Pointers to users current communication frequencies.
- SGPropertyNode* comm1_node;
- SGPropertyNode* comm2_node;
+ SGPropertyNode* comm_node[2];
// Pointers to current users position
SGPropertyNode* lon_node;
// Position of the ATC that the comm radios are tuned to in order to decide
// whether transmission will be received.
- double comm1_x, comm1_y, comm1_z, comm1_elev;
- double comm2_x, comm2_y, comm2_z, comm2_elev;
-
- double comm1_range, comm1_effective_range;
- bool comm1_valid;
- bool comm1_atis_valid;
- bool comm1_tower_valid;
- bool comm1_approach_valid;
- const char* comm1_ident;
- const char* comm1_atis_ident;
- const char* comm1_tower_ident;
- const char* comm1_approach_ident;
- const char* last_comm1_ident;
- const char* last_comm1_atis_ident;
- const char* last_comm1_tower_ident;
- const char* last_comm1_approach_ident;
-
- double comm2_range, comm2_effective_range;
- bool comm2_valid;
- bool comm2_atis_valid;
- bool comm2_tower_valid;
- bool comm2_approach_valid;
- const char* comm2_ident;
- const char* comm2_atis_ident;
- const char* comm2_tower_ident;
- const char* comm2_approach_ident;
- const char* last_comm2_ident;
- const char* last_comm2_atis_ident;
- const char* last_comm2_tower_ident;
- const char* last_comm2_approach_ident;
-
+ double comm_x[2], comm_y[2], comm_z[2], comm_lon[2], comm_lat[2], comm_elev[2];
+
+ double comm_range[2], comm_effective_range[2];
+ bool comm_valid[2];
+ const char* comm_ident[2];
+ const char* last_comm_ident[2];
+
const char* approach_ident;
bool last_in_range;
- FGATIS atis;
+ //FGATIS atis;
//FGGround ground;
FGTower tower;
- FGApproach approaches[max_app];
FGApproach approach;
//FGDeparture departure;
// Display a dialog box with options relevant to the currently tuned ATC service.
void doStandardDialog();
- atc_type GetComm1ATCType() { return(comm1_type); }
- FGATC* GetComm1ATCPointer() { return(comm1_atc_ptr); }
- atc_type GetComm2ATCType() { return(comm2_type); }
- FGATC* GetComm2ATCPointer() { return(comm2_atc_ptr); }
+ atc_type GetComm1ATCType() { return(comm_type[0]); }
+ FGATC* GetComm1ATCPointer() { return(comm_atc_ptr[0]); }
+ atc_type GetComm2ATCType() { return(comm_type[1]); }
+ FGATC* GetComm2ATCPointer() { return(comm_atc_ptr[1]); }
private:
// Remove a class from the atc_list and delete it from memory
+ // *if* no other comm channel or AI plane is using it.
+ void CommRemoveFromList(const char* id, atc_type tp, int chan);
+
+ // Remove a class from the atc_list and delete it from memory
+ // Should be called from the above - not directly!!
void RemoveFromList(const char* id, atc_type tp);
- // Return a pointer to a class in the list (external interface to this is through GetATCPointer)
+ // Return a pointer to a class in the list given ICAO code and type
+ // (external interface to this is through GetATCPointer)
+ // Return NULL if the given service is not in the list
+ // - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
FGATC* FindInList(const char* id, atc_type tp);
// Search the specified channel for stations on the same frequency and in range.
- void Search(int chan);
+ void FreqSearch(int channel);
+
+ // Search ATC stations by area in order that we appear 'on the radar'
+ void AreaSearch();
};
atis.hxx atis.cxx atislist.hxx atislist.cxx \
tower.hxx tower.cxx towerlist.hxx towerlist.cxx \
approach.hxx approach.cxx approachlist.hxx approachlist.cxx \
- ground.hxx ground.cxx groundlist.hxx groundlist.cxx \
+ ground.hxx ground.cxx \
+ commlist.hxx commlist.cxx \
ATCdisplay.hxx ATCdisplay.cxx \
ATCVoice.hxx ATCVoice.cxx \
ATCmgr.hxx ATCmgr.cxx \
}
//Constructor
-FGApproach::FGApproach()
-: type(0),
- lon(0.0), lat(0.0), elev(0.0),
- x(0.0), y(0.0), z(0.0),
- freq(0),
+FGApproach::FGApproach() :
bucket(0),
- range(0.0),
active_runway(""),
active_rw_hdg(0.0),
display(false),
displaying(false),
- ident(""),
- name(""),
num_planes(0),
transmission(""),
first(true),
if ( planes[i].contact == 0) {
double comm1_freq = comm1_node->getDoubleValue();
if ( (int)(comm1_freq*100.0 + 0.5) == freq ) planes[i].contact = 1;
+ //cout << "comm1 = " << (int)(comm1_freq*100.0 + 0.5) << " freq = " << freq << '\n';
}
else if ( planes[i].contact == 1 ) {
if ( planes[i].wpn == 0 ) { // calculate initial waypoints
#else
double hdg = stationweather.get_wind_from_heading_deg();
#endif
-
+
FGRunway runway;
+ //if ( runways.search( "EGNX", int(hdg), &runway) ) {
if ( runways.search( ident, int(hdg), &runway) ) {
active_runway = runway.rwy_no;
active_rw_hdg = runway.heading;
class FGApproach : public FGATC {
- char type;
- double lon, lat;
- double elev;
- double x, y, z;
- int freq;
int bucket;
- double range;
-
string active_runway;
double active_rw_hdg;
bool display; // Flag to indicate whether we should be outputting to the display.
bool displaying; // Flag to indicate whether we are outputting to the display.
- string ident; // Code of the airport its at.
- string name; // Name transmitted in the broadcast.
int num_planes; // number of planes on the stack
PlaneApp planes[max_planes]; // Array of planes
string transmission;
//Indicate that this instance should not be outputting to the ATC display
inline void SetNoDisplay(void) {display = false;}
- inline char get_type() const { return type; }
- inline double get_lon() const { return lon; }
- inline double get_lat() const { return lat; }
- inline double get_elev() const { return elev; }
- inline double get_x() const { return x; }
- inline double get_y() const { return y; }
- inline double get_z() const { return z; }
inline double get_bucket() const { return bucket; }
- inline int get_freq() const { return freq; }
- inline double get_range() const { return range; }
inline int get_pnum() const { return num_planes; }
- inline const char* GetIdent() { return ident.c_str(); }
inline string get_trans_ident() { return trans_ident; }
- inline string get_name() { return name; }
inline atc_type GetType() { return APPROACH; }
private:
//Update the transmission string
void UpdateTransmission(void);
-
- friend istream& operator>> ( istream&, FGApproach& );
-};
-
-inline istream&
-operator >> ( istream& in, FGApproach& a )
-{
- double f;
- char ch;
-
- 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;
- }
-
- in >> a.type;
-
- if ( a.type == '[' )
- return in >> skipeol;
-
- in >> a.lat >> a.lon >> a.elev >> f >> a.range
- >> a.ident;
-
- a.name = "";
- in >> ch;
- a.name += ch;
- while(1) {
- //in >> noskipws
- in.unsetf(ios::skipws);
- in >> ch;
- a.name += 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 << "approach.name = " << a.name << '\n';
-
- a.freq = (int)(f*100.0 + 0.5);
-
- // generate cartesian coordinates
- Point3D geod( a.lon * SGD_DEGREES_TO_RADIANS , a.lat * SGD_DEGREES_TO_RADIANS,
- a.elev * SG_FEET_TO_METER );
- Point3D cart = sgGeodToCart( geod );
- a.x = cart.x();
- a.y = cart.y();
- a.z = cart.z();
-
- // get bucket number
- SGBucket buck(a.lon, a.lat);
- a.bucket = buck.gen_index();
-
- a.trans_ident = a.ident;
- a.approach_failed = false;
-
- return in >> skipeol;
-}
+};
#endif // _FG_APPROACH_HXX
+
// load the approach data and build the map
bool FGApproachList::init( SGPath path ) {
-
- approachlist_freq.erase( approachlist_freq.begin(), approachlist_freq.end() );
- approachlist_bck.erase( approachlist_bck.begin(), approachlist_bck.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;
-
- cout << " APPROACH " << endl;
-#ifdef __MWERKS__
- char c = 0;
- while ( in.get(c) && c != '\0' ) {
- in.putback(c);
-#else
- while ( !in.eof() ) {
-#endif
-
- FGApproach a;
- in >> a;
- if ( a.get_type() == '[' ) {
- break;
- }
- //cout << " type = " << a.get_type() << endl;
- //cout << " lon = " << a.get_lon() << endl;
- //cout << " lat = " << a.get_lat() << endl;
- //cout << " elev = " << a.get_elev() << endl;
- //cout << " freq = " << a.get_freq() << endl;
- //cout << " Airport Code = " << a.GetIdent() << endl;
- //cout << " Name = " << a.get_name() << endl;
-
- approachlist_freq[a.get_freq()].push_back(a);
- approachlist_bck[int(a.get_bucket())].push_back(a);
- in >> skipcomment;
-
- }
-
return true;
}
-
-// query the database for the specified frequency, lon and lat are in
-// degrees, elev is in meters
-bool FGApproachList::query_freq( double lon, double lat, double elev, double freq,
- FGApproach *a )
-{
- lon *= SGD_DEGREES_TO_RADIANS;
- lat *= SGD_DEGREES_TO_RADIANS;
-
- approach_list_type stations = approachlist_freq[(int)(freq*100.0 + 0.5)];
-
- approach_list_iterator current = stations.begin();
- approach_list_iterator last = stations.end();
-
- // double az1, az2, s;
- Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) );
- Point3D station;
- double d;
- for ( ; current != last ; ++current ) {
- //cout << "testing " << current->GetIdent() << endl;
- station = Point3D(current->get_x(), current->get_y(), current->get_z());
- //cout << "aircraft = " << aircraft << endl;
- //cout << "station = " << station << endl;
-
- d = aircraft.distance3Dsquared( station );
-
- //cout << " dist = " << sqrt(d)
- // << " range = " << current->get_range() * SG_NM_TO_METER << endl;
- //cout << " Aircraft: lon = " << lon << " lat = " << lat
- // << " elev = " << elev << endl;
- //cout << " Airport: lon = " << current->get_lon()
- // << " lat = " << current->get_lat()
- // << " elev = " << current->get_elev()
- // << " z = " << current->get_z() << endl;
-
- // match up to twice the published range so we can model
- // reduced signal strength
- if ( d < (2 * current->get_range() * SG_NM_TO_METER
- * 2 * current->get_range() * SG_NM_TO_METER ) ) {
- //cout << "matched = " << current->GetIdent() << endl;
- *a = *current;
- return true;
- }
- }
- return false;
-}
-
-// query the database for the specified frequency, lon and lat are in
-// degrees, elev is in meters
-bool FGApproachList::query_bck( double lon, double lat, double elev, FGApproach *a,
- int max_app, int &num_app)
-{
-
- // get bucket number for plane position
- SGBucket buck(lon, lat);
-
- //cout << "plane bucket" << bucket << endl;
-
- // get neigboring buckets
- double max_range = 100;
- int bx = int ( max_range*SG_NM_TO_METER / buck.get_width_m() / 2);
- int by = int ( max_range*SG_NM_TO_METER / buck.get_height_m() / 2 );
-
- // loop over bucket range
- for ( int i=-bx; i<bx; i++) {
- for ( int j=-by; j<by; j++) {
- buck = sgBucketOffset(lon, lat, i, j);
- long int bucket = buck.gen_index();
- //cout << "bucket number = " << bucket << endl;
- approach_list_type stations = approachlist_bck[bucket];
- approach_list_iterator current = stations.begin();
- approach_list_iterator last = stations.end();
-
- double rlon = lon * SGD_DEGREES_TO_RADIANS;
- double rlat = lat * SGD_DEGREES_TO_RADIANS;
-
- // double az1, az2, s;
- Point3D aircraft = sgGeodToCart( Point3D(rlon, rlat, elev) );
- Point3D station;
- double d;
- for ( ; current != last ; ++current ) {
- station = Point3D(current->get_x(), current->get_y(), current->get_z());
- d = aircraft.distance3Dsquared( station );
- /*
- cout << " dist = " << sqrt(d)
- << " range = " << current->get_range() * SG_NM_TO_METER << endl;
- cout << " Aircraft: lon = " << lon
- << " lat = " << lat/SGD_DEGREES_TO_RADIANS
- << " bucket = " << bucket
- << " elev = " << elev << endl;
- cout << " Airport: Id = " << current->GetIdent()
- << " lon = " << current->get_lon()
- << " lat = " << current->get_lat()
- << " elev = " << current->get_elev()
- << " bucket = " << current->get_bucket()
- << " z = " << current->get_z() << endl;
- */
- // match up to twice the published range so we can model
- // reduced signal strength
- if ( d < (current->get_range() * SG_NM_TO_METER
- * current->get_range() * SG_NM_TO_METER ) ) {
- //cout << "matched = " << current->GetIdent() << endl;
- if (num_app < max_app) {
- a[num_app] = *current;
- num_app += 1;
- }
- else {
- cout << "Approachlist error: Too many stations in range" << endl;
- }
-
- //return true;
- }
- }
- }
- }
- return true; //DCL - added this to prevent a compiler warning
-}
-
-
-bool FGApproachList::get_name( string apt_id )
-{
- string name;
- double freq = 125.22;
-
- approach_list_type stations = approachlist_freq[(int)(freq*100.0 + 0.5)];
-
- approach_list_iterator current = stations.begin();
- approach_list_iterator last = stations.end();
-
- if(current != last) {
- cout << "ApproachList" << endl;
- cout << "name" << current->get_name() << endl;
- cout << "bucket" << current->get_bucket() << endl;
- }
-
- return 0;
-
-}
// load the approach data and build the map
bool init( SGPath path );
-
- // query the database for the specified frequency, lon and lat are
- // in degrees, elev is in meters
- bool query_freq( double lon, double lat, double elev, double freq, FGApproach *a );
-
- // query the database for the specified bucket number, lon and lat are
- // in degrees
- bool query_bck( double lon, double lat, double elev, FGApproach *a, int max_app, int &num_app );
-
- bool get_name( string apt_id );
};
#include <Airports/runways.hxx>
#include "atis.hxx"
-#include "atislist.hxx"
+#include "commlist.hxx"
+//#include "atislist.hxx"
#include "ATCdisplay.hxx"
#include "ATCutils.hxx"
#include "ATCmgr.hxx"
// Constructor
-FGATIS::FGATIS()
-: type(0),
-lon(0.0), lat(0.0),
-elev(0.0),
-x(0.0), y(0.0), z(0.0),
-freq(0),
-range(0),
+FGATIS::FGATIS() :
display(false),
displaying(false),
-ident(""),
-name(""),
transmission(""),
trans_ident(""),
atis_failed(false),
refname("atis")
+//type(ATIS)
{
}
hours = atoi((time_str.substr(1,2)).c_str()); //Warning - this is fragile if the
//time string format changes
//cout << "In atis.cxx, hours = " << hours << endl;
- phonetic_id = current_atislist->GetCallSign(ident, hours, 0);
+ phonetic_id = current_commlist->GetCallSign(ident, hours, 0);
phonetic_id_string = GetPhoneticIdent(phonetic_id);
transmission += " ";
transmission += phonetic_id_string;
//DCL - a complete guess for now.
#define FG_ATIS_DEFAULT_RANGE 30
-
+
class FGATIS : public FGATC {
- char type;
- double lon, lat, elev;
- double x, y, z;
- int freq;
- int range;
+ //atc_type type;
bool display; // Flag to indicate whether we should be outputting to the ATC display.
bool displaying; // Flag to indicate whether we are outputting to the ATC display.
- string ident; // Code of the airport its at.
- string name; // Name transmitted in the broadcast.
string transmission; // The actual ATIS transmission
// This is not stored in default.atis but is generated
// from the prevailing conditions when required.
//Indicate that this instance should not be outputting to the ATC display
inline void SetNoDisplay(void) {display = false;}
- inline char get_type() const { return type; }
- inline double get_lon() const { return lon; }
- inline double get_lat() const { return lat; }
- inline double get_elev() const { return elev; }
- inline double get_x() const { return x; }
- inline double get_y() const { return y; }
- inline double get_z() const { return z; }
- inline int get_freq() const { return freq; }
- inline int get_range() const { return range; }
- inline const char* GetIdent() { return ident.c_str(); }
- inline string get_trans_ident() { return trans_ident; }
inline atc_type GetType() { return ATIS; }
+ //inline void set_type(const atc_type tp) {type = tp;}
+ inline string get_trans_ident() { return trans_ident; }
inline void set_refname(string r) { refname = r; }
private:
//Update the transmission string
void UpdateTransmission(void);
- /* inline void set_type( char t ) { type = t; }
- inline void set_lon( double l ) { lon = l; }
- inline void set_lat( double l ) { lat = l; }
- inline void set_elev( double e ) { elev = e; }
- inline void set_freq( int f ) { freq = f; }
- inline void set_range( int r ) { range = r; }
- inline void set_dme( bool b ) { dme = b; }
- inline void set_ident( char *i ) { strncpy( ident, i, 5 ); } */
-
friend istream& operator>> ( istream&, FGATIS& );
};
-
-inline istream&
-operator >> ( istream& in, FGATIS& a )
-{
- double f;
- char ch;
-
- 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;
- }
-
- in >> a.type;
-
- if ( a.type == '[' )
- return in >> skipeol;
-
- in >> a.lat >> a.lon >> a.elev >> f >> a.range
- >> a.ident;
-
- a.name = "";
- in >> ch;
- a.name += ch;
- while(1) {
- //in >> noskipws
- in.unsetf(ios::skipws);
- in >> ch;
- a.name += 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 << "atis.name = " << a.name << '\n';
-
- a.freq = (int)(f*100.0 + 0.5);
-
- // cout << a.ident << endl;
-
- // generate cartesian coordinates
- Point3D geod( a.lon * SGD_DEGREES_TO_RADIANS, a.lat * SGD_DEGREES_TO_RADIANS, a.elev );
- Point3D cart = sgGeodToCart( geod );
- a.x = cart.x();
- a.y = cart.y();
- a.z = cart.z();
-
- a.trans_ident = a.ident;
- a.atis_failed = false;
-
- return in >> skipeol;
-}
-
#endif // _FG_ATIS_HXX
# include <config.h>
#endif
-#include <simgear/debug/logstream.hxx>
-#include <simgear/misc/sgstream.hxx>
-#include <simgear/math/sg_geodesy.hxx>
-#include <simgear/math/sg_random.h>
-
#include "atislist.hxx"
// load the navaids and build the map
bool FGATISList::init( SGPath path ) {
-
- atislist.erase( atislist.begin(), atislist.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 >> skipcomment;
-
-#ifdef __MWERKS__
- char c = 0;
- while ( in.get(c) && c != '\0' ) {
- in.putback(c);
-#else
- while ( !in.eof() ) {
-#endif
-
- FGATIS a;
- in >> a;
- if ( a.get_type() == '[' ) {
- break;
- }
-
- /* cout << "id = " << a.GetIdent() << endl;
- cout << " type = " << a.get_type() << endl;
- cout << " lon = " << a.get_lon() << endl;
- cout << " lat = " << a.get_lat() << endl;
- cout << " elev = " << a.get_elev() << endl;
- cout << " freq = " << a.get_freq() << endl;
- cout << " range = " << a.get_range() << endl << endl; */
-
- atislist[a.get_freq()].push_back(a);
- in >> skipcomment;
-
- }
-
return true;
}
-
-// query the database for the specified frequency, lon and lat are in
-// degrees, elev is in meters
-bool FGATISList::query( double lon, double lat, double elev, double freq,
- FGATIS *a )
-{
- lon *= SGD_DEGREES_TO_RADIANS;
- lat *= SGD_DEGREES_TO_RADIANS;
-
- atis_list_type stations = atislist[(int)(freq*100.0 + 0.5)];
-
- atis_list_iterator current = stations.begin();
- atis_list_iterator last = stations.end();
-
- // double az1, az2, s;
- Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) );
- Point3D station;
- double d;
- for ( ; current != last ; ++current ) {
- //cout << "testing " << current->get_ident() << endl;
- station = Point3D(current->get_x(), current->get_y(), current->get_z());
- //cout << "aircraft = " << aircraft << endl;
- //cout << "station = " << station << endl;
-
- d = aircraft.distance3Dsquared( station );
-
- //cout << " dist = " << sqrt(d)
- // << " range = " << current->get_range() * SG_NM_TO_METER << endl;
-
- // match up to twice the published range so we can model
- // reduced signal strength
- if ( d < (2 * current->get_range() * SG_NM_TO_METER
- * 2 * current->get_range() * SG_NM_TO_METER ) ) {
- //cout << "matched = " << current->get_ident() << endl;
- *a = *current;
- return true;
- }
- }
-
- return false;
-}
-
-
-int FGATISList::GetCallSign( string apt_id, int hours, int mins )
-{
- atis_transmission_type tran;
-
- if(atislog.find(apt_id) == atislog.end()) {
- // This station has not transmitted yet - return a random identifier
- // and add the transmission to the log
- tran.hours = hours;
- tran.mins = mins;
- sg_srandom_time();
- tran.callsign = int(sg_random() * 25) + 1; // This *should* give a random int between 1 and 26
- //atislog[apt_id].push_back(tran);
- atislog[apt_id] = tran;
- } else {
- // This station has transmitted - calculate the appropriate identifier
- // and add the transmission to the log if it has changed
- tran = atislog[apt_id];
- // This next bit assumes that no-one comes back to the same ATIS station
- // after running FlightGear for more than 24 hours !!
- if((tran.hours == hours) && (tran.mins == mins)) {
- return(tran.callsign);
- } else {
- if(tran.hours == hours) {
- // The minutes must have changed
- tran.mins = mins;
- tran.callsign++;
- } else {
- if(hours < tran.hours) {
- hours += 24;
- }
- tran.callsign += (hours - tran.hours);
- if(mins != 0) {
- // Assume transmissions were made on every hour
- tran.callsign++;
- }
- tran.hours = hours;
- tran.mins = mins;
- }
- // Wrap if we've exceeded Zulu
- if(tran.callsign > 26) {
- tran.callsign -= 26;
- }
- // And write the new transmission to the log
- atislog[apt_id] = tran;
- }
- }
- return(tran.callsign);
-}
atis_map_type atislist;
- // Add structure and map for storing a log of atis transmissions
- // made in this session of FlightGear. This allows the callsign
- // to be allocated correctly wrt time.
- typedef struct {
- int hours;
- int mins;
- int callsign;
- } atis_transmission_type;
-
- typedef map < string, atis_transmission_type > atis_log_type;
- typedef atis_log_type::iterator atis_log_iterator;
- typedef atis_log_type::const_iterator atis_log_const_iterator;
-
- atis_log_type atislog;
-
public:
FGATISList();
// load all atis and build the map
bool init( SGPath path );
-
- // query the database for the specified frequency, lon and lat are
- // in degrees, elev is in meters
- bool query( double lon, double lat, double elev, double freq, FGATIS *a );
-
- // Return the callsign for a transmission given transmission time and airpord id
- int GetCallSign( string apt_id, int hours, int mins );
};
--- /dev/null
+// commlist.cxx -- comm frequency lookup class
+//
+// Written by David Luff and Alexander Kappes, started Jan 2003.
+// Based on navlist.cxx by Curtis Olson, started April 2000.
+//
+// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
+//
+// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/bucket/newbucket.hxx>
+
+#include "commlist.hxx"
+//#include "atislist.hxx"
+
+
+FGCommList *current_commlist;
+
+
+// Constructor
+FGCommList::FGCommList( void ) {
+}
+
+
+// Destructor
+FGCommList::~FGCommList( void ) {
+}
+
+
+// load the navaids and build the map
+bool FGCommList::init( SGPath path ) {
+
+ SGPath temp = path;
+ commlist_freq.erase(commlist_freq.begin(), commlist_freq.end());
+ commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
+ temp.append( "ATC/default.atis" );
+ LoadComms(temp);
+ temp = path;
+ temp.append( "ATC/default.tower" );
+ LoadComms(temp);
+ temp = path;
+ temp.append( "ATC/default.approach" );
+ LoadComms(temp);
+ return true;
+}
+
+
+bool FGCommList::LoadComms(SGPath path) {
+
+ sg_gzifstream fin( path.str() );
+ if ( !fin.is_open() ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
+ exit(-1);
+ }
+
+ // read in each line of the file
+ fin >> skipcomment;
+
+#ifdef __MWERKS__
+ char c = 0;
+ while ( fin.get(c) && c != '\0' ) {
+ fin.putback(c);
+#else
+ while ( !fin.eof() ) {
+#endif
+ ATCData a;
+ fin >> a;
+ if(a.type == INVALID) {
+ break;
+ }
+
+ // Push all stations onto frequency map
+ commlist_freq[a.freq].push_back(a);
+
+ // Push approach stations onto bucket map as well
+ if(a.type == APPROACH) {
+ // get bucket number
+ SGBucket bucket(a.lon, a.lat);
+ int bucknum = bucket.gen_index();
+ commlist_bck[bucknum].push_back(a);
+ }
+
+ fin >> skipcomment;
+ }
+ return true;
+}
+
+
+// query the database for the specified frequency, lon and lat are in
+// degrees, elev is in meters
+// If no atc_type is specified, it returns true if any non-invalid type is found
+// If atc_type is specifed, returns true only if the specified type is found
+bool FGCommList::FindByFreq( double lon, double lat, double elev, double freq,
+ ATCData* ad, atc_type tp )
+{
+ lon *= SGD_DEGREES_TO_RADIANS;
+ lat *= SGD_DEGREES_TO_RADIANS;
+
+ comm_list_type stations = commlist_freq[(int)(freq*100.0 + 0.5)];
+ comm_list_iterator current = stations.begin();
+ comm_list_iterator last = stations.end();
+
+ // double az1, az2, s;
+ Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) );
+ Point3D station;
+ double d;
+ // TODO - at the moment this loop returns the first match found in range
+ // We want to return the closest match in the event of a frequency conflict
+ for ( ; current != last ; ++current ) {
+ //cout << "testing " << current->get_ident() << endl;
+ station = Point3D(current->x, current->y, current->z);
+ //cout << "aircraft = " << aircraft << endl;
+ //cout << "station = " << station << endl;
+
+ d = aircraft.distance3Dsquared( station );
+
+ //cout << " dist = " << sqrt(d)
+ // << " range = " << current->get_range() * SG_NM_TO_METER << endl;
+
+ // match up to twice the published range so we can model
+ // reduced signal strength
+ if ( d < (2 * current->range * SG_NM_TO_METER
+ * 2 * current->range * SG_NM_TO_METER ) ) {
+ //cout << "matched = " << current->get_ident() << endl;
+ if((tp == INVALID) || (tp == (*current).type)) {
+ *ad = *current;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+int FGCommList::FindByPos(double lon, double lat, double elev, comm_list_type* stations, atc_type tp)
+{
+ // number of relevant stations found within range
+ int found = 0;
+ stations->erase(stations->begin(), stations->end());
+
+ // get bucket number for plane position
+ SGBucket buck(lon, lat);
+
+ // get neigboring buckets
+ int max_range = 100;
+ int bx = (int)( max_range*SG_NM_TO_METER / buck.get_width_m() / 2);
+ int by = (int)( max_range*SG_NM_TO_METER / buck.get_height_m() / 2 );
+
+ // loop over bucket range
+ for ( int i=-bx; i<bx; i++) {
+ for ( int j=-by; j<by; j++) {
+ buck = sgBucketOffset(lon, lat, i, j);
+ long int bucket = buck.gen_index();
+ comm_list_type Fstations = commlist_bck[bucket];
+ comm_list_iterator current = Fstations.begin();
+ comm_list_iterator last = Fstations.end();
+
+ double rlon = lon * SGD_DEGREES_TO_RADIANS;
+ double rlat = lat * SGD_DEGREES_TO_RADIANS;
+
+ // double az1, az2, s;
+ Point3D aircraft = sgGeodToCart( Point3D(rlon, rlat, elev) );
+ Point3D station;
+ double d;
+ for(; current != last; ++current) {
+ if((current->type == tp) || (tp == INVALID)) {
+ station = Point3D(current->x, current->y, current->z);
+ d = aircraft.distance3Dsquared( station );
+ if ( d < (current->range * SG_NM_TO_METER
+ * current->range * SG_NM_TO_METER ) ) {
+ stations->push_back(*current);
+ ++found;
+ }
+ }
+ }
+ }
+ }
+ return found;
+}
+
+
+// TODO - this function should move somewhere else eventually!
+// Return an appropriate call-sign for an ATIS transmission.
+int FGCommList::GetCallSign( string apt_id, int hours, int mins )
+{
+ atis_transmission_type tran;
+
+ if(atislog.find(apt_id) == atislog.end()) {
+ // This station has not transmitted yet - return a random identifier
+ // and add the transmission to the log
+ tran.hours = hours;
+ tran.mins = mins;
+ sg_srandom_time();
+ tran.callsign = int(sg_random() * 25) + 1; // This *should* give a random int between 1 and 26
+ //atislog[apt_id].push_back(tran);
+ atislog[apt_id] = tran;
+ } else {
+ // This station has transmitted - calculate the appropriate identifier
+ // and add the transmission to the log if it has changed
+ tran = atislog[apt_id];
+ // This next bit assumes that no-one comes back to the same ATIS station
+ // after running FlightGear for more than 24 hours !!
+ if((tran.hours == hours) && (tran.mins == mins)) {
+ return(tran.callsign);
+ } else {
+ if(tran.hours == hours) {
+ // The minutes must have changed
+ tran.mins = mins;
+ tran.callsign++;
+ } else {
+ if(hours < tran.hours) {
+ hours += 24;
+ }
+ tran.callsign += (hours - tran.hours);
+ if(mins != 0) {
+ // Assume transmissions were made on every hour
+ tran.callsign++;
+ }
+ tran.hours = hours;
+ tran.mins = mins;
+ }
+ // Wrap if we've exceeded Zulu
+ if(tran.callsign > 26) {
+ tran.callsign -= 26;
+ }
+ // And write the new transmission to the log
+ atislog[apt_id] = tran;
+ }
+ }
+ return(tran.callsign);
+}
--- /dev/null
+// commlist.hxx -- comm frequency lookup class
+//
+// Written by David Luff and Alexander Kappes, started Jan 2003.
+// Based on navlist.hxx by Curtis Olson, started April 2000.
+//
+// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org
+//
+// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+/*****************************************************************
+*
+* FGCommList is used to store communication frequency information
+* for the ATC and AI subsystems. Two maps are maintained - one
+* searchable by location and one searchable by frequency. The
+* data structure returned from the search is the ATCData struct
+* defined in ATC.hxx, containing location, frequency, name, range
+* and type of the returned station.
+*
+******************************************************************/
+
+#ifndef _FG_COMMLIST_HXX
+#define _FG_COMMLIST_HXX
+
+
+#include <simgear/compiler.h>
+#include <simgear/misc/sg_path.hxx>
+
+#include <map>
+#include <list>
+#include <string>
+
+#include "ATC.hxx"
+#include "atis.hxx"
+
+SG_USING_STD(map);
+SG_USING_STD(vector);
+SG_USING_STD(string);
+
+// A list of ATC stations
+typedef list < ATCData > comm_list_type;
+typedef comm_list_type::iterator comm_list_iterator;
+typedef comm_list_type::const_iterator comm_list_const_iterator;
+
+// A map of ATC station lists
+typedef map < int, comm_list_type > comm_map_type;
+typedef comm_map_type::iterator comm_map_iterator;
+typedef comm_map_type::const_iterator comm_map_const_iterator;
+
+
+class FGCommList {
+
+public:
+
+ FGCommList();
+ ~FGCommList();
+
+ // load all comm frequencies and build the map
+ bool init( SGPath path );
+
+ // query the database for the specified frequency, lon and lat are
+ // in degrees, elev is in meters
+ // If no atc_type is specified, it returns true if any non-invalid type is found
+ // If atc_type is specifed, returns true only if the specified type is found
+ // The data found is written into the passed-in ATCData structure.
+ bool FindByFreq( double lon, double lat, double elev, double freq, ATCData* ad, atc_type tp = INVALID );
+
+ // query the database by location, lon and lat are
+ // in degrees, elev is in meters
+ // Returns the number of stations of the specified type that are in range, and pushes them into stations
+ // If atc_type is specifed, returns the number of all stations in range, and pushes them into stations
+ // ** stations is erased before use **
+ int FindByPos( double lon, double lat, double elev, comm_list_type* stations, atc_type tp = INVALID );
+
+ // Return the callsign for an ATIS transmission given transmission time and airpord id
+ // This maybe should get moved somewhere else!!
+ int GetCallSign( string apt_id, int hours, int mins );
+
+private:
+
+ // Comm stations mapped by frequency
+ comm_map_type commlist_freq;
+
+ // Comm stations mapped by bucket
+ comm_map_type commlist_bck;
+
+ // Load comms from a specified path (which must include the filename)
+ bool LoadComms(SGPath path);
+
+//----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else
+ // Add structure and map for storing a log of atis transmissions
+ // made in this session of FlightGear. This allows the callsign
+ // to be allocated correctly wrt time.
+ typedef struct {
+ int hours;
+ int mins;
+ int callsign;
+ } atis_transmission_type;
+
+ typedef map < string, atis_transmission_type > atis_log_type;
+ typedef atis_log_type::iterator atis_log_iterator;
+ typedef atis_log_type::const_iterator atis_log_const_iterator;
+
+ atis_log_type atislog;
+//-----------------------------------------------------------------------------------------------
+
+};
+
+
+extern FGCommList *current_commlist;
+
+
+#endif // _FG_COMMLIST_HXX
inline void SetDisplay() {display = true;}
inline void SetNoDisplay() {display = false;}
- inline char get_type() const { return type; }
- inline double get_lon() const { return lon; }
- inline double get_lat() const { return lat; }
- inline double get_elev() const { return elev; }
- inline double get_x() const { return x; }
- inline double get_y() const { return y; }
- inline double get_z() const { return z; }
- inline int get_freq() const { return freq; }
- inline int get_range() const { return range; }
- inline const char* GetIdent() { return ident.c_str(); }
inline string get_trans_ident() { return trans_ident; }
- inline string get_name() { return name; }
inline atc_type GetType() { return TOWER; }
// Make a request of tower control
void IssueGoAround(TowerPlaneRec* tpr);
void IssueDepartureClearance(TowerPlaneRec* tpr);
- char type;
- double lon, lat;
- double elev;
- double x, y, z;
- int freq;
- int range;
bool display; // Flag to indicate whether we should be outputting to the ATC display.
bool displaying; // Flag to indicate whether we are outputting to the ATC display.
- string ident; // Code of the airport its at.
- string name; // Name generally used in transmissions.
-
// Need a data structure to hold details of the various active planes
// or possibly another data structure with the positions of the inactive planes.
friend istream& operator>> ( istream&, FGTower& );
};
-
-inline istream&
-operator >> ( istream& in, FGTower& t )
-{
- double f;
- char ch;
-
- in >> t.type;
-
- if ( t.type == '[' )
- return in >> skipeol;
-
- in >> t.lat >> t.lon >> t.elev >> f >> t.range
- >> t.ident;
-
- t.name = "";
- in >> ch;
- t.name += ch;
- while(1) {
- //in >> noskipws
- in.unsetf(ios::skipws);
- in >> ch;
- t.name += 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 << "tower.name = " << t.name << '\n';
-
- t.freq = (int)(f*100.0 + 0.5);
-
- // cout << t.ident << endl;
-
- // generate cartesian coordinates
- Point3D geod( t.lon * SGD_DEGREES_TO_RADIANS, t.lat * SGD_DEGREES_TO_RADIANS, t.elev );
- Point3D cart = sgGeodToCart( geod );
- t.x = cart.x();
- t.y = cart.y();
- t.z = cart.z();
-
- t.trans_ident = t.ident;
- t.tower_failed = false;
-
- return in >> skipeol;
-}
-
-
#endif //_FG_TOWER_HXX
// load the navaids and build the map
bool FGTowerList::init( SGPath path ) {
-
- towerlist.erase( towerlist.begin(), towerlist.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 >> skipcomment;
-
-#ifdef __MWERKS__
- char c = 0;
- while ( in.get(c) && c != '\0' ) {
- in.putback(c);
-#else
- while ( !in.eof() ) {
-#endif
-
- FGTower t;
- in >> t;
- if ( t.get_type() == '[' ) {
- break;
- }
-
- //cout << "id = " << t.GetIdent() << endl;
- //cout << " type = " << t.get_type() << endl;
- //cout << " lon = " << t.get_lon() << endl;
- //cout << " lat = " << t.get_lat() << endl;
- //cout << " elev = " << t.get_elev() << endl;
- //cout << " freq = " << t.get_freq() << endl;
- //cout << " range = " << t.get_range() << endl;
-
- towerlist[t.get_freq()].push_back(t);
- in >> skipcomment;
- }
-
return true;
}
-
-// query the database for the specified frequency, lon and lat are in
-// degrees, elev is in meters
-bool FGTowerList::query( double lon, double lat, double elev, double freq,
- FGTower *t )
-{
- lon *= SGD_DEGREES_TO_RADIANS;
- lat *= SGD_DEGREES_TO_RADIANS;
- //cout << "lon = " << lon << '\n';
- //cout << "lat = " << lat << '\n';
- //cout << "elev = " << elev << '\n';
- //cout << "freq = " << freq << '\n';
-
- tower_list_type stations = towerlist[(int)(freq*100.0 + 0.5)];
-
- tower_list_iterator current = stations.begin();
- tower_list_iterator last = stations.end();
-
- // double az1, az2, s;
- Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) );
- Point3D station;
- double d;
- for ( ; current != last ; ++current ) {
- //cout << "testing " << current->GetIdent() << endl;
- station = Point3D(current->get_x(), current->get_y(), current->get_z());
- //cout << "aircraft = " << aircraft << endl;
- //cout << "station = " << station << endl;
-
- d = aircraft.distance3Dsquared( station );
-
- //cout << " dist = " << sqrt(d)
- // << " range = " << current->get_range() * SG_NM_TO_METER << endl;
-
- // match up to twice the published range so we can model
- // reduced signal strength
- if ( d < (2 * current->get_range() * SG_NM_TO_METER
- * 2 * current->get_range() * SG_NM_TO_METER ) ) {
- //cout << "matched = " << current->GetIdent() << endl;
- *t = *current;
- return true;
- }
- }
-
- return false;
-}
// load all atis and build the map
bool init( SGPath path );
- // query the database for the specified frequency, lon and lat are
- // in degrees, elev is in meters
- bool query( double lon, double lat, double elev, double freq, FGTower *t );
-
};