]> git.mxchange.org Git - flightgear.git/blobdiff - src/Autopilot/route_mgr.cxx
Remove un-needed header.
[flightgear.git] / src / Autopilot / route_mgr.cxx
index d39c49c5546e877908abc71445f8e82bddba3e84..337f2e9f2007751691e1fec38f7219d15cf98d66 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <boost/algorithm/string/case_conv.hpp>
 #include <boost/tuple/tuple.hpp>
+#include <boost/foreach.hpp>
 
 #include <simgear/misc/strutils.hxx>
 #include <simgear/structure/exception.hxx>
@@ -452,7 +453,7 @@ void FGRouteMgr::update( double dt )
   }
 
   if (checkFinished()) {
-    // maybe we're done
+    endOfRoute();
   }
   
 // basic course/distance information
@@ -534,14 +535,11 @@ int FGRouteMgr::currentIndex() const
 
 Waypt* FGRouteMgr::wayptAtIndex(int index) const
 {
-  if (_plan) {
-    FlightPlan::Leg* leg = _plan->legAtIndex(index);
-    if (leg) {
-      return leg->waypoint();
-    }
+  if (!_plan) {
+    throw sg_range_exception("wayptAtindex: no flightplan");
   }
   
-  return NULL;
+  return _plan->legAtIndex(index)->waypoint();
 }
 
 int FGRouteMgr::numLegs() const
@@ -589,8 +587,12 @@ void FGRouteMgr::removeLegAtIndex(int aIndex)
 void FGRouteMgr::waypointsChanged()
 {
   update_mirror();
-   _edited->fireValueChanged();
-  checkFinished();
+  _edited->fireValueChanged();
+  
+// removing waypoints, deactivate if we hit the end.
+  if (currentIndex() >= numLegs()) {
+    endOfRoute();
+  }
 }
 
 // mirror internal route to the property system for inspection by other subsystems
@@ -801,11 +803,21 @@ void FGRouteMgr::sequence()
     return;
   }
   
-  if (checkFinished()) {
+  int nextIndex = _plan->currentIndex() + 1;
+  if (nextIndex >= _plan->numLegs()) {
+    SG_LOG(SG_AUTOPILOT, SG_INFO, "sequenced on final leg, deactivating route");
+    endOfRoute();
     return;
   }
-  
-  _plan->setCurrentIndex(_plan->currentIndex() + 1);
+
+  _plan->setCurrentIndex(nextIndex);
+}
+
+void FGRouteMgr::endOfRoute()
+{
+  SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
+  _finished->fireValueChanged();
+  active->setBoolValue(false);
 }
 
 bool FGRouteMgr::checkFinished()
@@ -823,15 +835,8 @@ bool FGRouteMgr::checkFinished()
     done = weightOnWheels->getBoolValue() && (gs < 25);
   }
   
-// also done if we hit the final waypoint
-  if (_plan->currentIndex() >= _plan->numLegs()) {
-    done = true;
-  }
-  
   if (done) {
-    SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
-    _finished->fireValueChanged();
-    active->setBoolValue(false);
+    SG_LOG(SG_AUTOPILOT, SG_INFO, "checkFinished: on the ground on destination runway, we're done");
   }
   
   return done;
@@ -913,6 +918,69 @@ const char* FGRouteMgr::getSID() const
   return "";
 }
 
+static double headingDiffDeg(double a, double b)
+{
+  double rawDiff = b - a;
+  SG_NORMALIZE_RANGE(rawDiff, -180.0, 180.0);
+  return rawDiff;
+}
+
+flightgear::SID* createDefaultSID(FGRunway* aRunway, double enrouteCourse)
+{
+  if (!aRunway) {
+    return NULL;
+  }
+  
+  double runwayElevFt = aRunway->end().getElevationFt();
+  WayptVec wpts;
+  std::ostringstream ss;
+  ss << aRunway->ident() << "-3";
+  
+  SGGeod p = aRunway->pointOnCenterline(aRunway->lengthM() + (3.0 * SG_NM_TO_METER));
+  WayptRef w = new BasicWaypt(p, ss.str(), NULL);
+  w->setAltitude(runwayElevFt + 3000.0, RESTRICT_AT);
+  wpts.push_back(w);
+  
+  ss.str("");
+  ss << aRunway->ident() << "-6";
+  p = aRunway->pointOnCenterline(aRunway->lengthM() + (6.0 * SG_NM_TO_METER));
+  w = new BasicWaypt(p, ss.str(), NULL);
+  w->setAltitude(runwayElevFt + 6000.0, RESTRICT_AT);
+  wpts.push_back(w);
+
+  if (enrouteCourse >= 0.0) {
+    // valid enroute course
+    int index = 3;
+    double course = aRunway->headingDeg();
+    double diff;
+    while (fabs(diff = headingDiffDeg(course, enrouteCourse)) > 45.0) {
+      // turn in the sign of the heading change 45 degrees
+      course += copysign(45.0, diff);
+      ss.str("");
+      ss << "DEP-" << index++;
+      SGGeod pos = wpts.back()->position();
+      pos = SGGeodesy::direct(pos, course, 3.0 * SG_NM_TO_METER);
+      w = new BasicWaypt(pos, ss.str(), NULL);
+      wpts.push_back(w);
+    }
+  } else {
+    // no enroute course, just keep runway heading
+    ss.str("");
+    ss << aRunway->ident() << "-9";
+    p = aRunway->pointOnCenterline(aRunway->lengthM() + (9.0 * SG_NM_TO_METER));
+    w = new BasicWaypt(p, ss.str(), NULL);
+    w->setAltitude(runwayElevFt + 9000.0, RESTRICT_AT);
+    wpts.push_back(w);
+  }
+  
+  BOOST_FOREACH(Waypt* w, wpts) {
+    w->setFlag(WPT_DEPARTURE);
+    w->setFlag(WPT_GENERATED);
+  }
+  
+  return flightgear::SID::createTempSID("DEFAULT", aRunway, wpts);
+}
+
 void FGRouteMgr::setSID(const char* aIdent)
 {
   FGAirport* apt = _plan->departureAirport();
@@ -921,6 +989,16 @@ void FGRouteMgr::setSID(const char* aIdent)
     return;
   } 
   
