]> git.mxchange.org Git - flightgear.git/blobdiff - src/Traffic/Schedule.cxx
Canvas: Add new element type map for geo mapping.
[flightgear.git] / src / Traffic / Schedule.cxx
index 20d30609cf9e1b57a0f4c735e278ca24f56dc45c..9af6a0c2725e0d0a0cc44325332c244aae41822a 100644 (file)
@@ -41,7 +41,6 @@
 #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>
 
@@ -57,7 +56,7 @@
 
 /******************************************************************************
  * the FGAISchedule class contains data members and code to maintain a
- * schedule of Flights for an articically controlled aircraft. 
+ * schedule of Flights for an artificially controlled aircraft.
  *****************************************************************************/
 FGAISchedule::FGAISchedule()
 {
@@ -68,6 +67,8 @@ FGAISchedule::FGAISchedule()
   radius = 0;
   groundOffset = 0;
   distanceToUser = 0;
+  valid = true;
+  lastRun = 0;
   //score = 0;
 }
 
@@ -119,7 +120,9 @@ FGAISchedule::FGAISchedule(string model,
   firstRun         = true;
   runCount         = 0;
   hits             = 0;
+  lastRun          = 0;
   initialized      = false;
+  valid            = true;
 }
 
 FGAISchedule::FGAISchedule(const FGAISchedule &other)
@@ -145,13 +148,24 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
   firstRun           = other.firstRun;
   runCount           = other.runCount;
   hits               = other.hits;
+  lastRun            = other.lastRun;
   initialized        = other.initialized;
