#endif
#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <boost/foreach.hpp>
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/debug/logstream.hxx>
-#include <simgear/route/waypoint.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Airports/runways.hxx>
+#include <ATCDCL/ATCutils.hxx>
-#include <string>
-#include <vector>
+#include "simple.hxx"
+#include "dynamics.hxx"
using std::string;
using std::vector;
using std::sort;
using std::random_shuffle;
-#include "simple.hxx"
-#include "dynamics.hxx"
-
FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
-_ap(ap), rwyPrefs(ap), SIDs(ap)
-{
- lastUpdate = 0;
-
- // For testing only. This needs to be refined when we move ATIS functionality over.
- atisInformation = "Sierra";
-}
+ _ap(ap), rwyPrefs(ap),
+ startupController (this),
+ towerController (this),
+ approachController (this),
+ atisSequenceIndex(-1),
+ atisSequenceTimeStamp(0.0)
-// Note that the ground network should also be copied
-FGAirportDynamics::
-FGAirportDynamics(const FGAirportDynamics & other):rwyPrefs(other.
- rwyPrefs),
-SIDs(other.SIDs)
{
- for (FGParkingVecConstIterator ip = other.parkings.begin();
- ip != other.parkings.end(); ip++)
- parkings.push_back(*(ip));
- // rwyPrefs = other.rwyPrefs;
- lastUpdate = other.lastUpdate;
-
- stringVecConstIterator il;
- for (il = other.landing.begin(); il != other.landing.end(); il++)
- landing.push_back(*il);
- for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
- takeoff.push_back(*il);
- lastUpdate = other.lastUpdate;
- atisInformation = other.atisInformation;
+ lastUpdate = 0;
}
// Destructor
random_shuffle(parkings.begin(), parkings.end());
sort(parkings.begin(), parkings.end());
// add the gate positions to the ground network.
+ groundNetwork.setParent(_ap);
groundNetwork.addNodes(&parkings);
groundNetwork.init();
groundNetwork.setTowerController(&towerController);
- groundNetwork.setParent(_ap);
+
}
-bool FGAirportDynamics::getAvailableParking(double *lat, double *lon,
- double *heading, int *gateId,
- double rad,
- const string & flType,
- const string & acType,
- const string & airline)
+int FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
+ const string & acType,
+ const string & airline,
+ bool skipEmptyAirlineCode)
{
- bool found = false;
- bool available = false;
-
-
- FGParkingVecIterator i;
- if (parkings.begin() == parkings.end()) {
- //cerr << "Could not find parking spot at " << _ap->getId() << endl;
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- found = true;
- } else {
- // First try finding a parking with a designated airline code
- for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
- available = true;
- // Taken by another aircraft
- if (!(i->isAvailable())) {
- available = false;
- continue;
- }
- // No airline codes, so skip
- if (i->getCodes().empty()) {
- available = false;
- continue;
- } else { // Airline code doesn't match
- //cerr << "Code = " << airline << ": Codes " << i->getCodes();
- if (i->getCodes().find(airline, 0) == string::npos) {
- available = false;
- //cerr << "Unavailable" << endl;
- continue;
- } else {
- //cerr << "Available" << endl;
- }
- }
- // Type doesn't match
- if (i->getType() != flType) {
- available = false;
- continue;
- }
- // too small
- if (i->getRadius() < rad) {
- available = false;
- continue;
- }
-
- if (available) {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getHeading();
- *gateId = i->getIndex();
- i->setAvailable(false);
- found = true;
- }
- }
- // then try again for those without codes.
- for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
- available = true;
- if (!(i->isAvailable())) {
- available = false;
- continue;
- }
- if (!(i->getCodes().empty())) {
- if ((i->getCodes().find(airline, 0) == string::npos)) {
- available = false;
- continue;
- }
- }
- if (i->getType() != flType) {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad) {
- available = false;
- continue;
- }
-
- if (available) {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getHeading();
- *gateId = i->getIndex();
- i->setAvailable(false);
- found = true;
- }
- }
- // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
- for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
- available = true;
- if (!(i->isAvailable())) {
- available = false;
- continue;
- }
- if (i->getType() != flType) {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad) {
- available = false;
- continue;
- }
-
- if (available) {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getHeading();
- *gateId = i->getIndex();
- i->setAvailable(false);
- found = true;
- }
- }
+ BOOST_FOREACH(FGParking* i, parkings) {
+ // Taken by another aircraft, or no airline codes
+ if (!i->isAvailable()) {
+ continue;
}
- if (!found) {
- //cerr << "Traffic overflow at" << _ap->getId()
- // << ". flType = " << flType
- // << ". airline = " << airline
- // << " Radius = " <<rad
- // << endl;
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- *gateId = -1;
- //exit(1);
+
+ if (skipEmptyAirlineCode && i->getCodes().empty()) {
+ continue;
}
- return found;
+
+ // check airline codes match
+ if (!airline.empty() && !i->getCodes().empty()) {
+ if (i->getCodes().find(airline, 0) == string::npos) {
+ continue;
+ }
+ }
+
+ // Type doesn't match
+ if (i->getType() != flType) {
+ continue;
+ }
+ // too small
+ if (i->getRadius() < radius) {
+ continue;
+ }
+
+ i->setAvailable(false);
+ return i->getIndex();
+ }
+
+ return -1;
}
-void FGAirportDynamics::getParking(int id, double *lat, double *lon,
- double *heading)
+int FGAirportDynamics::getAvailableParking(double radius, const string & flType,
+ const string & acType,
+ const string & airline)
{
- if (id < 0) {
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- } else {
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++) {
- if (id == i->getIndex()) {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getHeading();
- }
- }
+ if (parkings.empty()) {
+ return -1;
}
+
+ // most exact seach - airline codes must be present and match
+ int result = innerGetAvailableParking(radius, flType, acType, airline, true);
+ if (result >= 0) {
+ return result;
+ }
+
+ // more tolerant - gates with empty airline codes are permitted
+ result = innerGetAvailableParking(radius, flType, acType, airline, false);
+ if (result >= 0) {
+ return result;
+ }
+
+ // fallback - ignore the airline code entirely
+ return innerGetAvailableParking(radius, flType, acType, string(), false);
}
FGParking *FGAirportDynamics::getParking(int id)
{
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++) {
- if (id == i->getIndex()) {
- return &(*i);
- }
+ BOOST_FOREACH(FGParking* i, parkings) {
+ if (id == i->getIndex()) {
+ return i;
}
- return 0;
+ }
+
+ return NULL;
}
string FGAirportDynamics::getParkingName(int id)
{
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++) {
- if (id == i->getIndex()) {
- return i->getName();
- }
+ FGParking* p = getParking(id);
+ if (p) {
+ return p->getName();
+ }
+
+ return string();
+}
+
+int FGAirportDynamics::findParkingByName(const std::string& name) const
+{
+ BOOST_FOREACH(FGParking* i, parkings) {
+ if (name == i->getName()) {
+ return i->getIndex();
}
+ }
- return string("overflow");
+ return -1;
}
void FGAirportDynamics::releaseParking(int id)
{
if (id >= 0) {
-
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++) {
- if (id == i->getIndex()) {
- i->setAvailable(true);
- }
- }
+ FGParking* parking = getParking(id);
+ if (parking) {
+ parking->setAvailable(true);
+ }
}
}
void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
{
rwyPrefs = ref;
- //cerr << "Exiting due to not implemented yet" << endl;
- //exit(1);
}
bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
return rwy->ident();
}
-void FGAirportDynamics::addParking(FGParking & park)
+void FGAirportDynamics::addParking(FGParking* park)
{
parkings.push_back(park);
}
-double FGAirportDynamics::getLatitude() const
-{
- return _ap->getLatitude();
-}
-
-double FGAirportDynamics::getLongitude() const
-{
- return _ap->getLongitude();
-}
-
double FGAirportDynamics::getElevation() const
{
return _ap->getElevation();
}
-const string & FGAirportDynamics::getId() const
+const string FGAirportDynamics::getId() const
{
return _ap->getId();
}
int FGAirportDynamics::getGroundFrequency(unsigned leg)
{
//return freqGround.size() ? freqGround[0] : 0; };
+ //cerr << "Getting frequency for : " << leg << endl;
int groundFreq = 0;
- if (leg < 2) {
+ if (leg < 1) {
SG_LOG(SG_ATC, SG_ALERT,
- "Leg value is smaller than two at " << SG_ORIGIN);
+ "Leg value is smaller than one at " << SG_ORIGIN);
}
if (freqGround.size() == 0) {
return 0;
}
- if ((freqGround.size() > leg - 1) && (leg > 1)) {
- groundFreq = freqGround[leg - 1];
- }
- if ((freqGround.size() < leg - 1) && (leg > 1)) {
+
+ if ((freqGround.size() < leg) && (leg > 0)) {
groundFreq =
- (freqGround.size() <
+ (freqGround.size() <=
(leg - 1)) ? freqGround[freqGround.size() -
- 1] : freqGround[leg - 2];
+ 1] : freqGround[leg - 1];
}
- if ((freqGround.size() >= leg - 1) && (leg > 1)) {
- groundFreq = freqGround[leg - 2];
+ if ((freqGround.size() >= leg) && (leg > 0)) {
+ groundFreq = freqGround[leg - 1];
}
return groundFreq;
}
return towerFreq;
}
+const std::string FGAirportDynamics::getAtisSequence()
+{
+ if (atisSequenceIndex == -1) {
+ updateAtisSequence(1, false);
+ }
+
+ return GetPhoneticLetter(atisSequenceIndex);
+}
-FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
- double heading)
+int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
{
- return SIDs.getBest(activeRunway, heading);
+ double now = globals->get_sim_time_sec();
+ if (atisSequenceIndex == -1) {
+ // first computation
+ atisSequenceTimeStamp = now;
+ atisSequenceIndex = rand() % LTRS; // random initial sequence letters
+ return atisSequenceIndex;
+ }
+
+ int steps = static_cast<int>((now - atisSequenceTimeStamp) / interval);
+ atisSequenceTimeStamp += (interval * steps);
+ if (forceUpdate && (steps == 0)) {
+ ++steps; // a "special" ATIS update is required
+ }
+
+ atisSequenceIndex = (atisSequenceIndex + steps) % LTRS;
+ // return a huge value if no update occurred
+ return (atisSequenceIndex + (steps ? 0 : LTRS*1000));
}