]> git.mxchange.org Git - flightgear.git/blobdiff - src/Traffic/Schedule.cxx
Close dialogs on GUI shutdown
[flightgear.git] / src / Traffic / Schedule.cxx
index 32be291b869ab98d816e52b5bc6db00b189a761f..a47dfd2ca3493c2485be2d0b1181736b07747e0d 100644 (file)
 #include <string>
 #include <vector>
 #include <algorithm>
+#include <boost/foreach.hpp>
 
 #include <simgear/compiler.h>
 #include <simgear/sg_inlines.h>
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/props/props.hxx>
-#include <simgear/route/waypoint.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/xml/easyxml.hxx>
 
 #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;
-  AIManagerRef = 0;
-
-  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; 
@@ -108,22 +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))));*/
-  AIManagerRef     = 0;
-  score    =         0;
-  firstRun         = true;
-  runCount         = 0;
-  hits             = 0;
-  lastRun          = 0;
-  initialized      = false;
-  valid            = true;
 }
 
 FGAISchedule::FGAISchedule(const FGAISchedule &other)
@@ -135,7 +129,7 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
   heavy              = other.heavy;
   flightIdentifier   = other.flightIdentifier;
   flights            = other.flights;
-  AIManagerRef       = other.AIManagerRef;
+  aiAircraft         = other.aiAircraft;
   acType             = other.acType;
   airline            = other.airline;
   m_class            = other.m_class;
@@ -150,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;
 }
 
 
@@ -159,12 +155,9 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
 FGAISchedule::~FGAISchedule()
 {
     // remove related object from AI manager
-    if (AIManagerRef)
+    if (aiAircraft)
     {
-        FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
-        if (aimgr)
-            aimgr->destroyObject(AIManagerRef);
-        AIManagerRef = 0;
+      aiAircraft->setDie(true);
     }
 
 /*  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
@@ -200,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. 
@@ -232,14 +240,12 @@ 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 (AIManagerRef) {
-    // Check if this aircraft has been released. 
-    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
-    if (tmgr->isReleased(AIManagerRef)) {
-      AIManagerRef = 0;
+  if (aiAircraft) {
+    if (aiAircraft->getDie()) {
+      aiAircraft = NULL;
     } else {
       return true; // in visual range, let the AIManager handle it
     }
@@ -248,19 +254,19 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   // This flight entry is entirely in the past, do we need to 
   // push it forward in time to the next scheduled departure. 
   if (flight->getArrivalTime() < now) {
-    SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager:      Flight is in the Past");
+    SG_LOG (SG_AI, SG_BULK, "Traffic Manager:      Flight is in the Past");
     // Don't just update: check whether we need to load a new leg. etc.
     // This update occurs for distant aircraft, so we can update the current leg
     // 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;
@@ -280,14 +286,14 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
       
       SGGeodesy::direct(dep->geod(), course, coveredDistance, position, az2);
       
-      SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager:      Flight is in progress, %=" << x);
+      SG_LOG (SG_AI, SG_BULK, "Traffic Manager:      Flight is in progress, %=" << x);
       speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0;
     } else {
     // not departed yet
       //remainingTimeEnroute = totalTimeEnroute;
       elapsedTimeEnroute = 0;
       position = dep->geod();
-      SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager:      Flight is pending, departure in "
+      SG_LOG (SG_AI, SG_BULK, "Traffic Manager:      Flight is pending, departure in "
         << flight->getDepartureTime() - now << " seconds ");
     }
   } else {
@@ -301,17 +307,50 @@ 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.
-  SG_LOG (SG_GENERAL, SG_BULK, "Traffic manager: " << registration << " is scheduled for a flight from " 
+  SG_LOG (SG_AI, SG_BULK, "Traffic manager: " << registration << " is scheduled for a flight from "
             << dep->getId() << " to " << arr->getId() << ". Current distance to user: " 
              << distanceToUser);
   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)
+{
+    return (resolveModelPath(modelPath) != SGPath());
+}
+
+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 SGPath();
 }
 
 bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime)
@@ -319,35 +358,22 @@ 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_GENERAL, 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_GENERAL, SG_WARN, "TrafficManager: Could not load model " << mp_ai.str());
-    return true;
-  }
+  SG_LOG(SG_AI, SG_DEBUG, "Traffic manager: Creating AIModel from:" << flightPlanName);
 
-  FGAIAircraft *aircraft = new FGAIAircraft(this);
-  aircraft->setPerformance(m_class); //"jet_transport";
-  aircraft->setCompany(airline); //i->getAirline();
-  aircraft->setAcType(acType); //i->getAcType();
-  aircraft->setPath(modelPath.c_str());
+  aiAircraft = new FGAIAircraft(this);
+  aiAircraft->setPerformance(acType, m_class); //"jet_transport";
+  aiAircraft->setCompany(airline); //i->getAirline();
+  aiAircraft->setAcType(acType); //i->getAcType();
+  aiAircraft->setPath(modelPath.c_str());
   //aircraft->setFlightPlan(flightPlanName);
-  aircraft->setLatitude(position.getLatitudeDeg());
-  aircraft->setLongitude(position.getLongitudeDeg());
-  aircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet
-  aircraft->setSpeed(0);
-  aircraft->setBank(0);
+  aiAircraft->setLatitude(position.getLatitudeDeg());
+  aiAircraft->setLongitude(position.getLongitudeDeg());
+  aiAircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet
+  aiAircraft->setSpeed(0);
+  aiAircraft->setBank(0);
       
   courseToDest = SGGeodesy::courseDeg(position, arr->geod());
-  FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime,
+  FGAIFlightPlan *fp = new FGAIFlightPlan(aiAircraft, flightPlanName, courseToDest, deptime,
                                             dep, arr, true, radius, 
                                             flight->getCruiseAlt()*100, 
                                             position.getLatitudeDeg(), 
@@ -355,13 +381,12 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
                                             speedKnots, flightType, acType, 
                                             airline);
   if (fp->isValidPlan()) {
-        aircraft->SetFlightPlan(fp);
+        aiAircraft->SetFlightPlan(fp);
         FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
-        aimgr->attach(aircraft);
-        AIManagerRef = aircraft->getID();
+        aimgr->attach(aiAircraft);
         return true;
   } else {
-        delete aircraft;
+        aiAircraft = NULL;
         delete fp;
         //hand back the flights that had already been scheduled
         while (!flights.empty()) {
@@ -378,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");
-  SG_LOG(SG_GENERAL, SG_BULK, "Scheduling Flights for : " << modelPath << " " <<  registration << " " << homePort);
+  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++;
@@ -412,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_GENERAL, 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);
-  SG_LOG(SG_GENERAL, SG_BULK, " Done ");
+
+    // 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()
@@ -509,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)))