#include <simgear/debug/logstream.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
+#include <Main/locale.hxx>
#include <Airports/runways.hxx>
-#include <ATCDCL/ATCutils.hxx>
+#include <Airports/groundnetwork.hxx>
+#include <Navaids/NavDataCache.hxx>
-#include "simple.hxx"
+#include "airport.hxx"
#include "dynamics.hxx"
using std::string;
using std::sort;
using std::random_shuffle;
+class ParkingAssignment::ParkingAssignmentPrivate
+{
+public:
+ ParkingAssignmentPrivate(FGParking* pk, FGAirportDynamics* dyn) :
+ refCount(0),
+ parking(pk),
+ dynamics(dyn)
+ {
+ assert(pk);
+ assert(dyn);
+ retain(); // initial count of 1
+ }
+
+ ~ParkingAssignmentPrivate()
+ {
+ dynamics->releaseParking(parking);
+ }
+
+ void release()
+ {
+ if ((--refCount) == 0) {
+ delete this;
+ }
+ }
+
+ void retain()
+ {
+ ++refCount;
+ }
+
+ unsigned int refCount;
+ FGParkingRef parking;
+ FGAirportDynamicsRef dynamics;
+};
+
+ParkingAssignment::ParkingAssignment() :
+ _sharedData(NULL)
+{
+}
+
+ParkingAssignment::~ParkingAssignment()
+{
+ if (_sharedData) {
+ _sharedData->release();
+ }
+}
+
+ParkingAssignment::ParkingAssignment(FGParking* pk, FGAirportDynamics* dyn) :
+ _sharedData(NULL)
+{
+ if (pk) {
+ _sharedData = new ParkingAssignmentPrivate(pk, dyn);
+ }
+}
+
+ParkingAssignment::ParkingAssignment(const ParkingAssignment& aOther) :
+ _sharedData(aOther._sharedData)
+{
+ if (_sharedData) {
+ _sharedData->retain();
+ }
+}
+
+void ParkingAssignment::operator=(const ParkingAssignment& aOther)
+{
+ if (_sharedData == aOther._sharedData) {
+ return; // self-assignment, special case
+ }
+
+ if (_sharedData) {
+ _sharedData->release();
+ }
+
+ _sharedData = aOther._sharedData;
+ if (_sharedData) {
+ _sharedData->retain();
+ }
+}
+
+void ParkingAssignment::release()
+{
+ if (_sharedData) {
+ _sharedData->release();
+ _sharedData = NULL;
+ }
+}
+
+bool ParkingAssignment::isValid() const
+{
+ return (_sharedData != NULL);
+}
+
+FGParking* ParkingAssignment::parking() const
+{
+ return _sharedData ? _sharedData->parking.ptr() : NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
_ap(ap), rwyPrefs(ap),
startupController (this),
{
lastUpdate = 0;
+ groundNetwork.reset(new FGGroundNetwork);
}
// Destructor
FGAirportDynamics::~FGAirportDynamics()
{
+ SG_LOG(SG_AI, SG_INFO, "destroyed dynamics for:" << _ap->ident());
}
// Initialization required after XMLRead
void FGAirportDynamics::init()
{
- // This may seem a bit weird to first randomly shuffle the parkings
- // and then sort them again. However, parkings are sorted here by ascending
- // radius. Since many parkings have similar radii, with each radius class they will
- // still be allocated relatively systematically. Randomizing prior to sorting will
- // prevent any initial orderings to be destroyed, leading (hopefully) to a more
- // naturalistic gate assignment.
- 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->init(this);
+ groundController.setTowerController(&towerController);
+ groundController.init(this);
}
-int FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
- const string & acType,
+FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
const string & airline,
bool skipEmptyAirlineCode)
{
- BOOST_FOREACH(FGParking* i, parkings) {
- // Taken by another aircraft, or no airline codes
- if (!i->isAvailable()) {
- continue;
- }
-
- if (skipEmptyAirlineCode && i->getCodes().empty()) {
- continue;
- }
-
- // 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;
+ const FGParkingList& parkings(groundNetwork->allParkings());
+ FGParkingList::const_iterator it;
+ for (it = parkings.begin(); it != parkings.end(); ++it) {
+ FGParkingRef parking = *it;
+ if (!isParkingAvailable(parking)) {
+ continue;
+ }
+
+ if (skipEmptyAirlineCode && parking->getCodes().empty()) {
+ continue;
+ }
+
+ if (!airline.empty() && !parking->getCodes().empty()) {
+ if (parking->getCodes().find(airline, 0) == string::npos) {
+ continue;
+ }
+ }
+
+ setParkingAvailable(parking, false);
+ return parking;
}
-
- i->setAvailable(false);
- return i->getIndex();
- }
-
- return -1;
+
+ return NULL;
}
-int FGAirportDynamics::getAvailableParking(double radius, const string & flType,
+ParkingAssignment FGAirportDynamics::getAvailableParking(double radius, const string & flType,
const string & acType,
const string & airline)
{
- if (parkings.empty()) {
- return -1;
- }
+ SG_UNUSED(acType); // sadly not used at the moment
// most exact seach - airline codes must be present and match
- int result = innerGetAvailableParking(radius, flType, acType, airline, true);
- if (result >= 0) {
- return result;
+ FGParking* result = innerGetAvailableParking(radius, flType, airline, true);
+ if (result) {
+ return ParkingAssignment(result, this);
}
// more tolerant - gates with empty airline codes are permitted
- result = innerGetAvailableParking(radius, flType, acType, airline, false);
- if (result >= 0) {
- return result;
+ result = innerGetAvailableParking(radius, flType, airline, false);
+ if (result) {
+ return ParkingAssignment(result, this);
}
// fallback - ignore the airline code entirely
- return innerGetAvailableParking(radius, flType, acType, string(), false);
+ result = innerGetAvailableParking(radius, flType, string(), false);
+ return result ? ParkingAssignment(result, this) : ParkingAssignment();
}
-FGParking *FGAirportDynamics::getParking(int id)
+ParkingAssignment FGAirportDynamics::getParkingByName(const std::string& name) const
{
- BOOST_FOREACH(FGParking* i, parkings) {
- if (id == i->getIndex()) {
- return i;
+ const FGParkingList& parkings(groundNetwork->allParkings());
+ FGParkingList::const_iterator it;
+ for (it = parkings.begin(); it != parkings.end(); ++it) {
+ if ((*it)->name() == name) {
+ return ParkingAssignment(*it, const_cast<FGAirportDynamics*>(this));
+ }
}
- }
-
- return NULL;
+
+ return ParkingAssignment();
}
-string FGAirportDynamics::getParkingName(int id)
+void FGAirportDynamics::setParkingAvailable(FGParking* park, bool available)
{
- FGParking* p = getParking(id);
- if (p) {
- return p->getName();
+ if (available) {
+ releaseParking(park);
+ } else {
+ occupiedParkings.insert(park);
}
-
- return string();
}
-int FGAirportDynamics::findParkingByName(const std::string& name) const
+bool FGAirportDynamics::isParkingAvailable(FGParking* parking) const
{
- BOOST_FOREACH(FGParking* i, parkings) {
- if (name == i->getName()) {
- return i->getIndex();
- }
- }
+ return (occupiedParkings.find(parking) == occupiedParkings.end());
+}
- return -1;
+void FGAirportDynamics::releaseParking(FGParking* id)
+{
+ ParkingSet::iterator it = occupiedParkings.find(id);
+ if (it == occupiedParkings.end()) {
+ return;
+ }
+
+ occupiedParkings.erase(it);
}
-void FGAirportDynamics::releaseParking(int id)
+class GetParkingsPredicate
{
- if (id >= 0) {
- FGParking* parking = getParking(id);
- if (parking) {
- parking->setAvailable(true);
- }
+ bool mustBeAvailable;
+ std::string type;
+ const FGAirportDynamics* dynamics;
+public:
+ GetParkingsPredicate(bool b, const std::string& ty, const FGAirportDynamics* dyn) :
+ mustBeAvailable(b),
+ type(ty),
+ dynamics(dyn)
+ {}
+
+ bool operator()(const FGParkingRef& park) const
+ {
+ if (!type.empty() && (park->getType() != type))
+ return true;
+
+ if (mustBeAvailable && !dynamics->isParkingAvailable(park)) {
+ return true;
+ }
+
+ return false;
}
+};
+
+FGParkingList FGAirportDynamics::getParkings(bool onlyAvailable, const std::string &type) const
+{
+ FGParkingList result(groundNetwork->allParkings());
+
+ GetParkingsPredicate pred(onlyAvailable, type, this);
+ FGParkingList::iterator it = std::remove_if(result.begin(), result.end(), pred);
+ result.erase(it, result.end());
+ return result;
}
void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
RunwayGroup *currRunwayGroup = 0;
int nrActiveRunways = 0;
time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
- if ((abs((long) (dayStart - lastUpdate)) > 600)
+ if ((std::abs((long) (dayStart - lastUpdate)) > 600)
|| trafficType != prevTrafficType) {
landing.clear();
takeoff.clear();
return rwy->ident();
}
-void FGAirportDynamics::addParking(FGParking* park)
-{
- parkings.push_back(park);
-}
-
double FGAirportDynamics::getElevation() const
{
return _ap->getElevation();
if (atisSequenceIndex == -1) {
updateAtisSequence(1, false);
}
+
+ char atisSequenceString[2];
+ atisSequenceString[0] = 'a' + atisSequenceIndex;
+ atisSequenceString[1] = 0;
- return GetPhoneticLetter(atisSequenceIndex);
+ return globals->get_locale()->getLocalizedString(atisSequenceString, "atc", "unknown");
}
int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
if (atisSequenceIndex == -1) {
// first computation
atisSequenceTimeStamp = now;
- atisSequenceIndex = rand() % LTRS; // random initial sequence letters
+ atisSequenceIndex = rand() % 26; // random initial sequence letters
return atisSequenceIndex;
}
++steps; // a "special" ATIS update is required
}
- atisSequenceIndex = (atisSequenceIndex + steps) % LTRS;
+ atisSequenceIndex = (atisSequenceIndex + steps) % 26;
// return a huge value if no update occurred
- return (atisSequenceIndex + (steps ? 0 : LTRS*1000));
+ return (atisSequenceIndex + (steps ? 0 : 26*1000));
}