]> git.mxchange.org Git - flightgear.git/commitdiff
Major update to the AI code:
authorDurk Talsma <durk@linux-iue5.site>
Sun, 29 Aug 2010 17:25:34 +0000 (19:25 +0200)
committerDurk Talsma <durk@linux-iue5.site>
Sun, 29 Aug 2010 17:25:34 +0000 (19:25 +0200)
  * New features
    - More realistic descent paths
    - Separation during descent and approach
    - ATC approach controller (still silent)
    - inbound traffic flow will start immediately
  * Bug fixes
    - Properly handle vertical speed when on ground
    - Departing aircraft now wait for taxiclerance before moving
    - Traffic manager waits for proper weather initialization
    - Fixed instabilities in the preferential runway usage code
    - Fine tuning of waypoint following code.

16 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIAircraft.hxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIFlightPlanCreate.cxx
src/AIModel/AIFlightPlanCreateCruise.cxx
src/ATC/trafficcontrol.cxx
src/ATC/trafficcontrol.hxx
src/Airports/dynamics.cxx
src/Airports/dynamics.hxx
src/Airports/groundnetwork.cxx
src/Airports/runwaybase.cxx
src/Airports/runwaybase.hxx
src/Airports/runwayprefs.cxx
src/Traffic/Schedule.cxx
src/Traffic/TrafficMgr.cxx

index 92f458427fc6c9d4add7ee9dbb764b5b8d03aa9d..ac79b97cc7f19aaad3f854f075d9c06be9bc3284 100644 (file)
@@ -1,4 +1,4 @@
-// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane
+// FGAIAircraft - FGAIBase-derived class creates an AI airplane
 //
 // Written by David Culp, started October 2003.
 //
@@ -78,6 +78,8 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
     roll = 0;
     headingChangeRate = 0.0;
     headingError = 0;
+    minBearing = 360;
+    speedFraction =1.0;
 
     holdPos = false;
     needsTaxiClearance = false;
@@ -257,6 +259,16 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
           return;
     dt_count = 0;
 
+    double distanceToDescent;
+    if(reachedEndOfCruise(distanceToDescent)) {
+        if (!loadNextLeg(distanceToDescent)) {
+            setDie(true);
+            return;
+        }
+        prev = fp->getPreviousWaypoint();
+        curr = fp->getCurrentWaypoint();
+        next = fp->getNextWaypoint();
+    }
     if (! leadPointReached(curr)) {
         controlHeading(curr);
         controlSpeed(curr, next);
@@ -278,7 +290,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
 
         //TODO let the fp handle this (loading of next leg)
         fp->IncrementWaypoint( trafficRef != 0 );
-        if (!(fp->getNextWaypoint()) && trafficRef != 0)
+        if  ( ((!(fp->getNextWaypoint()))) && (trafficRef != 0) )
             if (!loadNextLeg()) {
                 setDie(true);
                 return;
@@ -342,7 +354,7 @@ const char * FGAIAircraft::_getTransponderCode() const {
 }
 
 
-bool FGAIAircraft::loadNextLeg() {
+bool FGAIAircraft::loadNextLeg(double distance) {
 
     int leg;
     if ((leg = fp->getLeg())  == 10) {
@@ -374,7 +386,8 @@ bool FGAIAircraft::loadNextLeg() {
                     trafficRef->getRadius(),
                     trafficRef->getFlightType(),
                     acType,
-                    company);
+                    company,
+                    distance);
        //cerr << "created  leg " << leg << " for " << trafficRef->getCallSign() << endl;
     }
     return true;
@@ -423,6 +436,7 @@ void FGAIAircraft::doGroundAltitude() {
         altitude_ft = (tgt_altitude_ft + groundOffset);
     else
         altitude_ft += 0.1 * ((tgt_altitude_ft+groundOffset) - altitude_ft);
+    tgt_vs = 0;
 }
 
 
@@ -449,6 +463,11 @@ void FGAIAircraft::announcePositionToController() {
                 cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
             }
             break;
+        case 7:
+             if (trafficRef->getDepartureAirport()->getDynamics()) {
+                 controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
+              }
+              break;
         case 9:              // Taxiing for parking
             if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
                 controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
@@ -629,13 +648,34 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
     //          << dist_to_go << ": Lead distance " 
     //          << lead_dist << " " << curr->name 
     //          << " Ground target speed " << groundTargetSpeed << endl;
-   // if (trafficRef) {
-   //      if (trafficRef->getCallSign() == "Transavia7584") {
-   //           cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " " 
-   //                << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << curr->name << endl; 
-   //      }
-   //  }
-    return dist_to_go < lead_dist;
+    double bearing;
+    if (speed > 50) { // don't do bearing calculations for ground traffic
+       bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
+       if (bearing < minBearing) {
+            minBearing = bearing;
+            if (minBearing < 10) {
+                 minBearing = 10;
+            }
+            if ((minBearing < 360.0) && (minBearing > 10.0)) {
+                speedFraction = cos(minBearing *SG_DEGREES_TO_RADIANS);
+            } else {
+                speedFraction = 1.0;
+            }
+       }
+    } 
+    if (trafficRef) {
+         //cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl;
+/*         if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
+              cerr << trafficRef->getCallSign() << " " << tgt_altitude_ft << " " << _getSpeed() << " " 
+                   << _getAltitude() << " "<< _getLatitude() << " " << _getLongitude() << " " << dist_to_go << " " << lead_dist << " " << curr->name << " " << vs << " " << tgt_vs << " " << bearing << " " << minBearing << " " << speedFraction << endl; 
+         }*/
+     }
+    if ((dist_to_go < lead_dist) || (bearing > (minBearing * 1.1))) {
+        minBearing = 360;
+        return true;
+    } else {
+        return false;
+    }
 }
 
 
@@ -1024,7 +1064,7 @@ void FGAIAircraft::updateActualState() {
     if (onGround())
         speed = _performance->actualSpeed(this, groundTargetSpeed, dt);
     else
-        speed = _performance->actualSpeed(this, tgt_speed, dt);
+        speed = _performance->actualSpeed(this, (tgt_speed *speedFraction), dt);
 
     updateHeading();
     roll = _performance->actualBankAngle(this, tgt_roll, dt);
@@ -1045,3 +1085,89 @@ void FGAIAircraft::updateSecondaryTargetValues() {
 
     //TODO calculate wind correction angle (tgt_yaw)
 }
+
+
+bool FGAIAircraft::reachedEndOfCruise(double &distance) {
+    FGAIFlightPlan::waypoint* curr = fp->getCurrentWaypoint();
+    if (curr->name == "BOD") {
+        double dist = fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
+        double descentSpeed = (getPerformance()->vDescent() * SG_NM_TO_METER) / 3600.0;     // convert from kts to meter/s
+        double descentRate  = (getPerformance()->descentRate() * SG_FEET_TO_METER) / 60.0;  // convert from feet/min to meter/s
+
+        double verticalDistance  = ((altitude_ft - 2000.0) - trafficRef->getArrivalAirport()->getElevation()) *SG_FEET_TO_METER;
+        double descentTimeNeeded = verticalDistance / descentRate;
+        double distanceCovered   = descentSpeed * descentTimeNeeded; 
+
+        //cerr << "Tracking  : " << fgGetString("/ai/track-callsign");
+        if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
+            cerr << "Checking for end of cruise stage for :" << trafficRef->getCallSign() << endl;
+            cerr << "Descent rate      : " << descentRate << endl;
+            cerr << "Descent speed     : " << descentSpeed << endl;
+            cerr << "VerticalDistance  : " << verticalDistance << ". Altitude : " << altitude_ft << ". Elevation " << trafficRef->getArrivalAirport()->getElevation() << endl;
+            cerr << "DecentTimeNeeded  : " << descentTimeNeeded << endl;
+            cerr << "DistanceCovered   : " << distanceCovered   << endl;
+        }
+        //cerr << "Distance = " << distance << endl;
+        distance = distanceCovered;
+        if (dist < distanceCovered) {
+              if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
+                   //exit(1);
+              }
+              return true;
+        } else {
+              return false;
+        }
+    } else {
+         return false;
+    }
+}
+
+void FGAIAircraft::resetPositionFromFlightPlan()
+{
+    // the one behind you
+    FGAIFlightPlan::waypoint* prev = 0;
+    // the one ahead
+    FGAIFlightPlan::waypoint* curr = 0;
+    // the next plus 1
+    FGAIFlightPlan::waypoint* next = 0;
+
+    prev = fp->getPreviousWaypoint();
+    curr = fp->getCurrentWaypoint();
+    next = fp->getNextWaypoint();
+
+    setLatitude(prev->latitude);
+    setLongitude(prev->longitude);
+    double tgt_heading = fp->getBearing(curr, next);
+    setHeading(tgt_heading);
+    setAltitude(prev->altitude);
+    setSpeed(prev->speed);
+}
+
+double FGAIAircraft::getBearing(double crse) 
+{
+  double hdgDiff = fabs(hdg-crse);
+  if (hdgDiff > 180)
+      hdgDiff = fabs(hdgDiff - 360);
+  return hdgDiff;
+}
+
+time_t FGAIAircraft::checkForArrivalTime(string wptName) {
+     FGAIFlightPlan::waypoint* curr = 0;
+     curr = fp->getCurrentWaypoint();
+
+     double tracklength = fp->checkTrackLength(wptName);
+     if (tracklength > 0.1) {
+          tracklength += fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
+     } else {
+         return 0;
+     }
+     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+     time_t arrivalTime = fp->getArrivalTime();
+     
+     time_t ete = tracklength / ((speed * SG_NM_TO_METER) / 3600.0); 
+     time_t secondsToGo = arrivalTime - now;
+     if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {    
+          cerr << "Checking arrival time: ete " << ete << ". Time to go : " << secondsToGo << ". Track length = " << tracklength << endl;
+     }
+     return (ete - secondsToGo); // Positive when we're too slow...
+}
\ No newline at end of file
index 7e65d0df51294732c4543a3dcff5c4461fc50f54..26ceb51207bbdf630c2592950a58a635a6ddc409 100644 (file)
@@ -53,6 +53,7 @@ public:
     void initializeFlightPlan();
     FGAIFlightPlan* GetFlightPlan() const { return fp; };
     void ProcessFlightPlan( double dt, time_t now );
+    time_t checkForArrivalTime(string wptName);
     
     void AccelTo(double speed);
     void PitchTo(double angle);
@@ -63,7 +64,9 @@ public:
     
     void getGroundElev(double dt); //TODO these 3 really need to be public?
     void doGroundAltitude();
-    bool loadNextLeg  ();
+    bool loadNextLeg  (double dist=0);
+    void resetPositionFromFlightPlan();
+    double getBearing(double crse);
 
     void setAcType(const std::string& ac) { acType = ac; };
     void setCompany(const std::string& comp) { company = comp;};
@@ -90,6 +93,7 @@ public:
     inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
     inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
     std::string atGate();
+
     
 protected:
     void Run(double dt);
@@ -104,6 +108,8 @@ private:
     double dt_elev_count;
     double headingChangeRate;
     double headingError;
+    double minBearing;
+    double speedFraction;
     double groundTargetSpeed;
     double groundOffset;
     double dt;
@@ -118,6 +124,7 @@ private:
     void handleFirstWaypoint(void);
     bool leadPointReached(FGAIFlightPlan::waypoint* curr);
     bool handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t now);
+    bool reachedEndOfCruise(double&);
     bool aiTrafficVisible(void);
     void controlHeading(FGAIFlightPlan::waypoint* curr);
     void controlSpeed(FGAIFlightPlan::waypoint* curr,
index 60952d799621889b7ced9a87f5578853c5b9ec5b..13285885051d2d5ac6cef5515629e8673ed7f68e 100644 (file)
@@ -187,8 +187,8 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
       time_t now = time(NULL) + fgGetLong("/sim/time/warp");
       time_t timeDiff = now-start; 
       leg = 1;
-      /*
-      if ((timeDiff > 300) && (timeDiff < 1200))
+      
+      if ((timeDiff > 60) && (timeDiff < 1200))
        leg = 2;
       else if ((timeDiff >= 1200) && (timeDiff < 1500))
        leg = 3;
@@ -196,14 +196,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
        leg = 4;
       else if (timeDiff >= 2000)
        leg = 5;
-      */
+      /*
       if (timeDiff >= 2000)
           leg = 5;
-
+      */
       SG_LOG(SG_GENERAL, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
       wpt_iterator = waypoints.begin();
+      bool dist = 0;
       create(ac, dep,arr, leg, alt, speed, lat, lon,
-            firstLeg, radius, fltType, acType, airline);
+            firstLeg, radius, fltType, acType, airline, dist);
       wpt_iterator = waypoints.begin();
       //cerr << "after create: " << (*wpt_iterator)->name << endl;
       //leg++;
@@ -411,6 +412,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
   
   //lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS); 
   lead_distance = turn_radius * tan((leadInAngle * SG_DEGREES_TO_RADIANS)/2);
+  /*
   if ((lead_distance > (3*turn_radius)) && (current->on_ground == false)) {
       // cerr << "Warning: Lead-in distance is large. Inbound = " << inbound
       //      << ". Outbound = " << outbound << ". Lead in angle = " << leadInAngle  << ". Turn radius = " << turn_radius << endl;
@@ -420,7 +422,7 @@ void FGAIFlightPlan::setLeadDistance(double speed, double bearing,
   if ((leadInAngle > 90) && (current->on_ground == true)) {
       lead_distance = turn_radius * tan((90 * SG_DEGREES_TO_RADIANS)/2);
       return;
-  }
+  }*/
 }
 
 void FGAIFlightPlan::setLeadDistance(double distance_ft){
@@ -493,3 +495,20 @@ int FGAIFlightPlan::getRouteIndex(int i) {
   else
     return 0;
 }
+
+
+double FGAIFlightPlan::checkTrackLength(string wptName) {
+    // skip the first two waypoints: first one is behind, second one is partially done;
+    double trackDistance = 0;
+    wpt_vector_iterator wptvec = waypoints.begin();
+    wptvec++;
+    wptvec++;
+    while ((wptvec != waypoints.end()) && ((*wptvec)->name != wptName)) {
+           trackDistance += (*wptvec)->trackLength;
+           wptvec++;
+    }
+    if (wptvec == waypoints.end()) {
+        trackDistance = 0; // name not found
+    }
+    return trackDistance;
+}
\ No newline at end of file
index c70028dd3e85a3fa37b206eff29a1f19133f2d0f..1de5658bdb8eb569a838445491c6b267555c2b5e 100644 (file)
@@ -55,6 +55,7 @@ public:
    bool on_ground;
     int routeIndex;  // For AI/ATC purposes;
    double time_sec;
+   double trackLength; // distance from previous waypoint (for AI purposes);
    string time;
 
   } waypoint;
@@ -90,10 +91,12 @@ public:
    double getLeadDistance( void ) const {return lead_distance;}
    double getBearing(waypoint* previous, waypoint* next) const;
    double getBearing(double lat, double lon, waypoint* next) const;
+   double checkTrackLength(string wptName);
   time_t getStartTime() const { return start_time; }
+   time_t getArrivalTime() const { return arrivalTime; }
 
   void    create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
-                bool firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline);
+                bool firstLeg, double radius, const string& fltType, const string& aircraftType, const string& airline, double distance);
 
   void setLeg(int val) { leg = val;}
   void setTime(time_t st) { start_time = st; }
@@ -128,6 +131,7 @@ private:
   typedef vector <waypoint*> wpt_vector_type;
   typedef wpt_vector_type::const_iterator wpt_vector_iterator;
 
+
   wpt_vector_type       waypoints;
   wpt_vector_iterator   wpt_iterator;
 
@@ -136,6 +140,7 @@ private:
   double lead_distance;
   double leadInAngle;
   time_t start_time;
+  time_t arrivalTime;       // For AI/ATC purposes.
   int leg;
   int gateId, lastNodeVisited;
   string activeRunway;
@@ -148,7 +153,7 @@ private:
   void createTakeOff(FGAIAircraft *, bool, FGAirport *, double, const string&);
   void createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const string&);
   void createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const string&);
-  void createDecent(FGAIAircraft *, FGAirport *, const string&);
+  void createDescent(FGAIAircraft *, FGAirport *,  double latitude, double longitude, double speed, double alt,const string&, double distance);
   void createLanding(FGAIAircraft *, FGAirport *, const string&);
   void createParking(FGAIAircraft *, FGAirport *, double radius);
   void deleteWaypoints(); 
@@ -158,6 +163,8 @@ private:
   void createDefaultLandingTaxi(FGAIAircraft *, FGAirport* aAirport);
   void createDefaultTakeoffTaxi(FGAIAircraft *, FGAirport* aAirport, FGRunway* aRunway);
   void createTakeoffTaxi(FGAIAircraft *, bool firstFlight, FGAirport *apt, double radius, const string& fltType, const string& acType, const string& airline);
