]> git.mxchange.org Git - flightgear.git/commitdiff
Fix flight-plan course and distance computations.
authorJames Turner <zakalawe@mac.com>
Mon, 8 Dec 2014 17:56:15 +0000 (17:56 +0000)
committerJames Turner <zakalawe@mac.com>
Mon, 8 Dec 2014 17:56:15 +0000 (17:56 +0000)
Always use the RoutePath system for course and distance computations
in the flight plan, so that dynamic segments are handled correctly.

src/Autopilot/route_mgr.cxx
src/GUI/WaypointList.cxx
src/GUI/WaypointList.hxx
src/Instrumentation/gps.cxx
src/Navaids/FlightPlan.cxx
src/Navaids/route.cxx
src/Navaids/route.hxx
src/Navaids/routePath.cxx
src/Navaids/routePath.hxx
src/Scripting/NasalPositioned.cxx

index fa9e588a289d4a3ee27690bf2dbc38067439d274..ca851881eb2d57f102ecbd8f16d951a381d79276 100644 (file)
@@ -51,6 +51,8 @@
 #include "Navaids/positioned.hxx"
 #include <Navaids/waypoint.hxx>
 #include <Navaids/procedure.hxx>
+#include <Navaids/routePath.hxx>
+
 #include "Airports/airport.hxx"
 #include "Airports/runways.hxx"
 #include <GUI/new_gui.hxx>
@@ -482,11 +484,13 @@ void FGRouteMgr::update( double dt )
     return;
   }
   
-  double courseDeg;
-  double distanceM;
-  boost::tie(courseDeg, distanceM) = leg->waypoint()->courseAndDistanceFrom(currentPos);
-  
-// update wp0 / wp1 / wp-last
+  // use RoutePath to compute location of active WP
+  RoutePath path(_plan);
+  SGGeod wpPos = path.positionForIndex(_plan->currentIndex());
+  double courseDeg, az2, distanceM;
+  SGGeodesy::inverse(currentPos, wpPos, courseDeg, az2, distanceM);
+
+  // update wp0 / wp1 / wp-last
   wp0->setDoubleValue("dist", distanceM * SG_METER_TO_NM);
   wp0->setDoubleValue("true-bearing-deg", courseDeg);
   courseDeg -= magvar->getDoubleValue(); // expose magnetic bearing
@@ -507,8 +511,9 @@ void FGRouteMgr::update( double dt )
   
   FlightPlan::Leg* nextLeg = _plan->nextLeg();
   if (nextLeg) {
-    boost::tie(courseDeg, distanceM) = nextLeg->waypoint()->courseAndDistanceFrom(currentPos);
-     
+    wpPos = path.positionForIndex(_plan->currentIndex() + 1);
+    SGGeodesy::inverse(currentPos, wpPos, courseDeg, az2, distanceM);
+
     wp1->setDoubleValue("dist", distanceM * SG_METER_TO_NM);
     wp1->setDoubleValue("true-bearing-deg", courseDeg);
     courseDeg -= magvar->getDoubleValue(); // expose magnetic bearing
index 20183d44ea314894ef63520ccb2ed7317d094734..3687c58b7f3e95f9a4170433204900145a129dd0 100644 (file)
@@ -18,6 +18,7 @@
 #include <Main/fg_props.hxx>
 
 #include <Navaids/positioned.hxx>
+#include <Navaids/routePath.hxx>
 #include <Autopilot/route_mgr.hxx>
 
 // select if the widget grabs keys necessary to fly aircraft from the keyboard,
@@ -78,6 +79,11 @@ public:
     return _fp->legAtIndex(index)->waypoint();
   }
 
