]> git.mxchange.org Git - flightgear.git/commitdiff
Add the AIModel based air traffic subsystem from Durk Talsma.
authorehofman <ehofman>
Thu, 3 Jun 2004 17:59:14 +0000 (17:59 +0000)
committerehofman <ehofman>
Thu, 3 Jun 2004 17:59:14 +0000 (17:59 +0000)
19 files changed:
Thanks
configure.ac
src/AIModel/AIBase.hxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIManager.cxx
src/AIModel/AIScenario.cxx
src/FDM/JSBSim/FGTrimAxis.cpp
src/Main/Makefile.am
src/Main/fg_init.cxx
src/Main/globals.hxx
src/Makefile.am
src/Traffic/Makefile.am [new file with mode: 0644]
src/Traffic/SchedFlight.cxx [new file with mode: 0644]
src/Traffic/SchedFlight.hxx [new file with mode: 0644]
src/Traffic/Schedule.cxx [new file with mode: 0644]
src/Traffic/Schedule.hxx [new file with mode: 0644]
src/Traffic/TrafficMgr.cxx [new file with mode: 0644]
src/Traffic/TrafficMgr.hxx [new file with mode: 0644]

diff --git a/Thanks b/Thanks
index e8cd8c8e9c94f287b91d8582d6e5194d5c864b40..e1e9ba2f75179122e7fc3c5689b103a69d6d7d6a 100644 (file)
--- a/Thanks
+++ b/Thanks
@@ -145,7 +145,7 @@ Bruce Finney <bfinney@gte.net>
 Melchior Franz <a8603365@unet.univie.ac.at>
   Made that joystick high/low support for joystick hats.
   Nasal-ified the Saitek Cyborg Gold 3D (USB) joystick which now forms
-  the basis of a lot of porgrammable joysticks.
+  the basis of a lot of programmable joysticks.
   Created the led.txf font.
   Ruthlessly hunted down memory leaks in FlightGear, SimGear, and JSBSim.
   Maintains the only fully working helicopter model in FlightGear (Bolkow 105).
index 73b49cb5a6a70ae80216306e39c6c856b26f3fa9..797e353fa90e30382cfb2424bccbb2eea87c4903 100644 (file)
@@ -120,7 +120,7 @@ case "${host}" in
     if test -d /opt/X11R6 ; then
         EXTRA_DIR2="/opt/X11R6"
     fi
-    EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2"
+    EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2 /usr/local/"
     ;;
 
 esac
