]> git.mxchange.org Git - flightgear.git/commitdiff
Traffic Manager II source code changes
authordurk <durk>
Sun, 16 Nov 2008 13:45:24 +0000 (13:45 +0000)
committerdurk <durk>
Sun, 16 Nov 2008 13:45:24 +0000 (13:45 +0000)
- Decouple aircraft entities from Flights
- Dynamic runtime flight assignment for each aircraft

src/Traffic/SchedFlight.cxx
src/Traffic/SchedFlight.hxx
src/Traffic/Schedule.cxx
src/Traffic/Schedule.hxx
src/Traffic/TrafficMgr.cxx
src/Traffic/TrafficMgr.hxx

index 52661664d4924368d76da665792e43c9dc8d03a2..0fad5b88d7af7fd7f47d032661361bcd80ae47f5 100644 (file)
 
 FGScheduledFlight::FGScheduledFlight()
 {
+   initialized = false;
+   available = true;
 }
   
 FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
 {
-  callsign        = other.callsign;
-  fltRules        = other.fltRules;
-  departurePort   = other.departurePort;
-  depId           = other.depId;
-  arrId           = other.arrId;
-  departureTime   = other.departureTime;
-  cruiseAltitude  = other.cruiseAltitude;
-  arrivalPort     = other.arrivalPort;
-  arrivalTime     = other.arrivalTime;
-  repeatPeriod    = other.repeatPeriod;
-  initialized     = other.initialized;
+  callsign          = other.callsign;
+  fltRules          = other.fltRules;
+  departurePort     = other.departurePort;
+  depId             = other.depId;
+  arrId             = other.arrId;
+  departureTime     = other.departureTime;
+  cruiseAltitude    = other.cruiseAltitude;
+  arrivalPort       = other.arrivalPort;
+  arrivalTime       = other.arrivalTime;
+  repeatPeriod      = other.repeatPeriod;
+  initialized       = other.initialized;
+  requiredAircraft  = other.requiredAircraft;
+  available         = other.available;
 }
 
 FGScheduledFlight::FGScheduledFlight(const string& cs,
@@ -103,7 +107,8 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
                   int cruiseAlt,
                   const string& deptime,
                   const string& arrtime,
-                  const string& rep)
+                  const string& rep,
+                   const string& reqAC)
 {
   callsign          = cs;
   fltRules          = fr;
@@ -115,6 +120,7 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
   //departureTime     = processTimeString(deptime);
   //arrivalTime       = processTimeString(arrtime);
   cruiseAltitude    = cruiseAlt;
+  requiredAircraft  = reqAC;
 
   // Process the repeat period string
   if (rep.find("WEEK",0) != string::npos)
@@ -136,11 +142,13 @@ FGScheduledFlight::FGScheduledFlight(const string& cs,
   // arrival times. 
   departureTime = processTimeString(deptime);
   arrivalTime   = processTimeString(arrtime);
+  //departureTime += rand() % 300; // Make sure departure times are not limited to 5 minute increments.
   if (departureTime > arrivalTime)
     {
       departureTime -= repeatPeriod;
     }
   initialized = false;
+  available   = true;
 }
 
 
index 63ba6c7fd403746a44cdb7a560aa95520b5d49f9..0ee3eb6bd1f9c5b3056daa27b0488810ec53c59b 100644 (file)
@@ -55,11 +55,14 @@ private:
   FGAirport *arrivalPort;
   string depId;
   string arrId;
+  string requiredAircraft;
   time_t departureTime;
   time_t arrivalTime;
   time_t repeatPeriod;
   int cruiseAltitude;
+  
   bool initialized;
+  bool available;
 
  
  
@@ -74,7 +77,8 @@ public:
                     int cruiseAlt,
                     const string& deptime,
                     const string& arrtime,
-                    const string& rep
+                    const string& rep,
+                     const string& reqAC
                     );
   ~FGScheduledFlight();
 
@@ -99,11 +103,19 @@ public:
 
   time_t processTimeString(const string& time);
   const string& getCallSign() {return callsign; };
+  const string& getRequirement() { return requiredAircraft; }
+
+  void lock() { available = false; };
+  void release() { available = true; };
+
+  bool isAvailable() { return available; };
 };
 
 typedef vector<FGScheduledFlight*>           FGScheduledFlightVec;
 typedef vector<FGScheduledFlight*>::iterator FGScheduledFlightVecIterator;
 
+typedef std::map < std::string, FGScheduledFlightVec > FGScheduledFlightMap;
+
 bool compareScheduledFlights(FGScheduledFlight *a, FGScheduledFlight *b);
 
 
index 699aa144c4f4fd89cbbb7020cfc153a1488b3171..2e365d5223210bbceb82f9e8c87be21802a988fa 100644 (file)
@@ -74,9 +74,10 @@ FGAISchedule::FGAISchedule()
   radius = 0;
   groundOffset = 0;
   distanceToUser = 0;
