]> git.mxchange.org Git - flightgear.git/commitdiff
Traffic improvements.
authorJames Turner <zakalawe@mac.com>
Tue, 30 Oct 2012 15:43:54 +0000 (15:43 +0000)
committerJames Turner <zakalawe@mac.com>
Tue, 30 Oct 2012 15:43:54 +0000 (15:43 +0000)
Make landings and takeoffs look more correct; tweak climb-out and touchdown phases in particular, so the turn to destination heading occurs earlier on climb out, and touchdown occurs close the GS transmitter / some distance down the runway from the beginning.

12 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIAircraft.hxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIFlightPlanCreate.cxx
src/Airports/groundnetwork.cxx
src/Airports/groundnetwork.hxx
src/Airports/runways.cxx
src/Airports/runways.hxx
src/Navaids/NavDataCache.cxx
src/Navaids/NavDataCache.hxx
src/Traffic/TrafficMgr.cxx

index fe93d938b29385ca9437ea62f96117ad2c0b1582..2db78de6d9a1e841179537c892293e32570e18a4 100644 (file)
@@ -709,9 +709,9 @@ void FGAIAircraft::handleFirstWaypoint() {
     setAltitude(prev->getAltitude());
 
     if (prev->getSpeed() > 0.0)
-        setHeading(fp->getBearing(prev->getLatitude(), prev->getLongitude(), curr));
+        setHeading(fp->getBearing(prev, curr));
     else
-        setHeading(fp->getBearing(curr->getLatitude(), curr->getLongitude(), prev));
+        setHeading(fp->getBearing(curr, prev));
 
     // If next doesn't exist, as in incrementally created flightplans for
     // AI/Trafficmanager created plans,
@@ -799,7 +799,7 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) {
     //          << " Ground target speed " << groundTargetSpeed << endl;
     double bearing = 0;
      // don't do bearing calculations for ground traffic
-       bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
+       bearing = getBearing(fp->getBearing(pos, curr));
        if (bearing < minBearing) {
             minBearing = bearing;
             if (minBearing < 10) {
@@ -913,12 +913,11 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
  * @param curr
  */
 void FGAIAircraft::controlHeading(FGAIWaypoint* curr) {
-    double calc_bearing = fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
+    double calc_bearing = fp->getBearing(pos, curr);
     //cerr << "Bearing = " << calc_bearing << endl;
     if (speed < 0) {
         calc_bearing +=180;
-        if (calc_bearing > 360)
-            calc_bearing -= 360;
+        SG_NORMALIZE_RANGE(calc_bearing, 0.0, 360.0);
     }
 
     if (finite(calc_bearing)) {
@@ -1023,19 +1022,6 @@ void FGAIAircraft::updatePrimaryTargetValues(bool& flightplanActive, bool& aiOut
     }
 }
 
-void FGAIAircraft::updatePosition() {
-    // convert speed to degrees per second
-    double speed_north_deg_sec = cos( hdg * SGD_DEGREES_TO_RADIANS )
-                                 * speed * 1.686 / ft_per_deg_lat;
-    double speed_east_deg_sec  = sin( hdg * SGD_DEGREES_TO_RADIANS )
-                                 * speed * 1.686 / ft_per_deg_lon;
-
-    // set new position
-    pos.setLatitudeDeg( pos.getLatitudeDeg() + speed_north_deg_sec * dt);
-    pos.setLongitudeDeg( pos.getLongitudeDeg() + speed_east_deg_sec * dt);
-}
-
-
 void FGAIAircraft::updateHeading() {
     // adjust heading based on current bank angle
     if (roll == 0.0)
@@ -1181,13 +1167,9 @@ void FGAIAircraft::updateVerticalSpeedTarget() {
         // find target vertical speed
         if (use_perf_vs) {
             if (altitude_ft < tgt_altitude_ft) {
-                tgt_vs = tgt_altitude_ft - altitude_ft;
-                if (tgt_vs > _performance->climbRate())
-                    tgt_vs = _performance->climbRate();
+                tgt_vs = std::min(tgt_altitude_ft - altitude_ft, _performance->climbRate());
             } else {
-                tgt_vs = tgt_altitude_ft - altitude_ft;
-                if (tgt_vs  < (-_performance->descentRate()))
-                    tgt_vs = -_performance->descentRate();
+                tgt_vs = std::max(tgt_altitude_ft - altitude_ft, -_performance->descentRate());
             }
         } else {
             double vert_dist_ft = fp->getCurrentWaypoint()->getCrossat() - altitude_ft;
@@ -1265,7 +1247,9 @@ void FGAIAircraft::handleATCRequests() {
 void FGAIAircraft::updateActualState() {
     //update current state
     //TODO have a single tgt_speed and check speed limit on ground on setting tgt_speed
-    updatePosition();
+    double distance = speed * SG_KT_TO_MPS * dt;
+    pos = SGGeodesy::direct(pos, hdg, distance);
+
 
     if (onGround())
         speed = _performance->actualSpeed(this, groundTargetSpeed, dt, holdPos);
index 73e98aeb3c9db2d9a2fd4fe968d510ad4e649798..dec7a86a41c48ade05b7026d775614bd49fbbd5a 100644 (file)
@@ -148,7 +148,6 @@ private:
     void updatePrimaryTargetValues(bool& flightplanActive, bool& aiOutOfSight);
     
     void updateSecondaryTargetValues();
-    void updatePosition();
     void updateHeading();
     void updateBankAngleTarget();
     void updateVerticalSpeedTarget();
index 1ec20e1881935e65dec9a4ef61566c11c15e423e..14c4de1acf3036654af47a8788a85fee5edc9b71 100644 (file)
@@ -34,6 +34,7 @@
 #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>
 
@@ -124,45 +125,8 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
   lastNodeVisited   = 0;
   taxiRoute         = 0;
 
-  SGPath path( globals->get_fg_root() );
-  path.append( ("/AI/FlightPlans/" + filename).c_str() );
-  SGPropertyNode root;
-
-  try {
-      readProperties(path.str(), &root);
-  } catch (const sg_exception &) {
-      SG_LOG(SG_AI, SG_ALERT,
-       "Error reading AI flight plan: " << path.str());
-       // cout << path.str() << endl;
-     return;
-  }
-
-  SGPropertyNode * node = root.getNode("flightplan");
-  for (int i = 0; i < node->nChildren(); i++) {
-     //cout << "Reading waypoint " << i << endl;        
-     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", ""        ));
-
-     if (wpt->getName() == "END") wpt->setFinished(true);
-     else wpt->setFinished(false);
-
-     pushBackWaypoint( wpt );
-   }
 
-  wpt_iterator = waypoints.begin();
-  isValid = true;
-  //cout << waypoints.size() << " waypoints read." << endl;
+  isValid = parseProperties(filename);
 }
 
 
@@ -186,7 +150,9 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
                                double speed,
                                const string& fltType,
                                const string& acType,
-                               const string& airline)
+                               const string& airline) :
+  departure(dep),
+  arrival(arr)
 {
   sid               = 0;
   repeat            = false;
@@ -199,99 +165,110 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
   lastNodeVisited   = 0;
   taxiRoute         = 0;
 
-  SGPath path( globals->get_fg_root() );
-  path.append( "/AI/FlightPlans" );
-  path.append( p );
-  
-  SGPropertyNode root;
-  isValid = true;
-
-  // 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.
-//  bool useInitialWayPoint = true;
-//  bool useCurrentWayPoint = false;
-//  if (course == 999)
-//    {
-//      useInitialWayPoint = false;
-//      useCurrentWayPoint = true;
-//    }
-
-  if (path.exists()) 
-    {
-      try 
-       {
-         readProperties(path.str(), &root);
-         
-         SGPropertyNode * node = root.getNode("flightplan");
-         
-         //pushBackWaypoint( init_waypoint );
-         for (int i = 0; i < node->nChildren(); i++) { 
-           //cout << "Reading waypoint " << i << endl;
-           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 ));
-           
-           if (wpt->getName() == "END") wpt->setFinished(true);
-           else wpt->setFinished(false);
-           pushBackWaypoint(wpt);
-         } // of node loop
-          wpt_iterator = waypoints.begin();
-       } catch (const sg_exception &e) {
-      SG_LOG(SG_AI, SG_WARN, "Error reading AI flight plan: " <<
-        e.getMessage() << " from " << e.getOrigin());
-    }
+  if (parseProperties(p)) {
+    isValid = true;
   } 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 > 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();
-    }
-
+    createWaypoints(ac, course, start, dep, arr, firstLeg, radius,
+                    alt, lat, lon, speed, fltType, acType, airline);
+  }
 }
 
-
-
-
 FGAIFlightPlan::~FGAIFlightPlan()
 {
   deleteWaypoints();
   delete taxiRoute;
+
+// if we're parked at a gate, release it
+  if (gateId >= 0) {
+    FGAirport* apt = (leg >= 7) ? arrival : departure;
+    if (apt) {
+      SG_LOG(SG_AI, SG_INFO, "releasing parking gate " << gateId << " at " << apt->ident());
+      apt->getDynamics()->releaseParking(gateId);
+    }
+  }
+}
+
+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;
+}
 
 FGAIWaypoint* const FGAIFlightPlan::getPreviousWaypoint( void ) const
 {
@@ -425,10 +402,9 @@ double FGAIFlightPlan::getBearing(FGAIWaypoint* first, FGAIWaypoint* second) con
   return SGGeodesy::courseDeg(first->getPos(), second->getPos());
 }
 
-
-double FGAIFlightPlan::getBearing(double lat, double lon, FGAIWaypoint* wp) const
+double FGAIFlightPlan::getBearing(const SGGeod& aPos, FGAIWaypoint* wp) const
 {
-  return SGGeodesy::courseDeg(SGGeod::fromDeg(lon, lat), wp->getPos());
+  return SGGeodesy::courseDeg(aPos, wp->getPos());
 }
 
 void FGAIFlightPlan::deleteWaypoints()
index c32d88345cdf0bba5a7abc04ebbd2ffd77868e0a..5b5586af1a1b36f352964dc7d0dcc34fbb6d4b3d 100644 (file)
 #ifndef _FG_AIFLIGHTPLAN_HXX
 #define _FG_AIFLIGHTPLAN_HXX
 
-#include <simgear/compiler.h>
 #include <vector>
 #include <string>
+
+#include <simgear/compiler.h>
 #include <simgear/math/SGMath.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
 
+// forward decls
 class FGTaxiRoute;
 class FGRunway;
 class FGAIAircraft;
 class FGAirport;
 
+typedef SGSharedPtr<FGAirport> FGAirportRef;
+
 class FGAIWaypoint {
 private:
    std::string name;
@@ -121,7 +126,8 @@ public:
    void setLeadDistance(double distance_ft);
    double getLeadDistance( void ) const {return lead_distance;}
    double getBearing(FGAIWaypoint* previous, FGAIWaypoint* next) const;
-   double getBearing(double lat, double lon, FGAIWaypoint* next) const;
+   double getBearing(const SGGeod& aPos, FGAIWaypoint* next) const;
+  
    double checkTrackLength(std::string wptName);
   time_t getStartTime() const { return start_time; }
    time_t getArrivalTime() const { return arrivalTime; }
@@ -187,9 +193,10 @@ private:
   FGTaxiRoute *taxiRoute;
   std::string name;
   bool isValid;
-
+  FGAirportRef departure, arrival;
+  
   void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double radius, const std::string&, const std::string&, const std::string&);
-  bool createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
+  bool createClimb(FGAIAircraft *, bool, FGAirport *, FGAirport* arrival, double, double, const std::string&);
   bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
   bool createDescent(FGAIAircraft *, FGAirport *,  double latitude, double longitude, double speed, double alt,const std::string&, double distance);
   bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
@@ -214,6 +221,28 @@ private:
 
   //void createCruiseFallback(bool, FGAirport*, FGAirport*, double, double, double, double);
  void evaluateRoutePart(double deplat, double deplon, double arrlat, double arrlon);
+  
+  /**
+   * look for and parse an PropertyList flight-plan file - essentially
+   * a flat list waypoint objects, encoded to properties
+   */
+  bool parseProperties(const std::string& filename);
+  
+  void 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 std::string& fltType,
+                       const std::string& acType,
+                       const std::string& airline);
+  
  public:
   wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); };
   wpt_vector_iterator getLastWayPoint()  { return waypoints.end(); };
