Lots of changes to the ATC/AI system for initial revision of random AI GA VFR traffic
This commit is contained in:
parent
afb654a068
commit
a739fad664
25 changed files with 1718 additions and 441 deletions
|
@ -40,19 +40,39 @@
|
||||||
|
|
||||||
#include "AIEntity.hxx"
|
#include "AIEntity.hxx"
|
||||||
|
|
||||||
|
FGAIEntity::FGAIEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
FGAIEntity::~FGAIEntity() {
|
FGAIEntity::~FGAIEntity() {
|
||||||
|
//cout << "FGAIEntity dtor called..." << endl;
|
||||||
|
_model->deRef(); // Ought to check valid?
|
||||||
|
//cout << "Removing model from scene graph..." << endl;
|
||||||
|
globals->get_scenery()->get_scene_graph()->removeKid(_aip.getSceneGraph());
|
||||||
|
//cout << "Done!" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEntity::SetModel(ssgBranch* model) {
|
||||||
|
_model = model;
|
||||||
|
_model->ref();
|
||||||
|
_aip.init(_model);
|
||||||
|
_aip.setVisible(false);
|
||||||
|
globals->get_scenery()->get_scene_graph()->addKid(_aip.getSceneGraph());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIEntity::Update(double dt) {
|
void FGAIEntity::Update(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string FGAIEntity::GetCallsign() {
|
||||||
|
return("");
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIEntity::RegisterTransmission(int code) {
|
void FGAIEntity::RegisterTransmission(int code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
//void FGAIEntity::Update() {
|
//void FGAIEntity::Update() {
|
||||||
void FGAIEntity::Transform() {
|
void FGAIEntity::Transform() {
|
||||||
aip.setPosition(pos.lon(), pos.lat(), pos.elev() * SG_METER_TO_FEET);
|
_aip.setPosition(_pos.lon(), _pos.lat(), _pos.elev() * SG_METER_TO_FEET);
|
||||||
aip.setOrientation(roll, pitch, hdg);
|
_aip.setOrientation(_roll, _pitch, _hdg);
|
||||||
aip.update( globals->get_scenery()->get_center() );
|
_aip.update( globals->get_scenery()->get_center() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,11 @@ class FGAIEntity {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
FGAIEntity();
|
||||||
virtual ~FGAIEntity();
|
virtual ~FGAIEntity();
|
||||||
|
|
||||||
|
// Set the 3D model to use (Must be called)
|
||||||
|
void SetModel(ssgBranch* model);
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
virtual void Update(double dt);
|
virtual void Update(double dt);
|
||||||
|
@ -50,17 +54,20 @@ public:
|
||||||
// FIXME int code is a hack - eventually this will receive Alexander's coded messages.
|
// FIXME int code is a hack - eventually this will receive Alexander's coded messages.
|
||||||
virtual void RegisterTransmission(int code);
|
virtual void RegisterTransmission(int code);
|
||||||
|
|
||||||
inline Point3D GetPos() { return(pos); }
|
inline Point3D GetPos() { return(_pos); }
|
||||||
|
|
||||||
|
virtual string GetCallsign();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Point3D pos; // WGS84 lat & lon in degrees, elev above sea-level in meters
|
Point3D _pos; // WGS84 lat & lon in degrees, elev above sea-level in meters
|
||||||
double hdg; //True heading in degrees
|
double _hdg; //True heading in degrees
|
||||||
double roll; //degrees
|
double _roll; //degrees
|
||||||
double pitch; //degrees
|
double _pitch; //degrees
|
||||||
|
|
||||||
char* model_path; //Path to the 3D model
|
char* _model_path; //Path to the 3D model
|
||||||
SGModelPlacement aip;
|
ssgBranch* _model; // Pointer to the model
|
||||||
|
SGModelPlacement _aip;
|
||||||
|
|
||||||
void Transform();
|
void Transform();
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -45,7 +45,8 @@ enum TaxiState {
|
||||||
enum OperatingState {
|
enum OperatingState {
|
||||||
IN_PATTERN,
|
IN_PATTERN,
|
||||||
TAXIING,
|
TAXIING,
|
||||||
PARKED
|
PARKED,
|
||||||
|
EN_ROUTE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StartOfDescent {
|
struct StartOfDescent {
|
||||||
|
@ -58,11 +59,12 @@ class FGAILocalTraffic : public FGAIPlane {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// At the moment we expect the expanded short form callsign - eventually we will just want the reg + type.
|
||||||
FGAILocalTraffic();
|
FGAILocalTraffic();
|
||||||
~FGAILocalTraffic();
|
~FGAILocalTraffic();
|
||||||
|
|
||||||
// Initialise
|
// Initialise
|
||||||
bool Init(string ICAO, OperatingState initialState = PARKED, PatternLeg initialLeg = DOWNWIND);
|
bool Init(const string& callsign, string ICAO, OperatingState initialState = PARKED, PatternLeg initialLeg = DOWNWIND);
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
void Update(double dt);
|
void Update(double dt);
|
||||||
|
@ -94,9 +96,38 @@ protected:
|
||||||
// Attempt to enter the traffic pattern in a reasonably intelligent manner
|
// Attempt to enter the traffic pattern in a reasonably intelligent manner
|
||||||
void EnterTrafficPattern(double dt);
|
void EnterTrafficPattern(double dt);
|
||||||
|
|
||||||
|
// Set up the internal state to be consistent for a downwind entry.
|
||||||
|
void DownwindEntry();
|
||||||
|
|
||||||
|
// Ditto for straight-in
|
||||||
|
void StraightInEntry(bool des = false);
|
||||||
|
|
||||||
// Do what is necessary to land and parkup at home airport
|
// Do what is necessary to land and parkup at home airport
|
||||||
void ReturnToBase(double dt);
|
void ReturnToBase(double dt);
|
||||||
|
|
||||||
|
// Airport/runway/pattern details
|
||||||
|
string airportID; // The ICAO code of the airport that we're operating around
|
||||||
|
double aptElev; // Airport elevation
|
||||||
|
FGGround* ground; // A pointer to the ground control.
|
||||||
|
FGTower* tower; // A pointer to the tower control.
|
||||||
|
bool _controlled; // Set true if we find tower control working for the airport, false otherwise.
|
||||||
|
RunwayDetails rwy;
|
||||||
|
double patternDirection; // 1 for right, -1 for left (This is double because we multiply/divide turn rates
|
||||||
|
// with it to get RH/LH turns - DON'T convert it to int under ANY circumstances!!
|
||||||
|
double glideAngle; // Assumed to be visual glidepath angle for FGAILocalTraffic - can be found at www.airnav.com
|
||||||
|
// Its conceivable that patternDirection and glidePath could be moved into the RunwayDetails structure.
|
||||||
|
|
||||||
|
// Its possible that this might be moved out to the ground/airport class at some point.
|
||||||
|
FGATCAlignedProjection ortho; // Orthogonal mapping of the local area with the threshold at the origin
|
||||||
|
// and the runway aligned with the y axis.
|
||||||
|
|
||||||
|
void GetAirportDetails(string id);
|
||||||
|
|
||||||
|
void GetRwyDetails(string id);
|
||||||
|
|
||||||
|
double responseCounter; // timer in seconds to allow response to requests to be a little while after them
|
||||||
|
// Will almost certainly get moved to FGAIPlane.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FGATCMgr* ATC;
|
FGATCMgr* ATC;
|
||||||
// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!
|
// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!
|
||||||
|
@ -105,21 +136,7 @@ private:
|
||||||
OperatingState operatingState;
|
OperatingState operatingState;
|
||||||
int circuitsToFly; //Number of circuits still to do in this session NOT INCLUDING THE CURRENT ONE
|
int circuitsToFly; //Number of circuits still to do in this session NOT INCLUDING THE CURRENT ONE
|
||||||
bool touchAndGo; //True if circuits should be flown touch and go, false for full stop
|
bool touchAndGo; //True if circuits should be flown touch and go, false for full stop
|
||||||
|
bool transmitted; // Set true when a position report for the current leg has been transmitted.
|
||||||
// Its possible that this might be moved out to the ground/airport class at some point.
|
|
||||||
FGATCAlignedProjection ortho; // Orthogonal mapping of the local area with the threshold at the origin
|
|
||||||
// and the runway aligned with the y axis.
|
|
||||||
|
|
||||||
// Airport/runway/pattern details
|
|
||||||
string airportID; // The ICAO code of the airport that we're operating around
|
|
||||||
double aptElev; // Airport elevation
|
|
||||||
FGGround* ground; // A pointer to the ground control.
|
|
||||||
FGTower* tower; // A pointer to the tower control.
|
|
||||||
RunwayDetails rwy;
|
|
||||||
double patternDirection; // 1 for right, -1 for left (This is double because we multiply/divide turn rates
|
|
||||||
// with it to get RH/LH turns - DON'T convert it to int under ANY circumstances!!
|
|
||||||
double glideAngle; // Assumed to be visual glidepath angle for FGAILocalTraffic - can be found at www.airnav.com
|
|
||||||
// Its conceivable that patternDirection and glidePath could be moved into the RunwayDetails structure.
|
|
||||||
|
|
||||||
// Performance characteristics of the plane in knots and ft/min - some of this might get moved out into FGAIPlane
|
// Performance characteristics of the plane in knots and ft/min - some of this might get moved out into FGAIPlane
|
||||||
double Vr;
|
double Vr;
|
||||||
|
@ -175,14 +192,19 @@ private:
|
||||||
bool reportReadyForDeparture; // set true when ATC has requested that the plane report when ready for departure
|
bool reportReadyForDeparture; // set true when ATC has requested that the plane report when ready for departure
|
||||||
bool clearedToLineUp;
|
bool clearedToLineUp;
|
||||||
bool clearedToTakeOff;
|
bool clearedToTakeOff;
|
||||||
|
bool _clearedToLand; // also implies cleared for the option.
|
||||||
bool liningUp; // Set true when the turn onto the runway heading is commenced when taxiing out
|
bool liningUp; // Set true when the turn onto the runway heading is commenced when taxiing out
|
||||||
bool goAround; // Set true if need to go-around
|
bool goAround; // Set true if need to go-around
|
||||||
bool goAroundCalled; // Set true during go-around only after we have called our go-around on the radio
|
bool goAroundCalled; // Set true during go-around only after we have called our go-around on the radio
|
||||||
bool contactTower; // we have been told to contact tower
|
bool contactTower; // we have been told to contact tower
|
||||||
bool contactGround; // we have been told to contact ground
|
bool contactGround; // we have been told to contact ground
|
||||||
bool changeFreq; // true when we need to change frequency
|
bool changeFreq; // true when we need to change frequency
|
||||||
|
bool _taxiToGA; // Temporary mega-hack indicating we are to taxi to the GA parking and disconnect from tower control.
|
||||||
atc_type changeFreqType; // the service we need to change to
|
atc_type changeFreqType; // the service we need to change to
|
||||||
double responseCounter; // timer in seconds to allow response to requests to be a little while after them
|
bool freeTaxi; // False if the airport has a facilities file with a logical taxi network defined, true if we need to calculate our own taxiing points.
|
||||||
|
|
||||||
|
// Hack for getting close to the runway when atan can go pear-shaped
|
||||||
|
double _savedSlope;
|
||||||
|
|
||||||
void FlyTrafficPattern(double dt);
|
void FlyTrafficPattern(double dt);
|
||||||
|
|
||||||
|
@ -201,8 +223,6 @@ private:
|
||||||
void GetNextTaxiNode();
|
void GetNextTaxiNode();
|
||||||
|
|
||||||
void DoGroundElev();
|
void DoGroundElev();
|
||||||
|
|
||||||
void GetRwyDetails();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_AILocalTraffic_HXX
|
#endif // _FG_AILocalTraffic_HXX
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
@ -33,9 +34,18 @@
|
||||||
# include <dirent.h> // for directory reading
|
# include <dirent.h> // for directory reading
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef FG_WEATHERCM
|
||||||
|
# include <WeatherCM/FGLocalWeatherDatabase.h>
|
||||||
|
#else
|
||||||
|
# include <Environment/environment_mgr.hxx>
|
||||||
|
# include <Environment/environment.hxx>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "AIMgr.hxx"
|
#include "AIMgr.hxx"
|
||||||
#include "AILocalTraffic.hxx"
|
#include "AILocalTraffic.hxx"
|
||||||
|
#include "AIGAVFRTraffic.hxx"
|
||||||
#include "ATCutils.hxx"
|
#include "ATCutils.hxx"
|
||||||
|
#include "commlist.hxx"
|
||||||
|
|
||||||
SG_USING_STD(list);
|
SG_USING_STD(list);
|
||||||
SG_USING_STD(cout);
|
SG_USING_STD(cout);
|
||||||
|
@ -43,12 +53,18 @@ SG_USING_STD(cout);
|
||||||
FGAIMgr::FGAIMgr() {
|
FGAIMgr::FGAIMgr() {
|
||||||
ATC = globals->get_ATC_mgr();
|
ATC = globals->get_ATC_mgr();
|
||||||
initDone = false;
|
initDone = false;
|
||||||
|
ai_callsigns_used["CFGFS"] = 1; // so we don't inadvertently use this
|
||||||
|
// TODO - use the proper user callsign when it becomes user settable.
|
||||||
|
removalList.clear();
|
||||||
|
activated.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAIMgr::~FGAIMgr() {
|
FGAIMgr::~FGAIMgr() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIMgr::init() {
|
void FGAIMgr::init() {
|
||||||
|
//cout << "AIMgr::init called..." << endl;
|
||||||
|
|
||||||
// Pointers to user's position
|
// Pointers to user's position
|
||||||
lon_node = fgGetNode("/position/longitude-deg", true);
|
lon_node = fgGetNode("/position/longitude-deg", true);
|
||||||
lat_node = fgGetNode("/position/latitude-deg", true);
|
lat_node = fgGetNode("/position/latitude-deg", true);
|
||||||
|
@ -58,12 +74,26 @@ void FGAIMgr::init() {
|
||||||
lat = lat_node->getDoubleValue();
|
lat = lat_node->getDoubleValue();
|
||||||
elev = elev_node->getDoubleValue();
|
elev = elev_node->getDoubleValue();
|
||||||
|
|
||||||
|
// Load up models at the start to avoid pausing later
|
||||||
|
// Hack alert - Hardwired paths!!
|
||||||
|
string planepath = "Aircraft/c172/Models/c172-dpm.ac";
|
||||||
|
_defaultModel = sgLoad3DModel( globals->get_fg_root(),
|
||||||
|
planepath.c_str(),
|
||||||
|
globals->get_props(),
|
||||||
|
globals->get_sim_time_sec() );
|
||||||
|
|
||||||
|
planepath = "Aircraft/pa28-161/Models/pa28-161.ac";
|
||||||
|
_piperModel = sgLoad3DModel( globals->get_fg_root(),
|
||||||
|
planepath.c_str(),
|
||||||
|
globals->get_props(),
|
||||||
|
globals->get_sim_time_sec() );
|
||||||
|
|
||||||
// go through the $FG_ROOT/ATC directory and find all *.taxi files
|
// go through the $FG_ROOT/ATC directory and find all *.taxi files
|
||||||
SGPath path(globals->get_fg_root());
|
SGPath path(globals->get_fg_root());
|
||||||
path.append("ATC/");
|
path.append("ATC/");
|
||||||
string dir = path.dir();
|
string dir = path.dir();
|
||||||
string ext;
|
string ext;
|
||||||
string file, f_ident;
|
string file, f_ident;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
// WARNING - I (DCL) haven't tested this on MSVC - this is simply cribbed from TerraGear
|
// WARNING - I (DCL) haven't tested this on MSVC - this is simply cribbed from TerraGear
|
||||||
|
@ -88,12 +118,12 @@ void FGAIMgr::init() {
|
||||||
if(dclFindAirportID(f_ident, &a)) {
|
if(dclFindAirportID(f_ident, &a)) {
|
||||||
SGBucket sgb(a.longitude, a.latitude);
|
SGBucket sgb(a.longitude, a.latitude);
|
||||||
int idx = sgb.gen_index();
|
int idx = sgb.gen_index();
|
||||||
if(airports.find(idx) != airports.end()) {
|
if(facilities.find(idx) != facilities.end()) {
|
||||||
airports[idx]->push_back(f_ident);
|
facilities[idx]->push_back(f_ident);
|
||||||
} else {
|
} else {
|
||||||
aptID_list_type* apts = new aptID_list_type;
|
aptID_list_type* apts = new aptID_list_type;
|
||||||
apts->push_back(f_ident);
|
apts->push_back(f_ident);
|
||||||
airports[idx] = apts;
|
facilities[idx] = apts;
|
||||||
}
|
}
|
||||||
SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx);
|
SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx);
|
||||||
}
|
}
|
||||||
|
@ -119,12 +149,12 @@ void FGAIMgr::init() {
|
||||||
if(dclFindAirportID(f_ident, &a)) {
|
if(dclFindAirportID(f_ident, &a)) {
|
||||||
SGBucket sgb(a.longitude, a.latitude);
|
SGBucket sgb(a.longitude, a.latitude);
|
||||||
int idx = sgb.gen_index();
|
int idx = sgb.gen_index();
|
||||||
if(airports.find(idx) != airports.end()) {
|
if(facilities.find(idx) != facilities.end()) {
|
||||||
airports[idx]->push_back(f_ident);
|
facilities[idx]->push_back(f_ident);
|
||||||
} else {
|
} else {
|
||||||
aptID_list_type* apts = new aptID_list_type;
|
ID_list_type* apts = new ID_list_type;
|
||||||
apts->push_back(f_ident);
|
apts->push_back(f_ident);
|
||||||
airports[idx] = apts;
|
facilities[idx] = apts;
|
||||||
}
|
}
|
||||||
SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx);
|
SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx);
|
||||||
}
|
}
|
||||||
|
@ -135,9 +165,27 @@ void FGAIMgr::init() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// See if are in range at startup and activate if necessary
|
// See if are in range at startup and activate if necessary
|
||||||
SearchByPos(10.0);
|
SearchByPos(15.0);
|
||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
|
|
||||||
|
//cout << "AIMgr::init done..." << endl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TESTING
|
||||||
|
FGATCAlignedProjection ortho;
|
||||||
|
ortho.Init(dclGetAirportPos("KEMT"), 205.0); // Guess of rwy19 heading
|
||||||
|
//Point3D ip = ortho.ConvertFromLocal(Point3D(6000, 1000, 1000)); // 90 deg entry
|
||||||
|
//Point3D ip = ortho.ConvertFromLocal(Point3D(-7000, 3000, 1000)); // 45 deg entry
|
||||||
|
Point3D ip = ortho.ConvertFromLocal(Point3D(1000, -7000, 1000)); // straight-in
|
||||||
|
ATC->AIRegisterAirport("KEMT");
|
||||||
|
FGAIGAVFRTraffic* p = new FGAIGAVFRTraffic();
|
||||||
|
p->SetModel(_defaultModel);
|
||||||
|
p->Init(ip, "KEMT", GenerateShortForm(GenerateUniqueCallsign()));
|
||||||
|
ai_list.push_back(p);
|
||||||
|
traffic[ident].push_back(p);
|
||||||
|
activated["KEMT"] = 1;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIMgr::bind() {
|
void FGAIMgr::bind() {
|
||||||
|
@ -152,6 +200,11 @@ void FGAIMgr::update(double dt) {
|
||||||
SG_LOG(SG_ATC, SG_WARN, "Warning - AIMgr::update(...) called before AIMgr::init()");
|
SG_LOG(SG_ATC, SG_WARN, "Warning - AIMgr::update(...) called before AIMgr::init()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cout << activated.size() << '\n';
|
||||||
|
|
||||||
|
Point3D userPos = Point3D(lon_node->getDoubleValue(), lat_node->getDoubleValue(), elev_node->getDoubleValue());
|
||||||
|
|
||||||
|
// TODO - make these class variables!!
|
||||||
static int i = 0;
|
static int i = 0;
|
||||||
static int j = 0;
|
static int j = 0;
|
||||||
|
|
||||||
|
@ -163,25 +216,106 @@ void FGAIMgr::update(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(j == 215) {
|
if(j == 215) {
|
||||||
SearchByPos(15.0);
|
SearchByPos(25.0);
|
||||||
j = 0;
|
j = 0;
|
||||||
|
} else if(j == 200) {
|
||||||
|
// Go through the list of activated airports and remove those out of range
|
||||||
|
//cout << "The following airports have been activated by the AI system:\n";
|
||||||
|
ai_activated_map_iterator apt_itr = activated.begin();
|
||||||
|
while(apt_itr != activated.end()) {
|
||||||
|
//cout << "FIRST IS " << (*apt_itr).first << '\n';
|
||||||
|
if(dclGetHorizontalSeparation(userPos, dclGetAirportPos((*apt_itr).first)) > (35.0 * 1600.0)) {
|
||||||
|
// Then get rid of it and make sure the iterator is left pointing to the next one!
|
||||||
|
string s = (*apt_itr).first;
|
||||||
|
if(traffic.find(s) != traffic.end()) {
|
||||||
|
//cout << "s = " << s << ", traffic[s].size() = " << traffic[s].size() << '\n';
|
||||||
|
if(traffic[s].size()) {
|
||||||
|
apt_itr++;
|
||||||
|
} else {
|
||||||
|
//cout << "Erasing " << (*apt_itr).first << " and traffic" << '\n';
|
||||||
|
activated.erase(apt_itr++);
|
||||||
|
traffic.erase(s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//cout << "Erasing " << (*apt_itr).first << ' ' << (*apt_itr).second << '\n';
|
||||||
|
activated.erase(apt_itr++);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apt_itr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(j == 180) {
|
||||||
|
// Go through the list of activated airports and do the random airplane generation
|
||||||
|
ai_traffic_map_iterator it = traffic.begin();
|
||||||
|
while(it != traffic.end()) {
|
||||||
|
string s = (*it).first;
|
||||||
|
//cout << "s = " << s << " size = " << (*it).second.size() << '\n';
|
||||||
|
// Only generate extra traffic if within a certain distance of the user,
|
||||||
|
// TODO - maybe take users's tuned freq into account as well.
|
||||||
|
double d = dclGetHorizontalSeparation(userPos, dclGetAirportPos(s));
|
||||||
|
if(d < (15.0 * 1600.0)) {
|
||||||
|
double cd = 0.0;
|
||||||
|
bool gen = false;
|
||||||
|
//cout << "Size of list is " << (*it).second.size() << " at " << s << '\n';
|
||||||
|
if((*it).second.size()) {
|
||||||
|
FGAIEntity* e = *((*it).second.rbegin());
|
||||||
|
cd = dclGetHorizontalSeparation(e->GetPos(), dclGetAirportPos(s));
|
||||||
|
if(cd < (d < 5000 ? 10000 : d + 5000)) {
|
||||||
|
gen = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gen = true;
|
||||||
|
cd = 0.0;
|
||||||
|
}
|
||||||
|
if(gen) {
|
||||||
|
//cout << "Generating extra traffic at airport " << s << ", at least " << cd << " meters out\n";
|
||||||
|
//GenerateSimpleAirportTraffic(s, cd);
|
||||||
|
GenerateSimpleAirportTraffic(s, cd + 2000.0); // The random seems a bit wierd - traffic could get far too bunched without the +2000.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++j;
|
++j;
|
||||||
|
|
||||||
|
//cout << "Size of AI list is " << ai_list.size() << '\n';
|
||||||
|
|
||||||
// TODO - need to add a check of if any activated airports have gone out of range
|
// TODO - need to add a check of if any activated airports have gone out of range
|
||||||
|
|
||||||
|
string rs; // plane to be removed, if one.
|
||||||
|
if(removalList.size()) {
|
||||||
|
rs = *(removalList.begin());
|
||||||
|
removalList.pop_front();
|
||||||
|
} else {
|
||||||
|
rs = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Traverse the list of active planes and run all their update methods
|
// Traverse the list of active planes and run all their update methods
|
||||||
// TODO - spread the load - not all planes should need updating every frame.
|
// TODO - spread the load - not all planes should need updating every frame.
|
||||||
// Note that this will require dt to be calculated for each plane though
|
// Note that this will require dt to be calculated for each plane though
|
||||||
// since they rely on it to calculate distance travelled.
|
// since they rely on it to calculate distance travelled.
|
||||||
ai_list_itr = ai_list.begin();
|
ai_list_itr = ai_list.begin();
|
||||||
while(ai_list_itr != ai_list.end()) {
|
while(ai_list_itr != ai_list.end()) {
|
||||||
(*ai_list_itr)->Update(dt);
|
FGAIEntity *e = *ai_list_itr;
|
||||||
++ai_list_itr;
|
if(rs.size() && e->GetCallsign() == rs) {
|
||||||
|
//cout << "Removing " << rs << " from ai_list\n";
|
||||||
|
ai_list_itr = ai_list.erase(ai_list_itr);
|
||||||
|
delete e;
|
||||||
|
// This is a hack - we should deref this plane from the airport count!
|
||||||
|
} else {
|
||||||
|
e->Update(dt);
|
||||||
|
++ai_list_itr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cout << "Size of AI list is " << ai_list.size() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIMgr::ScheduleRemoval(string s) {
|
||||||
|
//cout << "Scheduling removal of plane " << s << " from AIMgr\n";
|
||||||
|
removalList.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
// Activate AI traffic at an airport
|
// Activate AI traffic at an airport
|
||||||
void FGAIMgr::ActivateAirport(string ident) {
|
void FGAIMgr::ActivateAirport(string ident) {
|
||||||
|
@ -189,21 +323,197 @@ void FGAIMgr::ActivateAirport(string ident) {
|
||||||
// TODO - need to start the traffic more randomly
|
// TODO - need to start the traffic more randomly
|
||||||
FGAILocalTraffic* local_traffic = new FGAILocalTraffic;
|
FGAILocalTraffic* local_traffic = new FGAILocalTraffic;
|
||||||
//local_traffic->Init(ident, IN_PATTERN, TAKEOFF_ROLL);
|
//local_traffic->Init(ident, IN_PATTERN, TAKEOFF_ROLL);
|
||||||
local_traffic->Init(ident);
|
local_traffic->Init(GenerateShortForm(GenerateUniqueCallsign()), ident);
|
||||||
local_traffic->FlyCircuits(1, true); // Fly 2 circuits with touch & go in between
|
local_traffic->FlyCircuits(1, true); // Fly 2 circuits with touch & go in between
|
||||||
ai_list.push_back(local_traffic);
|
ai_list.push_back(local_traffic);
|
||||||
|
traffic[ident].push_back(local_traffic);
|
||||||
|
//cout << "******** ACTIVATING AIRPORT, ident = " << ident << '\n';
|
||||||
activated[ident] = 1;
|
activated[ident] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hack - Generate AI traffic at an airport with no facilities file
|
||||||
|
void FGAIMgr::GenerateSimpleAirportTraffic(string ident, double min_dist) {
|
||||||
|
// Ugly hack - don't let VFR Cessnas operate at a hardwired list of major airports
|
||||||
|
// This will go eventually once airport .xml files specify the traffic profile
|
||||||
|
if(ident == "KSFO" || ident == "KDFW" || ident == "EGLL" || ident == "KORD" || ident == "KJFK"
|
||||||
|
|| ident == "KMSP" || ident == "KLAX" || ident == "KBOS" || ident == "KEDW"
|
||||||
|
|| ident == "KSEA" || ident == "EHAM") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO - check for military airports - this should be in the current data.
|
||||||
|
// UGGH - there's no point at the moment - everything is labelled civil in basic.dat!
|
||||||
|
FGAirport a;
|
||||||
|
if(dclFindAirportID(ident, &a)) {
|
||||||
|
cout << "CODE IS " << a.code << '\n';
|
||||||
|
} else {
|
||||||
|
// UG - can't find the airport!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Point3D aptpos = dclGetAirportPos(ident); // TODO - check for elev of -9999
|
||||||
|
//cout << "ident = " << ident << ", elev = " << aptpos.elev() << '\n';
|
||||||
|
|
||||||
|
// Operate from airports at 3000ft and below only to avoid the default cloud layers and since we don't degrade AI performance with altitude.
|
||||||
|
if(aptpos.elev() > 3000) {
|
||||||
|
//cout << "High alt airports not yet supported - returning\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rough hack for plane type - make 70% of the planes cessnas, the rest pipers.
|
||||||
|
bool cessna = true;
|
||||||
|
|
||||||
|
// Get the time and only operate VFR in the (approximate) daytime.
|
||||||
|
//SGTime *t = globals->get_time_params();
|
||||||
|
string time_str = fgGetString("sim/time/gmt-string");
|
||||||
|
int loc_time = atoi((time_str.substr(0,3)).c_str());
|
||||||
|
//cout << "gmt_time = " << loc_time << '\n';
|
||||||
|
loc_time += (int)((aptpos.lon() / 360.0) * 24.0);
|
||||||
|
while(loc_time < 0) loc_time += 24;
|
||||||
|
while(loc_time > 24) loc_time -= 24;
|
||||||
|
//cout << "loc_time = " << loc_time << '\n';
|
||||||
|
if(loc_time < 7 || loc_time > 19) return;
|
||||||
|
|
||||||
|
// Check that the visibility is OK for IFR operation.
|
||||||
|
double visibility;
|
||||||
|
#ifdef FG_WEATHERCM
|
||||||
|
//sgVec3 position = { aptpos.lat(), aptpos.lon(), aptpos.elev() };
|
||||||
|
//FGPhysicalProperty stationweather = WeatherDatabase->get(position);
|
||||||
|
#else
|
||||||
|
FGEnvironment stationweather =
|
||||||
|
((FGEnvironmentMgr *)globals->get_subsystem("environment"))
|
||||||
|
->getEnvironment(aptpos.lat(), aptpos.lon(), aptpos.elev()); // TODO - check whether this should take ft or m for elev.
|
||||||
|
#endif
|
||||||
|
#ifdef FG_WEATHERCM
|
||||||
|
visibility = fgGetDouble("/environment/visibility-m");
|
||||||
|
#else
|
||||||
|
visibility = stationweather.get_visibility_m();
|
||||||
|
#endif
|
||||||
|
// Technically we can do VFR down to 1 mile (1600m) but that's pretty murky!
|
||||||
|
//cout << "vis = " << visibility << '\n';
|
||||||
|
if(visibility < 3000) return;
|
||||||
|
|
||||||
|
ATC->AIRegisterAirport(ident);
|
||||||
|
|
||||||
|
// Next - get the distance from user to the airport.
|
||||||
|
Point3D userpos = Point3D(lon_node->getDoubleValue(), lat_node->getDoubleValue(), elev_node->getDoubleValue());
|
||||||
|
double d = dclGetHorizontalSeparation(userpos, aptpos); // in meters
|
||||||
|
|
||||||
|
int lev = fgGetInt("/sim/ai-traffic/level");
|
||||||
|
if(lev < 1 || lev > 3) lev = 2;
|
||||||
|
if(visibility < 6000) lev = 1;
|
||||||
|
//cout << "level = " << lev << '\n';
|
||||||
|
|
||||||
|
// Next - generate any local / circuit traffic
|
||||||
|
|
||||||
|
/*
|
||||||
|
// --------------------------- THIS BLOCK IS JUST FOR TESTING - COMMENT OUT BEFORE RELEASE ---------------
|
||||||
|
// Finally - generate VFR approaching traffic
|
||||||
|
//if(d > 2000) {
|
||||||
|
if(ident == "KPOC") {
|
||||||
|
double ad = 2000.0;
|
||||||
|
double avd = 3000.0; // average spacing of arriving traffic in meters - relate to airport business and AI density setting one day!
|
||||||
|
//while(ad < (d < 10000 ? 12000 : d + 2000)) {
|
||||||
|
for(int i=0; i<8; ++i) {
|
||||||
|
double dd = sg_random() * avd;
|
||||||
|
// put a minimum spacing in for now since I don't think tower will cope otherwise!
|
||||||
|
if(dd < 1500) dd = 1500;
|
||||||
|
//ad += dd;
|
||||||
|
ad += dd;
|
||||||
|
double dir = int(sg_random() * 36);
|
||||||
|
if(dir == 36) dir--;
|
||||||
|
dir *= 10;
|
||||||
|
//dir = 180;
|
||||||
|
if(sg_random() < 0.3) cessna = false;
|
||||||
|
else cessna = true;
|
||||||
|
string s = GenerateShortForm(GenerateUniqueCallsign(), (cessna ? "Cessna-" : "Piper-"));
|
||||||
|
FGAIGAVFRTraffic* t = new FGAIGAVFRTraffic();
|
||||||
|
t->SetModel(cessna ? _defaultModel : _piperModel);
|
||||||
|
//cout << "Generating VFR traffic " << s << " inbound to " << ident << " " << ad << " meters out from " << dir << " degrees\n";
|
||||||
|
Point3D tpos = dclUpdatePosition(aptpos, dir, 6.0, ad);
|
||||||
|
if(tpos.elev() > (aptpos.elev() + 3000.0)) tpos.setelev(aptpos.elev() + 3000.0);
|
||||||
|
t->Init(tpos, ident, s);
|
||||||
|
ai_list.push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activated[ident] = 1;
|
||||||
|
return;
|
||||||
|
//---------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
double ad; // Minimum distance out of first arriving plane in meters.
|
||||||
|
double mind; // Minimum spacing of traffic in meters
|
||||||
|
double avd; // average spacing of arriving traffic in meters - relate to airport business and AI density setting one day!
|
||||||
|
// Finally - generate VFR approaching traffic
|
||||||
|
//if(d > 2000) {
|
||||||
|
if(1) {
|
||||||
|
if(lev == 3) {
|
||||||
|
ad = 5000.0;
|
||||||
|
mind = 2000.0;
|
||||||
|
avd = 6000.0;
|
||||||
|
} else if(lev == 2) {
|
||||||
|
ad = 8000.0;
|
||||||
|
mind = 4000.0;
|
||||||
|
avd = 10000.0;
|
||||||
|
} else {
|
||||||
|
ad = 9000.0; // Start the first aircraft at least 9K out for now.
|
||||||
|
mind = 6000.0;
|
||||||
|
avd = 15000.0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// Check if there is already arriving traffic at this airport
|
||||||
|
cout << "BING A " << ident << '\n';
|
||||||
|
if(traffic.find(ident) != traffic.end()) {
|
||||||
|
cout << "BING B " << ident << '\n';
|
||||||
|
ai_list_type lst = traffic[ident];
|
||||||
|
cout << "BING C " << ident << '\n';
|
||||||
|
if(lst.size()) {
|
||||||
|
cout << "BING D " << ident << '\n';
|
||||||
|
double cd = dclGetHorizontalSeparation(aptpos, (*lst.rbegin())->GetPos());
|
||||||
|
cout << "ident = " << ident << ", cd = " << cd << '\n';
|
||||||
|
if(cd > ad) ad = cd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if(min_dist != 0) ad = min_dist;
|
||||||
|
//cout << "ident = " << ident << ", ad = " << ad << '\n';
|
||||||
|
while(ad < (d < 5000 ? 15000 : d + 10000)) {
|
||||||
|
double dd = mind + (sg_random() * (avd - mind));
|
||||||
|
ad += dd;
|
||||||
|
double dir = int(sg_random() * 36);
|
||||||
|
if(dir == 36) dir--;
|
||||||
|
dir *= 10;
|
||||||
|
if(sg_random() < 0.3) cessna = false;
|
||||||
|
else cessna = true;
|
||||||
|
string s = GenerateShortForm(GenerateUniqueCallsign(), (cessna ? "Cessna-" : "Piper-"));
|
||||||
|
FGAIGAVFRTraffic* t = new FGAIGAVFRTraffic();
|
||||||
|
t->SetModel(cessna ? _defaultModel : _piperModel);
|
||||||
|
//cout << "Generating VFR traffic " << s << " inbound to " << ident << " " << ad << " meters out from " << dir << " degrees\n";
|
||||||
|
Point3D tpos = dclUpdatePosition(aptpos, dir, 6.0, ad);
|
||||||
|
if(tpos.elev() > (aptpos.elev() + 3000.0)) tpos.setelev(aptpos.elev() + 3000.0); // FEET yuk :-(
|
||||||
|
t->Init(tpos, ident, s);
|
||||||
|
ai_list.push_back(t);
|
||||||
|
traffic[ident].push_back(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Generate a VFR arrival at airport apt, at least distance d (meters) out.
|
||||||
|
void FGAIMgr::GenerateVFRArrival(string apt, double d) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Search for valid airports in the vicinity of the user and activate them if necessary
|
// Search for valid airports in the vicinity of the user and activate them if necessary
|
||||||
void FGAIMgr::SearchByPos(double range)
|
void FGAIMgr::SearchByPos(double range) {
|
||||||
{
|
|
||||||
//cout << "In SearchByPos(...)" << endl;
|
//cout << "In SearchByPos(...)" << endl;
|
||||||
|
|
||||||
// get bucket number for plane position
|
// get bucket number for plane position
|
||||||
lon = lon_node->getDoubleValue();
|
lon = lon_node->getDoubleValue();
|
||||||
lat = lat_node->getDoubleValue();
|
lat = lat_node->getDoubleValue();
|
||||||
|
elev = elev_node->getDoubleValue() * SG_FEET_TO_METER;
|
||||||
SGBucket buck(lon, lat);
|
SGBucket buck(lon, lat);
|
||||||
|
|
||||||
// get neigboring buckets
|
// get neigboring buckets
|
||||||
|
@ -212,6 +522,7 @@ void FGAIMgr::SearchByPos(double range)
|
||||||
int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 );
|
int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 );
|
||||||
//cout << "by = " << by << endl;
|
//cout << "by = " << by << endl;
|
||||||
|
|
||||||
|
// Search for airports with facitities files --------------------------
|
||||||
// loop over bucket range
|
// loop over bucket range
|
||||||
for ( int i=-bx; i<=bx; i++) {
|
for ( int i=-bx; i<=bx; i++) {
|
||||||
//cout << "i loop\n";
|
//cout << "i loop\n";
|
||||||
|
@ -220,10 +531,10 @@ void FGAIMgr::SearchByPos(double range)
|
||||||
buck = sgBucketOffset(lon, lat, i, j);
|
buck = sgBucketOffset(lon, lat, i, j);
|
||||||
long int bucket = buck.gen_index();
|
long int bucket = buck.gen_index();
|
||||||
//cout << "bucket is " << bucket << endl;
|
//cout << "bucket is " << bucket << endl;
|
||||||
if(airports.find(bucket) != airports.end()) {
|
if(facilities.find(bucket) != facilities.end()) {
|
||||||
aptID_list_type* apts = airports[bucket];
|
ID_list_type* apts = facilities[bucket];
|
||||||
aptID_list_iterator current = apts->begin();
|
ID_list_iterator current = apts->begin();
|
||||||
aptID_list_iterator last = apts->end();
|
ID_list_iterator last = apts->end();
|
||||||
|
|
||||||
//cout << "Size of apts is " << apts->size() << endl;
|
//cout << "Size of apts is " << apts->size() << endl;
|
||||||
|
|
||||||
|
@ -239,7 +550,10 @@ void FGAIMgr::SearchByPos(double range)
|
||||||
//if(dclFindAirportID(*current, &a)) {
|
//if(dclFindAirportID(*current, &a)) {
|
||||||
// // We can do something here based on distance from the user if we wish.
|
// // We can do something here based on distance from the user if we wish.
|
||||||
//}
|
//}
|
||||||
|
//string s = *current;
|
||||||
|
//cout << "s = " << s << '\n';
|
||||||
ActivateAirport(*current);
|
ActivateAirport(*current);
|
||||||
|
//ActivateSimpleAirport(*current); // TODO - put this back to ActivateAirport when that code is done.
|
||||||
//cout << "Activation done" << endl;
|
//cout << "Activation done" << endl;
|
||||||
} else {
|
} else {
|
||||||
//cout << *current << " already activated" << endl;
|
//cout << *current << " already activated" << endl;
|
||||||
|
@ -248,4 +562,86 @@ void FGAIMgr::SearchByPos(double range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
|
||||||
|
// Search for any towered airports in the vicinity ------------
|
||||||
|
comm_list_type towered;
|
||||||
|
comm_list_iterator twd_itr;
|
||||||
|
|
||||||
|
int num_twd = current_commlist->FindByPos(lon, lat, elev, range, &towered, TOWER);
|
||||||
|
if (num_twd != 0) {
|
||||||
|
double closest = 1000000;
|
||||||
|
string s = "";
|
||||||
|
for(twd_itr = towered.begin(); twd_itr != towered.end(); twd_itr++) {
|
||||||
|
// Only activate the closest airport not already activated each time.
|
||||||
|
if(activated.find(twd_itr->ident) == activated.end()) {
|
||||||
|
double sep = dclGetHorizontalSeparation(Point3D(lon, lat, elev), dclGetAirportPos(twd_itr->ident));
|
||||||
|
if(sep < closest) {
|
||||||
|
closest = sep;
|
||||||
|
s = twd_itr->ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s.size()) {
|
||||||
|
// TODO - find out why empty strings come through here when all in-range airports done.
|
||||||
|
GenerateSimpleAirportTraffic(s);
|
||||||
|
//cout << "**************ACTIVATING SIMPLE AIRPORT, ident = " << s << '\n';
|
||||||
|
activated[s] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string FGAIMgr::GenerateCallsign() {
|
||||||
|
// For now we'll just generate US callsigns until we can regionally identify airports.
|
||||||
|
string s = "N";
|
||||||
|
// Add 3 to 5 numbers and make up to 5 with letters.
|
||||||
|
//sg_srandom_time();
|
||||||
|
double d = sg_random();
|
||||||
|
int n = int(d * 3);
|
||||||
|
if(n == 3) --n;
|
||||||
|
//cout << "First n, n = " << n << '\n';
|
||||||
|
int j = 3 + n;
|
||||||
|
//cout << "j = " << j << '\n';
|
||||||
|
for(int i=0; i<j; ++i) {
|
||||||
|
int n = int(sg_random() * 10);
|
||||||
|
if(n == 10) --n;
|
||||||
|
s += (char)('0' + n);
|
||||||
|
}
|
||||||
|
for(int i=j; i<5; ++i) {
|
||||||
|
int n = int(sg_random() * 26);
|
||||||
|
if(n == 26) --n;
|
||||||
|
//cout << "Alpha, n = " << n << '\n';
|
||||||
|
s += (char)('A' + n);
|
||||||
|
}
|
||||||
|
//cout << "s = " << s << '\n';
|
||||||
|
return(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
string FGAIMgr::GenerateUniqueCallsign() {
|
||||||
|
while(1) {
|
||||||
|
string s = GenerateCallsign();
|
||||||
|
if(!ai_callsigns_used[s]) {
|
||||||
|
ai_callsigns_used[s] = 1;
|
||||||
|
return(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will be moved somewhere else eventually!!!!
|
||||||
|
string FGAIMgr::GenerateShortForm(string callsign, string plane_str, bool local) {
|
||||||
|
//cout << callsign << '\n';
|
||||||
|
string s;
|
||||||
|
if(local) s = "Trainer-";
|
||||||
|
else s = plane_str;
|
||||||
|
for(int i=3; i>0; --i) {
|
||||||
|
char c = callsign[callsign.size() - i];
|
||||||
|
//cout << c << '\n';
|
||||||
|
string tmp = "";
|
||||||
|
tmp += c;
|
||||||
|
if(isalpha(c)) s += GetPhoneticIdent(c);
|
||||||
|
else s += ConvertNumToSpokenDigits(tmp);
|
||||||
|
if(i > 1) s += '-';
|
||||||
|
}
|
||||||
|
return(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,19 +54,32 @@ private:
|
||||||
// at any point in or at the end of the list.
|
// at any point in or at the end of the list.
|
||||||
// Hence any new access must explicitly first check for atc_list.end() before dereferencing.
|
// Hence any new access must explicitly first check for atc_list.end() before dereferencing.
|
||||||
|
|
||||||
// A list of airport ID's
|
// A list of airport or airplane ID's
|
||||||
typedef list < string > aptID_list_type;
|
typedef list < string > ID_list_type;
|
||||||
typedef aptID_list_type::iterator aptID_list_iterator;
|
typedef ID_list_type::iterator ID_list_iterator;
|
||||||
|
|
||||||
|
// Temporary storage of ID of planes scheduled for removeal
|
||||||
|
ID_list_type removalList;
|
||||||
|
|
||||||
// A map of airport-IDs that have taxiway network files against bucket number
|
// A map of airport-IDs that have taxiway network files against bucket number
|
||||||
typedef map < int, aptID_list_type* > ai_apt_map_type;
|
typedef map < int, ID_list_type* > ai_apt_map_type;
|
||||||
typedef ai_apt_map_type::iterator ai_apt_map_iterator;
|
typedef ai_apt_map_type::iterator ai_apt_map_iterator;
|
||||||
ai_apt_map_type airports;
|
ai_apt_map_type facilities;
|
||||||
|
|
||||||
// A map of airport ID's that we've activated AI traffic at
|
// A map of airport ID's that we've activated AI traffic at
|
||||||
typedef map < string, int > ai_activated_map_type;
|
typedef map < string, int > ai_activated_map_type;
|
||||||
typedef ai_activated_map_type::iterator ai_activated_map_iterator;
|
typedef ai_activated_map_type::iterator ai_activated_map_iterator;
|
||||||
ai_activated_map_type activated;
|
ai_activated_map_type activated;
|
||||||
|
|
||||||
|
// AI traffic lists mapped by airport
|
||||||
|
typedef map < string, ai_list_type > ai_traffic_map_type;
|
||||||
|
typedef ai_traffic_map_type::iterator ai_traffic_map_iterator;
|
||||||
|
ai_traffic_map_type traffic;
|
||||||
|
|
||||||
|
// A map of callsigns that we have used (eg CFGFS or N0546D - the code will generate Cessna-four-six-delta from this later)
|
||||||
|
typedef map < string, int > ai_callsigns_map_type;
|
||||||
|
typedef ai_callsigns_map_type::iterator ai_callsigns_map_iterator;
|
||||||
|
ai_callsigns_map_type ai_callsigns_used;
|
||||||
|
|
||||||
// Position of the Users Aircraft
|
// Position of the Users Aircraft
|
||||||
double lon;
|
double lon;
|
||||||
|
@ -89,8 +102,15 @@ public:
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
void update(double dt);
|
void update(double dt);
|
||||||
|
|
||||||
|
// Signal that it is OK to remove a plane of callsign s
|
||||||
|
// (To be called by the plane itself).
|
||||||
|
void ScheduleRemoval(string s);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
ssgBranch* _defaultModel; // Cessna 172!
|
||||||
|
ssgBranch* _piperModel; // pa28-161
|
||||||
|
|
||||||
bool initDone; // Hack - guard against update getting called before init
|
bool initDone; // Hack - guard against update getting called before init
|
||||||
|
|
||||||
|
@ -98,10 +118,19 @@ private:
|
||||||
//void RemoveFromList(const char* id, atc_type tp);
|
//void RemoveFromList(const char* id, atc_type tp);
|
||||||
|
|
||||||
// Activate AI traffic at an airport
|
// Activate AI traffic at an airport
|
||||||
void ActivateAirport(string id);
|
void ActivateAirport(string ident);
|
||||||
|
|
||||||
|
// Hack - Generate AI traffic at an airport with no facilities file, with the first plane being at least min_dist out.
|
||||||
|
void GenerateSimpleAirportTraffic(string ident, double min_dist = 0.0);
|
||||||
|
|
||||||
// Search for valid airports in the vicinity of the user and activate them if necessary
|
// Search for valid airports in the vicinity of the user and activate them if necessary
|
||||||
void SearchByPos(double range);
|
void SearchByPos(double range);
|
||||||
|
|
||||||
|
string GenerateCallsign();
|
||||||
|
|
||||||
|
string GenerateUniqueCallsign();
|
||||||
|
|
||||||
|
string GenerateShortForm(string callsign, string plane_str = "Cessna-", bool local = false);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ void FGAIPlane::Update(double dt) {
|
||||||
if(_pending) {
|
if(_pending) {
|
||||||
if(tuned_station) {
|
if(tuned_station) {
|
||||||
if(tuned_station->GetFreqClear()) {
|
if(tuned_station->GetFreqClear()) {
|
||||||
|
//cout << "TUNED STATION FREQ CLEAR\n";
|
||||||
tuned_station->SetFreqInUse();
|
tuned_station->SetFreqInUse();
|
||||||
_pending = false;
|
_pending = false;
|
||||||
_transmit = true;
|
_transmit = true;
|
||||||
|
@ -69,6 +70,7 @@ void FGAIPlane::Update(double dt) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not tuned to ATC - Just go ahead and transmit
|
// Not tuned to ATC - Just go ahead and transmit
|
||||||
|
//cout << "NOT TUNED TO ATC\n";
|
||||||
_pending = false;
|
_pending = false;
|
||||||
_transmit = true;
|
_transmit = true;
|
||||||
_transmitting = false;
|
_transmitting = false;
|
||||||
|
@ -115,16 +117,16 @@ void FGAIPlane::Update(double dt) {
|
||||||
|
|
||||||
void FGAIPlane::Bank(double angle) {
|
void FGAIPlane::Bank(double angle) {
|
||||||
// This *should* bank us smoothly to any angle
|
// This *should* bank us smoothly to any angle
|
||||||
if(fabs(roll - angle) > 0.6) {
|
if(fabs(_roll - angle) > 0.6) {
|
||||||
roll -= ((roll - angle)/fabs(roll - angle));
|
_roll -= ((_roll - angle)/fabs(_roll - angle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplication of Bank(0.0) really - should I cut this?
|
// Duplication of Bank(0.0) really - should I cut this?
|
||||||
void FGAIPlane::LevelWings(void) {
|
void FGAIPlane::LevelWings(void) {
|
||||||
// bring the plane back to level smoothly (this should work to come out of either bank)
|
// bring the plane back to level smoothly (this should work to come out of either bank)
|
||||||
if(fabs(roll) > 0.6) {
|
if(fabs(_roll) > 0.6) {
|
||||||
roll -= (roll/fabs(roll));
|
_roll -= (_roll/fabs(_roll));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,9 @@ public:
|
||||||
|
|
||||||
// Return what type of landing we're doing on this circuit
|
// Return what type of landing we're doing on this circuit
|
||||||
virtual LandingType GetLandingOption();
|
virtual LandingType GetLandingOption();
|
||||||
|
|
||||||
|
// Return the callsign
|
||||||
|
inline string GetCallsign() {return plane.callsign;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PlaneRec plane;
|
PlaneRec plane;
|
||||||
|
|
|
@ -34,8 +34,10 @@ FGATC::FGATC() {
|
||||||
receiving = false;
|
receiving = false;
|
||||||
respond = false;
|
respond = false;
|
||||||
runResponseCounter = false;
|
runResponseCounter = false;
|
||||||
|
_runReleaseCounter = false;
|
||||||
responseID = "";
|
responseID = "";
|
||||||
responseReqd = false;
|
responseReqd = false;
|
||||||
|
_type = INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGATC::~FGATC() {
|
FGATC::~FGATC() {
|
||||||
|
@ -53,6 +55,15 @@ void FGATC::Update(double dt) {
|
||||||
responseCounter += dt;
|
responseCounter += dt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_runReleaseCounter) {
|
||||||
|
if(_releaseCounter >= _releaseTime) {
|
||||||
|
freqClear = true;
|
||||||
|
_runReleaseCounter = false;
|
||||||
|
} else {
|
||||||
|
_releaseCounter += dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATC::ReceiveUserCallback(int code) {
|
void FGATC::ReceiveUserCallback(int code) {
|
||||||
|
@ -71,12 +82,15 @@ void FGATC::SetResponseReqd(string rid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATC::NotifyTransmissionFinished(string rid) {
|
void FGATC::NotifyTransmissionFinished(string rid) {
|
||||||
|
//cout << "Transmission finished, callsign = " << rid << '\n';
|
||||||
receiving = false;
|
receiving = false;
|
||||||
responseID = rid;
|
responseID = rid;
|
||||||
if(responseReqd) {
|
if(responseReqd) {
|
||||||
runResponseCounter = true;
|
runResponseCounter = true;
|
||||||
responseCounter = 0.0;
|
responseCounter = 0.0;
|
||||||
responseTime = 1.8; // TODO - randomize this slightly.
|
responseTime = 1.2; // TODO - randomize this slightly, and allow it to be dependent on the transmission and how busy the ATC is.
|
||||||
|
respond = false; // TODO - this ignores the fact that more than one plane could call this before response
|
||||||
|
// Shouldn't happen with AI only, but user could confuse things??
|
||||||
} else {
|
} else {
|
||||||
freqClear = true;
|
freqClear = true;
|
||||||
}
|
}
|
||||||
|
@ -95,10 +109,6 @@ void FGATC::SetDisplay() {
|
||||||
void FGATC::SetNoDisplay() {
|
void FGATC::SetNoDisplay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
atc_type FGATC::GetType() {
|
|
||||||
return INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FGATC::SetData(ATCData* d) {
|
void FGATC::SetData(ATCData* d) {
|
||||||
lon = d->lon;
|
lon = d->lon;
|
||||||
lat = d->lat;
|
lat = d->lat;
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
// The user will just have to wait for a gap in dialog as in real life.
|
// The user will just have to wait for a gap in dialog as in real life.
|
||||||
|
|
||||||
// Return the type of ATC station that the class represents
|
// Return the type of ATC station that the class represents
|
||||||
virtual atc_type GetType();
|
inline atc_type GetType() { return _type; }
|
||||||
|
|
||||||
// Set the core ATC data
|
// Set the core ATC data
|
||||||
void SetData(ATCData* d);
|
void SetData(ATCData* d);
|
||||||
|
@ -192,6 +192,7 @@ protected:
|
||||||
int range;
|
int range;
|
||||||
string ident; // Code of the airport its at.
|
string ident; // Code of the airport its at.
|
||||||
string name; // Name transmitted in the broadcast.
|
string name; // Name transmitted in the broadcast.
|
||||||
|
atc_type _type;
|
||||||
|
|
||||||
// Rendering related stuff
|
// Rendering related stuff
|
||||||
bool voice; // Flag - true if we are using voice
|
bool voice; // Flag - true if we are using voice
|
||||||
|
@ -209,6 +210,9 @@ protected:
|
||||||
string responseID; // ID of the plane to respond to
|
string responseID; // ID of the plane to respond to
|
||||||
bool respond; // Flag to indicate now is the time to respond - ie set following the count down of the response timer.
|
bool respond; // Flag to indicate now is the time to respond - ie set following the count down of the response timer.
|
||||||
// Derived classes only need monitor this flag, and use the response ID, as long as they call FGATC::Update(...)
|
// Derived classes only need monitor this flag, and use the response ID, as long as they call FGATC::Update(...)
|
||||||
|
bool _runReleaseCounter; // A timer for releasing the frequency after giving the message enough time to display
|
||||||
|
double _releaseTime;
|
||||||
|
double _releaseCounter;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline istream&
|
inline istream&
|
||||||
|
|
|
@ -260,7 +260,7 @@ void FGATCDialog::add_entry(string station, string transmission, string menutext
|
||||||
|
|
||||||
void FGATCDialog::remove_entry( const string &station, const string &trans, atc_type type ) {
|
void FGATCDialog::remove_entry( const string &station, const string &trans, atc_type type ) {
|
||||||
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
||||||
atcmentry_vec_iterator current = p->begin();
|
atcmentry_vec_iterator current = p->begin();
|
||||||
while(current != p->end()) {
|
while(current != p->end()) {
|
||||||
if(current->transmission == trans) current = p->erase(current);
|
if(current->transmission == trans) current = p->erase(current);
|
||||||
else ++current;
|
else ++current;
|
||||||
|
@ -269,7 +269,7 @@ void FGATCDialog::remove_entry( const string &station, const string &trans, atc_
|
||||||
|
|
||||||
void FGATCDialog::remove_entry( const string &station, int code, atc_type type ) {
|
void FGATCDialog::remove_entry( const string &station, int code, atc_type type ) {
|
||||||
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
||||||
atcmentry_vec_iterator current = p->begin();
|
atcmentry_vec_iterator current = p->begin();
|
||||||
while(current != p->end()) {
|
while(current != p->end()) {
|
||||||
if(current->callback_code == code) current = p->erase(current);
|
if(current->callback_code == code) current = p->erase(current);
|
||||||
else ++current;
|
else ++current;
|
||||||
|
@ -279,7 +279,7 @@ void FGATCDialog::remove_entry( const string &station, int code, atc_type type )
|
||||||
// query the database whether the transmission is already registered;
|
// query the database whether the transmission is already registered;
|
||||||
bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_type type ) {
|
bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_type type ) {
|
||||||
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
||||||
atcmentry_vec_iterator current = p->begin();
|
atcmentry_vec_iterator current = p->begin();
|
||||||
for ( ; current != p->end() ; ++current ) {
|
for ( ; current != p->end() ; ++current ) {
|
||||||
if ( current->transmission == trans ) return true;
|
if ( current->transmission == trans ) return true;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,7 @@ bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_typ
|
||||||
// query the database whether the transmission is already registered;
|
// query the database whether the transmission is already registered;
|
||||||
bool FGATCDialog::trans_reg( const string &station, int code, atc_type type ) {
|
bool FGATCDialog::trans_reg( const string &station, int code, atc_type type ) {
|
||||||
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
atcmentry_vec_type* p = &((available_dialog[type])[station]);
|
||||||
atcmentry_vec_iterator current = p->begin();
|
atcmentry_vec_iterator current = p->begin();
|
||||||
for ( ; current != p->end() ; ++current ) {
|
for ( ; current != p->end() ; ++current ) {
|
||||||
if ( current->callback_code == code ) return true;
|
if ( current->callback_code == code ) return true;
|
||||||
}
|
}
|
||||||
|
@ -397,14 +397,23 @@ void FGATCDialog::PopupCallback() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(atcptr->GetType() == TOWER) {
|
} else if(atcptr->GetType() == TOWER) {
|
||||||
ATCMenuEntry a = ((available_dialog[TOWER])[(string)atcptr->get_ident()])[atcDialogCommunicationOptions->getValue()];
|
//cout << "TOWER " << endl;
|
||||||
atcptr->SetFreqInUse();
|
//cout << "ident is " << atcptr->get_ident() << endl;
|
||||||
globals->get_ATC_display()->RegisterSingleMessage(atcptr->GenText(a.transmission, a.callback_code));
|
atcmentry_vec_type atcmlist = (available_dialog[TOWER])[(string)atcptr->get_ident()];
|
||||||
_callbackPending = true;
|
if(atcmlist.size()) {
|
||||||
_callbackTimer = 0.0;
|
//cout << "Doing callback...\n";
|
||||||
_callbackWait = 5.0;
|
ATCMenuEntry a = atcmlist[atcDialogCommunicationOptions->getValue()];
|
||||||
_callbackPtr = atcptr;
|
atcptr->SetFreqInUse();
|
||||||
_callbackCode = a.callback_code;
|
globals->get_ATC_display()->RegisterSingleMessage(atcptr->GenText(a.transmission, a.callback_code));
|
||||||
|
_callbackPending = true;
|
||||||
|
_callbackTimer = 0.0;
|
||||||
|
_callbackWait = 5.0;
|
||||||
|
_callbackPtr = atcptr;
|
||||||
|
_callbackCode = a.callback_code;
|
||||||
|
} else {
|
||||||
|
//cout << "No options available...\n";
|
||||||
|
}
|
||||||
|
//cout << "Donded" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
FGATCDisplay::FGATCDisplay() {
|
FGATCDisplay::FGATCDisplay() {
|
||||||
rep_msg = false;
|
rep_msg = false;
|
||||||
change_msg_flag = false;
|
change_msg_flag = false;
|
||||||
dsp_offset1 = 0;
|
dsp_offset1 = 0.0;
|
||||||
dsp_offset2 = 0;
|
dsp_offset2 = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ void FGATCDisplay::update(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATCDisplay::RegisterSingleMessage(string msg, double delay) {
|
void FGATCDisplay::RegisterSingleMessage(string msg, double delay) {
|
||||||
|
//cout << msg << '\n';
|
||||||
atcMessage m;
|
atcMessage m;
|
||||||
m.msg = msg;
|
m.msg = msg;
|
||||||
m.repeating = false;
|
m.repeating = false;
|
||||||
|
|
|
@ -48,6 +48,7 @@ AirportATC::AirportATC() :
|
||||||
ground_active(false),
|
ground_active(false),
|
||||||
set_by_AI(false),
|
set_by_AI(false),
|
||||||
numAI(0)
|
numAI(0)
|
||||||
|
//airport_atc_map.clear();
|
||||||
{
|
{
|
||||||
for(int i=0; i<ATC_NUM_TYPES; ++i) {
|
for(int i=0; i<ATC_NUM_TYPES; ++i) {
|
||||||
set_by_comm[0][i] = false;
|
set_by_comm[0][i] = false;
|
||||||
|
@ -58,9 +59,9 @@ AirportATC::AirportATC() :
|
||||||
FGATCMgr::FGATCMgr() {
|
FGATCMgr::FGATCMgr() {
|
||||||
comm_ident[0] = "";
|
comm_ident[0] = "";
|
||||||
comm_ident[1] = "";
|
comm_ident[1] = "";
|
||||||
last_comm_ident[0] = "";
|
//last_comm_ident[0] = "";
|
||||||
last_comm_ident[1] = "";
|
//last_comm_ident[1] = "";
|
||||||
approach_ident = "";
|
//approach_ident = "";
|
||||||
last_in_range = false;
|
last_in_range = false;
|
||||||
comm_type[0] = INVALID;
|
comm_type[0] = INVALID;
|
||||||
comm_type[1] = INVALID;
|
comm_type[1] = INVALID;
|
||||||
|
@ -83,6 +84,8 @@ void FGATCMgr::unbind() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATCMgr::init() {
|
void FGATCMgr::init() {
|
||||||
|
//cout << "ATCMgr::init called..." << endl;
|
||||||
|
|
||||||
comm_node[0] = fgGetNode("/radios/comm[0]/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);
|
comm_node[1] = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true);
|
||||||
lon_node = fgGetNode("/position/longitude-deg", true);
|
lon_node = fgGetNode("/position/longitude-deg", true);
|
||||||
|
@ -135,6 +138,7 @@ void FGATCMgr::init() {
|
||||||
current_atcdialog->Init();
|
current_atcdialog->Init();
|
||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
|
//cout << "ATCmgr::init done!" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATCMgr::update(double dt) {
|
void FGATCMgr::update(double dt) {
|
||||||
|
@ -149,7 +153,7 @@ void FGATCMgr::update(double dt) {
|
||||||
//Traverse the list of active stations.
|
//Traverse the list of active stations.
|
||||||
//Only update one class per update step to avoid the whole ATC system having to calculate between frames.
|
//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.
|
//Eventually we should only update every so many steps.
|
||||||
//cout << "In FGATCMgr::update - atc_list.size = " << atc_list.size() << '\n';
|
//cout << "In FGATCMgr::update - atc_list.size = " << atc_list.size() << endl;
|
||||||
if(atc_list.size()) {
|
if(atc_list.size()) {
|
||||||
if(atc_list_itr == atc_list.end()) {
|
if(atc_list_itr == atc_list.end()) {
|
||||||
atc_list_itr = atc_list.begin();
|
atc_list_itr = atc_list.begin();
|
||||||
|
@ -161,6 +165,14 @@ void FGATCMgr::update(double dt) {
|
||||||
++atc_list_itr;
|
++atc_list_itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
cout << "ATC_LIST: " << atc_list.size() << ' ';
|
||||||
|
for(atc_list_iterator it = atc_list.begin(); it != atc_list.end(); it++) {
|
||||||
|
cout << (*it)->get_ident() << ' ';
|
||||||
|
}
|
||||||
|
cout << '\n';
|
||||||
|
*/
|
||||||
|
|
||||||
// Search the tuned frequencies every now and then - this should be done with the event scheduler
|
// Search the tuned frequencies every now and then - this should be done with the event scheduler
|
||||||
static int i = 0; // Very ugly - but there should only ever be one instance of FGATCMgr.
|
static int i = 0; // Very ugly - but there should only ever be one instance of FGATCMgr.
|
||||||
/*
|
/*
|
||||||
|
@ -197,6 +209,7 @@ unsigned short int FGATCMgr::GetFrequency(string ident, atc_type tp) {
|
||||||
// Might need more sophistication in this in the future - eg registration by aircraft call-sign.
|
// Might need more sophistication in this in the future - eg registration by aircraft call-sign.
|
||||||
bool FGATCMgr::AIRegisterAirport(string ident) {
|
bool FGATCMgr::AIRegisterAirport(string ident) {
|
||||||
SG_LOG(SG_ATC, SG_BULK, "AI registered airport " << ident << " with the ATC system");
|
SG_LOG(SG_ATC, SG_BULK, "AI registered airport " << ident << " with the ATC system");
|
||||||
|
//cout << "AI registered airport " << ident << " with the ATC system" << '\n';
|
||||||
if(airport_atc_map.find(ident) != airport_atc_map.end()) {
|
if(airport_atc_map.find(ident) != airport_atc_map.end()) {
|
||||||
airport_atc_map[ident]->set_by_AI = true;
|
airport_atc_map[ident]->set_by_AI = true;
|
||||||
airport_atc_map[ident]->numAI++;
|
airport_atc_map[ident]->numAI++;
|
||||||
|
@ -234,9 +247,19 @@ bool FGATCMgr::AIRegisterAirport(string ident) {
|
||||||
// Channel is zero based
|
// Channel is zero based
|
||||||
bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) {
|
bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) {
|
||||||
SG_LOG(SG_ATC, SG_BULK, "Comm channel " << chan << " registered airport " << ident);
|
SG_LOG(SG_ATC, SG_BULK, "Comm channel " << chan << " registered airport " << ident);
|
||||||
|
//cout << "Comm channel " << chan << " registered airport " << ident << '\n';
|
||||||
if(airport_atc_map.find(ident) != airport_atc_map.end()) {
|
if(airport_atc_map.find(ident) != airport_atc_map.end()) {
|
||||||
//cout << "IN MAP - flagging set by comm..." << endl;
|
//cout << "IN MAP - flagging set by comm..." << endl;
|
||||||
airport_atc_map[ident]->set_by_comm[chan][tp] = true;
|
airport_atc_map[ident]->set_by_comm[chan][tp] = true;
|
||||||
|
if(tp == ATIS) {
|
||||||
|
airport_atc_map[ident]->atis_active = true;
|
||||||
|
} else if(tp == TOWER) {
|
||||||
|
airport_atc_map[ident]->tower_active = true;
|
||||||
|
} else if(tp == GROUND) {
|
||||||
|
airport_atc_map[ident]->ground_active = true;
|
||||||
|
} else if(tp == APPROACH) {
|
||||||
|
//a->approach_active = true;
|
||||||
|
} // TODO - there *must* be a better way to do this!!!
|
||||||
return(true);
|
return(true);
|
||||||
} else {
|
} else {
|
||||||
//cout << "NOT IN MAP - creating new..." << endl;
|
//cout << "NOT IN MAP - creating new..." << endl;
|
||||||
|
@ -253,6 +276,15 @@ bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) {
|
||||||
a->tower_active = false;
|
a->tower_active = false;
|
||||||
a->ground_freq = GetFrequency(ident, GROUND);
|
a->ground_freq = GetFrequency(ident, GROUND);
|
||||||
a->ground_active = false;
|
a->ground_active = false;
|
||||||
|
if(tp == ATIS) {
|
||||||
|
a->atis_active = true;
|
||||||
|
} else if(tp == TOWER) {
|
||||||
|
a->tower_active = true;
|
||||||
|
} else if(tp == GROUND) {
|
||||||
|
a->ground_active = true;
|
||||||
|
} else if(tp == APPROACH) {
|
||||||
|
//a->approach_active = true;
|
||||||
|
} // TODO - there *must* be a better way to do this!!!
|
||||||
// TODO - some airports will have a tower/ground frequency but be inactive overnight.
|
// TODO - some airports will have a tower/ground frequency but be inactive overnight.
|
||||||
a->set_by_AI = false;
|
a->set_by_AI = false;
|
||||||
a->numAI = 0;
|
a->numAI = 0;
|
||||||
|
@ -267,8 +299,9 @@ bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) {
|
||||||
|
|
||||||
// Remove from list only if not needed by the AI system or the other comm channel
|
// Remove from list only if not needed by the AI system or the other comm channel
|
||||||
// Note that chan is zero based.
|
// Note that chan is zero based.
|
||||||
void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp, int chan) {
|
void FGATCMgr::CommRemoveFromList(string id, atc_type tp, int chan) {
|
||||||
SG_LOG(SG_ATC, SG_BULK, "CommRemoveFromList called for airport " << id << " " << tp << " by channel " << chan);
|
SG_LOG(SG_ATC, SG_BULK, "CommRemoveFromList called for airport " << id << " " << tp << " by channel " << chan);
|
||||||
|
//cout << "CommRemoveFromList called for airport " << id << " " << tp << " by channel " << chan << '\n';
|
||||||
if(airport_atc_map.find(id) != airport_atc_map.end()) {
|
if(airport_atc_map.find(id) != airport_atc_map.end()) {
|
||||||
AirportATC* a = airport_atc_map[id];
|
AirportATC* a = airport_atc_map[id];
|
||||||
//cout << "In CommRemoveFromList, a->ground_freq = " << a->ground_freq << endl;
|
//cout << "In CommRemoveFromList, a->ground_freq = " << a->ground_freq << endl;
|
||||||
|
@ -309,12 +342,16 @@ void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp, int chan) {
|
||||||
a->set_by_comm[0][tp] = false;
|
a->set_by_comm[0][tp] = false;
|
||||||
// Remove only if not also set by the other comm channel
|
// Remove only if not also set by the other comm channel
|
||||||
if(!a->set_by_comm[1][tp]) {
|
if(!a->set_by_comm[1][tp]) {
|
||||||
|
a->tower_active = false;
|
||||||
|
a->ground_active = false;
|
||||||
RemoveFromList(id, tp);
|
RemoveFromList(id, tp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
a->set_by_comm[1][tp] = false;
|
a->set_by_comm[1][tp] = false;
|
||||||
if(!a->set_by_comm[0][tp]) {
|
if(!a->set_by_comm[0][tp]) {
|
||||||
|
a->tower_active = false;
|
||||||
|
a->ground_active = false;
|
||||||
RemoveFromList(id, tp);
|
RemoveFromList(id, tp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -326,24 +363,26 @@ void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp, int chan) {
|
||||||
|
|
||||||
// Remove from list - should only be called from above or similar
|
// 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.
|
// This function *will* remove it from the list regardless of who else might want it.
|
||||||
void FGATCMgr::RemoveFromList(const char* id, atc_type tp) {
|
void FGATCMgr::RemoveFromList(string id, atc_type tp) {
|
||||||
//cout << "Requested type = " << tp << '\n';
|
//cout << "FGATCMgr::RemoveFromList called..." << endl;
|
||||||
//cout << "id = " << id << '\n';
|
//cout << "Requested type = " << tp << endl;
|
||||||
atc_list_itr = atc_list.begin();
|
//cout << "id = " << id << endl;
|
||||||
while(atc_list_itr != atc_list.end()) {
|
atc_list_iterator it = atc_list.begin();
|
||||||
//cout << "type = " << (*atc_list_itr)->GetType() << '\n';
|
while(it != atc_list.end()) {
|
||||||
//cout << "Ident = " << (*atc_list_itr)->get_ident() << '\n';
|
//cout << "type = " << (*it)->GetType() << '\n';
|
||||||
if( (!strcmp((*atc_list_itr)->get_ident(), id))
|
//cout << "Ident = " << (*it)->get_ident() << '\n';
|
||||||
&& ((*atc_list_itr)->GetType() == tp) ) {
|
if( (!strcmp((*it)->get_ident(), id.c_str()))
|
||||||
//Before removing it stop it transmitting!!
|
&& ((*it)->GetType() == tp) ) {
|
||||||
//cout << "OBLITERATING FROM LIST!!!\n";
|
//Before removing it stop it transmitting!!
|
||||||
(*atc_list_itr)->SetNoDisplay();
|
//cout << "OBLITERATING FROM LIST!!!\n";
|
||||||
(*atc_list_itr)->Update(0.00833);
|
(*it)->SetNoDisplay();
|
||||||
delete (*atc_list_itr);
|
(*it)->Update(0.00833);
|
||||||
atc_list_itr = atc_list.erase(atc_list_itr);
|
delete (*it);
|
||||||
break;
|
atc_list.erase(it);
|
||||||
} // Note that that can upset where we are in the list but that doesn't really matter
|
atc_list_itr = atc_list.begin(); // Reset the persistent itr incase we've left it off the end.
|
||||||
++atc_list_itr;
|
break;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,16 +390,18 @@ void FGATCMgr::RemoveFromList(const char* id, atc_type tp) {
|
||||||
// Find in list - return a currently active ATC pointer given ICAO code and type
|
// 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
|
// Return NULL if the given service is not in the list
|
||||||
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
||||||
FGATC* FGATCMgr::FindInList(const char* id, atc_type tp) {
|
FGATC* FGATCMgr::FindInList(string id, atc_type tp) {
|
||||||
atc_list_itr = atc_list.begin();
|
//cout << "Entering FindInList for " << id << ' ' << tp << endl;
|
||||||
while(atc_list_itr != atc_list.end()) {
|
atc_list_iterator it = atc_list.begin();
|
||||||
if( (!strcmp((*atc_list_itr)->get_ident(), id))
|
while(it != atc_list.end()) {
|
||||||
&& ((*atc_list_itr)->GetType() == tp) ) {
|
if( (!strcmp((*it)->get_ident(), id.c_str()))
|
||||||
return(*atc_list_itr);
|
&& ((*it)->GetType() == tp) ) {
|
||||||
} // Note that that can upset where we are in the list but that shouldn't really matter
|
return(*it);
|
||||||
++atc_list_itr;
|
}
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
// If we get here it's not in the list
|
// If we get here it's not in the list
|
||||||
|
//cout << "Couldn't find it in the list though :-(" << endl;
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,8 +422,10 @@ bool FGATCMgr::GetAirportATCDetails(string icao, AirportATC* a) {
|
||||||
// - at the moment all these GetATC... functions exposed are just too complicated.
|
// - at the moment all these GetATC... functions exposed are just too complicated.
|
||||||
FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
||||||
if(airport_atc_map.find(icao) == airport_atc_map.end()) {
|
if(airport_atc_map.find(icao) == airport_atc_map.end()) {
|
||||||
|
//cout << "Unable to find " << icao << ' ' << type << " in the airport_atc_map" << endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
//cout << "Found " << icao << ' ' << type << endl;
|
||||||
AirportATC *a = airport_atc_map[icao];
|
AirportATC *a = airport_atc_map[icao];
|
||||||
//cout << "a->lon = " << a->lon << '\n';
|
//cout << "a->lon = " << a->lon << '\n';
|
||||||
//cout << "a->elev = " << a->elev << '\n';
|
//cout << "a->elev = " << a->elev << '\n';
|
||||||
|
@ -400,6 +443,7 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
||||||
atc_list.push_back(t);
|
atc_list.push_back(t);
|
||||||
a->tower_active = true;
|
a->tower_active = true;
|
||||||
airport_atc_map[icao] = a;
|
airport_atc_map[icao] = a;
|
||||||
|
//cout << "Initing tower in GetATCPointer()\n";
|
||||||
t->Init();
|
t->Init();
|
||||||
return(t);
|
return(t);
|
||||||
} else {
|
} else {
|
||||||
|
@ -441,6 +485,7 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_ATC, SG_ALERT, "ERROR IN FGATCMgr - reached end of GetATCPointer");
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR IN FGATCMgr - reached end of GetATCPointer");
|
||||||
|
//cout << "ERROR IN FGATCMgr - reached end of GetATCPointer" << endl;
|
||||||
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
@ -503,7 +548,7 @@ void FGATCMgr::FreqSearch(int channel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// At this point we can assume that we need to add the service.
|
// At this point we can assume that we need to add the service.
|
||||||
comm_ident[chan] = (data.ident).c_str();
|
comm_ident[chan] = data.ident;
|
||||||
comm_type[chan] = data.type;
|
comm_type[chan] = data.type;
|
||||||
comm_x[chan] = (double)data.x;
|
comm_x[chan] = (double)data.x;
|
||||||
comm_y[chan] = (double)data.y;
|
comm_y[chan] = (double)data.y;
|
||||||
|
@ -520,6 +565,7 @@ void FGATCMgr::FreqSearch(int channel) {
|
||||||
if(app != NULL) {
|
if(app != NULL) {
|
||||||
// The station is already in the ATC list
|
// The station is already in the ATC list
|
||||||
//cout << "In list - flagging SetDisplay..." << endl;
|
//cout << "In list - flagging SetDisplay..." << endl;
|
||||||
|
comm_atc_ptr[chan] = app;
|
||||||
app->SetDisplay();
|
app->SetDisplay();
|
||||||
} else {
|
} else {
|
||||||
// Generate the station and put in the ATC list
|
// Generate the station and put in the ATC list
|
||||||
|
@ -532,19 +578,24 @@ void FGATCMgr::FreqSearch(int channel) {
|
||||||
atc_list.push_back(a);
|
atc_list.push_back(a);
|
||||||
}
|
}
|
||||||
} else if (comm_type[chan] == TOWER) {
|
} else if (comm_type[chan] == TOWER) {
|
||||||
|
//cout << "TOWER TOWER TOWER\n";
|
||||||
CommRegisterAirport(comm_ident[chan], chan, TOWER);
|
CommRegisterAirport(comm_ident[chan], chan, TOWER);
|
||||||
//cout << "Done (TOWER)" << endl;
|
//cout << "Done (TOWER)" << endl;
|
||||||
FGATC* app = FindInList(comm_ident[chan], TOWER);
|
FGATC* app = FindInList(comm_ident[chan], TOWER);
|
||||||
if(app != NULL) {
|
if(app != NULL) {
|
||||||
// The station is already in the ATC list
|
// The station is already in the ATC list
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, comm_ident[chan] << " is in list - flagging SetDisplay...");
|
SG_LOG(SG_GENERAL, SG_DEBUG, comm_ident[chan] << " is in list - flagging SetDisplay...");
|
||||||
|
//cout << comm_ident[chan] << " is in list - flagging SetDisplay...\n";
|
||||||
|
comm_atc_ptr[chan] = app;
|
||||||
app->SetDisplay();
|
app->SetDisplay();
|
||||||
} else {
|
} else {
|
||||||
// Generate the station and put in the ATC list
|
// Generate the station and put in the ATC list
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, comm_ident[chan] << " is not in list - generating...");
|
SG_LOG(SG_GENERAL, SG_DEBUG, comm_ident[chan] << " is not in list - generating...");
|
||||||
|
//cout << comm_ident[chan] << " is not in list - generating...\n";
|
||||||
FGTower* t = new FGTower;
|
FGTower* t = new FGTower;
|
||||||
t->SetData(&data);
|
t->SetData(&data);
|
||||||
comm_atc_ptr[chan] = t;
|
comm_atc_ptr[chan] = t;
|
||||||
|
//cout << "Initing tower in FreqSearch()\n";
|
||||||
t->Init();
|
t->Init();
|
||||||
t->SetDisplay();
|
t->SetDisplay();
|
||||||
atc_list.push_back(t);
|
atc_list.push_back(t);
|
||||||
|
@ -555,6 +606,7 @@ void FGATCMgr::FreqSearch(int channel) {
|
||||||
FGATC* app = FindInList(comm_ident[chan], GROUND);
|
FGATC* app = FindInList(comm_ident[chan], GROUND);
|
||||||
if(app != NULL) {
|
if(app != NULL) {
|
||||||
// The station is already in the ATC list
|
// The station is already in the ATC list
|
||||||
|
comm_atc_ptr[chan] = app;
|
||||||
app->SetDisplay();
|
app->SetDisplay();
|
||||||
} else {
|
} else {
|
||||||
// Generate the station and put in the ATC list
|
// Generate the station and put in the ATC list
|
||||||
|
@ -638,19 +690,21 @@ void FGATCMgr::AreaSearch() {
|
||||||
|
|
||||||
// remove planes which are out of range
|
// remove planes which are out of range
|
||||||
// TODO - I'm not entirely sure that this belongs here.
|
// TODO - I'm not entirely sure that this belongs here.
|
||||||
atc_list_itr = atc_list.begin();
|
atc_list_iterator it = atc_list.begin();
|
||||||
while(atc_list_itr != atc_list.end()) {
|
while(it != atc_list.end()) {
|
||||||
if((*atc_list_itr)->GetType() == APPROACH ) {
|
if((*it)->GetType() == APPROACH ) {
|
||||||
int np = (*atc_list_itr)->RemovePlane();
|
int np = (*it)->RemovePlane();
|
||||||
// if approach has no planes left remove it from ATC list
|
// if approach has no planes left remove it from ATC list
|
||||||
if ( np == 0) {
|
if ( np == 0) {
|
||||||
(*atc_list_itr)->SetNoDisplay();
|
//cout << "REMOVING AN APPROACH STATION WITH NO PLANES..." << endl;
|
||||||
(*atc_list_itr)->Update(0.00833);
|
(*it)->SetNoDisplay();
|
||||||
delete (*atc_list_itr);
|
(*it)->Update(0.00833);
|
||||||
atc_list_itr = atc_list.erase(atc_list_itr);
|
delete (*it);
|
||||||
|
atc_list.erase(it);
|
||||||
|
atc_list_itr = atc_list.begin(); // Reset the persistent itr incase we've left it off the end.
|
||||||
break; // the other stations will be checked next time
|
break; // the other stations will be checked next time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++atc_list_itr;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,10 +128,9 @@ private:
|
||||||
|
|
||||||
double comm_range[2], comm_effective_range[2];
|
double comm_range[2], comm_effective_range[2];
|
||||||
bool comm_valid[2];
|
bool comm_valid[2];
|
||||||
const char* comm_ident[2];
|
string comm_ident[2];
|
||||||
const char* last_comm_ident[2];
|
//string last_comm_ident[2];
|
||||||
|
//string approach_ident;
|
||||||
const char* approach_ident;
|
|
||||||
bool last_in_range;
|
bool last_in_range;
|
||||||
|
|
||||||
//FGATIS atis;
|
//FGATIS atis;
|
||||||
|
@ -195,17 +194,17 @@ private:
|
||||||
|
|
||||||
// Remove a class from the atc_list and delete it from memory
|
// Remove a class from the atc_list and delete it from memory
|
||||||
// *if* no other comm channel or AI plane is using it.
|
// *if* no other comm channel or AI plane is using it.
|
||||||
void CommRemoveFromList(const char* id, atc_type tp, int chan);
|
void CommRemoveFromList(string id, atc_type tp, int chan);
|
||||||
|
|
||||||
// Remove a class from the atc_list and delete it from memory
|
// Remove a class from the atc_list and delete it from memory
|
||||||
// Should be called from the above - not directly!!
|
// Should be called from the above - not directly!!
|
||||||
void RemoveFromList(const char* id, atc_type tp);
|
void RemoveFromList(string id, atc_type tp);
|
||||||
|
|
||||||
// Return a pointer to a class in the list given ICAO code and type
|
// Return a pointer to a class in the list given ICAO code and type
|
||||||
// (external interface to this is through GetATCPointer)
|
// (external interface to this is through GetATCPointer)
|
||||||
// Return NULL if the given service is not in the list
|
// Return NULL if the given service is not in the list
|
||||||
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
// - *** THE CALLING FUNCTION MUST CHECK FOR THIS ***
|
||||||
FGATC* FindInList(const char* id, atc_type tp);
|
FGATC* FindInList(string id, atc_type tp);
|
||||||
|
|
||||||
// Search the specified channel for stations on the same frequency and in range.
|
// Search the specified channel for stations on the same frequency and in range.
|
||||||
void FreqSearch(int channel);
|
void FreqSearch(int channel);
|
||||||
|
|
|
@ -114,38 +114,71 @@ string ConvertRwyNumToSpokenString(string s) {
|
||||||
// Return the phonetic letter of a letter represented as an integer 1->26
|
// Return the phonetic letter of a letter represented as an integer 1->26
|
||||||
string GetPhoneticIdent(int i) {
|
string GetPhoneticIdent(int i) {
|
||||||
// TODO - Check i is between 1 and 26 and wrap if necessary
|
// TODO - Check i is between 1 and 26 and wrap if necessary
|
||||||
switch(i) {
|
return(GetPhoneticIdent(char('a' + (i-1))));
|
||||||
case 1 : return("alpha");
|
}
|
||||||
case 2 : return("bravo");
|
|
||||||
case 3 : return("charlie");
|
// Return the phonetic letter of a character in the range a-z or A-Z.
|
||||||
case 4 : return("delta");
|
// Currently always returns prefixed by lowercase.
|
||||||
case 5 : return("echo");
|
string GetPhoneticIdent(char c) {
|
||||||
case 6 : return("foxtrot");
|
c = tolower(c);
|
||||||
case 7 : return("golf");
|
// TODO - Check c is between a and z and wrap if necessary
|
||||||
case 8 : return("hotel");
|
switch(c) {
|
||||||
case 9 : return("india");
|
case 'a' : return("alpha");
|
||||||
case 10 : return("juliet");
|
case 'b' : return("bravo");
|
||||||
case 11 : return("kilo");
|
case 'c' : return("charlie");
|
||||||
case 12 : return("lima");
|
case 'd' : return("delta");
|
||||||
case 13 : return("mike");
|
case 'e' : return("echo");
|
||||||
case 14 : return("november");
|
case 'f' : return("foxtrot");
|
||||||
case 15 : return("oscar");
|
case 'g' : return("golf");
|
||||||
case 16 : return("papa");
|
case 'h' : return("hotel");
|
||||||
case 17 : return("quebec");
|
case 'i' : return("india");
|
||||||
case 18 : return("romeo");
|
case 'j' : return("juliet");
|
||||||
case 19 : return("sierra");
|
case 'k' : return("kilo");
|
||||||
case 20 : return("tango");
|
case 'l' : return("lima");
|
||||||
case 21 : return("uniform");
|
case 'm' : return("mike");
|
||||||
case 22 : return("victor");
|
case 'n' : return("november");
|
||||||
case 23 : return("whiskey");
|
case 'o' : return("oscar");
|
||||||
case 24 : return("x-ray");
|
case 'p' : return("papa");
|
||||||
case 25 : return("yankee");
|
case 'q' : return("quebec");
|
||||||
case 26 : return("zulu");
|
case 'r' : return("romeo");
|
||||||
|
case 's' : return("sierra");
|
||||||
|
case 't' : return("tango");
|
||||||
|
case 'u' : return("uniform");
|
||||||
|
case 'v' : return("victor");
|
||||||
|
case 'w' : return("whiskey");
|
||||||
|
case 'x' : return("x-ray");
|
||||||
|
case 'y' : return("yankee");
|
||||||
|
case 'z' : return("zulu");
|
||||||
}
|
}
|
||||||
// We shouldn't get here
|
// We shouldn't get here
|
||||||
return("Error");
|
return("Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the compass direction associated with a heading in degrees
|
||||||
|
// Currently returns 8 direction resolution (N, NE, E etc...)
|
||||||
|
// Might be modified in future to return 4, 8 or 16 resolution but defaulting to 8.
|
||||||
|
string GetCompassDirection(double h) {
|
||||||
|
while(h < 0.0) h += 360.0;
|
||||||
|
while(h > 360.0) h -= 360.0;
|
||||||
|
if(h < 22.5 || h > 337.5) {
|
||||||
|
return("North");
|
||||||
|
} else if(h < 67.5) {
|
||||||
|
return("North-East");
|
||||||
|
} else if(h < 112.5) {
|
||||||
|
return("East");
|
||||||
|
} else if(h < 157.5) {
|
||||||
|
return("South-East");
|
||||||
|
} else if(h < 202.5) {
|
||||||
|
return("South");
|
||||||
|
} else if(h < 247.5) {
|
||||||
|
return("South-West");
|
||||||
|
} else if(h < 292.5) {
|
||||||
|
return("West");
|
||||||
|
} else {
|
||||||
|
return("North-West");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//================================================================================================================
|
//================================================================================================================
|
||||||
|
|
||||||
// Given two positions (lat & lon in degrees), get the HORIZONTAL separation (in meters)
|
// Given two positions (lat & lon in degrees), get the HORIZONTAL separation (in meters)
|
||||||
|
@ -305,16 +338,31 @@ double dclGetAirportElev( const string& id ) {
|
||||||
FGAirport a;
|
FGAirport a;
|
||||||
// double lon, lat;
|
// double lon, lat;
|
||||||
|
|
||||||
SG_LOG( SG_GENERAL, SG_INFO,
|
SG_LOG( SG_ATC, SG_INFO,
|
||||||
"Finding elevation for airport: " << id );
|
"Finding elevation for airport: " << id );
|
||||||
|
|
||||||
if ( dclFindAirportID( id, &a ) ) {
|
if ( dclFindAirportID( id, &a ) ) {
|
||||||
return a.elevation;
|
return a.elevation * SG_FEET_TO_METER;
|
||||||
} else {
|
} else {
|
||||||
return -9999.0;
|
return -9999.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get airport position
|
||||||
|
Point3D dclGetAirportPos( const string& id ) {
|
||||||
|
FGAirport a;
|
||||||
|
// double lon, lat;
|
||||||
|
|
||||||
|
SG_LOG( SG_ATC, SG_INFO,
|
||||||
|
"Finding position for airport: " << id );
|
||||||
|
|
||||||
|
if ( dclFindAirportID( id, &a ) ) {
|
||||||
|
return Point3D(a.longitude, a.latitude, a.elevation);
|
||||||
|
} else {
|
||||||
|
return Point3D(0.0, 0.0, -9999.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Runway stuff
|
// Runway stuff
|
||||||
// Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
|
// Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
|
||||||
bool OnRunway(Point3D pt, const FGRunway& rwy) {
|
bool OnRunway(Point3D pt, const FGRunway& rwy) {
|
||||||
|
|
|
@ -56,6 +56,14 @@ string ConvertRwyNumToSpokenString(string s);
|
||||||
// Return the phonetic letter of a letter represented as an integer 1->26
|
// Return the phonetic letter of a letter represented as an integer 1->26
|
||||||
string GetPhoneticIdent(int i);
|
string GetPhoneticIdent(int i);
|
||||||
|
|
||||||
|
// Return the phonetic letter of a character in the range a-z or A-Z.
|
||||||
|
// Currently always returns prefixed by lowercase.
|
||||||
|
string GetPhoneticIdent(char c);
|
||||||
|
|
||||||
|
// Get the compass direction associated with a heading in degrees
|
||||||
|
// Currently returns 8 direction resolution (N, NE, E etc...)
|
||||||
|
// Might be modified in future to return 4, 8 or 16 resolution but defaulting to 8.
|
||||||
|
string GetCompassDirection(double h);
|
||||||
|
|
||||||
/*******************************
|
/*******************************
|
||||||
*
|
*
|
||||||
|
@ -97,9 +105,12 @@ double GetAngleDiff_deg( const double &a1, const double &a2);
|
||||||
// find basic airport location info from airport database
|
// find basic airport location info from airport database
|
||||||
bool dclFindAirportID( const string& id, FGAirport *a );
|
bool dclFindAirportID( const string& id, FGAirport *a );
|
||||||
|
|
||||||
// get airport elevation
|
// get airport elevation IN METERS
|
||||||
double dclGetAirportElev( const string& id );
|
double dclGetAirportElev( const string& id );
|
||||||
|
|
||||||
|
// get airport position (elev portion in FEET)
|
||||||
|
Point3D dclGetAirportPos( const string& id );
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
*
|
*
|
||||||
* Runways
|
* Runways
|
||||||
|
|
|
@ -17,6 +17,7 @@ libATC_a_SOURCES = \
|
||||||
AIEntity.hxx AIEntity.cxx \
|
AIEntity.hxx AIEntity.cxx \
|
||||||
AIPlane.hxx AIPlane.cxx \
|
AIPlane.hxx AIPlane.cxx \
|
||||||
AILocalTraffic.hxx AILocalTraffic.cxx \
|
AILocalTraffic.hxx AILocalTraffic.cxx \
|
||||||
|
AIGAVFRTraffic.hxx AIGAVFRTraffic.cxx \
|
||||||
transmission.hxx transmission.cxx transmissionlist.hxx transmissionlist.cxx
|
transmission.hxx transmission.cxx transmissionlist.hxx transmissionlist.cxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
FGApproach::FGApproach(){
|
FGApproach::FGApproach(){
|
||||||
comm1_node = fgGetNode("/radios/comm[0]/frequencies/selected-mhz", true);
|
comm1_node = fgGetNode("/radios/comm[0]/frequencies/selected-mhz", true);
|
||||||
comm2_node = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true);
|
comm2_node = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true);
|
||||||
|
|
||||||
|
_type = APPROACH;
|
||||||
|
|
||||||
num_planes = 0;
|
num_planes = 0;
|
||||||
lon_node = fgGetNode("/position/longitude-deg", true);
|
lon_node = fgGetNode("/position/longitude-deg", true);
|
||||||
|
|
|
@ -169,7 +169,6 @@ public:
|
||||||
inline double get_bucket() const { return bucket; }
|
inline double get_bucket() const { return bucket; }
|
||||||
inline int get_pnum() const { return num_planes; }
|
inline int get_pnum() const { return num_planes; }
|
||||||
inline string get_trans_ident() { return trans_ident; }
|
inline string get_trans_ident() { return trans_ident; }
|
||||||
inline atc_type GetType() { return APPROACH; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ FGATIS::FGATIS() :
|
||||||
{
|
{
|
||||||
vPtr = globals->get_ATC_mgr()->GetVoicePointer(ATIS);
|
vPtr = globals->get_ATC_mgr()->GetVoicePointer(ATIS);
|
||||||
voiceOK = (vPtr == NULL ? false : true);
|
voiceOK = (vPtr == NULL ? false : true);
|
||||||
|
_type = ATIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGATIS::~FGATIS() {
|
FGATIS::~FGATIS() {
|
||||||
|
|
|
@ -86,7 +86,6 @@ class FGATIS : public FGATC {
|
||||||
//Indicate that this instance should not be outputting to the ATC display
|
//Indicate that this instance should not be outputting to the ATC display
|
||||||
inline void SetNoDisplay(void) {display = false;}
|
inline void SetNoDisplay(void) {display = false;}
|
||||||
|
|
||||||
inline atc_type GetType() { return ATIS; }
|
|
||||||
//inline void set_type(const atc_type tp) {type = tp;}
|
//inline void set_type(const atc_type tp) {type = tp;}
|
||||||
inline string get_trans_ident() { return trans_ident; }
|
inline string get_trans_ident() { return trans_ident; }
|
||||||
inline void set_refname(string r) { refname = r; }
|
inline void set_refname(string r) { refname = r; }
|
||||||
|
|
|
@ -53,6 +53,7 @@ a_path::a_path() {
|
||||||
|
|
||||||
FGGround::FGGround() {
|
FGGround::FGGround() {
|
||||||
ATCmgr = globals->get_ATC_mgr();
|
ATCmgr = globals->get_ATC_mgr();
|
||||||
|
_type = GROUND;
|
||||||
display = false;
|
display = false;
|
||||||
networkLoadOK = false;
|
networkLoadOK = false;
|
||||||
ground_traffic.erase(ground_traffic.begin(), ground_traffic.end());
|
ground_traffic.erase(ground_traffic.begin(), ground_traffic.end());
|
||||||
|
@ -454,6 +455,11 @@ Gate* FGGround::GetGateNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
node* FGGround::GetHoldShortNode(string rwyID) {
|
||||||
|
return(NULL); // TODO - either implement me or remove me!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// WARNING - This is hardwired to my prototype logical network format
|
// WARNING - This is hardwired to my prototype logical network format
|
||||||
// and will almost certainly change when Bernie's stuff comes on-line.
|
// and will almost certainly change when Bernie's stuff comes on-line.
|
||||||
// Returns NULL if it can't find a valid node.
|
// Returns NULL if it can't find a valid node.
|
||||||
|
@ -495,7 +501,7 @@ ground_network_path_type FGGround::GetPath(node* A, node* B) {
|
||||||
ground_network_path_type FGGround::GetPath(node* A, string rwyID) {
|
ground_network_path_type FGGround::GetPath(node* A, string rwyID) {
|
||||||
node* b = GetThresholdNode(rwyID);
|
node* b = GetThresholdNode(rwyID);
|
||||||
if(b == NULL) {
|
if(b == NULL) {
|
||||||
SG_LOG(SG_ATC, SG_ALERT, "ERROR - unable to find path to runway theshold in ground.cxx\n");
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR - unable to find path to runway theshold in ground.cxx for airport " << ident << '\n');
|
||||||
ground_network_path_type emptyPath;
|
ground_network_path_type emptyPath;
|
||||||
emptyPath.erase(emptyPath.begin(), emptyPath.end());
|
emptyPath.erase(emptyPath.begin(), emptyPath.end());
|
||||||
return(emptyPath);
|
return(emptyPath);
|
||||||
|
|
|
@ -232,7 +232,6 @@ public:
|
||||||
void Update(double dt);
|
void Update(double dt);
|
||||||
|
|
||||||
inline string get_trans_ident() { return trans_ident; }
|
inline string get_trans_ident() { return trans_ident; }
|
||||||
inline atc_type GetType() { return GROUND; }
|
|
||||||
inline void SetDisplay() {display = true;}
|
inline void SetDisplay() {display = true;}
|
||||||
inline void SetNoDisplay() {display = false;}
|
inline void SetNoDisplay() {display = false;}
|
||||||
|
|
||||||
|
@ -258,6 +257,9 @@ public:
|
||||||
// Return a pointer to an unused gate
|
// Return a pointer to an unused gate
|
||||||
Gate* GetGateNode();
|
Gate* GetGateNode();
|
||||||
|
|
||||||
|
// Return a pointer to a hold short node
|
||||||
|
node* GetHoldShortNode(string rwyID);
|
||||||
|
|
||||||
// Runway stuff - this might change in the future.
|
// Runway stuff - this might change in the future.
|
||||||
// Get a list of exits from a given runway
|
// Get a list of exits from a given runway
|
||||||
// It is up to the calling function to check for non-zero size of returned array before use
|
// It is up to the calling function to check for non-zero size of returned array before use
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -60,7 +60,8 @@ enum tower_callback_type {
|
||||||
USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO = 4,
|
USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO = 4,
|
||||||
USER_REPORT_3_MILE_FINAL = 5,
|
USER_REPORT_3_MILE_FINAL = 5,
|
||||||
USER_REPORT_DOWNWIND = 6,
|
USER_REPORT_DOWNWIND = 6,
|
||||||
USER_REPORT_RWY_VACATED = 7
|
USER_REPORT_RWY_VACATED = 7,
|
||||||
|
USER_REPORT_GOING_AROUND = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO - need some differentiation of IFR and VFR traffic in order to give the former priority.
|
// TODO - need some differentiation of IFR and VFR traffic in order to give the former priority.
|
||||||
|
@ -135,6 +136,8 @@ public:
|
||||||
// eg "Cessna Charlie Foxtrot Golf Foxtrot Sierra eight miles South of the airport for full stop with Bravo"
|
// eg "Cessna Charlie Foxtrot Golf Foxtrot Sierra eight miles South of the airport for full stop with Bravo"
|
||||||
// This function probably only called via user interaction - AI planes will have an overloaded function taking a planerec.
|
// This function probably only called via user interaction - AI planes will have an overloaded function taking a planerec.
|
||||||
void VFRArrivalContact(string ID, LandingType opt = AIP_LT_UNKNOWN);
|
void VFRArrivalContact(string ID, LandingType opt = AIP_LT_UNKNOWN);
|
||||||
|
// For the AI planes...
|
||||||
|
void VFRArrivalContact(PlaneRec plane, FGAIPlane* requestee, LandingType lt = AIP_LT_UNKNOWN);
|
||||||
|
|
||||||
void RequestDepartureClearance(string ID);
|
void RequestDepartureClearance(string ID);
|
||||||
void ReportFinal(string ID);
|
void ReportFinal(string ID);
|
||||||
|
@ -154,6 +157,9 @@ public:
|
||||||
// CAUTION - currently it is assumed that this plane's callsign is unique - it is up to AIMgr to generate unique callsigns.
|
// CAUTION - currently it is assumed that this plane's callsign is unique - it is up to AIMgr to generate unique callsigns.
|
||||||
void RegisterAIPlane(PlaneRec plane, FGAIPlane* ai, tower_traffic_type op, PatternLeg lg = LEG_UNKNOWN);
|
void RegisterAIPlane(PlaneRec plane, FGAIPlane* ai, tower_traffic_type op, PatternLeg lg = LEG_UNKNOWN);
|
||||||
|
|
||||||
|
// Deregister and remove an AI plane.
|
||||||
|
void DeregisterAIPlane(string id);
|
||||||
|
|
||||||
// Public interface to the active runway - this will get more complex
|
// Public interface to the active runway - this will get more complex
|
||||||
// in the future and consider multi-runway use, airplane weight etc.
|
// in the future and consider multi-runway use, airplane weight etc.
|
||||||
inline string GetActiveRunway() { return activeRwy; }
|
inline string GetActiveRunway() { return activeRwy; }
|
||||||
|
@ -165,7 +171,6 @@ public:
|
||||||
inline void SetNoDisplay() { display = false; }
|
inline void SetNoDisplay() { display = false; }
|
||||||
|
|
||||||
inline string get_trans_ident() { return trans_ident; }
|
inline string get_trans_ident() { return trans_ident; }
|
||||||
inline atc_type GetType() { return TOWER; }
|
|
||||||
|
|
||||||
inline FGGround* GetGroundPtr() { return ground; }
|
inline FGGround* GetGroundPtr() { return ground; }
|
||||||
|
|
||||||
|
@ -184,13 +189,17 @@ private:
|
||||||
// Respond to a transmission
|
// Respond to a transmission
|
||||||
void Respond();
|
void Respond();
|
||||||
|
|
||||||
void CheckHoldList(double dt);
|
void ProcessRunwayVacatedReport(TowerPlaneRec* t);
|
||||||
|
|
||||||
void CheckCircuitList(double dt);
|
|
||||||
|
|
||||||
|
// Remove all options from the user dialog choice
|
||||||
|
void RemoveAllUserDialogOptions();
|
||||||
|
|
||||||
|
// Periodic checks on the various traffic.
|
||||||
|
void CheckHoldList(double dt);
|
||||||
|
void CheckCircuitList(double dt);
|
||||||
void CheckRunwayList(double dt);
|
void CheckRunwayList(double dt);
|
||||||
|
|
||||||
void CheckApproachList(double dt);
|
void CheckApproachList(double dt);
|
||||||
|
void CheckDepartureList(double dt);
|
||||||
|
|
||||||
// Currently this assumes we *are* next on the runway and doesn't check for planes about to land -
|
// Currently this assumes we *are* next on the runway and doesn't check for planes about to land -
|
||||||
// this should be done prior to calling this function.
|
// this should be done prior to calling this function.
|
||||||
|
@ -199,6 +208,9 @@ private:
|
||||||
// Find a pointer to plane of callsign ID within the internal data structures
|
// Find a pointer to plane of callsign ID within the internal data structures
|
||||||
TowerPlaneRec* FindPlane(string ID);
|
TowerPlaneRec* FindPlane(string ID);
|
||||||
|
|
||||||
|
// Remove and delete all instances of a plane with a given ID
|
||||||
|
void RemovePlane(string ID);
|
||||||
|
|
||||||
// Figure out if a given position lies on the active runway
|
// Figure out if a given position lies on the active runway
|
||||||
// Might have to change when we consider more than one active rwy.
|
// Might have to change when we consider more than one active rwy.
|
||||||
bool OnActiveRunway(Point3D pt);
|
bool OnActiveRunway(Point3D pt);
|
||||||
|
@ -292,8 +304,14 @@ private:
|
||||||
tower_plane_rec_list_type trafficList; // TODO - needs to be expandable to more than one rwy
|
tower_plane_rec_list_type trafficList; // TODO - needs to be expandable to more than one rwy
|
||||||
tower_plane_rec_list_iterator trafficListItr;
|
tower_plane_rec_list_iterator trafficListItr;
|
||||||
|
|
||||||
|
// List of planes that have vacated the runway inbound but not yet handed off to ground
|
||||||
|
tower_plane_rec_list_type vacatedList;
|
||||||
|
tower_plane_rec_list_iterator vacatedListItr;
|
||||||
|
|
||||||
// Returns true if successful
|
// Returns true if successful
|
||||||
bool RemoveFromTrafficList(string id);
|
bool RemoveFromTrafficList(string id);
|
||||||
|
bool RemoveFromAppList(string id);
|
||||||
|
bool RemoveFromRwyList(string id);
|
||||||
|
|
||||||
// Return the ETA of plane no. list_pos (1-based) in the traffic list.
|
// Return the ETA of plane no. list_pos (1-based) in the traffic list.
|
||||||
// i.e. list_pos = 1 implies next to use runway.
|
// i.e. list_pos = 1 implies next to use runway.
|
||||||
|
@ -311,6 +329,9 @@ private:
|
||||||
bool separateGround; // true if ground control is separate
|
bool separateGround; // true if ground control is separate
|
||||||
FGGround* ground; // The ground control associated with this airport.
|
FGGround* ground; // The ground control associated with this airport.
|
||||||
|
|
||||||
|
bool _departureControlled; // true if we need to hand off departing traffic to departure control
|
||||||
|
//FGDeparture* _departure; // The relevant departure control (once we've actually written it!)
|
||||||
|
|
||||||
// for failure modeling
|
// for failure modeling
|
||||||
string trans_ident; // transmitted ident
|
string trans_ident; // transmitted ident
|
||||||
bool tower_failed; // tower failed?
|
bool tower_failed; // tower failed?
|
||||||
|
|
Loading…
Add table
Reference in a new issue