]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIFlightPlan.cxx
Overhaul the ground-net / parking code.
[flightgear.git] / src / AIModel / AIFlightPlan.cxx
index 8f728a8aff07db8188b1033e67b34bde07d1662a..df5cbf64fbfd990a563a13a0e4cdacad57e2a8cf 100644 (file)
@@ -1,4 +1,4 @@
-// FGAIFlightPlan - class for loading and storing  AI flight plans
+// // FGAIFlightPlan - class for loading and storing  AI flight plans
 // Written by David Culp, started May 2004
 // - davidculp2@comcast.net
 //
 #  include <config.h>
 #endif
 
+#include <iostream>
+
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/debug/logstream.hxx>
-#include <simgear/route/waypoint.hxx>
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/structure/exception.hxx>
 #include <simgear/constants.h>
-#ifdef __BORLANDC__
-#  define exception c_exception
-#endif
 #include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/fg_init.hxx>
 #include <Airports/simple.hxx>
+#include <Airports/dynamics.hxx>
 #include <Airports/runways.hxx>
-
+#include <Airports/groundnetwork.hxx>
 
 #include <Environment/environment_mgr.hxx>
 #include <Environment/environment.hxx>
 
 #include "AIFlightPlan.hxx"
+#include "AIAircraft.hxx"
+
+using std::cerr;
+
+FGAIWaypoint::FGAIWaypoint() {
+  speed       = 0;
+  crossat     = 0;
+  finished    = 0;
+  gear_down   = 0;
+  flaps_down  = 0;
+  on_ground   = 0;
+  routeIndex  = 0;
+  time_sec    = 0;
+  trackLength = 0;
+}
 
+bool FGAIWaypoint::contains(string target) {
+    size_t found = name.find(target);
+    if (found == string::npos)
+        return false;
+    else
+        return true;
+}
 
-FGAIFlightPlan::FGAIFlightPlan(const string& filename)
+double FGAIWaypoint::getLatitude()
 {
-  int i;
-  start_time = 0;
-  leg = 10;
-  gateId = 0;
-  SGPath path( globals->get_fg_root() );
-  path.append( ("/AI/FlightPlans/" + filename).c_str() );
-  SGPropertyNode root;
-  repeat = false;
+  return pos.getLatitudeDeg();
+}
 
-  try {
-      readProperties(path.str(), &root);
-  } catch (const sg_exception &e) {
-      SG_LOG(SG_GENERAL, SG_ALERT,
-       "Error reading AI flight plan: " << path.str());
-       // cout << path.str() << endl;
-     return;
-  }
+double FGAIWaypoint::getLongitude()
+{
+  return pos.getLongitudeDeg();
+}
 
-  SGPropertyNode * node = root.getNode("flightplan");
-  for (i = 0; i < node->nChildren(); i++) { 
-     //cout << "Reading waypoint " << i << endl;        
-     waypoint* wpt = new waypoint;
-     SGPropertyNode * wpt_node = node->getChild(i);
-     wpt->name      = wpt_node->getStringValue("name", "END");
-     wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
-     wpt->longitude = wpt_node->getDoubleValue("lon", 0);
-     wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
-     wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
-     wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
-     wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
-     wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
-     wpt->on_ground = wpt_node->getBoolValue("on-ground", false);
-
-     if (wpt->name == "END") wpt->finished = true;
-     else wpt->finished = false;
-
-     waypoints.push_back( wpt );
-   }
+double FGAIWaypoint::getAltitude()
+{
+  return pos.getElevationFt();
+}
 
-  wpt_iterator = waypoints.begin();
-  //cout << waypoints.size() << " waypoints read." << endl;
+void FGAIWaypoint::setLatitude(double lat)
+{
+  pos.setLatitudeDeg(lat);
+}
+
+void FGAIWaypoint::setLongitude(double lon)
+{
+  pos.setLongitudeDeg(lon);
+}
+
+void FGAIWaypoint::setAltitude(double alt)
+{
+  pos.setElevationFt(alt);
+}
+
+FGAIFlightPlan::FGAIFlightPlan()
+{
+    sid             = 0;
+    repeat          = false;
+    distance_to_go  = 0;
+    lead_distance   = 0;
+    start_time      = 0;
+    arrivalTime     = 0;
+    leg             = 10;
+    lastNodeVisited = 0;
+  //  taxiRoute       = 0;
+    wpt_iterator    = waypoints.begin();
+    isValid         = true;
+}
+
+FGAIFlightPlan::FGAIFlightPlan(const string& filename)
+{
+  sid               = 0;
+  repeat            = false;
+  distance_to_go    = 0;
+  lead_distance     = 0;
+  start_time        = 0;
+  arrivalTime       = 0;
+  leg               = 10;
+  lastNodeVisited   = 0;
+//  taxiRoute         = 0;
+
+
+  isValid = parseProperties(filename);
 }
 
 