index 47026b60ed71a826d8325e4f789ddad228b89313..795aceadbe603422838d413f1668e9772f29c07d 100644 (file)
@@ -38,6 +38,7 @@
 #include <Environment/environment_mgr.hxx>
 #include <Environment/environment.hxx>
 #include <FDM/LaRCsim/basic_aero.h>
+#include <Navaids/navrecord.hxx>
 
 
 /* FGAIFlightPlan::create()
@@ -78,7 +79,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
         retVal = createTakeOff(ac, firstFlight, dep, speed, fltType);
         break;
     case 4:
-        retVal = createClimb(ac, firstFlight, dep, speed, alt, fltType);
+        retVal = createClimb(ac, firstFlight, dep, arr, speed, alt, fltType);
         break;
     case 5:
         retVal = createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
@@ -460,20 +461,18 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
                                    const string & fltType)
 {
     const double ACCEL_POINT = 105.0;
-    const double KNOTS_HOUR_TO_MSEC = SG_NM_TO_METER / 3600.0;
   // climb-out angle in degrees. could move this to the perf-db but this
   // value is pretty sane
-    const double INITIAL_PITCH_ANGLE = 12.5;
+    const double INITIAL_PITCH_ANGLE = 10.0;
   
     double accel = ac->getPerformance()->acceleration();
     double vTaxi = ac->getPerformance()->vTaxi();
     double vRotate = ac->getPerformance()->vRotate();
     double vTakeoff = ac->getPerformance()->vTakeoff();
 
-    double accelMetric = accel * KNOTS_HOUR_TO_MSEC;
-    double vTaxiMetric = vTaxi * KNOTS_HOUR_TO_MSEC;
-    double vRotateMetric = vRotate * KNOTS_HOUR_TO_MSEC;
-    double vTakeoffMetric = vTakeoff * KNOTS_HOUR_TO_MSEC;
+    double accelMetric = accel * SG_KT_TO_MPS;
+    double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
+    double vRotateMetric = vRotate * SG_KT_TO_MPS;
    
     FGAIWaypoint *wpt;
     // Get the current active runway, based on code from David Luff
@@ -498,7 +497,8 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
     wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
     pushBackWaypoint(wpt);
 
-    double vRef = vTakeoffMetric + 20; // climb-out at v2 + 20kts
+    double vRef = vTakeoff + 20; // climb-out at v2 + 20kts
+  
     double gearUpDist = d + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
     accelPoint = rwy->pointOnCenterline(gearUpDist);
     
@@ -509,14 +509,22 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
     wpt->setGear_down(false);
     pushBackWaypoint(wpt);
   
+  // limit climbout speed to 240kts below 10000'
+    double vClimbBelow10000 = std::min(240.0, ac->getPerformance()->vClimb());
+  
+  // create two climb-out points. This is important becuase the first climb point will
+  // be a (sometimes large) turn towards the destination, and we don't want to
+  // commence that turn below 2000'
     double climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2000 * SG_FEET_TO_METER);
     accelPoint = rwy->pointOnCenterline(climbOut);
-    wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vRef);
+    wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vClimbBelow10000);
+    pushBackWaypoint(wpt);
+  
+    climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2500 * SG_FEET_TO_METER);
+    accelPoint = rwy->pointOnCenterline(climbOut);
+    wpt = createInAir(ac, "2500'", accelPoint, airportElev + 2500, vClimbBelow10000);
     pushBackWaypoint(wpt);
 
-  // as soon as we pass 2000', hand off to departure so the next acft can line up
-  // ideally the next aircraft would be able to line-up + hold but that's tricky
-  // with the current design.
     return true;
 }
 
@@ -525,14 +533,14 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
  * initialize the Aircraft at the parking location
  ******************************************************************/
 bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