+  if (!strcmp(aIdent, "DEFAULT")) {
+    double enrouteCourse = -1.0;
+    if (_plan->destinationAirport()) {
+      enrouteCourse = SGGeodesy::courseDeg(apt->geod(), _plan->destinationAirport()->geod());
+    }
+    
+    _plan->setSID(createDefaultSID(_plan->departureRunway(), enrouteCourse));
+    return;
+  }
+  
   string ident(aIdent);
   size_t hyphenPos = ident.find('-');
   if (hyphenPos != string::npos) {
@@ -990,9 +1068,79 @@ const char* FGRouteMgr::getApproach() const
   return "";
 }
 
+flightgear::Approach* createDefaultApproach(FGRunway* aRunway, double aEnrouteCourse)
+{
+  if (!aRunway) {
+    return NULL;
+  }
+
+  double thresholdElevFt = aRunway->threshold().getElevationFt();
+  const double approachHeightFt = 2000.0;
+  double glideslopeDistanceM = (approachHeightFt * SG_FEET_TO_METER) /
+    tan(3.0 * SG_DEGREES_TO_RADIANS);
+  
+  std::ostringstream ss;
+  ss << aRunway->ident() << "-12";
+  WayptVec wpts;
+  SGGeod p = aRunway->pointOnCenterline(-12.0 * SG_NM_TO_METER);
+  WayptRef w = new BasicWaypt(p, ss.str(), NULL);
+  w->setAltitude(thresholdElevFt + 4000, RESTRICT_AT);
+  wpts.push_back(w);
+
+// work back form the first point on the centerline
+  
+  if (aEnrouteCourse >= 0.0) {
+    // valid enroute course
+    int index = 4;
+    double course = aRunway->headingDeg();
+    double diff;
+    while (fabs(diff = headingDiffDeg(aEnrouteCourse, course)) > 45.0) {
+      // turn in the sign of the heading change 45 degrees
+      course -= copysign(45.0, diff);
+      ss.str("");
+      ss << "APP-" << index++;
+      SGGeod pos = wpts.front()->position();
+      pos = SGGeodesy::direct(pos, course + 180.0, 3.0 * SG_NM_TO_METER);
+      w = new BasicWaypt(pos, ss.str(), NULL);
+      wpts.insert(wpts.begin(), w);
+    }
+  }
+    
+  p = aRunway->pointOnCenterline(-8.0 * SG_NM_TO_METER);
+  ss.str("");
+  ss << aRunway->ident() << "-8";
+  w = new BasicWaypt(p, ss.str(), NULL);
+  w->setAltitude(thresholdElevFt + approachHeightFt, RESTRICT_AT);
+  wpts.push_back(w);
+  
+  p = aRunway->pointOnCenterline(-glideslopeDistanceM);    
+  ss.str("");
+  ss << aRunway->ident() << "-GS";
+  w = new BasicWaypt(p, ss.str(), NULL);
+  w->setAltitude(thresholdElevFt + approachHeightFt, RESTRICT_AT);
+  wpts.push_back(w);
+    
+  BOOST_FOREACH(Waypt* w, wpts) {
+    w->setFlag(WPT_APPROACH);
+    w->setFlag(WPT_GENERATED);
+  }
+  
+  return Approach::createTempApproach("DEFAULT", aRunway, wpts);
+}
+
 void FGRouteMgr::setApproach(const char* aIdent)
 {
   FGAirport* apt = _plan->destinationAirport();
+  if (!strcmp(aIdent, "DEFAULT")) {
+    double enrouteCourse = -1.0;
+    if (_plan->departureAirport()) {
+      enrouteCourse = SGGeodesy::courseDeg(_plan->departureAirport()->geod(), apt->geod());
+    }
+    
+    _plan->setApproach(createDefaultApproach(_plan->destinationRunway(), enrouteCourse));
+    return;
+  }
+  
   if (!apt || (aIdent == NULL)) {
     _plan->setApproach(NULL);
   } else {