@@ -95,214 +134,130 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
 // Position computed by the traffic manager, as well
 // as setting speeds and altitude computed by the
 // traffic manager. 
-FGAIFlightPlan::FGAIFlightPlan(const std::string& p,
-                              double course,
-                              time_t start,
-                              FGAirport *dep,
-                              FGAirport *arr,
-                              bool firstLeg,
-                              double radius,
+FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
+                               const std::string& p,
+                               double course,
+                               time_t start,
+                               FGAirport *dep,
+                               FGAirport *arr,
+                               bool firstLeg,
+                               double radius,
                                double alt,
                                double lat,
                                double lon,
                                double speed,
-                              const string& fltType,
-                              const string& acType,
-                              const string& airline)
+                               const string& fltType,
+                               const string& acType,
+                               const string& airline) :
+  departure(dep),
+  arrival(arr)
 {
-  leg = 10;
-  gateId=0;
-  start_time = start;
-  bool useInitialWayPoint = true;
-  bool useCurrentWayPoint = false;
-  SGPath path( globals->get_fg_root() );
-  path.append( "/AI/FlightPlans" );
-  path.append( p );
-  SGPropertyNode root;
-  
-  // This is a bit of a hack:
-  // Normally the value of course will be used to evaluate whether
-  // or not a waypoint will be used for midair initialization of 
-  // an AI aircraft. However, if a course value of 999 will be passed
-  // when an update request is received, which will by definition always be
-  // on the ground and should include all waypoints.
-  if (course == 999) 
-    {
-      useInitialWayPoint = false;
-      useCurrentWayPoint = true;
-    }
-
-  if (path.exists()) 
-    {
-      try 
-       {
-         readProperties(path.str(), &root);
-         
-         SGPropertyNode * node = root.getNode("flightplan");
-         
-         //waypoints.push_back( init_waypoint );
-         for (int i = 0; i < node->nChildren(); i++) { 
-           //cout << "Reading waypoint " << i << endl;
-           waypoint* wpt = new waypoint;
-           SGPropertyNode * wpt_node = node->getChild(i);
-           wpt->name      = wpt_node->getStringValue("name", "END");
-           wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
-           wpt->longitude = wpt_node->getDoubleValue("lon", 0);
-           wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
-           wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
-           //wpt->speed     = speed;
-           wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
-           wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
-           wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
-           
-           if (wpt->name == "END") wpt->finished = true;
-           else wpt->finished = false;
-           waypoints.push_back(wpt);
-         }
-       }
-      catch (const sg_exception &e) {
-       SG_LOG(SG_GENERAL, SG_WARN,
-              "Error reading AI flight plan: ");
-       cerr << "Errno = " << errno << endl;
-       if (errno == ENOENT)
-         {
-           cerr << "Reason: No such file or directory" << endl;
-         }
-      }
-    }
-  else
-    {
-      // cout << path.str() << endl;
-      // cout << "Trying to create this plan dynamically" << endl;
-      // cout << "Route from " << dep->id << " to " << arr->id << endl;
-      time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-      time_t timeDiff = now-start; 
-      leg = 1;
-      if ((timeDiff > 300) && (timeDiff < 1200))
-       leg = 2;
-      else if ((timeDiff >= 1200) && (timeDiff < 1500))
-       leg = 3;
-      else if ((timeDiff >= 1500) && (timeDiff < 2000))
-       leg = 4;
-      else if (timeDiff >= 2000)
-       leg = 5;
-      
-      //cerr << "Set leg to : " << leg << endl;  
-      wpt_iterator = waypoints.begin();
-      create(dep,arr, leg, alt, speed, lat, lon,
-            firstLeg, radius, fltType, acType, airline);
-      wpt_iterator = waypoints.begin();
-      //cerr << "after create: " << (*wpt_iterator)->name << endl;
-      //leg++;
-      // Now that we have dynamically created a flight plan,
-      // we need to add some code that pops any waypoints already past.
-      //return;
-    }
-  /*
-    waypoint* init_waypoint   = new waypoint;
-    init_waypoint->name       = string("initial position");
-    init_waypoint->latitude   = entity->latitude;
-    init_waypoint->longitude  = entity->longitude;
-    init_waypoint->altitude   = entity->altitude;
-    init_waypoint->speed      = entity->speed;
-    init_waypoint->crossat    = - 10000;
-    init_waypoint->gear_down  = false;
-    init_waypoint->flaps_down = false;
-    init_waypoint->finished   = false;
-    
-    wpt_vector_iterator i = waypoints.begin();
-    while (i != waypoints.end())
-    {
-      //cerr << "Checking status of each waypoint: " << (*i)->name << endl;
-       SGWayPoint first(init_waypoint->longitude, 
-                      init_waypoint->latitude, 
-                      init_waypoint->altitude);
-      SGWayPoint curr ((*i)->longitude, 
-                      (*i)->latitude, 
-                      (*i)->altitude);
-      double crse, crsDiff;
-      double dist;
-      curr.CourseAndDistance(first, &crse, &dist);
-      
-      dist *= SG_METER_TO_NM;
-      
-      // We're only interested in the absolute value of crsDiff
-      // wich should fall in the 0-180 deg range.
-      crsDiff = fabs(crse-course);
-      if (crsDiff > 180)
-       crsDiff = 360-crsDiff;
-      // These are the three conditions that we consider including
-      // in our flight plan:
-      // 1) current waypoint is less then 100 miles away OR
-      // 2) curren waypoint is ahead of us, at any distance
-     
-      if ((dist > 20.0) && (crsDiff > 90.0) && ((*i)->name != string ("EOF")))
-       {
-         //useWpt = false;
-         // Once we start including waypoints, we have to continue, even though
-         // one of the following way point would suffice. 
-         // so once is the useWpt flag is set to true, we cannot reset it to false.
-         //cerr << "Discarding waypoint: " << (*i)->name 
-         //   << ": Course difference = " << crsDiff
-         //  << "Course = " << course
-         // << "crse   = " << crse << endl;
-       }
-      else
-       useCurrentWayPoint = true;
-      
-      if (useCurrentWayPoint)
-       {
-         if ((dist > 100.0) && (useInitialWayPoint))
-           {
-             //waypoints.push_back(init_waypoint);;
-             waypoints.insert(i, init_waypoint);
-             //cerr << "Using waypoint : " << init_waypoint->name <<  endl;
-           }
-         //if (useInitialWayPoint)
-         // {
-         //    (*i)->speed = dist; // A hack
-         //  }
-         //waypoints.push_back( wpt );
-         //cerr << "Using waypoint : " << (*i)->name 
-         //  << ": course diff : " << crsDiff 
-         //   << "Course = " << course
-         //   << "crse   = " << crse << endl
-         //    << "distance      : " << dist << endl;
-         useInitialWayPoint = false;
-         i++;
-       }
-      else 
-       {
-         //delete wpt;
-         delete *(i);
-         i = waypoints.erase(i);
-         }
-         
-       }
-  */
-  //for (i = waypoints.begin(); i != waypoints.end(); i++)
-  //  cerr << "Using waypoint : " << (*i)->name << endl;
-  //wpt_iterator = waypoints.begin();
-  //cout << waypoints.size() << " waypoints read." << endl;
+  sid               = 0;
+  repeat            = false;
+  distance_to_go    = 0;
+  lead_distance     = 0;
+  start_time        = start;
+  arrivalTime       = 0;
+  leg               = 10;
+  lastNodeVisited   = 0;
+ // taxiRoute         = 0;
+
+  if (parseProperties(p)) {
+    isValid = true;
+  } else {
+    createWaypoints(ac, course, start, dep, arr, firstLeg, radius,
+                    alt, lat, lon, speed, fltType, acType, airline);
+  }
 }
 
-
-
-
 FGAIFlightPlan::~FGAIFlightPlan()
 {
   deleteWaypoints();
-  //waypoints.clear();
-  //while (waypoints.begin() != waypoints.end())
-  //  {
-  //    delete *(waypoints.begin());
-  //    waypoints.erase (waypoints.begin());
-  //  }
+  //delete taxiRoute;
+}
+
+void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
+                                     double course,
+                                     time_t start,
+                                     FGAirport *dep,
+                                     FGAirport *arr,
+                                     bool firstLeg,
+                                     double radius,
+                                     double alt,
+                                     double lat,
+                                     double lon,
+                                     double speed,
+                                     const string& fltType,
+                                     const string& acType,
+                                     const string& airline)
+{
+  time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+  time_t timeDiff = now-start;
+  leg = 1;
+  
+  if ((timeDiff > 60) && (timeDiff < 1500))
+    leg = 2;
+  //else if ((timeDiff >= 1200) && (timeDiff < 1500)) {
+       //leg = 3;
+  //ac->setTakeOffStatus(2);
+  //}
+  else if ((timeDiff >= 1500) && (timeDiff < 2000))
+    leg = 4;
+  else if (timeDiff >= 2000)
+    leg = 5;
+  /*
+   if (timeDiff >= 2000)
+   leg = 5;
+   */
+  SG_LOG(SG_AI, SG_INFO, "Route from " << dep->getId() << " to " << arr->getId() << ". Set leg to : " << leg << " " << ac->getTrafficRef()->getCallSign());
+  wpt_iterator = waypoints.begin();
+  bool dist = 0;
+  isValid = create(ac, dep, arr, leg, alt, speed, lat, lon,
+                   firstLeg, radius, fltType, acType, airline, dist);
+  wpt_iterator = waypoints.begin();
 }
 
+bool FGAIFlightPlan::parseProperties(const std::string& filename)
+{
+  SGPath path( globals->get_fg_root() );
+  path.append( "/AI/FlightPlans/" + filename );
+  if (!path.exists()) {
+    return false;
+  }
+  
+  SGPropertyNode root;
+  try {
+    readProperties(path.str(), &root);
+  } catch (const sg_exception &e) {
+    SG_LOG(SG_AI, SG_ALERT, "Error reading AI flight plan: " << path.str()
+           << "message:" << e.getFormattedMessage());
+    return false;
+  }
+  
+  SGPropertyNode * node = root.getNode("flightplan");
+  for (int i = 0; i < node->nChildren(); i++) {
+    FGAIWaypoint* wpt = new FGAIWaypoint;
+    SGPropertyNode * wpt_node = node->getChild(i);
+    wpt->setName       (wpt_node->getStringValue("name", "END"     ));
+    wpt->setLatitude   (wpt_node->getDoubleValue("lat", 0          ));
+    wpt->setLongitude  (wpt_node->getDoubleValue("lon", 0          ));
+    wpt->setAltitude   (wpt_node->getDoubleValue("alt", 0          ));
+    wpt->setSpeed      (wpt_node->getDoubleValue("ktas", 0         ));
+    wpt->setCrossat    (wpt_node->getDoubleValue("crossat", -10000 ));
+    wpt->setGear_down  (wpt_node->getBoolValue("gear-down", false  ));
+    wpt->setFlaps_down (wpt_node->getBoolValue("flaps-down", false ));
+    wpt->setOn_ground  (wpt_node->getBoolValue("on-ground", false  ));
+    wpt->setTime_sec   (wpt_node->getDoubleValue("time-sec", 0     ));
+    wpt->setTime       (wpt_node->getStringValue("time", ""        ));
+    wpt->setFinished   ((wpt->getName() == "END"));
+    pushBackWaypoint( wpt );
+  }
+  
+  wpt_iterator = waypoints.begin();
+  return true;
+}
 
-FGAIFlightPlan::waypoint* const
-FGAIFlightPlan::getPreviousWaypoint( void ) const
+FGAIWaypoint* const FGAIFlightPlan::getPreviousWaypoint( void ) const
 {
   if (wpt_iterator == waypoints.begin()) {
     return 0;
@@ -312,14 +267,14 @@ FGAIFlightPlan::getPreviousWaypoint( void ) const
   }
 }
 
-FGAIFlightPlan::waypoint* const
-FGAIFlightPlan::getCurrentWaypoint( void ) const
+FGAIWaypoint* const FGAIFlightPlan::getCurrentWaypoint( void ) const
 {
+  if (wpt_iterator == waypoints.end())
+      return 0;
   return *wpt_iterator;
 }
 
-FGAIFlightPlan::waypoint* const
-FGAIFlightPlan::getNextWaypoint( void ) const
+FGAIWaypoint* const FGAIFlightPlan::getNextWaypoint( void ) const
 {
   wpt_vector_iterator i = waypoints.end();
   i--;  // end() points to one element after the last one. 
@@ -347,44 +302,81 @@ void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
     }
   else
     wpt_iterator++;