-                                 FGAirport * apt, double speed, double alt,
+                                 FGAirport * apt, FGAirport* arrival,
+                                 double speed, double alt,
                                  const string & fltType)
 {
     FGAIWaypoint *wpt;
-//  bool planLoaded = false;
-    string fPLName;
+  //  string fPLName;
     double vClimb = ac->getPerformance()->vClimb();
-
+  
     if (firstFlight) {
         string rwyClass = getRunwayClassFromTrafficType(fltType);
         double heading = ac->getTrafficRef()->getCourse();
@@ -546,18 +554,23 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
             //cerr << " Cloning waypoint " << endl;
         }
     } else {
-        FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
-        assert( rwy != NULL );
-
-        SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER);
+        FGRunway* runway = apt->getRunwayByIdent(activeRunway);
+        SGGeod cur = runway->end();
+        if (!waypoints.empty()) {
+          cur = waypoints.back()->getPos();
+        }
+      
+      // compute course towards destination
+        double course = SGGeodesy::courseDeg(cur, arrival->geod());
+      
+        SGGeod climb1 = SGGeodesy::direct(cur, course, 10 * SG_NM_TO_METER);
         wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb);
         wpt->setGear_down(true);
         wpt->setFlaps_down(true);
         pushBackWaypoint(wpt);
 