-  score = 0;
+  //score = 0;
 }
 
+/*
 FGAISchedule::FGAISchedule(string    mdl, 
                           string    liv, 
                           string    reg, 
@@ -88,59 +89,77 @@ FGAISchedule::FGAISchedule(string    mdl,
                           double rad,
                           double grnd,
                           int    scre,
-                          FGScheduledFlightVec flt)
+                          FGScheduledFlightVec flt)*/
+FGAISchedule::FGAISchedule(string model, 
+                           string lvry,
+                           string port, 
+                           string reg, 
+                           string flightId,
+                           bool   hvy, 
+                           string act, 
+                           string arln, 
+                           string mclass, 
+                           string fltpe, 
+                           double rad, 
+                           double grnd)
 {
-  modelPath    = mdl; 
-  livery       = liv; 
-  registration = reg;
-  acType       = act;
-  airline      = arln;
-  m_class      = mclass;
-  flightType   = fltpe;
-  lat = 0;
-  lon = 0;
-  radius       = rad;
-  groundOffset = grnd;
-  distanceToUser = 0;
-  heavy = hvy;
-  for (FGScheduledFlightVecIterator i = flt.begin();
+  modelPath        = model; 
+  livery           = lvry; 
+  homePort         = port;
+  registration     = reg;
+  flightIdentifier = flightId;
+  acType           = act;
+  airline          = arln;
+  m_class          = mclass;
+  flightType       = fltpe;
+  lat              = 0;
+  lon              = 0;
+  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    = scre;
-  firstRun = true;
+    flights.push_back(new FGScheduledFlight((*(*i))));*/
+  AIManagerRef     = 0;
+  //score    = scre;
+  firstRun         = true;
 }
 
 FGAISchedule::FGAISchedule(const FGAISchedule &other)
 {
-  modelPath    = other.modelPath;
-  livery       = other.livery;
-  registration = other.registration;
-  heavy        = other.heavy;
-  flights      = other.flights;
-  lat          = other.lat;
-  lon          = other.lon;
-  AIManagerRef = other.AIManagerRef;
-  acType       = other.acType;
-  airline      = other.airline;
-  m_class      = other.m_class;
-  firstRun     = other.firstRun;
-  radius       = other.radius;
-  groundOffset = other.groundOffset;
-  flightType   = other.flightType;
-  score        = other.score;
-  distanceToUser = other.distanceToUser;
+  modelPath          = other.modelPath;
+  homePort           = other.homePort;
+  livery             = other.livery;
+  registration       = other.registration;
+  heavy              = other.heavy;
+  flightIdentifier   = other.flightIdentifier;
+  flights            = other.flights;
+  lat                = other.lat;
+  lon                = other.lon;
+  AIManagerRef       = other.AIManagerRef;
+  acType             = other.acType;
+  airline            = other.airline;
+  m_class            = other.m_class;
+  firstRun           = other.firstRun;
+  radius             = other.radius;
+  groundOffset       = other.groundOffset;
+  flightType         = other.flightType;
+  //score            = other.score;
+  distanceToUser     = other.distanceToUser;
+  currentDestination = other.currentDestination;
+  firstRun           = other.firstRun;
 }
 
 
 FGAISchedule::~FGAISchedule()
 {
-  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
+/*  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
     {
       delete (*flt);
     }
-  flights.clear();
+  flights.clear();*/
 } 
 
 bool FGAISchedule::init()
@@ -153,14 +172,14 @@ bool FGAISchedule::init()
   //sgTimeFormatTime(&targetTimeDate, buffer);
   //cout << "Scheduled Time " << buffer << endl; 
   //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
-  for (FGScheduledFlightVecIterator i = flights.begin(); 
+  /*for (FGScheduledFlightVecIterator i = flights.begin(); 
        i != flights.end(); 
        i++)
     {
       //i->adjustTime(now);
       if (!((*i)->initializeAirports()))
        return false;
-    } 
+    } */
   //sort(flights.begin(), flights.end());
   // Since time isn't initialized yet when this function is called,
   // Find the closest possible airport.
@@ -170,7 +189,7 @@ bool FGAISchedule::init()
 }
 
 bool FGAISchedule::update(time_t now)
-{
+{ 
   FGAirport *dep;
   FGAirport *arr;
   double angle;
@@ -194,40 +213,51 @@ bool FGAISchedule::update(time_t now)
     return true;
   
   aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");  
-  // Before the flight status of this traffic entity is updated 
-  // for the first time, we need to roll back it's flight schedule so
-  // so that all the flights are centered around this simulated week's time
-  // table. This is to avoid the situation where the first scheduled flight is
-  // in the future, causing the traffic manager to not generate traffic until
-  // simulated time has caught up with the real world time at initialization.
-  // This is to counter a more general initialization bug, caused by the fact
-  // that warp is not yet set when the  schedule is initialized. This is
-  // especially a problem when using a negative time offset.
-  // i.e let's say we specify FlightGear to run with --time-offset=-24:00:00. 
-  // Then the schedule will initialize using today, but we will fly yesterday.
-  // Thus, it would take a whole day of simulation before the traffic manager
-  // finally kicks in. 
-  if (firstRun)
-    {
-      if (init() == false)
-       AIManagerRef = BOGUS;
-       
-      for (FGScheduledFlightVecIterator i = flights.begin(); 
-          i != flights.end(); 
-          i++)
-       {
-         (*i)->adjustTime(now);
-       }
-      if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true)
-       deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft 
-                                      // from cluttering the gate areas.
-      firstRun = false;
+    // Out-of-work aircraft seeks employment. Willing to work irregular hours ...
+    //cerr << "About to find a flight " << endl;
+    if (flights.empty()) {
+        //execute this loop at least once. 
+        SG_LOG(SG_GENERAL, SG_INFO, "Scheduling for : " << modelPath << " " <<  registration << " " << homePort);
+        FGScheduledFlight *flight = 0;
+         do {
+            flight = findAvailableFlight(currentDestination, flightIdentifier);
+            if (flight) {
+                currentDestination = flight->getArrivalAirport()->getId();
+                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_INFO, "  " << flight->getCallSign() << ":" 
+                                         << "  " << flight->getDepartureAirport()->getId() << ":"
+                                         << "  " << depT << ":"
+                                         << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
+                                         << "  " << arrT << ":");
+            flights.push_back(flight);
+            }
+        } while ((currentDestination != homePort) && (flight != 0));
+        SG_LOG(SG_GENERAL, SG_INFO, cerr << " Done " << endl);
     }
-  
+    //cerr << " Done " << endl;
+   // No flights available for this aircraft
+  if (flights.size() == 0) {
+      return false;
+  }
   // 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. 
-  sort(flights.begin(), flights.end(), compareScheduledFlights);
+  //sort(flights.begin(), flights.end(), compareScheduledFlights);
+ if (firstRun) {
+     if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) {
+         deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft 
+                                   // from cluttering the gate areas.
+         cerr << "Scheduling " << registration << " for instantaneous action flight " << endl;
+     }
+     firstRun = false;
+  }
   if (!deptime)
     deptime = (*flights.begin())->getDepartureTime();
   FGScheduledFlightVecIterator i = flights.begin();
@@ -251,7 +281,13 @@ bool FGAISchedule::update(time_t now)
       if (((*i)->getDepartureTime() < now) && ((*i)->getArrivalTime() < now))
        {
           SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager:      Flight is in the Past");
+          //cerr << modelPath << " " <<  registration << ": Flights from the past belong to the past :-)" << endl;
+          //exit(1);
+          // 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. 
          (*i)->update();
+          i = flights.erase(i);
          return true;
        }
 
@@ -357,7 +393,7 @@ bool FGAISchedule::update(time_t now)
          SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: " << registration << " is scheduled for a flight from " 
             << dep->getId() << " to " << arr->getId() << ". Current distance to user: " 
              << distanceToUser*SG_METER_TO_NM);