+
+  double getTurnRadius(double, bool);
         
   waypoint* createOnGround(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
   waypoint* createInAir(FGAIAircraft *, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed);
index d2cd7a81e386148014fd0b68c56f1fe36f1292be..d276cc96ae26b63e9dbecc262903e6e881321c65 100644 (file)
  *
  * This is the top-level function, and the only one that is publicly available.
  *
- */ 
+ */
 
 
 // Check lat/lon values during initialization;
-void FGAIFlightPlan::create(FGAIAircraft *ac, FGAirport *dep, FGAirport *arr, int legNr, 
-                           double alt, double speed, double latitude, 
-                           double longitude, bool firstFlight,double radius, 
-                           const string& fltType, const string& aircraftType, 
-                           const string& airline)
-{ 
-  int currWpt = wpt_iterator - waypoints.begin();
-  switch(legNr)
-    {
-      case 1:
-      createPushBack(ac, firstFlight,dep, latitude, longitude, 
-                    radius, fltType, aircraftType, airline);
-      break;
-    case 2: 
-      createTakeoffTaxi(ac, firstFlight, dep, radius, fltType, aircraftType, airline);
-      break;
-    case 3: 
-      createTakeOff(ac, firstFlight, dep, speed, fltType);
-      break;
-    case 4: 
-      createClimb(ac, firstFlight, dep, speed, alt, fltType);
-      break;
-    case 5: 
-      createCruise(ac, firstFlight, dep,arr, latitude, longitude, speed, alt, fltType);
-      break;
-    case 6: 
-      createDecent(ac, arr, fltType);
-      break;
-    case 7: 
-      createLanding(ac, arr, fltType);
-      break;
-    case 8: 
-      createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
-      break;
-      case 9: 
-       createParking(ac, arr, radius);
-      break;
+void FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
+                            FGAirport * arr, int legNr, double alt,
+                            double speed, double latitude,
+                            double longitude, bool firstFlight,
+                            double radius, const string & fltType,
+                            const string & aircraftType,
+                            const string & airline, double distance)
+{
+    int currWpt = wpt_iterator - waypoints.begin();
+    switch (legNr) {
+    case 1:
+        createPushBack(ac, firstFlight, dep, latitude, longitude,
+                       radius, fltType, aircraftType, airline);
+        break;
+    case 2:
+        createTakeoffTaxi(ac, firstFlight, dep, radius, fltType,
+                          aircraftType, airline);
+        break;
+    case 3:
+        createTakeOff(ac, firstFlight, dep, speed, fltType);
+        break;
+    case 4:
+        createClimb(ac, firstFlight, dep, speed, alt, fltType);
+        break;
+    case 5:
+        createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
+                     alt, fltType);
+        break;
+    case 6:
+        createDescent(ac, arr, latitude, longitude, speed, alt, fltType,
+                      distance);
+        break;
+    case 7:
+        createLanding(ac, arr, fltType);
+        break;
+    case 8:
+        createLandingTaxi(ac, arr, radius, fltType, aircraftType, airline);
+        break;
+    case 9:
+        createParking(ac, arr, radius);
+        break;
     default:
-      //exit(1);
-      SG_LOG(SG_INPUT, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg"
-            " this is probably an internal program error");
+        //exit(1);
+        SG_LOG(SG_INPUT, SG_ALERT,
+               "AIFlightPlan::create() attempting to create unknown leg"
+               " this is probably an internal program error");
     }
-  wpt_iterator = waypoints.begin()+currWpt;
-  leg++;
+    wpt_iterator = waypoints.begin() + currWpt;
+    leg++;
 }
 
-FGAIFlightPlan::waypoint*
-FGAIFlightPlan::createOnGround(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
+FGAIFlightPlan::waypoint *
+    FGAIFlightPlan::createOnGround(FGAIAircraft * ac,
+                                   const std::string & aName,
+                                   const SGGeod & aPos, double aElev,
+                                   double aSpeed)
 {
-  waypoint* wpt = new waypoint;
-  wpt->name = aName;
-  wpt->longitude = aPos.getLongitudeDeg();
-  wpt->latitude = aPos.getLatitudeDeg();
-  wpt->altitude  = aElev;
-  wpt->speed     = aSpeed; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  wpt->routeIndex= 0;
-  return wpt;
+    waypoint *wpt = new waypoint;
+    wpt->name = aName;
+    wpt->longitude = aPos.getLongitudeDeg();
+    wpt->latitude = aPos.getLatitudeDeg();
+    wpt->altitude = aElev;
+    wpt->speed = aSpeed;
+    wpt->crossat = -10000.1;
+    wpt->gear_down = true;
+    wpt->flaps_down = true;
+    wpt->finished = false;
+    wpt->on_ground = true;
+    wpt->routeIndex = 0;
+    return wpt;
 }
 
-FGAIFlightPlan::waypoint*
-FGAIFlightPlan::createInAir(FGAIAircraft *ac, const std::string& aName, const SGGeod& aPos, double aElev, double aSpeed)
+FGAIFlightPlan::waypoint *
+    FGAIFlightPlan::createInAir(FGAIAircraft * ac,
+                                const std::string & aName,
+                                const SGGeod & aPos, double aElev,
+                                double aSpeed)
 {
-  waypoint* wpt = new waypoint;
-  wpt->name = aName;
-  wpt->longitude = aPos.getLongitudeDeg();
-  wpt->latitude = aPos.getLatitudeDeg();
-  wpt->altitude  = aElev;
-  wpt->speed     = aSpeed; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = false;
-  wpt->flaps_down= false;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  wpt->routeIndex= 0;
-  return wpt;
+    waypoint *wpt = new waypoint;
+    wpt->name = aName;
+    wpt->longitude = aPos.getLongitudeDeg();
+    wpt->latitude = aPos.getLatitudeDeg();
+    wpt->altitude = aElev;
+    wpt->speed = aSpeed;
+    wpt->crossat = -10000.1;
+    wpt->gear_down = false;
+    wpt->flaps_down = false;
+    wpt->finished = false;
+    wpt->on_ground = false;
+    wpt->routeIndex = 0;
+    return wpt;
 }
 
-FGAIFlightPlan::waypoint*
-FGAIFlightPlan::cloneWithPos(FGAIAircraft *ac, waypoint* aWpt, const std::string& aName, const SGGeod& aPos)
+FGAIFlightPlan::waypoint *
+    FGAIFlightPlan::cloneWithPos(FGAIAircraft * ac, waypoint * aWpt,
+                                 const std::string & aName,
+                                 const SGGeod & aPos)
 {
-  waypoint* wpt = new waypoint;
-  wpt->name = aName;
-  wpt->longitude = aPos.getLongitudeDeg();
-  wpt->latitude = aPos.getLatitudeDeg();
-  
-  wpt->altitude  = aWpt->altitude;
-  wpt->speed     = aWpt->speed; 
-  wpt->crossat   = aWpt->crossat;
-  wpt->gear_down = aWpt->gear_down;
-  wpt->flaps_down= aWpt->flaps_down;
-  wpt->finished  = aWpt->finished;
-  wpt->on_ground = aWpt->on_ground;
-  wpt->routeIndex = 0;
-  
-  return wpt;
+    waypoint *wpt = new waypoint;
+    wpt->name = aName;
+    wpt->longitude = aPos.getLongitudeDeg();
+    wpt->latitude = aPos.getLatitudeDeg();
+
+    wpt->altitude = aWpt->altitude;
+    wpt->speed = aWpt->speed;
+    wpt->crossat = aWpt->crossat;
+    wpt->gear_down = aWpt->gear_down;
+    wpt->flaps_down = aWpt->flaps_down;
+    wpt->finished = aWpt->finished;
+    wpt->on_ground = aWpt->on_ground;
+    wpt->routeIndex = 0;
+
+    return wpt;
 }
 
-FGAIFlightPlan::waypoint*
-FGAIFlightPlan::clone(waypoint* aWpt)
+FGAIFlightPlan::waypoint * FGAIFlightPlan::clone(waypoint * aWpt)
 {
-  waypoint* wpt  = new waypoint;
-  wpt->name      = aWpt->name;
-  wpt->longitude = aWpt->longitude;
-  wpt->latitude  = aWpt->latitude;
-
-  wpt->altitude  = aWpt->altitude;
-  wpt->speed     = aWpt->speed; 
-  wpt->crossat   = aWpt->crossat;
-  wpt->gear_down = aWpt->gear_down;
-  wpt->flaps_down= aWpt->flaps_down;
-  wpt->finished  = aWpt->finished;
-  wpt->on_ground = aWpt->on_ground;
-  wpt->routeIndex = 0;
-  
-  return wpt;
+    waypoint *wpt = new waypoint;
+    wpt->name = aWpt->name;
+    wpt->longitude = aWpt->longitude;
+    wpt->latitude = aWpt->latitude;
+
+    wpt->altitude = aWpt->altitude;
+    wpt->speed = aWpt->speed;
+    wpt->crossat = aWpt->crossat;
+    wpt->gear_down = aWpt->gear_down;
+    wpt->flaps_down = aWpt->flaps_down;
+    wpt->finished = aWpt->finished;
+    wpt->on_ground = aWpt->on_ground;
+    wpt->routeIndex = 0;
+
+    return wpt;
 }
 
 
-void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft *ac, FGAirport* aAirport, FGRunway* aRunway)
+void FGAIFlightPlan::createDefaultTakeoffTaxi(FGAIAircraft * ac,
+                                              FGAirport * aAirport,
+                                              FGRunway * aRunway)
 {
-  SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0);
-  double airportElev = aAirport->getElevation();
-  
-  waypoint* wpt;
-  wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi());
-  waypoints.push_back(wpt);
-  wpt = createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev, ac->getPerformance()->vTaxi());
-  waypoints.push_back(wpt);    
+    SGGeod runwayTakeoff = aRunway->pointOnCenterline(5.0);
+    double airportElev = aAirport->getElevation();
+
+    waypoint *wpt;
+    wpt =
+        createOnGround(ac, "Airport Center", aAirport->geod(), airportElev,
+                       ac->getPerformance()->vTaxi());
+    waypoints.push_back(wpt);
+    wpt =
+        createOnGround(ac, "Runway Takeoff", runwayTakeoff, airportElev,
+                       ac->getPerformance()->vTaxi());
+    waypoints.push_back(wpt);
 }
 
-void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft *ac, bool firstFlight, 
-                               FGAirport *apt,
-                               double radius, const string& fltType, 
-                               const string& acType, const string& airline)
+void FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
+                                       FGAirport * apt,
+                                       double radius,
+                                       const string & fltType,
+                                       const string & acType,
+                                       const string & airline)
 {
-  double heading, lat, lon;
-  
-  // If this function is called during initialization,
-  // make sure we obtain a valid gate ID first
-  // and place the model at the location of the gate.
-  if (firstFlight) {
-    if (!(apt->getDynamics()->getAvailableParking(&lat, &lon, 
-              &heading, &gateId, 
-              radius, fltType, 
-              acType, airline)))
-    {
-      SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " << 
-       acType <<
-       " of flight type " << fltType <<
-       " of airline     " << airline <<
-       " at airport     " << apt->getId());
-    }
-  }
-  
-  string rwyClass = getRunwayClassFromTrafficType(fltType);
-
-  // Only set this if it hasn't been set by ATC already.
-  if (activeRunway.empty()) {
-      //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
-      double depHeading = ac->getTrafficRef()->getCourse();
-      apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, depHeading);
-  }
-  rwy = apt->getRunwayByIdent(activeRunway);
-  SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
-
-  FGGroundNetwork* gn = apt->getDynamics()->getGroundNetwork();
-  if (!gn->exists()) {
-    createDefaultTakeoffTaxi(ac, apt, rwy);
-    return;
-  }
-  
-  intVec ids;
-  int runwayId = gn->findNearestNode(runwayTakeoff);
-
-  // A negative gateId indicates an overflow parking, use a
-  // fallback mechanism for this. 
-  // Starting from gate 0 in this case is a bit of a hack
-  // which requires a more proper solution later on.
-  delete taxiRoute;
-  taxiRoute = new FGTaxiRoute;
-
-  // Determine which node to start from.
-  int node = 0;
-  // Find out which node to start from
-  FGParking *park = apt->getDynamics()->getParking(gateId);
-  if (park) {
-    node = park->getPushBackPoint();
-  }
-  
-  if (node == -1) {
-    node = gateId;
-  }
-  
-  // HAndle case where parking doens't have a node
-  if ((node == 0) && park) {
+    double heading, lat, lon;
+
+    // If this function is called during initialization,
+    // make sure we obtain a valid gate ID first
+    // and place the model at the location of the gate.
     if (firstFlight) {
-      node = gateId;
+        if (!(apt->getDynamics()->getAvailableParking(&lat, &lon,
+                                                      &heading, &gateId,
+                                                      radius, fltType,
+                                                      acType, airline))) {
+            SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " <<
+                   acType <<
+                   " of flight type " << fltType <<
+                   " of airline     " << airline <<
+                   " at airport     " << apt->getId());
+        }
+    }
+
+    string rwyClass = getRunwayClassFromTrafficType(fltType);
+
+    // Only set this if it hasn't been set by ATC already.
+    if (activeRunway.empty()) {
+        //cerr << "Getting runway for " << ac->getTrafficRef()->getCallSign() << " at " << apt->getId() << endl;
+        double depHeading = ac->getTrafficRef()->getCourse();
+        apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+                                            depHeading);
+    }
+    rwy = apt->getRunwayByIdent(activeRunway);
+    SGGeod runwayTakeoff = rwy->pointOnCenterline(5.0);
+
+    FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
+    if (!gn->exists()) {
+        createDefaultTakeoffTaxi(ac, apt, rwy);
+        return;
+    }
+
+    intVec ids;
+    int runwayId = gn->findNearestNode(runwayTakeoff);
+
+    // A negative gateId indicates an overflow parking, use a
+    // fallback mechanism for this. 
+    // Starting from gate 0 in this case is a bit of a hack
+    // which requires a more proper solution later on.
+    delete taxiRoute;
+    taxiRoute = new FGTaxiRoute;
+
+    // Determine which node to start from.
+    int node = 0;
+    // Find out which node to start from
+    FGParking *park = apt->getDynamics()->getParking(gateId);
+    if (park) {
+        node = park->getPushBackPoint();
+    }
+
+    if (node == -1) {
+        node = gateId;
+    }
+    // HAndle case where parking doens't have a node
+    if ((node == 0) && park) {
+        if (firstFlight) {
+            node = gateId;
+        } else {
+            node = lastNodeVisited;
+        }
+    }
+
+    *taxiRoute = gn->findShortestRoute(node, runwayId);
+    intVecIterator i;
+
+    if (taxiRoute->empty()) {
+        createDefaultTakeoffTaxi(ac, apt, rwy);
+        return;
+    }
+
+    taxiRoute->first();
+    //bool isPushBackPoint = false;
+    if (firstFlight) {
+        // If this is called during initialization, randomly
+        // skip a number of waypoints to get a more realistic
+        // taxi situation.
+        int nrWaypointsToSkip = rand() % taxiRoute->size();
+        // but make sure we always keep two active waypoints
+        // to prevent a segmentation fault
+        for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
+            taxiRoute->next(&node);
+        }
+        apt->getDynamics()->releaseParking(gateId);
     } else {
-      node = lastNodeVisited;
-    }
-  }
-
-  *taxiRoute = gn->findShortestRoute(node, runwayId);
-  intVecIterator i;
-        
-  if (taxiRoute->empty()) {
-    createDefaultTakeoffTaxi(ac, apt, rwy);
-    return;
-  }
-  
-  taxiRoute->first();
-  //bool isPushBackPoint = false;
-  if (firstFlight) {
-    // If this is called during initialization, randomly
-    // skip a number of waypoints to get a more realistic
-    // taxi situation.
-    int nrWaypointsToSkip = rand() % taxiRoute->size();
-    // but make sure we always keep two active waypoints
-    // to prevent a segmentation fault
-    for (int i = 0; i < nrWaypointsToSkip-2; i++) {
-      taxiRoute->next(&node);
-    }
-    apt->getDynamics()->releaseParking(gateId);
-  } else {
-    if (taxiRoute->size() > 1) {
-      taxiRoute->next(&node); // chop off the first waypoint, because that is already the last of the pushback route
-    }
-  }
-  
-  // push each node on the taxi route as a waypoint
-  int route;
-  while(taxiRoute->next(&node, &route)) {
-               char buffer[10];
-               snprintf (buffer, 10, "%d", node);
-               FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
-    waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
-    wpt->routeIndex = route;
-               waypoints.push_back(wpt);
-  }
+        if (taxiRoute->size() > 1) {
+            taxiRoute->next(&node);     // chop off the first waypoint, because that is already the last of the pushback route
+        }
+    }
+
+    // push each node on the taxi route as a waypoint
+    int route;
+    while (taxiRoute->next(&node, &route)) {
+        char buffer[10];
+        snprintf(buffer, 10, "%d", node);
+        FGTaxiNode *tn =
+            apt->getDynamics()->getGroundNetwork()->findNode(node);
+        waypoint *wpt =
+            createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
+                           ac->getPerformance()->vTaxi());
+        wpt->routeIndex = route;
+        waypoints.push_back(wpt);
+    }
 }
 
-void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft *ac, FGAirport* aAirport)
+void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
+                                              FGAirport * aAirport)
 {
-  SGGeod lastWptPos = 
-    SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
-  double airportElev = aAirport->getElevation();
-  
-  waypoint* wpt;
-  wpt = createOnGround(ac, "Runway Exit", lastWptPos, airportElev, ac->getPerformance()->vTaxi());
-  waypoints.push_back(wpt);    
-  wpt = createOnGround(ac, "Airport Center", aAirport->geod(), airportElev, ac->getPerformance()->vTaxi());
-  waypoints.push_back(wpt);
-  
-  double heading, lat, lon;
-  aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading);
-  wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), airportElev, ac->getPerformance()->vTaxi());
-  waypoints.push_back(wpt);
+    SGGeod lastWptPos =
+        SGGeod::fromDeg(waypoints.back()->longitude,
+                        waypoints.back()->latitude);
+    double airportElev = aAirport->getElevation();
+
+    waypoint *wpt;
+    wpt =
+        createOnGround(ac, "Runway Exit", lastWptPos, airportElev,
+                       ac->getPerformance()->vTaxi());
+    waypoints.push_back(wpt);
+    wpt =
+        createOnGround(ac, "Airport Center", aAirport->geod(), airportElev,
+                       ac->getPerformance()->vTaxi());
+    waypoints.push_back(wpt);
+
+    double heading, lat, lon;
+    aAirport->getDynamics()->getParking(gateId, &lat, &lon, &heading);
+    wpt =
+        createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), airportElev,
+                       ac->getPerformance()->vTaxi());
+    waypoints.push_back(wpt);
 }
 
-void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
-                               double radius, const string& fltType, 
-                               const string& acType, const string& airline)
+void FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
+                                       double radius,
+                                       const string & fltType,
+                                       const string & acType,
+                                       const string & airline)
 {
-  double heading, lat, lon;
-  apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, 
-        &gateId, radius, fltType, acType, airline);
-  
-  SGGeod lastWptPos = 
-    SGGeod::fromDeg(waypoints.back()->longitude, waypoints.back()->latitude);
-  FGGroundNetwork* gn = apt->getDynamics()->getGroundNetwork();
-  
-   // Find a route from runway end to parking/gate.
-  if (!gn->exists()) {
-    createDefaultLandingTaxi(ac, apt);
-    return;
-  }
-  
-       intVec ids;
-  int runwayId = gn->findNearestNode(lastWptPos);
-  // A negative gateId indicates an overflow parking, use a
-  // fallback mechanism for this. 
-  // Starting from gate 0 is a bit of a hack...
-  //FGTaxiRoute route;
-  delete taxiRoute;
-  taxiRoute = new FGTaxiRoute;
-  if (gateId >= 0)
-    *taxiRoute = gn->findShortestRoute(runwayId, gateId);
-  else
-    *taxiRoute = gn->findShortestRoute(runwayId, 0);
-  intVecIterator i;
-  
-  if (taxiRoute->empty()) {
-    createDefaultLandingTaxi(ac, apt);
-    return;
-  }
-  
-  int node;
-  taxiRoute->first();
-  int size = taxiRoute->size();
-  // Omit the last two waypoints, as 
-  // those are created by createParking()
-  int route;
-  for (int i = 0; i < size-2; i++) {
-    taxiRoute->next(&node, &route);
-    char buffer[10];
-    snprintf (buffer, 10, "%d", node);
-    FGTaxiNode *tn = gn->findNode(node);
-    waypoint* wpt = createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi());
-    wpt->routeIndex = route;
-    waypoints.push_back(wpt);
-  }
+    double heading, lat, lon;
+    apt->getDynamics()->getAvailableParking(&lat, &lon, &heading,
+                                            &gateId, radius, fltType,
+                                            acType, airline);
+
+    SGGeod lastWptPos =
+        SGGeod::fromDeg(waypoints.back()->longitude,
+                        waypoints.back()->latitude);
+    FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
+
+    // Find a route from runway end to parking/gate.
+    if (!gn->exists()) {
+        createDefaultLandingTaxi(ac, apt);
+        return;
+    }
+
+    intVec ids;
+    int runwayId = gn->findNearestNode(lastWptPos);
+    // A negative gateId indicates an overflow parking, use a
+    // fallback mechanism for this. 
+    // Starting from gate 0 is a bit of a hack...
+    //FGTaxiRoute route;
+    delete taxiRoute;
+    taxiRoute = new FGTaxiRoute;
+    if (gateId >= 0)
+        *taxiRoute = gn->findShortestRoute(runwayId, gateId);
+    else
+        *taxiRoute = gn->findShortestRoute(runwayId, 0);
+    intVecIterator i;
+
+    if (taxiRoute->empty()) {
+        createDefaultLandingTaxi(ac, apt);
+        return;
+    }
+
+    int node;
+    taxiRoute->first();
+    int size = taxiRoute->size();
+    // Omit the last two waypoints, as 
+    // those are created by createParking()
+    int route;
+    for (int i = 0; i < size - 2; i++) {
+        taxiRoute->next(&node, &route);
+        char buffer[10];
+        snprintf(buffer, 10, "%d", node);
+        FGTaxiNode *tn = gn->findNode(node);
+        waypoint *wpt =
+            createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(),
+                           ac->getPerformance()->vTaxi());
+        wpt->routeIndex = route;
+        waypoints.push_back(wpt);
+    }
 }
 
 /*******************************************************************
@@ -375,38 +411,42 @@ void FGAIFlightPlan::createLandingTaxi(FGAIAircraft *ac, FGAirport *apt,
  *  more likely however. 
  * 
  ******************************************************************/