+  virtual flightgear::FlightPlan* flightplan() const
+  {
+    return _fp;
+  }
+  
   virtual void deleteAt(unsigned int index)
   {
     _fp->deleteIndex(index);
@@ -372,8 +378,11 @@ void WaypointList::draw( int dx, int dy )
   y -= (_scrollPx % rowHeight); // partially draw the first row
   
   _arrowWidth = legendFont.getStringWidth(">");
+  
+  RoutePath path(_model->flightplan());
+  
   for ( ; row <= final; ++row, y += rowHeight) {
-    drawRow(dx, dy, row, y);
+    drawRow(dx, dy, row, y, path);
   } // of row drawing iteration
   
   glDisable(GL_SCISSOR_TEST);
@@ -392,7 +401,8 @@ void WaypointList::draw( int dx, int dy )
   }
 }
 
-void WaypointList::drawRow(int dx, int dy, int rowIndex, int y)
+void WaypointList::drawRow(int dx, int dy, int rowIndex, int y,
+                           const RoutePath& path)
 {
   flightgear::Waypt* wp(_model->waypointAt(rowIndex));
     
@@ -459,18 +469,20 @@ void WaypointList::drawRow(int dx, int dy, int rowIndex, int y)
   x += 300 + PUSTR_LGAP;
   
   if (_showLatLon) {
-    SGGeod p(wp->position());
-    char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S';
-    char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W';
-    
-    ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c",
-      fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns);
+    // only show for non-dynamic waypoints
+    if (!wp->flag(WPT_DYNAMIC)) {
+      SGGeod p(wp->position());
+      char ns = (p.getLatitudeDeg() > 0.0) ? 'N' : 'S';
+      char ew = (p.getLongitudeDeg() > 0.0) ? 'E' : 'W';
+      
+      ::snprintf(buffer, 128 - count, "%4.2f%c %4.2f%c",
+        fabs(p.getLongitudeDeg()), ew, fabs(p.getLatitudeDeg()), ns);
+    } else {
+      buffer[0] = 0;
+    }
   } else if (rowIndex > 0) {
-    double courseDeg;
-    double distanceM;
-    Waypt* prev = _model->waypointAt(rowIndex - 1);
-    boost::tie(courseDeg, distanceM) = wp->courseAndDistanceFrom(prev->position());
-  
+    double courseDeg = path.computeTrackForIndex(rowIndex);
+    double distanceM = path.computeDistanceForIndex(rowIndex);
     ::snprintf(buffer, 128 - count, "%03.0f %5.1fnm",
       courseDeg, distanceM * SG_METER_TO_NM);
   }
index 4176d751ff63d10594e03e55c87f375e02a9799a..32ac8f274ecb25c690bfcda7030a791d8a200b24 100644 (file)
 // forward decls
 class puaScrollBar;
 class SGCallback;
+class RoutePath;
 
 namespace flightgear {
   class Waypt;
+  class FlightPlan;
 }
 
 class WaypointList : public puFrame, public GUI_ID
@@ -76,6 +78,8 @@ public:
     virtual int currentWaypoint() const = 0;
     virtual flightgear::Waypt* waypointAt(unsigned int index) const = 0;
   
+    virtual flightgear::FlightPlan* flightplan() const = 0;
+    
   // update notifications
     virtual void setUpdateCallback(SGCallback* cb) = 0;
   
@@ -90,7 +94,7 @@ public:
 protected:
 
 private:
-  void drawRow(int dx, int dy, int rowIndex, int yOrigin);
+  void drawRow(int dx, int dy, int rowIndex, int yOrigin, const RoutePath& path);
 
   void handleDrag(int x, int y);
   void doDrop(int x, int y);
index 2e8f5bc47b24c296d037aba9175a13cfa3f1991b..cf897e254b0f52f7dad45fafa63caa07d7c88dbe 100644 (file)
@@ -23,6 +23,8 @@
 #include <Navaids/waypoint.hxx>
 #include "Navaids/navrecord.hxx"
 #include "Navaids/FlightPlan.hxx"
+#include <Navaids/routePath.hxx>
+
 #include "Airports/airport.hxx"
 #include "Airports/runways.hxx"
 #include "Autopilot/route_mgr.hxx"