-         if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDIST)
+         if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDISTTOSTART)
            {
              string flightPlanName = dep->getId() + string("-") + arr->getId() + 
                string(".xml");
@@ -441,10 +477,102 @@ bool FGAISchedule::update(time_t now)
 }
 
 
-void FGAISchedule::next()
+bool FGAISchedule::next()
+{
+  FGScheduledFlightVecIterator i = flights.begin();
+  (*i)->release();
+  //FIXME: remove first entry, 
+  // load new flights until back at home airport
+  // Lock loaded flights
+  //sort(flights.begin(), flights.end(), compareScheduledFlights);
+  // until that time
+  i = flights.erase(i);
+  //cerr << "Next: scheduling for : " << modelPath << " " <<  registration << endl;
+  FGScheduledFlight *flight = findAvailableFlight(currentDestination, flightIdentifier);
+  if (flight) {
+      currentDestination = flight->getArrivalAirport()->getId();
+      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);
+      //cerr << "  " << flight->getCallSign() << ":" 
+      //     << "  " << flight->getDepartureAirport()->getId() << ":"
+      //     << "  " << depT << ":"
+      //     << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
+      //     << "  " << arrT << ":" << endl;
+
+       flights.push_back(flight);
+       return true;
+  } else {
+       return false;
+  }
+  //cerr << "FGAISchedule :: next needs updating" << endl;
+  //exit(1);
+}
+
+FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDestination,
+                                                      const string &req)
 {
-  (*flights.begin())->update();
-  sort(flights.begin(), flights.end(), compareScheduledFlights);
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+
+    FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
+    FGScheduledFlightVecIterator fltBegin, fltEnd;
+    fltBegin = tmgr->getFirstFlight(req);
+    fltEnd   = tmgr->getLastFlight(req);
+
+
+     //cerr << "Finding available flight " << endl;
+     // For Now:
+     // Traverse every registered flight
+     if (fltBegin == fltEnd) {
+          //cerr << "No Flights Scheduled for " << req << endl;
+     }
+     int counter = 0;
+     for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
+          (*i)->adjustTime(now);
+           //sort(fltBegin, fltEnd, compareScheduledFlights);
+           //cerr << counter++ << endl;
+     }
+     sort(fltBegin, fltEnd, compareScheduledFlights);
+     for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
+          //bool valid = true;
+          counter++;
+          if (!(*i)->isAvailable()) {
+               //cerr << (*i)->getCallSign() << "is no longer available" << endl;
+               continue;
+          }
+          if (!((*i)->getRequirement() == req)) {
+               continue;
+          }
+          if (!(((*i)->getArrivalAirport()) && ((*i)->getDepartureAirport()))) {
+              continue;
+          }
+          if (!(currentDestination.empty())) {
+              if (currentDestination != (*i)->getDepartureAirport()->getId()) {
+                   //cerr << (*i)->getCallSign() << "Doesn't match destination" << endl;
+                   //cerr << "Current Destination " << currentDestination << "Doesnt match flight's " <<
+                   //          (*i)->getArrivalAirport()->getId() << endl;
+                   continue;
+              }
+          }
+          //TODO: check time
+          // So, if we actually get here, we have a winner
+          //cerr << "found flight: " << req << " : " << currentDestination << " : " <<       
+          //         (*i)->getArrivalAirport()->getId() << endl;
+          (*i)->lock();
+          return (*i);
+     }
+     // matches req?
+     // if currentDestination has a value, does it match departure of next flight?
+     // is departure time later than planned arrival?
+     // is departure port valid?
+     // is arrival port valid?
+     //cerr << "Ack no flight found: " << endl;
+     return 0;
 }
 
 double FGAISchedule::getSpeed()