-void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport *apt, double speed, const string &fltType)
+void FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
+                                   FGAirport * apt, double speed,
+                                   const string & fltType)
 {
-    double accel    = ac->getPerformance()->acceleration();
-    double vTaxi    = ac->getPerformance()->vTaxi();
-    double vRotate  = ac->getPerformance()->vRotate();
+    double accel = ac->getPerformance()->acceleration();
+    double vTaxi = ac->getPerformance()->vTaxi();
+    double vRotate = ac->getPerformance()->vRotate();
     double vTakeoff = ac->getPerformance()->vTakeoff();
-    double vClimb   = ac->getPerformance()->vClimb();
+    double vClimb = ac->getPerformance()->vClimb();
 
-    double accelMetric    = (accel * SG_NM_TO_METER) / 3600;
-    double vTaxiMetric    = (vTaxi * SG_NM_TO_METER) / 3600;
-    double vRotateMetric  = (vRotate * SG_NM_TO_METER) / 3600;
-    double vTakeoffMetric = (vTakeoff *  SG_NM_TO_METER) / 3600;
-    double vClimbMetric   = (vClimb *  SG_NM_TO_METER) / 3600;
+    double accelMetric = (accel * SG_NM_TO_METER) / 3600;
+    double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
+    double vRotateMetric = (vRotate * SG_NM_TO_METER) / 3600;
+    double vTakeoffMetric = (vTakeoff * SG_NM_TO_METER) / 3600;
+    double vClimbMetric = (vClimb * SG_NM_TO_METER) / 3600;
     // Acceleration = dV / dT
     // Acceleration X dT = dV
     // dT = dT / Acceleration
     //d = (Vf^2 - Vo^2) / (2*a)
     //double accelTime = (vRotate - vTaxi) / accel;
     //cerr << "Using " << accelTime << " as total acceleration time" << endl;
-    double accelDistance = (vRotateMetric*vRotateMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
-    cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
+    double accelDistance =
+        (vRotateMetric * vRotateMetric -
+         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
+    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vRotateMetric << endl;
     waypoint *wpt;
     // Get the current active runway, based on code from David Luff
     // This should actually be unified and extended to include 
     // Preferential runway use schema's 
     // NOTE: DT (2009-01-18: IIRC, this is currently already the case, 
     // because the getActive runway function takes care of that.
-    if (firstFlight)
-    {
+    if (firstFlight) {
         string rwyClass = getRunwayClassFromTrafficType(fltType);
         double heading = ac->getTrafficRef()->getCourse();
-        apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
+        apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+                                            heading);
         rwy = apt->getRunwayByIdent(activeRunway);
     }
 
@@ -417,182 +457,462 @@ void FGAIFlightPlan::createTakeOff(FGAIAircraft *ac, bool firstFlight, FGAirport
     waypoints.push_back(wpt);
 
 
-    accelDistance = (vTakeoffMetric*vTakeoffMetric - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
-    cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    accelPoint = rwy->pointOnCenterline(105.0+accelDistance);
+    accelDistance =
+        (vTakeoffMetric * vTakeoffMetric -
+         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
+    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
+    accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
     wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
     waypoints.push_back(wpt);
 
-    accelDistance = ((vTakeoffMetric*1.1)*(vTakeoffMetric*1.1) - vTaxiMetric*vTaxiMetric) / (2*accelMetric);
-    cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
-    accelPoint = rwy->pointOnCenterline(105.0+accelDistance);
-    wpt = createOnGround(ac, "rotate", accelPoint, airportElev+1000, vTakeoff*1.1);
+    accelDistance =
+        ((vTakeoffMetric * 1.1) * (vTakeoffMetric * 1.1) -
+         vTaxiMetric * vTaxiMetric) / (2 * accelMetric);
+    //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl;
+    accelPoint = rwy->pointOnCenterline(105.0 + accelDistance);
+    wpt =
+        createOnGround(ac, "rotate", accelPoint, airportElev + 1000,
+                       vTakeoff * 1.1);
     wpt->on_ground = false;
     waypoints.push_back(wpt);
 
     wpt = cloneWithPos(ac, wpt, "3000 ft", rwy->end());
-    wpt->altitude  = airportElev+3000;
+    wpt->altitude = airportElev + 3000;
     waypoints.push_back(wpt);
 
     // Finally, add two more waypoints, so that aircraft will remain under
     // Tower control until they have reached the 3000 ft climb point
     SGGeod pt = rwy->pointOnCenterline(5000 + rwy->lengthM() * 0.5);
     wpt = cloneWithPos(ac, wpt, "5000 ft", pt);
-    wpt->altitude  = airportElev+5000;
+    wpt->altitude = airportElev + 5000;
     waypoints.push_back(wpt);
 }
-  
+
 /*******************************************************************
  * CreateClimb
  * initialize the Aircraft at the parking location
  ******************************************************************/
-void FGAIFlightPlan::createClimb(FGAIAircraft *ac, bool firstFlight, FGAirport *apt, double speed, double alt, const string &fltType)
+void FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
+                                 FGAirport * apt, double speed, double alt,
+                                 const string & fltType)
 {
-  waypoint *wpt;
+    waypoint *wpt;
 //  bool planLoaded = false;
-  string fPLName;
-  double vClimb   = ac->getPerformance()->vClimb();
+    string fPLName;
+    double vClimb = ac->getPerformance()->vClimb();
 
-  if (firstFlight) {
-    string rwyClass = getRunwayClassFromTrafficType(fltType);
-    double heading = ac->getTrafficRef()->getCourse();
-    apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
-    rwy = apt->getRunwayByIdent(activeRunway);
-  }
-  if (sid) {
-    for (wpt_vector_iterator i = sid->getFirstWayPoint(); 
-         i != sid->getLastWayPoint(); 
-         i++) {
+    if (firstFlight) {
+        string rwyClass = getRunwayClassFromTrafficType(fltType);
+        double heading = ac->getTrafficRef()->getCourse();
+        apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+                                            heading);
+        rwy = apt->getRunwayByIdent(activeRunway);
+    }
+    if (sid) {
+        for (wpt_vector_iterator i = sid->getFirstWayPoint();
+             i != sid->getLastWayPoint(); i++) {
             waypoints.push_back(clone(*(i)));
             //cerr << " Cloning waypoint " << endl;
+        }
+    } else {
+        SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER);
+        wpt = createInAir(ac, "10000ft climb", climb1, vClimb, 10000);
+        wpt->gear_down = true;
+        wpt->flaps_down = true;
+        waypoints.push_back(wpt);
+
+        SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER);
+        wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
+        wpt->altitude = 18000;
+        waypoints.push_back(wpt);
     }
-  } else  {
-      SGGeod climb1 = rwy->pointOnCenterline(10*SG_NM_TO_METER);
-      wpt = createInAir(ac, "10000ft climb", climb1, vClimb, 10000);
-      wpt->gear_down = true;
-      wpt->flaps_down= true;
-      waypoints.push_back(wpt); 
-
-      SGGeod climb2 = rwy->pointOnCenterline(20*SG_NM_TO_METER);
-      wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
-      wpt->altitude  = 18000;
-      waypoints.push_back(wpt); 
-   }
 }
 
 
 
 /*******************************************************************
- * CreateDecent
- * initialize the Aircraft at the parking location
+ * CreateDescent
+ * Generate a flight path from the last waypoint of the cruise to 
+ * the permission to land point
  ******************************************************************/
-void FGAIFlightPlan::createDecent(FGAIAircraft *ac, FGAirport *apt, const string &fltType)
+void FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
+                                   double latitude, double longitude,
+                                   double speed, double alt,
+                                   const string & fltType,
+                                   double requiredDistance)
 {
-  // Ten thousand ft. Slowing down to 240 kts
-  waypoint *wpt;
-  double vDecent   = ac->getPerformance()->vDescent();
-  double vApproach = ac->getPerformance()->vApproach();
-
-  //Beginning of Decent
-  //string name;
-  // allow "mil" and "gen" as well
-  string rwyClass = getRunwayClassFromTrafficType(fltType);
-  double heading = ac->getTrafficRef()->getCourse();
-  apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
-  rwy = apt->getRunwayByIdent(activeRunway);
-     
-  SGGeod descent1 = rwy->pointOnCenterline(-100000); // 100km out
-  wpt = createInAir(ac, "Dec 10000ft", descent1, apt->getElevation(), vDecent);
-  wpt->crossat   = 10000;
-  waypoints.push_back(wpt);  
-  
-  // Three thousand ft. Slowing down to 160 kts
-  SGGeod descent2 = rwy->pointOnCenterline(-8*SG_NM_TO_METER); // 8nm out
-  wpt = createInAir(ac, "DEC 3000ft", descent2, apt->getElevation(), vApproach);
-  wpt->crossat   = 3000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  waypoints.push_back(wpt);
+    bool reposition = false;
+    waypoint *wpt;
+    double vDescent = ac->getPerformance()->vDescent();
+    double vApproach = ac->getPerformance()->vApproach();
+
+
+    //Beginning of Descent 
+    string rwyClass = getRunwayClassFromTrafficType(fltType);
+    double heading = ac->getTrafficRef()->getCourse();
+    apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
+                                        heading);
+    rwy = apt->getRunwayByIdent(activeRunway);
+
+
+
+    // Create a slow descent path that ends 250 lateral to the runway.
+    double initialTurnRadius = getTurnRadius(vDescent, true);
+    double finalTurnRadius = getTurnRadius(vApproach, true);
+
+// get length of the downwind leg for the intended runway
+    double distanceOut = apt->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance();    //12 * SG_NM_TO_METER;
+    //time_t previousArrivalTime=  apt->getDynamics()->getApproachController()->getRunway(rwy->name())->getEstApproachTime();
+
+
+    SGGeod current = SGGeod::fromDegM(longitude, latitude, 0);
+    SGGeod initialTarget = rwy->pointOnCenterline(-distanceOut);
+    SGGeod refPoint = rwy->pointOnCenterline(0);
+    double distance = SGGeodesy::distanceM(current, initialTarget);
+    double azimuth = SGGeodesy::courseDeg(current, initialTarget);
+    double dummyAz2;
+
+    // To prevent absurdly steep approaches, compute the origin from where the approach should have started
+    SGGeod origin;
+
+    if (ac->getTrafficRef()->getCallSign() ==
+        fgGetString("/ai/track-callsign")) {
+        //cerr << "Reposition information: Actual distance " << distance << ". required distance " << requiredDistance << endl;
+        //exit(1);
+    }
+
+    if (distance < requiredDistance * 0.8) {
+        reposition = true;
+        SGGeodesy::direct(initialTarget, azimuth,
+                          -requiredDistance, origin, dummyAz2);
+
+        distance = SGGeodesy::distanceM(current, initialTarget);
+        azimuth = SGGeodesy::courseDeg(current, initialTarget);
+    } else {
+        origin = current;
+    }
+
+
+    double dAlt = alt - (apt->getElevation() + 2000);
+
+    double nPoints = 100;
+
+    char buffer[16];
+
+    // The descent path contains the following phases:
+    // 1) a linear glide path from the initial position to
+    // 2) a semi circle turn to final
+    // 3) approach
+
+    //cerr << "Phase 1: Linear Descent path to runway" << rwy->name() << endl;
+    // Create an initial destination point on a semicircle
+    //cerr << "lateral offset : " << lateralOffset << endl;
+    //cerr << "Distance       : " << distance      << endl;
+    //cerr << "Azimuth        : " << azimuth       << endl;
+    //cerr << "Initial Lateral point: " << lateralOffset << endl;
+    double lat = refPoint.getLatitudeDeg();
+    double lon = refPoint.getLongitudeDeg();
+    //cerr << "Reference point (" << lat << ", " << lon << ")." << endl;
+    lat = initialTarget.getLatitudeDeg();
+    lon = initialTarget.getLongitudeDeg();
+    //cerr << "Initial Target point (" << lat << ", " << lon << ")." << endl;
+
+    double ratio = initialTurnRadius / distance;
+    if (ratio > 1.0)
+        ratio = 1.0;
+    if (ratio < -1.0)
+        ratio = -1.0;
+
+    double newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
+    double newDistance =
+        cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
+    //cerr << "new distance " << newDistance << ". additional Heading " << newHeading << endl;
+    double side = azimuth - rwy->headingDeg();
+    double lateralOffset = initialTurnRadius;
+    if (side < 0)
+        side += 360;
+    if (side < 180) {
+        lateralOffset *= -1;
+    }
+    // Calculate the ETA at final, based on remaining distance, and approach speed.
+    // distance should really consist of flying time to terniary target, plus circle 
+    // but the distance to secondary target should work as a reasonable approximation
+    // aditionally add the amount of distance covered by making a turn of "side"
+    double turnDistance = (2 * M_PI * initialTurnRadius) * (side / 360.0);
+    time_t remaining =
+        (turnDistance + distance) / ((vDescent * SG_NM_TO_METER) / 3600.0);
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+    //if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) {
+    //     cerr << "   Arrival time estimation: turn angle " <<  side << ". Turn distance " << turnDistance << ". Linear distance " << distance << ". Time to go " << remaining << endl;
+    //     //exit(1);
+    //}
+
+    time_t eta = now + remaining;
+    //choose a distance to the runway such that it will take at least 60 seconds more
+    // time to get there than the previous aircraft.
+    // Don't bother when aircraft need to be repositioned, because that marks the initialization phased...
+
+    time_t newEta;
+
+    if (reposition == false) {
+        newEta =
+            apt->getDynamics()->getApproachController()->getRunway(rwy->
+                                                                   name
+                                                                   ())->
+            requestTimeSlot(eta);
+    } else {
+        newEta = eta;
+    }
+    //if ((eta < (previousArrivalTime+60)) && (reposition == false)) {
+    arrivalTime = newEta;
+    time_t additionalTimeNeeded = newEta - eta;
+    double distanceCovered =
+        ((vApproach * SG_NM_TO_METER) / 3600.0) * additionalTimeNeeded;
+    distanceOut += distanceCovered;
+    //apt->getDynamics()->getApproachController()->getRunway(rwy->name())->setEstApproachTime(eta+additionalTimeNeeded);
+    //cerr << "Adding additional distance: " << distanceCovered << " to allow " << additionalTimeNeeded << " seconds of flying time" << endl << endl;
+    //} else {
+    //apt->getDynamics()->getApproachController()->getRunway(rwy->name())->setEstApproachTime(eta);
+    //}
+    //cerr << "Timing information : Previous eta: " << previousArrivalTime << ". Current ETA : " << eta << endl;
+
+    SGGeod secondaryTarget =
+        rwy->pointOffCenterline(-distanceOut, lateralOffset);
+    initialTarget = rwy->pointOnCenterline(-distanceOut);
+    distance = SGGeodesy::distanceM(origin, secondaryTarget);
+    azimuth = SGGeodesy::courseDeg(origin, secondaryTarget);
+
+
+    lat = secondaryTarget.getLatitudeDeg();
+    lon = secondaryTarget.getLongitudeDeg();
+    //cerr << "Secondary Target point (" << lat << ", " << lon << ")." << endl;
+    //cerr << "Distance       : " << distance      << endl;
+    //cerr << "Azimuth        : " << azimuth       << endl;
+
+
+    ratio = initialTurnRadius / distance;
+    if (ratio > 1.0)
+        ratio = 1.0;
+    if (ratio < -1.0)
+        ratio = -1.0;
+    newHeading = asin(ratio) * SG_RADIANS_TO_DEGREES;
+    newDistance = cos(newHeading * SG_DEGREES_TO_RADIANS) * distance;
+    //cerr << "new distance realative to secondary target: " << newDistance << ". additional Heading " << newHeading << endl;
+    if (side < 180) {
+        azimuth += newHeading;
+    } else {
+        azimuth -= newHeading;
+    }
+
+    SGGeod tertiaryTarget;
+    SGGeodesy::direct(origin, azimuth,
+                      newDistance, tertiaryTarget, dummyAz2);
+
+    lat = tertiaryTarget.getLatitudeDeg();
+    lon = tertiaryTarget.getLongitudeDeg();
+    //cerr << "tertiary Target point (" << lat << ", " << lon << ")." << endl;
+
+
+    for (int i = 1; i < nPoints; i++) {
+        SGGeod result;
+        double currentDist = i * (newDistance / nPoints);
+        double currentAltitude = alt - (i * (dAlt / nPoints));
+        SGGeodesy::direct(origin, azimuth, currentDist, result, dummyAz2);
+        snprintf(buffer, 16, "descent%03d", i);
+        wpt = createInAir(ac, buffer, result, currentAltitude, vDescent);
+        wpt->crossat = currentAltitude;
+        wpt->trackLength = (newDistance / nPoints);
+        waypoints.push_back(wpt);
+        //cerr << "Track Length : " << wpt->trackLength;
+        //cerr << "  Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
+    }
+
+    //cerr << "Phase 2: Circle " << endl;
+    double initialAzimuth =
+        SGGeodesy::courseDeg(secondaryTarget, tertiaryTarget);
+    double finalAzimuth =
+        SGGeodesy::courseDeg(secondaryTarget, initialTarget);
+
+    //cerr << "Angles from secondary target: " << initialAzimuth << " " << finalAzimuth << endl;
+    int increment, startval, endval;
+    // circle right around secondary target if orig of position is to the right of the runway
+    // i.e. use negative angles; else circle leftward and use postivi
+    if (side < 180) {
+        increment = -1;
+        startval = floor(initialAzimuth);
+        endval = ceil(finalAzimuth);
+        if (endval > startval) {
+            endval -= 360;
+        }
+    } else {
+        increment = 1;
+        startval = ceil(initialAzimuth);
+        endval = floor(finalAzimuth);
+        if (endval < startval) {
+            endval += 360;
+        }
+
+    }
+
+    //cerr << "creating circle between " << startval << " and " << endval << " using " << increment << endl;
+    double trackLength = (2 * M_PI * initialTurnRadius) / 360.0;
+    for (int i = startval; i != endval; i += increment) {
+        SGGeod result;
+        double currentAltitude = apt->getElevation() + 2000;
+        SGGeodesy::direct(secondaryTarget, i,
+                          initialTurnRadius, result, dummyAz2);
+        snprintf(buffer, 16, "turn%03d", i);
+        wpt = createInAir(ac, buffer, result, currentAltitude, vDescent);
+        wpt->crossat = currentAltitude;
+        wpt->trackLength = trackLength;
+        //cerr << "Track Length : " << wpt->trackLength;
+        waypoints.push_back(wpt);
+        //cerr << "  Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
+    }
+
+
+    // The approach leg should bring the aircraft to approximately 4-6 out, after which the landing phase should take over. 
+    //cerr << "Phase 3: Approach" << endl;
+    distanceOut -= distanceCovered;
+    for (int i = 1; i < nPoints; i++) {
+        SGGeod result;
+        double currentDist = i * (distanceOut / nPoints);
+        double currentAltitude =
+            apt->getElevation() + 2000 - (i * 2000 / nPoints);
+        snprintf(buffer, 16, "final%03d", i);
+        result = rwy->pointOnCenterline((-distanceOut) + currentDist);
+        wpt = createInAir(ac, buffer, result, currentAltitude, vApproach);
+        wpt->crossat = currentAltitude;
+        wpt->trackLength = (distanceOut / nPoints);
+        // account for the extra distance due to an extended downwind leg
+        if (i == 1) {
+            wpt->trackLength += distanceCovered;
+        }
+        //cerr << "Track Length : " << wpt->trackLength;
+        waypoints.push_back(wpt);
+        //cerr << "  Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << endl;
+    }
+
+    //cerr << "Done" << endl;
+
+    // Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans
+    IncrementWaypoint(true);
+    IncrementWaypoint(true);
+
+    if (reposition) {
+        double tempDistance;
+        double minDistance = HUGE_VAL;
+        string wptName;
+        tempDistance = SGGeodesy::distanceM(current, initialTarget);
+        time_t eta =
+            tempDistance / ((vDescent * SG_NM_TO_METER) / 3600.0) + now;
+        time_t newEta =
+            apt->getDynamics()->getApproachController()->getRunway(rwy->
+                                                                   name
+                                                                   ())->
+            requestTimeSlot(eta);
+        arrivalTime = newEta;
+        double newDistance =
+            ((vDescent * SG_NM_TO_METER) / 3600.0) * (newEta - now);
+        //cerr << "Repositioning information : eta" << eta << ". New ETA " << newEta << ". Diff = " << (newEta - eta) << ". Distance = " << tempDistance << ". New distance = " << newDistance << endl;
+        IncrementWaypoint(true);        // remove waypoint BOD2
+        while (checkTrackLength("final001") > newDistance) {
+            IncrementWaypoint(true);
+        }
+        //cerr << "Repositioning to waypoint " << (*waypoints.begin())->name << endl;
+        ac->resetPositionFromFlightPlan();
+    }
+
+
 }