+
+}
+
+void FGAIFlightPlan::DecrementWaypoint(bool eraseWaypoints )
+{
+    if (eraseWaypoints)
+    {
+        if (wpt_iterator == waypoints.end())
+            wpt_iterator--;
+        else
+        {
+            delete *(waypoints.end());
+            waypoints.erase(waypoints.end());
+            wpt_iterator = waypoints.end();
+            wpt_iterator--;
+        }
+    }
+    else
+        wpt_iterator--;
+}
+
+void FGAIFlightPlan::eraseLastWaypoint()
+{
+    delete (waypoints.back());
+    waypoints.pop_back();;
+    wpt_iterator = waypoints.begin();
+    wpt_iterator++;
 }
 
+
+
+
 // gives distance in feet from a position to a waypoint
-double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp) const{
-   // get size of a degree2 at the present latitude
-   // this won't work over large distances
-   double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
-   double ft_per_deg_lon = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
-   double lat_diff_ft = fabs(wp->latitude - lat) * ft_per_deg_lat;
-   double lon_diff_ft = fabs(wp->longitude - lon) * ft_per_deg_lon;
-   return sqrt((lat_diff_ft * lat_diff_ft) + (lon_diff_ft * lon_diff_ft));
+double FGAIFlightPlan::getDistanceToGo(double lat, double lon, FGAIWaypoint* wp) const{
+  return SGGeodesy::distanceM(SGGeod::fromDeg(lon, lat), wp->getPos());
 }
 
 // sets distance in feet from a lead point to the current waypoint
 void FGAIFlightPlan::setLeadDistance(double speed, double bearing, 
-                                     waypoint* current, waypoint* next){
+                                     FGAIWaypoint* current, FGAIWaypoint* next){
   double turn_radius;
-    if (fabs(speed) > 1) 
+  // Handle Ground steering
+  // At a turn rate of 30 degrees per second, it takes 12 seconds to do a full 360 degree turn
+  // So, to get an estimate of the turn radius, calculate the cicumference of the circle
+  // we travel on. Get the turn radius by dividing by PI (*2).
+  if (speed < 0.5) {
+        lead_distance = 0.5;
+        return;
+  }
+  if (speed < 25) {
+       turn_radius = ((360/30)*fabs(speed)) / (2*M_PI);
+  } else 
       turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
-    else
-      turn_radius = 1.0;
 
   double inbound = bearing;
   double outbound = getBearing(current, next);
   leadInAngle = fabs(inbound - outbound);
   if (leadInAngle > 180.0) 
     leadInAngle = 360.0 - leadInAngle;
-  if (leadInAngle < 1.0) // To prevent lead_dist from getting so small it is skipped 
-    leadInAngle = 1.0;
+  //if (leadInAngle < 30.0) // To prevent lead_dist from getting so small it is skipped 
+  //  leadInAngle = 30.0;
   
-  lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS); 
-  //  if ((errno == EDOM) || (errno == ERANGE) || lead_distance < 1.0)
-  //  {
-  //    cerr << "Lead Distance = " << lead_distance
-  //      << "Diff          = " << diff
-  //      << "Turn Radius   = " << turn_radius 
-  //      << "Speed         = " << speed << endl;
-  //  }
+  //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;
+       lead_distance = 3 * turn_radius;
+       return;
+  }
+  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){
@@ -392,59 +384,15 @@ void FGAIFlightPlan::setLeadDistance(double distance_ft){
 }
 
 
-double FGAIFlightPlan::getBearing(waypoint* first, waypoint* second) const{
-  return getBearing(first->latitude, first->longitude, second);
-}
-
-
-double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp) const{
-  double course, distance;
- //  double latd = lat;
-//   double lond = lon;
-//   double latt = wp->latitude;
-//   double lont = wp->longitude;
-//   double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES);
-//   double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES);
-
-//   if (lond < 0.0) {
-//     lond+=360.0;
-//     lont+=360;
-//   }
-//   if (lont < 0.0) {
-//     lond+=360.0;
-//     lont+=360.0;
-//   }
-//   latd+=90.0;
-//   latt+=90.0;
-
-//   double lat_diff = (latt - latd) * ft_per_deg_lat;
-//   double lon_diff = (lont - lond) * ft_per_deg_lon;
-//   double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES;
-
-//   bool southerly = true;
-//   if (latt > latd) southerly = false;
-//   bool easterly = false;
-//   if (lont > lond) easterly = true;
-//   if (southerly && easterly) return 90.0 + angle;
-//   if (!southerly && easterly) return 90.0 - angle;
-//   if (southerly && !easterly) return 270.0 - angle;
-//   if (!southerly && !easterly) return 270.0 + angle; 
-  SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
-  sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
-  
-  return course;
-  // Omit a compiler warning. 
-  //if ((errno == EDOM) || (errno == ERANGE))
-  //  {
-  //    cerr << "Lon:  " << wp->longitude
-  //      << "Lat       = " << wp->latitude
-  //   << "Tgt Lon   = " <<  
-  //   << "TgT Lat   = " << speed << endl;
-  //  }
-  
+double FGAIFlightPlan::getBearing(FGAIWaypoint* first, FGAIWaypoint* second) const
+{
+  return SGGeodesy::courseDeg(first->getPos(), second->getPos());
 }
 
-
+double FGAIFlightPlan::getBearing(const SGGeod& aPos, FGAIWaypoint* wp) const
+{
+  return SGGeodesy::courseDeg(aPos, wp->getPos());
+}
 
 void FGAIFlightPlan::deleteWaypoints()
 {
@@ -461,27 +409,76 @@ void FGAIFlightPlan::resetWaypoints()
     return;
   else
     {
-      waypoint *wpt = new waypoint;
+      FGAIWaypoint *wpt = new FGAIWaypoint;
       wpt_vector_iterator i = waypoints.end();
       i--;
-      wpt->name      = (*i)->name;
-      wpt->latitude  = (*i)->latitude;
-      wpt->longitude =  (*i)->longitude;
-      wpt->altitude  =  (*i)->altitude;
-      wpt->speed     =  (*i)->speed;
-      wpt->crossat   =  (*i)->crossat;
-      wpt->gear_down =  (*i)->gear_down;
-      wpt->flaps_down=  (*i)->flaps_down;
-      wpt->finished  = false;
-      wpt->on_ground =  (*i)->on_ground;
+      wpt->setName        ( (*i)->getName()       );
+      wpt->setPos         ( (*i)->getPos()        );
+      wpt->setCrossat     ( (*i)->getCrossat()    );
+      wpt->setGear_down   ( (*i)->getGear_down()  );
+      wpt->setFlaps_down  ( (*i)->getFlaps_down() );
+      wpt->setFinished    ( false                 );
+      wpt->setOn_ground   ( (*i)->getOn_ground()  );
       //cerr << "Recycling waypoint " << wpt->name << endl;
       deleteWaypoints();
-      waypoints.push_back(wpt);
+      pushBackWaypoint(wpt);
     }
 }
 
+void FGAIFlightPlan::pushBackWaypoint(FGAIWaypoint *wpt)
+{
+  // std::vector::push_back invalidates waypoints
+  //  so we should restore wpt_iterator after push_back
+  //  (or it could be an index in the vector)
+  size_t pos = wpt_iterator - waypoints.begin();
+  waypoints.push_back(wpt);
+  wpt_iterator = waypoints.begin() + pos;
+}
+
 // Start flightplan over from the beginning
 void FGAIFlightPlan::restart()
 {
   wpt_iterator = waypoints.begin();
 }
+
+int FGAIFlightPlan::getRouteIndex(int i) {
+  if ((i > 0) && (i < (int)waypoints.size())) {
+    return waypoints[i]->getRouteIndex();
+  }
+  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)->contains(wptName)))) {
+           trackDistance += (*wptvec)->getTrackLength();
+           wptvec++;
+    }
+    if (wptvec == waypoints.end()) {
+        trackDistance = 0; // name not found
+    }
+    return trackDistance;
+}
+
+void FGAIFlightPlan::shortenToFirst(unsigned int number, string name)
+{
+    while (waypoints.size() > number + 3) {
+        eraseLastWaypoint();
+    }
+    (waypoints.back())->setName((waypoints.back())->getName() + name);
+}
+
+void FGAIFlightPlan::setGate(ParkingAssignment pka)
+{
+  gate = pka;
+}
+
+FGParking* FGAIFlightPlan::getParkingGate()
+{
+  return gate.parking();
+}