@@ -472,12 +600,20 @@ double FGAISchedule::getSpeed()
   dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
   speed =  (distanceToDest*SG_METER_TO_NM) / 
     ((double) remainingTimeEnroute/3600.0);
+  if (speed < 300) {
+     //cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is low : " << speed << " clamping to 300" << endl;
+     speed = 300.0;
+  }
+  if (speed > 500) {
+     //cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is high : " << speed << " clamping to 300" << endl;
+     speed = 500.0;
+  }
   return speed;
 }
 
 bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
 { 
-  return (*a) < (*b); 
+  //return (*a) < (*b); 
 } 
 
 
index f18d7492e572bd448d67a6d34ef57a739702f4f5..5511a7d1a258e01534376b99b7efbda037c47255 100644 (file)
 #ifndef _FGSCHEDULE_HXX_
 #define _FGSCHEDULE_HXX_
 
-#define TRAFFICTOAIDIST 150.0
+#define TRAFFICTOAIDISTTOSTART 150.0
+#define TRAFFICTOAIDISTTODIE   200.0
 
 
 class FGAISchedule
 {
  private:
   string modelPath;
+  string homePort;
   string livery;
   string registration;
   string airline;
   string acType;
   string m_class;
   string flightType;
+  string flightIdentifier;
+  string currentDestination;
   bool heavy;
   FGScheduledFlightVec flights;
   float lat;
@@ -50,14 +54,25 @@ class FGAISchedule
   double groundOffset;
   double distanceToUser;
   int AIManagerRef;
-  int score;
+  //int score;
   bool firstRun;
+  
 
 
  public:
   FGAISchedule();                                           // constructor
-  FGAISchedule(string, string, string, bool, string, string, string, string, double, double, 
-              int, FGScheduledFlightVec);                  // construct & init
+  FGAISchedule(string model, 
+               string livery,
+               string homePort, 
+               string registration, 
+               string flightId,
+               bool   heavy, 
+               string acType, 
+               string airline, 
+               string m_class, 
+               string flight_type, 
+               double radius, 
+               double offset);                              // construct & init
   FGAISchedule(const FGAISchedule &other);                  // copy constructor
 
 
@@ -69,9 +84,10 @@ class FGAISchedule
 
   double getSpeed         ();
   //void setClosestDistanceToUser();
-  void next();   // forces the schedule to move on to the next flight.
+  bool next();   // forces the schedule to move on to the next flight.
 
-  time_t      getDepartureTime    () { return (*flights.begin())->getDepartureTime   (); };
+  // TODO: rework these four functions
+   time_t      getDepartureTime    () { return (*flights.begin())->getDepartureTime   (); };
   FGAirport * getDepartureAirport () { return (*flights.begin())->getDepartureAirport(); };
   FGAirport * getArrivalAirport   () { return (*flights.begin())->getArrivalAirport  (); };
   int         getCruiseAlt        () { return (*flights.begin())->getCruiseAlt       (); };
@@ -84,9 +100,10 @@ class FGAISchedule
   const string& getRegistration   () { return registration;};
   const string& getFlightRules    () { return (*flights.begin())->getFlightRules (); };
   bool getHeavy                   () { return heavy; };
+  FGScheduledFlight*findAvailableFlight (const string &currentDestination, const string &req);
   // used to sort in decending order of score: I've probably found a better way to
   // decending order sorting, but still need to test that.
-  bool operator< (const FGAISchedule &other) const { return (score > other.score); };
+  //bool operator< (const FGAISchedule &other) const { return (score > other.score); };
   //void * getAiRef                 () { return AIManagerRef; };
   //FGAISchedule* getAddress        () { return this;};
 
index 3a8eb5513cdc5fd180927dbbd8cb7b078d2aea4e..07d0cd0ab2626f0ac1c4842f8f8377ff4c3f171f 100644 (file)
  *
  **************************************************************************/
  
-/* This a prototype version of a top-level flight plan manager for Flightgear.
- * It parses the fgtraffic.txt file and determine for a specific time/date, 
- * where each aircraft listed in this file is at the current time. 
+/* 
+ * Traffic manager parses airlines timetable-like data and uses this to 
+ * determine the approximate position of each AI aircraft in its database.
+ * When an AI aircraft is close to the user's position, a more detailed 
+ * AIModels based simulation is set up. 
  * 
  * I'm currently assuming the following simplifications:
  * 1) The earth is a perfect sphere
@@ -77,8 +79,9 @@ using std::sort;
  *****************************************************************************/
 FGTrafficManager::FGTrafficManager()
 {
-  score = 0;
-  runCount = 0;
+  //score = 0;
+  //runCount = 0;
+  acCounter = 0;
 }
 
 FGTrafficManager:: ~FGTrafficManager()
@@ -88,50 +91,22 @@ FGTrafficManager:: ~FGTrafficManager()
       delete (*sched);
     }
   scheduledAircraft.clear();
-  // for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
-//     {
-//       delete (*flt);
-//     }
-//   flights.clear();
+  flights.clear();
 }
 
 
 void FGTrafficManager::init()
 { 
-  //cerr << "Initializing Schedules" << endl;
-  //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-  //currAircraft = scheduledAircraft.begin();
-  //while (currAircraft != scheduledAircraft.end())
-  //  {
-  //    if (!(currAircraft->init()))
-  //   {
-  //     currAircraft=scheduledAircraft.erase(currAircraft);
-  //     //cerr << "Erasing " << currAircraft->getRegistration() << endl;
-  //   }
-  //   else 
-  //   {
-  //     currAircraft++;
-  //   }
-  //   }
-  // Sort by points: Aircraft with frequent visits to the
-  // startup airport will be processed first
   ulDir* d, *d2;
   ulDirEnt* dent, *dent2;
   SGPath aircraftDir = globals->get_fg_root();
 
-  /* keep the following three lines (which mimicks the old "fixed path" behavior)
-   * until we have some AI models with traffic in the base package
-   */ 
   SGPath path = aircraftDir;
-  path.append("Traffic/fgtraffic.xml");
-  if (path.exists())
-    readXML(path.str(),*this);
-
-  aircraftDir.append("AI/Aircraft");
+  
+  aircraftDir.append("AI/Traffic");
   if ((d = ulOpenDir(aircraftDir.c_str())) != NULL)
     {
       while((dent = ulReadDir(d)) != NULL) {
-       //cerr << "Scanning : " << dent->d_name << endl;
        if (string(dent->d_name) != string(".")  && 
            string(dent->d_name) != string("..") &&
            dent->d_isdir)
@@ -145,7 +120,6 @@ void FGTrafficManager::init()
              currFile.append(dent2->d_name);
              if (currFile.extension() == string("xml"))
                {
-                 //cerr << "found " << dent2->d_name << " for parsing" << endl;
                  SGPath currFile = currACDir;
                  currFile.append(dent2->d_name);
                  SG_LOG(SG_GENERAL, SG_INFO, "Scanning " << currFile.str() << " for traffic");
@@ -157,12 +131,10 @@ void FGTrafficManager::init()
       }
       ulCloseDir(d);
     }
-  // Sort by points: Aircraft with frequent visits to the
-  // startup airport will be processed first
-  sort(scheduledAircraft.begin(), scheduledAircraft.end(), compareSchedules);
-  currAircraft = scheduledAircraft.begin();
-  currAircraftClosest = scheduledAircraft.begin();
-  //cerr << "Done initializing schedules" << endl;
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+
+    currAircraft = scheduledAircraft.begin();
+    currAircraftClosest = scheduledAircraft.begin();
 }
 
 void FGTrafficManager::update(double /*dt*/)
@@ -170,7 +142,6 @@ void FGTrafficManager::update(double /*dt*/)
 
   time_t now = time(NULL) + fgGetLong("/sim/time/warp");
   if (scheduledAircraft.size() == 0) {
-    //SG_LOG( SG_GENERAL, SG_INFO, "Returned Running TrafficManager::Update() ");
     return;
   }
   if(currAircraft == scheduledAircraft.end())
@@ -179,12 +150,12 @@ void FGTrafficManager::update(double /*dt*/)
     }
   if (!((*currAircraft)->update(now)))
     {
+      // NOTE: With traffic manager II, this statement below is no longer true
       // after proper initialization, we shouldnt get here.
       // But let's make sure
-      SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager");
+      //SG_LOG( SG_GENERAL, SG_ALERT, "Failed to update aircraft schedule in traffic manager");
     }
   currAircraft++;