@@ -564,6 +564,7 @@ AC_CONFIG_FILES([ \
        src/Sound/Makefile \
        src/Systems/Makefile \
        src/Time/Makefile \
+       src/Traffic/Makefile \
        tests/Makefile \
        utils/Makefile \
        utils/TerraSync/Makefile \
index b9db98c6c889665aa7781cdd2571b894d907eaf9..b98cb5d260980156b391062c32382c7fd87ea7f4 100644 (file)
@@ -163,6 +163,7 @@ inline void FGAIBase::setAltitude( double altitude_ft ) {
 
 inline void FGAIBase::setBank( double bank ) {
   roll = tgt_roll = bank;
+  no_roll = false;
 }
 
 inline void FGAIBase::setLongitude( double longitude ) {
index 289d850dd374ffa35f857c5d91b9c3c37b2d1640..b8fdc884bcc412ca7292cf0bed37e50eb6447cde 100644 (file)
@@ -20,6 +20,7 @@
 #include "AIFlightPlan.hxx"
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/debug/logstream.hxx>
+#include <simgear/route/waypoint.hxx>
 #include <simgear/structure/exception.hxx>
 #include <simgear/constants.h>
 #ifdef __BORLANDC__
@@ -72,6 +73,124 @@ FGAIFlightPlan::FGAIFlightPlan(string filename)
 }
 
 
+// This is a modified version of the constructor,
+// Which not only reads the waypoints from a 
+// Flight plan file, but also adds the current
+// Position computed by the traffic manager, as well
+// as setting speeds and altitude computed by the
+// traffic manager. 
+FGAIFlightPlan::FGAIFlightPlan(string filename, 
+                              double lat, 
+                              double lon,
+                              double alt,
+                              double speed,
+                              double course)
+{
+  int i;
+  bool useInitialWayPoint = true;
+  SGPath path( globals->get_fg_root() );
+  path.append( ("/Data/AI/FlightPlans/" + filename).c_str() );
+  SGPropertyNode root;
+
+  try {
+      readProperties(path.str(), &root);
+  } catch (const sg_exception &e) {
+      SG_LOG(SG_GENERAL, SG_ALERT,
+       "Error reading AI flight plan: ");
+       cout << path.str() << endl;
+      return;
+  }
+
+  SGPropertyNode * node = root.getNode("flightplan");
+  // First waypoint is current position of the aircraft as
+  // dictated by the traffic manager. 
+  waypoint* init_waypoint   = new waypoint;
+  init_waypoint->name       = string("initial position");
+  init_waypoint->latitude   = lat;
+  init_waypoint->longitude  = lon;
+  init_waypoint->altitude   = alt;
+  init_waypoint->speed      = speed;
+  init_waypoint->crossat    = - 10000;
+  init_waypoint->gear_down  = false;
+  init_waypoint->flaps_down = false;
+  waypoints.push_back( init_waypoint );
+  for (i = 0; i < node->nChildren(); i++) { 
+     //cout << "Reading waypoint " << i << endl;
+     waypoint* wpt = new waypoint;
+     SGPropertyNode * wpt_node = node->getChild(i);
+     wpt->name      = wpt_node->getStringValue("name", "END");
+     wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
+     wpt->longitude = wpt_node->getDoubleValue("lon", 0);
+     wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
+     wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
+     //wpt->speed     = speed;
+     wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
+     wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
+     wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
+
+     if (wpt->name == "END") wpt->finished = true;
+     else wpt->finished = false;
+     // discard this waypoint if it's bearing differs more than
+     // 90 degrees from the course we should fly according to the
+     // Traffic manager. Those are considered "behind" us.
+     SGWayPoint first(init_waypoint->longitude, 
+                     init_waypoint->latitude, 
+                     init_waypoint->altitude);
+     SGWayPoint curr (wpt->longitude, 
+                     wpt->latitude, 
+                     wpt->altitude);
+     double crse, crsDiff;
+     double dist;
+     first.CourseAndDistance(curr, &crse, &dist);
+
+     dist *= SG_METER_TO_NM;
+
+     // We're only interested in the absolute value of crsDiff
+     // wich should fall in the 0-180 deg range.
+     crsDiff = fabs(crse-course);
+     if (crsDiff > 180)
+       crsDiff -= 180;
+     // These are the threee conditions that we consder including
+     // in our flight plan:
+     // 1) current waypoint is less then 100 miles away OR
+     // 2) curren waypoint is ahead of us, at any distance
+     bool useWpt = false;
+     if ((dist > 100.0) && (crsDiff > 90.0) && (wpt->name != string ("EOF")))
+       {
+        //useWpt = false;
+        // Once we start including waypoints, we have to continue, even though
+        // one of the following way point would suffice. 
+        // so once is the useWpt flag is set to true, we cannot reset it to false.
+        // cerr << "Discarding waypoint: " << wpt->name 
+        //    << ": Course difference = " << crsDiff << endl;
+       }
+     else
+       useWpt = true;
+     
+     if (useWpt)
+       {
+        if ((dist > 100.0) && (useInitialWayPoint))
+          {
+            waypoints.push_back(init_waypoint);
+            //cerr << "Using waypoint : " << init_waypoint->name <<  endl;
+          }
+        waypoints.push_back( wpt );
+        //cerr << "Using waypoint : " << wpt->name 
+        //    << ": course diff : " << crsDiff 
+        //      << "distance      : " << dist << endl;
+        useInitialWayPoint = false;
+       }
+     else 
+       delete wpt;
+  }
+  
+  wpt_iterator = waypoints.begin();
+  //cout << waypoints.size() << " waypoints read." << endl;
+}
+
+
+
+
 FGAIFlightPlan::~FGAIFlightPlan()
 {
   waypoints.clear();
@@ -144,32 +263,41 @@ double FGAIFlightPlan::getBearing(waypoint* first, waypoint* second){
 
 
 double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){
-  double latd = lat;
-  double lond = lon;
-  double latt = wp->latitude;
-  double lont = wp->longitude;
-  double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES);
-  double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES);
-
-  if (lond < 0.0) lond+=360.0;
-  if (lont < 0.0) lont+=360.0;
-  latd+=90.0;
-  latt+=90.0;
-
-  double lat_diff = (latt - latd) * ft_per_deg_lat;
-  double lon_diff = (lont - lond) * ft_per_deg_lon;
-  double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES;
-
-  bool southerly = true;
-  if (latt > latd) southerly = false;
-  bool easterly = false;
-  if (lont > lond) easterly = true;
-  if (southerly && easterly) return 90.0 + angle;
-  if (!southerly && easterly) return 90.0 - angle;
-  if (southerly && !easterly) return 270.0 - angle;
-  if (!southerly && !easterly) return 270.0 + angle; 
+  double course, distance;
+ //  double latd = lat;
+//   double lond = lon;
+//   double latt = wp->latitude;
+//   double lont = wp->longitude;
+//   double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES);
+//   double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES);
+
+//   if (lond < 0.0) {
+//     lond+=360.0;
+//     lont+=360;
+//   }
+//   if (lont < 0.0) {
+//     lond+=360.0;
+//     lont+=360.0;
+//   }
+//   latd+=90.0;
+//   latt+=90.0;
+
+//   double lat_diff = (latt - latd) * ft_per_deg_lat;
+//   double lon_diff = (lont - lond) * ft_per_deg_lon;
+//   double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES;
 
+//   bool southerly = true;
+//   if (latt > latd) southerly = false;
+//   bool easterly = false;
+//   if (lont > lond) easterly = true;
+//   if (southerly && easterly) return 90.0 + angle;
+//   if (!southerly && easterly) return 90.0 - angle;
+//   if (southerly && !easterly) return 270.0 - angle;
+//   if (!southerly && !easterly) return 270.0 + angle; 
+  SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
+  sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
+  return course;
   // Omit a compiler warning.
-  return 0;
 }
 
index bc75b9ab32cfe2c85c6c53e35c2552f6ab50c2d8..50040e554714e48a4047b80788ae7f3083846451 100644 (file)
@@ -44,6 +44,12 @@ public:
   } waypoint;
 
    FGAIFlightPlan(string filename);
+  FGAIFlightPlan(string filename, 
+                double lat, 
+                double lon, 
+                double alt, 
+                double speed, 
+                double course);
    ~FGAIFlightPlan();
 
    waypoint* getPreviousWaypoint( void );
index 1aed8f732f923735d1ff07615e07d50ebff3eff5..3667d15568d7606779349176575442f052ecebd1 100644 (file)
@@ -123,7 +123,7 @@ int FGAIManager::assignID() {
   int maxint = 30000;
   int x; 
   bool used;
-  for (x=0; x<maxint; x++) {
+  for (x=1; x<maxint; x++) {
      used = false;
      id_itr = ids.begin();
      while( id_itr != ids.end() ) {
index dcd87360f32f8f7871181f02fc3455c3a1b247cc..ac4e100b57721d86410beb28caa47a46bdc3885f 100644 (file)
@@ -67,8 +67,8 @@ FGAIScenario::FGAIScenario(string filename)
      en->azimuth        = entry_node->getDoubleValue("azimuth", 0.0); 
      en->elevation      = entry_node->getDoubleValue("elevation", 0.0); 
      en->rudder         = entry_node->getDoubleValue("rudder", 0.0);
-     en->strength       = entry_node->getDoubleValue("strength", 0.0);
-     en->diameter       = entry_node->getDoubleValue("diameter", 0.0);
+     en->strength       = entry_node->getDoubleValue("strength-fps", 0.0);
+     en->diameter       = entry_node->getDoubleValue("diameter-ft", 0.0);
    }
 
   entry_iterator = entries.begin();
index e95d1c54bfc0e564f268172178d6e592be3d2643..9181bae7c1dcc72812c713e3e14d170ef90c935e 100644 (file)
@@ -290,7 +290,8 @@ void FGTrimAxis::SetThetaOnGround(double ff) {
 
 bool FGTrimAxis::initTheta(void) {
   int i,N,iAft, iForward;
-  double zAft,zForward,zDiff,theta;
+  double zAft,zForward,zDiff,theta; 
+  double xAft,xForward,xDiff;
   bool level;  
   double saveAlt;
   
@@ -317,17 +318,25 @@ bool FGTrimAxis::initTheta(void) {
   }
          
   // now adjust theta till the wheels are the same distance from the ground
-  zAft=fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear(3);
-  zForward=fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear(3);
-  zDiff = zForward - zAft;
-  level=false;
-  theta=fgic->GetPitchAngleDegIC(); 
-  while(!level && (i < 100)) {
-         theta+=2.0*zDiff;
-         fgic->SetPitchAngleDegIC(theta);   
-         fdmex->RunIC();
-         zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
-    zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+   xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
+   xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
+   xDiff = xForward - xAft;
+   zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+   zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+   zDiff = zForward - zAft;
+   level=false;
+   theta=fgic->GetPitchAngleDegIC();
+   while(!level && (i < 100)) {
+     theta+=180.0/M_PI*zDiff/fabs(xDiff);
+     fgic->SetPitchAngleDegIC(theta);
+     fdmex->RunIC();
+     xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
+     xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
+     xDiff = xForward - xAft;
+     zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+     zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+     zDiff = zForward - zAft;
+
     zDiff = zForward - zAft;
          //cout << endl << theta << "  " << zDiff << endl;
          //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
index f3f801463425c20c392863be94f7b867046b02b3..d1373a27aa4b5fa5fff7bfbed598dd52c0b8acb5 100644 (file)
@@ -83,6 +83,7 @@ fgfs_LDADD = \
        $(top_builddir)/src/Replay/libReplay.a \
        $(top_builddir)/src/Systems/libSystems.a \
        $(top_builddir)/src/Time/libTime.a \
+       $(top_builddir)/src/Traffic/libTraffic.a \
        $(top_builddir)/src/Environment/libEnvironment.a \
        $(CLOUD3D_LIBS) \
        -lsgroute -lsgsky -lsgsound -lsgephem -lsgmaterial -lsgtgdb -lsgmodel \
index 43f699fd650194562bf10db6bebb44586a68f7d9..15681791f561346fbe550acaaf0724a00d56f076 100644 (file)
 #include <Time/sunpos.hxx>
 #include <Time/sunsolver.hxx>
 #include <Time/tmp.hxx>
+#include <Traffic/TrafficMgr.hxx>
 
 #ifdef FG_MPLAYER_AS
 #include <MultiPlayer/multiplaytxmgr.hxx>
@@ -1684,14 +1685,26 @@ bool fgInitSubsystems() {
     ////////////////////////////////////////////////////////////////////
     // Initialise the AI Model Manager
     ////////////////////////////////////////////////////////////////////
-
     SG_LOG(SG_GENERAL, SG_INFO, "  AI Model Manager");
     globals->add_subsystem("ai_model", new FGAIManager);
 
 
+     // It's probably a good idea to initialize the top level traffic manager
+     // After the AI and ATC systems have been initialized properly.
+     // AI Traffic manager
+     globals->add_subsystem("Traffic Manager", new FGTrafficManager);
+            FGTrafficManager *dispatcher = 
+            (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
+
+     readXML(string(globals->get_fg_root() + string("/Traffic/fgtraffic.xml")),
+            *dispatcher);
+     globals->get_subsystem("Traffic Manager")->init();
+
     globals->add_subsystem("instrumentation", new FGInstrumentMgr);
     globals->add_subsystem("systems", new FGSystemMgr);
 
+
+
     ////////////////////////////////////////////////////////////////////
     // Initialize the radio stack subsystem.
     ////////////////////////////////////////////////////////////////////
index 2545cd12f1eaa6ac2c7a0f857fb76ca8d56e85b5..b0ecf79de6ed71d29c6315a2cdd82e575874ee4c 100644 (file)
@@ -62,6 +62,7 @@ class SGPropertyNode;
 class SGTime;
 class SGSoundMgr;
 
+
 class FGAirportList;
 class FGRunwayList;
 class FGAIMgr;
@@ -69,6 +70,7 @@ class FGATCMgr;
 class FGATCDisplay;
 class FGAircraftModel;
 class FGControls;
+class FGFlightPlanDispatcher;
 class FGIO;
 class FGNavList;
 class FGFixList;
@@ -173,6 +175,8 @@ private:
 
     SGModelLib *model_lib;
 
+  //FGFlightPlanDispatcher *fpDispatcher;
+
     FGAircraftModel *acmodel;
 
     FGModelMgr * model_mgr;
index 7a668f4ee040d993b954e54dd33ba61e1e9dfd6e..c0baac3c19d4a8d54c060c453983af2efe0222cb 100644 (file)
@@ -29,4 +29,5 @@ SUBDIRS = \
         Sound \
         Systems \
         Time \
+       Traffic \
         Main
diff --git a/src/Traffic/Makefile.am b/src/Traffic/Makefile.am
new file mode 100644 (file)
index 0000000..b625991
--- /dev/null
@@ -0,0 +1,9 @@
+noinst_LIBRARIES = libTraffic.a
+
+libTraffic_a_SOURCES = \
+       SchedFlight.cxx SchedFlight.hxx \
+       Schedule.cxx Schedule.hxx \
+       TrafficMgr.cxx TrafficMgr.hxx
+
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/Traffic/SchedFlight.cxx b/src/Traffic/SchedFlight.cxx
new file mode 100644 (file)
index 0000000..b05c7a6
--- /dev/null
@@ -0,0 +1,257 @@
+/******************************************************************************
+ * SchedFlight.cxx
+ * Written by Durk Talsma, started May 5, 2004.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+/* 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. 
+ * 
+ * I'm currently assuming the following simplifications:
+ * 1) The earth is a perfect sphere
+ * 2) Each aircraft flies a perfect great circle route.
+ * 3) Each aircraft flies at a constant speed (with infinite accelerations and
+ *    decelerations) 
+ * 4) Each aircraft leaves at exactly the departure time. 
+ * 5) Each aircraft arrives at exactly the specified arrival time. 
+ *
+ * TODO:
+ * - Check the code for known portability issues
+ * - Find an alternative for the depricated Point3D class
+ *
+ *****************************************************************************/
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+
+
+#include <string>
+#include <vector>
+
+#include <plib/sg.h>
+
+#include <simgear/compiler.h>
+#include <simgear/math/polar3d.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/route/waypoint.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/timing/sg_time.hxx>
+#include <simgear/xml/easyxml.hxx>
+
+#include <AIModel/AIFlightPlan.hxx>
+#include <AIModel/AIManager.hxx>
+#include <Airports/simple.hxx>
+#include <Main/fg_init.hxx>   // That's pretty ugly, but I need fgFindAirportID
+
+
+
+#include <Main/globals.hxx>
+
+#include "SchedFlight.hxx"
+
+
+/******************************************************************************
+ * FGScheduledFlight stuff
+ *****************************************************************************/
+
+FGScheduledFlight::FGScheduledFlight()
+{
+}
+  
+FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
+{
+  callsign        = other.callsign;
+  fltRules        = other.fltRules;
+  departurePort   = other.departurePort;
+  departureTime   = other.departureTime;
+  cruiseAltitude  = other.cruiseAltitude;
+  arrivalPort     = other.arrivalPort;
+  arrivalTime     = other.arrivalTime;
+  repeatPeriod    = other.repeatPeriod;
+  initialized     = other.initialized;
+}
+
+FGScheduledFlight::FGScheduledFlight(string cs,
+                  string fr,
+                  string depPrt,
+                  string arrPrt,
+                  int cruiseAlt,
+                  string deptime,
+                  string arrtime,
+                  string rep)
+{
+  callsign          = cs;
+  fltRules          = fr;
+  departurePort.id  = depPrt;
+  arrivalPort.id    = arrPrt;
+  //departureTime     = processTimeString(deptime);
+  //arrivalTime       = processTimeString(arrtime);
+  cruiseAltitude    = cruiseAlt;
+
+  // Process the repeat period string
+  if (rep.find("WEEK",0) != string::npos)
+    {
+      repeatPeriod = 7*24*60*60; // in seconds
+    }
+  else if (rep.find("Hr", 0) != string::npos)
+    {
+      repeatPeriod = 60*60*atoi(rep.substr(0,2).c_str());
+    }
+  else
+    {
+      cerr << "Unknown repeat period" << endl;
+      exit(1);
+    }
+
+  // What we still need to do is preprocess the departure and
+  // arrival times. 
+  departureTime = processTimeString(deptime);
+  arrivalTime   = processTimeString(arrtime);
+  if (departureTime > arrivalTime)
+    {
+      departureTime -= repeatPeriod;
+    }
+  initialized = false;
+}
+
+
+FGScheduledFlight:: ~FGScheduledFlight()
+{
+}
+
+time_t FGScheduledFlight::processTimeString(string theTime)
+{
+  int weekday;
+  int timeOffsetInDays;
+  int targetDate;
+  int targetHour;
+  int targetMinute;
+  int targetSecond;
+
+  tm targetTimeDate;
+  SGTime* currTimeDate = globals->get_time_params();
+  string timeCopy = theTime;
+
+
+  // okay first split theTime string into
+  // weekday, hour, minute, second;
+  // Check if a week day is specified 
+  if (timeCopy.find("/",0) != string::npos)
+    {
+      weekday          = atoi(timeCopy.substr(0,1).c_str());
+      timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
+      timeCopy = timeCopy.substr(2,timeCopy.length());
+    }
+  else 
+    {
+      timeOffsetInDays = 0;
+    }
+  targetHour   = atoi(timeCopy.substr(0,2).c_str());
+  targetMinute = atoi(timeCopy.substr(3,5).c_str());
+  targetSecond = atoi(timeCopy.substr(6,8).c_str());
+  targetTimeDate.tm_year  = currTimeDate->getGmt()->tm_year;
+  targetTimeDate.tm_mon   = currTimeDate->getGmt()->tm_mon;
+  targetTimeDate.tm_mday  = currTimeDate->getGmt()->tm_mday;
+  targetTimeDate.tm_hour  = targetHour;
+  targetTimeDate.tm_min   = targetMinute;
+  targetTimeDate.tm_sec   = targetSecond;
+
+  time_t processedTime = sgTimeGetGMT(&targetTimeDate);
+  processedTime += timeOffsetInDays*24*60*60;
+  if (processedTime < currTimeDate->get_cur_time())
+    {
+      processedTime += repeatPeriod;
+    }
+  //tm *temp = currTimeDate->getGmt();
+  //char buffer[512];
+  //sgTimeFormatTime(&targetTimeDate, buffer);
+  //cout << "Scheduled Time " << buffer << endl; 
+  //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
+  return processedTime;
+}
+
+void FGScheduledFlight::update()
+{
+  departureTime += repeatPeriod;
+  arrivalTime  += repeatPeriod;
+}
+
+void FGScheduledFlight::adjustTime(time_t now)
+{
+  //cerr << "1: Adjusting schedule please wait: " << now 
+  //   << " " << arrivalTime << " " << arrivalTime+repeatPeriod << endl;
+  // Make sure that the arrival time is in between 
+  // the current time and the next repeat period.
+  while ((arrivalTime < now) || (arrivalTime > now+repeatPeriod))
+    {
+      if (arrivalTime < now)
+       {
+         departureTime += repeatPeriod;
+         arrivalTime   += repeatPeriod;
+       }
+      else if (arrivalTime > now+repeatPeriod)
+       {
+         departureTime -= repeatPeriod;
+         arrivalTime   -= repeatPeriod;
+       }
+      //      cerr << "2: Adjusting schedule please wait: " << now 
+      //   << " " << arrivalTime << " " << arrivalTime+repeatPeriod << endl;
+    }
+}
+
+
+FGAirport *FGScheduledFlight::getDepartureAirport()
+{
+  if (!(initialized))
+    {
+      initializeAirports();
+    }
+  return &departurePort;
+}
+FGAirport * FGScheduledFlight::getArrivalAirport  ()
+{
+   if (!(initialized))
+    {
+      initializeAirports();
+    }
+  return &arrivalPort;
+}
+
+// Upon the first time of requesting airport information
+// for this scheduled flight, these data need to be
+// looked up in the main FlightGear database. 
+// Missing or bogus Airport codes are currently ignored,
+// but we should improve that. The best idea is probably to cancel
+// this flight entirely by removing it from the schedule, if one
+// of the airports cannot be found. 
+void FGScheduledFlight::initializeAirports()
+{
+  if(!(fgFindAirportID(arrivalPort.id, &arrivalPort  )))
+    {
+      //cerr << ": Could not find " << arrivalPort.id << endl; 
+    }
+  if(!(fgFindAirportID(departurePort.id, &departurePort)))
+    {
+      //cerr << ": Could not find " << departurePort.id << endl;
+    }
+  initialized = true;
+}
diff --git a/src/Traffic/SchedFlight.hxx b/src/Traffic/SchedFlight.hxx
new file mode 100644 (file)
index 0000000..5f01f34
--- /dev/null
@@ -0,0 +1,104 @@
+/* -*- Mode: C++ -*- *****************************************************
+ * SchedFlight.hxx
+ * Written by Durk Talsma. Started May 5, 2004
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+/**************************************************************************
+ * ScheduledFlight is a class that is used by FlightGear's Traffic Manager
+ * A scheduled flight can be assigned to a schedule, which can be assigned 
+ * to an aircraft. The traffic manager decides for each schedule which
+ * scheduled flight (if any) is currently active. I no scheduled flights
+ * are found active, it tries to position the aircraft associated with this
+ * schedule at departure airport of the next scheduled flight.
+ * The class ScheduledFlight is a software implimentation of this.
+ * In summary, this class stores arrival and departure information, as well
+ * as some administrative data, such as the callsign of this particular
+ * flight (used in future ATC scenarios), under which flight rules the 
+ * flight is taking place, as well as a requested initial cruise altitude.
+ * Finally, the class contains a repeat period, wich indicates after how
+ * many seconds a flight should repeat in this schedule (which is usually
+ * after either a day or a week). If this value is zero, this flight won't
+ * repeat. 
+ **************************************************************************/
+
+#ifndef _FGSCHEDFLIGHT_HXX_
+#define _FGSCHEDFLIGHT_HXX_
+
+
+using namespace std;
+
+SG_USING_STD(vector);
+
+
+class FGScheduledFlight
+{
+private:
+  string callsign;
+  string fltRules;
+  FGAirport departurePort;
+  FGAirport arrivalPort;
+  time_t departureTime;
+  time_t arrivalTime;
+  time_t repeatPeriod;
+  int cruiseAltitude;
+  bool initialized;
+
+  void initializeAirports();
+public:
+  FGScheduledFlight();
+  FGScheduledFlight(const FGScheduledFlight &other);
+  //  FGScheduledFlight(const string);
+  FGScheduledFlight::FGScheduledFlight(string cs,
+                    string fr,
+                    string depPrt,
+                    string arrPrt,
+                    int cruiseAlt,
+                    string deptime,
+                    string arrtime,
+                    string rep
+                    );
+  ~FGScheduledFlight();
+
+  void update();
+  
+  void adjustTime(time_t now);
+
+  time_t getDepartureTime() { return departureTime; };
+  time_t getArrivalTime  () { return arrivalTime;   };
+  
+  FGAirport *getDepartureAirport();
+  FGAirport *getArrivalAirport  ();
+
+  int getCruiseAlt() { return cruiseAltitude; };
+
+  bool operator<(const FGScheduledFlight &other) const  
+  { 
+    return (departureTime < other.departureTime); 
+  };
+
+  time_t processTimeString(string time);
+  
+};
+
+typedef vector<FGScheduledFlight>           FGScheduledFlightVec;
+typedef vector<FGScheduledFlight>::iterator FGScheduledFlightVecIterator;
+
+
+#endif
diff --git a/src/Traffic/Schedule.cxx b/src/Traffic/Schedule.cxx
new file mode 100644 (file)
index 0000000..ce6deed
--- /dev/null
@@ -0,0 +1,290 @@
+/******************************************************************************
+ * Schedule.cxx
+ * Written by Durk Talsma, started May 5, 2004.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ ****************************************************************************
+ *
+ *****************************************************************************/
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+
+
+#include <string>
+#include <vector>
+
+#include <plib/sg.h>
+
+#include <simgear/compiler.h>
+#include <simgear/math/polar3d.hxx>
+#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 <Airports/simple.hxx>
+#include <Main/fg_init.hxx>   // That's pretty ugly, but I need fgFindAirportID
+
+
+#include "SchedFlight.hxx"
+#include "TrafficMgr.hxx"
+
+
+/******************************************************************************
+ * the FGAISchedule class contains data members and code to maintain a
+ * schedule of Flights for an articically controlled aircraft. 
+ *****************************************************************************/
+FGAISchedule::FGAISchedule()
+{
+  firstRun     = true;
+  AIManagerRef = 0;
+}
+
+FGAISchedule::FGAISchedule(string    mdl, 
+                          string    liv, 
+                          string    reg, 
+                          bool      hvy, 
+                          FGScheduledFlightVec flt)
+{
+  modelPath    = mdl; 
+  livery       = liv; 
+  registration = reg;
+  heavy = hvy;
+  for (FGScheduledFlightVecIterator i = flt.begin();
+       i != flt.end();
+       i++)
+    flights.push_back(FGScheduledFlight((*i)));
+  AIManagerRef = 0;
+  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;
+  firstRun     = other.firstRun;
+}
+
+FGAISchedule::~FGAISchedule()
+{
+  
+} 
+
+void FGAISchedule::update(time_t now)
+{
+  FGAirport *dep;
+  FGAirport *arr;
+  sgdVec3 a, b, cross;
+  sgdVec3 newPos;
+  sgdMat4 matrix;
+  double angle;
+
+  FGAIManager *aimgr;
+  string airport;
+  
+  double courseToUser,   courseToDest;
+  double distanceToUser, distanceToDest;
+  double speed;
+
+  Point3D temp;
+  time_t 
+    totalTimeEnroute, 
+    elapsedTimeEnroute,
+    remainingTimeEnroute;
+  double
+    userLatitude,
+    userLongitude;
+
+  if (fgGetBool("/sim/ai/enabled") == false)
+    return;
+  
+  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)
+    {
+      for (FGScheduledFlightVecIterator i = flights.begin(); 
+          i != flights.end(); 
+          i++)
+       {
+         i->adjustTime(now);
+       }
+      firstRun = 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());
+  FGScheduledFlightVecIterator i = flights.begin();
+  if (!AIManagerRef)
+    {
+      userLatitude  = fgGetDouble("/position/latitude-deg");
+      userLongitude = fgGetDouble("/position/longitude-deg");
+
+
+      // This flight entry is entirely in the past, do we need to 
+      // push it forward in time to the next scheduled departure. 
+      if ((i->getDepartureTime() < now) && (i->getArrivalTime() < now))
+       {
+         i->update();
+         return;
+       }
+
+      // Departure time in the past and arrival time in the future.
+      // This flight is in progress, so we need to calculate it's
+      // approximate position and -if in range- create an AIAircraft
+      // object for it. 
+      if ((i->getDepartureTime() < now) && (i->getArrivalTime() > now))
+       {
+         dep = i->getDepartureAirport();
+         arr = i->getArrivalAirport  ();
+         
+         temp = sgPolarToCart3d(Point3D(dep->longitude * 
+                                        SG_DEGREES_TO_RADIANS, 
+                                        dep->latitude  * 
+                                        SG_DEGREES_TO_RADIANS, 
+                                        1.0));
+         a[0] = temp.x();
+         a[1] = temp.y();
+         a[2] = temp.z();
+         
+         temp = sgPolarToCart3d(Point3D(arr->longitude *
+                                        SG_DEGREES_TO_RADIANS,
+                                        arr->latitude  *
+                                        SG_DEGREES_TO_RADIANS, 
+                                        1.0));
+         b[0] = temp.x();
+         b[1] = temp.y();
+         b[2] = temp.z();
+         sgdNormaliseVec3(a);
+         sgdNormaliseVec3(b);
+         sgdVectorProductVec3(cross,b,a);
+         
+         angle = sgACos(sgdScalarProductVec3(a,b));
+         
+         // Okay, at this point we have the angle between departure and 
+         // arrival airport, in degrees. From here we can interpolate the
+         // position of the aircraft by calculating the ratio between 
+         // total time enroute and elapsed time enroute. 
+         totalTimeEnroute     = i->getArrivalTime() - i->getDepartureTime();
+         elapsedTimeEnroute   = now - i->getDepartureTime();
+         remainingTimeEnroute = i->getArrivalTime()   - now;  
+         
+         angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute);
+         
+         
+         //cout << "a = " << a[0] << " " << a[1] << " " << a[2] 
+         //     << "b = " << b[0] << " " << b[1] << " " << b[2] << endl;  
+         sgdMakeRotMat4(matrix, angle, cross); 
+         for(int j = 0; j < 3; j++)
+           {
+             newPos[j] =0.0;
+             for (int k = 0; k<3; k++)
+               {
+                 newPos[j] += matrix[j][k]*a[k];
+               }
+           }
+
+         temp = sgCartToPolar3d(Point3D(newPos[0], newPos[1],newPos[2]));
+
+         lat = temp.lat() * SG_RADIANS_TO_DEGREES;
+         lon = temp.lon() * SG_RADIANS_TO_DEGREES;
+         
+         SGWayPoint current  (lon,
+                              lat,
+                              i->getCruiseAlt());
+         SGWayPoint user (   userLongitude,
+                             userLatitude,
+                             i->getCruiseAlt());
+         SGWayPoint dest (   arr->longitude,
+                             arr->latitude,
+                             i->getCruiseAlt());
+         // We really only need distance to user
+         // and course to destination 
+         current.CourseAndDistance(user, &courseToUser, &distanceToUser);
+         current.CourseAndDistance(dest, &courseToDest, &distanceToDest);
+         speed =  (distanceToDest*SG_METER_TO_NM) / 
+           ((double) remainingTimeEnroute/3600.0);
+         
+
+         // If distance between user and simulated aircaft 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.
+         //cerr << registration << " is currently enroute from " 
+         //   << dep->id << " to " << arr->id << "distance : " << distanceToUser*SG_METER_TO_NM << endl;
+         if ((distanceToUser*SG_METER_TO_NM) < 500.0)
+           {
+             string flightPlanName = dep->id + string("-") + arr->id + string(".xml");
+
+             FGAIFlightPlan* f;
+             // If we're less then 10 minutes behind schedule, do a normal
+             // full flight plan initialization, otherwise, do a modified 
+             // in-air initializition, at the location where this flight is
+             // according to the Traffic Manager
+             if (elapsedTimeEnroute < 600)
+               f = new FGAIFlightPlan(flightPlanName);
+             else
+               f = new FGAIFlightPlan(flightPlanName, 
+                                      lat, 
+                                      lon, 
+                                      i->getCruiseAlt() * 1000, // convert from FL to feet
+                                      speed, 
+                                      courseToDest);
+             // Fixme: A non-existent model path results in an
+             // abort, due to an unhandled exeption, in fg main loop.
+             AIManagerRef = aimgr->createAircraft("jet_transport", 
+                                              modelPath, f); 
+             //cerr << "Created: " << AIManagerRef << endl;
+           }
+         return;
+       }
+      // Both departure and arrival time are in the future, so this
+      // the aircraft is parked at the departure airport.
+      // Currently this status is mostly ignored, but in furture
+      // versions, code should go here that -if within user range-
+      // positions these aircraft at parking locations at the airport.
+      if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
+       { 
+         dep = i->getDepartureAirport();
+         return;
+       } 
+    }
+}
diff --git a/src/Traffic/Schedule.hxx b/src/Traffic/Schedule.hxx
new file mode 100644 (file)
index 0000000..689524a
--- /dev/null
@@ -0,0 +1,62 @@
+/* -*- Mode: C++ -*- *****************************************************
+ * Schedule.hxx
+ * Written by Durk Talsma. Started May 5, 2004
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+/**************************************************************************
+ * This file contains the definition of the class Shedule.
+ *
+ * A schedule is basically a number of scheduled flights, wich can be
+ * assigned to an AI aircraft. 
+ **************************************************************************/
+
+#ifndef _FGSCHEDULE_HXX_
+#define _FGSCHEDULE_HXX_
+
+
+class FGAISchedule
+{
+ private:
+  string modelPath;
+  string livery;
+  string registration;
+  bool heavy;
+  FGScheduledFlightVec flights;
+  float lat;
+  float lon; 
+  int AIManagerRef;
+  bool firstRun;
+
+ public:
+  FGAISchedule();                                           // constructor
+  FGAISchedule(string, string, string, bool, FGScheduledFlightVec);  // construct & init
+  FGAISchedule(const FGAISchedule &other);             // copy constructor
+
+  ~FGAISchedule(); //destructor
+
+  void update(time_t now);
+  // More member functions follow later
+
+};
+
+typedef vector<FGAISchedule>           ScheduleVector;
+typedef vector<FGAISchedule>::iterator ScheduleVectorIterator;
+
+#endif
+
diff --git a/src/Traffic/TrafficMgr.cxx b/src/Traffic/TrafficMgr.cxx
new file mode 100644 (file)
index 0000000..07f804b
--- /dev/null
@@ -0,0 +1,207 @@
+/******************************************************************************
+ * TrafficMGr.cxx
+ * Written by Durk Talsma, started May 5, 2004.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+/* 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. 
+ * 
+ * I'm currently assuming the following simplifications:
+ * 1) The earth is a perfect sphere
+ * 2) Each aircraft flies a perfect great circle route.
+ * 3) Each aircraft flies at a constant speed (with infinite accelerations and
+ *    decelerations) 
+ * 4) Each aircraft leaves at exactly the departure time. 
+ * 5) Each aircraft arrives at exactly the specified arrival time. 
+ *
+ *
+ *****************************************************************************/
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+
+
+#include <string>
+#include <vector>
+
+#include <plib/sg.h>
+
+#include <simgear/compiler.h>
+#include <simgear/math/polar3d.hxx>
+#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 <Airports/simple.hxx>
+#include <Main/fg_init.hxx>   // That's pretty ugly, but I need fgFindAirportID
+
+
+
+#include "TrafficMgr.hxx"
+
+/******************************************************************************
+ * TrafficManager
+ *****************************************************************************/
+FGTrafficManager::FGTrafficManager()
+{
+}
+
+
+void FGTrafficManager::init()
+{
+  currAircraft = scheduledAircraft.begin();
+}
+
+void FGTrafficManager::update(double something)
+{
+
+  //static const SGPropertyNode *warp = globals->get_props()->getNode("/sim/time/warp");
+  
+  //time_t now = time(NULL) + globals->get_warp();
+  time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+  //  cerr << "TrafficManager update" << globals->get_warp() << endl;
+    if(currAircraft == scheduledAircraft.end())
+      currAircraft = scheduledAircraft.begin();
+    currAircraft->update(now);
+    currAircraft++;
+}
+
+void  FGTrafficManager::startXML () {
+  //cout << "Start XML" << endl;
+}
+
+void  FGTrafficManager::endXML () {
+  //cout << "End XML" << endl;
+}
+
+void  FGTrafficManager::startElement (const char * name, const XMLAttributes &atts) {
+  const char * attval;
+  //cout << "Start element " << name << endl;
+  //FGTrafficManager temp;
+  //for (int i = 0; i < atts.size(); i++)
+  //  if (string(atts.getName(i)) == string("include"))
+  attval = atts.getValue("include");
+  if (attval != 0)
+      {
+       //cout << "including " << attval << endl;
+       string path = 
+         globals->get_fg_root()   + 
+         string("/Traffic/")      + 
+         string(attval);
+       readXML(path, *this);
+      }
+  //  cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
+}
+
+void  FGTrafficManager::endElement (const char * name) {
+  //cout << "End element " << name << endl;
+  string element(name);
+  if (element == string("model"))
+    mdl = value;
+  else if (element == string("livery"))
+    livery = value;
+  else if (element == string("registration"))
+    registration = value;
+  else if (element == string("heavy"))
+    {
+      if(value == string("true"))
+       heavy = true;
+      else
+       heavy = false;
+    }
+  else if (element == string("callsign"))
+    callsign = value;
+  else if (element == string("fltrules"))
+    fltrules = value;
+  else if (element == string("port"))
+    port = value;
+  else if (element == string("time"))
+    timeString = value;
+  else if (element == string("departure"))
+    {
+      departurePort = port;
+      departureTime = timeString;
+    }
+  else if (element == string("cruise-alt"))
+    cruiseAlt = atoi(value.c_str());
+  else if (element == string("arrival"))
+    {
+      arrivalPort = port;
+      arrivalTime = timeString;
+    }
+  else if (element == string("repeat"))
+    repeat = value;
+  else if (element == string("flight"))
+    {
+      // We have loaded and parsed all the information belonging to this flight
+      // so we temporarily store it. 
+      //cerr << "Pusing back flight " << callsign << endl;
+      //cerr << callsign  <<  " " << fltrules     << " "<< departurePort << " " <<  arrivalPort << " "
+      //   << cruiseAlt <<  " " << departureTime<< " "<< arrivalTime   << " " << repeat << endl;
+      flights.push_back(FGScheduledFlight(callsign,
+                                         fltrules,
+                                         departurePort,
+                                         arrivalPort,
+                                         cruiseAlt,
+                                         departureTime,
+                                         arrivalTime,
+                                         repeat));
+    }
+  else if (element == string("aircraft"))
+    {
+      //cerr << "Pushing back aircraft " << registration << endl;
+      scheduledAircraft.push_back(FGAISchedule(mdl, 
+                                               livery, 
+                                               registration, 
+                                               heavy, 
+                                               flights));
+      while(flights.begin() != flights.end())
+       flights.pop_back();
+    }
+}
+
+void  FGTrafficManager::data (const char * s, int len) {
+  string token = string(s,len);
+  //cout << "Character data " << string(s,len) << endl;
+  if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
+      value += token;
+  else
+    value = string("");
+}
+
+void  FGTrafficManager::pi (const char * target, const char * data) {
+  //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void  FGTrafficManager::warning (const char * message, int line, int column) {
+  cout << "Warning: " << message << " (" << line << ',' << column << ')'   
+       << endl;
+}
+
+void  FGTrafficManager::error (const char * message, int line, int column) {
+  cout << "Error: " << message << " (" << line << ',' << column << ')'
+       << endl;
+}
diff --git a/src/Traffic/TrafficMgr.hxx b/src/Traffic/TrafficMgr.hxx
new file mode 100644 (file)
index 0000000..1521111
--- /dev/null
@@ -0,0 +1,69 @@
+/* -*- Mode: C++ -*- *****************************************************
+ * TrafficMgr.hxx
+ * Written by Durk Talsma. Started May 5, 2004
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+/**************************************************************************
+ * This file contains the class definitions for a (Top Level) traffic
+ * manager for FlightGear. 
+ **************************************************************************/
+
+#ifndef _TRAFFICMGR_HXX_
+#define _TRAFFICMGR_HXX_
+
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/xml/easyxml.hxx>
+
+#include "SchedFlight.hxx"
+#include "Schedule.hxx"
+
+
+class FGTrafficManager : public SGSubsystem, public XMLVisitor
+{
+private:
+  ScheduleVector scheduledAircraft;
+  ScheduleVectorIterator currAircraft;
+  string value;
+
+  string mdl, livery, registration, callsign, fltrules, 
+    port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
+    repeat;
+  int cruiseAlt;
+  bool heavy;
+    
+  FGScheduledFlightVec flights;
+
+public:
+  FGTrafficManager();
+  
+  void init();
+  void update(double time);
+
+  // Some overloaded virtual XMLVisitor members
+  virtual void startXML (); 
+  virtual void endXML   ();
+  virtual void startElement (const char * name, const XMLAttributes &atts);
+  virtual void endElement (const char * name);
+  virtual void data (const char * s, int len);
+  virtual void pi (const char * target, const char * data);
+  virtual void warning (const char * message, int line, int column);
+  virtual void error (const char * message, int line, int column);
+};
+
+#endif