]> git.mxchange.org Git - flightgear.git/blobdiff - src/Airports/dynamics.cxx
httpd: provide more airport information in geojson
[flightgear.git] / src / Airports / dynamics.cxx
index 21d45d08be4296056321b0aa59ed221545d052bb..5916c68b0645080e0933249d3833bb040bfb7cb7 100644 (file)
 #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 <Navaids/NavDataCache.hxx>
 
-#include "simple.hxx"
+#include "airport.hxx"
 #include "dynamics.hxx"
 
 using std::string;
@@ -49,6 +50,105 @@ using std::vector;
 using std::sort;
 using std::random_shuffle;
 
+class ParkingAssignment::ParkingAssignmentPrivate
+{
+public:
+  ParkingAssignmentPrivate(FGParking* pk, FGAirport* apt) :
+    refCount(0),
+    parking(pk),
+    airport(apt)
+  {
+    assert(pk);
+    assert(apt);
+    retain(); // initial count of 1
+  }
+  
+  ~ParkingAssignmentPrivate()
+  {
+    airport->getDynamics()->releaseParking(parking->guid());
+  }
+  
+  void release()
+  {
+    if ((--refCount) == 0) {
+      delete this;
+    }
+  }
+  
+  void retain()
+  {
+    ++refCount;
+  }
+  
+  unsigned int refCount;
+  SGSharedPtr<FGParking> parking;
+  SGSharedPtr<FGAirport> airport;
+};
+
+ParkingAssignment::ParkingAssignment() :
+  _sharedData(NULL)
+{
+}
+
+ParkingAssignment::~ParkingAssignment()
+{
+  if (_sharedData) {
+    _sharedData->release();
+  }
+}
+  
+ParkingAssignment::ParkingAssignment(FGParking* pk, FGAirport* apt) :
+  _sharedData(NULL)
+{
+  if (pk) {
+    _sharedData = new ParkingAssignmentPrivate(pk, apt);
+  }
+}
+
+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),
@@ -70,131 +170,109 @@ FGAirportDynamics::~FGAirportDynamics()
 // 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.init(_ap);
     groundNetwork.setTowerController(&towerController);
     
 }
 
-int FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
-                                           const string & acType,
+FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
                                            const string & airline,
                                            bool skipEmptyAirlineCode)
 {
-  FGParkingVecIterator i;
-  for (i = parkings.begin(); i != parkings.end(); i++) {
-    // Taken by another aircraft, or no airline codes
-    if (!i->isAvailable()) {
+  flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+  BOOST_FOREACH(PositionedID pk, cache->findAirportParking(_ap->guid(), flType, radius)) {
+    if (!isParkingAvailable(pk)) {
       continue;
     }
     
-    if (skipEmptyAirlineCode && i->getCodes().empty()) {
+    FGParking* parking = getParking(pk);
+    if (skipEmptyAirlineCode && parking->getCodes().empty()) {
       continue;
     }
     
-    // check airline codes match
-    if (!airline.empty() && !i->getCodes().empty()) {
-      if (i->getCodes().find(airline, 0) == string::npos) {
+    if (!airline.empty() && !parking->getCodes().empty()) {
+      if (parking->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();
+    setParkingAvailable(pk, false);
+    return parking;
   }
   
-  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, _ap);
   }
   
   // 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, _ap);
   }
 
   // fallback - ignore the airline code entirely
-  return innerGetAvailableParking(radius, flType, acType, string(), false);
+  result = innerGetAvailableParking(radius, flType, string(), false);
+  return result ? ParkingAssignment(result, _ap) : ParkingAssignment();
 }
 
-FGParking *FGAirportDynamics::getParking(int id)
+FGParkingRef FGAirportDynamics::getParking(PositionedID id) const
 {
-    FGParkingVecIterator i = parkings.begin();
-    for (i = parkings.begin(); i != parkings.end(); i++) {
-        if (id == i->getIndex()) {
-            return &(*i);
-        }
-    }
-    return 0;
+  return FGPositioned::loadById<FGParking>(id);
 }
 
-string FGAirportDynamics::getParkingName(int id)
+string FGAirportDynamics::getParkingName(PositionedID id) const
 {
-    FGParkingVecIterator i = parkings.begin();
-    for (i = parkings.begin(); i != parkings.end(); i++) {
-        if (id == i->getIndex()) {
-            return i->getName();
-        }
-    }
-
-    return string("overflow");
+  FGParking* p = getParking(id);
+  if (p) {
+    return p->getName();
+  }
+  
+  return string();
 }
 
-int FGAirportDynamics::findParkingByName(const std::string& name) const
+ParkingAssignment FGAirportDynamics::getParkingByName(const std::string& name) const
 {
-  FGParkingVec::const_iterator i = parkings.begin();
-  for (i = parkings.begin(); i != parkings.end(); i++) {
-    if (i->getName() == name) {
-      return i->getIndex();
-    }
+  PositionedID guid = flightgear::NavDataCache::instance()->airportItemWithIdent(parent()->guid(), FGPositioned::PARKING, name);
+  if (guid == 0) {
+    return ParkingAssignment();
   }
   
-  return -1;
+  return ParkingAssignment(getParking(guid), _ap);
 }
 
-void FGAirportDynamics::releaseParking(int id)
+void FGAirportDynamics::setParkingAvailable(PositionedID guid, bool available)
 {
-    if (id >= 0) {
+  if (available) {
+    releaseParking(guid);
+  } else {
+    occupiedParkings.insert(guid);
+  }
+}
 
-        FGParkingVecIterator i = parkings.begin();
-        for (i = parkings.begin(); i != parkings.end(); i++) {
-            if (id == i->getIndex()) {
-                i->setAvailable(true);
-            }
-        }
-    }
+bool FGAirportDynamics::isParkingAvailable(PositionedID parking) const
+{
+  return (occupiedParkings.find(parking) == occupiedParkings.end());
+}
+
+void FGAirportDynamics::releaseParking(PositionedID id)
+{
+  ParkingSet::iterator it = occupiedParkings.find(id);
+  if (it == occupiedParkings.end()) {
+    return;
+  }
+  
+  occupiedParkings.erase(it);
 }
 
 void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
@@ -380,11 +458,6 @@ string FGAirportDynamics::chooseRunwayFallback()
     return rwy->ident();
 }
 
-void FGAirportDynamics::addParking(FGParking & park)
-{
-    parkings.push_back(park);
-}
-
 double FGAirportDynamics::getElevation() const
 {
     return _ap->getElevation();
@@ -457,8 +530,12 @@ 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)
@@ -467,7 +544,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;
     }
 
@@ -477,7 +554,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));
 }