From: daveluff Date: Thu, 6 Feb 2003 10:42:43 +0000 (+0000) Subject: Major re-work of the comm frequency storage and lookup. Only a small core amount... X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=9b7405304d48c050849bbf45f6088a558916a43b;p=flightgear.git Major re-work of the comm frequency storage and lookup. Only a small core amount of data is now stored instead of the whole ATC classes. All the comm frequency types are now stored in one map instead of a map each. query(...) and query_bck(...) have been renamed to FindByFreq(...) and FindByPos(...) for clarity and consistency with NavList --- diff --git a/src/ATC/ATC.cxx b/src/ATC/ATC.cxx index 86055ff99..24c0c0d60 100644 --- a/src/ATC/ATC.cxx +++ b/src/ATC/ATC.cxx @@ -1,5 +1,4 @@ -// 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. // @@ -40,14 +39,23 @@ void FGATC::SetDisplay() { 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): diff --git a/src/ATC/ATC.hxx b/src/ATC/ATC.hxx index 143b3080a..1babf06f7 100644 --- a/src/ATC/ATC.hxx +++ b/src/ATC/ATC.hxx @@ -23,12 +23,16 @@ #define _FG_ATC_HXX #include +#include +#include +#include #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. @@ -42,6 +46,19 @@ enum atc_type { 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 { @@ -65,11 +82,105 @@ public: // 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 diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index 8e0cb4843..485565e9f 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -25,10 +25,11 @@ #include #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" /* @@ -158,34 +159,16 @@ static bool do_ATC_dialog(const SGPropertyNode* arg) { 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() { @@ -198,8 +181,8 @@ void FGATCMgr::unbind() { } 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); @@ -209,6 +192,11 @@ void FGATCMgr::init() { // 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; @@ -245,6 +233,7 @@ void FGATCMgr::init() { } 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. @@ -253,25 +242,34 @@ void FGATCMgr::update(double dt) { 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 @@ -281,19 +279,23 @@ void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp) { } 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"; @@ -308,19 +310,19 @@ void FGATCMgr::RemoveFromList(const char* id, atc_type tp) { } -//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); } @@ -351,8 +353,9 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) { 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; @@ -396,7 +399,9 @@ void FGATCMgr::Render(string msg, string refname, bool repeating) { 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); @@ -446,7 +451,7 @@ void FGATCMgr::doStandardDialog() { //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."); @@ -480,312 +485,144 @@ void FGATCMgr::doStandardDialog() { // 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; iGetIdent() << 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; } } diff --git a/src/ATC/ATCmgr.hxx b/src/ATC/ATCmgr.hxx index 362804410..3e45af4bd 100644 --- a/src/ATC/ATCmgr.hxx +++ b/src/ATC/ATCmgr.hxx @@ -42,8 +42,6 @@ SG_USING_STD(string); 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. @@ -100,19 +98,15 @@ private: 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; @@ -121,44 +115,19 @@ private: // 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; @@ -202,21 +171,32 @@ public: // 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(); }; diff --git a/src/ATC/Makefile.am b/src/ATC/Makefile.am index 261e24ee7..c176199ce 100644 --- a/src/ATC/Makefile.am +++ b/src/ATC/Makefile.am @@ -5,7 +5,8 @@ libATC_a_SOURCES = \ 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 \ diff --git a/src/ATC/approach.cxx b/src/ATC/approach.cxx index c3b2390fc..273fd82ab 100644 --- a/src/ATC/approach.cxx +++ b/src/ATC/approach.cxx @@ -55,19 +55,12 @@ PlaneApp::PlaneApp() } //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), @@ -106,6 +99,7 @@ void FGApproach::Update() { 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 @@ -256,8 +250,9 @@ void FGApproach::get_active_runway() { #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; diff --git a/src/ATC/approach.hxx b/src/ATC/approach.hxx index 0dfe949ae..a5217abf5 100644 --- a/src/ATC/approach.hxx +++ b/src/ATC/approach.hxx @@ -96,21 +96,12 @@ struct PlaneApp { 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; @@ -146,20 +137,9 @@ public: //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: @@ -198,66 +178,8 @@ 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 + diff --git a/src/ATC/approachlist.cxx b/src/ATC/approachlist.cxx index 4da9521a8..f40cc72f8 100644 --- a/src/ATC/approachlist.cxx +++ b/src/ATC/approachlist.cxx @@ -48,187 +48,6 @@ FGApproachList::~FGApproachList( void ) { // 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; iget_name() << endl; - cout << "bucket" << current->get_bucket() << endl; - } - - return 0; - -} diff --git a/src/ATC/approachlist.hxx b/src/ATC/approachlist.hxx index cc53bd4f4..d84b346e9 100644 --- a/src/ATC/approachlist.hxx +++ b/src/ATC/approachlist.hxx @@ -59,16 +59,6 @@ public: // 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 ); }; diff --git a/src/ATC/atis.cxx b/src/ATC/atis.cxx index 25eba6d10..344a3bc2e 100644 --- a/src/ATC/atis.cxx +++ b/src/ATC/atis.cxx @@ -50,27 +50,21 @@ SG_USING_STD(cout); #include #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) { } @@ -136,7 +130,7 @@ void FGATIS::UpdateTransmission() { 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; diff --git a/src/ATC/atis.hxx b/src/ATC/atis.hxx index e5b785d8f..d74c6ef19 100644 --- a/src/ATC/atis.hxx +++ b/src/ATC/atis.hxx @@ -49,18 +49,12 @@ SG_USING_STD(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. @@ -92,18 +86,9 @@ class FGATIS : public FGATC { //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: @@ -113,71 +98,7 @@ class FGATIS : public FGATC { //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 diff --git a/src/ATC/atislist.cxx b/src/ATC/atislist.cxx index 08e440fec..e713ad15c 100644 --- a/src/ATC/atislist.cxx +++ b/src/ATC/atislist.cxx @@ -24,11 +24,6 @@ # include #endif -#include -#include -#include -#include - #include "atislist.hxx" @@ -47,137 +42,6 @@ FGATISList::~FGATISList( void ) { // 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); -} diff --git a/src/ATC/atislist.hxx b/src/ATC/atislist.hxx index f0f5474a8..3370aaf86 100644 --- a/src/ATC/atislist.hxx +++ b/src/ATC/atislist.hxx @@ -52,21 +52,6 @@ class FGATISList { 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(); @@ -74,13 +59,6 @@ public: // 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 ); }; diff --git a/src/ATC/commlist.cxx b/src/ATC/commlist.cxx new file mode 100644 index 000000000..17990558d --- /dev/null +++ b/src/ATC/commlist.cxx @@ -0,0 +1,252 @@ +// 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 +#endif + +#include +#include +#include +#include +#include + +#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; itype == 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); +} diff --git a/src/ATC/commlist.hxx b/src/ATC/commlist.hxx new file mode 100644 index 000000000..482ad6adf --- /dev/null +++ b/src/ATC/commlist.hxx @@ -0,0 +1,124 @@ +// 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 +#include + +#include +#include +#include + +#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 diff --git a/src/ATC/tower.hxx b/src/ATC/tower.hxx index 1aa78d040..cd4b1e46a 100644 --- a/src/ATC/tower.hxx +++ b/src/ATC/tower.hxx @@ -99,18 +99,7 @@ class FGTower : public FGATC { 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 @@ -122,17 +111,8 @@ class FGTower : public FGATC { 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. @@ -166,52 +146,4 @@ class FGTower : public FGATC { 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 diff --git a/src/ATC/towerlist.cxx b/src/ATC/towerlist.cxx index 1ffba0405..6b262a6e4 100644 --- a/src/ATC/towerlist.cxx +++ b/src/ATC/towerlist.cxx @@ -45,90 +45,6 @@ FGTowerList::~FGTowerList( void ) { // 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; -} diff --git a/src/ATC/towerlist.hxx b/src/ATC/towerlist.hxx index 599f76967..380d124c2 100644 --- a/src/ATC/towerlist.hxx +++ b/src/ATC/towerlist.hxx @@ -61,10 +61,6 @@ public: // 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 ); - };