+
 /*******************************************************************
  * CreateLanding
- * initialize the Aircraft at the parking location
+ * Create a flight path from the "permision to land" point (currently
+   hardcoded at 5000 meters from the threshold) to the threshold, at
+   a standard glide slope angle of 3 degrees. 
  ******************************************************************/
-void FGAIFlightPlan::createLanding(FGAIAircraft *ac, FGAirport *apt, const string &fltType)
+void FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
+                                   const string & fltType)
 {
-  double vTouchdown   = ac->getPerformance()->vTouchdown();
-  double vTaxi        = ac->getPerformance()->vTaxi();
-
-  string rwyClass = getRunwayClassFromTrafficType(fltType);
-  double heading = ac->getTrafficRef()->getCourse();
-  apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
-  rwy = apt->getRunwayByIdent(activeRunway);
-  
-
-  waypoint *wpt;
-  double aptElev = apt->getElevation();
-
-  SGGeod coord;
-  char buffer[12];
-  for (int i = 1; i < 10; i++) {
-      snprintf(buffer, 12, "wpt%d", i);
-      coord = rwy->pointOnCenterline(rwy->lengthM() * (i/10.0));
-      wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown/i));
-      wpt->crossat = apt->getElevation();
-      waypoints.push_back(wpt); 
-  }
-
-  /*
-  //Runway Threshold
-  wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
-  wpt->crossat = apt->getElevation();
-  waypoints.push_back(wpt); 
-
- // Roll-out
-  wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
-  waypoints.push_back(wpt);
-
-  SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
-  wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
-  wpt->crossat   = apt->getElevation();
-  waypoints.push_back(wpt); 
-  */
+    double vTouchdown = ac->getPerformance()->vTouchdown();
+    double vTaxi = ac->getPerformance()->vTaxi();
+
+    //string rwyClass = getRunwayClassFromTrafficType(fltType);
+    //double heading = ac->getTrafficRef()->getCourse();
+    //apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
+    //rwy = apt->getRunwayByIdent(activeRunway);
+
+
+    waypoint *wpt;
+    double aptElev = apt->getElevation();
+
+    SGGeod coord;
+    char buffer[12];
+    for (int i = 1; i < 10; i++) {
+        snprintf(buffer, 12, "wpt%d", i);
+        coord = rwy->pointOnCenterline(rwy->lengthM() * (i / 10.0));
+        wpt = createOnGround(ac, buffer, coord, aptElev, (vTouchdown / i));
+        wpt->crossat = apt->getElevation();
+        waypoints.push_back(wpt);
+    }
+
+    /*
+       //Runway Threshold
+       wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
+       wpt->crossat = apt->getElevation();
+       waypoints.push_back(wpt); 
+
      // Roll-out
+       wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
+       waypoints.push_back(wpt);
+
+       SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
+       wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
+       wpt->crossat   = apt->getElevation();
+       waypoints.push_back(wpt); 
+     */
 }
 
 /*******************************************************************
  * CreateParking
  * initialize the Aircraft at the parking location
  ******************************************************************/