@@ -723,16 +725,18 @@ void GPS::computeTurnData()
   }
   
   WayptRef next = _route->nextLeg()->waypoint();
-  if (next->flag(WPT_DYNAMIC) || !_config.turnAnticipationEnabled()) {
+  if (next->flag(WPT_DYNAMIC) ||
+      !_config.turnAnticipationEnabled() ||
+      next->flag(WPT_OVERFLIGHT))
+  {
     _anticipateTurn = false;
     return;
   }
   
   _turnStartBearing = _desiredCourse;
 // compute next leg course
-  double crs, dist;
-  boost::tie(crs, dist) = next->courseAndDistanceFrom(_currentWaypt->position());
-    
+  RoutePath path(_route);
+  double crs = path.computeTrackForIndex(_route->currentIndex() + 1);
 
 // compute offset bearing
   _turnAngle = crs - _turnStartBearing;
@@ -795,9 +799,14 @@ void GPS::updateRouteData()
 {
   double totalDistance = _wayptController->distanceToWayptM() * SG_METER_TO_NM;
   // walk all waypoints from wp2 to route end, and sum
- // for (int i=_routeMgr->currentIndex()+1; i<_routeMgr->numWaypts(); ++i) {
-    //totalDistance += _routeMgr->get_waypoint(i).get_distance();
-  //}
+  for (int i=_route->currentIndex()+1; i<_route->numLegs(); ++i) {
+    FlightPlan::Leg* leg = _route->legAtIndex(i);
+    // omit missed-approach waypoints in distance calculation
+    if (leg->waypoint()->flag(WPT_MISS))
+      continue;
+      
+    totalDistance += leg->distanceAlongRoute();
+  }
   
   _routeDistanceNm->setDoubleValue(totalDistance * SG_METER_TO_NM);
   if (_last_speed_kts > 1.0) {
index 8a407c99111d58ad14f442bb4c6e6fc4d1cb1354..3b2fe687056457daf30486bc6b448a272bbb149f 100644 (file)
@@ -49,6 +49,7 @@
 #include "Main/fg_props.hxx"
 #include <Navaids/procedure.hxx>
 #include <Navaids/waypoint.hxx>
+#include <Navaids/routePath.hxx>
 
 using std::string;
 using std::vector;
@@ -1186,17 +1187,21 @@ double FlightPlan::Leg::distanceAlongRoute() const
 void FlightPlan::rebuildLegData()
 {
   _totalDistance = 0.0;
+  double totalDistanceIncludingMissed = 0.0;
+  RoutePath path(this);
+  
   int lastLeg = static_cast<int>(_legs.size()) - 1;
   for (int l=0; l<lastLeg; ++l) {
-    Leg* cur = _legs[l];
-    Leg* next = _legs[l + 1];
+    _legs[l]->_courseDeg = path.computeTrackForIndex(l);
+    _legs[l]->_pathDistance = path.computeDistanceForIndex(l) * SG_METER_TO_NM;
+    _legs[l]->_distanceAlongPath = totalDistanceIncludingMissed;
+    
+    // omit misseed-approach waypoints from total distance calculation
+    if (!_legs[l]->waypoint()->flag(WPT_MISS)) {
+      _totalDistance += _legs[l]->_pathDistance;
+    }
     
-    std::pair<double, double> crsDist =
-      next->waypoint()->courseAndDistanceFrom(cur->waypoint()->position());
-    _legs[l]->_courseDeg = crsDist.first;
-    _legs[l]->_pathDistance = crsDist.second * SG_METER_TO_NM;
-    _legs[l]->_distanceAlongPath = _totalDistance;
-    _totalDistance += crsDist.second * SG_METER_TO_NM;
+    totalDistanceIncludingMissed += _legs[l]->_pathDistance;
   } // of legs iteration
   
 // set some data on the final leg
@@ -1205,7 +1210,7 @@ void FlightPlan::rebuildLegData()
     // waypoint
     _legs[lastLeg]->_courseDeg = _legs[lastLeg - 1]->_courseDeg;
     _legs[lastLeg]->_pathDistance = 0.0;
-    _legs[lastLeg]->_distanceAlongPath = _totalDistance;
+    _legs[lastLeg]->_distanceAlongPath = totalDistanceIncludingMissed;
   }
 }
   
index 8d4eb4029a8b04a88306adb67b928ad704ddfd97..0697769d33fd3158cecd0b022226f7c850f5a10c 100644 (file)
@@ -139,18 +139,6 @@ double Waypt::speedMach() const
   assert(_speedRestrict == SPEED_RESTRICT_MACH);
   return speed();
 }
-  
-std::pair<double, double>
-Waypt::courseAndDistanceFrom(const SGGeod& aPos) const
-{
-  if (flag(WPT_DYNAMIC)) {
-    return std::make_pair(0.0, 0.0);
-  }
-  
-  double course, az2, distance;
-  SGGeodesy::inverse(aPos, position(), course, az2, distance);
-  return std::make_pair(course, distance);
-}
 
 double Waypt::magvarDeg() const
 {
index 344ac1b38d8afb2f917d41ef041368253ee05029..657a939ef92b1381cc31957ea71ca70b2a755809 100644 (file)
@@ -98,13 +98,7 @@ public:
   
        RouteBase* owner() const 
                { return _owner; }
-  
-  /**
-   * Return true course (in degrees) and distance (in metres) from the provided
-   * position to this waypoint
-   */
-  virtual std::pair<double, double> courseAndDistanceFrom(const SGGeod& aPos) const;
-                       
+               
        virtual SGGeod position() const = 0;
        
        /**
index afbd628542644387cefbe0fc46ac57a68f2a1bb7..904154ecbc8afe921594e7b7c2e6f86e9197bbd0 100644 (file)
@@ -210,18 +210,6 @@ SGGeodVec RoutePath::pathForHold(Hold* hold) const
   return r;
 }
 
-/**
- * the path context holds the state of of an imaginary aircraft traversing
- * the route, and limits the rate at which heading / altitude / position can
- * change
- */
-class RoutePath::PathCtx
-{
-public:
-  SGGeod pos;
-  double heading;
-};
-
 bool RoutePath::computedPositionForIndex(int index, SGGeod& r) const
 {
   if ((index < 0) || (index >= (int) _waypts.size())) {
@@ -300,7 +288,21 @@ bool RoutePath::computedPositionForIndex(int index, SGGeod& r) const
     SGGeodesy::direct(prevPos, hdg, d * SG_NM_TO_METER, r, az2);
     return true;
   } else if (w->type() == "vectors"){
-    return false;
+    // return position of next point (which is presumably static fix/wpt)
+    // however, a missed approach might end with VECTORS, so tolerate that case
+    if (index + 1 >= _waypts.size()) {
+      SG_LOG(SG_NAVAID, SG_INFO, "route ends with VECTORS, no position");
+      return false;
+    }
+    
+    WayptRef nextWp = _waypts[index+1];
+    if (nextWp->flag(WPT_DYNAMIC)) {
+      SG_LOG(SG_NAVAID, SG_INFO, "dynamic WP following VECTORS, no position");
+      return false;
+    }
+    
+    r = nextWp->position();
+    return true;
   } else if (w->type() == "hold") {
     r = w->position();
     return true;
@@ -310,6 +312,39 @@ bool RoutePath::computedPositionForIndex(int index, SGGeod& r) const
   return false;
 }
 
+double RoutePath::computeDistanceForIndex(int index) const
+{
+  if ((index < 0) || (index >= (int) _waypts.size())) {
+    throw sg_range_exception("waypt index out of range",
+                             "RoutePath::computeDistanceForIndex");
+  }
+  
+  if (index + 1 >= (int) _waypts.size()) {
+    // final waypoint, distance is 0
+    return 0.0;
+  }
+  
+  WayptRef w = _waypts[index],
+    nextWp = _waypts[index+1];
+  
+  // common case, both waypoints are static
+  if (!w->flag(WPT_DYNAMIC) && !nextWp->flag(WPT_DYNAMIC)) {
+    return SGGeodesy::distanceM(w->position(), nextWp->position());
+  }
+  
+  
+  SGGeod wPos, nextPos;
+  bool ok = computedPositionForIndex(index, wPos),
+    nextOk = computedPositionForIndex(index + 1, nextPos);
+  if (ok && nextOk) {
+    return SGGeodesy::distanceM(wPos, nextPos);
+  }
+  
+  SG_LOG(SG_NAVAID, SG_INFO, "RoutePath::computeDistanceForIndex: unhandled arrangement:"
+         << w->type() << " followed by " << nextWp->type());
+  return 0.0;
+}
+
 double RoutePath::computeAltitudeForIndex(int index) const
 {
   if ((index < 0) || (index >= (int) _waypts.size())) {
@@ -382,17 +417,21 @@ double RoutePath::computeTrackForIndex(int index) const
     return rwy->headingDeg();
   }
   
-// course based upon previous and current pos
-  SGGeod pos, prevPos;
+// final waypoint, use inbound course
+  if (index + 1 >= _waypts.size()) {
+    return computeTrackForIndex(index - 1);
+  }
   
+// course based upon current and next pos
+  SGGeod pos, nextPos;
   if (!computedPositionForIndex(index, pos) ||
-      !computedPositionForIndex(index - 1, prevPos))
+      !computedPositionForIndex(index + 1, nextPos))
   {
     SG_LOG(SG_NAVAID, SG_WARN, "unable to compute position for waypoints");
     throw sg_range_exception("unable to compute position for waypoints");
   }
 
-  return SGGeodesy::courseDeg(prevPos, pos);
+  return SGGeodesy::courseDeg(pos, nextPos);
 }
 
 double RoutePath::distanceForClimb(double climbFt) const
@@ -412,4 +451,3 @@ double RoutePath::magVarFor(const SGGeod& geod) const
   double jd = globals->get_time_params()->getJD();
   return sgGetMagVar(geod, jd) * SG_RADIANS_TO_DEGREES;
 }
-
index 778e0d00ef68a268b9931bc62095a4403cadddfa..ddc15693ed588df8e91779ddb2a1d56f9d384352 100644 (file)
@@ -44,6 +44,9 @@ public:
   
   SGGeod positionForIndex(int index) const;
   
+  double computeDistanceForIndex(int index) const;
+  double computeTrackForIndex(int index) const;
+
 private:
   void commonInit();
   
@@ -53,7 +56,6 @@ private:
   
   bool computedPositionForIndex(int index, SGGeod& pos) const;
   double computeAltitudeForIndex(int index) const;
-  double computeTrackForIndex(int index) const;
   
   void interpolateGreatCircle(const SGGeod& aFrom, const SGGeod& aTo, SGGeodVec& r) const;
   
index 5386fc81d47b3f6c71eb10c934e4a7d28caa1b28..9d1260bd36cb21c85776e828f73eb6889a7540cd 100644 (file)
@@ -2299,11 +2299,12 @@ static naRef f_leg_courseAndDistanceFrom(naContext c, naRef me, int argc, naRef*
     
     SGGeod pos;
     geodFromArgs(args, 0, argc, pos);
-    
-    double courseDeg;
-    double distanceM;
-    boost::tie(courseDeg, distanceM) = leg->waypoint()->courseAndDistanceFrom(pos);
-    
+  
+    RoutePath path(leg->owner());
+    SGGeod wpPos = path.positionForIndex(leg->index());
+    double courseDeg, az2, distanceM;
+    SGGeodesy::inverse(pos, wpPos, courseDeg, az2, distanceM);
+  
     naRef result = naNewVector(c);
     naVec_append(result, naNum(courseDeg));
     naVec_append(result, naNum(distanceM * SG_METER_TO_NM));