]> git.mxchange.org Git - flightgear.git/commitdiff
Overhaul the ground-net / parking code.
authorJames Turner <zakalawe@mac.com>
Mon, 1 Oct 2012 16:18:36 +0000 (17:18 +0100)
committerJames Turner <zakalawe@mac.com>
Thu, 8 Nov 2012 09:07:05 +0000 (09:07 +0000)
Use the nav-data-cache to cache groundnet information, including
parking positions and the taxi-node graph.

26 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIFlightPlanCreate.cxx
src/AIModel/AIFlightPlanCreatePushBack.cxx
src/AIModel/performancedata.cxx
src/AIModel/performancedata.hxx
src/ATC/atc_mgr.cxx
src/ATC/trafficcontrol.cxx
src/Airports/dynamicloader.cxx
src/Airports/dynamicloader.hxx
src/Airports/dynamics.cxx
src/Airports/dynamics.hxx
src/Airports/gnnode.cxx
src/Airports/gnnode.hxx
src/Airports/groundnetwork.cxx
src/Airports/groundnetwork.hxx
src/Airports/parking.cxx
src/Airports/parking.hxx
src/Airports/simple.cxx
src/Airports/xmlloader.cxx
src/Main/positioninit.cxx
src/Navaids/NavDataCache.cxx
src/Navaids/NavDataCache.hxx
src/Navaids/positioned.hxx
src/Scripting/NasalPositioned.cxx

index 2db78de6d9a1e841179537c892293e32570e18a4..4f02828fba4008057d0d779988b2e1fe16280f9b 100644 (file)
@@ -862,7 +862,8 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
     //cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl;
     //cerr << "Passing waypoint : " << prev->getName() << endl;
     if (prev->contains("PushBackPoint")) {
-        dep->getDynamics()->releaseParking(fp->getGate());
+      // clearing the parking assignment will release the gate
+        fp->setGate(ParkingAssignment());
         AccelTo(0.0);
         //setTaxiClearanceRequest(true);
     }
@@ -1209,18 +1210,15 @@ void FGAIAircraft::updatePitchAngleTarget() {
     }
 }
 
