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
This commit is contained in:
parent
9864453259
commit
9b7405304d
18 changed files with 737 additions and 1097 deletions
|
@ -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):
|
||||
|
|
117
src/ATC/ATC.hxx
117
src/ATC/ATC.hxx
|
@ -23,12 +23,16 @@
|
|||
#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.
|
||||
|
@ -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
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
#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"
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
//cout << "not picking up atis" << endl;
|
||||
}
|
||||
|
||||
//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();
|
||||
FGTower* t = new FGTower;
|
||||
*t = tower;
|
||||
comm1_atc_ptr = 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 = "";
|
||||
}
|
||||
//cout << "not picking up ground control" << endl;
|
||||
}
|
||||
*/
|
||||
// ================================================================================
|
||||
// Search for Approach stations
|
||||
// ================================================================================
|
||||
// init number of approach stations reachable by plane
|
||||
int num_app = 0;
|
||||
|
||||
// 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 ( 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");
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
// 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;
|
||||
|
||||
// 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->SetData(&data);
|
||||
comm_atc_ptr[chan] = t;
|
||||
t->SetDisplay();
|
||||
atc_list.push_back(t);
|
||||
}
|
||||
} /*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);
|
||||
}
|
||||
// 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 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;
|
||||
|
||||
for(app_itr = approaches.begin(); app_itr != approaches.end(); app_itr++) {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 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];
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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; 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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -50,27 +50,21 @@ SG_USING_STD(cout);
|
|||
#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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -24,11 +24,6 @@
|
|||
# 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"
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
};
|
||||
|
||||
|
||||
|
|
252
src/ATC/commlist.cxx
Normal file
252
src/ATC/commlist.cxx
Normal file
|
@ -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 <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);
|
||||
}
|
124
src/ATC/commlist.hxx
Normal file
124
src/ATC/commlist.hxx
Normal file
|
@ -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 <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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue