#include "route_mgr.hxx"
+#include <boost/algorithm/string/case_conv.hpp>
+
#include <simgear/misc/strutils.hxx>
#include <simgear/structure/exception.hxx>
FGRouteMgr::FGRouteMgr() :
_route( new SGRoute ),
- _autoSequence(true),
- _driveAutopilot(true),
input(fgGetNode( RM "input", true )),
- mirror(fgGetNode( RM "route", true )),
- altitude_set( false )
+ mirror(fgGetNode( RM "route", true ))
{
listener = new InputListener(this);
input->setStringValue("");
lat = fgGetNode( "/position/latitude-deg", true );
alt = fgGetNode( "/position/altitude-ft", true );
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
-
-// autopilot drive properties
- _apTargetAltitudeFt = fgGetNode( "/autopilot/settings/target-altitude-ft", true );
- _apAltitudeLock = fgGetNode( "/autopilot/locks/altitude", true );
- _apTrueHeading = fgGetNode( "/autopilot/settings/true-heading-deg", true );
- rm->tie("drive-autopilot", SGRawValuePointer<bool>(&_driveAutopilot));
-
+
departure = fgGetNode(RM "departure", true);
+ departure->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
+ departure->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDepartureName, NULL));
+
// init departure information from current location
SGGeod pos = SGGeod::fromDegFt(lon->getDoubleValue(), lat->getDoubleValue(), alt->getDoubleValue());
- FGAirport* apt = FGAirport::findClosest(pos, 10.0);
- if (apt) {
- departure->setStringValue("airport", apt->ident().c_str());
- FGRunway* active = apt->getActiveRunwayForUsage();
+ _departure = FGAirport::findClosest(pos, 20.0);
+ if (_departure) {
+ FGRunway* active = _departure->getActiveRunwayForUsage();
departure->setStringValue("runway", active->ident().c_str());
} else {
- departure->setStringValue("airport", "");
departure->setStringValue("runway", "");
}
destination = fgGetNode(RM "destination", true);
destination->getChild("airport", 0, true);
+
+ destination->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
+ destination->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDestinationName, NULL));
+
destination->getChild("runway", 0, true);
destination->getChild("eta", 0, true);
destination->getChild("touchdown-time", 0, true);
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);
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);
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;
-
- if (!_driveAutopilot) {
- return;
- }
-
- _apTargetAltitudeFt->setDoubleValue(wp.get_target().getElevationFt());
-
- if ( !near_ground() ) {
- _apAltitudeLock->setStringValue( "altitude-hold" );
- }
-}
-
bool FGRouteMgr::isRouteActive() const
{
return active->getBoolValue();
}
// basic course/distance information
- double inboundCourse, dummy, wp_course, wp_distance;
+ double wp_course, wp_distance;
SGWayPoint wp = _route->get_current();
-
- wp.CourseAndDistance(_route->get_waypoint(_route->current_index() - 1),
- &inboundCourse, &dummy);
-
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();
- }
- }
-
- if (_driveAutopilot) {
- _apTrueHeading->setDoubleValue(wp_course);
- }
-
// update wp0 / wp1 / wp-last for legacy users
wp0->setDoubleValue("dist", wp_distance * SG_METER_TO_NM);
wp_course -= magvar->getDoubleValue(); // expose magnetic bearing
}
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;
}
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 );
if ( pos != string::npos ) {
double lon = atof( target.substr(0, pos).c_str());
double lat = atof( target.c_str() + pos + 1);
- return new SGWayPoint( lon, lat, alt, SGWayPoint::WGS84, target );
+ char buf[32];
+ char ew = (lon < 0.0) ? 'W' : 'E';
+ char ns = (lat < 0.0) ? 'S' : 'N';
+ snprintf(buf, 32, "%c%03d%c%03d", ew, (int) fabs(lon), ns, (int)fabs(lat));
+ return new SGWayPoint( lon, lat, alt, SGWayPoint::WGS84, buf);
}
SGGeod basePosition;
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) {
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);
}
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
bool FGRouteMgr::activate()
{
- const FGAirport* depApt = fgFindAirportID(departure->getStringValue("airport"));
- if (!depApt) {
- SG_LOG(SG_AUTOPILOT, SG_ALERT,
- "unable to activate route: departure airport is invalid:"
- << departure->getStringValue("airport") );
- return false;
- }
-
- string runwayId(departure->getStringValue("runway"));
- FGRunway* runway = NULL;
- if (depApt->hasRunwayWithIdent(runwayId)) {
- runway = depApt->getRunwayByIdent(runwayId);
- } else {
- SG_LOG(SG_AUTOPILOT, SG_INFO,
- "route-manager, departure runway not found:" << runwayId);
- runway = depApt->getActiveRunwayForUsage();
+ if (_departure) {
+ string runwayId(departure->getStringValue("runway"));
+ FGRunway* runway = NULL;
+ if (_departure->hasRunwayWithIdent(runwayId)) {
+ runway = _departure->getRunwayByIdent(runwayId);
+ } else {
+ SG_LOG(SG_AUTOPILOT, SG_INFO,
+ "route-manager, departure runway not found:" << runwayId);
+ runway = _departure->getActiveRunwayForUsage();
+ }
+
+ SGWayPoint swp(runway->threshold(),
+ _departure->ident() + "-" + runway->ident(), runway->name());
+ add_waypoint(swp, 0);
}
- SGWayPoint swp(runway->threshold(),
- depApt->ident() + "-" + runway->ident(), runway->name());
- add_waypoint(swp, 0);
-
- const FGAirport* destApt = fgFindAirportID(destination->getStringValue("airport"));
- if (!destApt) {
- SG_LOG(SG_AUTOPILOT, SG_ALERT,
- "unable to activate route: destination airport is invalid:"
- << destination->getStringValue("airport") );
- return false;
+ if (_destination) {
+ string runwayId = (destination->getStringValue("runway"));
+ if (_destination->hasRunwayWithIdent(runwayId)) {
+ FGRunway* runway = _destination->getRunwayByIdent(runwayId);
+ SGWayPoint swp(runway->end(),
+ _destination->ident() + "-" + runway->ident(), runway->name());
+ add_waypoint(swp);
+ } else {
+ // quite likely, since destination runway may not be known until enroute
+ // probably want a listener on the 'destination' node to allow an enroute
+ // update
+ add_waypoint(SGWayPoint(_destination->geod(), _destination->ident(), _destination->name()));
+ }
}
- runwayId = (destination->getStringValue("runway"));
- if (destApt->hasRunwayWithIdent(runwayId)) {
- FGRunway* runway = depApt->getRunwayByIdent(runwayId);
- SGWayPoint swp(runway->end(),
- destApt->ident() + "-" + runway->ident(), runway->name());
- add_waypoint(swp);
- } else {
- // quite likely, since destination runway may not be known until enroute
- // probably want a listener on the 'destination' node to allow an enroute
- // update
- add_waypoint(SGWayPoint(destApt->geod(), destApt->ident(), destApt->name()));
- }
-
_route->set_current(0);
double routeDistanceNm = _route->total_distance() * SG_METER_TO_NM;
}
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;
}
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)
wp1->getChild("id")->setStringValue("");
}
- currentWp->setIntValue(_route->current_index());
- updateTargetAltitude();
SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _route->current_index());
}
}
string depIdent = dep->getStringValue("airport");
- const FGAirport* depApt = fgFindAirportID(depIdent);
- if (!depApt) {
- throw sg_io_exception("bad route file, unknown airport:" + depIdent);
- }
-
- departure->setStringValue("runway", dep->getStringValue("runway"));
-
+ _departure = (FGAirport*) fgFindAirportID(depIdent);
+
+
// destination
SGPropertyNode* dst = routeData->getChild("destination");
if (!dst) {
throw sg_io_exception("malformed route file, no destination node");
}
- destination->setStringValue("airport", dst->getStringValue("airport"));
- destination->setStringValue("runay", dst->getStringValue("runway"));
+ _destination = (FGAirport*) fgFindAirportID(dst->getStringValue("airport"));
+ destination->setStringValue("runway", dst->getStringValue("runway"));
// alternate
SGPropertyNode* alt = routeData->getChild("alternate");
// route nodes
_route->clear();
SGPropertyNode_ptr _route = routeData->getChild("route", 0);
- SGGeod lastPos(depApt->geod());
+ SGGeod lastPos = (_departure ? _departure->geod() : SGGeod());
for (int i=0; i<_route->nChildren(); ++i) {
SGPropertyNode_ptr wp = _route->getChild("wp", i);
}
SGPropertyNode_ptr altProp = aWP->getChild("altitude-ft");
- double alt = -9999.0;
+ double altM = cruise->getDoubleValue("altitude-ft") * SG_FEET_TO_METER;
if (altProp) {
- alt = altProp->getDoubleValue();
+ altM = altProp->getDoubleValue() * SG_FEET_TO_METER;
}
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,
+ aWP->getDoubleValue("latitude-deg"), altM,
SGWayPoint::WGS84, ident, aWP->getStringValue("name"));
add_waypoint(swp);
} else if (aWP->hasChild("navid")) {
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 swp(pos.getLongitudeDeg(), pos.getLatitudeDeg(), altM,
SGWayPoint::WGS84, ident, "");
add_waypoint(swp);
} else {
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 swp(p->longitude(), p->latitude(), altM,
SGWayPoint::WGS84, p->ident(), p->name());
add_waypoint(swp);
}
}
+
+const char* FGRouteMgr::getDepartureICAO() const
+{
+ if (!_departure) {
+ return "";
+ }
+
+ return _departure->ident().c_str();
+}
+
+const char* FGRouteMgr::getDepartureName() const
+{
+ if (!_departure) {
+ return "";
+ }
+
+ return _departure->name().c_str();
+}
+
+void FGRouteMgr::setDepartureICAO(const char* aIdent)
+{
+ _departure = FGAirport::findByIdent(aIdent);
+}
+
+const char* FGRouteMgr::getDestinationICAO() const
+{
+ if (!_destination) {
+ return "";
+ }
+
+ return _destination->ident().c_str();
+}
+
+const char* FGRouteMgr::getDestinationName() const
+{
+ if (!_destination) {
+ return "";
+ }
+
+ return _destination->name().c_str();
+}
+
+void FGRouteMgr::setDestinationICAO(const char* aIdent)
+{
+ _destination = FGAirport::findByIdent(aIdent);
+}
+