-void FGAIFlightPlan::createParking(FGAIAircraft *ac, FGAirport *apt, double radius)
+void FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
+                                   double radius)
 {
-  waypoint* wpt;
-  double aptElev = apt->getElevation();
-  double lat = 0.0, lat2 = 0.0;
-  double lon = 0.0, lon2 = 0.0;
-  double az2 = 0.0;
-  double heading = 0.0;
-
-  double vTaxi        = ac->getPerformance()->vTaxi();
-  double vTaxiReduced = vTaxi * (2.0/3.0);
-  apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
-  heading += 180.0;
-  if (heading > 360)
-    heading -= 360; 
-  geo_direct_wgs_84 ( 0, lat, lon, heading, 
-                     2.2*radius,           
-                     &lat2, &lon2, &az2 );
-  wpt = createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
-  waypoints.push_back(wpt);
-  
-  geo_direct_wgs_84 ( 0, lat, lon, heading, 
-                     0.1 *radius,           
-                     &lat2, &lon2, &az2 );
-          
-  wpt = createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2), aptElev, vTaxiReduced);
-  waypoints.push_back(wpt);   
-
-  wpt = createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev, vTaxiReduced);
-  waypoints.push_back(wpt);
+    waypoint *wpt;
+    double aptElev = apt->getElevation();
+    double lat = 0.0, lat2 = 0.0;
+    double lon = 0.0, lon2 = 0.0;
+    double az2 = 0.0;
+    double heading = 0.0;
+
+    double vTaxi = ac->getPerformance()->vTaxi();
+    double vTaxiReduced = vTaxi * (2.0 / 3.0);
+    apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
+    heading += 180.0;
+    if (heading > 360)
+        heading -= 360;
+    geo_direct_wgs_84(0, lat, lon, heading,
+                      2.2 * radius, &lat2, &lon2, &az2);
+    wpt =
+        createOnGround(ac, "taxiStart", SGGeod::fromDeg(lon2, lat2),
+                       aptElev, vTaxiReduced);
+    waypoints.push_back(wpt);
+
+    geo_direct_wgs_84(0, lat, lon, heading,
+                      0.1 * radius, &lat2, &lon2, &az2);
+
+    wpt =
+        createOnGround(ac, "taxiStart2", SGGeod::fromDeg(lon2, lat2),
+                       aptElev, vTaxiReduced);
+    waypoints.push_back(wpt);
+
+    wpt =
+        createOnGround(ac, "END", SGGeod::fromDeg(lon, lat), aptElev,
+                       vTaxiReduced);
+    waypoints.push_back(wpt);
 }
 
 /**
@@ -620,17 +940,29 @@ void FGAIFlightPlan::createParking(FGAIAircraft *ac, FGAirport *apt, double radi
  */
 string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
 {
-    if ((fltType == "gate") || (fltType == "cargo")) { 
-       return string("com");
+    if ((fltType == "gate") || (fltType == "cargo")) {
+        return string("com");
     }
     if (fltType == "ga") {
-        return string ("gen");
+        return string("gen");
     }
     if (fltType == "ul") {
         return string("ul");
     }
-    if ((fltType == "mil-fighter") || (fltType == "mil-transport")) { 
-       return string("mil");
+    if ((fltType == "mil-fighter") || (fltType == "mil-transport")) {
+        return string("mil");
+    }
+    return string("com");
+}
+
+
+double FGAIFlightPlan::getTurnRadius(double speed, bool inAir)
+{
+    double turn_radius;
+    if (inAir == false) {
+        turn_radius = ((360 / 30) * fabs(speed)) / (2 * M_PI);
+    } else {
+        turn_radius = 0.1911 * speed * speed;   // an estimate for 25 degrees bank
     }
-   return string("com");
+    return turn_radius;
 }
index 13df4b6072425b93218866be5b0b6420e5f52fe8..269acda945bec5bc919609a8d28f085ac319ec86 100644 (file)
@@ -300,8 +300,11 @@ void FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport
   arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
   rwy = arr->getRunwayByIdent(activeRunway);
   // begin descent 110km out
-  SGGeod beginDescentPoint = rwy->pointOnCenterline(-110000);
+  SGGeod beginDescentPoint     = rwy->pointOnCenterline(0);
+  SGGeod secondaryDescentPoint = rwy->pointOnCenterline(-10000);
   
-  wpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
+  wpt = createInAir(ac, "BOD", beginDescentPoint,  alt, vCruise);
+  waypoints.push_back(wpt); 
+  wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
   waypoints.push_back(wpt); 
 }
index c7d20bdb595fc3f5d5d6f9b8e322375caef0afeb..53ddf28b5ec394dfdfd65cb83fbe513eccef230e 100644 (file)
 #  include <config.h>
 #endif
 
+#include <algorithm>
+
 #include "trafficcontrol.hxx"
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
+#include <AIModel/performancedata.hxx>
+#include <AIModel/performancedb.hxx>
 #include <Traffic/TrafficMgr.hxx>
 #include <Airports/groundnetwork.hxx>
 #include <Airports/dynamics.hxx>
 
+
+using std::sort;
+
+/***************************************************************************
+ * ActiveRunway
+ **************************************************************************/
+time_t ActiveRunway::requestTimeSlot(time_t eta)
+{
+    time_t newEta;
+    time_t separation = 90;
+    bool found = false;
+    if (estimatedArrivalTimes.size() == 0) {
+        estimatedArrivalTimes.push_back(eta);
+        return eta;
+    } else {
+        TimeVectorIterator i = estimatedArrivalTimes.begin();
+        //cerr << "Checking eta slots " << eta << ": " << endl;
+        for (i = estimatedArrivalTimes.begin();
+             i != estimatedArrivalTimes.end(); i++) {
+            //cerr << "Stored time : " << (*i) << endl;
+        }
+        i = estimatedArrivalTimes.begin();
+        if ((eta + separation) < (*i)) {
+            newEta = eta;
+            found = true;
+            //cerr << "Storing at beginning" << endl;
+        }
+        while ((i != estimatedArrivalTimes.end()) && (!found)) {
+            TimeVectorIterator j = i + 1;
+            if (j == estimatedArrivalTimes.end()) {
+                if (((*i) + separation) < eta) {
+                    //cerr << "Storing at end" << endl;
+                    newEta = eta;
+                } else {
+                    newEta = (*i) + separation;
+                    //cerr << "Storing at end + separation" << endl;
+                }
+            } else {
+                if ((((*j) - (*i)) > (separation * 2))) {       // found a potential slot
+                    // now check whether this slow is usable:
+                    // 1) eta should fall between the two points
+                    //    i.e. eta > i AND eta < j
+                    //
+                    //cerr << "Found potential slot after " << (*i) << endl;
+                    if (eta > (*i) && (eta < (*j))) {
+                        found = true;
+                        if (eta < ((*i) + separation)) {
+                            newEta = (*i) + separation;
+                            //cerr << "Using  original" << (*i) << " + separation " << endl;
+                        } else {
+                            newEta = eta;
+                            //cerr << "Using original after " << (*i) << endl;
+                        }
+                    } else if (eta < (*i)) {
+                        found = true;
+                        newEta = (*i) + separation;
+                        //cerr << "Using delayed slot after " << (*i) << endl;
+                    }
+                    /*
+                       if (((*j) - separation) < eta) {
+                       found = true;
+                       if (((*i) + separation) < eta) {
+                       newEta = eta;
+                       cerr << "Using original after " << (*i) << endl;
+                       } else {
+                       newEta = (*i) + separation;
+                       cerr << "Using  " << (*i) << " + separation " << endl;
+                       }
+                       } */
+                }
+            }
+            i++;
+        }
+    }
+    //cerr << ". done. New ETA : " << newEta << endl;
+
+    estimatedArrivalTimes.push_back(newEta);
+    sort(estimatedArrivalTimes.begin(), estimatedArrivalTimes.end());
+    // do some housekeeping : remove any timestamps that are past
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+    TimeVectorIterator i = estimatedArrivalTimes.begin();
+    while (i != estimatedArrivalTimes.end()) {
+        if ((*i) < now) {
+            //cerr << "Deleting timestamp " << (*i) << " (now = " << now << "). " << endl;
+            estimatedArrivalTimes.erase(i);
+            i = estimatedArrivalTimes.begin();
+        } else {
+            i++;
+        }
+    }
+    return newEta;
+}
+
 /***************************************************************************
  * FGTrafficRecord
  **************************************************************************/
-FGTrafficRecord::FGTrafficRecord() :
-  id(0), waitsForId(0),
-  currentPos(0),
-  leg(0),
-  frequencyId(0),
-  state(0),
-   allowTransmission(true),
-  latitude(0),
-  longitude(0), 
-   heading(0), 
-   speed(0), 
-   altitude(0), 
-   radius(0)
-{
-}
-
-void FGTrafficRecord::setPositionAndIntentions(int pos, FGAIFlightPlan *route)
-{
-   currentPos = pos;
-   if (intentions.size()) {
-     intVecIterator i = intentions.begin();
-     if ((*i) != pos) {
-       SG_LOG(SG_GENERAL, SG_ALERT, "Error in FGTrafficRecord::setPositionAndIntentions");
-       //cerr << "Pos : " << pos << " Curr " << *(intentions.begin())  << endl;
-       for (intVecIterator i = intentions.begin(); i != intentions.end() ; i++) {
-       //cerr << (*i) << " ";
-       }
-       //cerr << endl;
-     }
-     intentions.erase(i);
-   } else {
-     //FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
-     int size = route->getNrOfWayPoints();
-     //cerr << "Setting pos" << pos << " ";
-     //cerr << "setting intentions ";
-     for (int i = 0; i < size; i++) {
-       int val = route->getRouteIndex(i);
-       //cerr << val<< " ";
-       if ((val) && (val != pos))
-       {
-         intentions.push_back(val); 
-         //cerr << "[set] ";
-       }
-     }
-     //cerr << endl;
-     //while (route->next(&legNr, &routeNr)) {
-     //intentions.push_back(routeNr);
-     //}
-     //route->rewind(currentPos);
-   }
-   //exit(1);
-}
-
-bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord &other)
-{
-   bool result = false;
-   //cerr << "Start check 1" << endl;
-   if (currentPos == other.currentPos) 
-     {
-       //cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
-       result = true;
-     }
-  //  else if (other.intentions.size()) 
- //     {
- //       cerr << "Start check 2" << endl;
- //       intVecIterator i = other.intentions.begin(); 
- //       while (!((i == other.intentions.end()) || ((*i) == currentPos)))
- //    i++;
- //       if (i != other.intentions.end()) {
- //    cerr << "Check Position and intentions: current matches other.intentions" << endl;
- //    result = true;
- //       }
-   else if (intentions.size()) {
-     //cerr << "Start check 3" << endl;
-     intVecIterator i = intentions.begin(); 
-     //while (!((i == intentions.end()) || ((*i) == other.currentPos)))
-     while (i != intentions.end()) {
-       if ((*i) == other.currentPos) {
-        break;
-       }
-       i++;
-     }
-     if (i != intentions.end()) {
-       //cerr << callsign << ": Check Position and intentions: .other.current matches" << other.callsign << "Index = " << (*i) << endl;
-       result = true;
-     }
-   }
-   //cerr << "Done !!" << endl;
-   return result;
-}
-
-void FGTrafficRecord::setPositionAndHeading(double lat, double lon, double hdg, 
-                                           double spd, double alt)
-{
-  latitude = lat;
-  longitude = lon;
-  heading = hdg;
-  speed = spd;
-  altitude = alt;
-}
-
-int FGTrafficRecord::crosses(FGGroundNetwork *net, FGTrafficRecord &other)
-{
-   if (checkPositionAndIntentions(other) || (other.checkPositionAndIntentions(*this)))
-     return -1;
-   intVecIterator i, j;
-   int currentTargetNode = 0, otherTargetNode = 0;
-   if (currentPos > 0)
-     currentTargetNode = net->findSegment(currentPos      )->getEnd()->getIndex(); // OKAY,... 
-   if (other.currentPos > 0)
-     otherTargetNode   = net->findSegment(other.currentPos)->getEnd()->getIndex(); // OKAY,...
-   if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
-     return currentTargetNode;
-   if (intentions.size())
-     {
-       for (i = intentions.begin(); i != intentions.end(); i++)
-       {
-         if ((*i) > 0) {
-           if ((currentTargetNode == net->findSegment(*i)->getEnd()->getIndex()))
-             {
-               //cerr << "Current crosses at " << currentTargetNode <<endl;
-               return currentTargetNode;
-             }
-         }
-       }
-     }
-   if (other.intentions.size())
-     {
-       for (i = other.intentions.begin(); i != other.intentions.end(); i++)
-       {
-         if ((*i) > 0) {
-           if (otherTargetNode == net->findSegment(*i)->getEnd()->getIndex())
-             {
-               //cerr << "Other crosses at " << currentTargetNode <<endl;
-               return otherTargetNode;
-             }
-         }
-       }
-     }
-   if (intentions.size() && other.intentions.size())
-     {
-       for (i = intentions.begin(); i != intentions.end(); i++) 
-       {
-         for (j = other.intentions.begin(); j != other.intentions.end(); j++)
-           {
-             //cerr << "finding segment " << *i << " and " << *j << endl;
-             if (((*i) > 0) && ((*j) > 0)) {
-               currentTargetNode = net->findSegment(*i)->getEnd()->getIndex();
-               otherTargetNode   = net->findSegment(*j)->getEnd()->getIndex();
-               if (currentTargetNode == otherTargetNode) 
-                 {
-                   //cerr << "Routes will cross at " << currentTargetNode << endl;
-                   return currentTargetNode;
-                 }
-             }
-           }
-       }
-     }
-  return -1;
-}
-
-bool FGTrafficRecord::onRoute(FGGroundNetwork *net, FGTrafficRecord &other)
-{
-  int node = -1, othernode = -1;
-  if (currentPos >0)
-    node = net->findSegment(currentPos)->getEnd()->getIndex();
-  if (other.currentPos > 0)
-    othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
-  if ((node == othernode) && (node != -1))
-    return true;
-  if (other.intentions.size())
-    {
-      for (intVecIterator i = other.intentions.begin(); i != other.intentions.end(); i++)
-       {
-         if (*i > 0) 
-           {
-             othernode = net->findSegment(*i)->getEnd()->getIndex();
-             if ((node == othernode) && (node > -1))
-               return true;
-           }
-       }
-    }
-  //if (other.currentPos > 0)
-  //  othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
-  //if (intentions.size())
-  //  {
-  //    for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
-  //   {
-  //     if (*i > 0) 
-  //       {
-  //         node = net->findSegment(*i)->getEnd()->getIndex();
-  //         if ((node == othernode) && (node > -1))
-  //           return true;
-  //       }
-  //   }
-  //  }
-  return false;
-}
-
-
-bool FGTrafficRecord::isOpposing (FGGroundNetwork *net, FGTrafficRecord &other, int node)
-{
-   // Check if current segment is the reverse segment for the other aircraft
-   FGTaxiSegment *opp;
-   //cerr << "Current segment " << currentPos << endl;
-   if ((currentPos > 0) && (other.currentPos > 0))
-     {
-       opp = net->findSegment(currentPos)->opposite();
-       if (opp) {
-       if (opp->getIndex() == other.currentPos)
-         return true;
-       }
-      
-       for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
-       {
-         if ((opp = net->findSegment(other.currentPos)->opposite()))
-           {
-             if ((*i) > 0)
-               if (opp->getIndex() == net->findSegment(*i)->getIndex())
-                 {
-                   if (net->findSegment(*i)->getStart()->getIndex() == node) {
-                     {
-                       //cerr << "Found the node " << node << endl;
-                       return true;
-                     }
-                   }
-                 }
-           }
-         if (other.intentions.size())
-           {
-             for (intVecIterator j = other.intentions.begin(); j != other.intentions.end(); j++)
-               {
-                 // cerr << "Current segment 1 " << (*i) << endl;
-                 if ((*i) > 0) {
-                   if ((opp = net->findSegment(*i)->opposite()))
-                     {
-                       if (opp->getIndex() == 
-                           net->findSegment(*j)->getIndex())
-                         {
-                           //cerr << "Nodes " << net->findSegment(*i)->getIndex()
-                           //   << " and  " << net->findSegment(*j)->getIndex()
-                           //   << " are opposites " << endl;
-                           if (net->findSegment(*i)->getStart()->getIndex() == node) {
-                             {
-                               //cerr << "Found the node " << node << endl;
-                               return true;
-                             }
-                           }
-                         }
-                     }
-                 }
-               }
-           }
-       }
-     }
-   return false;
-}
-
-void FGTrafficRecord::setSpeedAdjustment(double spd) 
-{ 
-  instruction.setChangeSpeed(true); 
-  instruction.setSpeed(spd); 
-}
-
-void FGTrafficRecord::setHeadingAdjustment(double heading) 
-{ 
-  instruction.setChangeHeading(true);
-  instruction.setHeading(heading); 
-}
-
-bool FGTrafficRecord::pushBackAllowed() {
-      double course, az2,dist;
-       SGGeod curr(SGGeod::fromDegM(getLongitude(),
-                                       getLatitude(), 
-                                       getAltitude()));
-
-      double userLatitude  = fgGetDouble("/position/latitude-deg");
-      double userLongitude = fgGetDouble("/position/longitude-deg");
-      SGGeod user(SGGeod::fromDeg(userLongitude,userLatitude));
-      SGGeodesy::inverse(curr, user, course, az2, dist);
-      //cerr << "Distance to user : " << dist << endl;
-      return (dist > 250);
+FGTrafficRecord::FGTrafficRecord():
+id(0), waitsForId(0),
+currentPos(0),
+leg(0),
+frequencyId(0),
+state(0),
+allowTransmission(true),
+latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0)
+{
+}
+
+void FGTrafficRecord::setPositionAndIntentions(int pos,
+                                               FGAIFlightPlan * route)
+{
+
+    currentPos = pos;
+    if (intentions.size()) {
+        intVecIterator i = intentions.begin();
+        if ((*i) != pos) {
+            SG_LOG(SG_GENERAL, SG_ALERT,
+                   "Error in FGTrafficRecord::setPositionAndIntentions");
+            //cerr << "Pos : " << pos << " Curr " << *(intentions.begin())  << endl;
+            for (intVecIterator i = intentions.begin();
+                 i != intentions.end(); i++) {
+                //cerr << (*i) << " ";
+            }
+            //cerr << endl;
+        }
+        intentions.erase(i);
+    } else {
+        //FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
+        int size = route->getNrOfWayPoints();
+        //cerr << "Setting pos" << pos << " ";
+        //cerr << "setting intentions ";
+        for (int i = 0; i < size; i++) {
+            int val = route->getRouteIndex(i);
+            //cerr << val<< " ";
+            if ((val) && (val != pos)) {
+                intentions.push_back(val);
+                //cerr << "[set] ";
+            }
+        }
+        //cerr << endl;
+        //while (route->next(&legNr, &routeNr)) {
+        //intentions.push_back(routeNr);
+        //}
+        //route->rewind(currentPos);
+    }
+    //exit(1);
+}
+
+bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
+{
+    bool result = false;
+    //cerr << "Start check 1" << endl;
+    if (currentPos == other.currentPos) {
+        //cerr << callsign << ": Check Position and intentions: we are on the same taxiway" << other.callsign << "Index = " << currentPos << endl;
+        result = true;
+    }
+    //  else if (other.intentions.size()) 
+    //     {
+    //       cerr << "Start check 2" << endl;
+    //       intVecIterator i = other.intentions.begin(); 
+    //       while (!((i == other.intentions.end()) || ((*i) == currentPos)))
+    //     i++;
+    //       if (i != other.intentions.end()) {
+    //     cerr << "Check Position and intentions: current matches other.intentions" << endl;
+    //     result = true;
+    //       }
+    else if (intentions.size()) {
+        //cerr << "Start check 3" << endl;
+        intVecIterator i = intentions.begin();
+        //while (!((i == intentions.end()) || ((*i) == other.currentPos)))
+        while (i != intentions.end()) {
+            if ((*i) == other.currentPos) {
+                break;
+            }
+            i++;
+        }
+        if (i != intentions.end()) {
+            //cerr << callsign << ": Check Position and intentions: .other.current matches" << other.callsign << "Index = " << (*i) << endl;
+            result = true;
+        }
+    }
+    //cerr << "Done !!" << endl;
+    return result;
+}
+
+void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
+                                            double hdg, double spd,
+                                            double alt)
+{
+    latitude = lat;
+    longitude = lon;
+    heading = hdg;
+    speed = spd;
+    altitude = alt;
+}
+
+int FGTrafficRecord::crosses(FGGroundNetwork * net,
+                             FGTrafficRecord & other)
+{
+    if (checkPositionAndIntentions(other)
+        || (other.checkPositionAndIntentions(*this)))
+        return -1;
+    intVecIterator i, j;
+    int currentTargetNode = 0, otherTargetNode = 0;
+    if (currentPos > 0)
+        currentTargetNode = net->findSegment(currentPos)->getEnd()->getIndex(); // OKAY,... 
+    if (other.currentPos > 0)
+        otherTargetNode = net->findSegment(other.currentPos)->getEnd()->getIndex();     // OKAY,...
+    if ((currentTargetNode == otherTargetNode) && currentTargetNode > 0)
+        return currentTargetNode;
+    if (intentions.size()) {
+        for (i = intentions.begin(); i != intentions.end(); i++) {
+            if ((*i) > 0) {
+                if ((currentTargetNode ==
+                     net->findSegment(*i)->getEnd()->getIndex())) {
+                    //cerr << "Current crosses at " << currentTargetNode <<endl;
+                    return currentTargetNode;
+                }
+            }
+        }
+    }
+    if (other.intentions.size()) {
+        for (i = other.intentions.begin(); i != other.intentions.end();
+             i++) {
+            if ((*i) > 0) {
+                if (otherTargetNode ==
+                    net->findSegment(*i)->getEnd()->getIndex()) {
+                    //cerr << "Other crosses at " << currentTargetNode <<endl;
+                    return otherTargetNode;
+                }
+            }
+        }
+    }
+    if (intentions.size() && other.intentions.size()) {
+        for (i = intentions.begin(); i != intentions.end(); i++) {
+            for (j = other.intentions.begin(); j != other.intentions.end();
+                 j++) {
+                //cerr << "finding segment " << *i << " and " << *j << endl;
+                if (((*i) > 0) && ((*j) > 0)) {
+                    currentTargetNode =
+                        net->findSegment(*i)->getEnd()->getIndex();
+                    otherTargetNode =
+                        net->findSegment(*j)->getEnd()->getIndex();
+                    if (currentTargetNode == otherTargetNode) {
+                        //cerr << "Routes will cross at " << currentTargetNode << endl;
+                        return currentTargetNode;
+                    }
+                }
+            }
+        }
+    }
+    return -1;
+}
+
+bool FGTrafficRecord::onRoute(FGGroundNetwork * net,
+                              FGTrafficRecord & other)
+{
+    int node = -1, othernode = -1;
+    if (currentPos > 0)
+        node = net->findSegment(currentPos)->getEnd()->getIndex();
+    if (other.currentPos > 0)
+        othernode =
+            net->findSegment(other.currentPos)->getEnd()->getIndex();
+    if ((node == othernode) && (node != -1))
+        return true;
+    if (other.intentions.size()) {
+        for (intVecIterator i = other.intentions.begin();
+             i != other.intentions.end(); i++) {
+            if (*i > 0) {
+                othernode = net->findSegment(*i)->getEnd()->getIndex();
+                if ((node == othernode) && (node > -1))
+                    return true;
+            }
+        }
+    }
+    //if (other.currentPos > 0)
+    //  othernode = net->findSegment(other.currentPos)->getEnd()->getIndex();
+    //if (intentions.size())
+    //  {
+    //    for (intVecIterator i = intentions.begin(); i != intentions.end(); i++)
+    //    {
+    //      if (*i > 0) 
+    //        {
+    //          node = net->findSegment(*i)->getEnd()->getIndex();
+    //          if ((node == othernode) && (node > -1))
+    //            return true;
+    //        }
+    //    }
+    //  }
+    return false;
+}
+
+
+bool FGTrafficRecord::isOpposing(FGGroundNetwork * net,
+                                 FGTrafficRecord & other, int node)
+{
+    // Check if current segment is the reverse segment for the other aircraft
+    FGTaxiSegment *opp;
+    //cerr << "Current segment " << currentPos << endl;
+    if ((currentPos > 0) && (other.currentPos > 0)) {
+        opp = net->findSegment(currentPos)->opposite();
+        if (opp) {
+            if (opp->getIndex() == other.currentPos)
+                return true;
+        }
+
+        for (intVecIterator i = intentions.begin(); i != intentions.end();
+             i++) {
+            if ((opp = net->findSegment(other.currentPos)->opposite())) {
+                if ((*i) > 0)
+                    if (opp->getIndex() ==
+                        net->findSegment(*i)->getIndex()) {
+                        if (net->findSegment(*i)->getStart()->getIndex() ==
+                            node) {
+                            {
+                                //cerr << "Found the node " << node << endl;
+                                return true;
+                            }
+                        }
+                    }
+            }
+            if (other.intentions.size()) {
+                for (intVecIterator j = other.intentions.begin();
+                     j != other.intentions.end(); j++) {
+                    // cerr << "Current segment 1 " << (*i) << endl;
+                    if ((*i) > 0) {
+                        if ((opp = net->findSegment(*i)->opposite())) {
+                            if (opp->getIndex() ==
+                                net->findSegment(*j)->getIndex()) {
+                                //cerr << "Nodes " << net->findSegment(*i)->getIndex()
+                                //   << " and  " << net->findSegment(*j)->getIndex()
+                                //   << " are opposites " << endl;
+                                if (net->findSegment(*i)->getStart()->
+                                    getIndex() == node) {
+                                    {
+                                        //cerr << "Found the node " << node << endl;
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
+void FGTrafficRecord::setSpeedAdjustment(double spd)
+{
+    instruction.setChangeSpeed(true);
+    instruction.setSpeed(spd);
+}
+
+void FGTrafficRecord::setHeadingAdjustment(double heading)
+{
+    instruction.setChangeHeading(true);
+    instruction.setHeading(heading);
+}
+
+bool FGTrafficRecord::pushBackAllowed()
+{
+    double course, az2, dist;
+    SGGeod curr(SGGeod::fromDegM(getLongitude(),
+                                 getLatitude(), getAltitude()));
+
+    double userLatitude = fgGetDouble("/position/latitude-deg");
+    double userLongitude = fgGetDouble("/position/longitude-deg");
+    SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
+    SGGeodesy::inverse(curr, user, course, az2, dist);
+    //cerr << "Distance to user : " << dist << endl;
+    return (dist > 250);
 
 }
 
@@ -328,22 +418,23 @@ bool FGTrafficRecord::pushBackAllowed() {
  **************************************************************************/
 FGATCInstruction::FGATCInstruction()
 {
-  holdPattern    = false; 
-  holdPosition   = false;
-  changeSpeed    = false;
-  changeHeading  = false;
-  changeAltitude = false;
-  resolveCircularWait = false;
+    holdPattern = false;
+    holdPosition = false;
+    changeSpeed = false;
+    changeHeading = false;
+    changeAltitude = false;
+    resolveCircularWait = false;
 
-  speed   = 0;
-  heading = 0;
-  alt     = 0;
+    speed = 0;
+    heading = 0;
+    alt = 0;
 }
 
 
 bool FGATCInstruction::hasInstruction()
 {
-  return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
+    return (holdPattern || holdPosition || changeSpeed || changeHeading
+            || changeAltitude || resolveCircularWait);
 }
 
 /***************************************************************************
@@ -354,24 +445,25 @@ bool FGATCInstruction::hasInstruction()
 
 
 
-FGATCController::FGATCController() 
+FGATCController::FGATCController()
 {
-     dt_count = 0; 
-     available = true; 
-     lastTransmission = 0;
+    dt_count = 0;
+    available = true;
+    lastTransmission = 0;
 }
 
-string FGATCController::getGateName(FGAIAircraft *ref) 
+string FGATCController::getGateName(FGAIAircraft * ref)
 {
     return ref->atGate();
 }
 
-void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir)
+void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
+                               AtcMsgDir msgDir)
 {
     string sender, receiver;
     int stationFreq = 0;
-    int taxiFreq    = 0;
-    int freqId      = 0;
+    int taxiFreq = 0;
+    int freqId = 0;
     string atisInformation;
     string text;
     string taxiFreqStr;
@@ -388,126 +480,153 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
     sender = rec->getAircraft()->getTrafficRef()->getCallSign();
     //cerr << "transmitting for: " << sender << "Leg = " << rec->getLeg() << endl;
     switch (rec->getLeg()) {
-        case 2:
-        case 3:
-            freqId = rec->getNextFrequency();
-            stationFreq =
-            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(rec->getLeg()+freqId);
-            taxiFreq =
-            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getGroundFrequency(3);
-            receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Ground";
-            atisInformation = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getAtisInformation();
-            break;
-        case 4: 
-            receiver = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getName() + "-Tower";
-            break;
+    case 2:
+    case 3:
+        freqId = rec->getNextFrequency();
+        stationFreq =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getDynamics()->getGroundFrequency(rec->getLeg() + freqId);
+        taxiFreq =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getDynamics()->getGroundFrequency(3);
+        receiver =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getName() + "-Ground";
+        atisInformation =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getDynamics()->getAtisInformation();
+        break;
+    case 4:
+        receiver =
+            rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getName() + "-Tower";
+        break;
     }
     // Swap sender and receiver value in case of a ground to air transmission
     if (msgDir == ATC_GROUND_TO_AIR) {
-       string tmp = sender;
-       sender = receiver;
-       receiver = tmp;
+        string tmp = sender;
+        sender = receiver;
+        receiver = tmp;
     }
     switch (msgId) {
-          case MSG_ANNOUNCE_ENGINE_START:
-               text = sender + ". Ready to Start up";
-               break;
-          case MSG_REQUEST_ENGINE_START:
-               text = receiver + ", This is " + sender + ". Position " +getGateName(rec->getAircraft()) +
-                       ". Information " + atisInformation + ". " +
-                       rec->getAircraft()->getTrafficRef()->getFlightRules() + " to " + 
-                       rec->getAircraft()->getTrafficRef()->getArrivalAirport()->getName() + ". Request start-up";
-               break;
-          // Acknowledge engine startup permission
-          // Assign departure runway
-          // Assign SID, if necessery (TODO)
-          case MSG_PERMIT_ENGINE_START:
-               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
-
-               heading = rec->getAircraft()->getTrafficRef()->getCourse();
-               fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
-               rwyClass= rec->getAircraft()->GetFlightPlan()->getRunwayClassFromTrafficType(fltType);
-
-               rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway, heading);
-               rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
-               fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->getDynamics()->getSID(activeRunway, heading);
-               rec->getAircraft()->GetFlightPlan()->setSID(fp);
-               if (fp) {
-                   SID = fp->getName() + " departure";
-               } else {
-                   SID = "fly runway heading ";
-               }
-               //snprintf(buffer, 7, "%3.2f", heading);
-               fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
-               transponderCode = genTransponderCode(fltRules);
-               rec->getAircraft()->SetTransponderCode(transponderCode);
-               text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway
-                       + ", " + SID + ", squawk " + transponderCode + ". " +
-                      "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender + " control.";
-               break;
-          case MSG_DENY_ENGINE_START:
-               text = receiver + ". Standby";
-               break;
-         case MSG_ACKNOWLEDGE_ENGINE_START:
-               fp = rec->getAircraft()->GetFlightPlan()->getSID();
-               if (fp) {
-                  SID = rec->getAircraft()->GetFlightPlan()->getSID()->getName() + " departure";
-               } else {
-                  SID = "fly runway heading ";
-               }
-               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
-               activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
-               transponderCode = rec->getAircraft()->GetTransponderCode();
-               text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " +
-                      activeRunway + ", " + SID + ", squawk " + transponderCode + ". " +
-                      "For push-back and taxi clearance call " + taxiFreqStr + ". " + sender;
-               break;
-           case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
-               taxiFreqStr = formatATCFrequency3_2(taxiFreq);
-               text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
-               break;
-           case MSG_INITIATE_CONTACT:
-                text = receiver + ". With you. " + sender;
-                break;
-           case MSG_ACKNOWLEDGE_INITIATE_CONTACT:
-                text = receiver + ". Roger. " + sender;
-                break;
-           case MSG_REQUEST_PUSHBACK_CLEARANCE:
-               text = receiver + ". Request push-back. " + sender;
-               break;
-           case MSG_PERMIT_PUSHBACK_CLEARANCE:
-               text = receiver + ". Push-back approved. " + sender;
-               break;
-           case MSG_HOLD_PUSHBACK_CLEARANCE:
-                text = receiver + ". Standby. " + sender;
-                break;
-           case MSG_REQUEST_TAXI_CLEARANCE:
-                text = receiver + ". Ready to Taxi. " + sender;
-                break;
-           case MSG_ISSUE_TAXI_CLEARANCE:
-                text = receiver + ". Cleared to taxi. " + sender;
-                break;
-           case MSG_ACKNOWLEDGE_TAXI_CLEARANCE:
-                text = receiver + ". Cleared to taxi. " + sender;
-                break;
-           case MSG_HOLD_POSITION:
-                text = receiver + ". Hold Position. " + sender;
-                break;
-           case MSG_ACKNOWLEDGE_HOLD_POSITION:
-                text = receiver + ". Holding Position. " + sender;
-                break;
-           case MSG_RESUME_TAXI:
-                text = receiver + ". Resume Taxiing. " + sender;
-                break;
-           case MSG_ACKNOWLEDGE_RESUME_TAXI:
-                text = receiver + ". Continuing Taxi. " + sender;
-                break;
-           default:
-                 text = text + sender + ". Transmitting unknown Message";
-                  break;
+    case MSG_ANNOUNCE_ENGINE_START:
+        text = sender + ". Ready to Start up";
+        break;
+    case MSG_REQUEST_ENGINE_START:
+        text =
+            receiver + ", This is " + sender + ". Position " +
+            getGateName(rec->getAircraft()) + ". Information " +
+            atisInformation + ". " +
+            rec->getAircraft()->getTrafficRef()->getFlightRules() +
+            " to " +
+            rec->getAircraft()->getTrafficRef()->getArrivalAirport()->
+            getName() + ". Request start-up";
+        break;
+        // Acknowledge engine startup permission
+        // Assign departure runway
+        // Assign SID, if necessery (TODO)
+    case MSG_PERMIT_ENGINE_START:
+        taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+
+        heading = rec->getAircraft()->getTrafficRef()->getCourse();
+        fltType = rec->getAircraft()->getTrafficRef()->getFlightType();
+        rwyClass =
+            rec->getAircraft()->GetFlightPlan()->
+            getRunwayClassFromTrafficType(fltType);
+
+        rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getDynamics()->getActiveRunway(rwyClass, 1, activeRunway,
+                                           heading);
+        rec->getAircraft()->GetFlightPlan()->setRunway(activeRunway);
+        fp = rec->getAircraft()->getTrafficRef()->getDepartureAirport()->
+            getDynamics()->getSID(activeRunway, heading);
+        rec->getAircraft()->GetFlightPlan()->setSID(fp);
+        if (fp) {
+            SID = fp->getName() + " departure";
+        } else {
+            SID = "fly runway heading ";
+        }
+        //snprintf(buffer, 7, "%3.2f", heading);
+        fltRules = rec->getAircraft()->getTrafficRef()->getFlightRules();
+        transponderCode = genTransponderCode(fltRules);
+        rec->getAircraft()->SetTransponderCode(transponderCode);
+        text =
+            receiver + ". Start-up approved. " + atisInformation +
+            " correct, runway " + activeRunway + ", " + SID + ", squawk " +
+            transponderCode + ". " +
+            "For push-back and taxi clearance call " + taxiFreqStr + ". " +
+            sender + " control.";
+        break;
+    case MSG_DENY_ENGINE_START:
+        text = receiver + ". Standby";
+        break;
+    case MSG_ACKNOWLEDGE_ENGINE_START:
+        fp = rec->getAircraft()->GetFlightPlan()->getSID();
+        if (fp) {
+            SID =
+                rec->getAircraft()->GetFlightPlan()->getSID()->getName() +
+                " departure";
+        } else {
+            SID = "fly runway heading ";
+        }
+        taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+        activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
+        transponderCode = rec->getAircraft()->GetTransponderCode();
+        text =
+            receiver + ". Start-up approved. " + atisInformation +
+            " correct, runway " + activeRunway + ", " + SID + ", squawk " +
+            transponderCode + ". " +
+            "For push-back and taxi clearance call " + taxiFreqStr + ". " +
+            sender;
+        break;
+    case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY:
+        taxiFreqStr = formatATCFrequency3_2(taxiFreq);
+        text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
+        break;
+    case MSG_INITIATE_CONTACT:
+        text = receiver + ". With you. " + sender;
+        break;
+    case MSG_ACKNOWLEDGE_INITIATE_CONTACT:
+        text = receiver + ". Roger. " + sender;
+        break;
+    case MSG_REQUEST_PUSHBACK_CLEARANCE:
+        text = receiver + ". Request push-back. " + sender;
+        break;
+    case MSG_PERMIT_PUSHBACK_CLEARANCE:
+        text = receiver + ". Push-back approved. " + sender;
+        break;
+    case MSG_HOLD_PUSHBACK_CLEARANCE:
+        text = receiver + ". Standby. " + sender;
+        break;
+    case MSG_REQUEST_TAXI_CLEARANCE:
+        text = receiver + ". Ready to Taxi. " + sender;
+        break;
+    case MSG_ISSUE_TAXI_CLEARANCE:
+        text = receiver + ". Cleared to taxi. " + sender;
+        break;
+    case MSG_ACKNOWLEDGE_TAXI_CLEARANCE:
+        text = receiver + ". Cleared to taxi. " + sender;
+        break;
+    case MSG_HOLD_POSITION:
+        text = receiver + ". Hold Position. " + sender;
+        break;
+    case MSG_ACKNOWLEDGE_HOLD_POSITION:
+        text = receiver + ". Holding Position. " + sender;
+        break;
+    case MSG_RESUME_TAXI:
+        text = receiver + ". Resume Taxiing. " + sender;
+        break;
+    case MSG_ACKNOWLEDGE_RESUME_TAXI:
+        text = receiver + ". Continuing Taxi. " + sender;
+        break;
+    default:
+        text = text + sender + ". Transmitting unknown Message";
+        break;
     }
-    double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
-    double onBoardRadioFreq1 = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+    double onBoardRadioFreq0 =
+        fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+    double onBoardRadioFreq1 =
+        fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
     int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
     int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
     //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
@@ -515,27 +634,31 @@ void FGATCController::transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir m
     // Display ATC message only when one of the radios is tuned
     // the relevant frequency.
     // Note that distance attenuation is currently not yet implemented
-    if ((onBoardRadioFreqI0 == stationFreq) || (onBoardRadioFreqI1 == stationFreq)) {
+    if ((onBoardRadioFreqI0 == stationFreq)
+        || (onBoardRadioFreqI1 == stationFreq)) {
         if (rec->allowTransmissions()) {
             fgSetString("/sim/messages/atc", text.c_str());
         }
     }
 }
 
-string FGATCController::formatATCFrequency3_2(int freq) {
+string FGATCController::formatATCFrequency3_2(int freq)
+{
     char buffer[7];
-    snprintf(buffer, 7, "%3.2f", ( (float) freq / 100.0) );
+    snprintf(buffer, 7, "%3.2f", ((float) freq / 100.0));
     return string(buffer);
 }
 
 // TODO: Set transponder codes according to real-world routes.
 // The current version just returns a random string of four octal numbers. 
-string FGATCController::genTransponderCode(string fltRules) {
+string FGATCController::genTransponderCode(string fltRules)
+{
     if (fltRules == "VFR") {
         return string("1200");
     } else {
         char buffer[5];
-        snprintf(buffer, 5, "%d%d%d%d", rand() % 8, rand() % 8,rand() % 8, rand() % 8);
+        snprintf(buffer, 5, "%d%d%d%d", rand() % 8, rand() % 8, rand() % 8,
+                 rand() % 8);
         return string(buffer);
     }
 }
@@ -544,69 +667,72 @@ string FGATCController::genTransponderCode(string fltRules) {
  * class FGTowerController
  *
  **************************************************************************/
-FGTowerController::FGTowerController() :
-  FGATCController()
+FGTowerController::FGTowerController():
+FGATCController()
 {
 }
 
 // 
-void FGTowerController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
-                                        double lat, double lon, double heading, 
-                                        double speed, double alt, double radius, int leg,
-                                        FGAIAircraft *ref)
-{
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search whether the current id alread has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
-  if (activeTraffic.size()) {
-    //while ((i->getId() != id) && i != activeTraffic.end()) {
-    while (i != activeTraffic.end()) {
-      if (i->getId() == id) {
-       break;
-      }
-      i++;
-    }
-  }
-  
-  // Add a new TrafficRecord if no one exsists for this aircraft.
-  if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-    FGTrafficRecord rec;
-    rec.setId(id);
-
-    rec.setPositionAndHeading(lat, lon, heading, speed, alt);
-    rec.setRunway(intendedRoute->getRunway());
-    rec.setLeg(leg);
-    //rec.setCallSign(callsign);
-    rec.setAircraft(ref);
-    activeTraffic.push_back(rec);
-  } else {
-    i->setPositionAndHeading(lat, lon, heading, speed, alt);
-  }
-}
-
-void FGTowerController::update(int id, double lat, double lon, double heading, double speed, double alt, 
-                            double dt)
+void FGTowerController::announcePosition(int id,
+                                         FGAIFlightPlan * intendedRoute,
+                                         int currentPosition, double lat,
+                                         double lon, double heading,
+                                         double speed, double alt,
+                                         double radius, int leg,
+                                         FGAIAircraft * ref)
 {
     TrafficVectorIterator i = activeTraffic.begin();
-    // Search search if the current id has an entry
+    // Search whether the current id alread has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
-    TrafficVectorIterator current, closest;
     if (activeTraffic.size()) {
-      //while ((i->getId() != id) && i != activeTraffic.end()) {
-      while (i != activeTraffic.end()) {
-       if (i->getId() == id) {
-         break;
-       }
-        i++;
-      }
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    // Add a new TrafficRecord if no one exsists for this aircraft.
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        FGTrafficRecord rec;
+        rec.setId(id);
+
+        rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+        rec.setRunway(intendedRoute->getRunway());
+        rec.setLeg(leg);
+        //rec.setCallSign(callsign);
+        rec.setAircraft(ref);
+        activeTraffic.push_back(rec);
+    } else {
+        i->setPositionAndHeading(lat, lon, heading, speed, alt);
     }
+}
 
+void FGTowerController::update(int id, double lat, double lon,
+                               double heading, double speed, double alt,
+                               double dt)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search whether the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    TrafficVectorIterator current, closest;
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
 //    // update position of the current aircraft
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: updating aircraft without traffic record");
     } else {
-      i->setPositionAndHeading(lat, lon, heading, speed, alt);
-      current = i;
+        i->setPositionAndHeading(lat, lon, heading, speed, alt);
+        current = i;
     }
     setDt(getDt() + dt);
 
@@ -614,65 +740,66 @@ void FGTowerController::update(int id, double lat, double lon, double heading, d
     ActiveRunwayVecIterator rwy = activeRunways.begin();
     // again, a map might be more efficient here
     if (activeRunways.size()) {
-      //while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) {
-      while (rwy != activeRunways.end()) {
-       if (rwy->getRunwayName() == current->getRunway()) {
-         break;
-       }
-        rwy++;
-      }
+        //while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) {
+        while (rwy != activeRunways.end()) {
+            if (rwy->getRunwayName() == current->getRunway()) {
+                break;
+            }
+            rwy++;
+        }
     }
     if (rwy == activeRunways.end()) {
-      ActiveRunway aRwy(current->getRunway(), id);
-      activeRunways.push_back(aRwy);   // Since there are no clearance records for this runway yet
-      current->setHoldPosition(false); // Clear the current aircraft to continue
-    }
-    else {
-      // Okay, we have a clearance record for this runway, so check
-      // whether the clearence ID matches that of the current aircraft
-      if (id == rwy->getCleared()) {
-        current->setHoldPosition(false);
-      } else {
-        current->setHoldPosition(true);
-      }
+        ActiveRunway aRwy(current->getRunway(), id);
+        activeRunways.push_back(aRwy);  // Since there are no clearance records for this runway yet
+        current->setHoldPosition(false);        // Clear the current aircraft to continue
+    } else {
+        // Okay, we have a clearance record for this runway, so check
+        // whether the clearence ID matches that of the current aircraft
+        if (id == rwy->getCleared()) {
+            current->setHoldPosition(false);
+        } else {
+            current->setHoldPosition(true);
+        }
     }
 }
 
 
-void FGTowerController::signOff(int id) 
+void FGTowerController::signOff(int id)
 {
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search search if the current id alread has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id alread has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
     if (activeTraffic.size()) {
-      //while ((i->getId() != id) && i != activeTraffic.end()) {
-      while (i != activeTraffic.end()) {
-       if (i->getId() == id) {
-         break;
-       }
-        i++;
-      }
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
     }
     // If this aircraft has left the runway, we can clear the departure record for this runway
     ActiveRunwayVecIterator rwy = activeRunways.begin();
     if (activeRunways.size()) {
-      //while ((rwy->getRunwayName() != i->getRunway()) && (rwy != activeRunways.end())) {
-      while (rwy != activeRunways.end()) {
-        if (rwy->getRunwayName() == i->getRunway()) {
-         break;
-       }
-        rwy++;
-      }
-      if (rwy != activeRunways.end()) {
-        rwy = activeRunways.erase(rwy);
-      } else {
-        SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
-      }
+        //while ((rwy->getRunwayName() != i->getRunway()) && (rwy != activeRunways.end())) {
+        while (rwy != activeRunways.end()) {
+            if (rwy->getRunwayName() == i->getRunway()) {
+                break;
+            }
+            rwy++;
+        }
+        if (rwy != activeRunways.end()) {
+            rwy = activeRunways.erase(rwy);
+        } else {
+            SG_LOG(SG_GENERAL, SG_ALERT,
+                   "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff");
+        }
     }
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: Aircraft without traffic record is signing off from tower");
     } else {
-      i = activeTraffic.erase(i);
+        i = activeTraffic.erase(i);
     }
 }
 
@@ -687,90 +814,93 @@ bool FGTowerController::hasInstruction(int id)
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
-    if (activeTraffic.size()) 
-      {
+    if (activeTraffic.size()) {
         //while ((i->getId() != id) && i != activeTraffic.end()) {
-       while (i != activeTraffic.end()) {
-         if (i->getId() == id) {
-           break;
-         }
-        i++;
-      }
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
     }
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: checking ATC instruction for aircraft without traffic record");
     } else {
-      return i->hasInstruction();
+        return i->hasInstruction();
     }
-  return false;
+    return false;
 }
 
 
 FGATCInstruction FGTowerController::getInstruction(int id)
 {
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search search if the current id has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
-  if (activeTraffic.size()) {
-    //while ((i->getId() != id) && i != activeTraffic.end()) {
-    while (i != activeTraffic.end()) {
-      if (i->getId() == id) {
-       break;
-      }
-      i++;
-    }
-  }
-  if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-    SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
-  } else {
-    return i->getInstruction();
-  }
-  return FGATCInstruction();
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: requesting ATC instruction for aircraft without traffic record");
+    } else {
+        return i->getInstruction();
+    }
+    return FGATCInstruction();
 }
 
 /***************************************************************************
  * class FGStartupController
  *
  **************************************************************************/
-FGStartupController::FGStartupController() :
-  FGATCController()
-{
-}
-
-void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
-                                        double lat, double lon, double heading, 
-                                        double speed, double alt, double radius, int leg,
-                                        FGAIAircraft *ref)
-{
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search whether the current id alread has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
-  if (activeTraffic.size()) {
-    //while ((i->getId() != id) && i != activeTraffic.end()) {
-    while (i != activeTraffic.end()) {
-      if (i->getId() == id) {
-       break;
-      }
-      i++;
-    }
-  }
-  
-  // Add a new TrafficRecord if no one exsists for this aircraft.
-  if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-    FGTrafficRecord rec;
-    rec.setId(id);
-
-    rec.setPositionAndHeading(lat, lon, heading, speed, alt);
-    rec.setRunway(intendedRoute->getRunway());
-    rec.setLeg(leg);
-    //rec.setCallSign(callsign);
-    rec.setAircraft(ref);
-    rec.setHoldPosition(true);
-    activeTraffic.push_back(rec);
+FGStartupController::FGStartupController():
+FGATCController()
+{
+}
+
+void FGStartupController::announcePosition(int id,
+                                           FGAIFlightPlan * intendedRoute,
+                                           int currentPosition, double lat,
+                                           double lon, double heading,
+                                           double speed, double alt,
+                                           double radius, int leg,
+                                           FGAIAircraft * ref)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search whether the current id alread has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    // Add a new TrafficRecord if no one exsists for this aircraft.
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        FGTrafficRecord rec;
+        rec.setId(id);
+
+        rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+        rec.setRunway(intendedRoute->getRunway());
+        rec.setLeg(leg);
+        //rec.setCallSign(callsign);
+        rec.setAircraft(ref);
+        rec.setHoldPosition(true);
+        activeTraffic.push_back(rec);
     } else {
         i->setPositionAndHeading(lat, lon, heading, speed, alt);
-        
-  }
+
+    }
 }
 
 // NOTE:
@@ -784,97 +914,101 @@ bool FGStartupController::hasInstruction(int id)
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
-    if (activeTraffic.size()) 
-      {
+    if (activeTraffic.size()) {
         //while ((i->getId() != id) && i != activeTraffic.end()) {
-       while (i != activeTraffic.end()) {
-         if (i->getId() == id) {
-           break;
-         }
-        i++;
-      }
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
     }
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: checking ATC instruction for aircraft without traffic record");
     } else {
-      return i->hasInstruction();
+        return i->hasInstruction();
     }
-  return false;
+    return false;
 }
 
 
 FGATCInstruction FGStartupController::getInstruction(int id)
 {
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search search if the current id has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
-  if (activeTraffic.size()) {
-    //while ((i->getId() != id) && i != activeTraffic.end()) {
-    while (i != activeTraffic.end()) {
-      if (i->getId() == id) {
-       break;
-      }
-      i++;
-    }
-  }
-  if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-    SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
-  } else {
-    return i->getInstruction();
-  }
-  return FGATCInstruction();
-}
-
-void FGStartupController::signOff(int id) 
-{
-  TrafficVectorIterator i = activeTraffic.begin();
-  // Search search if the current id alread has an entry
-  // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
     if (activeTraffic.size()) {
-      //while ((i->getId() != id) && i != activeTraffic.end()) {
-      while (i != activeTraffic.end()) {
-       if (i->getId() == id) {
-         break;
-       }
-        i++;
-      }
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
     }
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: requesting ATC instruction for aircraft without traffic record");
     } else {
-      i = activeTraffic.erase(i);
+        return i->getInstruction();
     }