-        SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER);
-        wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
-        wpt->setAltitude(18000);
+        SGGeod climb2 = SGGeodesy::direct(cur, course, 20 * SG_NM_TO_METER);
+        wpt = createInAir(ac, "18000ft climb", climb2, 18000, vClimb);
         pushBackWaypoint(wpt);
     }
     return true;
@@ -580,8 +593,6 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
     FGAIWaypoint *wpt;
     double vDescent = ac->getPerformance()->vDescent();
     double vApproach = ac->getPerformance()->vApproach();
-    double vTouchdown = ac->getPerformance()->vTouchdown();
-
 
     //Beginning of Descent 
     string rwyClass = getRunwayClassFromTrafficType(fltType);
@@ -827,34 +838,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
 
     // The approach leg should bring the aircraft to approximately 4-6 nm out, after which the landing phase should take over. 
     //cerr << "Phase 3: Approach" << endl;
-    double tgt_speed = vApproach;
-    distanceOut -= distanceCovered;
-    double touchDownPoint = 0; //(rwy->lengthM() * 0.1);
-    for (int i = 1; i < nPoints; i++) {
-        SGGeod result;
-        double currentDist = i * (distanceOut / nPoints);
-        //double currentAltitude =
-        //    apt->getElevation() + 2000 - (i * 2000 / (nPoints-1));
-        double alt = currentAltitude -  (i * 2000 / (nPoints - 1));
-        snprintf(buffer, 16, "final%03d", i);
-        result = rwy->pointOnCenterline((-distanceOut) + currentDist + touchDownPoint);
-        if (i == nPoints - 30) {
-            tgt_speed = vTouchdown;
-        }
-        wpt = createInAir(ac, buffer, result, alt, tgt_speed);
-        wpt->setCrossat(alt);
-        wpt->setTrackLength((distanceOut / nPoints));
-        // account for the extra distance due to an extended downwind leg
-        if (i == 1) {
-            wpt->setTrackLength(wpt->getTrackLength() + distanceCovered);
-        }
-        //cerr << "Track Length : " << wpt->trackLength;
-        pushBackWaypoint(wpt);
-        //if (apt->ident() == fgGetString("/sim/presets/airport-id")) {
-        //    cerr << "  Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << " " << apt->getElevation() << " " << distanceOut << endl;
-        //}
-    }
-
+    
     //cerr << "Done" << endl;
 
     // Erase the two bogus BOD points: Note check for conflicts with scripted AI flightPlans