+  valid              = other.valid;
 }
 
 
 
 FGAISchedule::~FGAISchedule()
 {
+    // remove related object from AI manager
+    if (AIManagerRef)
+    {
+        FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
+        if (aimgr)
+            aimgr->destroyObject(AIManagerRef);
+        AIManagerRef = 0;
+    }
+
 /*  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
     {
       delete (*flt);
@@ -190,11 +204,14 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   time_t 
     totalTimeEnroute, 
     elapsedTimeEnroute,
-    remainingTimeEnroute, 
+    //remainingTimeEnroute,
     deptime = 0;
-  
-  scheduleFlights();
+  if (!valid) {
+    return false;
+  }
+  scheduleFlights(now);
   if (flights.empty()) { // No flights available for this aircraft
+      valid = false;
       return false;
   }
   
@@ -219,7 +236,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     
   if (AIManagerRef) {
     // Check if this aircraft has been released. 
-    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
+    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
     if (tmgr->isReleased(AIManagerRef)) {
       AIManagerRef = 0;
     } else {
@@ -234,10 +251,10 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     // 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();
+    flight->update();
     flights.erase(flights.begin()); // pop_front(), effectively
-         return true;
-       }
+    return true;
+  }
   
   FGAirport* dep = flight->getDepartureAirport();
   FGAirport* arr = flight->getArrivalAirport();
@@ -250,7 +267,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     totalTimeEnroute = flight->getArrivalTime() - flight->getDepartureTime();
     if (flight->getDepartureTime() < now) {
       elapsedTimeEnroute   = now - flight->getDepartureTime();
-      remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
+      //remainingTimeEnroute = totalTimeEnroute - elapsedTimeEnroute;
       double x = elapsedTimeEnroute / (double) totalTimeEnroute;
       
     // current pos is based on great-circle course between departure/arrival,
@@ -266,7 +283,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
       speed = ((distanceM - coveredDistance) * SG_METER_TO_NM) / 3600.0;
     } else {
     // not departed yet
-      remainingTimeEnroute = totalTimeEnroute;
+      //remainingTimeEnroute = totalTimeEnroute;
       elapsedTimeEnroute = 0;
       position = dep->geod();
       SG_LOG (SG_GENERAL, SG_BULK, "Traffic Manager:      Flight is pending, departure in "
@@ -274,7 +291,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
     }
   } else {
     // departure / arrival coincident
-    remainingTimeEnroute = totalTimeEnroute = 0.0;
+    //remainingTimeEnroute = totalTimeEnroute = 0.0;
     elapsedTimeEnroute = 0;
     position = dep->geod();
   }
@@ -296,6 +313,18 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   return createAIAircraft(flight, speed, deptime);
 }
 
+bool FGAISchedule::validModelPath(const std::string& modelPath)
+{
+    SGPath mp(globals->get_fg_root());
+    SGPath mp_ai = mp;
+
+    mp.append(modelPath);
+    mp_ai.append("AI");
+    mp_ai.append(modelPath);
+
+    return mp.exists() || mp_ai.exists();
+}
+
 bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots, time_t deptime)
 {
   FGAirport* dep = flight->getDepartureAirport();
@@ -312,7 +341,7 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
   mp_ai.append(modelPath);
 
   if (!mp.exists() && !mp_ai.exists()) {
-    SG_LOG(SG_INPUT, SG_WARN, "TrafficManager: Could not load model " << mp.str());
+    SG_LOG(SG_GENERAL, SG_WARN, "TrafficManager: Could not load model " << mp_ai.str());
     return true;
   }
 
@@ -325,46 +354,70 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
   aircraft->setLatitude(position.getLatitudeDeg());
   aircraft->setLongitude(position.getLongitudeDeg());
   aircraft->setAltitude(flight->getCruiseAlt()*100); // convert from FL to feet
-  aircraft->setSpeed(speedKnots);
+  aircraft->setSpeed(0);
   aircraft->setBank(0);
       
   courseToDest = SGGeodesy::courseDeg(position, arr->geod());
-  aircraft->SetFlightPlan(new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime, 
-                                                            dep, arr, true, radius, 
-                                                            flight->getCruiseAlt()*100, 
-                                                            position.getLatitudeDeg(), 
-                   position.getLongitudeDeg(), 
-                   speedKnots, flightType, acType, 
-                                                            airline));
-                   
-    
-  FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
-  aimgr->attach(aircraft);
-  AIManagerRef = aircraft->getID();
-  return true;
+  FGAIFlightPlan *fp = new FGAIFlightPlan(aircraft, flightPlanName, courseToDest, deptime,
+                                            dep, arr, true, radius, 
+                                            flight->getCruiseAlt()*100, 
+                                            position.getLatitudeDeg(), 
+                                            position.getLongitudeDeg(), 
+                                            speedKnots, flightType, acType, 
+                                            airline);
+  if (fp->isValidPlan()) {
+        aircraft->SetFlightPlan(fp);
+        FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
+        aimgr->attach(aircraft);
+        AIManagerRef = aircraft->getID();
+        return true;
+  } else {
+        delete aircraft;
+        delete fp;
+        //hand back the flights that had already been scheduled
+        while (!flights.empty()) {
+            flights.front()->release();
+            flights.erase(flights.begin());
+        }
+        return false;
+  }
 }
 
-void FGAISchedule::scheduleFlights()
+// Create an initial heading for user controlled aircraft.
+void FGAISchedule::setHeading()  
+{ 
+    courseToDest = SGGeodesy::courseDeg((*flights.begin())->getDepartureAirport()->geod(), (*flights.begin())->getArrivalAirport()->geod());
+}
+
+void FGAISchedule::scheduleFlights(time_t now)
 {
   if (!flights.empty()) {
     return;
   }
-  
-  SG_LOG(SG_GENERAL, SG_BULK, "Scheduling for : " << modelPath << " " <<  registration << " " << homePort);
+  //string startingPort;
+  string userPort = fgGetString("/sim/presets/airport-id");
+  SG_LOG(SG_GENERAL, SG_BULK, "Scheduling Flights for : " << modelPath << " " <<  registration << " " << homePort);
   FGScheduledFlight *flight = NULL;
   do {
-    flight = findAvailableFlight(currentDestination, flightIdentifier);
+    if (currentDestination.empty()) {
+        flight = findAvailableFlight(userPort, flightIdentifier, now, (now+6400));
+        if (!flight)
+            flight = findAvailableFlight(currentDestination, flightIdentifier);
+    } else {
+        flight = findAvailableFlight(currentDestination, flightIdentifier);
+    }
     if (!flight) {
       break;
     }
-    
     currentDestination = flight->getArrivalAirport()->getId();
+    //cerr << "Current destination " <<  currentDestination << endl;
     if (!initialized) {
         string departurePort = flight->getDepartureAirport()->getId();
-       //cerr << "Scheduled " << registration <<  " " << score << " for Flight " 
-       //     << flight-> getCallSign() << " from " << departurePort << " to " << currentDestination << endl;
-        if (fgGetString("/sim/presets/airport-id") == departurePort) {
+        if (userPort == departurePort) {
+            lastRun = 1;
             hits++;
+        } else {
+            lastRun = 0;
         }
         //runCount++;
         initialized = true;
@@ -378,11 +431,11 @@ void FGAISchedule::scheduleFlights()
 
     depT = depT.substr(0,24);
     arrT = arrT.substr(0,24);
-    SG_LOG(SG_GENERAL, SG_BULK, "  " << flight->getCallSign() << ":" 
-                             << "  " << flight->getDepartureAirport()->getId() << ":"
-                             << "  " << depT << ":"
-                             << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
-                             << "  " << arrT << ":");
+    SG_LOG(SG_GENERAL, SG_BULK, "  Flight " << flight->getCallSign() << ":" 
+                             << "  "        << flight->getDepartureAirport()->getId() << ":"
+                             << "  "        << depT << ":"
+                             << " \""       << flight->getArrivalAirport()->getId() << "\"" << ":"
+                             << "  "        << arrT << ":");
   
     flights.push_back(flight);
   } while (currentDestination != homePort);
@@ -422,11 +475,12 @@ bool FGAISchedule::next()
 }
 
 FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDestination,
-                                                      const string &req)
+                                                      const string &req,
+                                                     time_t min, time_t max)
 {
     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
 
-    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
+    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
     FGScheduledFlightVecIterator fltBegin, fltEnd;
     fltBegin = tmgr->getFirstFlight(req);
     fltEnd   = tmgr->getLastFlight(req);
@@ -466,7 +520,18 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDesti
                    continue;
               }
           }
-          //TODO: check time
+          if (flights.size()) {
+            time_t arrival = flights.back()->getArrivalTime();
+            int groundTime = groundTimeFromRadius();
+            if ((*i)->getDepartureTime() < (arrival+(groundTime)))
+                continue;
+          }
+          if (min != 0) {
+              time_t dep = (*i)->getDepartureTime();
+              if ((dep < min) || (dep > max))
+                  continue;
+          }
+
           // So, if we actually get here, we have a winner
           //cerr << "found flight: " << req << " : " << currentDestination << " : " <<       
           //         (*i)->getArrivalAirport()->getId() << endl;
@@ -482,6 +547,23 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDesti
      return NULL;
 }
 
+int FGAISchedule::groundTimeFromRadius()
+{
+    if (radius < 10) 
+        return 15 * 60;
+    else if (radius < 15)
+        return 20 * 60;
+    else if (radius < 20)
+        return 30 * 60;
+    else if (radius < 25)
+        return 50 * 60;
+    else if (radius < 30)
+        return 90 * 60;
+    else 
+        return 120 * 60;
+}
+
+
 double FGAISchedule::getSpeed()
 {
   FGScheduledFlightVecIterator i = flights.begin();
@@ -515,48 +597,11 @@ bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
   return (*a) < (*b); 
 } 
 
-
-// void FGAISchedule::setClosestDistanceToUser()
-// {
-  
-  
-//   double course;
-//   double dist;
-
-//   time_t 
-//     totalTimeEnroute, 
-//     elapsedTimeEnroute;
-//   double userLatitude  = fgGetDouble("/position/latitude-deg");
-//   double userLongitude = fgGetDouble("/position/longitude-deg");
-
-//   FGAirport *dep;
-  
-// #if defined( __CYGWIN__) || defined( __MINGW32__)
-//   #define HUGE HUGE_VAL
-// #endif
-//   distanceToUser = HUGE;
-//   FGScheduledFlightVecIterator i = flights.begin();
-//   while (i != flights.end())
-//     {
-//       dep = i->getDepartureAirport();
-//       //if (!(dep))
-//       //return HUGE;
-      
-//       SGWayPoint user (   userLongitude,
-//                       userLatitude,
-//                       i->getCruiseAlt());
-//       SGWayPoint current (dep->getLongitude(),
-//                       dep->getLatitude(),
-//                       0);
-//       user.CourseAndDistance(current, &course, &dist);
-//       if (dist < distanceToUser)
-//     {
-//       distanceToUser = dist;
-//       //cerr << "Found closest distance to user for " << registration << " to be " << distanceToUser << " at airport " << dep->getId() << endl;
-//     }
-//       i++;
-//     }
-//   //return distToUser;
-// }
+bool FGAISchedule::operator< (const FGAISchedule &other) const
+{ 
+    //cerr << "Sorting " << registration << " and "  << other.registration << endl;
+    double currentScore = score       * (1.5 - lastRun);
+    double otherScore   = other.score * (1.5 - other.lastRun);
+    return currentScore > otherScore;
+}