airborne = fgGetNode(RM "airborne", true);
airborne->setBoolValue(false);
- currentWp = fgGetNode(RM "current-wp", true);
- currentWp->setIntValue(_route->current_index());
+ _edited = fgGetNode(RM "signals/edited", true);
+ _finished = fgGetNode(RM "signals/finished", true);
+
+ rm->tie("current-wp", SGRawValueMethods<FGRouteMgr, int>
+ (*this, &FGRouteMgr::currentWaypoint, &FGRouteMgr::jumpToIndex));
// temporary distance / eta calculations, for backward-compatability
wp0 = fgGetNode(RM "wp", 0, true);
}
void FGRouteMgr::add_waypoint( const SGWayPoint& wp, int n ) {
- _route->add_waypoint( wp, n );
- update_mirror();
+ _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);
+ }
- update_mirror();
- return wp;
+ SGWayPoint wp = _route->get_waypoint(n);
+ _route->delete_waypoint(n);
+
+ update_mirror();
+ _edited->fireValueChanged();
+ checkFinished();
+
+ return wp;
}
add_waypoint( *wp, n );
delete wp;
-
- if ( !near_ground() ) {
- fgSetString( "/autopilot/locks/heading", "true-heading-hold" );
- }
}
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
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;
}
currentWaypointChanged();
}
+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)
{
if (!active->getBoolValue()) {
wp1->getChild("id")->setStringValue("");
}
- currentWp->setIntValue(_route->current_index());
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _route->current_index());
}
}
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();
}
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"));
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);
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);
SGPropertyNode_ptr active;
SGPropertyNode_ptr airborne;
- SGPropertyNode_ptr currentWp;
SGPropertyNode_ptr wp0;
SGPropertyNode_ptr wp1;
SGPropertyNode_ptr _pathNode;
+ /**
+ * Signal property to notify people that the route was edited
+ */
+ SGPropertyNode_ptr _edited;
+
+ /**
+ * Signal property to notify when the last waypoint is reached
+ */
+ SGPropertyNode_ptr _finished;
+
void setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDistance);
class InputListener : public SGPropertyChangeListener {
void update_mirror();
- bool near_ground();
void currentWaypointChanged();
* Parse a route/wp node (from a saved, property-lsit formatted route)
*/
void parseRouteWaypoint(SGPropertyNode* aWP);
+
+ /**
+ * Check if we've reached the final waypoint.
+ * Returns true if we have.
+ */
+ bool checkFinished();
public:
FGRouteMgr();
_gps->routeActivated();
} else if (prop == _gps->_ref_navaid_id_node) {
_gps->referenceNavaidSet(prop->getStringValue(""));
+ } else if (prop == _gps->_routeEditedSignal) {
+ _gps->routeEdited();
+ } else if (prop == _gps->_routeFinishedSignal) {
+ _gps->routeFinished();
}
_guard = false;
// should these move to the route manager?
_routeDistanceNm = node->getChild("route-distance-nm", 0, true);
_routeETE = node->getChild("ETE", 0, true);
-
- // disable auto-sequencing in the route manager; we'll deal with it
- // ourselves using turn anticipation
- SGPropertyNode_ptr autoSeq = fgGetNode("/autopilot/route-manager/auto-sequence", true);
- autoSeq->setBoolValue(false);
-
+ _routeEditedSignal = fgGetNode("/autopilot/route-manager/signals/edited", true);
+ _routeFinishedSignal = fgGetNode("/autopilot/route-manager/signals/finished", true);
+
// add listener to various things
_listener = new GPSListener(this);
_route_current_wp_node = fgGetNode("/autopilot/route-manager/current-wp", true);
_route_active_node = fgGetNode("/autopilot/route-manager/active", true);
_route_active_node->addChangeListener(_listener);
_ref_navaid_id_node->addChangeListener(_listener);
-
+ _routeEditedSignal->addChangeListener(_listener);
+ _routeFinishedSignal->addChangeListener(_listener);
+
// navradio slaving properties
node->tie("cdi-deflection", SGRawValueMethods<GPS,double>
(*this, &GPS::getCDIDeflection));
SGPropertyNode* toFlag = node->getChild("to-flag", 0, true);
toFlag->alias(wp1_node->getChild("to-flag"));
+
+ SGPropertyNode* fromFlag = node->getChild("from-flag", 0, true);
+ fromFlag->alias(wp1_node->getChild("from-flag"));
+
// autopilot drive properties
_apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
_apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
wp1Changed();
}
+void GPS::routeEdited()
+{
+ if (_mode != "leg") {
+ return;
+ }
+
+ SG_LOG(SG_INSTR, SG_INFO, "GPS route edited while in LEG mode, updating waypoints");
+ routeManagerSequenced();
+}
+
+void GPS::routeFinished()
+{
+ if (_mode != "leg") {
+ return;
+ }
+
+ SG_LOG(SG_INSTR, SG_INFO, "GPS route finished, reverting to OBS");
+ _mode = "obs";
+ _wp0_position = _indicated_pos;
+ wp1Changed();
+}
+
void GPS::updateTurn()
{
bool printProgress = false;
double altFt = _wp1_position.getElevationFt();
if (altFt < -9990.0) {
_apTargetAltitudeFt->setDoubleValue(0.0);
- _apAltitudeLock->setBoolValue(false);
} else {
_apTargetAltitudeFt->setDoubleValue(altFt);
- _apAltitudeLock->setBoolValue(true);
}
}
void routeActivated();
void routeManagerSequenced();
+ void routeEdited();
+ void routeFinished();
void updateTurn();
void updateOverflight();
SGPropertyNode_ptr _route_current_wp_node;
SGPropertyNode_ptr _routeDistanceNm;
SGPropertyNode_ptr _routeETE;
-
+ SGPropertyNode_ptr _routeEditedSignal;
+ SGPropertyNode_ptr _routeFinishedSignal;
+
double _selectedCourse;
bool _last_valid;
gps_has_gs_node = fgGetNode("/instrumentation/gps/has-gs", true);
gps_course_node = fgGetNode("/instrumentation/gps/selected-course-deg", true);
gps_xtrack_error_nm_node = fgGetNode("/instrumentation/gps/wp/wp[1]/course-error-nm", true);
-
+ _magvarNode = fgGetNode("/environment/magnetic-variation-deg", true);
+
std::ostringstream temp;
temp << _name << "nav-ident" << _num;
nav_fx_name = temp.str();
_cdiCrossTrackErrorM = gps_xtrack_error_nm_node->getDoubleValue() * SG_NM_TO_METER;
_gsNeedleDeflection = 0.0; // FIXME, supply this
- //sel_radial_node->setDoubleValue(gps_course_node->getDoubleValue());
+ double trtrue = gps_course_node->getDoubleValue() + _magvarNode->getDoubleValue();
+ SG_NORMALIZE_RANGE(trtrue, 0.0, 360.0);
+ target_radial_true_node->setDoubleValue( trtrue );
}
void FGNavRadio::updateCDI(double dt)
SGPropertyNode_ptr gps_has_gs_node;
SGPropertyNode_ptr gps_course_node;
SGPropertyNode_ptr gps_xtrack_error_nm_node;
-
+ SGPropertyNode_ptr _magvarNode;
+
// internal (private) values
int play_count;