-string FGAIAircraft::atGate() {
-     string tmp("");
-     if (fp->getLeg() < 3) {
-         if (trafficRef) {
-             if (fp->getGate() > 0) {
-                 FGParking *park =
-                     trafficRef->getDepartureAirport()->getDynamics()->getParking(fp->getGate());
-                 tmp = park->getName();
-             }
-         }
+string FGAIAircraft::atGate()
+{
+     if ((fp->getLeg() < 3) && trafficRef) {
+       if (fp->getParkingGate()) {
+         return fp->getParkingGate()->ident();
+       }
      }
-     return tmp;
+       
+     return string();
 }
 
 void FGAIAircraft::handleATCRequests() {
index 14c4de1acf3036654af47a8788a85fee5edc9b71..df5cbf64fbfd990a563a13a0e4cdacad57e2a8cf 100644 (file)
@@ -105,9 +105,8 @@ FGAIFlightPlan::FGAIFlightPlan()
     start_time      = 0;
     arrivalTime     = 0;
     leg             = 10;
-    gateId          = 0;
     lastNodeVisited = 0;
-    taxiRoute       = 0;
+  //  taxiRoute       = 0;
     wpt_iterator    = waypoints.begin();
     isValid         = true;
 }
@@ -121,9 +120,8 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
   start_time        = 0;
   arrivalTime       = 0;
   leg               = 10;
-  gateId            = 0;
   lastNodeVisited   = 0;
-  taxiRoute         = 0;
+//  taxiRoute         = 0;
 
 
   isValid = parseProperties(filename);
@@ -161,9 +159,8 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
   start_time        = start;
   arrivalTime       = 0;
   leg               = 10;
-  gateId            = 0;
   lastNodeVisited   = 0;
-  taxiRoute         = 0;
// taxiRoute         = 0;
 
   if (parseProperties(p)) {
     isValid = true;
@@ -176,16 +173,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
 FGAIFlightPlan::~FGAIFlightPlan()
 {
   deleteWaypoints();
-  delete taxiRoute;
-
-// if we're parked at a gate, release it
-  if (gateId >= 0) {
-    FGAirport* apt = (leg >= 7) ? arrival : departure;
-    if (apt) {
-      SG_LOG(SG_AI, SG_INFO, "releasing parking gate " << gateId << " at " << apt->ident());
-      apt->getDynamics()->releaseParking(gateId);
-    }
-  }
+  //delete taxiRoute;
 }
 
 void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
@@ -227,7 +215,6 @@ void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
   isValid = create(ac, dep, arr, leg, alt, speed, lat, lon,
                    firstLeg, radius, fltType, acType, airline, dist);
   wpt_iterator = waypoints.begin();
 }
 
 bool FGAIFlightPlan::parseProperties(const std::string& filename)
@@ -454,14 +441,6 @@ void FGAIFlightPlan::restart()
   wpt_iterator = waypoints.begin();
 }
 
-
-void FGAIFlightPlan::deleteTaxiRoute() 
-{
-  delete taxiRoute;
-  taxiRoute = 0;
-}
-
-
 int FGAIFlightPlan::getRouteIndex(int i) {
   if ((i > 0) && (i < (int)waypoints.size())) {
     return waypoints[i]->getRouteIndex();
@@ -470,7 +449,6 @@ int FGAIFlightPlan::getRouteIndex(int i) {
     return 0;
 }
 
-
 double FGAIFlightPlan::checkTrackLength(string wptName) {
     // skip the first two waypoints: first one is behind, second one is partially done;
     double trackDistance = 0;
@@ -494,3 +472,13 @@ void FGAIFlightPlan::shortenToFirst(unsigned int number, string name)
     }
     (waypoints.back())->setName((waypoints.back())->getName() + name);
 }
+
+void FGAIFlightPlan::setGate(ParkingAssignment pka)
+{
+  gate = pka;
+}
+
+FGParking* FGAIFlightPlan::getParkingGate()
+{
+  return gate.parking();
+}
index 5b5586af1a1b36f352964dc7d0dcc34fbb6d4b3d..94476aa8dc49254747b4ddc9cca5abdd312a0ffb 100644 (file)
@@ -25,6 +25,8 @@
 #include <simgear/compiler.h>
 #include <simgear/math/SGMath.hxx>
 #include <simgear/structure/SGSharedPtr.hxx>
+#include <Navaids/positioned.hxx>
+#include <Airports/dynamics.hxx>
 
 // forward decls
 class FGTaxiRoute;
@@ -139,8 +141,7 @@ public:
 
   void setLeg(int val) { leg = val;}
   void setTime(time_t st) { start_time = st; }
-  int getGate() const { return gateId; }
-  void setGate(int id) { gateId = id; };
+
 
   double getLeadInAngle() const { return leadInAngle; }
   const std::string& getRunway() const;
@@ -149,9 +150,9 @@ public:
   bool getRepeat(void) const { return repeat; }
   void restart(void);
   int getNrOfWayPoints() { return waypoints.size(); }
-  int getRouteIndex(int i); // returns the AI related index of this current routes. 
-  FGTaxiRoute *getTaxiRoute() { return taxiRoute; }
-  void deleteTaxiRoute();
+
+  int getRouteIndex(int i); // returns the AI related index of this current routes.
+
   std::string getRunway() { return activeRunway; }
   bool isActive(time_t time) {return time >= this->getStartTime();}
 
@@ -172,6 +173,8 @@ public:
   
   void shortenToFirst(unsigned int number, std::string name);
 
+  void setGate(ParkingAssignment pka);
+  FGParking* getParkingGate();
 private:
   FGAIFlightPlan *sid;
   typedef std::vector <FGAIWaypoint*> wpt_vector_type;
@@ -188,9 +191,9 @@ private:
   time_t start_time;
   time_t arrivalTime;       // For AI/ATC purposes.
   int leg;
-  int gateId, lastNodeVisited;
+  ParkingAssignment gate;
+  PositionedID lastNodeVisited;
   std::string activeRunway;
-  FGTaxiRoute *taxiRoute;
   std::string name;
   bool isValid;
   FGAirportRef departure, arrival;
index 795aceadbe603422838d413f1668e9772f29c07d..92b901bcedc3efbfd12156b46290e6a6f68da4c0 100644 (file)
@@ -214,9 +214,9 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
     // and place the model at the location of the gate.
     if (firstFlight)
     {
-      gateId =  apt->getDynamics()->getAvailableParking(radius, fltType,
+      gate =  apt->getDynamics()->getAvailableParking(radius, fltType,
                                                         acType, airline);
-      if (gateId < 0) {
+      if (!gate.isValid()) {
         SG_LOG(SG_AI, SG_WARN, "Could not find parking for a " <<
                acType <<
                " of flight type " << fltType <<
@@ -245,7 +245,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
     }
 
     intVec ids;
-    int runwayId = 0;
+    PositionedID runwayId = 0;
     if (gn->getVersion() > 0) {
         runwayId = gn->findNearestNodeOnRunway(runwayTakeoff);
     } else {
@@ -256,75 +256,74 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
     // fallback mechanism for this. 
     // Starting from gate 0 in this case is a bit of a hack
     // which requires a more proper solution later on.
-    delete taxiRoute;
-    taxiRoute = new FGTaxiRoute;
+  //  delete taxiRoute;
+  //  taxiRoute = new FGTaxiRoute;
 
     // Determine which node to start from.
-    int node = 0;
+    PositionedID node = 0;
     // Find out which node to start from
-    FGParking *park = apt->getDynamics()->getParking(gateId);
+    FGParking *park = gate.parking();
     if (park) {
         node = park->getPushBackPoint();
-    }
-
-    if (node == -1) {
-        node = gateId;
-    }
-    // HAndle case where parking doens't have a node
-    if ((node == 0) && park) {
-        if (firstFlight) {
-            node = gateId;
-        } else {
-            node = lastNodeVisited;
+        if (node == -1) {
+            node = park->guid();
+        } else if (node == 0) {
+            // HAndle case where parking doens't have a node
+            if (firstFlight) {
+                node = park->guid();
+            } else {
+                node = lastNodeVisited;
+            }
         }
     }
-
-    *taxiRoute = gn->findShortestRoute(node, runwayId);
+    
+    FGTaxiRoute taxiRoute = gn->findShortestRoute(node, runwayId);
     intVecIterator i;
 
-    if (taxiRoute->empty()) {
+    if (taxiRoute.empty()) {
         createDefaultTakeoffTaxi(ac, apt, rwy);
         return true;
     }
 
-    taxiRoute->first();
+    taxiRoute.first();
     //bool isPushBackPoint = false;
     if (firstFlight) {
         // If this is called during initialization, randomly
         // skip a number of waypoints to get a more realistic
         // taxi situation.
-        int nrWaypointsToSkip = rand() % taxiRoute->size();
+        int nrWaypointsToSkip = rand() % taxiRoute.size();
         // but make sure we always keep two active waypoints
         // to prevent a segmentation fault
         for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
-            taxiRoute->next(&node);
+            taxiRoute.next(&node);
         }
-        apt->getDynamics()->releaseParking(gateId);
+        
+        gate.release(); // free up our gate as required
     } else {
-        if (taxiRoute->size() > 1) {
-            taxiRoute->next(&node);     // chop off the first waypoint, because that is already the last of the pushback route
+        if (taxiRoute.size() > 1) {
+            taxiRoute.next(&node);     // chop off the first waypoint, because that is already the last of the pushback route
         }
     }
 
     // push each node on the taxi route as a waypoint
-    int route;
+  //  int route;
     //cerr << "Building taxi route" << endl;
-    while (taxiRoute->next(&node, &route)) {
+    while (taxiRoute.next(&node)) {
         char buffer[10];
-        snprintf(buffer, 10, "%d", node);
+        snprintf(buffer, 10, "%lld", node);
         FGTaxiNode *tn =
             apt->getDynamics()->getGroundNetwork()->findNode(node);
         FGAIWaypoint *wpt =
             createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
                            ac->getPerformance()->vTaxi());
-        wpt->setRouteIndex(route);
+       // wpt->setRouteIndex(route);
         //cerr << "Nodes left " << taxiRoute->nodesLeft() << " ";
-        if (taxiRoute->nodesLeft() == 1) {
+        if (taxiRoute.nodesLeft() == 1) {
             // Note that we actually have hold points in the ground network, but this is just an initial test.
             //cerr << "Setting departurehold point: " << endl;
             wpt->setName( wpt->getName() + string("DepartureHold"));
         }
-        if (taxiRoute->nodesLeft() == 0) {
+        if (taxiRoute.nodesLeft() == 0) {
             wpt->setName(wpt->getName() + string("Accel"));
         }
         pushBackWaypoint(wpt);
@@ -356,9 +355,8 @@ void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
                        ac->getPerformance()->vTaxi());
     pushBackWaypoint(wpt);
 
-    FGParking* parkPos = aAirport->getDynamics()->getParking(gateId);
-    if (parkPos) {
-        wpt = createOnGround(ac, "ENDtaxi", parkPos->geod(), airportElev,
+    if (gate.isValid()) {
+        wpt = createOnGround(ac, "ENDtaxi", gate.parking()->geod(), airportElev,
                          ac->getPerformance()->vTaxi());
         pushBackWaypoint(wpt);
     }
@@ -370,12 +368,10 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
                                        const string & acType,
                                        const string & airline)
 {
-    gateId = apt->getDynamics()->getAvailableParking(radius, fltType,
+    gate = apt->getDynamics()->getAvailableParking(radius, fltType,
                                             acType, airline);
 
-    SGGeod lastWptPos =
-        SGGeod::fromDeg(waypoints.back()->getLongitude(),
-                        waypoints.back()->getLatitude());
+    SGGeod lastWptPos = waypoints.back()->getPos();
     FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
 
     // Find a route from runway end to parking/gate.
@@ -385,7 +381,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
     }
 
     intVec ids;
-    int runwayId = 0;
+    PositionedID runwayId = 0;
     if (gn->getVersion() == 1) {
         runwayId = gn->findNearestNodeOnRunway(lastWptPos);
     } else {
@@ -396,34 +392,35 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
     // fallback mechanism for this. 
     // Starting from gate 0 is a bit of a hack...
     //FGTaxiRoute route;
-    delete taxiRoute;
-    taxiRoute = new FGTaxiRoute;
-    if (gateId >= 0)
-        *taxiRoute = gn->findShortestRoute(runwayId, gateId);
+  //  delete taxiRoute;
+   // taxiRoute = new FGTaxiRoute;
+    FGTaxiRoute taxiRoute;
+    if (gate.isValid())
+        taxiRoute = gn->findShortestRoute(runwayId, gate.parking()->guid());
     else
-        *taxiRoute = gn->findShortestRoute(runwayId, 0);
+        taxiRoute = gn->findShortestRoute(runwayId, 0);
     intVecIterator i;
 
-    if (taxiRoute->empty()) {
+    if (taxiRoute.empty()) {
         createDefaultLandingTaxi(ac, apt);
         return true;
     }
 
-    int node;
-    taxiRoute->first();
-    int size = taxiRoute->size();
+    PositionedID node;
+    taxiRoute.first();
+    int size = taxiRoute.size();
     // Omit the last two waypoints, as 
     // those are created by createParking()
-    int route;
+   // int route;
     for (int i = 0; i < size - 2; i++) {
-        taxiRoute->next(&node, &route);
+        taxiRoute.next(&node);
         char buffer[10];
-        snprintf(buffer, 10, "%d", node);
+        snprintf(buffer, 10, "%lld", node);
         FGTaxiNode *tn = gn->findNode(node);
         FGAIWaypoint *wpt =
             createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
                            ac->getPerformance()->vTaxi());
-        wpt->setRouteIndex(route);
+       // wpt->setRouteIndex(route);
         pushBackWaypoint(wpt);
     }
     return true;
@@ -638,21 +635,20 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
         origin = current;
     }
 
-
     double dAlt = 0; //  = alt - (apt->getElevation() + 2000);
     FGTaxiNode * tn = 0;
     if (apt->getDynamics()->getGroundNetwork()) {
         int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
         tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
     }
+  
     if (tn) {
-        dAlt = alt - ((tn->getElevationFt(apt->getElevation())) + 2000);
+        dAlt = alt - ((tn->getElevationFt()) + 2000);
     } else {
         dAlt = alt - (apt->getElevation() + 2000);
     }
-
+  
     double nPoints = 100;
-
     char buffer[16];
 
     // The descent path contains the following phases:
@@ -814,7 +810,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
     //FGTaxiNode * tn = apt->getDynamics()->getGroundNetwork()->findNearestNode(initialTarget);
     double currentAltitude = 0;
     if (tn) {
-        currentAltitude = (tn->getElevationFt(apt->getElevation())) + 2000;
+        currentAltitude = (tn->getElevationFt()) + 2000;
     } else {
         currentAltitude = apt->getElevation() + 2000;
     }
@@ -906,12 +902,12 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
 {
     double vTouchdown = ac->getPerformance()->vTouchdown();
     double vTaxi      = ac->getPerformance()->vTaxi();
-    double decel     = ac->getPerformance()->deceleration() * 1.4;
+    double decel     = ac->getPerformance()->decelerationOnGround();
     double vApproach = ac->getPerformance()->vApproach();
   
-    double vTouchdownMetric = (vTouchdown  * SG_NM_TO_METER) / 3600;
-    double vTaxiMetric      = (vTaxi       * SG_NM_TO_METER) / 3600;
-    double decelMetric      = (decel       * SG_NM_TO_METER) / 3600;
+    double vTouchdownMetric = vTouchdown  * SG_KT_TO_MPS;
+    double vTaxiMetric      = vTaxi       * SG_KT_TO_MPS;
+    double decelMetric      = decel       * SG_KT_TO_MPS;
 
     char buffer[12];
     FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
@@ -996,15 +992,14 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
     double aptElev = apt->getElevation();
     double vTaxi = ac->getPerformance()->vTaxi();
     double vTaxiReduced = vTaxi * (2.0 / 3.0);
-    FGParking* parking = apt->getDynamics()->getParking(gateId);
-    if (!parking) {
+    if (!gate.isValid()) {
       wpt = createOnGround(ac, "END-Parking", apt->geod(), aptElev,
                            vTaxiReduced);
       pushBackWaypoint(wpt);
-
       return true;
     }
   
+    FGParking* parking = gate.parking();
     double heading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0);
     double az; // unused
     SGGeod pos;
index 7ebdd7af1e1d39c017c6885ca7570de07408ee4d..976463ccf74867e0396afe658fd41495627a4677 100644 (file)
@@ -49,7 +49,6 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
     double vTaxi = ac->getPerformance()->vTaxi();
     double vTaxiBackward = vTaxi * (-2.0/3.0);
     double vTaxiReduced  = vTaxi * (2.0/3.0);
-    FGTaxiRoute *pushBackRoute;
     // Active runway can be conditionally set by ATC, so at the start of a new flight, this
     // must be reset.
     activeRunway.clear();
@@ -63,9 +62,9 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
   
   // establish the parking position / gate if required
     if (firstFlight) {
-      gateId = dep->getDynamics()->getAvailableParking(radius, fltType,
+      gate = dep->getDynamics()->getAvailableParking(radius, fltType,
                                                        aircraftType, airline);
-      if (gateId < 0) {
+      if (!gate.isValid()) {
         SG_LOG(SG_AI, SG_WARN, "Warning: Could not find parking for a " <<
                aircraftType <<
                " of flight type " << fltType <<
@@ -73,47 +72,47 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
                " at airport     " << dep->getId());
         return false;
       }
-    } else {
-      dep->getDynamics()->getParking(gateId);
     }
   
-    if (gateId < 0) {
+    if (!gate.isValid()) {
         createPushBackFallBack(ac, firstFlight, dep,
                                radius, fltType, aircraftType, airline);
         return true;
 
     }
-
-    FGParking *parking = dep->getDynamics()->getParking(gateId);
-    int pushBackNode = parking->getPushBackPoint();
-
-    pushBackRoute = parking->getPushBackRoute();
-    if ((pushBackNode > 0) && (pushBackRoute == 0)) {  // Load the already established route for this gate
-        int node, rte;
-        FGTaxiRoute route;
-        //cerr << "Creating push-back for " << gateId << " (" << parking->getName() << ") using push-back point " << pushBackNode << endl;
-        route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, pushBackNode, false);
-        parking->setPushBackRoute(std::auto_ptr<FGTaxiRoute>(new FGTaxiRoute(route)));
-
-        pushBackRoute = parking->getPushBackRoute();
-        int size = pushBackRoute->size();
+  
+    FGGroundNetwork* groundNet = dep->getDynamics()->getGroundNetwork();
+    FGParking *parking = gate.parking();
+    if (parking && parking->getPushBackPoint() > 0) {
+        FGTaxiRoute route = groundNet->findShortestRoute(parking->guid(), parking->getPushBackPoint(), false);
+      
+        int size = route.size();
         if (size < 2) {
-            SG_LOG(SG_AI, SG_ALERT, "Push back route from gate " << gateId << " has only " << size << " nodes.");
-            SG_LOG(SG_AI, SG_ALERT, "Using  " << pushBackNode);
+            SG_LOG(SG_AI, SG_ALERT, "Push back route from gate " << parking->ident() << " has only " << size << " nodes.");
+            SG_LOG(SG_AI, SG_ALERT, "Using  " << parking->getPushBackPoint());
         }
-        pushBackRoute->first();
-        while (pushBackRoute->next(&node, &rte))
+        
+        route.first();
+        PositionedID node, previous= 0;
+      
+        while (route.next(&node))
         {
-            //FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findSegment(node)->getEnd();
             char buffer[10];
-            snprintf (buffer, 10, "%d", node);
-            FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
-            //ids.pop_back();
-            //wpt = new waypoint;
+            snprintf (buffer, 10, "%lld", node);
+            FGTaxiNode *tn = groundNet->findNode(node);
             FGAIWaypoint *wpt = createOnGround(ac, string(buffer), tn->geod(), dep->getElevation(), vTaxiBackward);
-
-            wpt->setRouteIndex(rte);
+          
+            if (previous) {
+              FGTaxiSegment* segment = groundNet->findSegment(previous, node);
+              wpt->setRouteIndex(segment->getIndex());
+            } else {
+              // not on the route yet, make up a unique segment ID
+              int x = (int) tn->guid();
+              wpt->setRouteIndex(x);
+            }
+          
             pushBackWaypoint(wpt);
+            previous = node;
         }
         // some special considerations for the last point:
         waypoints.back()->setName(string("PushBackPoint"));
@@ -123,36 +122,32 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
         ac->setTaxiClearanceRequest(false);
         double az2 = 0.0;
 
-        //cerr << "Creating final push forward point for gate " << gateId << endl;
-        FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(gateId);
-        // there aren't any routes for this parking.
-        // in cases like these we should flag the gate as being inoperative and return false
-        if (tn->arcs().empty()) {
-            SG_LOG(SG_AI, SG_ALERT, "Gate " << gateId << "doesn't seem to have routes associated with it.");
-            parking->setAvailable(false);
-            return false;
-        }
-      
-        FGTaxiSegment* pushForwardSegment = tn->arcs().front();
-        lastNodeVisited = pushForwardSegment->getEnd()->getIndex();
-        double distance = pushForwardSegment->getLength();
+      FGTaxiSegment* pushForwardSegment = dep->getDynamics()->getGroundNetwork()->findSegment(parking->guid(), 0);
+      // there aren't any routes for this parking.
+      if (!pushForwardSegment) {
+          SG_LOG(SG_AI, SG_ALERT, "Gate " << parking->ident() << "doesn't seem to have routes associated with it.");
+          return false;
+      }
 
-        double parkingHeading = parking->getHeading();
-      
-        for (int i = 1; i < 10; i++) {
-            SGGeod pushForwardPt;
-            SGGeodesy::direct(parking->geod(), parkingHeading,
-                              ((i / 10.0) * distance), pushForwardPt, az2);
-            char buffer[16];
-            snprintf(buffer, 16, "pushback-%02d", i);
-            FGAIWaypoint *wpt = createOnGround(ac, string(buffer), pushForwardPt, dep->getElevation(), vTaxiReduced);
-
-            wpt->setRouteIndex(pushForwardSegment->getIndex());
-            pushBackWaypoint(wpt);
-        }
-        // cerr << "Done " << endl;
-        waypoints.back()->setName(string("PushBackPoint"));
-        // cerr << "Done assinging new name" << endl;
+      lastNodeVisited = pushForwardSegment->getEnd()->getIndex();
+      double distance = pushForwardSegment->getLength();
+
+      double parkingHeading = parking->getHeading();
+    
+      for (int i = 1; i < 10; i++) {
+          SGGeod pushForwardPt;
+          SGGeodesy::direct(parking->geod(), parkingHeading,
+                            ((i / 10.0) * distance), pushForwardPt, az2);
+          char buffer[16];
+          snprintf(buffer, 16, "pushback-%02d", i);
+          FGAIWaypoint *wpt = createOnGround(ac, string(buffer), pushForwardPt, dep->getElevation(), vTaxiReduced);
+
+          wpt->setRouteIndex(pushForwardSegment->getIndex());
+          pushBackWaypoint(wpt);
+      }
+
+      waypoints.back()->setName(string("PushBackPoint"));
+      // cerr << "Done assinging new name" << endl;
     }
 
     return true;
index 8e5dfa9f317a354ef3703534a1578cd811502db4..80d62dba63416684dca90b2509c4b1818d909465 100644 (file)
@@ -107,6 +107,11 @@ double PerformanceData::actualSpeed(FGAIAircraft* ac, double tgt_speed, double d
     return speed;
 }
 
+double PerformanceData::decelerationOnGround() const
+{
+  return _deceleration * BRAKE_SETTING;
+}
+
 double PerformanceData::actualBankAngle(FGAIAircraft* ac, double tgt_roll, double dt) {
     // check maximum bank angle
     if (fabs(tgt_roll) > _maxbank)
index fd6deb53d6aea2e542cc2e01202a3a18ca1ba3c8..a8aef6400e3b46ec76585d8b54b3a50194b94c36 100644 (file)
@@ -46,6 +46,7 @@ public:
     inline double vTouchdown       () { return _vTouchdown; };
     inline double vCruise          () { return _vCruise; };
     
+    double decelerationOnGround() const;
 private:
     double _acceleration;
     double _deceleration;
index bbfc73311b52a41c9dd1b783372b5ffe03256fb7..28639c910a588de7e5a59ace17aa36b7114a4b43 100644 (file)
@@ -101,12 +101,11 @@ void FGATCManager::init() {
     FGAirport *apt = FGAirport::findByIdent(airport); 
     if (apt && onGround) {// && !runway.empty()) {
         FGAirportDynamics* dcs = apt->getDynamics();
-        int park_index = dcs->getNrOfParkings() - 1;
-        //cerr << "found information: " << runway << " " << airport << ": parking = " << parking << endl;
         fp = new FGAIFlightPlan;
-        while (park_index >= 0 && dcs->getParkingName(park_index) != parking) park_index--;
+        ParkingAssignment pk(dcs->getParkingByName(parking));
+      
         // No valid parking location, so either at the runway or at a random location.
-        if (parking.empty() || (park_index < 0)) {
+        if (!pk.isValid()) {
             if (!runway.empty()) {
                 controller = apt->getDynamics()->getTowerController();
                 int stationFreq = apt->getDynamics()->getTowerFrequency(2);
@@ -134,12 +133,11 @@ void FGATCManager::init() {
             leg = 1;
             //double, lat, lon, head; // Unused variables;
             //int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
-            FGParking* parking = dcs->getParking(park_index);
-            aircraftRadius = parking->getRadius();
-            string fltType = parking->getType(); // gate / ramp, ga, etc etc. 
+            aircraftRadius = pk.parking()->getRadius();
+            string fltType = pk.parking()->getType(); // gate / ramp, ga, etc etc.
             string aircraftType; // Unused.
             string airline;      // Currently used for gate selection, but a fallback mechanism will apply when not specified.
-            fp->setGate(park_index);
+            fp->setGate(pk);
             if (!(fp->createPushBack(&ai_ac,
                                false, 
                                apt, 
index c71dd034dcd6664ffddfb1b01c21941279890461..7f1596a0059de31a2018f5d99cdb375edbd4becb 100644 (file)
@@ -1363,7 +1363,7 @@ void FGStartupController::render(bool visible)
                     } else {
                         elevationStart = ((i)->getAircraft()->_getAltitude() * SG_FEET_TO_METER);
                     }
-                    double elevationEnd   = segment->getEnd()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
+                    double elevationEnd   = segment->getEnd()->getElevationM();
                     if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
                         SGGeod center2 = end;
                         center2.setElevationM(SG_MAX_ELEVATION_M);
@@ -1425,8 +1425,8 @@ void FGStartupController::render(bool visible)
                         obj_trans->setDataVariance(osg::Object::STATIC);
                         FGTaxiSegment *segment  = parent->getGroundNetwork()->findSegment(k);
 
-                        double elevationStart = segment->getStart()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
-                        double elevationEnd   = segment->getEnd  ()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
+                        double elevationStart = segment->getStart()->getElevationM();
+                        double elevationEnd   = segment->getEnd  ()->getElevationM();
                         if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
                             SGGeod center2 = segment->getStart()->geod();
                             center2.setElevationM(SG_MAX_ELEVATION_M);
index b79030a22be3d6d3480dccbe4db8e7257e0ea76e..bf3eeed70a1fd47ee5cb412acc2c416c5a154b72 100644 (file)
 
 #include <cstdlib>
 #include <cstring> // for strcmp
+#include <boost/foreach.hpp>
 
 #include "dynamicloader.hxx"
 
+#include <Navaids/NavDataCache.hxx>
+#include <Airports/dynamics.hxx>
+#include <Airports/simple.hxx>
+
 /*****************************************************************************
  * Helper function for parsing position string
  ****************************************************************************/
@@ -53,8 +58,25 @@ void  FGAirportDynamicsXMLLoader::startXML () {
   //cout << "FGAirportDynamicsLoader::Start XML" << endl;
 }
 
-void  FGAirportDynamicsXMLLoader::endXML () {
-  //cout << "End XML" << endl;
+void  FGAirportDynamicsXMLLoader::endXML ()
+{
+  std::map<PositionedID, int>::iterator it;
+  flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+  
+  for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
+    std::map<int, PositionedID>::iterator j = _idMap.find(it->second);
+    if (j == _idMap.end()) {
+      SG_LOG(SG_GENERAL, SG_WARN, "bad groundnet, no node for index:" << it->first);
+      continue;
+    }
+    
+    cache->setParkingPushBackRoute(it->first, j->second);
+  }
+  
+  BOOST_FOREACH(PositionedID id, _unreferencedNodes) {
+    SG_LOG(SG_GENERAL, SG_WARN, "unreferenced groundnet node:" << id);
+  }
+  
 }
 
 void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
@@ -100,10 +122,14 @@ void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
  
   SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
   
-  FGParking* pk = new FGParking(0, index, pos, heading, radius,
-                                gateName + gateNumber, type, airlineCodes);
-  pk->setPushBackPoint(pushBackRoute);
-  _dynamics->addParking(pk);
+  PositionedID guid = flightgear::NavDataCache::instance()->insertParking(gateName + gateNumber, pos,
+                                                      _dynamics->parent()->guid(),
+                                                      heading, radius, type, airlineCodes);
+  if (pushBackRoute > 0) {
+    _parkingPushbacks[guid] = pushBackRoute;
+  }
+  
+  _idMap[index] = guid;
 }
 
 void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
@@ -140,9 +166,15 @@ void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
     }
        }
   
+  if (_idMap.find(index) != _idMap.end()) {
+    SG_LOG(SG_GENERAL, SG_WARN, "duplicate ground-net index:" << index);
+  }
+  
   SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
-  FGTaxiNode* taxiNode = new FGTaxiNode(0, index, pos, onRunway, holdPointType);
-  _dynamics->getGroundNetwork()->addNode(taxiNode);
+  PositionedID guid = flightgear::NavDataCache::instance()->insertTaxiNode(pos,
+    _dynamics->parent()->guid(), holdPointType, onRunway);
+  _idMap[index] = guid;
+  _unreferencedNodes.insert(guid);
 }
 
 void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
@@ -161,7 +193,22 @@ void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
            isPushBackRoute = std::atoi(atts.getValue(i)) != 0;
        }
   
-  _dynamics->getGroundNetwork()->addSegment(new FGTaxiSegment(begin, end, isPushBackRoute));
+  IntPair e(begin, end);
+  if (_arcSet.find(e) != _arcSet.end()) {
+    SG_LOG(SG_GENERAL, SG_WARN, _dynamics->parent()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
+    return;
+  }
+  
+  _arcSet.insert(e);
+  flightgear::NavDataCache::instance()->insertGroundnetEdge(_dynamics->parent()->guid(),
+                                                            _idMap[begin], _idMap[end]);
+  
+  _unreferencedNodes.erase(_idMap[begin]);
+  _unreferencedNodes.erase(_idMap[end]);
+  
+  if (isPushBackRoute) {
+    flightgear::NavDataCache::instance()->markGroundnetAsPushback(_idMap[end]);
+  }
 }
 
 void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
index 0584d06ac25b3a67e5e85a79fde1a5bb2d82dcd1..b204e9bf1b266d8622aeef93acc1af140a1cd3f8 100644 (file)
@@ -19,6 +19,7 @@
 #include <simgear/xml/easyxml.hxx>
 
 #include "dynamics.hxx"
+#include <Navaids/positioned.hxx>
 
 class FGAirportDynamicsXMLLoader : public XMLVisitor {
 public:
@@ -41,6 +42,20 @@ private:
   
     FGAirportDynamics* _dynamics;
     string value;
+  
+    // map from local (groundnet.xml) to global (nav-cache) IDs for nodes
+    std::map<int, PositionedID> _idMap;
+  
+  // data integrity - watch for unreferenced nodes and duplicated edges
+    typedef std::pair<int, int> IntPair;
+    std::set<IntPair> _arcSet;
+  
+    std::set<PositionedID> _unreferencedNodes;
+  
+    // map from allocated parking position to its local push-back node
+    // used to defer binding the push-back node until we've processed
+    // all nodes
+    std::map<PositionedID, int> _parkingPushbacks;
 };
 
 #endif
index dde1983568d2520e0f8aab84f6d97d24fb22a7b6..d505d580c3d267bfddeabf1827d165c5994c9e87 100644 (file)
@@ -40,6 +40,7 @@
 #include <Main/fg_props.hxx>
 #include <Airports/runways.hxx>
 #include <ATCDCL/ATCutils.hxx>
+#include <Navaids/NavDataCache.hxx>
 
 #include "simple.hxx"
 #include "dynamics.hxx"
@@ -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,96 +170,68 @@ 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)
 {
-  BOOST_FOREACH(FGParking* i, parkings) {
-    // 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)
+FGParking *FGAirportDynamics::getParking(PositionedID id) const
 {
-  BOOST_FOREACH(FGParking* i, parkings) {
-    if (id == i->getIndex()) {
-      return i;
-    }
-  }
-  
-  return NULL;
+  return static_cast<FGParking*>(flightgear::NavDataCache::instance()->loadById(id));
 }
 
-string FGAirportDynamics::getParkingName(int id)
+string FGAirportDynamics::getParkingName(PositionedID id) const
 {
   FGParking* p = getParking(id);
   if (p) {
@@ -169,25 +241,38 @@ string FGAirportDynamics::getParkingName(int id)
   return string();
 }
 
-int FGAirportDynamics::findParkingByName(const std::string& name) const
+ParkingAssignment FGAirportDynamics::getParkingByName(const std::string& name) const
 {
-  BOOST_FOREACH(FGParking* i, parkings) {
-    if (name == i->getName()) {
-      return i->getIndex();
-    }
+  PositionedID guid = flightgear::NavDataCache::instance()->airportItemWithIdent(parent()->guid(), FGPositioned::PARKING, name);
+  if (guid == 0) {
+    return ParkingAssignment();
   }
+  
+  return ParkingAssignment(getParking(guid), _ap);
+}
 
-  return -1;
+void FGAirportDynamics::setParkingAvailable(PositionedID guid, bool available)
+{
+  if (available) {
+    releaseParking(guid);
+  } else {
+    occupiedParkings.insert(guid);
+  }
 }
 
-void FGAirportDynamics::releaseParking(int id)
+bool FGAirportDynamics::isParkingAvailable(PositionedID parking) const
 {
-    if (id >= 0) {
-      FGParking* parking = getParking(id);
-      if (parking) {
-        parking->setAvailable(true);
-      }
-    }
+  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)
@@ -373,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();
index 33481b12cbe6db3ded5bbd66fe5a4682b3c6956e..007c8a780d36f2933ac1974cb703dad11d101517 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef _AIRPORT_DYNAMICS_HXX_
 #define _AIRPORT_DYNAMICS_HXX_
 
+#include <set>
+
 #include <ATC/trafficcontrol.hxx>
 #include "parking.hxx"
 #include "groundnetwork.hxx"
 class FGAirport;
 class FGEnvironment;
 
+class ParkingAssignment
+{
+public:
+  ParkingAssignment();
+  ~ParkingAssignment();
+  
+// create a parking assignment (and mark it as unavailable)
+  ParkingAssignment(FGParking* pk, FGAirport* apt);
+  
+  ParkingAssignment(const ParkingAssignment& aOther);
+  void operator=(const ParkingAssignment& aOther);
+  
+  bool isValid() const;
+  FGParking* parking() const;
+  
+  void release();
+private:
+  void clear();
+
+  class ParkingAssignmentPrivate;
+  ParkingAssignmentPrivate* _sharedData;
+};
+
 class FGAirportDynamics {
 
 private:
     FGAirport* _ap;
 
-    FGParkingVec         parkings;
+    typedef std::set<PositionedID> ParkingSet;
+    // if a parking item is in this set, it is occupied
+    ParkingSet occupiedParkings;
+
     FGRunwayPreference   rwyPrefs;
     FGStartupController  startupController;
     FGGroundNetwork      groundNetwork;
@@ -63,8 +91,8 @@ private:
     bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
     std::string chooseRwyByHeading(stringVec rwys, double heading);
 
-  int innerGetAvailableParking(double radius, const std::string & flType,
-                               const std::string & acType, const std::string & airline,
+    FGParking* innerGetAvailableParking(double radius, const std::string & flType,
+                               const std::string & airline,
                                bool skipEmptyAirlineCode);
 public:
     FGAirportDynamics(FGAirport* ap);
@@ -98,28 +126,28 @@ public:
     { return _ap; }
   
     void getActiveRunway(const string& trafficType, int action, string& runway, double heading);
-
-    void addParking(FGParking* park);
     
     /**
      * retrieve an available parking by GateID, or -1 if no suitable
      * parking location could be found.
      */
-    int getAvailableParking(double radius, const std::string& fltype,
+    ParkingAssignment getAvailableParking(double radius, const std::string& fltype,
                           const std::string& acType, const std::string& airline);
 
-    FGParking *getParking(int i);
-    void releaseParking(int id);
-    std::string getParkingName(int i);
-    int getNrOfParkings() {
-        return parkings.size();
-    };
+    void setParkingAvailable(PositionedID guid, bool available);
+  
+    bool isParkingAvailable(PositionedID parking) const;
+  
+    FGParking *getParking(PositionedID i) const;
+    void releaseParking(PositionedID id);
+    std::string getParkingName(PositionedID i) const;
 
     /**
      * Find a parking gate index by name. Note names are often not unique
-     * in our data, so will return the first match.
+     * in our data, so will return the first match. If the parking is found,
+     * it will be marked as in-use (unavailable)
      */
-    int findParkingByName(const std::string& name) const;
+    ParkingAssignment getParkingByName(const std::string& name) const;
 
     // ATC related functions.
     FGStartupController    *getStartupController()    {
index 85fc93022c680048897bfa136d2158ce8bfa3f95..12759bc2cdda0211aa3d24fab174e5add7cf6c87 100644 (file)
@@ -4,16 +4,18 @@
 
 #include "groundnetwork.hxx"
 
+#include <Navaids/NavDataCache.hxx>
 #include <Main/globals.hxx>
 #include <Scenery/scenery.hxx>
 
+using namespace flightgear;
+
 /**************************************************************************
  * FGTaxiNode
  *************************************************************************/
 
-FGTaxiNode::FGTaxiNode(PositionedID aGuid, int index, const SGGeod& pos, bool aOnRunway, int aHoldType) :
+FGTaxiNode::FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType) :
   FGPositioned(aGuid, FGPositioned::PARKING, "", pos),
-  index(index),
   isOnRunway(aOnRunway),
   holdType(aHoldType)
 {
@@ -29,35 +31,24 @@ void FGTaxiNode::setElevation(double val)
   // ignored for the moment
 }
 
-double FGTaxiNode::getElevationFt(double refelev)
+double FGTaxiNode::getElevationFt()
 {
-#if 0
-    double elevF = elevation();
-    double elevationEnd = 0;
-    if ((elevF == 0) || (elevF == refelev)) {
-        SGGeod center2 = mPosition;
-        FGScenery * local_scenery = globals->get_scenery();
-        center2.setElevationM(SG_MAX_ELEVATION_M);
-        if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
-            geod.setElevationM(elevationEnd);
-        }
+  if (mPosition.getElevationFt() == 0.0) {
+    SGGeod center2 = mPosition;
+    FGScenery* local_scenery = globals->get_scenery();
+    center2.setElevationM(SG_MAX_ELEVATION_M);
+    double elevationEnd = -100;
+    if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
+      
+      mPosition.setElevationM(elevationEnd);
+      NavDataCache::instance()->updatePosition(guid(), mPosition);
     }
-#endif
+  }
+  
   return mPosition.getElevationFt();
 }
 
-double FGTaxiNode::getElevationM(double refelev)
+double FGTaxiNode::getElevationM()
 {
-    return geod().getElevationM();
-}
-
-FGTaxiSegment* FGTaxiNode::getArcTo(FGTaxiNode* aEnd) const
-{
-  BOOST_FOREACH(FGTaxiSegment* arc, next) {
-    if (arc->getEnd() == aEnd) {
-      return arc;
-    }
-  }
-  
-  return NULL;
+  return getElevationFt() * SG_FEET_TO_METER;
 }
index 5902badfbb7cf342df2bab035fa77583983ef6d0..2ade6673d57bc43ff22a184b4131ed022b308098 100644 (file)
 #ifndef _GN_NODE_HXX_
 #define _GN_NODE_HXX_
 
-#include <vector>
-#include <string>
-
 #include <simgear/compiler.h>
 #include <simgear/structure/SGSharedPtr.hxx>
 
 #include <Navaids/positioned.hxx>
 
-class FGTaxiSegment;
-
-typedef std::vector<FGTaxiSegment*>  FGTaxiSegmentVector;
-typedef FGTaxiSegmentVector::iterator FGTaxiSegmentVectorIterator;
-
-bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b);
-bool sortByLength     (FGTaxiSegment *a, FGTaxiSegment *b);
-
 class FGTaxiNode : public FGPositioned
 {
 protected:
-  int index;
-
   bool isOnRunway;
   int  holdType;
-  FGTaxiSegmentVector next; // a vector of pointers to all the segments leaving from this node
-
-  // used in way finding - should really move to a dynamic struct
-  double pathScore;
-  FGTaxiNode* previousNode;
-  FGTaxiSegment* previousSeg;
-
 
 public:    
-  FGTaxiNode(PositionedID aGuid, int index, const SGGeod& pos, bool aOnRunway, int aHoldType);
+  FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType);
   virtual ~FGTaxiNode();
   
   void setElevation(double val);
-  void addSegment(FGTaxiSegment *segment) { next.push_back(segment);     };
-
-  void setPathScore   (double val)         { pathScore    = val; };
-  void setPreviousNode(FGTaxiNode *val)    { previousNode = val; };
-  void setPreviousSeg (FGTaxiSegment *val) { previousSeg  = val; };
 
-  FGTaxiNode    *getPreviousNode()    { return previousNode; };
-  FGTaxiSegment *getPreviousSegment() { return previousSeg;  };
-
-  double getPathScore() { return pathScore; };
-
-  double getElevationM (double refelev);
-  double getElevationFt(double refelev);
+  double getElevationM ();
+  double getElevationFt();
   
-  int getIndex() const { return index; };
+  PositionedID getIndex() const { return guid(); };
   int getHoldPointType() const { return holdType; };
   bool getIsOnRunway() const { return isOnRunway; };
-
-  const FGTaxiSegmentVector& arcs() const
-  { return next; }
-  
-  /// find the arg which leads from this node to another.
-  /// returns NULL if no such arc exists.
-  FGTaxiSegment* getArcTo(FGTaxiNode* aEnd) const;
-  
-  bool operator<(const FGTaxiNode &other) const { return index < other.index; };
-
-
 };
 
 typedef SGSharedPtr<FGTaxiNode> FGTaxiNode_ptr;
index 3c65c8e48bee0d391d2569a0603c8e307ed89883..fe4d2e75b7050a5d639afac5db9388df026a9d12 100644 (file)
@@ -27,6 +27,7 @@
 #include <math.h>
 #include <algorithm>
 #include <fstream>
+#include <map>
 #include <boost/foreach.hpp>
 
 #include <osg/Geode>
@@ -40,6 +41,7 @@
 #include <simgear/scene/material/mat.hxx>
 #include <simgear/scene/util/OsgMath.hxx>
 #include <simgear/structure/exception.hxx>
+#include <simgear/timing/timestamp.hxx>
 
 #include <Airports/simple.hxx>
 #include <Airports/dynamics.hxx>
@@ -48,6 +50,7 @@
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/performancedata.hxx>
 #include <AIModel/AIFlightPlan.hxx>
+#include <Navaids/NavDataCache.hxx>
 
 #include <ATC/atc_mgr.hxx>
 
 #include "groundnetwork.hxx"
 
 using std::string;
+using flightgear::NavDataCache;
 
 /***************************************************************************
  * FGTaxiSegment
  **************************************************************************/
 
-FGTaxiSegment::FGTaxiSegment(int aStart, int aEnd, bool isPushBack) :
+FGTaxiSegment::FGTaxiSegment(PositionedID aStart, PositionedID aEnd) :
   startNode(aStart),
   endNode(aEnd),
-  length(0),
-  heading(0),
   isActive(0),
-  isPushBackRoute(isPushBack),
-  start(0),
-  end(0),
   index(0),
   oppositeDirection(0)
 {
 };
 
-bool FGTaxiSegment::bindToNodes(const IndexTaxiNodeMap& nodes)
+SGGeod FGTaxiSegment::getCenter() const
 {
-  IndexTaxiNodeMap::const_iterator it = nodes.find(startNode);
-  if (it == nodes.end()) {
-    return false;
-  }
-  
-  start = it->second;
-  
-  it = nodes.find(endNode);
-  if (it == nodes.end()) {
-    return false;
-  }
-  
-  end = it->second;
-  
-  start->addSegment(this);
-  double az2;
+  FGTaxiNode* start(getStart()), *end(getEnd());
+  double heading, length, az2;
   SGGeodesy::inverse(start->geod(), end->geod(), heading, az2, length);
-  return true;
+  return SGGeodesy::direct(start->geod(), heading, length * 0.5);
 }
 
-SGGeod FGTaxiSegment::getCenter() const
+FGTaxiNode* FGTaxiSegment::getEnd() const
 {
-  return SGGeodesy::direct(start->geod(), heading, length * 0.5);
+  return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(endNode));
+}
+
+FGTaxiNode* FGTaxiSegment::getStart() const
+{
+  return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(startNode));
+}
+
+double FGTaxiSegment::getLength() const
+{
+  return dist(getStart()->cart(), getEnd()->cart());
+}
+
+double FGTaxiSegment::getHeading() const
+{
+  return SGGeodesy::courseDeg(getStart()->geod(), getEnd()->geod());
 }
 
+
 void FGTaxiSegment::block(int id, time_t blockTime, time_t now)
 {
     BlockListIterator i = blockTimes.begin();
@@ -144,81 +145,17 @@ void FGTaxiSegment::unblock(time_t now)
 /***************************************************************************
  * FGTaxiRoute
  **************************************************************************/
-bool FGTaxiRoute::next(int *nde)
+bool FGTaxiRoute::next(PositionedID *nde)
 {
-    //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
-    //  cerr << "FGTaxiRoute contains : " << *(i) << endl;
-    //cerr << "Offset from end: " << nodes.end() - currNode << endl;
-    //if (currNode != nodes.end())
-    //  cerr << "true" << endl;
-    //else
-    //  cerr << "false" << endl;
-    //if (nodes.size() != (routes.size()) +1)
-    //  cerr << "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size() << endl;
-
     if (currNode == nodes.end())
         return false;
+  
     *nde = *(currNode);
-    if (currNode != nodes.begin())      // make sure route corresponds to the end node
-        currRoute++;
-    currNode++;
-    return true;
-};
 
-bool FGTaxiRoute::next(int *nde, int *rte)
-{
-    //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
-    //  cerr << "FGTaxiRoute contains : " << *(i) << endl;
-    //cerr << "Offset from end: " << nodes.end() - currNode << endl;
-    //if (currNode != nodes.end())
-    //  cerr << "true" << endl;
-    //else
-    //  cerr << "false" << endl;
-    if (nodes.size() != (routes.size()) + 1) {
-        SG_LOG(SG_GENERAL, SG_ALERT,
-               "ALERT: Misconfigured TaxiRoute : " << nodes.
-               size() << " " << routes.size());
-      throw sg_range_exception("misconfigured taxi route");
-    }
-    if (currNode == nodes.end())
-        return false;
-    *nde = *(currNode);
-    //*rte = *(currRoute);
-    if (currNode != nodes.begin())      // Make sure route corresponds to the end node
-    {
-        *rte = *(currRoute);
-        currRoute++;
-    } else {
-        // If currNode points to the first node, this means the aircraft is not on the taxi node
-        // yet. Make sure to return a unique identifyer in this situation though, because otherwise
-        // the speed adjust AI code may be unable to resolve whether two aircraft are on the same
-        // taxi route or not. the negative of the preceding route seems a logical choice, as it is
-        // unique for any starting location.
-        // Note that this is probably just a temporary fix until I get Parking / tower control working.
-        *rte = -1 * *(currRoute);
-    }
     currNode++;
     return true;
 };
 
-
-void FGTaxiRoute::rewind(int route)
-{
-    int currPoint;
-    int currRoute;
-    first();
-    do {
-        if (!(next(&currPoint, &currRoute))) {
-            SG_LOG(SG_GENERAL, SG_ALERT,
-                   "Error in rewinding TaxiRoute: current" << currRoute <<
-                   " goal " << route);
-        }
-    } while (currRoute != route);
-}
-
-
-
-
 /***************************************************************************
  * FGGroundNetwork()
  **************************************************************************/
@@ -232,7 +169,6 @@ FGGroundNetwork::FGGroundNetwork() :
   parent(NULL)
 {
     hasNetwork = false;
-    foundRoute = false;
     totalDistance = 0;
     maxDistance = 0;
     //maxDepth    = 1000;
@@ -253,52 +189,16 @@ FGGroundNetwork::~FGGroundNetwork()
 // When I fix FGPositioned lifetimes (unloading-at-runtime support), this
 // will need to be re-visited so it can run safely during shutdown.
 #if 0
-    //cerr << "Running Groundnetwork Destructor " << endl;
-    bool saveData = false;
-    ofstream cachefile;
-    if (fgGetBool("/sim/ai/groundnet-cache")) {
-        SGPath cacheData(globals->get_fg_home());
-        cacheData.append("ai");
-        string airport = parent->getId();
-
-        if ((airport) != "") {
-            char buffer[128];
-            ::snprintf(buffer, 128, "%c/%c/%c/",
-                       airport[0], airport[1], airport[2]);
-            cacheData.append(buffer);
-            if (!cacheData.exists()) {
-                cacheData.create_dir(0777);
-            }
-            cacheData.append(airport + "-groundnet-cache.txt");
-            cachefile.open(cacheData.str().c_str());
-            saveData = true;
-        }
-    }
-    cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
-    for (FGTaxiNodeVectorIterator node = nodes.begin();
-            node != nodes.end(); node++) {
-        if (saveData) {
-            cachefile << (*node)->getIndex     () << " "
-            << (*node)->getElevationM (parent->getElevation()*SG_FEET_TO_METER)   << " "
-            << endl;
-        }
-        delete(*node);
-    }
-    nodes.clear();
-    pushBackNodes.clear();
-    for (FGTaxiSegmentVectorIterator seg = segments.begin();
-            seg != segments.end(); seg++) {
-        delete(*seg);
-    }
-    segments.clear();
-    if (saveData) {
-        cachefile.close();
-    }
+  saveElevationCache();
 #endif
+  BOOST_FOREACH(FGTaxiSegment* seg, segments) {
+    delete seg;
+  }
 }
 
-void FGGroundNetwork::saveElevationCache() {
-    //cerr << "Running Groundnetwork Destructor " << endl;
+void FGGroundNetwork::saveElevationCache()
+{
+#if 0
     bool saveData = false;
     ofstream cachefile;
     if (fgGetBool("/sim/ai/groundnet-cache")) {
@@ -331,59 +231,38 @@ void FGGroundNetwork::saveElevationCache() {
     if (saveData) {
         cachefile.close();
     }
+#endif
 }
 
-void FGGroundNetwork::addSegment(FGTaxiSegment* seg)
-{
-    segments.push_back(seg);
-}
-
-void FGGroundNetwork::addNode(FGTaxiNode* node)
-{
-  assert(node);
-  IndexTaxiNodeMap::iterator it = nodes.find(node->getIndex());
-  if (it != nodes.end()) {
-    throw sg_range_exception();
-  }
-  
-  nodes.insert(it, std::make_pair(node->getIndex(), node));
-}
-
-void FGGroundNetwork::addNodes(FGParkingVec * parkings)
-{
-  BOOST_FOREACH(FGParking* parking, *parkings) {
-    addNode(parking);
-  }
-}
-
-void FGGroundNetwork::init()
+void FGGroundNetwork::init(FGAirport* pr)
 {
     if (networkInitialized) {
         FGATCController::init();
         //cerr << "FGground network already initialized" << endl;
         return;
     }
+    
+    parent = pr;
+    assert(parent);
     hasNetwork = true;
     nextSave = 0;
     int index = 1;
   
-  // bind segments to nodes
+    loadSegments();
+  
+  // establish pairing of segments
     BOOST_FOREACH(FGTaxiSegment* segment, segments) {
-      if (!segment->bindToNodes(nodes)) {
-        SG_LOG(SG_GENERAL, SG_ALERT, "unable to bind taxiway segment");
-      }
-      
       segment->setIndex(index++);
-      if (segment->isPushBack()) {
-        pushBackNodes.push_back(segment->getEnd());
+      
+      if (segment->oppositeDirection) {
+        continue; // already establish
       }
-    }
-
-    // establish pairing of segments
-    BOOST_FOREACH(FGTaxiSegment* segment, segments) {
-      FGTaxiSegment* opp = segment->getEnd()->getArcTo(segment->getStart());
+      
+      FGTaxiSegment* opp = findSegment(segment->endNode, segment->startNode);
       if (opp) {
-        segment->setOpposite(opp);
+        assert(opp->oppositeDirection == NULL);
+        segment->oppositeDirection = opp;
+        opp->oppositeDirection = segment;
       }
     }
 
@@ -394,6 +273,18 @@ void FGGroundNetwork::init()
     networkInitialized = true;
 }
 
+void FGGroundNetwork::loadSegments()
+{
+  flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+// iterate over all ground-net nodes in this airport
+  BOOST_FOREACH(PositionedID node, cache->groundNetNodes(parent->guid(), false)) {
+    // find all segments leaving the node
+    BOOST_FOREACH(PositionedID end, cache->groundNetEdgesFrom(node, false)) {
+      segments.push_back(new FGTaxiSegment(node, end));
+    }
+  }
+}
+
 void FGGroundNetwork::parseCache()
 {
   SGPath cacheData(globals->get_fg_home());
@@ -403,7 +294,7 @@ void FGGroundNetwork::parseCache()
   if (airport.empty()) {
     return;
   }
-  
+#if 0
   char buffer[128];
   ::snprintf(buffer, 128, "%c/%c/%c/",
              airport[0], airport[1], airport[2]);
@@ -437,76 +328,29 @@ void FGGroundNetwork::parseCache()
       }
     }
   }
+#endif
 }
 
-int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
+int FGGroundNetwork::findNearestNode(const SGGeod & aGeod) const
 {
-    double minDist = HUGE_VAL;
-    int index = -1;
-
-    IndexTaxiNodeMap::iterator i;
-    for (i = nodes.begin(); i != nodes.end(); i++) {
-        double d = SGGeodesy::distanceM(aGeod, i->second->geod());
-        if (d < minDist) {
-            minDist = d;
-            index = i->first;
-        }
-    }
-
-    return index;
+  const bool onRunway = false;
+  return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway);
 }
 
-int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway)
+int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
 {
-    double minDist = HUGE_VAL;
-    int index = -1;
-
-    IndexTaxiNodeMap::iterator i;
-    for (i = nodes.begin(); i != nodes.end(); i++) {
-        if (!i->second->getIsOnRunway()) {
-            continue;
-        }
-      // check point lies on the runway - i.e that course from aGeod to the
-      // runway end, matches the runway heading
-        if (aRunway) {
-          double course = SGGeodesy::courseDeg(i->second->geod(), aRunway->end());
-          double headingDiff = course - aRunway->headingDeg();
-          SG_NORMALIZE_RANGE(headingDiff, -180.0, 180.0);
-          if (fabs(headingDiff) > 3.0) { // 3 degrees tolerance
-            continue;
-          }
-        }
-      
-        double d = SGGeodesy::distanceM(aGeod, i->second->geod());
-        if (d < minDist) {
-            minDist = d;
-            index = i->first;
-        }
-    }
-
-    return index;
+  const bool onRunway = true;
+  return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway, aRunway);
 }
 
-FGTaxiNode* FGGroundNetwork::findNode(unsigned int idx)
-{                               
-  IndexTaxiNodeMap::iterator i = nodes.find(idx);
-  if (i == nodes.end()) {
-    return NULL;
-  }
-  
-  return i->second;
+FGTaxiNode* FGGroundNetwork::findNode(PositionedID idx) const
+{
+
+  return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(idx));
 }
 
-FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
-{                               /*
-                                   for (FGTaxiSegmentVectorIterator
-                                   itr = segments.begin();
-                                   itr != segments.end(); itr++)
-                                   {
-                                   if (itr->getIndex() == idx)
-                                   return itr->getAddress();
-                                   }
-                                 */
+FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx) const
+{ 
     if ((idx > 0) && (idx <= segments.size()))
         return segments[idx - 1];
     else {
@@ -515,34 +359,57 @@ FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
     }
 }
 
+FGTaxiSegment* FGGroundNetwork::findSegment(PositionedID from, PositionedID to) const
+{
+  if (from == 0) {
+    return NULL;
+  }
+  
+  // completely boring linear search of segments. Can be improved if/when
+  // this ever becomes a hot-spot
+    BOOST_FOREACH(FGTaxiSegment* seg, segments) {
+      if (seg->startNode != from) {
+        continue;
+      }
+      
+      if ((to == 0) || (seg->endNode == to)) {
+        return seg;
+      }
+    }
+  
+    return NULL; // not found
+}
+
+static int edgePenalty(FGTaxiNode* tn)
+{
+  return (tn->type() == FGPositioned::PARKING ? 10000 : 0) +
+    (tn->getIsOnRunway() ? 1000 : 0);
+}
+
+class ShortestPathData
+{
+public:
+  ShortestPathData() :
+    score(HUGE_VAL)
+  {}
+  
+  double score;
+  FGTaxiNode_ptr previousNode;
+};
 
-FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
+FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID end,
         bool fullSearch)
 {
 //implements Dijkstra's algorithm to find shortest distance route from start to end
 //taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
-
-    //double INFINITE = 100000000000.0;
-    // initialize scoring values
-    int nParkings = parent->getDynamics()->getNrOfParkings();
     FGTaxiNodeVector unvisited;
+    flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+    std::map<FGTaxiNode*, ShortestPathData> searchData;
   
-    if (fullSearch) {
-      // create vector from map values
-      IndexTaxiNodeMap::iterator i;
-      for (i = nodes.begin(); i != nodes.end(); i++) {
-        unvisited.push_back(i->second);
-      }
-    } else {
-        unvisited = pushBackNodes;
+    BOOST_FOREACH(PositionedID n, cache->groundNetNodes(parent->guid(), !fullSearch)) {
+      unvisited.push_back(findNode(n));
     }
   
-    BOOST_FOREACH(FGTaxiNode* node, unvisited) {
-        node->setPathScore(HUGE_VAL); //infinity by all practical means
-        node->setPreviousNode(0);     //
-        node->setPreviousSeg(0);      //
-    }
-
     FGTaxiNode *firstNode = findNode(start);
     if (!firstNode)
     {
@@ -551,7 +418,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
                << " at " << ((parent) ? parent->getId() : "<unknown>"));
         return FGTaxiRoute();
     }
-    firstNode->setPathScore(0);
+    searchData[firstNode].score = 0.0;
 
     FGTaxiNode *lastNode = findNode(end);
     if (!lastNode)
@@ -565,11 +432,11 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
     while (!unvisited.empty()) {
         FGTaxiNode *best = unvisited.front();
         BOOST_FOREACH(FGTaxiNode* i, unvisited) {
-            if (i->getPathScore() < best->getPathScore()) {
+            if (searchData[i].score < searchData[best].score) {
                 best = i;
             }
         }
-
+      
       // remove 'best' from the unvisited set
         FGTaxiNodeVectorIterator newend =
             remove(unvisited.begin(), unvisited.end(), best);
@@ -579,59 +446,38 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
             break;
         }
       
-        BOOST_FOREACH(FGTaxiSegment* seg, best->arcs()) {
-            if (!fullSearch && !seg->isPushBack()) {
-              continue; // inelligible!
-            }
-          
-            FGTaxiNode *tgt = seg->getEnd();
-            double alt = best->getPathScore() + seg->getLength() +
-                    seg->getPenalty(nParkings);
-            if (alt < tgt->getPathScore()) {    // Relax (u,v)
-                tgt->setPathScore(alt);
-                tgt->setPreviousNode(best);
-                tgt->setPreviousSeg(seg);
+        BOOST_FOREACH(PositionedID targetId, cache->groundNetEdgesFrom(best->guid(), !fullSearch)) {
+            FGTaxiNode* tgt = (FGTaxiNode*) cache->loadById(targetId);
+            double edgeLength = dist(best->cart(), tgt->cart());          
+            double alt = searchData[best].score + edgeLength + edgePenalty(tgt);
+            if (alt < searchData[tgt].score) {    // Relax (u,v)
+                searchData[tgt].score = alt;
+                searchData[tgt].previousNode = best;
             }
         } // of outgoing arcs/segments from current best node iteration
     } // of unvisited nodes remaining
 
-    if (lastNode->getPathScore() == HUGE_VAL) {
+    if (searchData[lastNode].score == HUGE_VAL) {
         // no valid route found
         if (fullSearch) {
             SG_LOG(SG_GENERAL, SG_ALERT,
                    "Failed to find route from waypoint " << start << " to "
                    << end << " at " << parent->getId());
         }
-        FGTaxiRoute empty;
-        return empty;
-        //exit(1); //TODO exit more gracefully, no need to stall the whole sim with broken GN's
-    } else {
-        // assemble route from backtrace information
-        intVec nodes, routes;
-        FGTaxiNode *bt = lastNode;
-        while (bt->getPreviousNode() != 0) {
-            nodes.push_back(bt->getIndex());
-            routes.push_back(bt->getPreviousSegment()->getIndex());
-            bt = bt->getPreviousNode();
-        }
-        nodes.push_back(start);
-        reverse(nodes.begin(), nodes.end());
-        reverse(routes.begin(), routes.end());
-
-        return FGTaxiRoute(nodes, routes, lastNode->getPathScore(), 0);
-    }
-}
-
-int FGTaxiSegment::getPenalty(int nGates)
-{
-    int penalty = 0;
-    if (end->getIndex() < nGates) {
-        penalty += 10000;
-    }
-    if (end->getIsOnRunway()) { // For now. In future versions, need to find out whether runway is active.
-        penalty += 1000;
+      
+        return FGTaxiRoute();
     }
-    return penalty;
+  
+    // assemble route from backtrace information
+    PositionedIDVec nodes;
+    FGTaxiNode *bt = lastNode;
+    while (searchData[bt].previousNode != 0) {
+        nodes.push_back(bt->guid());
+        bt = searchData[bt].previousNode;
+    }
+    nodes.push_back(start);
+    reverse(nodes.begin(), nodes.end());
+    return FGTaxiRoute(nodes, searchData[lastNode].score, 0);
 }
 
 /* ATC Related Functions */
@@ -644,7 +490,8 @@ void FGGroundNetwork::announcePosition(int id,
                                        double radius, int leg,
                                        FGAIAircraft * aircraft)
 {
-    init();
+    assert(parent);
+  
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
@@ -1345,7 +1192,7 @@ void FGGroundNetwork::render(bool visible)
                 } else {
                     elevationStart = ((i)->getAircraft()->_getAltitude());
                 }
-                double elevationEnd   = segments[pos]->getEnd()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
+                double elevationEnd   = segments[pos]->getEnd()->getElevationM();
                 //cerr << "Using elevation " << elevationEnd << endl;
 
                 if ((elevationEnd == 0) || (elevationEnd = parent->getElevation())) {
@@ -1406,8 +1253,8 @@ void FGGroundNetwork::render(bool visible)
                     obj_trans->setDataVariance(osg::Object::STATIC);
 
                     // Experimental: Calculate slope here, based on length, and the individual elevations
-                    double elevationStart = segments[k]->getStart()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
-                    double elevationEnd   = segments[k]->getEnd  ()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
+                    double elevationStart = segments[k]->getStart()->getElevationM();
+                    double elevationEnd   = segments[k]->getEnd  ()->getElevationM();
                     if ((elevationStart == 0)  || (elevationStart == parent->getElevation())) {
                         SGGeod center2 = segments[k]->getStart()->geod();
                         center2.setElevationM(SG_MAX_ELEVATION_M);
index 9b73e2e81d08e7909626e7a3243ead090615d809..de8d94ed44a5008af63bf98f341b5a2a585d2abd 100644 (file)
@@ -72,57 +72,40 @@ typedef BlockList::iterator BlockListIterator;
 class FGTaxiSegment
 {
 private:
-    int startNode;
-    int endNode;
-    double length;
-    double heading;
+    const PositionedID startNode;
+    const PositionedID endNode;
+    
     bool isActive;
-    bool isPushBackRoute;
     BlockList blockTimes;
-    FGTaxiNode *start;
-    FGTaxiNode *end;
+
     int index;
     FGTaxiSegment *oppositeDirection;
 
+    friend class FGGroundNetwork;
 public:
-  FGTaxiSegment(int start, int end, bool isPushBack);
+    FGTaxiSegment(PositionedID start, PositionedID end);
   
     void setIndex        (int val) {
         index     = val;
     };
-
-    void setOpposite(FGTaxiSegment *opp) {
-        oppositeDirection = opp;
-    };
-
-    bool bindToNodes(const IndexTaxiNodeMap& nodes);
   
     void setDimensions(double elevation);
     void block(int id, time_t blockTime, time_t now);
     void unblock(time_t now); 
     bool hasBlock(time_t now);
 
-    FGTaxiNode * getEnd() {
-        return end;
-    };
-    FGTaxiNode * getStart() {
-        return start;
-    };
-    double getLength() {
-        return length;
-    };
-    int getIndex() {
-        return index;
-    };
+    FGTaxiNode * getEnd() const;
+    FGTaxiNode * getStart() const;
+  
+    double getLength() const;
   
     // compute the center of the arc
     SGGeod getCenter() const;
   
-    double getHeading()   {
-        return heading;
-    };
-    bool isPushBack() {
-        return isPushBackRoute;
+    double getHeading() const;
+    
+    int getIndex() {
+      return index;
     };
 
     int getPenalty(int nGates);
@@ -130,7 +113,7 @@ public:
     bool operator<(const FGTaxiSegment &other) const {
         return index < other.index;
     };
-    //bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
+
     FGTaxiSegment *opposite() {
         return oppositeDirection;
     };
@@ -150,60 +133,45 @@ typedef std::vector<int>::iterator intVecIterator;
 class FGTaxiRoute
 {
 private:
-    intVec nodes;
-    intVec routes;
+    PositionedIDVec nodes;
     double distance;
-//  int depth;
-    intVecIterator currNode;
-    intVecIterator currRoute;
+    PositionedIDVec::iterator currNode;
 
 public:
     FGTaxiRoute() {
         distance = 0;
         currNode = nodes.begin();
-        currRoute = routes.begin();
     };
-    FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) {
+  
+    FGTaxiRoute(const PositionedIDVec& nds, double dist, int dpth) {
         nodes = nds;
-        routes = rts;
         distance = dist;
         currNode = nodes.begin();
-        currRoute = routes.begin();
-//    depth = dpth;
     };
 
     FGTaxiRoute& operator= (const FGTaxiRoute &other) {
         nodes = other.nodes;
-        routes = other.routes;
         distance = other.distance;
-//    depth = other.depth;
         currNode = nodes.begin();
-        currRoute = routes.begin();
         return *this;
     };
 
     FGTaxiRoute(const FGTaxiRoute& copy) :
             nodes(copy.nodes),
-            routes(copy.routes),
             distance(copy.distance),
-//    depth(copy.depth),
-            currNode(nodes.begin()),
-            currRoute(routes.begin())
+            currNode(nodes.begin())
     {};
 
     bool operator< (const FGTaxiRoute &other) const {
         return distance < other.distance;
     };
     bool empty () {
-        return nodes.begin() == nodes.end();
+        return nodes.empty();
     };
-    bool next(int *nde);
-    bool next(int *nde, int *rte);
-    void rewind(int legNr);
-
+    bool next(PositionedID *nde);
+  
     void first() {
         currNode = nodes.begin();
-        currRoute = routes.begin();
     };
     int size() {
         return nodes.size();
@@ -211,8 +179,6 @@ public:
     int nodesLeft() {
         return nodes.end() - currNode;
     };
-
-//  int getDepth() { return depth; };
 };
 
 typedef std::vector<FGTaxiRoute> TaxiRouteVector;
@@ -231,12 +197,8 @@ private:
     int count;
     int version;
   
-    IndexTaxiNodeMap nodes;
-    FGTaxiNodeVector pushBackNodes;
-  
     FGTaxiSegmentVector segments;
 
-    TaxiRouteVector routes;
     TrafficVector activeTraffic;
     TrafficVectorIterator currTraffic;
 
@@ -255,18 +217,16 @@ private:
 
 
     void parseCache();
+  
+    void loadSegments();
 public:
     FGGroundNetwork();
     ~FGGroundNetwork();
-
-    void addNode   (FGTaxiNode* node);
-    void addNodes  (FGParkingVec *parkings);
-    void addSegment(FGTaxiSegment* seg);
-    void setVersion (int v) { version = v;};
     
+    void setVersion (int v) { version = v;};
     int getVersion() { return version; };
 
-    void init();
+    void init(FGAirport* pr);
     bool exists() {
         return hasNetwork;
     };
@@ -274,21 +234,21 @@ public:
         towerController = twrCtrlr;
     };
 
-    int findNearestNode(const SGGeod& aGeod);
-    int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL);
+    int findNearestNode(const SGGeod& aGeod) const;
+    int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL) const;
 
-    FGTaxiNode *findNode(unsigned idx);
-    FGTaxiSegment *findSegment(unsigned idx);
-    FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
-    //void trace(FGTaxiNode *, int, int, double dist);
-
-    int getNrOfNodes() {
-        return nodes.size();
-    };
-
-    void setParent(FGAirport *par) {
-        parent = par;
-    };
+    FGTaxiNode *findNode(PositionedID idx) const;
+    FGTaxiSegment *findSegment(unsigned idx) const;
+  
+    /**
+     * Find the taxiway segment joining two (ground-net) nodes. Returns
+     * NULL if no such segment exists.
+     * It is permitted to pass 0 for the 'to' ID, indicating that any
+     * segment originating at 'from' is acceptable.
+     */
+    FGTaxiSegment* findSegment(PositionedID from, PositionedID to) const;
+  
+    FGTaxiRoute findShortestRoute(PositionedID start, PositionedID end, bool fullSearch=true);
 
     virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
                                   double lat, double lon, double hdg, double spd, double alt,
index 58928dfcfa0863492199131c4a7a296679728ddc..032a12549c50beb4dc58f92365d3b068438e2efd 100644 (file)
 #include <string>
 
 #include "parking.hxx"
-#include "groundnetwork.hxx"
 
 /*********************************************************************************
  * FGParking
  ********************************************************************************/
 
-FGParking::FGParking(PositionedID aGuid, int index, const SGGeod& pos,
+FGParking::FGParking(PositionedID aGuid, const SGGeod& pos,
                      double aHeading, double aRadius,
                      const std::string& name, const std::string& aType,
-                     const std::string& codes) :
-  FGTaxiNode(aGuid, index, pos, false, 0),
+                     const std::string& codes,
+                     PositionedID pushBackNode) :
+  FGTaxiNode(aGuid, pos, false, 0),
   heading(aHeading),
   radius(aRadius),
   parkingName(name),
   type(aType),
   airlineCodes(codes),
-  available(true),
-  pushBackPoint(0)
+  pushBackPoint(pushBackNode)
 {
 }
 
index c16038c5163c94fa4e7dd397066a0d01ab7cfc8f..ff466d256f56d1951f27e79b897b50a7ccff211d 100644 (file)
 
 #include "gnnode.hxx"
 
-class FGTaxiRoute;
-
 
 class FGParking : public FGTaxiNode
 {
 private:
-  double heading;
-  double radius;
-  std::string parkingName;
-  std::string type;
-  std::string airlineCodes;
-  bool available;
-  int pushBackPoint;
-  std::auto_ptr<FGTaxiRoute> pushBackRoute;
+  const double heading;
+  const double radius;
+  const std::string parkingName;
+  const std::string type;
+  const std::string airlineCodes;
+  const PositionedID pushBackPoint;
 
   SG_DISABLE_COPY(FGParking);
 public:
-  FGParking(PositionedID aGuid, int index, const SGGeod& pos,
+  FGParking(PositionedID aGuid, const SGGeod& pos,
             double heading, double radius,
             const std::string& name, const std::string& type,
-            const std::string& codes);
+            const std::string& codes,
+            PositionedID pushBackNode);
   virtual ~FGParking();
-
+#if 0
   void setHeading  (double hdg)  { heading     = hdg;  };
   void setRadius   (double rad)  { radius      = rad;  };
 
   void setName     (const std::string& name) { parkingName = name; };
   void setType     (const std::string& tpe)  { type        = tpe;  };
   void setCodes    (const std::string& codes){ airlineCodes= codes;};
-
-  void setPushBackRoute(std::auto_ptr<FGTaxiRoute> val) { pushBackRoute = val; };
-  void setPushBackPoint(int val)          { pushBackPoint = val; };
-
-  bool isAvailable ()   const { return available;};
-  void setAvailable(bool val) { available = val; };
+#endif
   
   double getHeading  () const { return heading;     };
   double getRadius   () const { return radius;      };
@@ -82,8 +73,6 @@ public:
   std::string getCodes    () const { return airlineCodes;};
   std::string getName     () const { return parkingName; };
 
-  FGTaxiRoute * getPushBackRoute () { return pushBackRoute.get(); };
-
   int getPushBackPoint () { return pushBackPoint; };
 
   bool operator< (const FGParking &other) const {
index aac730e5041ff2750844e474988cf3881bdacfd5..84ed7ffabb39c561e49f0ab0782ca0ebe9a12d0f 100644 (file)
@@ -112,7 +112,8 @@ FGAirportDynamics * FGAirport::getDynamics()
     
     _dynamics = new FGAirportDynamics(this);
     XMLLoader::load(_dynamics);
-
+    _dynamics->init();
+  
     FGRunwayPreference rwyPrefs(this);
     XMLLoader::load(&rwyPrefs);
     _dynamics->setRwyUse(rwyPrefs);
index 8b35cabd5b03bab346f5df79fd9f2ec9f8a83219..901d1235f19d34fe566946c6c55862be94b574dc 100644 (file)
@@ -20,6 +20,7 @@
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/xml/easyxml.hxx>
 #include <simgear/misc/strutils.hxx>
+#include <simgear/timing/timestamp.hxx>
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
@@ -32,6 +33,8 @@
 #include "simple.hxx"
 #include "runwayprefs.hxx"
 
+#include <Navaids/NavDataCache.hxx>
+
 using std::string;
 
 XMLLoader::XMLLoader() {}
@@ -39,10 +42,32 @@ XMLLoader::~XMLLoader() {}
 
 void XMLLoader::load(FGAirportDynamics* d)
 {
-  FGAirportDynamicsXMLLoader visitor(d);
-  if(loadAirportXMLDataIntoVisitor(d->parent()->ident(), "groundnet", visitor)) {
-    d->init();
+  SGPath path;
+  if (!findAirportData(d->parent()->ident(), "groundnet", path)) {
+    return;
+  }
+
+  flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+  if (!cache->isCachedFileModified(path)) {
+    return;
   }
+  
+  SG_LOG(SG_GENERAL, SG_INFO, "reading groundnet data from " << path);
+  SGTimeStamp t;
+  try {
+    cache->beginTransaction();
+    t.stamp();
+    {
+      FGAirportDynamicsXMLLoader visitor(d);
+      readXML(path.str(), visitor);
+    } // ensure visitor is destroyed so its destructor runs
+    cache->stampCacheFile(path);
+    cache->commitTransaction();
+  } catch (sg_exception& e) {
+    cache->abortTransaction();
+  }
+
+  SG_LOG(SG_GENERAL, SG_INFO, "parsing XML took " << t.elapsedMSec());
 }
 
 void XMLLoader::load(FGRunwayPreference* p) {
index d4cdd179935df5134fccc0da95e0602de85c9afa..cb4663cc2a8272db185a695c3286647ebd68dc5f 100644 (file)
@@ -169,7 +169,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
     return false;
   }
   
-  int gateID;
+  ParkingAssignment pka;
   double radius = fgGetDouble("/sim/dimensions/radius-m");
   if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
     string fltType;
@@ -203,27 +203,25 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
     }
     
     string acType; // Currently not used by findAvailable parking, so safe to leave empty.
-    gateID = dcs->getAvailableParking(radius, fltType, acType, acOperator);
-    if (gateID >=0 ) {
+    pka = dcs->getAvailableParking(radius, fltType, acType, acOperator);
+    if (pka.isValid()) {
       fgGetString("/sim/presets/parkpos");
-      fgSetString("/sim/presets/parkpos", dcs->getParking(gateID)->getName());
+      fgSetString("/sim/presets/parkpos", pka.parking()->getName());
     } else {
       SG_LOG( SG_GENERAL, SG_ALERT,
              "Failed to find a suitable parking at airport " << id );
       return false;
     }
   } else {
-    gateID = dcs->findParkingByName(parkpos);
-    if (gateID < 0) {
+    pka = dcs->getParkingByName(parkpos);
+    if (!pka.isValid()) {
       SG_LOG( SG_GENERAL, SG_ALERT,
                "Failed to find a parking at airport " << id << ":" << parkpos);
       return false;
     }
   }
   
-  FGParking* parking = dcs->getParking(gateID);
-  parking->setAvailable(false);
-  fgApplyStartOffset(parking->geod(), parking->getHeading());
+  fgApplyStartOffset(pka.parking()->geod(), pka.parking()->getHeading());
   return true;
 }
 
index 5d228c4bcf7dd4d21447884e4b9ab6969ee19bef..c5cd7feea06615341ceb22459f6fec4beebab7af 100644 (file)
@@ -60,6 +60,8 @@
 #include "PositionedOctree.hxx"
 #include <Airports/apt_loader.hxx>
 #include <Navaids/airways.hxx>
+#include <Airports/parking.hxx>
+#include <Airports/gnnode.hxx>
 
 using std::string;
 
@@ -68,7 +70,7 @@ using std::string;
 
 namespace {
 
-const int SCHEMA_VERSION = 4;
+const int SCHEMA_VERSION = 5;
 
 // bind a std::string to a sqlite statement. The std::string must live the
 // entire duration of the statement execution - do not pass a temporary
@@ -461,6 +463,29 @@ public:
            ")");
     
     runSQL("CREATE INDEX airway_edge_from ON airway_edge(a)");
+    
+    runSQL("CREATE TABLE taxi_node ("
+           "hold_type INT,"
+           "on_runway BOOL,"
+           "pushback BOOL"
+           ")");
+    
+    runSQL("CREATE TABLE parking ("
+           "heading FLOAT,"
+           "radius INT,"
+           "gate_type VARCHAR,"
+           "airlines VARCHAR,"
+           "pushback INT64"
+           ")");
+    
+    runSQL("CREATE TABLE groundnet_edge ("
+           "airport INT64,"
+           "a INT64,"
+           "b INT64"
+           ")");
+    
+    runSQL("CREATE INDEX groundnet_edge_airport ON groundnet_edge(airport)");
+    runSQL("CREATE INDEX groundnet_edge_from ON groundnet_edge(a)");
   }
   
   void prepareQueries()
@@ -570,6 +595,7 @@ public:
     sqlite3_bind_int(findILS, 4, FGPositioned::ILS);
     sqlite3_bind_int(findILS, 5, FGPositioned::LOC);
     
+  // airways 
     findAirway = prepare("SELECT rowid FROM airway WHERE network=?1 AND ident=?2");
     insertAirway = prepare("INSERT INTO airway (ident, network) "
                            "VALUES (?1, ?2)");
@@ -580,6 +606,47 @@ public:
     isPosInAirway = prepare("SELECT rowid FROM airway_edge WHERE network=?1 AND a=?2");
     
     airwayEdgesFrom = prepare("SELECT airway, b FROM airway_edge WHERE network=?1 AND a=?2");
+    
+  // parking / taxi-node graph
+    insertTaxiNode = prepare("INSERT INTO taxi_node (rowid, hold_type, on_runway, pushback) VALUES(?1, ?2, ?3, 0)");
+    insertParkingPos = prepare("INSERT INTO parking (rowid, heading, radius, gate_type, airlines) "
+                               "VALUES (?1, ?2, ?3, ?4, ?5)");
+    setParkingPushBack = prepare("UPDATE parking SET pushback=?2 WHERE rowid=?1");
+    
+    loadTaxiNodeStmt = prepare("SELECT hold_type, on_runway FROM taxi_node WHERE rowid=?1");
+    loadParkingPos = prepare("SELECT heading, radius, gate_type, airlines, pushback FROM parking WHERE rowid=?1");
+    taxiEdgesFrom = prepare("SELECT b FROM groundnet_edge WHERE a=?1");
+    pushbackEdgesFrom = prepare("SELECT b FROM groundnet_edge, taxi_node WHERE "
+                                "a=?1 AND groundnet_edge.b = taxi_node.rowid AND pushback=1");
+    
+    insertTaxiEdge = prepare("INSERT INTO groundnet_edge (airport, a,b) VALUES(?1, ?2, ?3)");
+    
+    markTaxiNodeAsPushback = prepare("UPDATE taxi_node SET pushback=1 WHERE rowid=?1");
+    airportTaxiNodes = prepare("SELECT rowid FROM positioned WHERE (type=?2 OR type=?3) AND airport=?1");
+    sqlite3_bind_int(airportTaxiNodes, 2, FGPositioned::PARKING);
+    sqlite3_bind_int(airportTaxiNodes, 3, FGPositioned::TAXI_NODE);
+    
+    airportPushbackNodes = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "\
+                                   "airport=?1 AND positioned.rowid=taxi_node.rowid AND pushback=1 "
+                                   "AND (type=?2 OR type=?3)");
+    sqlite3_bind_int(airportPushbackNodes, 2, FGPositioned::PARKING);
+    sqlite3_bind_int(airportPushbackNodes, 3, FGPositioned::TAXI_NODE);
+    
+    findNearestTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
+                                  "positioned.rowid = taxi_node.rowid AND airport=?1 "
+                                  "ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) "
+                                  "LIMIT 1");
+    
+    findNearestRunwayTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
+                                        "positioned.rowid = taxi_node.rowid AND airport=?1 "
+                                        "AND on_runway=1 " 
+                                        "ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) ");
+    
+    findAirportParking = prepare("SELECT positioned.rowid FROM positioned, parking WHERE "
+                                 "airport=?1 AND type=?4 AND "
+                                 "radius >= ?2 AND gate_type = ?3 AND "
+                                 "parking.rowid=positioned.rowid");
+    sqlite3_bind_int(findAirportParking, 4, FGPositioned::PARKING);
   }
   
   void writeIntProperty(const string& key, int value)
@@ -678,6 +745,35 @@ public:
     return new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
   }
   
+  FGPositioned* loadParking(sqlite3_int64 rowId,
+                            const string& name, const SGGeod& pos,
+                            PositionedID airport)
+  {
+    reset(loadParkingPos);
+    sqlite3_bind_int64(loadParkingPos, 1, rowId);
+    execSelect1(loadParkingPos);
+    
+    double heading = sqlite3_column_double(loadParkingPos, 0);
+    int radius = sqlite3_column_int(loadParkingPos, 1);
+    string aircraftType((char*) sqlite3_column_text(loadParkingPos, 2));
+    string airlines((char*) sqlite3_column_text(loadParkingPos, 3));
+    PositionedID pushBack = sqlite3_column_int64(loadParkingPos, 4);
+    
+    return new FGParking(rowId, pos, heading, radius, name, aircraftType, airlines, pushBack);
+  }
+  
+  FGPositioned* loadTaxiNode(sqlite3_int64 rowId, const SGGeod& pos,
+                             PositionedID airport)
+  {
+    reset(loadTaxiNodeStmt);
+    sqlite3_bind_int64(loadTaxiNodeStmt, 1, rowId);
+    execSelect1(loadTaxiNodeStmt);
+    
+    int hold_type = sqlite3_column_int(loadTaxiNodeStmt, 0);
+    bool onRunway = sqlite3_column_int(loadTaxiNodeStmt, 1);
+    return new FGTaxiNode(rowId, pos, onRunway, hold_type);
+  }
+  
   PositionedID insertPositioned(FGPositioned::Type ty, const string& ident,
                                 const string& name, const SGGeod& pos, PositionedID apt,
                                 bool spatialIndex)
@@ -822,6 +918,12 @@ public:
   sqlite3_stmt_ptr findAirway, insertAirwayEdge, isPosInAirway, airwayEdgesFrom,
   insertAirway;
   
+// groundnet (parking, taxi node graph)
+  sqlite3_stmt_ptr loadTaxiNodeStmt, loadParkingPos, insertTaxiNode, insertParkingPos;
+  sqlite3_stmt_ptr taxiEdgesFrom, pushbackEdgesFrom, insertTaxiEdge, markTaxiNodeAsPushback,
+    airportTaxiNodes, airportPushbackNodes, findNearestTaxiNode, findAirportParking,
+    setParkingPushBack, findNearestRunwayTaxiNode;
+  
 // since there's many permutations of ident/name queries, we create
 // them programtically, but cache the exact query by its raw SQL once
 // used.
@@ -910,6 +1012,12 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadFromStmt(sqlite3_stmt_ptr q
     case FGPositioned::FREQ_UNICOM:
       return loadComm(rowid, ty, ident, name, pos, aptId);
       
+    case FGPositioned::TAXI_NODE:
+      return loadTaxiNode(rowid, pos, aptId);
+      
+    case FGPositioned::PARKING:
+      return loadParking(rowid, ident, pos, aptId);
+      
     default:
       return NULL;
   }
@@ -1173,6 +1281,20 @@ void NavDataCache::stampCacheFile(const SGPath& path)
   d->execInsert(d->stampFileCache);
 }
 
+void NavDataCache::beginTransaction()
+{
+  d->runSQL("BEGIN");
+}
+  
+void NavDataCache::commitTransaction()
+{
+  d->runSQL("COMMIT");
+}
+  
+void NavDataCache::abortTransaction()
+{
+  d->runSQL("ROLLBACK");
+}
 
 FGPositioned* NavDataCache::loadById(PositionedID rowid)
 {
@@ -1723,5 +1845,128 @@ PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned
   return sqlite3_column_int64(d->findNavaidForRunway, 0);
 }
   
+PositionedID
+NavDataCache::insertParking(const std::string& name, const SGGeod& aPos,
+                            PositionedID aAirport,
+                           double aHeading, int aRadius, const std::string& aAircraftType,
+                           const std::string& aAirlines)
+{
+  sqlite3_int64 rowId = d->insertPositioned(FGPositioned::PARKING, name, "", aPos, aAirport, false);
+  
+// we need to insert a row into the taxi_node table, otherwise we can't maintain
+// the appropriate pushback flag.
+  d->reset(d->insertTaxiNode);
+  sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
+  sqlite3_bind_int(d->insertTaxiNode, 2, 0);
+  sqlite3_bind_int(d->insertTaxiNode, 3, 0);
+  d->execInsert(d->insertTaxiNode);
+  
+  d->reset(d->insertParkingPos);
+  sqlite3_bind_int64(d->insertParkingPos, 1, rowId);
+  sqlite3_bind_double(d->insertParkingPos, 2, aHeading);
+  sqlite3_bind_int(d->insertParkingPos, 3, aRadius);
+  sqlite_bind_stdstring(d->insertParkingPos, 4, aAircraftType);
+  sqlite_bind_stdstring(d->insertParkingPos, 5, aAirlines);
+  return d->execInsert(d->insertParkingPos);
+}
+  
+void NavDataCache::setParkingPushBackRoute(PositionedID parking, PositionedID pushBackNode)
+{
+  d->reset(d->setParkingPushBack);
+  sqlite3_bind_int64(d->setParkingPushBack, 1, parking);
+  sqlite3_bind_int64(d->setParkingPushBack, 2, pushBackNode);
+  d->execUpdate(d->setParkingPushBack);
+}
+
+PositionedID
+NavDataCache::insertTaxiNode(const SGGeod& aPos, PositionedID aAirport, int aHoldType, bool aOnRunway)
+{
+  sqlite3_int64 rowId = d->insertPositioned(FGPositioned::TAXI_NODE, string(), string(), aPos, aAirport, false);
+  d->reset(d->insertTaxiNode);
+  sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
+  sqlite3_bind_int(d->insertTaxiNode, 2, aHoldType);
+  sqlite3_bind_int(d->insertTaxiNode, 3, aOnRunway);
+  return d->execInsert(d->insertTaxiNode);
+}
+  
+void NavDataCache::insertGroundnetEdge(PositionedID aAirport, PositionedID from, PositionedID to)
+{
+  d->reset(d->insertTaxiEdge);
+  sqlite3_bind_int64(d->insertTaxiEdge, 1, aAirport);
+  sqlite3_bind_int64(d->insertTaxiEdge, 2, from);
+  sqlite3_bind_int64(d->insertTaxiEdge, 3, to);
+  d->execInsert(d->insertTaxiEdge);
+}
+  
+PositionedIDVec NavDataCache::groundNetNodes(PositionedID aAirport, bool onlyPushback)
+{
+  sqlite3_stmt_ptr q = onlyPushback ? d->airportPushbackNodes : d->airportTaxiNodes;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, aAirport);
+  return d->selectIds(q);
+}
+  
+void NavDataCache::markGroundnetAsPushback(PositionedID nodeId)
+{
+  d->reset(d->markTaxiNodeAsPushback);
+  sqlite3_bind_int64(d->markTaxiNodeAsPushback, 1, nodeId);
+  d->execUpdate(d->markTaxiNodeAsPushback);
+}
+
+static double headingDifferenceDeg(double crs1, double crs2)
+{
+  double diff =  crs2 - crs1;
+  SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
+  return diff;
+}
+  
+PositionedID NavDataCache::findGroundNetNode(PositionedID airport, const SGGeod& aPos,
+                                             bool onRunway, FGRunway* aRunway)
+{
+  sqlite3_stmt_ptr q = onRunway ? d->findNearestRunwayTaxiNode : d->findNearestTaxiNode;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, airport);
+  
+  SGVec3d cartPos(SGVec3d::fromGeod(aPos));
+  sqlite3_bind_double(q, 2, cartPos.x());
+  sqlite3_bind_double(q, 3, cartPos.y());
+  sqlite3_bind_double(q, 4, cartPos.z());
+  
+  while (d->execSelect(q)) {
+    PositionedID id = sqlite3_column_int64(q, 0);
+    if (!aRunway) {
+      return id;
+    }
+    
+  // ensure found node lies on the runway
+    FGPositionedRef node = loadById(id);
+    double course = SGGeodesy::courseDeg(node->geod(), aRunway->end());
+    if (fabs(headingDifferenceDeg(course, aRunway->headingDeg())) < 3.0 ) {
+      return id;
+    }
+  }
+  
+  return 0;
+}
+  
+PositionedIDVec NavDataCache::groundNetEdgesFrom(PositionedID pos, bool onlyPushback)
+{
+  sqlite3_stmt_ptr q = onlyPushback ? d->pushbackEdgesFrom : d->taxiEdgesFrom;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, pos);
+  return d->selectIds(q);
+}
+
+PositionedIDVec NavDataCache::findAirportParking(PositionedID airport, const std::string& flightType,
+                                   int radius)
+{
+  d->reset(d->findAirportParking);
+  sqlite3_bind_int64(d->findAirportParking, 1, airport);
+  sqlite3_bind_int(d->findAirportParking, 2, radius);
+  sqlite_bind_stdstring(d->findAirportParking, 3, flightType);
+  
+  return d->selectIds(d->findAirportParking);
+}
+
 } // of namespace flightgear
 
index 4080a608e6f1835dfc6dee68302d473b531ba5ad..01cc20bddbf46da12f8f880f6bb67850271102ec 100644 (file)
@@ -30,6 +30,7 @@
 #include <Navaids/positioned.hxx>
     
 class SGPath;
+class FGRunway;
 
 namespace flightgear
 {
@@ -84,6 +85,16 @@ public:
   string_list readStringListProperty(const std::string& key);
   void writeStringListProperty(const std::string& key, const string_list& values);
   
+// transaction API wrappers
+  void beginTransaction();
+  void commitTransaction();
+  void abortTransaction();
+  
+  /**
+   * retrieve an FGPositioned from the cache.
+   * This may be trivial if the object is previously loaded, or require actual
+   * disk IO.
+   */
   FGPositioned* loadById(PositionedID guid);
   
   PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
@@ -112,8 +123,25 @@ public:
   
   PositionedID createUserWaypoint(const std::string& ident, const SGGeod& aPos);
   
+  PositionedID insertParking(const std::string& name, const SGGeod& aPos,
+                             PositionedID aAirport,
+                             double aHeading, int aRadius, const std::string& aAircraftType,
+                             const std::string& aAirlines);
+  
+  void setParkingPushBackRoute(PositionedID parking, PositionedID pushBackNode);
+  
+  PositionedID insertTaxiNode(const SGGeod& aPos, PositionedID aAirport, int aHoldType, bool aOnRunway);
+  
+  void insertGroundnetEdge(PositionedID aAirport, PositionedID from, PositionedID to);
+  
+  /// update the metar flag associated with an airport
   void setAirportMetar(const std::string& icao, bool hasMetar);
   
+  /**
+   * Modify the position of an existing item.
+   * Use with care, since loaded instances will not be updated (at present -
+   * this behaviour could in theorey be improved)
+   */
   void updatePosition(PositionedID item, const SGGeod &pos);
   
   FGPositioned::List findAllWithIdent(const std::string& ident,
@@ -125,15 +153,35 @@ public:
                                       const SGGeod& aPos, FGPositioned::Filter* aFilter);
   
 
+  /**
+   * Helper to implement the AirportSearch widget. Optimised text search of
+   * airport names and idents, returning a list suitable for passing directly
+   * to PLIB.
+   */
   char** searchAirportNamesAndIdents(const std::string& aFilter);
   
+  /**
+   * Find the closest matching comm-station on a frequency, to a position.
+   * The filter with be used for both type ranging and to validate the result
+   * candidates.
+   */
   FGPositionedRef findCommByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
   
+  /**
+   * find all items of a specified type (or range of types) at an airport
+   */
   PositionedIDVec airportItemsOfType(PositionedID apt, FGPositioned::Type ty,
                                      FGPositioned::Type maxTy = FGPositioned::INVALID);
     
+  /**
+   * find the first match item of the specified type and ident, at an airport
+   */
   PositionedID airportItemWithIdent(PositionedID apt, FGPositioned::Type ty, const std::string& ident);
-  
+    
+  /**
+   * Find all navaids matching a particular frequency, sorted by range from the
+   * supplied position. Type-range will be determined from the filter
+   */
   PositionedIDVec findNavaidsByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
   
   /// overload version of the above that does not consider positioned when
@@ -175,8 +223,15 @@ public:
 // airways
   int findAirway(int network, const std::string& aName);
   
+  /**
+   * insert an edge between two positioned nodes, into the network.
+   * The airway identifier will be set accordingly. No reverse edge is created
+   * by this method - edges are directional so a reverses must be explicitly
+   * created.
+   */
   void insertEdge(int network, int airwayID, PositionedID from, PositionedID to);
   
+  /// is the specified positioned a node on the network?
   bool isInAirwayNetwork(int network, PositionedID pos);
   
   /**
@@ -184,6 +239,17 @@ public:
    * in an airway
    */
   AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
+  
+// ground-network
+  PositionedIDVec groundNetNodes(PositionedID aAirport, bool onlyPushback);
+  void markGroundnetAsPushback(PositionedID nodeId);
+  
+  PositionedID findGroundNetNode(PositionedID airport, const SGGeod& aPos,
+                                 bool onRunway, FGRunway* aRunway = NULL);
+  PositionedIDVec groundNetEdgesFrom(PositionedID pos, bool onlyPushback);
+  
+  PositionedIDVec findAirportParking(PositionedID airport, const std::string& flightType,
+                                     int radius);
 private:
   NavDataCache();
   
index e76ab83f674ddafc618a237d13291605a1a588b9..a9f2cd4bf8decd2c1badb65bba405096a870f033 100644 (file)
@@ -229,7 +229,7 @@ protected:
   void modifyPosition(const SGGeod& newPos);
   
   const PositionedID mGuid;
-  const SGGeod mPosition;
+  SGGeod mPosition;
   const SGVec3d mCart;
   const Type mType;
   const std::string mIdent;
index 3c66a4d0f30b042fd390e8cb3467c1b6f5831f34..24f5564ba3d462ba9a51bde97d6a855748b40d72 100644 (file)
@@ -53,6 +53,7 @@
 #include <Navaids/routePath.hxx>
 #include <Navaids/procedure.hxx>
 #include <Navaids/airways.hxx>
+#include <Navaids/NavDataCache.hxx>
 
 using namespace flightgear;
 
@@ -1339,13 +1340,16 @@ static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
   }
   
   FGAirportDynamics* dynamics = apt->getDynamics();
-  for (int i=0; i<dynamics->getNrOfParkings(); ++i) {
-    FGParking* park = dynamics->getParking(i);
-  // filter out based on availability and type
-    if (onlyAvailable && !park->isAvailable()) {
+  PositionedIDVec parkings = flightgear::NavDataCache::instance()->airportItemsOfType(apt->guid(),
+                                                                                      FGPositioned::PARKING);
+  
+  BOOST_FOREACH(PositionedID parking, parkings) {
+    // filter out based on availability and type
+    if (onlyAvailable && !dynamics->isParkingAvailable(parking)) {
       continue;
     }
     
+    FGParking* park = dynamics->getParking(parking);
     if (!type.empty() && (park->getType() != type)) {
       continue;
     }