]> git.mxchange.org Git - flightgear.git/blobdiff - src/Traffic/Schedule.cxx
Close dialogs on GUI shutdown
[flightgear.git] / src / Traffic / Schedule.cxx
index dd38787ace7fc168c99838a728107299539ab915..a47dfd2ca3493c2485be2d0b1181736b07747e0d 100644 (file)
@@ -36,6 +36,7 @@
 #include <string>
 #include <vector>
 #include <algorithm>
+#include <boost/foreach.hpp>
 
 #include <simgear/compiler.h>
 #include <simgear/sg_inlines.h>
 #include <AIModel/AIFlightPlan.hxx>
 #include <AIModel/AIManager.hxx>
 #include <AIModel/AIAircraft.hxx>
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
 #include <Main/fg_init.hxx>   // That's pretty ugly, but I need fgFindAirportID
 
 
 #include "SchedFlight.hxx"
 #include "TrafficMgr.hxx"
 
+using std::string;
+
 /******************************************************************************
  * the FGAISchedule class contains data members and code to maintain a
  * schedule of Flights for an artificially controlled aircraft.
  *****************************************************************************/
 FGAISchedule::FGAISchedule()
+  : heavy(false),
+    radius(0),
+    groundOffset(0),
+    distanceToUser(0),
+    score(0),
+    runCount(0),
+    hits(0),
+    lastRun(0),
+    firstRun(false),
+    courseToDest(0),
+    initialized(false),
+    valid(false),
+    scheduleComplete(false)
 {
-  firstRun     = true;
-
-  heavy = false;
-  radius = 0;
-  groundOffset = 0;
-  distanceToUser = 0;
-  valid = true;
-  lastRun = 0;
-  //score = 0;
 }
 
-/*
-FGAISchedule::FGAISchedule(string    mdl, 
-                          string    liv, 
-                          string    reg, 
-                          bool      hvy, 
-                          string act, 
-                          string arln, 
-                          string mclass, 
-                          string fltpe,
-                          double rad,
-                          double grnd,
-                          int    scre,
-                          FGScheduledFlightVec flt)*/
-FGAISchedule::FGAISchedule(string model, 
-                           string lvry,
-                           string port, 
-                           string reg, 
-                           string flightId,
+
+FGAISchedule::FGAISchedule(const string& model,
+                           const string& lvry,
+                           const string& port,
+                           const string& reg,
+                           const string& flightId,
                            bool   hvy, 
-                           string act, 
-                           string arln, 
-                           string mclass, 
-                           string fltpe, 
+                           const string& act,
+                           const string& arln,
+                           const string& mclass,
+                           const string& fltpe,
                            double rad, 
                            double grnd)
+    : heavy(hvy),
+      radius(rad),
+      groundOffset(grnd),
+      distanceToUser(0),
+      score(0),
+      runCount(0),
+      hits(0),
+      lastRun(0),
+      firstRun(true),
+      courseToDest(0),
+      initialized(false),
+      valid(true),
+      scheduleComplete(false)
 {
   modelPath        = model; 
   livery           = lvry; 
@@ -106,21 +114,10 @@ FGAISchedule::FGAISchedule(string model,
   airline          = arln;
   m_class          = mclass;
   flightType       = fltpe;
-  radius           = rad;
-  groundOffset     = grnd;
-  distanceToUser   = 0;
-  heavy            = hvy;
   /*for (FGScheduledFlightVecIterator i = flt.begin();
        i != flt.end();
        i++)
     flights.push_back(new FGScheduledFlight((*(*i))));*/
-  score    =         0;
-  firstRun         = true;
-  runCount         = 0;
-  hits             = 0;
-  lastRun          = 0;
-  initialized      = false;
-  valid            = true;
 }
 
 FGAISchedule::FGAISchedule(const FGAISchedule &other)
@@ -147,8 +144,10 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
   runCount           = other.runCount;
   hits               = other.hits;
   lastRun            = other.lastRun;
+  courseToDest       = other.courseToDest;
   initialized        = other.initialized;
   valid              = other.valid;
+  scheduleComplete   = other.scheduleComplete;
 }
 
 
@@ -194,22 +193,37 @@ bool FGAISchedule::init()
   return true;
 }
 
