]> git.mxchange.org Git - flightgear.git/blobdiff - src/Autopilot/route_mgr.cxx
Fix route-manager / GPS sequencing interaction; tied properties need help to fire...
[flightgear.git] / src / Autopilot / route_mgr.cxx
index a80c330bccd4a3267358a1ebe15ee14e7e5aaf4d..0ef72afb53d23bdeebbb332e0e85440bd2f95e13 100644 (file)
 #  include <config.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <time.h>
+#endif
+
 #include <simgear/compiler.h>
 
 #include "route_mgr.hxx"
 
+#include <boost/algorithm/string/case_conv.hpp>
+
 #include <simgear/misc/strutils.hxx>
 #include <simgear/structure/exception.hxx>
 
@@ -60,17 +66,10 @@ static double get_ground_speed() {
 
 FGRouteMgr::FGRouteMgr() :
     _route( new SGRoute ),
-    _autoSequence(true),
-    lon( NULL ),
-    lat( NULL ),
-    alt( NULL ),
-    target_altitude_ft( NULL ),
-    altitude_lock( NULL ),
     input(fgGetNode( RM "input", true )),
-    listener(new InputListener(this)),
-    mirror(fgGetNode( RM "route", true )),
-    altitude_set( false )
+    mirror(fgGetNode( RM "route", true ))
 {
+    listener = new InputListener(this);
     input->setStringValue("");
     input->addChangeListener(listener);
 }
@@ -91,14 +90,11 @@ void FGRouteMgr::init() {
   lat = fgGetNode( "/position/latitude-deg", true );
   alt = fgGetNode( "/position/altitude-ft", true );
   magvar = fgGetNode("/environment/magnetic-variation-deg", true);
-  
-  target_altitude_ft = fgGetNode( "/autopilot/settings/target-altitude-ft", true );
-  altitude_lock = fgGetNode( "/autopilot/locks/altitude", true );
-
+     
   departure = fgGetNode(RM "departure", true);
 // init departure information from current location
   SGGeod pos = SGGeod::fromDegFt(lon->getDoubleValue(), lat->getDoubleValue(), alt->getDoubleValue());
-  FGAirport* apt = FGAirport::findClosest(pos, 10.0);
+  FGAirport* apt = FGAirport::findClosest(pos, 20.0);
   if (apt) {
     departure->setStringValue("airport", apt->ident().c_str());
     FGRunway* active = apt->getActiveRunwayForUsage();
@@ -122,10 +118,12 @@ void FGRouteMgr::init() {
   alternate->getChild("runway", 0, true);
   
   cruise = fgGetNode(RM "cruise", true);
-  cruise->getChild("altitude", 0, true);
+  cruise->getChild("altitude-ft", 0, true);
+  cruise->setDoubleValue("altitude-ft", 10000.0);
   cruise->getChild("flight-level", 0, true);
-  cruise->getChild("speed", 0, true);
-      
+  cruise->getChild("speed-kts", 0, true);
+  cruise->setDoubleValue("speed-kts", 160.0);
+  
   totalDistance = fgGetNode(RM "total-distance", true);
   totalDistance->setDoubleValue(0.0);
   
@@ -140,11 +138,13 @@ void FGRouteMgr::init() {
   
   airborne = fgGetNode(RM "airborne", true);
   airborne->setBoolValue(false);
+    
+  _edited = fgGetNode(RM "signals/edited", true);
+  _finished = fgGetNode(RM "signals/finished", true);
   
-  rm->tie("auto-sequence", SGRawValuePointer<bool>(&_autoSequence));
-  
-  currentWp = fgGetNode(RM "current-wp", true);
-  currentWp->setIntValue(_route->current_index());
+  _currentWpt = fgGetNode(RM "current-wp", true);
+  _currentWpt->tie(SGRawValueMethods<FGRouteMgr, int>
+    (*this, &FGRouteMgr::currentWaypoint, &FGRouteMgr::jumpToIndex));
       
   // temporary distance / eta calculations, for backward-compatability
   wp0 = fgGetNode(RM "wp", 0, true);
@@ -186,41 +186,26 @@ void FGRouteMgr::postinit() {
 void FGRouteMgr::bind() { }
 void FGRouteMgr::unbind() { }
 
-void FGRouteMgr::updateTargetAltitude() {
-    if (_route->current_index() == _route->size()) {
-        altitude_set = false;
-        return;
-    }
-    
-    SGWayPoint wp = _route->get_current();
-    if (wp.get_target().getElevationM() < -9990.0) {
-        altitude_set = false;
-        return;
-    }
-    
-    altitude_set = true;
-    target_altitude_ft->setDoubleValue(wp.get_target().getElevationFt());
-            
-    if ( !near_ground() ) {
-        // James Turner [zakalawe]: there's no explanation for this logic,
-        // it feels like the autopilot should pull the target altitude out of
-        // wp0 instead of us pushing it through here. Hmmm.
-        altitude_lock->setStringValue( "altitude-hold" );
-    }
-}
-
 bool FGRouteMgr::isRouteActive() const
 {
   return active->getBoolValue();
 }
 
 void FGRouteMgr::update( double dt ) {
+    if (dt <= 0.0) {
+      // paused, nothing to do here
+      return;
+    }
+  
     if (!active->getBoolValue()) {
       return;
     }
     
     double groundSpeed = get_ground_speed();
-    if (!airborne->getBoolValue()) {
+    if (airborne->getBoolValue()) {
+      time_t now = time(NULL);
+      elapsedFlightTime->setDoubleValue(difftime(now, _takeoffTime));
+    } else { // not airborne
       if (weightOnWheels->getBoolValue() || (groundSpeed < 40)) {
         return;
       }
@@ -230,9 +215,7 @@ void FGRouteMgr::update( double dt ) {
       departure->setIntValue("takeoff-time", _takeoffTime);
     }
     
-    time_t now = time(NULL);
-    elapsedFlightTime->setDoubleValue(difftime(now, _takeoffTime));
-    
+  // basic course/distance information
     double inboundCourse, dummy, wp_course, wp_distance;
     SGWayPoint wp = _route->get_current();
   
@@ -242,15 +225,7 @@ void FGRouteMgr::update( double dt ) {
     wp.CourseAndDistance( lon->getDoubleValue(), lat->getDoubleValue(),
                           alt->getDoubleValue(), &wp_course, &wp_distance );
 
-    if (_autoSequence && (wp_distance < 2000.0)) {
-      double courseDeviation = inboundCourse - wp_course;
-      SG_NORMALIZE_RANGE(courseDeviation, -180.0, 180.0);
-      if (fabs(courseDeviation) < 90.0) {
-        SG_LOG( SG_AUTOPILOT, SG_INFO, "route manager doing sequencing");
-        sequence();
-      }
-    }
-
+  // update wp0 / wp1 / wp-last for legacy users
     wp0->setDoubleValue("dist", wp_distance * SG_METER_TO_NM);
     wp_course -= magvar->getDoubleValue(); // expose magnetic bearing
     wp0->setDoubleValue("bearing-deg", wp_course);
@@ -283,6 +258,12 @@ void FGRouteMgr::update( double dt ) {
 
 
 void FGRouteMgr::setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDistance) {
+    double speed = get_ground_speed();
+    if (speed < 1.0) {
+      aProp->setStringValue("--:--");
+      return;
+    }
+  
     char eta_str[64];
     double eta = aDistance * SG_METER_TO_NM / get_ground_speed();
     if ( eta >= 100.0 ) { 
@@ -300,27 +281,38 @@ void FGRouteMgr::setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDi
 }
 
 void FGRouteMgr::add_waypoint( const SGWayPoint& wp, int n ) {
-    _route->add_waypoint( wp, n );
-    update_mirror();
-    if ((n==0) || (_route->size() == 1)) {
-        updateTargetAltitude();
-    }
+  _route->add_waypoint( wp, n );
+    
+  if (_route->current_index() > n) {
+    _route->set_current(_route->current_index() + 1);
+  }
+  
+  update_mirror();
+  _edited->fireValueChanged();
 }
 
 
 SGWayPoint FGRouteMgr::pop_waypoint( int n ) {
-    SGWayPoint wp;
-
-    if ( _route->size() > 0 ) {
-        if ( n < 0 )
-            n = _route->size() - 1;
-        wp = _route->get_waypoint(n);
-        _route->delete_waypoint(n);
-    }
+  if ( _route->size() <= 0 ) {
+    return SGWayPoint();
+  }
+  
+  if ( n < 0 ) {
+    n = _route->size() - 1;
+  }
+  
+  if (_route->current_index() > n) {
+    _route->set_current(_route->current_index() - 1);
+  }
 
-    updateTargetAltitude();
-    update_mirror();
-    return wp;
+  SGWayPoint wp = _route->get_waypoint(n);
+  _route->delete_waypoint(n);
+    
+  update_mirror();
+  _edited->fireValueChanged();
+  checkFinished();
+  
+  return wp;
 }
 
 
@@ -337,23 +329,15 @@ void FGRouteMgr::new_waypoint( const string& target, int n ) {
     
     add_waypoint( *wp, n );
     delete wp;
-
-    if ( !near_ground() ) {
-        fgSetString( "/autopilot/locks/heading", "true-heading-hold" );
-    }
 }
 
 
 SGWayPoint* FGRouteMgr::make_waypoint(const string& tgt ) {
-    string target = tgt;
+    string target(boost::to_upper_copy(tgt));
     
-    // make upper case
-    for (unsigned int i = 0; i < target.size(); i++) {
-      target[i] = toupper(target[i]);
-    }
-
     // extract altitude
-    double alt = -9999.0;
+    double alt = cruise->getDoubleValue("altitude-ft") * SG_FEET_TO_METER;
+    
     size_t pos = target.find( '@' );
     if ( pos != string::npos ) {
         alt = atof( target.c_str() + pos + 1 );
@@ -390,9 +374,10 @@ SGWayPoint* FGRouteMgr::make_waypoint(const string& tgt ) {
       return NULL;
     }
     
+    SGGeod geod = SGGeod::fromGeodM(p->geod(), alt);
     if (pieces.size() == 1) {
       // simple case
-      return new SGWayPoint(p->geod(), target, p->name());
+      return new SGWayPoint(geod, target, p->name());
     }
         
     if (pieces.size() == 3) {
@@ -402,13 +387,10 @@ SGWayPoint* FGRouteMgr::make_waypoint(const string& tgt ) {
         az2;
       radial += magvar->getDoubleValue(); // convert to true bearing
       SGGeod offsetPos;
-      SGGeodesy::direct(p->geod(), radial, distanceNm * SG_NM_TO_METER, offsetPos, az2);
+      SGGeodesy::direct(geod, radial, distanceNm * SG_NM_TO_METER, offsetPos, az2);
+      offsetPos.setElevationM(alt);
       
       SG_LOG(SG_AUTOPILOT, SG_INFO, "final offset radial is " << radial);
-      
-      if (alt > -9990) {
-        offsetPos.setElevationM(alt);
-      } // otherwise use the elevation of navid
       return new SGWayPoint(offsetPos, p->ident() + pieces[2], target);
     }
     
@@ -453,20 +435,6 @@ void FGRouteMgr::update_mirror() {
     mirror->setIntValue("num", _route->size());
 }
 
-
-bool FGRouteMgr::near_ground() {
-    SGPropertyNode *gear = fgGetNode( "/gear/gear/wow", false );
-    if ( !gear || gear->getType() == simgear::props::NONE )
-        return fgGetBool( "/sim/presets/onground", true );
-
-    if ( fgGetDouble("/position/altitude-agl-ft", 300.0)
-            < fgGetDouble("/autopilot/route-manager/min-lock-altitude-agl-ft") )
-        return true;
-
-    return gear->getBoolValue();
-}
-
-
 // command interface /autopilot/route-manager/input:
 //
 //   @CLEAR             ... clear route
@@ -541,7 +509,7 @@ bool FGRouteMgr::activate()
 
   runwayId = (destination->getStringValue("runway"));
   if (destApt->hasRunwayWithIdent(runwayId)) {
-    FGRunway* runway = depApt->getRunwayByIdent(runwayId);
+    FGRunway* runway = destApt->getRunwayByIdent(runwayId);
     SGWayPoint swp(runway->end(), 
       destApt->ident() + "-" + runway->ident(), runway->name());
     add_waypoint(swp);
@@ -552,7 +520,7 @@ bool FGRouteMgr::activate()
     add_waypoint(SGWayPoint(destApt->geod(), destApt->ident(), destApt->name()));
   }
   
-  _route->set_current(0);
+  _route->set_current(1);
   
   double routeDistanceNm = _route->total_distance() * SG_METER_TO_NM;
   totalDistance->setDoubleValue(routeDistanceNm);
@@ -564,7 +532,6 @@ bool FGRouteMgr::activate()
   }
   
   active->setBoolValue(true);
-  sequence(); // sequence will sync up wp0, wp1 and current-wp
   SG_LOG(SG_AUTOPILOT, SG_INFO, "route-manager, activate route ok");
   return true;
 }
@@ -577,15 +544,26 @@ void FGRouteMgr::sequence()
     return;
   }
   
-  if (_route->current_index() == _route->size()) {
-    SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
-    // what now?
-    active->setBoolValue(false);
+  if (checkFinished()) {
     return;
   }
   
   _route->increment_current();
   currentWaypointChanged();
+  _currentWpt->fireValueChanged();
+}
+
+bool FGRouteMgr::checkFinished()
+{
+  int lastWayptIndex = _route->size() - 1;
+  if (_route->current_index() < lastWayptIndex) {
+    return false;
+  }
+  
+  SG_LOG(SG_AUTOPILOT, SG_INFO, "reached end of active route");
+  _finished->fireValueChanged();
+  active->setBoolValue(false);
+  return true;
 }
 
 void FGRouteMgr::jumpToIndex(int index)
@@ -621,7 +599,6 @@ void FGRouteMgr::currentWaypointChanged()
     wp1->getChild("id")->setStringValue("");
   }
   
-  currentWp->setIntValue(_route->current_index());
   SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _route->current_index());
 }
 
@@ -739,7 +716,7 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
   }
 
   SGPropertyNode_ptr altProp = aWP->getChild("altitude-ft");
-  double alt = -9999.0;
+  double alt = cruise->getDoubleValue("altitude-ft") * SG_FEET_TO_METER;
   if (altProp) {
     alt = altProp->getDoubleValue();
   }
@@ -747,10 +724,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
   string ident(aWP->getStringValue("ident"));
   if (aWP->hasChild("longitude-deg")) {
     // explicit longitude/latitude
-    if (alt < -9990.0) {
-      alt = 0.0; // don't export wyapoints with invalid altitude
-    }
-    
     SGWayPoint swp(aWP->getDoubleValue("longitude-deg"),
       aWP->getDoubleValue("latitude-deg"), alt, 
       SGWayPoint::WGS84, ident, aWP->getStringValue("name"));
@@ -773,10 +746,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
       SGGeodesy::direct(p->geod(), radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
     }
     
-    if (alt < -9990.0) {
-      alt = p->elevation();
-    }
-    
     SGWayPoint swp(pos.getLongitudeDeg(), pos.getLatitudeDeg(), alt, 
       SGWayPoint::WGS84, ident, "");
     add_waypoint(swp);
@@ -787,10 +756,6 @@ void FGRouteMgr::parseRouteWaypoint(SGPropertyNode* aWP)
       throw sg_io_exception("bad route file, unknown waypoint:" + ident);
     }
     
-    if (alt < -9990.0) {
-      alt = p->elevation();
-    }
-    
     SGWayPoint swp(p->longitude(), p->latitude(), alt, 
       SGWayPoint::WGS84, p->ident(), p->name());
     add_waypoint(swp);