@@ -885,10 +869,31 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
         ac->resetPositionFromFlightPlan();
     }
     waypoints[1]->setName( (waypoints[1]->getName() + string("legend"))); 
-    waypoints.back()->setName(waypoints.back()->getName() + "LandingThreshold");
     return true;
 }
 
+/**
+ * compute the distance along the centerline, to the ILS glideslope
+ * transmitter. Return -1 if there's no GS for the runway
+ */
+static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
+{
+  FGNavRecord* gs = rwy->glideslope();
+  if (!gs) {
+    return -1;
+  }
+  
+  SGVec3d runwayPosCart = SGVec3d::fromGeod(rwy->pointOnCenterline(0.0));
+  // compute a unit vector in ECF cartesian space, from the runway beginning to the end
+  SGVec3d runwayDirectionVec = normalize(SGVec3d::fromGeod(rwy->end()) - runwayPosCart);
+  SGVec3d gsTransmitterVec = gs->cart() - runwayPosCart;
+  
+// project the gsTransmitterVec along the runwayDirctionVec to get out
+// final value (in metres)
+  double dist = dot(runwayDirectionVec, gsTransmitterVec);
+  return dist;
+}
+
 /*******************************************************************
  * CreateLanding
  * Create a flight path from the "permision to land" point (currently
@@ -902,108 +907,81 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
     double vTouchdown = ac->getPerformance()->vTouchdown();
     double vTaxi      = ac->getPerformance()->vTaxi();
     double decel     = ac->getPerformance()->deceleration() * 1.4;
-    
+    double vApproach = ac->getPerformance()->vApproach();
+  
     double vTouchdownMetric = (vTouchdown  * SG_NM_TO_METER) / 3600;
     double vTaxiMetric      = (vTaxi       * SG_NM_TO_METER) / 3600;
     double decelMetric      = (decel       * SG_NM_TO_METER) / 3600;
 
-    //string rwyClass = getRunwayClassFromTrafficType(fltType);
-    //double heading = ac->getTrafficRef()->getCourse();
-    //apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
-    //rwy = apt->getRunwayByIdent(activeRunway);
-
-
-    FGAIWaypoint *wpt;
-    //double aptElev = apt->getElevation();
-    double currElev = 0;
     char buffer[12];
     FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
     assert( rwy != NULL );
-    SGGeod refPoint = rwy->pointOnCenterline(0);
-    FGTaxiNode *tn = 0;
-    if (apt->getDynamics()->getGroundNetwork()) {
-        int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
-        tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
-    }
-    if (tn) {
-        currElev = tn->getElevationFt(apt->getElevation());
-    } else {
-        currElev = apt->getElevation();
+    SGGeod threshold = rwy->threshold();
+    double currElev = threshold.getElevationFt();
+  
+    double touchdownDistance = runwayGlideslopeTouchdownDistance(rwy);
+    if (touchdownDistance < 0.0) {
+      double landingLength = rwy->lengthM() - (rwy->displacedThresholdM());
+      // touchdown 25% of the way along the landing area
+      touchdownDistance = rwy->displacedThresholdM() + (landingLength * 0.25);
     }
-
-
+  
     SGGeod coord;
-    
-
-    /*double distanceOut = rwy->lengthM() * .1;
-    double nPoints = 20;
-    for (int i = 1; i < nPoints; i++) {
-        snprintf(buffer, 12, "flare%d", i);
-        double currentDist = i * (distanceOut / nPoints);
-        double currentAltitude = apt->getElevation() + 20 - (i * 20 / nPoints);
-        coord = rwy->pointOnCenterline((currentDist * (i / nPoints)));
-        wpt = createInAir(ac, buffer, coord, currentAltitude, (vTouchdown));
-    }*/
-    double rolloutDistance =
-        (vTouchdownMetric * vTouchdownMetric - vTaxiMetric * vTaxiMetric) / (2 * decelMetric);
-    //cerr << " touchdown speed = " << vTouchdown << ". Rollout distance " << rolloutDistance << endl;
+  // find glideslope entry point, 2000' above touchdown elevation
+    double glideslopeEntry = -((2000 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
+    FGAIWaypoint *wpt = createInAir(ac, "Glideslope begin", rwy->pointOnCenterline(glideslopeEntry),
+                                  currElev + 2000, vApproach);
+    pushBackWaypoint(wpt);
+  
+  // deceleration point, 500' above touchdown elevation - slow from approach speed
+  // to touchdown speed
+    double decelPoint = -((500 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
+    wpt = createInAir(ac, "500' decel", rwy->pointOnCenterline(decelPoint),
+                                  currElev + 2000, vTouchdown);
+    pushBackWaypoint(wpt);
+  
+  // compute elevation above the runway start, based on a 3-degree glideslope
+    double heightAboveRunwayStart = touchdownDistance *
+      tan(3.0 * SG_DEGREES_TO_RADIANS) * SG_METER_TO_FEET;
+    wpt = createInAir(ac, "CrossThreshold", rwy->begin(),
+                      heightAboveRunwayStart + currElev, vTouchdown);
+    pushBackWaypoint(wpt);
+  
+    double rolloutDistance = accelDistance(vTouchdownMetric, vTaxiMetric, decelMetric);
+  
     int nPoints = 50;
     for (int i = 1; i < nPoints; i++) {
         snprintf(buffer, 12, "landing03%d", i);
-        
-        coord = rwy->pointOnCenterline((rolloutDistance * ((double) i / (double) nPoints)));
-        wpt = createOnGround(ac, buffer, coord, currElev, 2*vTaxi);
+        double t = ((double) i) / nPoints;
+        coord = rwy->pointOnCenterline(touchdownDistance + (rolloutDistance * t));
+        double vel = (vTouchdownMetric * (1.0 - t)) + (vTaxiMetric * t);
+        wpt = createOnGround(ac, buffer, coord, currElev, vel);
         wpt->setCrossat(currElev);
         pushBackWaypoint(wpt);
     }
+  
     wpt->setSpeed(vTaxi);
-    double mindist = 1.1 * rolloutDistance;
-    double maxdist = rwy->lengthM();
-    //cerr << "Finding nearest exit" << endl;
+    double mindist = (1.1 * rolloutDistance) + touchdownDistance;
+
     FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
-    if (gn) {
-        double min = 0;
-        for (int i = ceil(mindist); i < floor(maxdist); i++) {
-            coord = rwy->pointOnCenterline(mindist);
-            int nodeId = 0;
-            if (gn->getVersion() > 0) {
-                nodeId = gn->findNearestNodeOnRunway(coord);
-            } else {
-                nodeId = gn->findNearestNode(coord);
-            }
-            if (tn)
-                tn = gn->findNode(nodeId);
-            if (!tn)
-                break;
-            
-            double dist = SGGeodesy::distanceM(coord, tn->geod());
-            if (dist < (min + 0.75)) {
-                break;
-            }
-            min = dist;
-        }
-        if (tn) {
-            wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
-            pushBackWaypoint(wpt);
-        }
+    if (!gn) {
+      return true;
     }
-    //cerr << "Done. " << endl;
-
-    /*
-       //Runway Threshold
-       wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
-       wpt->crossat = apt->getElevation();
-       pushBackWaypoint(wpt); 
-
-       // Roll-out
-       wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
-       pushBackWaypoint(wpt);
-
-       SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
-       wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
-       wpt->crossat   = apt->getElevation();
-       pushBackWaypoint(wpt); 
-     */
+  
+    coord = rwy->pointOnCenterline(mindist);
+    int nodeId = 0;
+    if (gn->getVersion() > 0) {
+        nodeId = gn->findNearestNodeOnRunway(coord, rwy);
+    } else {
+        nodeId = gn->findNearestNode(coord);
+    }
+      
+    FGTaxiNode* tn = gn->findNode(nodeId);
+    if (tn) {
+        wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
+        pushBackWaypoint(wpt);
+    }
+
     return true;
 }
 
index c992f1e7b1e99420340ccdb3fbb0542e650dfab6..3c65c8e48bee0d391d2569a0603c8e307ed89883 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <Airports/simple.hxx>
 #include <Airports/dynamics.hxx>
+#include <Airports/runways.hxx>
 
 #include <AIModel/AIAircraft.hxx>
 #include <AIModel/performancedata.hxx>
@@ -455,7 +456,7 @@ int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
     return index;
 }
 
-int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod)
+int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway)
 {
     double minDist = HUGE_VAL;
     int index = -1;
@@ -465,6 +466,16 @@ int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod)
         if (!i->second->getIsOnRunway()) {
             continue;
         }
+      // check point lies on the runway - i.e that course from aGeod to the
+      // runway end, matches the runway heading
+        if (aRunway) {
+          double course = SGGeodesy::courseDeg(i->second->geod(), aRunway->end());
+          double headingDiff = course - aRunway->headingDeg();
+          SG_NORMALIZE_RANGE(headingDiff, -180.0, 180.0);
+          if (fabs(headingDiff) > 3.0) { // 3 degrees tolerance
+            continue;
+          }
+        }
       
         double d = SGGeodesy::distanceM(aGeod, i->second->geod());
         if (d < minDist) {
index 35fd03c0d3354aeaf19a96005ef8e5a9339ec4bb..9b73e2e81d08e7909626e7a3243ead090615d809 100644 (file)
 #include <list>
 #include <map>
 
-class Block;
-
 #include "gnnode.hxx"
 #include "parking.hxx"
 #include <ATC/trafficcontrol.hxx>
 
 
+class Block;
+class FGRunway;
 class FGTaxiSegment; // forward reference
 class FGAIFlightPlan; // forward reference
 class FGAirport;      // forward reference
@@ -275,7 +275,7 @@ public:
     };
 
     int findNearestNode(const SGGeod& aGeod);
-    int findNearestNodeOnRunway(const SGGeod& aGeod);
+    int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL);
 
     FGTaxiNode *findNode(unsigned idx);
     FGTaxiSegment *findSegment(unsigned idx);