+    return FGATCInstruction();
 }
 
-void FGStartupController::update(int id, double lat, double lon, double heading, double speed, double alt, 
-                            double dt)
+void FGStartupController::signOff(int id)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id alread has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: Aircraft without traffic record is signing off from tower");
+    } else {
+        i = activeTraffic.erase(i);
+    }
+}
+
+void FGStartupController::update(int id, double lat, double lon,
+                                 double heading, double speed, double alt,
+                                 double dt)
 {
     TrafficVectorIterator i = activeTraffic.begin();
     // Search search if the current id has an entry
     // This might be faster using a map instead of a vector, but let's start by taking a safe route
     TrafficVectorIterator current, closest;
     if (activeTraffic.size()) {
-      //while ((i->getId() != id) && i != activeTraffic.end()) {
-      while (i != activeTraffic.end()) {
-       if (i->getId() == id) {
-         break;
-       }
-        i++;
-      }
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
     }
-
 //    // update position of the current aircraft
     if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
-      SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: updating aircraft without traffic record");
     } else {
-      i->setPositionAndHeading(lat, lon, heading, speed, alt);
-      current = i;
+        i->setPositionAndHeading(lat, lon, heading, speed, alt);
+        current = i;
     }
     setDt(getDt() + dt);
 
     int state = i->getState();
-    time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
-    time_t now       = time(NULL) + fgGetLong("/sim/time/warp");
+    time_t startTime =
+        i->getAircraft()->getTrafficRef()->getDepartureTime();
+    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
     //cerr << i->getAircraft()->getTrafficRef()->getCallSign() 
     //     << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
     //     << " at parking " << getGateName(i->getAircraft()) << endl;