-  //SG_LOG( SG_GENERAL, SG_INFO, "Done Running TrafficManager::Update() ");
 }
 
 void FGTrafficManager::release(int id)
@@ -206,9 +177,181 @@ bool FGTrafficManager::isReleased(int id)
     }
   return false;
 }
+/*
+void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
+{
+    string model;
+    string livery;
+    string homePort;
+    string registration;
+    string flightReq;
+    bool   isHeavy;
+    string acType;
+    string airline;
+    string m_class;
+    string FlightType;
+    double radius;
+    double offset;
+
+    char buffer[256];
+    string buffString;
+    vector <string> tokens, depTime,arrTime;
+    vector <string>::iterator it;
+    ifstream infile(infileName.str().c_str());
+    while (1) {
+         infile.getline(buffer, 256);
+         if (infile.eof()) {
+             break;
+         }
+         //cerr << "Read line : " << buffer << endl;
+         buffString = string(buffer);
+         tokens.clear();
+         Tokenize(buffString, tokens, " \t");
+         //for (it = tokens.begin(); it != tokens.end(); it++) {
+         //    cerr << "Tokens: " << *(it) << endl;
+         //}
+         //cerr << endl;
+         if (!tokens.empty()) {
+             if (tokens[0] == string("AC")) {
+                 if (tokens.size() != 13) {
+                     SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
+                     exit(1);
+                 }
+                 model          = tokens[12];
+                 livery         = tokens[6];
+                 homePort       = tokens[1];
+                 registration   = tokens[2];
+                 if (tokens[11] == string("false")) {
+                     isHeavy = false;
+                 } else {
+                     isHeavy = true;
+                 }
+                 acType         = tokens[4];
+                 airline        = tokens[5];
+                 flightReq      = tokens[3] + tokens[5];
+                 m_class        = tokens[10];
+                 FlightType     = tokens[9];
+                 radius         = atof(tokens[8].c_str());
+                 offset         = atof(tokens[7].c_str());;
+                 //cerr << "Found AC string " << model << " " << livery << " " << homePort << " " 
+                 //     << registration << " " << flightReq << " " << isHeavy << " " << acType << " " << airline << " " << m_class 
+                 //     << " " << FlightType << " " << radius << " " << offset << endl;
+                 scheduledAircraft.push_back(new FGAISchedule(model, 
+                                                              livery, 
+                                                              homePort,
+                                                              registration, 
+                                                              flightReq,
+                                                              isHeavy,
+                                                              acType, 
+                                                              airline, 
+                                                              m_class, 
+                                                              FlightType,
+                                                              radius,
+                                                              offset));
+             }
+             if (tokens[0] == string("FLIGHT")) {
+                 //cerr << "Found flight " << buffString << " size is : " << tokens.size() << endl;
+                 if (tokens.size() != 10) {
+                     SG_LOG(SG_GENERAL, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
+                     exit(1);
+                 }
+                 string callsign = tokens[1];
+                 string fltrules = tokens[2];
+                 string weekdays = tokens[3];
+                 string departurePort = tokens[5];
+                 string arrivalPort   = tokens[7];
+                 int    cruiseAlt     = atoi(tokens[8].c_str());
+                 string depTimeGen    = tokens[4];
+                 string arrTimeGen    = tokens[6];
+                 string repeat        = "WEEK";
+                 string requiredAircraft = tokens[9];
+                 
+                 if (weekdays.size() != 7) {
+                     cerr << "Found misconfigured weekdays string" << weekdays << endl;
+                     exit(1);
+                 }
+                 depTime.clear();
+                 arrTime.clear();
+                 Tokenize(depTimeGen, depTime, ":");
+                 Tokenize(arrTimeGen, arrTime, ":");
+                 double dep = atof(depTime[0].c_str()) + (atof(depTime[1].c_str()) / 60.0);
+                 double arr = atof(arrTime[0].c_str()) + (atof(arrTime[1].c_str()) / 60.0);
+                 //cerr << "Using " << dep << " " << arr << endl;
+                 bool arrivalWeekdayNeedsIncrement = false;
+                 if (arr < dep) {
+                       arrivalWeekdayNeedsIncrement = true;
+                 }
+                 for (int i = 0; i < 7; i++) {
+                     if (weekdays[i] != '.') {
+                         char buffer[4];
+                         snprintf(buffer, 4, "%d/", i);
+                         string departureTime = string(buffer) + depTimeGen + string(":00");
+                         string arrivalTime;
+                         if (!arrivalWeekdayNeedsIncrement) {
+                             arrivalTime   = string(buffer) + arrTimeGen + string(":00");
+                         }
+                         if (arrivalWeekdayNeedsIncrement && i != 6 ) {
+                             snprintf(buffer, 4, "%d/", i+1);
+                             arrivalTime   = string(buffer) + arrTimeGen + string(":00");
+                         }
+                         if (arrivalWeekdayNeedsIncrement && i == 6 ) {
+                             snprintf(buffer, 4, "%d/", 0);
+                             arrivalTime   = string(buffer) + arrTimeGen  + string(":00");
+                         }
+                         cerr << "Adding flight: " << callsign       << " "
+                                                   << fltrules       << " "
+                                                   <<  departurePort << " "
+                                                   <<  arrivalPort   << " "
+                                                   <<  cruiseAlt     << " "
+                                                   <<  departureTime << " "
+                                                   <<  arrivalTime   << " "
+                                                   <<  repeat        << " " 
+                                                   <<  requiredAircraft << endl;
+
+                         flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
+                                                                 fltrules,
+                                                                 departurePort,
+                                                                 arrivalPort,
+                                                                 cruiseAlt,
+                                                                 departureTime,
+                                                                 arrivalTime,
+                                                                 repeat,
+                                                                 requiredAircraft));
+                    }
+                }
+             }
+         }
+
+    }
+    //exit(1);
+}*/
+
+/*
+void FGTrafficManager::Tokenize(const string& str,
+                      vector<string>& tokens,
+                      const string& delimiters)
+{
+    // Skip delimiters at beginning.
+    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+    // Find first "non-delimiter".
+    string::size_type pos     = str.find_first_of(delimiters, lastPos);
+
+    while (string::npos != pos || string::npos != lastPos)
+    {
+        // Found a token, add it to the vector.
+        tokens.push_back(str.substr(lastPos, pos - lastPos));
+        // Skip delimiters.  Note the "not_of"
+        lastPos = str.find_first_not_of(delimiters, pos);
+        // Find next "non-delimiter"
+        pos = str.find_first_of(delimiters, lastPos);
+    }
+}
+*/
 
 void  FGTrafficManager::startXML () {
   //cout << "Start XML" << endl;
+  requiredAircraft = "";
+  homePort         = "";
 }
 
 void  FGTrafficManager::endXML () {
@@ -245,12 +388,16 @@ void  FGTrafficManager::endElement (const char * name) {
     mdl = value;
   else if (element == string("livery"))
     livery = value;
+  else if (element == string("home-port"))
+    homePort = value;
   else if (element == string("registration"))
     registration = value;
   else if (element == string("airline"))
     airline = value;
   else if (element == string("actype"))
     acType = value;
+  else if (element == string("required-aircraft"))
+    requiredAircraft = value;
   else if (element == string("flighttype"))
     flighttype = value;
   else if (element == string("radius"))
@@ -299,42 +446,91 @@ void  FGTrafficManager::endElement (const char * name) {
       //Prioritize aircraft 
       string apt = fgGetString("/sim/presets/airport-id");
       //cerr << "Airport information: " << apt << " " << departurePort << " " << arrivalPort << endl;
-      if (departurePort == apt) score++;
-      flights.push_back(new FGScheduledFlight(callsign,
-                                         fltrules,
-                                         departurePort,
-                                         arrivalPort,
-                                         cruiseAlt,
-                                         departureTime,
-                                         arrivalTime,
-                                         repeat));
+      //if (departurePort == apt) score++;
+      //flights.push_back(new FGScheduledFlight(callsign,
+       //                                fltrules,
+       //                                departurePort,
+       //                                arrivalPort,
+       //                                cruiseAlt,
+       //                                departureTime,
+       //                                arrivalTime,
+       //                                repeat));
+    if (requiredAircraft == "") {
+        char buffer[16];
+        snprintf(buffer, 16, "%d", acCounter);
+        requiredAircraft = buffer;
     }
+    SG_LOG(SG_GENERAL, SG_DEBUG, "Adding flight: " << callsign       << " "
+                              << fltrules       << " "
+                              <<  departurePort << " "
+                              <<  arrivalPort   << " "
+                              <<  cruiseAlt     << " "
+                              <<  departureTime << " "
+                              <<  arrivalTime   << " "
+                              <<  repeat        << " " 
+                              <<  requiredAircraft);
+
+     flights[requiredAircraft].push_back(new FGScheduledFlight(callsign,
+                                                                 fltrules,
+                                                                 departurePort,
+                                                                 arrivalPort,
+                                                                 cruiseAlt,
+                                                                 departureTime,
+                                                                 arrivalTime,
+                                                                 repeat,
+                                                                 requiredAircraft));
+      requiredAircraft = "";
+  }
   else if (element == string("aircraft"))
     {
       int proportion = (int) (fgGetDouble("/sim/traffic-manager/proportion") * 100);
       int randval = rand() & 100;
       if (randval < proportion) {
-          scheduledAircraft.push_back(new FGAISchedule(mdl, 
-                                              livery, 
-                                              registration, 
-                                              heavy,
-                                              acType, 
-                                              airline, 
-                                              m_class, 
-                                              flighttype,
-                                              radius,
-                                              offset,
-                                              score,
-                                              flights));
+          //scheduledAircraft.push_back(new FGAISchedule(mdl, 
+       //                                     livery, 
+       //                                     registration, 
+       //                                     heavy,
+       //                                     acType, 
+       //                                     airline, 
+       //                                     m_class, 
+       //                                     flighttype,
+       //                                     radius,
+       //                                     offset,
+       //                                     score,
+       //                                     flights));
+    if (requiredAircraft == "") {
+        char buffer[16];
+        snprintf(buffer, 16, "%d", acCounter);
+        requiredAircraft = buffer;
+    }
+    if (homePort == "") {
+        homePort = departurePort;
+    }
+            scheduledAircraft.push_back(new FGAISchedule(mdl, 
+                                                         livery, 
+                                                         homePort,
+                                                         registration, 
+                                                         requiredAircraft,
+                                                         heavy,
+                                                         acType, 
+                                                         airline, 
+                                                         m_class, 
+                                                         flighttype,
+                                                         radius,
+                                                         offset));
+
      //  while(flights.begin() != flights.end()) {
 //     flights.pop_back();
 //       }
-      }
-  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
-    {
-      delete (*flt);
-    }
-  flights.clear();
+        }
+    acCounter++;
+    requiredAircraft = "";
+    homePort = "";
+  //for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
+  //  {
+  //    delete (*flt);
+  //  }
+  //flights.clear();
       SG_LOG( SG_GENERAL, SG_BULK, "Reading aircraft : " 
              << registration 
              << " with prioritization score " 
@@ -360,3 +556,4 @@ void  FGTrafficManager::warning (const char * message, int line, int column) {
 void  FGTrafficManager::error (const char * message, int line, int column) {
   SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
 }
+
index 23d9b4c6cfce213f46f44b7dbae2fce7b22e9f9b..c1a4465a8ea0b13af6bb8367acdd9c1285a44bf5 100644 (file)
 /**************************************************************************
  * This file contains the class definitions for a (Top Level) traffic
  * manager for FlightGear. 
+ * 
+ * This is traffic manager version II. The major difference from version 
+ * I is that the Flight Schedules are decoupled from the AIAircraft
+ * entities. This allows for a much greater flexibility in setting up
+ * Irregular schedules. Traffic Manager II also makes no longer use of .xml
+ * based configuration files. 
+ * 
+ * Here is a step plan to achieve the goal of creating Traffic Manager II
+ * 
+ * 1) Read aircraft data from a simple text file, like the one provided by
+ *    Gabor Toth
+ * 2) Create a new database structure of SchedFlights. This new database 
+ *    should not be part of the Schedule class, but of TrafficManager itself
+ * 3) Each aircraft should have a list of possible Flights it can operate
+ *    (i.e. airline and AC type match). 
+ * 4) Aircraft processing proceeds as current. During initialization, we seek 
+ *    the most urgent flight that needs to be operated 
+ * 5) Modify the getNextLeg function so that the next flight is loaded smoothly.
  **************************************************************************/
 
 #ifndef _TRAFFICMGR_HXX_
@@ -29,6 +48,7 @@
 
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/xml/easyxml.hxx>
+#include <simgear/misc/sg_path.hxx>
 
 #include "SchedFlight.hxx"
 #include "Schedule.hxx"
@@ -47,15 +67,18 @@ private:
 
   string mdl, livery, registration, callsign, fltrules, 
     port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
-    repeat, acType, airline, m_class, flighttype;
+    repeat, acType, airline, m_class, flighttype, requiredAircraft, homePort;
   int cruiseAlt;
-  int score, runCount;
+  int score, runCount, acCounter;
   double radius, offset;
   bool heavy;
 
   IdList releaseList;
     
-  FGScheduledFlightVec flights;
+  FGScheduledFlightMap flights;
+
+  //void readTimeTableFromFile(SGPath infilename);
+  //void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ");
 
 public:
   FGTrafficManager();
@@ -65,6 +88,9 @@ public:
   void release(int ref);
   bool isReleased(int id);
 
+  FGScheduledFlightVecIterator getFirstFlight(const string &ref) { return flights[ref].begin(); }
+  FGScheduledFlightVecIterator getLastFlight(const string &ref) { return flights[ref].end(); }
+
   // Some overloaded virtual XMLVisitor members
   virtual void startXML (); 
   virtual void endXML   ();