index d4b319e7566e33ead51ad683099f9fe1f015581b..70a2ee1b8db3710d90c205b693705a90ae818919 100644 (file)
@@ -149,6 +149,17 @@ FGNavRecord* FGRunway::ILS() const
   return (FGNavRecord*) flightgear::NavDataCache::instance()->loadById(_ils);
 }
 
+FGNavRecord* FGRunway::glideslope() const
+{
+  flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+  PositionedID gsId = cache->findNavaidForRunway(guid(), FGPositioned::GS);
+  if (gsId == 0) {
+    return NULL;
+  }
+  
+  return (FGNavRecord*) cache->loadById(gsId);
+}
+
 std::vector<flightgear::SID*> FGRunway::getSIDs() const
 {
   FGAirport* apt = airport();
index d824aa3e3f939985e0b83f54159d53ab90519a54..36f342c00f24edaca428ea135091296cc4fb8380 100644 (file)
@@ -108,6 +108,11 @@ public:
   
   FGNavRecord* ILS() const;
   
+  /**
+   * retrieve the associated glideslope transmitter, if one is defined.
+   */
+  FGNavRecord* glideslope() const;
+  
   void setILS(PositionedID nav) { _ils = nav; }
   
   FGRunway* reciprocalRunway() const;
index d39f438a5d67b57e6d75174f06460138152f8f5a..5d228c4bcf7dd4d21447884e4b9ab6969ee19bef 100644 (file)
@@ -528,6 +528,9 @@ public:
     findNavsByFreqNoPos = prepare("SELECT positioned.rowid FROM positioned, navaid WHERE "
                                   "positioned.rowid=navaid.rowid AND freq=?1 " AND_TYPED);
     
+    findNavaidForRunway = prepare("SELECT positioned.rowid FROM positioned, navaid WHERE "
+                                  "positioned.rowid=navaid.rowid AND runway=?1 AND type=?2");
+    
   // for an octree branch, return the child octree nodes which exist,
   // described as a bit-mask
     getOctreeChildren = prepare("SELECT children FROM octree WHERE rowid=?1");
@@ -808,7 +811,7 @@ public:
 
   sqlite3_stmt_ptr searchAirports;
   sqlite3_stmt_ptr findCommByFreq, findNavsByFreq,
-  findNavsByFreqNoPos;
+  findNavsByFreqNoPos, findNavaidForRunway;
   sqlite3_stmt_ptr getAirportItems, getAirportItemByIdent;
   sqlite3_stmt_ptr findAirportRunway,
     findILS;
@@ -1707,6 +1710,18 @@ AirwayEdgeVec NavDataCache::airwayEdgesFrom(int network, PositionedID pos)
   }
   return result;
 }