@@ -885,91 +1019,287 @@ void FGStartupController::update(int id, double lat, double lon, double heading,
 
     if ((state == 0) && available) {
         if (now > startTime) {
-             //cerr << "Transmitting startup msg" << endl;
-             transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
-             i->updateState();
-             lastTransmission = now;
-             available = false;
+            //cerr << "Transmitting startup msg" << endl;
+            transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
+            i->updateState();
+            lastTransmission = now;
+            available = false;
         }
     }
     if ((state == 1) && available) {
-        if (now > startTime+60) {
+        if (now > startTime + 60) {
             transmit(&(*i), MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
             i->updateState();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
     }
     if ((state == 2) && available) {
-        if (now > startTime+80) {
+        if (now > startTime + 80) {
             transmit(&(*i), MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
             i->updateState();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
     }
-    if ((state == 3) && available){
-        if (now > startTime+100) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
+    if ((state == 3) && available) {
+        if (now > startTime + 100) {
+            transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START,
+                     ATC_AIR_TO_GROUND);
             i->updateState();
             lastTransmission = now;
-             available = false;
-        }
-     }
-     // Note: The next four stages are only necessesary when Startup control is
-     //  on a different frequency, compared to ground control
-     if ((state == 4) && available){
-        if (now > startTime+130) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND);
+            available = false;
+        }
+    }
+    // Note: The next four stages are only necessesary when Startup control is
+    //  on a different frequency, compared to ground control
+    if ((state == 4) && available) {
+        if (now > startTime + 130) {
+            transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
+                     ATC_AIR_TO_GROUND);
             i->updateState();
             i->nextFrequency();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
-     }
-     if ((state == 5) && available){
-        if (now > startTime+140) {
+    }
+    if ((state == 5) && available) {
+        if (now > startTime + 140) {
             transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
             i->updateState();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
-     }
-     if ((state == 6) && available){
-        if (now > startTime+150) {
-            transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
+    }
+    if ((state == 6) && available) {
+        if (now > startTime + 150) {
+            transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
+                     ATC_GROUND_TO_AIR);
             i->updateState();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
-     }
-
+    }
 
-     // TODO: Switch to APRON control and request pushback Clearance.
-     // Get Push back clearance
-     if ((state == 7) && available){
-        if (now > startTime+180) {
-            transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
+    // TODO: Switch to APRON control and request pushback Clearance.
+    // Get Push back clearance
+    if ((state == 7) && available) {
+        if (now > startTime + 180) {
+            transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
+                     ATC_AIR_TO_GROUND);
             i->updateState();
             lastTransmission = now;
-             available = false;
+            available = false;
         }
-     }
-     if ((state == 8) && available){
-        if (now > startTime+200) {
+    }
+    if ((state == 8) && available) {
+        if (now > startTime + 200) {
             if (i->pushBackAllowed()) {
-                 i->allowRepeatedTransmissions();
-                 transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
-                 i->updateState();
+                i->allowRepeatedTransmissions();
+                transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
+                         ATC_GROUND_TO_AIR);
+                i->updateState();
             } else {
-                 transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
-                 i->suppressRepeatedTransmissions();
+                transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
+                         ATC_GROUND_TO_AIR);
+                i->suppressRepeatedTransmissions();
             }
             lastTransmission = now;
-             available = false;
+            available = false;
+        }
+    }
+    if ((state == 9) && available) {
+        i->setHoldPosition(false);
+    }
+}
+
+
+/***************************************************************************
+ * class FGApproachController
+ *
+ **************************************************************************/
+FGApproachController::FGApproachController():
+FGATCController()
+{
+}
+
+// 
+void FGApproachController::announcePosition(int id,
+                                            FGAIFlightPlan * intendedRoute,
+                                            int currentPosition,
+                                            double lat, double lon,
+                                            double heading, double speed,
+                                            double alt, double radius,
+                                            int leg, FGAIAircraft * ref)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search whether the current id alread has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    // Add a new TrafficRecord if no one exsists for this aircraft.
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        FGTrafficRecord rec;
+        rec.setId(id);
+
+        rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+        rec.setRunway(intendedRoute->getRunway());
+        rec.setLeg(leg);
+        //rec.setCallSign(callsign);
+        rec.setAircraft(ref);
+        activeTraffic.push_back(rec);
+    } else {
+        i->setPositionAndHeading(lat, lon, heading, speed, alt);
+    }
+}
+
+void FGApproachController::update(int id, double lat, double lon,
+                                  double heading, double speed, double alt,
+                                  double dt)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    TrafficVectorIterator current, closest;
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+//    // update position of the current aircraft
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: updating aircraft without traffic record");
+    } else {
+        i->setPositionAndHeading(lat, lon, heading, speed, alt);
+        current = i;
+        //cerr << "ApproachController: checking for speed" << endl;
+        time_t time_diff =
+            current->getAircraft()->
+            checkForArrivalTime(string("final001"));
+        if (time_diff > 15) {
+            current->setSpeedAdjustment(current->getAircraft()->
+                                        getPerformance()->vDescent() *
+                                        1.35);
+        } else if (time_diff > 5) {
+            current->setSpeedAdjustment(current->getAircraft()->
+                                        getPerformance()->vDescent() *
+                                        1.2);
+        } else if (time_diff < -15) {
+            current->setSpeedAdjustment(current->getAircraft()->
+                                        getPerformance()->vDescent() *
+                                        0.65);
+        } else if (time_diff < -5) {
+            current->setSpeedAdjustment(current->getAircraft()->
+                                        getPerformance()->vDescent() *
+                                        0.8);
+        } else {
+            current->clearSpeedAdjustment();
+        }
+        //current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff);
+    }
+    setDt(getDt() + dt);
+}
+
+void FGApproachController::signOff(int id)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id alread has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: Aircraft without traffic record is signing off from approach");
+    } else {
+        i = activeTraffic.erase(i);
+    }
+}
+
+
+
+
+bool FGApproachController::hasInstruction(int id)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
         }
-     }
-     if ((state == 9) && available){
-          i->setHoldPosition(false);
-     }
+    }
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: checking ATC instruction for aircraft without traffic record");
+    } else {
+        return i->hasInstruction();
+    }
+    return false;
+}
+
+
+FGATCInstruction FGApproachController::getInstruction(int id)
+{
+    TrafficVectorIterator i = activeTraffic.begin();
+    // Search search if the current id has an entry
+    // This might be faster using a map instead of a vector, but let's start by taking a safe route
+    if (activeTraffic.size()) {
+        //while ((i->getId() != id) && i != activeTraffic.end()) {
+        while (i != activeTraffic.end()) {
+            if (i->getId() == id) {
+                break;
+            }
+            i++;
+        }
+    }
+    if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+        SG_LOG(SG_GENERAL, SG_ALERT,
+               "AI error: requesting ATC instruction for aircraft without traffic record");
+    } else {
+        return i->getInstruction();
+    }
+    return FGATCInstruction();
+}
+
+
+ActiveRunway *FGApproachController::getRunway(string name)
+{
+    ActiveRunwayVecIterator rwy = activeRunways.begin();
+    if (activeRunways.size()) {
+        while (rwy != activeRunways.end()) {
+            if (rwy->getRunwayName() == name) {
+                break;
+            }
+            rwy++;
+        }
+    }
+    if (rwy == activeRunways.end()) {
+        ActiveRunway aRwy(name, 0);
+        activeRunways.push_back(aRwy);
+        rwy = activeRunways.end() - 1;
+    }
+    return &(*rwy);
 }
index d069a5b84120af9e5fa2773b4f13383c0b3f7dde..7e83a72b476097808a23c9745046a93eab2d1a64 100644 (file)
@@ -28,6 +28,8 @@
 
 
 #include <simgear/compiler.h>
+// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER...
+#include <simgear/math/sg_geodesy.hxx>
 #include <simgear/debug/logstream.hxx>
 
 
@@ -185,6 +187,9 @@ public:
 typedef vector<FGTrafficRecord> TrafficVector;
 typedef vector<FGTrafficRecord>::iterator TrafficVectorIterator;
 
+typedef vector<time_t> TimeVector;
+typedef vector<time_t>::iterator TimeVectorIterator;
+
 
 /***********************************************************************
  * Active runway, a utility class to keep track of which aircraft has
@@ -195,11 +200,18 @@ class ActiveRunway
 private:
   string rwy;
   int currentlyCleared;
+  double distanceToFinal;
+  TimeVector estimatedArrivalTimes;
 public:
-  ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; };
+  ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; };
   
   string getRunwayName() { return rwy; };
   int    getCleared   () { return currentlyCleared; };
+  double getApproachDistance() { return distanceToFinal; };
+  //time_t getEstApproachTime() { return estimatedArrival; };
+
+  //void setEstApproachTime(time_t time) { estimatedArrival = time; };
+  time_t requestTimeSlot(time_t eta);
 };
 
 typedef vector<ActiveRunway> ActiveRunwayVec;
@@ -207,7 +219,7 @@ typedef vector<ActiveRunway>::iterator ActiveRunwayVecIterator;
 
 /**
  * class FGATCController
- * NOTE: this class serves as an abstraction layer for all sorts of ATC controller. 
+ * NOTE: this class serves as an abstraction layer for all sorts of ATC controllers
  *************************************************************************************/
 class FGATCController
 {
@@ -317,4 +329,33 @@ public:
 
 }; 
 
+/******************************************************************************
+ * class FGTowerControl
+ *****************************************************************************/
+class FGApproachController : public FGATCController
+{
+private:
+  TrafficVector activeTraffic;
+  ActiveRunwayVec activeRunways;
+  
+public:
+  FGApproachController();
+  virtual ~FGApproachController() {};
+  virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
+                               double lat, double lon,
+                               double hdg, double spd, double alt, double radius, int leg,
+                               FGAIAircraft *aircraft);
+  virtual void             signOff(int id);
+  virtual void             update(int id, double lat, double lon, 
+                                 double heading, double speed, double alt, double dt);
+  virtual bool             hasInstruction(int id);
+  virtual FGATCInstruction getInstruction(int id);
+
+  ActiveRunway* getRunway(string name);
+
+  bool hasActiveTraffic() { return activeTraffic.size() != 0; };
+  TrafficVector &getActiveTraffic() { return activeTraffic; };
+};
+
+
 #endif // _TRAFFIC_CONTROL_HXX
index f45341e5e8f1fbc1dcb99e9e106f4987f10255e4..f5ebd05d1d397be6054fce286903cc3773e7c0d5 100644 (file)
@@ -325,17 +325,21 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
         takeoff.clear();
         lastUpdate = dayStart;
         prevTrafficType = trafficType;
-
+        /*
         FGEnvironment
             stationweather =
             ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
             ->getEnvironment(getLatitude(), getLongitude(),
                              getElevation());
-
-        windSpeed = stationweather.get_wind_speed_kt();
-        windHeading = stationweather.get_wind_from_heading_deg();
+        */
+        windSpeed   = fgGetInt("/environment/metar/base-wind-speed-kt"); //stationweather.get_wind_speed_kt();
+        windHeading = fgGetInt("/environment/metar/base-wind-dir-deg");
+        //stationweather.get_wind_from_heading_deg();
         string scheduleName;
-        //cerr << "finding active Runway for" << _ap->getId() << endl;
+        //cerr << "finding active Runway for : " << _ap->getId() << endl;
+        //cerr << "Wind Heading              : " << windHeading << endl;
+        //cerr << "Wind Speed                : " << windSpeed << endl;
+
         //cerr << "Nr of seconds since day start << " << dayStart << endl;
 
         ScheduleTime *currSched;
@@ -347,7 +351,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
         scheduleName = currSched->getName(dayStart);
         maxTail = currSched->getTailWind();
         maxCross = currSched->getCrossWind();
-        //cerr << "SChedule anme = " << scheduleName << endl;
+        //cerr << "Current Schedule =        : " << scheduleName << endl;
         if (scheduleName.empty())
             return false;
         //cerr << "C"<< endl;
@@ -371,6 +375,13 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
             currentlyActive = &ulActive;
         }
 
