]> git.mxchange.org Git - flightgear.git/blobdiff - src/Airports/dynamics.cxx
Interim windows build fix
[flightgear.git] / src / Airports / dynamics.cxx
index 293d2ff6a5682756478a7d0f472af9db1de39fdb..fae2add25c63734d2089921d669006b78a0a2d00 100644 (file)
 #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 <Main/locale.hxx>
 #include <Airports/runways.hxx>
-#include <ATCDCL/ATCutils.hxx>
+#include <Airports/groundnetwork.hxx>
+#include <Navaids/NavDataCache.hxx>
 
-#include <string>
-#include <vector>
+#include "airport.hxx"
+#include "dynamics.hxx"
 
 using std::string;
 using std::vector;
 using std::sort;
 using std::random_shuffle;
 
-#include "simple.hxx"
-#include "dynamics.hxx"
+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), SIDs(ap),
-        startupController    (this),
+    _ap(ap), rwyPrefs(ap),
+    startupController    (this),
     towerController      (this),
     approachController   (this),
     atisSequenceIndex(-1),
@@ -59,228 +160,152 @@ FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
 
 {
     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);
 }
 
-bool FGAirportDynamics::getAvailableParking(double *lat, double *lon,
-                                            double *heading, int *gateId,
-                                            double rad,
-                                            const string & flType,
-                                            const string & acType,
-                                            const string & airline)
+FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
+                                           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;
-            }
+    const FGParkingList& parkings(groundNetwork->allParkings());
+    FGParkingList::const_iterator it;
+    for (it = parkings.begin(); it != parkings.end(); ++it) {
+        FGParkingRef parking = *it;
+        if (!isParkingAvailable(parking)) {
+          continue;
         }
-        // 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;
-            }
+        if (skipEmptyAirlineCode && parking->getCodes().empty()) {
+          continue;
         }
-        // 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;
-            }
+        if (!airline.empty() && !parking->getCodes().empty()) {
+          if (parking->getCodes().find(airline, 0) == string::npos) {
+            continue;
+          }
         }
+
+        setParkingAvailable(parking, false);
+        return parking;
     }
-    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);
-    }
-    return found;
+
+    return NULL;
 }
 
-void FGAirportDynamics::getParking(int id, double *lat, double *lon,
-                                   double *heading)
+ParkingAssignment 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();
-            }
-        }
-    }
+  SG_UNUSED(acType); // sadly not used at the moment
+  
+  // most exact seach - airline codes must be present and match
+  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, airline, false);
+  if (result) {
+    return ParkingAssignment(result, this);
+  }
+
+  // fallback - ignore the airline code entirely
+  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
 {
-    FGParkingVecIterator i = parkings.begin();
-    for (i = parkings.begin(); i != parkings.end(); i++) {
-        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 0;
+
+  return ParkingAssignment();
 }
 
-string FGAirportDynamics::getParkingName(int id)
+void FGAirportDynamics::setParkingAvailable(FGParking* park, bool available)
 {
-    FGParkingVecIterator i = parkings.begin();
-    for (i = parkings.begin(); i != parkings.end(); i++) {
-        if (id == i->getIndex()) {
-            return i->getName();
-        }
-    }
+  if (available) {
+    releaseParking(park);
+  } else {
+    occupiedParkings.insert(park);
+  }
+}
 
-    return string("overflow");
+bool FGAirportDynamics::isParkingAvailable(FGParking* parking) const
+{
+  return (occupiedParkings.find(parking) == occupiedParkings.end());
 }
 
-void FGAirportDynamics::releaseParking(int id)
+void FGAirportDynamics::releaseParking(FGParking* id)
 {
-    if (id >= 0) {
+  ParkingSet::iterator it = occupiedParkings.find(id);
+  if (it == occupiedParkings.end()) {
+    return;
+  }
+  
+  occupiedParkings.erase(it);
+}
 
-        FGParkingVecIterator i = parkings.begin();
-        for (i = parkings.begin(); i != parkings.end(); i++) {
-            if (id == i->getIndex()) {
-                i->setAvailable(true);
-            }
+class GetParkingsPredicate
+{
+    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)
 {
     rwyPrefs = ref;
-    //cerr << "Exiting due to not implemented yet" << endl;
-    //exit(1);
 }
 
 bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
@@ -301,7 +326,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
     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();
@@ -461,27 +486,12 @@ string FGAirportDynamics::chooseRunwayFallback()
     return rwy->ident();
 }
 
-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();
 }
@@ -543,20 +553,17 @@ int FGAirportDynamics::getTowerFrequency(unsigned nr)
     return towerFreq;
 }
 
-
-FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
-                                          double heading)
-{
-    return SIDs.getBest(activeRunway, heading);
-}
-
 const std::string FGAirportDynamics::getAtisSequence()
 {
    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)
@@ -565,7 +572,7 @@ 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;
     }
 
@@ -575,7 +582,7 @@ int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
         ++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));
 }