+/**
+ *  Returns true when processing is complete.
+ *  Returns false when processing was aborted due to timeout, so
+ *    more time required - and another call is requested (next sim iteration).
+ */
 bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
-{ 
-  time_t 
-    totalTimeEnroute, 
-    elapsedTimeEnroute,
-    //remainingTimeEnroute,
-    deptime = 0;
+{
+
+  time_t totalTimeEnroute,
+         elapsedTimeEnroute,
+         //remainingTimeEnroute,
+         deptime = 0;
+
   if (!valid) {
-    return false;
+    return true; // processing complete
+  }
+
+  if (!scheduleComplete) {
+      scheduleComplete = scheduleFlights(now);
   }
-  scheduleFlights(now);
+
+  if (!scheduleComplete) {
+      return false; // not ready yet, continue processing in next iteration
+  }
+
   if (flights.empty()) { // No flights available for this aircraft
       valid = false;
-      return false;
+      return true; // processing complete
   }
-  
+
+
   // Sort all the scheduled flights according to scheduled departure time.
   // Because this is done at every update, we only need to check the status
   // of the first listed flight. 
@@ -226,7 +240,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   FGScheduledFlight* flight = flights.front();
   if (!deptime) {
     deptime = flight->getDepartureTime();
-    //cerr << "Settiing departure time " << deptime << endl;
+    //cerr << "Setting departure time " << deptime << endl;
   }
     
   if (aiAircraft) {
@@ -246,13 +260,13 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     // and detach it from the current list of aircraft. 
     flight->update();
     flights.erase(flights.begin()); // pop_front(), effectively
-    return true;
+    return true; // processing complete
   }
   
   FGAirport* dep = flight->getDepartureAirport();
   FGAirport* arr = flight->getArrivalAirport();
   if (!dep || !arr) {
-    return false;
+    return true; // processing complete
   }
     
   double speed = 450.0;
@@ -293,7 +307,8 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   // large distances involved here: see bug #80
   distanceToUser = dist(userCart, SGVec3d::fromGeod(position)) * SG_METER_TO_NM;
 
-  // If distance between user and simulated aircaft is less
+
+  // If distance between user and simulated aircraft is less
   // then 500nm, create this flight. At jet speeds 500 nm is roughly
   // one hour flight time, so that would be a good approximate point
   // to start a more detailed simulation of this aircraft.
@@ -303,19 +318,39 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
     return true; // out of visual range, for the moment.
   }
-  return createAIAircraft(flight, speed, deptime);
+
+  if (!createAIAircraft(flight, speed, deptime)) {
+      valid = false;
+  }
+
+
+    return true; // processing complete
 }
 
 bool FGAISchedule::validModelPath(const std::string& modelPath)
 {
-    SGPath mp(globals->get_fg_root());
-    SGPath mp_ai = mp;
+    return (resolveModelPath(modelPath) != SGPath());
+}
 
-    mp.append(modelPath);
-    mp_ai.append("AI");
-    mp_ai.append(modelPath);
+SGPath FGAISchedule::resolveModelPath(const std::string& modelPath)
+{
+    BOOST_FOREACH(SGPath aiPath, globals->get_data_paths("AI")) {
+        aiPath.append(modelPath);
+        if (aiPath.exists()) {
+            return aiPath;
+        }
+    }
+    
+    // check aircraft dirs
+    BOOST_FOREACH(std::string aircraftPath, globals->get_aircraft_paths()) {
+        SGPath mp(aircraftPath);
+        mp.append(modelPath);
+        if (mp.exists()) {
+            return mp;
+        }
+    }
 
-    return mp.exists() || mp_ai.exists();
+    return SGPath();
 }
 
 bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime)
@@ -323,20 +358,7 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
   FGAirport* dep = flight->getDepartureAirport();
   FGAirport* arr = flight->getArrivalAirport();
   string flightPlanName = dep->getId() + "-" + arr->getId() + ".xml";
-  SG_LOG(SG_AI, SG_INFO, "Traffic manager: Creating AIModel from:" << flightPlanName);
-
-  // Only allow traffic to be created when the model path (or the AI version of mp) exists
-  SGPath mp(globals->get_fg_root());
-  SGPath mp_ai = mp;
-
-  mp.append(modelPath);
-  mp_ai.append("AI");
-  mp_ai.append(modelPath);
-
-  if (!mp.exists() && !mp_ai.exists()) {
-    SG_LOG(SG_AI, SG_WARN, "TrafficManager: Could not load model " << mp_ai.str());
-    return true;
-  }
+  SG_LOG(SG_AI, SG_DEBUG, "Traffic manager: Creating AIModel from:" << flightPlanName);
 
   aiAircraft = new FGAIAircraft(this);
   aiAircraft->setPerformance(acType, m_class); //"jet_transport";