+        //cerr << "Durrently active selection for " << trafficType << ": ";
+        for (stringVecIterator it = currentlyActive->begin();
+             it != currentlyActive->end(); it++) {
+             //cerr << (*it) << " ";
+         }
+         //cerr << endl;
+
         currRunwayGroup->setActive(_ap,
                                    windSpeed,
                                    windHeading,
index 1f142eb529bd36e9f0d0477e4ea382ec6d49f9a9..60921821863438f422f2ad51e4c32d441d9dede3 100644 (file)
@@ -46,12 +46,13 @@ class FGAirportDynamics {
 private:
   FGAirport* _ap;
 
-  FGParkingVec        parkings;
-  FGRunwayPreference  rwyPrefs;
-  FGSidStar           SIDs;
-  FGStartupController startupController;
-  FGGroundNetwork     groundNetwork;
-  FGTowerController   towerController;
+  FGParkingVec         parkings;
+  FGRunwayPreference   rwyPrefs;
+  FGSidStar            SIDs;
+  FGStartupController  startupController;
+  FGGroundNetwork      groundNetwork;
+  FGTowerController    towerController;
+  FGApproachController approachController;
 
   time_t lastUpdate;
   string prevTrafficType;
@@ -112,9 +113,10 @@ public:
 
 
   // ATC related functions. 
-  FGStartupController *getStartupController() { return &startupController; };
-  FGGroundNetwork     *getGroundNetwork()     { return &groundNetwork; };
-  FGTowerController   *getTowerController()   { return &towerController; };
+  FGStartupController    *getStartupController()    { return &startupController; };
+  FGGroundNetwork        *getGroundNetwork()        { return &groundNetwork; };
+  FGTowerController      *getTowerController()      { return &towerController; };
+  FGApproachController   *getApproachController()   { return &approachController; };
 
   const string& getAtisInformation() { return atisInformation; };
   int getGroundFrequency(unsigned leg); //{ return freqGround.size() ? freqGround[0] : 0; };
index 011acb866d513014d9023dd164be137047255eb6..3d96ccf7dd4e4723cfaddb27a8bdbc4a3fe165e6 100644 (file)
@@ -553,35 +553,46 @@ void FGGroundNetwork::update(int id, double lat, double lon,
     current->clearResolveCircularWait();
     current->setWaitsForId(0);
     checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
-    checkHoldPosition(id, lat, lon, heading, speed, alt);
-    if (checkForCircularWaits(id)) {
-        i->setResolveCircularWait();
-    }
     bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
-    int state = current->getState();
-    time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-    if ((now - lastTransmission) > 15) {
-        available = true;
-    }
-    if (needsTaxiClearance && available) {
-         transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
-         current->getAircraft()->setTaxiClearanceRequest(false);
-         current->setState(3);
-         lastTransmission = now;
-         available = false;
-    }
-    if ((state == 3) && available) {
-         transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
-         current->setState(4);
-         lastTransmission = now;
-         available = false;
-    }
-    if ((state == 4) && available) {
-         transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
-         current->setState(0);
-         lastTransmission = now;
-         available = false;
+    if (!needsTaxiClearance) {
+        checkHoldPosition(id, lat, lon, heading, speed, alt);
+        if (checkForCircularWaits(id)) {
+            i->setResolveCircularWait();
+        }
+    } else {
+        current->setHoldPosition(true);
+        int state = current->getState();
+        time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+        if ((now - lastTransmission) > 15) {
+            available = true;
+        }
+        if ((state < 3) && available) {
+             transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+             current->setState(3);
+             lastTransmission = now;
+             available = false;
+        }
+        if ((state == 3) && available) {
+            transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
+            current->setState(4);
+            lastTransmission = now;
+            available = false;
+        }
+        if ((state == 4) && available) {
+            transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+            current->setState(5);
+            lastTransmission = now;
+            available = false;
+        }
+        if ((state == 5) && available) {
+            current->setState(0);
+            current->getAircraft()->setTaxiClearanceRequest(false);
+            current->setHoldPosition(true);
+            available = false;
+        }
+
     }
+
 }
 
 /**
index 1131e22a0c932db85168a7f43415ff7da76271b8..01855347c620c407ed5695a9f639a0621d54eda0 100644 (file)
@@ -73,6 +73,27 @@ SGGeod FGRunwayBase::pointOnCenterline(double aOffset) const
   return result;
 }
 
+
+
+SGGeod FGRunwayBase::pointOffCenterline(double aOffset, double lateralOffset) const
+{
+  SGGeod result;
+  SGGeod temp;
+  double dummyAz2;
+  double halfLengthMetres = lengthM() * 0.5;
+
+  SGGeodesy::direct(mPosition, _heading, 
+    aOffset - halfLengthMetres,
+    temp, dummyAz2);
+
+  SGGeodesy::direct(temp, (_heading+90.0), 
+    lateralOffset,
+    result, dummyAz2);
+
+  return result;
+}
+
+
 bool FGRunwayBase::isHardSurface() const
 {
   return ((_surface_code == 1) || (_surface_code == 2));
index 1f7e58f12033837ca65b525812305cf4e1e79af7..745d4cb86b43d6d577d1bebb58424bda7b0e548f 100644 (file)
@@ -52,6 +52,7 @@ public:
    * opposited direction. 0.0 corresponds to the (non-displaced) threshold
    */
   SGGeod pointOnCenterline(double aOffset) const;
+  SGGeod pointOffCenterline(double aOffset, double lateralOffset) const;
   
   double lengthFt() const
   { return _length; }
index b47c6bc778b12914206b7a575cf302c2559b9536..f3110a1a3d64a31f3ee5274f6dcf64ad013b0d09 100644 (file)
  * ScheduleTime
  ***************e*************************************************************/
 void ScheduleTime::clear()
-{ 
-  start.clear();
-  end.clear();
-  scheduleNames.clear();
+{
+    start.clear();
+    end.clear();
+    scheduleNames.clear();
 }
 
 
-ScheduleTime::ScheduleTime(const ScheduleTime &other) 
+ScheduleTime::ScheduleTime(const ScheduleTime & other)
 {
-  //timeVec   start;
-  timeVecConstIterator i;
-  for (i = other.start.begin(); i != other.start.end(); i++)
-    start.push_back(*i);
-   for (i = other.end.begin(); i != other.end.end(); i++)
-    end.push_back(*i);
-   stringVecConstIterator k;
-   for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
-     scheduleNames.push_back(*k);
-  
-  //timeVec   end;
-  //stringVec scheduleNames;
-  tailWind = other.tailWind;
-  crssWind = other.tailWind;
+    //timeVec   start;
+    timeVecConstIterator i;
+    for (i = other.start.begin(); i != other.start.end(); i++)
+        start.push_back(*i);
+    for (i = other.end.begin(); i != other.end.end(); i++)
+        end.push_back(*i);
+    stringVecConstIterator k;
+    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
+         k++)
+        scheduleNames.push_back(*k);
+
+    //timeVec   end;
+    //stringVec scheduleNames;
+    tailWind = other.tailWind;
+    crssWind = other.tailWind;
 }
 
 
-ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) 
+ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
 {
-  //timeVec   start;
-  clear();
-  timeVecConstIterator i;
-  for (i = other.start.begin(); i != other.start.end(); i++)
-    start.push_back(*i);
-   for (i = other.end.begin(); i != other.end.end(); i++)
-    end.push_back(*i);
-   stringVecConstIterator k;
-   for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
-     scheduleNames.push_back(*k);
-  
-  //timeVec   end;
-  //stringVec scheduleNames;
-  tailWind = other.tailWind;
-  crssWind = other.tailWind;
-  return *this;
+    //timeVec   start;
+    clear();
+    timeVecConstIterator i;
+    for (i = other.start.begin(); i != other.start.end(); i++)
+        start.push_back(*i);
+    for (i = other.end.begin(); i != other.end.end(); i++)
+        end.push_back(*i);
+    stringVecConstIterator k;
+    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
+         k++)
+        scheduleNames.push_back(*k);
+
+    //timeVec   end;
+    //stringVec scheduleNames;
+    tailWind = other.tailWind;
+    crssWind = other.tailWind;
+    return *this;
 }
+
 string ScheduleTime::getName(time_t dayStart)
 {
-  if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
-    {
-      SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
-      exit(1);
-    }
-  else
-    {
-      int nrItems = start.size();
-      //cerr << "Nr of items to process: " << nrItems << endl;
-      if (nrItems > 0)
-       {
-         for (unsigned int i = 0; i < start.size(); i++)
-           {
-             //cerr << i << endl;
-             if ((dayStart >= start[i]) && (dayStart <= end[i]))
-               return scheduleNames[i];
-           }
-       }
-      //couldn't find one so return 0;
-      //cerr << "Returning 0 " << endl;
+    if ((start.size() != end.size())
+        || (start.size() != scheduleNames.size())) {
+        SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
+        exit(1);
+    } else {
+        int nrItems = start.size();
+        //cerr << "Nr of items to process: " << nrItems << endl;
+        if (nrItems > 0) {
+            for (unsigned int i = 0; i < start.size(); i++) {
+                //cerr << i << endl;
+                if ((dayStart >= start[i]) && (dayStart <= end[i]))
+                    return scheduleNames[i];
+            }
+        }
+        //couldn't find one so return 0;
+        //cerr << "Returning 0 " << endl;
     }
     return string("");
-}                            
+}
+
 /******************************************************************************
  * RunwayList
  *****************************************************************************/
 
-RunwayList::RunwayList(const RunwayList &other)
+RunwayList::RunwayList(const RunwayList & other)
 {
-  type = other.type;
-  stringVecConstIterator i;
-  for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
-    preferredRunways.push_back(*i);
+    type = other.type;
+    stringVecConstIterator i;
+    for (i = other.preferredRunways.begin();
+         i != other.preferredRunways.end(); i++)
+        preferredRunways.push_back(*i);
 }
-RunwayList& RunwayList::operator= (const RunwayList &other)
+
+RunwayList & RunwayList::operator=(const RunwayList & other)
 {
-  type = other.type;
-  preferredRunways.clear();
-  stringVecConstIterator i;
-  for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
-    preferredRunways.push_back(*i);
-  return *this;
+    type = other.type;
+    preferredRunways.clear();
+    stringVecConstIterator i;
+    for (i = other.preferredRunways.begin();
+         i != other.preferredRunways.end(); i++)
+        preferredRunways.push_back(*i);
+    return *this;
 }
-void RunwayList::set(const string &tp, const string &lst)
+
+void RunwayList::set(const string & tp, const string & lst)
 {
-  //weekday          = atoi(timeCopy.substr(0,1).c_str());
-  //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
-  //    timeCopy = timeCopy.substr(2,timeCopy.length());
-  type = tp;
-  string rwys = lst;
-  string rwy;
-  while (rwys.find(",") != string::npos)
-    {
-      rwy = rwys.substr(0, rwys.find(",",0));
-      //cerr << "adding runway [" << rwy << "] to the list " << endl;
-      preferredRunways.push_back(rwy);
-      rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
-      while (rwys[0] == ' ')
-       rwys.erase(0, 1); // Erase any leading whitespaces.
-      //cerr << "Remaining runway list " << rwys;
-    } 
-  preferredRunways.push_back(rwys);
-  //exit(1);
+    //weekday          = atoi(timeCopy.substr(0,1).c_str());
+    //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
+    //    timeCopy = timeCopy.substr(2,timeCopy.length());
+    type = tp;
+    string rwys = lst;
+    string rwy;
+    while (rwys.find(",") != string::npos) {
+        rwy = rwys.substr(0, rwys.find(",", 0));
+        //cerr << "adding runway [" << rwy << "] to the list " << endl;
+        preferredRunways.push_back(rwy);
+        rwys.erase(0, rwys.find(",", 0) + 1);   // erase until after the first whitspace
+        while (rwys[0] == ' ')
+            rwys.erase(0, 1);   // Erase any leading whitespaces.
+        //cerr << "Remaining runway list " << rwys;
+    }
+    preferredRunways.push_back(rwys);
+    //exit(1);
 }
 
-void RunwayList::clear() 
+void RunwayList::clear()
 {
-  type = "";
-  preferredRunways.clear();
+    type = "";
+    preferredRunways.clear();
 }
+
 /****************************************************************************
  *
  ***************************************************************************/
 
-RunwayGroup::RunwayGroup(const RunwayGroup &other)
+RunwayGroup::RunwayGroup(const RunwayGroup & other)
 {
-  name = other.name; 
-  RunwayListVecConstIterator i;
-  for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
-    rwyList.push_back(*i);
-  choice[0] = other.choice[0];
-  choice[1] = other.choice[1];
-  nrActive = other.nrActive;
+    name = other.name;
+    RunwayListVecConstIterator i;
+    for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+        rwyList.push_back(*i);
+    choice[0] = other.choice[0];
+    choice[1] = other.choice[1];
+    nrActive = other.nrActive;
 }
-RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
-{ 
-  rwyList.clear();
-  name = other.name; 
-  RunwayListVecConstIterator i;
-  for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
-    rwyList.push_back(*i); 
-  choice[0] = other.choice[0];
-  choice[1] = other.choice[1];
-  nrActive = other.nrActive;
-  return *this;
+
+RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
+{
+    rwyList.clear();
+    name = other.name;
+    RunwayListVecConstIterator i;
+    for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+        rwyList.push_back(*i);
+    choice[0] = other.choice[0];
+    choice[1] = other.choice[1];
+    nrActive = other.nrActive;
+    return *this;
 }
 
-void RunwayGroup::setActive(const FGAirport* airport, 
-                           double windSpeed, 
-                           double windHeading, 
-                           double maxTail, 
-                           double maxCross,
-                           stringVec *currentlyActive)
+void RunwayGroup::setActive(const FGAirport * airport,
+                            double windSpeed,
+                            double windHeading,
+                            double maxTail,
+                            double maxCross, stringVec * currentlyActive)
 {
 
-  FGRunway* rwy;
-  int activeRwys = rwyList.size(); // get the number of runways active
-  int nrOfPreferences;
-  // bool found = true;
-  // double heading;
-  double hdgDiff;
-  double crossWind;
-  double tailWind;
-  string name;
-  //stringVec names;
-  int bestMatch = 0, bestChoice = 0;
-
-  if (activeRwys > 0)
-    {  
-      // Now downward iterate across all the possible preferences
-      // starting by the least preferred choice working toward the most preferred choice
-
-      nrOfPreferences = rwyList[0].getRwyList()->size();
-      bool validSelection = true;
-      bool foundValidSelection = false;
-      for (int i = nrOfPreferences-1; i >= 0; i--)
-       {
-         int match = 0;
-         
-
-         // Test each runway listed in the preference to see if it's possible to use
-         // If one runway of the selection isn't allowed, we need to exclude this
-         // preference, however, we don't want to stop right there, because we also
-         // don't want to randomly swap runway preferences, unless there is a need to. 
-         //
-         validSelection = true;
-         for (int j = 0; j < activeRwys; j++)
-    {
-      string ident(rwyList[j].getRwyList(i));
-      if (!airport->hasRunwayWithIdent(ident)) {
-        SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
-        continue;
-      }
-      
-            rwy = airport->getRunwayByIdent(ident);
-       
-                         //cerr << "Succes" << endl;
-                 hdgDiff = fabs(windHeading - rwy->headingDeg());
-                 //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
-                 //cerr << "Wind Speed  : " << windSpeed << endl;
-                 if (hdgDiff > 180)
-                   hdgDiff = 360 - hdgDiff;
-                 //cerr << "Heading diff: " << hdgDiff << endl;
-                 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
-                 crossWind = windSpeed * sin(hdgDiff);
-                 tailWind  = -windSpeed * cos(hdgDiff);
-                 //cerr << ". Tailwind : " << tailWind;
-                 //cerr << ". Crosswnd : " << crossWind;
-                 if ((tailWind > maxTail) || (crossWind > maxCross))
-                   {
-                     //cerr << ". [Invalid] " << endl;
-                     validSelection = false;
-                  }
-                 else 
-                   {
-                     //cerr << ". [Valid] ";
-                 }
-                             //cerr << endl;
-    } // of active runways iteration
-      
-         if (validSelection) 
-           {
-             //cerr << "Valid selection  : " << i << endl;;
-             foundValidSelection = true;
-             for (stringVecIterator it = currentlyActive->begin(); 
-                  it != currentlyActive->end(); it++)
-               {
-                 if ((*it) == name)
-                   match++;
-               }
-             if (match >= bestMatch) {
-               bestMatch = match;
-               bestChoice = i;
-             }
-           } 
-         //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
-       }
-      if (foundValidSelection)
-       {
-         //cerr << "Valid runay selection : " << bestChoice << endl;
-         nrActive = activeRwys;
-         active = bestChoice;
-         return;
-       }
-      // If this didn't work, due to heavy winds, try again
-      // but select only one landing and one takeoff runway. 
-      choice[0] = 0;
-      choice[1] = 0;
-      for (int i = activeRwys-1;  i; i--)
-       {
-         if (rwyList[i].getType() == string("landing"))
-           choice[0] = i;
-         if (rwyList[i].getType() == string("takeoff"))
-           choice[1] = i;
-       }
-      //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
-      nrOfPreferences = rwyList[0].getRwyList()->size();
-      for (int i = 0; i < nrOfPreferences; i++)
-       {
-         bool validSelection = true;
-         for (int j = 0; j < 2; j++)
-           {
-        name = rwyList[choice[j]].getRwyList(i);
-        rwy = airport->getRunwayByIdent(name);
-        
-                 //cerr << "Succes" << endl;
-                 hdgDiff = fabs(windHeading - rwy->headingDeg());
-                 if (hdgDiff > 180)
-                   hdgDiff = 360 - hdgDiff;
-                 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
-                 crossWind = windSpeed * sin(hdgDiff);
-                 tailWind  = -windSpeed * cos(hdgDiff);
-                 if ((tailWind > maxTail) || (crossWind > maxCross))
-                   validSelection = false;
-               
-
-           }
-         if (validSelection)
-           {
-             //cerr << "Valid runay selection : " << i << endl;
-             active = i;
-             nrActive = 2;
-             return;
-           }
-       }
+    FGRunway *rwy;
+    int activeRwys = rwyList.size();    // get the number of runways active
+    int nrOfPreferences;
+    // bool found = true;
+    // double heading;
+    double hdgDiff;
+    double crossWind;
+    double tailWind;
+    string name;
+    //stringVec names;
+    int bestMatch = 0, bestChoice = 0;
+
+    if (activeRwys > 0) {
+        // Now downward iterate across all the possible preferences
+        // starting by the least preferred choice working toward the most preferred choice
+
+        nrOfPreferences = rwyList[0].getRwyList()->size();
+        bool validSelection = true;
+        bool foundValidSelection = false;
+        for (int i = nrOfPreferences - 1; i >= 0; i--) {
+            int match = 0;
+
+
+            // Test each runway listed in the preference to see if it's possible to use
+            // If one runway of the selection isn't allowed, we need to exclude this
+            // preference, however, we don't want to stop right there, because we also
+            // don't want to randomly swap runway preferences, unless there is a need to. 
+            //
+            validSelection = true;
+            
+            for (int j = 0; j < activeRwys; j++) {
+                string ident(rwyList[j].getRwyList(i));
+                if (!airport->hasRunwayWithIdent(ident)) {
+                    SG_LOG(SG_GENERAL, SG_WARN,
+                           "no such runway:" << ident << " at " <<
+                           airport->ident());
+                    continue;
+                }
+
+                rwy = airport->getRunwayByIdent(ident);
+
+                //cerr << "Succes" << endl;
+                hdgDiff = fabs(windHeading - rwy->headingDeg());
+                name    = rwy->name();
+
+
+                if (hdgDiff > 180)
+                    hdgDiff = 360 - hdgDiff;
+                //cerr << "Heading diff: " << hdgDiff << endl;
+                hdgDiff *= ((2 * M_PI) / 360.0);        // convert to radians
+                crossWind = windSpeed * sin(hdgDiff);
+                tailWind = -windSpeed * cos(hdgDiff);
+                //cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
+                //cerr << ". Tailwind : " << tailWind;
+                //cerr << ". Crosswnd : " << crossWind;
+                if ((tailWind > maxTail) || (crossWind > maxCross)) {
+                    //cerr << ". [Invalid] " << endl;
+                    validSelection = false;
+                } else {
+                    //cerr << ". [Valid] ";
+                }
+                //cerr << endl;
+                for (stringVecIterator it = currentlyActive->begin();
+                     it != currentlyActive->end(); it++) {
+                    //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
+                    if ((*it) == name) {
+                        match++;
+                    }
+                }
+            }                   // of active runways iteration
+
+            if (validSelection) {
+                //cerr << "Valid selection  : " << i << endl;;
+                foundValidSelection = true;
+                if (match >= bestMatch) {
+                    bestMatch = match;
+                    bestChoice = i;
+                }
+            }
+            //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
+        }
+        if (foundValidSelection) {
+            //cerr << "Valid runay selection : " << bestChoice << endl;
+            nrActive = activeRwys;
+            active = bestChoice;
+            return;
+        }
+        // If this didn't work, due to heavy winds, try again
+        // but select only one landing and one takeoff runway. 
+        choice[0] = 0;
+        choice[1] = 0;
+        for (int i = activeRwys - 1; i; i--) {
+            if (rwyList[i].getType() == string("landing"))
+                choice[0] = i;
+            if (rwyList[i].getType() == string("takeoff"))
+                choice[1] = i;
+        }
+        //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
+        nrOfPreferences = rwyList[0].getRwyList()->size();
+        for (int i = 0; i < nrOfPreferences; i++) {
+            bool validSelection = true;
+            for (int j = 0; j < 2; j++) {
+                name = rwyList[choice[j]].getRwyList(i);
+                rwy = airport->getRunwayByIdent(name);
+
+                //cerr << "Succes" << endl;
+                hdgDiff = fabs(windHeading - rwy->headingDeg());
+                if (hdgDiff > 180)
+                    hdgDiff = 360 - hdgDiff;
+                hdgDiff *= ((2 * M_PI) / 360.0);        // convert to radians
+                crossWind = windSpeed * sin(hdgDiff);
+                tailWind = -windSpeed * cos(hdgDiff);
+                if ((tailWind > maxTail) || (crossWind > maxCross))
+                    validSelection = false;
+
+
+            }
+            if (validSelection) {
+                //cerr << "Valid runay selection : " << i << endl;
+                active = i;
+                nrActive = 2;
+                return;
+            }
+        }
     }
-  active = -1;
-  nrActive = 0;
+    active = -1;
+    nrActive = 0;
 }
 
-void RunwayGroup::getActive(int i, string &name, string &type)
+void RunwayGroup::getActive(int i, string & name, string & type)
 {
-  if (i == -1)
-    {
-      return;
-    }
-  if (nrActive == (int)rwyList.size())
-    {
-      name = rwyList[i].getRwyList(active);
-      type = rwyList[i].getType();
+    if (i == -1) {
+        return;
     }
-  else
-    { 
-      name = rwyList[choice[i]].getRwyList(active);
-      type = rwyList[choice[i]].getType();
+    if (nrActive == (int) rwyList.size()) {
+        name = rwyList[i].getRwyList(active);
+        type = rwyList[i].getType();
+    } else {
+        name = rwyList[choice[i]].getRwyList(active);
+        type = rwyList[choice[i]].getType();
     }
 }
+
 /*****************************************************************************
  * FGRunway preference
  ****************************************************************************/
-FGRunwayPreference::FGRunwayPreference(FGAirport* ap) : 
-  _ap(ap)
+FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
+_ap(ap)
 {
-  //cerr << "Running default Constructor" << endl;
-  initialized = false;
+    //cerr << "Running default Constructor" << endl;
+    initialized = false;
 }
 
-FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
+FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
 {
-  initialized = other.initialized;
+    initialized = other.initialized;
 
-  comTimes = other.comTimes; // Commercial Traffic;
-  genTimes = other.genTimes; // General Aviation;
-  milTimes = other.milTimes; // Military Traffic;
+    comTimes = other.comTimes;  // Commercial Traffic;
+    genTimes = other.genTimes;  // General Aviation;
+    milTimes = other.milTimes;  // Military Traffic;
 
-  PreferenceListConstIterator i;
-  for (i = other.preferences.begin(); i != other.preferences.end(); i++)
-    preferences.push_back(*i);
+    PreferenceListConstIterator i;
+    for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+        preferences.push_back(*i);
 }
-  
-FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
+
+FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
+                                                   & other)
 {
-  initialized = other.initialized;
-  
-  comTimes = other.comTimes; // Commercial Traffic;
-  genTimes = other.genTimes; // General Aviation;
-  milTimes = other.milTimes; // Military Traffic;
-  
-  PreferenceListConstIterator i;
-  preferences.clear();
-  for (i = other.preferences.begin(); i != other.preferences.end(); i++)
-    preferences.push_back(*i);
-  return *this;
+    initialized = other.initialized;
+
+    comTimes = other.comTimes;  // Commercial Traffic;
+    genTimes = other.genTimes;  // General Aviation;
+    milTimes = other.milTimes;  // Military Traffic;
+
+    PreferenceListConstIterator i;
+    preferences.clear();
+    for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+        preferences.push_back(*i);
+    return *this;
 }
 
 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
 {
-  if (!(strcmp(trafficType, "com"))) {
-    return &comTimes;
-  }
-  if (!(strcmp(trafficType, "gen"))) {
-    return &genTimes;
-  }
-  if (!(strcmp(trafficType, "mil"))) {
-    return &milTimes;
-  }
-  return 0;
+    if (!(strcmp(trafficType, "com"))) {
+        return &comTimes;
+    }
+    if (!(strcmp(trafficType, "gen"))) {
+        return &genTimes;
+    }
+    if (!(strcmp(trafficType, "mil"))) {
+        return &milTimes;
+    }
+    return 0;
 }
 
-RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
+RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
 {
-  PreferenceListIterator i = preferences.begin();
-  if (preferences.begin() == preferences.end())
-    return 0;
-  while (!(i == preferences.end() || i->getName() == groupName))
-    i++;
-  if (i != preferences.end())
-    return &(*i);
-  else
-    return 0;
+    PreferenceListIterator i = preferences.begin();
+    if (preferences.begin() == preferences.end())
+        return 0;
+    while (!(i == preferences.end() || i->getName() == groupName))
+        i++;
+    if (i != preferences.end())
+        return &(*i);
+    else
+        return 0;
 }
 
- string FGRunwayPreference::getId() { 
-   return _ap->getId(); 
- };
+string FGRunwayPreference::getId()
+{
+    return _ap->getId();
+};
index 8c0030de1f7a1163ead67111f5d0eadeadfce69c..65e8a2403661cf519c5d5a1bc4fb19e884ed1597 100644 (file)
@@ -289,7 +289,6 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
   if (distanceToUser >= TRAFFICTOAIDISTTOSTART) {
     return true; // out of visual range, for the moment.
   }
-  
   return createAIAircraft(flight, speed, deptime);
 }
 
index dc2444fbaa373834b93ffc76f57fd1b74c5ce805..7c13f0db602d59710d1b007b62a67f5025041569 100644 (file)
@@ -137,7 +137,9 @@ void FGTrafficManager::init()
 
 void FGTrafficManager::update(double /*dt*/)
 {
-
+  if (fgGetBool("/environment/metar/valid") == false) {
+       return;
+  }
   time_t now = time(NULL) + fgGetLong("/sim/time/warp");
   if (scheduledAircraft.size() == 0) {
     return;