+
+PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned::Type ty)
+{
+  d->reset(d->findNavaidForRunway);
+  sqlite3_bind_int64(d->findNavaidForRunway, 1, runway);
+  sqlite3_bind_int(d->findNavaidForRunway, 2, ty);
+  if (!d->execSelect(d->findNavaidForRunway)) {
+    return 0;
+  }
+  
+  return sqlite3_column_int64(d->findNavaidForRunway, 0);
+}
   
 } // of namespace flightgear
 
index e7909818c307d00ad8cb544c1d385bd2ee5892d2..4080a608e6f1835dfc6dee68302d473b531ba5ad 100644 (file)
@@ -140,6 +140,11 @@ public:
   /// returning results. Only used by TACAN carrier search
   PositionedIDVec findNavaidsByFreq(int freqKhz, FGPositioned::Filter* filt);
   
+  /**
+   * Given a runway and type, find the corresponding navaid (ILS / GS / OM)
+   */
+  PositionedID findNavaidForRunway(PositionedID runway, FGPositioned::Type ty);
+  
   /**
    * given a navaid name (or similar) from apt.dat / nav.dat, find the
    * corresponding airport and runway IDs.
index 464dca5e04286b7d589b3d58d2bb12e8428ec10e..acc9fa90c883c7cd2acb8d3caa1c68f1585dd718 100644 (file)
@@ -200,15 +200,15 @@ void FGTrafficManager::shutdown()
             cachefile << "[TrafficManagerCachedata:ref:2011:09:04]" << endl;
         }
     }
-    for (ScheduleVectorIterator sched = scheduledAircraft.begin();
-         sched != scheduledAircraft.end(); sched++) {
+  
+    BOOST_FOREACH(FGAISchedule* acft, scheduledAircraft) {
         if (saveData) {
-            cachefile << (*sched)->getRegistration() << " "
-                << (*sched)->getRunCount() << " "
-                << (*sched)->getHits() << " "
-                << (*sched)->getLastUsed() << endl;
+            cachefile << acft->getRegistration() << " "
+                << acft->getRunCount() << " "
+                << acft->getHits() << " "
+                << acft->getLastUsed() << endl;
         }
-        delete(*sched);
+        delete acft;
     }
     if (saveData) {
         cachefile.close();
@@ -271,10 +271,9 @@ void FGTrafficManager::finishInit()
     SG_LOG(SG_AI, SG_INFO, "finishing AI-Traffic init");
     loadHeuristics();
     
-    // Do sorting and scoring separately, to take advantage of the "homeport| variable
-    for (currAircraft = scheduledAircraft.begin();
-         currAircraft != scheduledAircraft.end(); currAircraft++) {
-        (*currAircraft)->setScore();
+    // Do sorting and scoring separately, to take advantage of the "homeport" variable
+    BOOST_FOREACH(FGAISchedule* schedule, scheduledAircraft) {
+        schedule->setScore();
     }
     
     sort(scheduledAircraft.begin(), scheduledAircraft.end(),
@@ -372,7 +371,7 @@ void FGTrafficManager::update(double /*dt */ )
     }
         
     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-    if (scheduledAircraft.size() == 0) {
+    if (scheduledAircraft.empty()) {
         return;
     }