@@ -381,30 +403,32 @@ void FGAISchedule::setHeading()
     courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
 }
 
-void FGAISchedule::scheduleFlights(time_t now)
+bool FGAISchedule::scheduleFlights(time_t now)
 {
-  if (!flights.empty()) {
-    return;
-  }
   //string startingPort;
-  string userPort = fgGetString("/sim/presets/airport-id");
+  const string& userPort = fgGetString("/sim/presets/airport-id");
   SG_LOG(SG_AI, SG_BULK, "Scheduling Flights for : " << modelPath << " " <<  registration << " " << homePort);
   FGScheduledFlight *flight = NULL;
+  SGTimeStamp start;
+  start.stamp();
+
+  bool first = true;
+  if (currentDestination.empty())
+    flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
+
   do {
-    if (currentDestination.empty()) {
-        flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
-        if (!flight)
-            flight = findAvailableFlight(currentDestination, flightIdentifier);
-    } else {
+    if ((!flight)||(!first)) {
         flight = findAvailableFlight(currentDestination, flightIdentifier);
     }
     if (!flight) {
       break;
     }
+
+    first = false;
     currentDestination = flight->getArrivalAirport()->getId();
     //cerr << "Current destination " <<  currentDestination << endl;
     if (!initialized) {
-        string departurePort = flight->getDepartureAirport()->getId();
+        const string& departurePort = flight->getDepartureAirport()->getId();
         if (userPort == departurePort) {
             lastRun = 1;
             hits++;
@@ -415,23 +439,36 @@ void FGAISchedule::scheduleFlights(time_t now)
         initialized = true;
     }
   
-    time_t arr, dep;
-    dep = flight->getDepartureTime();
-    arr = flight->getArrivalTime();
-    string depT = asctime(gmtime(&dep));
-    string arrT = asctime(gmtime(&arr));
-
-    depT = depT.substr(0,24);
-    arrT = arrT.substr(0,24);
-    SG_LOG(SG_AI, SG_BULK, "  Flight " << flight->getCallSign() << ":" 
-                             << "  "        << flight->getDepartureAirport()->getId() << ":"
-                             << "  "        << depT << ":"
-                             << " \""       << flight->getArrivalAirport()->getId() << "\"" << ":"
-                             << "  "        << arrT << ":");
+    if (sglog().would_log(SG_AI, SG_BULK))
+    {
+        time_t arr, dep;
+        dep = flight->getDepartureTime();
+        arr = flight->getArrivalTime();
+        string depT = asctime(gmtime(&dep));
+        string arrT = asctime(gmtime(&arr));
+        depT = depT.substr(0,24);
+        arrT = arrT.substr(0,24);
+        SG_LOG(SG_AI, SG_BULK, "  Flight " << flight->getCallSign() << ":"
+                                 << "  "        << flight->getDepartureAirport()->getId() << ":"
+                                 << "  "        << depT << ":"
+                                 << " \""       << flight->getArrivalAirport()->getId() << "\"" << ":"
+                                 << "  "        << arrT << ":");
+    }
   
     flights.push_back(flight);
-  } while (currentDestination != homePort);
+
+    // continue processing until complete, or preempt after timeout
+  } while ((currentDestination != homePort)&&
+           (start.elapsedMSec()<3.0));
+
+  if (flight && (currentDestination != homePort))
+  {
+      // processing preempted, need to continue in next iteration
+      return false;
+  }
+
   SG_LOG(SG_AI, SG_BULK, " Done ");
+  return true;
 }
 
 bool FGAISchedule::next()
@@ -512,7 +549,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDesti
                    continue;
               }
           }
-          if (flights.size()) {
+          if (! flights.empty()) {
             time_t arrival = flights.back()->getArrivalTime();
             int groundTime = groundTimeFromRadius();
             if ((*i)->getDepartureTime() < (arrival+(groundTime)))