_reciprocal = other;
}
-std::vector<flightgear::SID*> FGRunway::getSIDs()
+std::vector<flightgear::SID*> FGRunway::getSIDs() const
{
std::vector<flightgear::SID*> result;
for (unsigned int i=0; i<_airport->numSIDs(); ++i) {
return result;
}
-std::vector<flightgear::STAR*> FGRunway::getSTARs()
+std::vector<flightgear::STAR*> FGRunway::getSTARs() const
{
std::vector<flightgear::STAR*> result;
for (unsigned int i=0; i<_airport->numSTARs(); ++i) {
return result;
}
+std::vector<flightgear::Approach*> FGRunway::getApproaches() const
+{
+ std::vector<flightgear::Approach*> result;
+ for (unsigned int i=0; i<_airport->numApproaches(); ++i) {
+ flightgear::Approach* s = _airport->getApproachByIndex(i);
+ if (s->runway() == this) {
+ result.push_back(s);
+ }
+ } // of approaches at the airport iteration
+
+ return result;
+}
+
namespace flightgear {
class SID;
class STAR;
+ class Approach;
}
class FGRunway : public FGRunwayBase
/**
* Get SIDs (DPs) associated with this runway
*/
- std::vector<flightgear::SID*> getSIDs();
+ std::vector<flightgear::SID*> getSIDs() const;
/**
* Get STARs associared with this runway
*/
- std::vector<flightgear::STAR*> getSTARs();
+ std::vector<flightgear::STAR*> getSTARs() const;
+
+
+ std::vector<flightgear::Approach*> getApproaches() const;
};
}
SG_LOG(SG_GENERAL, SG_INFO, ident() << ": loading procedures from " << path.str());
- Route::loadAirportProcedures(path, const_cast<FGAirport*>(this));
+ RouteBase::loadAirportProcedures(path, const_cast<FGAirport*>(this));
}
void FGAirport::loadSceneryDefinitions() const
_tower_location = SGGeod::fromDegM(lon, lat, fieldElevationM + elevM);
}
-bool FGAirport::buildApproach(Waypt* aEnroute, STAR* aSTAR, FGRunway* aRwy, WayptVec& aRoute)
-{
- loadProcedures();
-
- if ((aRwy && (aRwy->airport() != this))) {
- throw sg_exception("invalid parameters", "FGAirport::buildApproach");
- }
-
- if (aSTAR) {
- bool ok = aSTAR->route(aRwy, aEnroute, aRoute);
- if (!ok) {
- SG_LOG(SG_GENERAL, SG_WARN, ident() << ": build approach, STAR " << aSTAR->ident()
- << " failed to route from transition " << aEnroute->ident());
- return false;
- }
- } else if (aEnroute) {
- // no a STAR specified, just use enroute point directly
- aRoute.push_back(aEnroute);
- }
-
- if (!aRwy) {
- // no runway selected yet, but we loaded the STAR, so that's fine, we're done
- return true;
- }
-
-// build the approach (possibly including transition), and including the missed segment
- vector<Approach*> aps;
- for (unsigned int j=0; j<mApproaches.size();++j) {
- if (mApproaches[j]->runway() == aRwy) {
- aps.push_back(mApproaches[j]);
- }
- } // of approach filter by runway
-
- if (aps.empty()) {
- SG_LOG(SG_GENERAL, SG_INFO, ident() << "; no approaches defined for runway " << aRwy->ident());
- // could build a fallback approach here
- return false;
- }
-
- for (unsigned int k=0; k<aps.size(); ++k) {
- if (aps[k]->route(aRoute.back(), aRoute)) {
- return true;
- }
- } // of initial approach iteration
-
- SG_LOG(SG_GENERAL, SG_INFO, ident() << ": unable to find transition to runway "
- << aRwy->ident() << ", assume vectors");
-
- WayptRef v(new ATCVectors(NULL, this));
- aRoute.push_back(v);
- return aps.front()->routeFromVectors(aRoute);
-}
-
-pair<flightgear::SID*, WayptRef>
-FGAirport::selectSID(const SGGeod& aDest, FGRunway* aRwy)
-{
- loadProcedures();
-
- WayptRef enroute;
- flightgear::SID* sid = NULL;
- double d = 1e9;
-
- for (unsigned int i=0; i<mSIDs.size(); ++i) {
- if (aRwy && !mSIDs[i]->isForRunway(aRwy)) {
- continue;
- }
-
- WayptRef e = mSIDs[i]->findBestTransition(aDest);
- if (!e) {
- continue; // strange, but let's not worry about it
- }
-
- // assert(e->isFixedPosition());
- double ed = SGGeodesy::distanceM(aDest, e->position());
- if (ed < d) { // new best match
- enroute = e;
- d = ed;
- sid = mSIDs[i];
- }
- } // of SID iteration
-
- if (!mSIDs.empty() && !sid) {
- SG_LOG(SG_GENERAL, SG_INFO, ident() << "selectSID, no SID found (runway="
- << (aRwy ? aRwy->ident() : "no runway preference"));
- }
-
- return std::make_pair(sid, enroute);
-}
-
-pair<STAR*, WayptRef>
-FGAirport::selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy)
-{
- loadProcedures();
-
- WayptRef enroute;
- STAR* star = NULL;
- double d = 1e9;
-
- for (unsigned int i=0; i<mSTARs.size(); ++i) {
- if (!mSTARs[i]->isForRunway(aRwy)) {
- continue;
- }
-
- SG_LOG(SG_GENERAL, SG_INFO, "STAR " << mSTARs[i]->ident() << " is valid for runway");
- WayptRef e = mSTARs[i]->findBestTransition(aOrigin);
- if (!e) {
- continue; // strange, but let's not worry about it
- }
-
- // assert(e->isFixedPosition());
- double ed = SGGeodesy::distanceM(aOrigin, e->position());
- if (ed < d) { // new best match
- enroute = e;
- d = ed;
- star = mSTARs[i];
- }
- } // of STAR iteration
-
- return std::make_pair(star, enroute);
-}
-
-
void FGAirport::addSID(flightgear::SID* aSid)
{
mSIDs.push_back(aSid);
return mApproaches[aIndex];
}
+Approach* FGAirport::findApproachWithIdent(const std::string& aIdent) const
+{
+ loadProcedures();
+ for (unsigned int i=0; i<mApproaches.size(); ++i) {
+ if (mApproaches[i]->ident() == aIdent) {
+ return mApproaches[i];
+ }
+ }
+
+ return NULL;
+}
+
void FGAirport::setCommStations(CommStationList& comms)
{
mCommStations.swap(comms);
unsigned int numApproaches() const;
flightgear::Approach* getApproachByIndex(unsigned int aIndex) const;
-
+ flightgear::Approach* findApproachWithIdent(const std::string& aIdent) const;
+
/**
* Syntactic wrapper around FGPositioned::findClosest - find the closest
* match for filter, and return it cast to FGAirport. The default filter
*/
static char** searchNamesAndIdents(const std::string& aFilter);
- bool buildApproach(flightgear::Waypt* aEnroute, flightgear::STAR* aSTAR,
- FGRunway* aRwy, flightgear::WayptVec& aRoute);
-
- /**
- * Given a destiation point, select the best SID and transition waypt from
- * this airport. Returns (NULL,NULL) is no SIDs are defined, otherwise the
- * best SID/transition is that which is closest to the destination point.
- */
- std::pair<flightgear::SID*, flightgear::WayptRef> selectSID(const SGGeod& aDest, FGRunway* aRwy);
-
- /**
- * Select a STAR and enroute transition waypt, given an origin (departure) position.
- * returns (NULL, NULL) is no suitable STAR is exists
- */
- std::pair<flightgear::STAR*, flightgear::WayptRef> selectSTAR(const SGGeod& aOrigin, FGRunway* aRwy);
-
void setCommStations(flightgear::CommStationList& comms);
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
using namespace flightgear;
-class PropertyWatcher : public SGPropertyChangeListener
-{
-public:
- void watch(SGPropertyNode* p)
- {
- p->addChangeListener(this, false);
- }
-
- virtual void valueChanged(SGPropertyNode*)
- {
- fire();
- }
-protected:
- virtual void fire() = 0;
-};
-
-/**
- * Template adapter, created by convenience helper below
- */
-template <class T>
-class MethodPropertyWatcher : public PropertyWatcher
-{
-public:
- typedef void (T::*fire_method)();
-
- MethodPropertyWatcher(T* obj, fire_method m) :
- _object(obj),
- _method(m)
- { ; }
-
-protected:
- virtual void fire()
- { // dispatch to the object method we're helping
- (_object->*_method)();
- }
-
-private:
- T* _object;
- fire_method _method;
-};
-
-template <class T>
-PropertyWatcher* createWatcher(T* obj, void (T::*m)())
-{
- return new MethodPropertyWatcher<T>(obj, m);
-}
-
static bool commandLoadFlightPlan(const SGPropertyNode* arg)
{
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
{
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
int index = arg->getIntValue("index");
- if ((index < 0) || (index >= self->numWaypts())) {
+ if ((index < 0) || (index >= self->numLegs())) {
return false;
}
} else {
return false; // failed to build waypoint
}
-
+
+ FlightPlan::Leg* leg = self->flightPlan()->insertWayptAtIndex(wp, index);
if (alt >= 0) {
- wp->setAltitude(alt, flightgear::RESTRICT_AT);
+ leg->setAltitude(RESTRICT_AT, alt);
}
if (ias > 0) {
- wp->setSpeed(ias, flightgear::RESTRICT_AT);
+ leg->setSpeed(RESTRICT_AT, ias);
}
-
- self->insertWayptAtIndex(wp, index);
+
return true;
}
{
FGRouteMgr* self = (FGRouteMgr*) globals->get_subsystem("route-manager");
int index = arg->getIntValue("index");
- self->removeWayptAtIndex(index);
+ self->removeLegAtIndex(index);
return true;
}
/////////////////////////////////////////////////////////////////////////////
FGRouteMgr::FGRouteMgr() :
- _currentIndex(0),
+ _plan(NULL),
input(fgGetNode( RM "input", true )),
- mirror(fgGetNode( RM "route", true )),
- _departureWatcher(NULL),
- _arrivalWatcher(NULL)
+ mirror(fgGetNode( RM "route", true ))
{
listener = new InputListener(this);
input->setStringValue("");
{
input->removeChangeListener(listener);
delete listener;
- delete _departureWatcher;
- delete _arrivalWatcher;
}
void FGRouteMgr::init() {
SGPropertyNode_ptr rm(fgGetNode(RM));
- lon = fgGetNode( "/position/longitude-deg", true );
- lat = fgGetNode( "/position/latitude-deg", true );
- alt = fgGetNode( "/position/altitude-ft", true );
magvar = fgGetNode("/environment/magnetic-variation-deg", true);
departure = fgGetNode(RM "departure", true);
departure->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
&FGRouteMgr::getDepartureICAO, &FGRouteMgr::setDepartureICAO));
+ departure->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDepartureRunway,
+ &FGRouteMgr::setDepartureRunway));
+ departure->tie("sid", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getSID,
+ &FGRouteMgr::setSID));
+
departure->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
&FGRouteMgr::getDepartureName, NULL));
- departure->setStringValue("runway", "");
-
- delete _departureWatcher;
- _departureWatcher = createWatcher(this, &FGRouteMgr::departureChanged);
- _departureWatcher->watch(departure->getChild("runway"));
-
+ departure->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
+ &FGRouteMgr::getDestinationFieldElevation, NULL));
departure->getChild("etd", 0, true);
- _departureWatcher->watch(departure->getChild("sid", 0, true));
departure->getChild("takeoff-time", 0, true);
destination = fgGetNode(RM "destination", true);
destination->tie("airport", SGRawValueMethods<FGRouteMgr, const char*>(*this,
&FGRouteMgr::getDestinationICAO, &FGRouteMgr::setDestinationICAO));
+ destination->tie("runway", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getDestinationRunway,
+ &FGRouteMgr::setDestinationRunway));
+ destination->tie("star", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getSTAR,
+ &FGRouteMgr::setSTAR));
+ destination->tie("approach", SGRawValueMethods<FGRouteMgr, const char*>(*this,
+ &FGRouteMgr::getApproach,
+ &FGRouteMgr::setApproach));
+
destination->tie("name", SGRawValueMethods<FGRouteMgr, const char*>(*this,
&FGRouteMgr::getDestinationName, NULL));
-
- delete _arrivalWatcher;
- _arrivalWatcher = createWatcher(this, &FGRouteMgr::arrivalChanged);
- _arrivalWatcher->watch(destination->getChild("runway", 0, true));
+ destination->tie("field-elevation-ft", SGRawValueMethods<FGRouteMgr, double>(*this,
+ &FGRouteMgr::getDestinationFieldElevation, NULL));
destination->getChild("eta", 0, true);
- _arrivalWatcher->watch(destination->getChild("star", 0, true));
- _arrivalWatcher->watch(destination->getChild("transition", 0, true));
destination->getChild("touchdown-time", 0, true);
alternate = fgGetNode(RM "alternate", true);
wpn->getChild("dist", 0, true);
wpn->getChild("eta", 0, true);
- update_mirror();
_pathNode = fgGetNode(RM "file-path", 0, true);
+ setFlightPlan(new FlightPlan());
}
for (it = waypoints->begin(); it != waypoints->end(); ++it) {
WayptRef w = waypointFromString(*it);
if (w) {
- _route.push_back(w);
+ _plan->insertWayptAtIndex(w, -1);
}
}
- SG_LOG(SG_AUTOPILOT, SG_INFO, "loaded initial waypoints:" << _route.size());
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "loaded initial waypoints:" << numLegs());
update_mirror();
}
return active->getBoolValue();
}
+bool FGRouteMgr::saveRoute(const SGPath& p)
+{
+ if (!_plan) {
+ return false;
+ }
+
+ return _plan->save(p);
+}
+
+bool FGRouteMgr::loadRoute(const SGPath& p)
+{
+ FlightPlan* fp = new FlightPlan;
+ if (!fp->load(p)) {
+ delete fp;
+ return false;
+ }
+
+ setFlightPlan(fp);
+ return true;
+}
+
+FlightPlan* FGRouteMgr::flightPlan() const
+{
+ return _plan;
+}
+
+void FGRouteMgr::setFlightPlan(FlightPlan* plan)
+{
+ if (plan == _plan) {
+ return;
+ }
+
+ if (_plan) {
+ delete _plan;
+ active->setBoolValue(false);
+ }
+
+ _plan = plan;
+ _plan->setDelegate(this);
+
+// fire all the callbacks!
+ departureChanged();
+ arrivalChanged();
+ waypointsChanged();
+ currentWaypointChanged();
+}
+
void FGRouteMgr::update( double dt )
{
if (dt <= 0.0) {
}
// basic course/distance information
- SGGeod currentPos = SGGeod::fromDegFt(lon->getDoubleValue(),
- lat->getDoubleValue(),alt->getDoubleValue());
+ SGGeod currentPos = globals->get_aircraft_position();
- Waypt* curWpt = currentWaypt();
- if (!curWpt) {
+ FlightPlan::Leg* leg = _plan ? _plan->currentLeg() : NULL;
+ if (!leg) {
return;
}
double courseDeg;
double distanceM;
- boost::tie(courseDeg, distanceM) = curWpt->courseAndDistanceFrom(currentPos);
+ boost::tie(courseDeg, distanceM) = leg->waypoint()->courseAndDistanceFrom(currentPos);
// update wp0 / wp1 / wp-last
wp0->setDoubleValue("dist", distanceM * SG_METER_TO_NM);
wp0->setDoubleValue("bearing-deg", courseDeg);
setETAPropertyFromDistance(wp0->getChild("eta"), distanceM);
- double totalPathDistance = totalDistance->getDoubleValue() * SG_NM_TO_METER;
- double totalDistanceRemaining = distanceM; // distance to current waypoint
- double pathDistance = cachedWaypointPathTotalDistance(_currentIndex);
+ double totalPathDistanceNm = _plan->totalDistanceNm();
+ double totalDistanceRemaining = distanceM * SG_METER_TO_NM; // distance to current waypoint
// total distance to go, is direct distance to wp0, plus the remaining
// path distance from wp0
- totalDistanceRemaining += (totalPathDistance - pathDistance);
+ totalDistanceRemaining += (totalPathDistanceNm - leg->distanceAlongRoute());
wp0->setDoubleValue("distance-along-route-nm",
- pathDistance * SG_METER_TO_NM);
+ leg->distanceAlongRoute());
wp0->setDoubleValue("remaining-distance-nm",
- (totalPathDistance - pathDistance) * SG_METER_TO_NM);
+ totalPathDistanceNm - leg->distanceAlongRoute());
- Waypt* nextWpt = nextWaypt();
- if (nextWpt) {
- boost::tie(courseDeg, distanceM) = nextWpt->courseAndDistanceFrom(currentPos);
+ FlightPlan::Leg* nextLeg = _plan->nextLeg();
+ if (nextLeg) {
+ boost::tie(courseDeg, distanceM) = nextLeg->waypoint()->courseAndDistanceFrom(currentPos);
wp1->setDoubleValue("dist", distanceM * SG_METER_TO_NM);
wp1->setDoubleValue("true-bearing-deg", courseDeg);
courseDeg -= magvar->getDoubleValue(); // expose magnetic bearing
wp1->setDoubleValue("bearing-deg", courseDeg);
- setETAPropertyFromDistance(wp1->getChild("eta"), distanceM);
-
- double pathDistance = cachedWaypointPathTotalDistance(_currentIndex + 1);
+ setETAPropertyFromDistance(wp1->getChild("eta"), distanceM);
wp1->setDoubleValue("distance-along-route-nm",
- pathDistance * SG_METER_TO_NM);
+ nextLeg->distanceAlongRoute());
wp1->setDoubleValue("remaining-distance-nm",
- (totalPathDistance - pathDistance) * SG_METER_TO_NM);
+ totalPathDistanceNm - nextLeg->distanceAlongRoute());
}
- distanceToGo->setDoubleValue(totalDistanceRemaining * SG_METER_TO_NM);
- wpn->setDoubleValue("dist", totalDistanceRemaining * SG_METER_TO_NM);
- ete->setDoubleValue(totalDistanceRemaining * SG_METER_TO_NM / groundSpeed * 3600.0);
+ distanceToGo->setDoubleValue(totalDistanceRemaining);
+ wpn->setDoubleValue("dist", totalDistanceRemaining);
+ ete->setDoubleValue(totalDistanceRemaining / groundSpeed * 3600.0);
setETAPropertyFromDistance(wpn->getChild("eta"), totalDistanceRemaining);
}
+void FGRouteMgr::clearRoute()
+{
+ if (_plan) {
+ _plan->clear();
+ }
+}
+
+Waypt* FGRouteMgr::currentWaypt() const
+{
+ if (_plan && _plan->currentLeg()) {
+ return _plan->currentLeg()->waypoint();
+ }
+
+ return NULL;
+}
+
+int FGRouteMgr::currentIndex() const
+{
+ if (!_plan) {
+ return 0;
+ }
+
+ return _plan->currentIndex();
+}
+
+Waypt* FGRouteMgr::wayptAtIndex(int index) const
+{
+ if (_plan) {
+ FlightPlan::Leg* leg = _plan->legAtIndex(index);
+ if (leg) {
+ return leg->waypoint();
+ }
+ }
+
+ return NULL;
+}
+
+int FGRouteMgr::numLegs() const
+{
+ if (_plan) {
+ return _plan->numLegs();
+ }
+
+ return 0;
+}
+
void FGRouteMgr::setETAPropertyFromDistance(SGPropertyNode_ptr aProp, double aDistance)
{
double speed = fgGetDouble("/velocities/groundspeed-kt", 0.0);
aProp->setStringValue( eta_str );
}
-flightgear::WayptRef FGRouteMgr::removeWayptAtIndex(int aIndex)
+void FGRouteMgr::removeLegAtIndex(int aIndex)
{
- int index = aIndex;
- if (aIndex < 0) { // negative indices count the the end
- index = _route.size() + index;
- }
-
- if ((index < 0) || (index >= numWaypts())) {
- SG_LOG(SG_AUTOPILOT, SG_WARN, "removeWayptAtIndex with invalid index:" << aIndex);
- return NULL;
- }
- WayptVec::iterator it = _route.begin();
- it += index;
-
- WayptRef w = *it; // hold a ref now, in case _route is the only other owner
- _route.erase(it);
-
- update_mirror();
-
- if (_currentIndex == index) {
- currentWaypointChanged(); // current waypoint was removed
- }
- else
- if (_currentIndex > index) {
- --_currentIndex; // shift current index down if necessary
+ if (!_plan) {
+ return;
}
-
- _edited->fireValueChanged();
- checkFinished();
- return w;
+ _plan->deleteIndex(aIndex);
}
-struct NotGeneratedWayptPredicate : public std::unary_function<const Waypt*, bool>
-{
- bool operator() (const Waypt* w) const
- {
- return (w->flag(WPT_GENERATED) == false);
- }
-};
-
-
-void FGRouteMgr::clearRoute()
-{
-// erase all non-generated waypoints
- WayptVec::iterator r =
- std::remove_if(_route.begin(), _route.end(), NotGeneratedWayptPredicate());
- _route.erase(r, _route.end());
-
- _currentIndex = -1;
-
- update_mirror();
- active->setBoolValue(false);
- _edited->fireValueChanged();
-}
-
/**
* route between index-1 and index, using airways.
*/
WayptRef wp2;
if (index == -1) {
- index = _route.size(); // can still be zero, of course
+ index = numLegs();
}
if (index == 0) {
- if (!_departure) {
+ if (!_plan->departureAirport()) {
SG_LOG(SG_AUTOPILOT, SG_WARN, "routeToIndex: no departure set");
return false;
}
- wp1 = new NavaidWaypoint(_departure.get(), NULL);
+ wp1 = new NavaidWaypoint(_plan->departureAirport().get(), NULL);
} else {
wp1 = wayptAtIndex(index - 1);
}
- if (index >= numWaypts()) {
- if (!_destination) {
+ if (index >= numLegs()) {
+ if (!_plan->destinationAirport()) {
SG_LOG(SG_AUTOPILOT, SG_WARN, "routeToIndex: no destination set");
return false;
}
- wp2 = new NavaidWaypoint(_destination.get(), NULL);
+ wp2 = new NavaidWaypoint(_plan->destinationAirport().get(), NULL);
} else {
wp2 = wayptAtIndex(index);
}
return false;
}
- WayptVec::iterator it = _route.begin();
- it += index;
- _route.insert(it, r.begin(), r.end());
-
- update_mirror();
- _edited->fireValueChanged();
+ _plan->insertWayptsAtIndex(r, index);
return true;
}
-void FGRouteMgr::autoRoute()
-{
- if (!_departure || !_destination) {
- return;
- }
-
- string runwayId(departure->getStringValue("runway"));
- FGRunway* runway = NULL;
- if (_departure->hasRunwayWithIdent(runwayId)) {
- runway = _departure->getRunwayByIdent(runwayId);
- }
-
- FGRunway* dstRunway = NULL;
- runwayId = destination->getStringValue("runway");
- if (_destination->hasRunwayWithIdent(runwayId)) {
- dstRunway = _destination->getRunwayByIdent(runwayId);
- }
-
- _route.clear(); // clear out the existing, first
-// SID
- flightgear::SID* sid;
- WayptRef sidTrans;
-
- boost::tie(sid, sidTrans) = _departure->selectSID(_destination->geod(), runway);
- if (sid) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "selected SID " << sid->ident());
- if (sidTrans) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "\tvia " << sidTrans->ident() << " transition");
- }
-
- sid->route(runway, sidTrans, _route);
- departure->setStringValue("sid", sid->ident());
- } else {
- // use airport location for airway search
- sidTrans = new NavaidWaypoint(_departure.get(), NULL);
- departure->setStringValue("sid", "");
- }
-
-// STAR
- destination->setStringValue("transition", "");
- destination->setStringValue("star", "");
-
- STAR* star;
- WayptRef starTrans;
- boost::tie(star, starTrans) = _destination->selectSTAR(_departure->geod(), dstRunway);
- if (star) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "selected STAR " << star->ident());
- if (starTrans) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "\tvia " << starTrans->ident() << " transition");
- destination->setStringValue("transition", starTrans->ident());
- }
- destination->setStringValue("star", star->ident());
- } else {
- // use airport location for search
- starTrans = new NavaidWaypoint(_destination.get(), NULL);
- }
-
-// route between them
- WayptVec airwayRoute;
- if (Airway::highLevel()->route(sidTrans, starTrans, airwayRoute)) {
- _route.insert(_route.end(), airwayRoute.begin(), airwayRoute.end());
- }
-
-// add the STAR if we have one
- if (star) {
- _destination->buildApproach(starTrans, star, dstRunway, _route);
- }
-
- update_mirror();
- _edited->fireValueChanged();
-}
-
void FGRouteMgr::departureChanged()
{
-// remove existing departure waypoints
- WayptVec::iterator it = _route.begin();
- for (; it != _route.end(); ++it) {
- if (!(*it)->flag(WPT_DEPARTURE)) {
- break;
- }
- }
-
- // erase() invalidates iterators, so grab now
+ _plan->clearWayptsWithFlag(WPT_DEPARTURE);
WayptRef enroute;
- if (it == _route.end()) {
- if (_destination) {
- enroute = new NavaidWaypoint(_destination.get(), NULL);
- }
- } else {
- enroute = *it;
- }
-
- _route.erase(_route.begin(), it);
- if (!_departure) {
- waypointsChanged();
- return;
- }
-
WayptVec wps;
buildDeparture(enroute, wps);
- for (it = wps.begin(); it != wps.end(); ++it) {
- (*it)->setFlag(WPT_DEPARTURE);
- (*it)->setFlag(WPT_GENERATED);
- }
- _route.insert(_route.begin(), wps.begin(), wps.end());
-
- update_mirror();
- waypointsChanged();
+ _plan->insertWayptsAtIndex(wps, 0);
}
void FGRouteMgr::buildDeparture(WayptRef enroute, WayptVec& wps)
{
- string runwayId(departure->getStringValue("runway"));
- if (!_departure->hasRunwayWithIdent(runwayId)) {
-// valid airport, but no runway selected, so just the airport noide itself
- wps.push_back(new NavaidWaypoint(_departure.get(), NULL));
+ if (!_plan->departureAirport()) {
return;
}
- FGRunway* r = _departure->getRunwayByIdent(runwayId);
- string sidId = departure->getStringValue("sid");
- flightgear::SID* sid = _departure->findSIDWithIdent(sidId);
- if (!sid) {
-// valid runway, but no SID selected/found, so just the runway node for now
- if (!sidId.empty() && (sidId != "(none)")) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "SID not found:" << sidId);
- }
-
- wps.push_back(new RunwayWaypt(r, NULL));
+ if (!_plan->departureRunway()) {
+// valid airport, but no runway selected, so just the airport _plan itself
+ WayptRef w = new NavaidWaypoint(_plan->departureAirport(), _plan);
+ w->setFlag(WPT_DEPARTURE);
+ wps.push_back(w);
return;
}
-// we have a valid SID, awesome
- string trans(departure->getStringValue("transition"));
- WayptRef t = sid->findTransitionByName(trans);
- if (!t && enroute) {
- t = sid->findBestTransition(enroute->position());
- }
-
- sid->route(r, t, wps);
- if (!wps.empty() && wps.front()->flag(WPT_DYNAMIC)) {
- // ensure first waypoint is static, to simplify other computations
- wps.insert(wps.begin(), new RunwayWaypt(r, NULL));
+ WayptRef rwyWaypt = new RunwayWaypt(_plan->departureRunway(), _plan);
+ rwyWaypt->setFlag(WPT_DEPARTURE);
+ wps.push_back(rwyWaypt);
+
+ if (!_plan->sid()) {
+ return;
}
+
+ _plan->sid()->route(_plan->departureRunway(), _plan->sidTransition(), wps);
}
void FGRouteMgr::arrivalChanged()
{
- // remove existing arrival waypoints
- WayptVec::reverse_iterator rit = _route.rbegin();
- for (; rit != _route.rend(); ++rit) {
- if (!(*rit)->flag(WPT_ARRIVAL)) {
- break;
- }
- }
-
- // erase() invalidates iterators, so grab now
- WayptRef enroute;
- WayptVec::iterator it;
-
- if (rit != _route.rend()) {
- enroute = *rit;
- it = rit.base(); // convert to fwd iterator
- } else {
- it = _route.begin();
- }
-
- _route.erase(it, _route.end());
-
+ _plan->clearWayptsWithFlag(WPT_ARRIVAL);
+ _plan->clearWayptsWithFlag(WPT_APPROACH);
WayptVec wps;
+ WayptRef enroute;
buildArrival(enroute, wps);
- for (it = wps.begin(); it != wps.end(); ++it) {
- (*it)->setFlag(WPT_ARRIVAL);
- (*it)->setFlag(WPT_GENERATED);
- }
- _route.insert(_route.end(), wps.begin(), wps.end());
-
- update_mirror();
- waypointsChanged();
+ _plan->insertWayptsAtIndex(wps, -1);
}
void FGRouteMgr::buildArrival(WayptRef enroute, WayptVec& wps)
{
- if (!_destination) {
+ FGAirportRef apt = _plan->departureAirport();
+ if (!apt.valid()) {
return;
}
- string runwayId(destination->getStringValue("runway"));
- if (!_destination->hasRunwayWithIdent(runwayId)) {
-// valid airport, but no runway selected, so just the airport node itself
- wps.push_back(new NavaidWaypoint(_destination.get(), NULL));
+ if (!_plan->destinationRunway()) {
+ WayptRef w = new NavaidWaypoint(apt.ptr(), _plan);
+ w->setFlag(WPT_ARRIVAL);
+ wps.push_back(w);
return;
}
- FGRunway* r = _destination->getRunwayByIdent(runwayId);
- string starId = destination->getStringValue("star");
- STAR* star = _destination->findSTARWithIdent(starId);
- if (!star) {
-// valid runway, but no STAR selected/found, so just the runway node for now
- wps.push_back(new RunwayWaypt(r, NULL));
- return;
+ if (_plan->star()) {
+ _plan->star()->route(_plan->destinationRunway(), _plan->starTransition(), wps);
}
-// we have a valid STAR
- string trans(destination->getStringValue("transition"));
- WayptRef t = star->findTransitionByName(trans);
- if (!t && enroute) {
- t = star->findBestTransition(enroute->position());
+ if (_plan->approach()) {
+ _plan->approach()->route(wps.back(), wps);
+ } else {
+ WayptRef w = new RunwayWaypt(_plan->destinationRunway(), _plan);
+ w->setFlag(WPT_APPROACH);
+ wps.push_back(w);
}
-
- _destination->buildApproach(t, star, r, wps);
}
void FGRouteMgr::waypointsChanged()
{
-
-}
-
-void FGRouteMgr::insertWayptAtIndex(Waypt* aWpt, int aIndex)
-{
- if (!aWpt) {
- return;
- }
-
- int index = aIndex;
- if ((aIndex == -1) || (aIndex > (int) _route.size())) {
- index = _route.size();
- }
-
- WayptVec::iterator it = _route.begin();
- it += index;
-
- if (_currentIndex >= index) {
- ++_currentIndex;
- }
-
- _route.insert(it, aWpt);
-
update_mirror();
- _edited->fireValueChanged();
-}
-
-WayptRef FGRouteMgr::waypointFromString(const string& tgt )
-{
- string target(boost::to_upper_copy(tgt));
- WayptRef wpt;
-
-// extract altitude
- double altFt = cruise->getDoubleValue("altitude-ft");
- RouteRestriction altSetting = RESTRICT_NONE;
-
- size_t pos = target.find( '@' );
- if ( pos != string::npos ) {
- altFt = atof( target.c_str() + pos + 1 );
- target = target.substr( 0, pos );
- if ( !strcmp(fgGetString("/sim/startup/units"), "meter") )
- altFt *= SG_METER_TO_FEET;
- altSetting = RESTRICT_AT;
- }
-
-// check for lon,lat
- pos = target.find( ',' );
- if ( pos != string::npos ) {
- double lon = atof( target.substr(0, pos).c_str());
- double lat = atof( target.c_str() + pos + 1);
- 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));
-
- wpt = new BasicWaypt(SGGeod::fromDeg(lon, lat), buf, NULL);
- if (altSetting != RESTRICT_NONE) {
- wpt->setAltitude(altFt, altSetting);
- }
- return wpt;
- }
-
- SGGeod basePosition;
- if (_route.empty()) {
- // route is empty, use current position
- basePosition = SGGeod::fromDeg(lon->getDoubleValue(), lat->getDoubleValue());
- } else {
- basePosition = _route.back()->position();
- }
-
- string_list pieces(simgear::strutils::split(target, "/"));
- FGPositionedRef p = FGPositioned::findClosestWithIdent(pieces.front(), basePosition);
- if (!p) {
- SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << pieces.front());
- return NULL;
- }
-
- if (pieces.size() == 1) {
- wpt = new NavaidWaypoint(p, NULL);
- } else if (pieces.size() == 3) {
- // navaid/radial/distance-nm notation
- double radial = atof(pieces[1].c_str()),
- distanceNm = atof(pieces[2].c_str());
- radial += magvar->getDoubleValue(); // convert to true bearing
- wpt = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
- } else if (pieces.size() == 2) {
- FGAirport* apt = dynamic_cast<FGAirport*>(p.ptr());
- if (!apt) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "Waypoint is not an airport:" << pieces.front());
- return NULL;
- }
-
- if (!apt->hasRunwayWithIdent(pieces[1])) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "No runway: " << pieces[1] << " at " << pieces[0]);
- return NULL;
- }
-
- FGRunway* runway = apt->getRunwayByIdent(pieces[1]);
- wpt = new NavaidWaypoint(runway, NULL);
- } else if (pieces.size() == 4) {
- // navid/radial/navid/radial notation
- FGPositionedRef p2 = FGPositioned::findClosestWithIdent(pieces[2], basePosition);
- if (!p2) {
- SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << pieces[2]);
- return NULL;
- }
-
- double r1 = atof(pieces[1].c_str()),
- r2 = atof(pieces[3].c_str());
- r1 += magvar->getDoubleValue();
- r2 += magvar->getDoubleValue();
-
- SGGeod intersection;
- bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection);
- if (!ok) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "no valid intersection for:" << target);
- return NULL;
- }
-
- std::string name = p->ident() + "-" + p2->ident();
- wpt = new BasicWaypt(intersection, name, NULL);
- }
-
- if (!wpt) {
- SG_LOG(SG_AUTOPILOT, SG_INFO, "Unable to parse waypoint:" << target);
- return NULL;
- }
-
- if (altSetting != RESTRICT_NONE) {
- wpt->setAltitude(altFt, altSetting);
- }
- return wpt;
+ _edited->fireValueChanged();
+ checkFinished();
}
// mirror internal route to the property system for inspection by other subsystems
void FGRouteMgr::update_mirror()
{
mirror->removeChildren("wp");
+ NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
+ FGDialog* rmDlg = gui ? gui->getDialog("route-manager") : NULL;
+
+ if (!_plan) {
+ mirror->setIntValue("num", 0);
+ if (rmDlg) {
+ rmDlg->updateValues();
+ }
+ return;
+ }
- int num = numWaypts();
- double totalDistanceEnroute = 0.0;
+ int num = _plan->numLegs();
for (int i = 0; i < num; i++) {
- Waypt* wp = _route[i];
+ FlightPlan::Leg* leg = _plan->legAtIndex(i);
+ WayptRef wp = leg->waypoint();
SGPropertyNode *prop = mirror->getChild("wp", i, 1);
const SGGeod& pos(wp->position());
prop->setDoubleValue("latitude-deg",pos.getLatitudeDeg());
// leg course+distance
- if (i < (num - 1)) {
- Waypt* next = _route[i+1];
- std::pair<double, double> crsDist =
- next->courseAndDistanceFrom(pos);
- prop->setDoubleValue("leg-bearing-true-deg", crsDist.first);
- prop->setDoubleValue("leg-distance-nm", crsDist.second * SG_METER_TO_NM);
- prop->setDoubleValue("distance-along-route-nm", totalDistanceEnroute);
- totalDistanceEnroute += crsDist.second * SG_METER_TO_NM;
- }
+
+ prop->setDoubleValue("leg-bearing-true-deg", leg->courseDeg());
+ prop->setDoubleValue("leg-distance-nm", leg->distanceNm());
+ prop->setDoubleValue("distance-along-route-nm", leg->distanceAlongRoute());
- if (wp->altitudeRestriction() != RESTRICT_NONE) {
- double ft = wp->altitudeFt();
+ if (leg->altitudeRestriction() != RESTRICT_NONE) {
+ double ft = leg->altitudeFt();
prop->setDoubleValue("altitude-m", ft * SG_FEET_TO_METER);
prop->setDoubleValue("altitude-ft", ft);
prop->setIntValue("flight-level", static_cast<int>(ft / 1000) * 10);
prop->setDoubleValue("altitude-ft", -9999.9);
}
- if (wp->speedRestriction() == SPEED_RESTRICT_MACH) {
- prop->setDoubleValue("speed-mach", wp->speedMach());
- } else if (wp->speedRestriction() != RESTRICT_NONE) {
- prop->setDoubleValue("speed-kts", wp->speedKts());
+ if (leg->speedRestriction() == SPEED_RESTRICT_MACH) {
+ prop->setDoubleValue("speed-mach", leg->speedMach());
+ } else if (leg->speedRestriction() != RESTRICT_NONE) {
+ prop->setDoubleValue("speed-kts", leg->speedKts());
}
if (wp->flag(WPT_ARRIVAL)) {
} // of waypoint iteration
// set number as listener attachment point
- mirror->setIntValue("num", _route.size());
+ mirror->setIntValue("num", _plan->numLegs());
- NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
- FGDialog* rmDlg = gui->getDialog("route-manager");
if (rmDlg) {
rmDlg->updateValues();
}
-
- if (_departure) {
- departure->setDoubleValue("field-elevation-ft", _departure->getElevation());
- }
- if (_destination) {
- destination->setDoubleValue("field-elevation-ft", _destination->getElevation());
- }
-
- totalDistance->setDoubleValue(totalDistanceEnroute);
-}
-
-double FGRouteMgr::cachedLegPathDistanceM(int index) const
-{
- SGPropertyNode *prop = mirror->getChild("wp", index, 1);
- return prop->getDoubleValue("leg-distance-nm") * SG_NM_TO_METER;
-}
-
-double FGRouteMgr::cachedWaypointPathTotalDistance(int index) const
-{
- SGPropertyNode *prop = mirror->getChild("wp", index, 1);
- return prop->getDoubleValue("distance-along-route-nm") * SG_NM_TO_METER;
+ totalDistance->setDoubleValue(_plan->totalDistanceNm());
}
// command interface /autopilot/route-manager/input:
SGPath path(mgr->_pathNode->getStringValue());
mgr->saveRoute(path);
} else if (!strcmp(s, "@NEXT")) {
- mgr->jumpToIndex(mgr->_currentIndex + 1);
+ mgr->jumpToIndex(mgr->currentIndex() + 1);
} else if (!strcmp(s, "@PREVIOUS")) {
- mgr->jumpToIndex(mgr->_currentIndex - 1);
+ mgr->jumpToIndex(mgr->currentIndex() - 1);
} else if (!strncmp(s, "@JUMP", 5)) {
mgr->jumpToIndex(atoi(s + 5));
} else if (!strncmp(s, "@DELETE", 7))
- mgr->removeWayptAtIndex(atoi(s + 7));
+ mgr->removeLegAtIndex(atoi(s + 7));
else if (!strncmp(s, "@INSERT", 7)) {
char *r;
int pos = strtol(s + 7, &r, 10);
while (isspace(*r))
r++;
if (*r)
- mgr->insertWayptAtIndex(mgr->waypointFromString(r), pos);
+ mgr->flightPlan()->insertWayptAtIndex(mgr->waypointFromString(r), pos);
} else if (!strncmp(s, "@ROUTE", 6)) {
char* r;
int endIndex = strtol(s + 6, &r, 10);
RouteType rt = (RouteType) mgr->_routingType->getIntValue();
mgr->routeToIndex(endIndex, rt);
- } else if (!strcmp(s, "@AUTOROUTE")) {
- mgr->autoRoute();
} else if (!strcmp(s, "@POSINIT")) {
mgr->initAtPosition();
} else
- mgr->insertWayptAtIndex(mgr->waypointFromString(s), -1);
+ mgr->flightPlan()->insertWayptAtIndex(mgr->waypointFromString(s), -1);
}
void FGRouteMgr::initAtPosition()
if (airborne->getBoolValue()) {
SG_LOG(SG_AUTOPILOT, SG_INFO, "initAtPosition: airborne, clearing departure info");
- _departure = NULL;
- departure->setStringValue("runway", "");
+ _plan->setDeparture((FGAirport*) NULL);
return;
}
// on the ground
- SGGeod pos = SGGeod::fromDegFt(lon->getDoubleValue(),
- lat->getDoubleValue(), alt->getDoubleValue());
- if (!_departure) {
- _departure = FGAirport::findClosest(pos, 20.0);
- if (!_departure) {
+ SGGeod pos = globals->get_aircraft_position();
+ if (!_plan->departureAirport()) {
+ _plan->setDeparture(FGAirport::findClosest(pos, 20.0));
+ if (!_plan->departureAirport()) {
SG_LOG(SG_AUTOPILOT, SG_INFO, "initAtPosition: couldn't find an airport within 20nm");
- departure->setStringValue("runway", "");
return;
}
}
std::string rwy = departure->getStringValue("runway");
+ FGRunway* r = NULL;
if (!rwy.empty()) {
- // runway already set, fine
- return;
+ r = _plan->departureAirport()->getRunwayByIdent(rwy);
+ } else {
+ r = _plan->departureAirport()->findBestRunwayForPos(pos);
}
- FGRunway* r = _departure->findBestRunwayForPos(pos);
if (!r) {
return;
}
- departure->setStringValue("runway", r->ident().c_str());
+ _plan->setDeparture(r);
SG_LOG(SG_AUTOPILOT, SG_INFO, "initAtPosition: starting at "
- << _departure->ident() << " on runway " << r->ident());
+ << _plan->departureAirport()->ident() << " on runway " << r->ident());
}
bool FGRouteMgr::haveUserWaypoints() const
{
- return std::find_if(_route.begin(), _route.end(), NotGeneratedWayptPredicate()) != _route.end();
+ // FIXME
+ return false;
}
bool FGRouteMgr::activate()
{
+ if (!_plan) {
+ SG_LOG(SG_AUTOPILOT, SG_WARN, "::activate, no flight plan defined");
+ return false;
+ }
+
if (isRouteActive()) {
SG_LOG(SG_AUTOPILOT, SG_WARN, "duplicate route-activation, no-op");
return false;
}
- _currentIndex = 0;
- currentWaypointChanged();
-
- /* double routeDistanceNm = _route->total_distance() * SG_METER_TO_NM;
- totalDistance->setDoubleValue(routeDistanceNm);
- double cruiseSpeedKts = cruise->getDoubleValue("speed", 0.0);
- if (cruiseSpeedKts > 1.0) {
- // very very crude approximation, doesn't allow for climb / descent
- // performance or anything else at all
- ete->setDoubleValue(routeDistanceNm / cruiseSpeedKts * (60.0 * 60.0));
- }
- */
+ _plan->setCurrentIndex(0);
active->setBoolValue(true);
SG_LOG(SG_AUTOPILOT, SG_INFO, "route-manager, activate route ok");
return true;
void FGRouteMgr::sequence()
{
- if (!active->getBoolValue()) {
+ if (!_plan || !active->getBoolValue()) {
SG_LOG(SG_AUTOPILOT, SG_ALERT, "trying to sequence waypoints with no active route");
return;
}
return;
}
- _currentIndex++;
- currentWaypointChanged();
+ _plan->setCurrentIndex(_plan->currentIndex() + 1);
}
bool FGRouteMgr::checkFinished()
{
- if (_currentIndex < (int) _route.size()) {
+ if (!_plan) {
+ return true;
+ }
+
+ if (_plan->currentIndex() < _plan->numLegs()) {
return false;
}
void FGRouteMgr::jumpToIndex(int index)
{
- if ((index < 0) || (index >= (int) _route.size())) {
- SG_LOG(SG_AUTOPILOT, SG_ALERT, "passed invalid index (" <<
- index << ") to FGRouteMgr::jumpToIndex");
+ if (!_plan) {
return;
}
-
- if (_currentIndex == index) {
- return; // no-op
- }
-// all the checks out the way, go ahead and update state
- _currentIndex = index;
- currentWaypointChanged();
- _currentWpt->fireValueChanged();
+ _plan->setCurrentIndex(index);
}
void FGRouteMgr::currentWaypointChanged()
{
Waypt* cur = currentWaypt();
- Waypt* next = nextWaypt();
+ FlightPlan::Leg* next = _plan ? _plan->nextLeg() : NULL;
wp0->getChild("id")->setStringValue(cur ? cur->ident() : "");
- wp1->getChild("id")->setStringValue(next ? next->ident() : "");
+ wp1->getChild("id")->setStringValue(next ? next->waypoint()->ident() : "");
_currentWpt->fireValueChanged();
- SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << _currentIndex);
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "route manager, current-wp is now " << currentIndex());
}
-int FGRouteMgr::findWayptIndex(const SGGeod& aPos) const
-{
- for (int i=0; i<numWaypts(); ++i) {
- if (_route[i]->matches(aPos)) {
- return i;
- }
+const char* FGRouteMgr::getDepartureICAO() const
+{
+ if (!_plan || !_plan->departureAirport()) {
+ return "";
}
- return -1;
-}
-
-Waypt* FGRouteMgr::currentWaypt() const
-{
- if ((_currentIndex < 0) || (_currentIndex >= numWaypts()))
- return NULL;
- return wayptAtIndex(_currentIndex);
+ return _plan->departureAirport()->ident().c_str();
}
-Waypt* FGRouteMgr::previousWaypt() const
+const char* FGRouteMgr::getDepartureName() const
{
- if (_currentIndex == 0) {
- return NULL;
+ if (!_plan || !_plan->departureAirport()) {
+ return "";
}
- return wayptAtIndex(_currentIndex - 1);
+ return _plan->departureAirport()->name().c_str();
}
-Waypt* FGRouteMgr::nextWaypt() const
+const char* FGRouteMgr::getDepartureRunway() const
{
- if ((_currentIndex < 0) || ((_currentIndex + 1) >= numWaypts())) {
- return NULL;
+ if (_plan && _plan->departureRunway()) {
+ return _plan->departureRunway()->ident().c_str();
}
- return wayptAtIndex(_currentIndex + 1);
+ return "";
}
-Waypt* FGRouteMgr::wayptAtIndex(int index) const
+void FGRouteMgr::setDepartureRunway(const char* aIdent)
{
- if ((index < 0) || (index >= numWaypts())) {
- throw sg_range_exception("waypt index out of range", "FGRouteMgr::wayptAtIndex");
+ FGAirport* apt = _plan->departureAirport();
+ if (!apt || (aIdent == NULL)) {
+ _plan->setDeparture(apt);
+ } else if (apt->hasRunwayWithIdent(aIdent)) {
+ _plan->setDeparture(apt->getRunwayByIdent(aIdent));
}
-
- return _route[index];
}
-SGPropertyNode_ptr FGRouteMgr::wayptNodeAtIndex(int index) const
+void FGRouteMgr::setDepartureICAO(const char* aIdent)
{
- if ((index < 0) || (index >= numWaypts())) {
- throw sg_range_exception("waypt index out of range", "FGRouteMgr::wayptAtIndex");
- }
-
- return mirror->getChild("wp", index);
+ if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
+ _plan->setDeparture((FGAirport*) NULL);
+ } else {
+ _plan->setDeparture(FGAirport::findByIdent(aIdent));
+ }
}
-bool FGRouteMgr::saveRoute(const SGPath& path)
+const char* FGRouteMgr::getSID() const
{
- SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
- try {
- SGPropertyNode_ptr d(new SGPropertyNode);
- SGPath path(_pathNode->getStringValue());
- d->setIntValue("version", 2);
-
- if (_departure) {
- d->setStringValue("departure/airport", _departure->ident());
- d->setStringValue("departure/sid", departure->getStringValue("sid"));
- d->setStringValue("departure/runway", departure->getStringValue("runway"));
- }
-
- if (_destination) {
- d->setStringValue("destination/airport", _destination->ident());
- d->setStringValue("destination/star", destination->getStringValue("star"));
- d->setStringValue("destination/transition", destination->getStringValue("transition"));
- d->setStringValue("destination/runway", destination->getStringValue("runway"));
- }
-
- // route nodes
- SGPropertyNode* routeNode = d->getChild("route", 0, true);
- for (unsigned int i=0; i<_route.size(); ++i) {
- Waypt* wpt = _route[i];
- wpt->saveAsNode(routeNode->getChild("wp", i, true));
- } // of waypoint iteration
- writeProperties(path.str(), d, true /* write-all */);
- return true;
- } catch (sg_exception& e) {
- SG_LOG(SG_IO, SG_ALERT, "Failed to save flight-plan '" << path.str() << "'. " << e.getMessage());
- return false;
+ if (_plan && _plan->sid()) {
+ return _plan->sid()->ident().c_str();
}
+
+ return "";
}
-bool FGRouteMgr::loadRoute(const SGPath& path)
+void FGRouteMgr::setSID(const char* aIdent)
{
- if (!path.exists())
- {
- SG_LOG(SG_IO, SG_ALERT, "Failed to load flight-plan '" << path.str()
- << "'. The file does not exist.");
- return false;
- }
-
- // deactivate route first
- active->setBoolValue(false);
-
- SGPropertyNode_ptr routeData(new SGPropertyNode);
+ FGAirport* apt = _plan->departureAirport();
+ if (!apt || (aIdent == NULL)) {
+ _plan->setSID((SID*) NULL);
+ return;
+ }
- SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
+ string ident(aIdent);
+ size_t hyphenPos = ident.find('-');
+ if (hyphenPos != string::npos) {
+ string sidIdent = ident.substr(0, hyphenPos);
+ string transIdent = ident.substr(hyphenPos + 1);
- bool Status = false;
- try {
- readProperties(path.str(), routeData);
- } catch (sg_exception& ) {
- // if XML parsing fails, the file might be simple textual list of waypoints
- Status = loadPlainTextRoute(path);
- routeData = 0;
- }
-
- if (routeData.valid())
- {
- try {
- int version = routeData->getIntValue("version", 1);
- if (version == 1) {
- loadVersion1XMLRoute(routeData);
- } else if (version == 2) {
- loadVersion2XMLRoute(routeData);
- } else {
- throw sg_io_exception("unsupported XML route version");
- }
- Status = true;
- } catch (sg_exception& e) {
- SG_LOG(SG_IO, SG_ALERT, "Failed to load flight-plan '" << e.getOrigin()
- << "'. " << e.getMessage());
- Status = false;
- }
+ SID* sid = apt->findSIDWithIdent(sidIdent);
+ Transition* trans = sid ? sid->findTransitionByName(transIdent) : NULL;
+ _plan->setSID(trans);
+ } else {
+ _plan->setSID(apt->findSIDWithIdent(aIdent));
}
-
- update_mirror();
-
- return Status;
}
-void FGRouteMgr::loadXMLRouteHeader(SGPropertyNode_ptr routeData)
-{
- // departure nodes
- SGPropertyNode* dep = routeData->getChild("departure");
- if (dep) {
- string depIdent = dep->getStringValue("airport");
- _departure = (FGAirport*) fgFindAirportID(depIdent);
- departure->setStringValue("runway", dep->getStringValue("runway"));
- departure->setStringValue("sid", dep->getStringValue("sid"));
- departure->setStringValue("transition", dep->getStringValue("transition"));
- }
-
-// destination
- SGPropertyNode* dst = routeData->getChild("destination");
- if (dst) {
- _destination = (FGAirport*) fgFindAirportID(dst->getStringValue("airport"));
- destination->setStringValue("runway", dst->getStringValue("runway"));
- destination->setStringValue("star", dst->getStringValue("star"));
- destination->setStringValue("transition", dst->getStringValue("transition"));
- }
-
-// alternate
- SGPropertyNode* alt = routeData->getChild("alternate");
- if (alt) {
- alternate->setStringValue(alt->getStringValue("airport"));
- } // of cruise data loading
-
-// cruise
- SGPropertyNode* crs = routeData->getChild("cruise");
- if (crs) {
- cruise->setDoubleValue("speed-kts", crs->getDoubleValue("speed-kts"));
- cruise->setDoubleValue("mach", crs->getDoubleValue("mach"));
- cruise->setDoubleValue("altitude-ft", crs->getDoubleValue("altitude-ft"));
- } // of cruise data loading
-
-}
-
-void FGRouteMgr::loadVersion2XMLRoute(SGPropertyNode_ptr routeData)
-{
- loadXMLRouteHeader(routeData);
-
-// route nodes
- WayptVec wpts;
- SGPropertyNode_ptr routeNode = routeData->getChild("route", 0);
- for (int i=0; i<routeNode->nChildren(); ++i) {
- SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i);
- WayptRef wpt = Waypt::createFromProperties(NULL, wpNode);
- wpts.push_back(wpt);
- } // of route iteration
-
- _route = wpts;
-}
-
-void FGRouteMgr::loadVersion1XMLRoute(SGPropertyNode_ptr routeData)
+const char* FGRouteMgr::getDestinationICAO() const
{
- loadXMLRouteHeader(routeData);
-
-// route nodes
- WayptVec wpts;
- SGPropertyNode_ptr routeNode = routeData->getChild("route", 0);
- for (int i=0; i<routeNode->nChildren(); ++i) {
- SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i);
- WayptRef wpt = parseVersion1XMLWaypt(wpNode);
- wpts.push_back(wpt);
- } // of route iteration
-
- _route = wpts;
+ if (!_plan || !_plan->destinationAirport()) {
+ return "";
+ }
+
+ return _plan->destinationAirport()->ident().c_str();
}
-WayptRef FGRouteMgr::parseVersion1XMLWaypt(SGPropertyNode* aWP)
+const char* FGRouteMgr::getDestinationName() const
{
- SGGeod lastPos;
- if (!_route.empty()) {
- lastPos = _route.back()->position();
- } else if (_departure) {
- lastPos = _departure->geod();
- }
-
- WayptRef w;
- string ident(aWP->getStringValue("ident"));
- if (aWP->hasChild("longitude-deg")) {
- // explicit longitude/latitude
- w = new BasicWaypt(SGGeod::fromDeg(aWP->getDoubleValue("longitude-deg"),
- aWP->getDoubleValue("latitude-deg")), ident, NULL);
-
- } else {
- string nid = aWP->getStringValue("navid", ident.c_str());
- FGPositionedRef p = FGPositioned::findClosestWithIdent(nid, lastPos);
- if (!p) {
- throw sg_io_exception("bad route file, unknown navid:" + nid);
- }
-
- SGGeod pos(p->geod());
- if (aWP->hasChild("offset-nm") && aWP->hasChild("offset-radial")) {
- double radialDeg = aWP->getDoubleValue("offset-radial");
- // convert magnetic radial to a true radial!
- radialDeg += magvar->getDoubleValue();
- double offsetNm = aWP->getDoubleValue("offset-nm");
- double az2;
- SGGeodesy::direct(p->geod(), radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
- }
-
- w = new BasicWaypt(pos, ident, NULL);
+ if (!_plan || !_plan->destinationAirport()) {
+ return "";
}
- double altFt = aWP->getDoubleValue("altitude-ft", -9999.9);
- if (altFt > -9990.0) {
- w->setAltitude(altFt, RESTRICT_AT);
- }
-
- return w;
+ return _plan->destinationAirport()->name().c_str();
}
-bool FGRouteMgr::loadPlainTextRoute(const SGPath& path)
+void FGRouteMgr::setDestinationICAO(const char* aIdent)
{
- try {
- sg_gzifstream in(path.str().c_str());
- if (!in.is_open()) {
- throw sg_io_exception("Cannot open file for reading.");
- }
-
- WayptVec wpts;
- while (!in.eof()) {
- string line;
- getline(in, line, '\n');
- // trim CR from end of line, if found
- if (line[line.size() - 1] == '\r') {
- line.erase(line.size() - 1, 1);
- }
-
- line = simgear::strutils::strip(line);
- if (line.empty() || (line[0] == '#')) {
- continue; // ignore empty/comment lines
- }
-
- WayptRef w = waypointFromString(line);
- if (!w) {
- throw sg_io_exception("Failed to create waypoint from line '" + line + "'.");
- }
-
- wpts.push_back(w);
- } // of line iteration
-
- _route = wpts;
- return true;
- } catch (sg_exception& e) {
- SG_LOG(SG_IO, SG_ALERT, "Failed to load route from: '" << path.str() << "'. " << e.getMessage());
- return false;
+ if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
+ _plan->setDestination((FGAirport*) NULL);
+ } else {
+ _plan->setDestination(FGAirport::findByIdent(aIdent));
}
}
-const char* FGRouteMgr::getDepartureICAO() const
+const char* FGRouteMgr::getDestinationRunway() const
{
- if (!_departure) {
- return "";
+ if (_plan && _plan->destinationRunway()) {
+ return _plan->destinationRunway()->ident().c_str();
}
- return _departure->ident().c_str();
+ return "";
}
-const char* FGRouteMgr::getDepartureName() const
+void FGRouteMgr::setDestinationRunway(const char* aIdent)
{
- if (!_departure) {
- return "";
+ FGAirport* apt = _plan->destinationAirport();
+ if (!apt || (aIdent == NULL)) {
+ _plan->setDestination(apt);
+ } else if (apt->hasRunwayWithIdent(aIdent)) {
+ _plan->setDestination(apt->getRunwayByIdent(aIdent));
}
-
- return _departure->name().c_str();
}
-void FGRouteMgr::setDepartureICAO(const char* aIdent)
+const char* FGRouteMgr::getApproach() const
{
- if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
- _departure = NULL;
- } else {
- _departure = FGAirport::findByIdent(aIdent);
+ if (_plan && _plan->approach()) {
+ return _plan->approach()->ident().c_str();
}
- departureChanged();
+ return "";
}
-const char* FGRouteMgr::getDestinationICAO() const
+void FGRouteMgr::setApproach(const char* aIdent)
{
- if (!_destination) {
- return "";
+ FGAirport* apt = _plan->destinationAirport();
+ if (!apt || (aIdent == NULL)) {
+ _plan->setApproach(NULL);
+ } else {
+ _plan->setApproach(apt->findApproachWithIdent(aIdent));
}
-
- return _destination->ident().c_str();
}
-const char* FGRouteMgr::getDestinationName() const
+const char* FGRouteMgr::getSTAR() const
{
- if (!_destination) {
- return "";
+ if (_plan && _plan->star()) {
+ return _plan->star()->ident().c_str();
}
- return _destination->name().c_str();
+ return "";
}
-void FGRouteMgr::setDestinationICAO(const char* aIdent)
+void FGRouteMgr::setSTAR(const char* aIdent)
{
- if ((aIdent == NULL) || (strlen(aIdent) < 4)) {
- _destination = NULL;
+ FGAirport* apt = _plan->destinationAirport();
+ if (!apt || (aIdent == NULL)) {
+ _plan->setSTAR((STAR*) NULL);
+ return;
+ }
+
+ string ident(aIdent);
+ size_t hyphenPos = ident.find('-');
+ if (hyphenPos != string::npos) {
+ string starIdent = ident.substr(0, hyphenPos);
+ string transIdent = ident.substr(hyphenPos + 1);
+
+ STAR* star = apt->findSTARWithIdent(starIdent);
+ Transition* trans = star ? star->findTransitionByName(transIdent) : NULL;
+ _plan->setSTAR(trans);
} else {
- _destination = FGAirport::findByIdent(aIdent);
+ _plan->setSTAR(apt->findSTARWithIdent(aIdent));
}
-
- arrivalChanged();
}
-FGAirportRef FGRouteMgr::departureAirport() const
+WayptRef FGRouteMgr::waypointFromString(const std::string& target)
{
- return _departure;
+ return _plan->waypointFromString(target);
}
-FGAirportRef FGRouteMgr::destinationAirport() const
+double FGRouteMgr::getDepartureFieldElevation() const
{
- return _destination;
+ if (!_plan || !_plan->departureAirport()) {
+ return 0.0;
+ }
+
+ return _plan->departureAirport()->elevation();
}
-FGRunway* FGRouteMgr::departureRunway() const
+double FGRouteMgr::getDestinationFieldElevation() const
{
- if (!_departure) {
- return NULL;
- }
-
- string runwayId(departure->getStringValue("runway"));
- if (!_departure->hasRunwayWithIdent(runwayId)) {
- return NULL;
- }
-
- return _departure->getRunwayByIdent(runwayId);
+ if (!_plan || !_plan->destinationAirport()) {
+ return 0.0;
+ }
+
+ return _plan->destinationAirport()->elevation();
}
-FGRunway* FGRouteMgr::destinationRunway() const
+SGPropertyNode_ptr FGRouteMgr::wayptNodeAtIndex(int index) const
{
- if (!_destination) {
- return NULL;
- }
-
- string runwayId(destination->getStringValue("runway"));
- if (!_destination->hasRunwayWithIdent(runwayId)) {
- return NULL;
- }
-
- return _destination->getRunwayByIdent(runwayId);
+ if ((index < 0) || (index >= numWaypts())) {
+ throw sg_range_exception("waypt index out of range", "FGRouteMgr::wayptAtIndex");
+ }
+
+ return mirror->getChild("wp", index);
}
-
*
*/
-class FGRouteMgr : public SGSubsystem
+class FGRouteMgr : public SGSubsystem,
+ public flightgear::FlightPlan::Delegate
{
public:
FGRouteMgr();
void bind ();
void unbind ();
void update (double dt);
-
- void insertWayptAtIndex(flightgear::Waypt* aWpt, int aIndex);
- flightgear::WayptRef removeWayptAtIndex(int index);
-
- void clearRoute();
typedef enum {
ROUTE_HIGH_AIRWAYS, ///< high-level airways routing
* used as the final waypoint.
*/
bool routeToIndex(int index, RouteType aRouteType);
-
- void autoRoute();
bool isRouteActive() const;
- int currentIndex() const
- { return _currentIndex; }
-
+ int currentIndex() const;
+
+ void setFlightPlan(flightgear::FlightPlan* plan);
+ flightgear::FlightPlan* flightPlan() const;
+
+ void clearRoute();
+
flightgear::Waypt* currentWaypt() const;
- flightgear::Waypt* nextWaypt() const;
- flightgear::Waypt* previousWaypt() const;
- const flightgear::WayptVec& waypts() const
- { return _route; }
+ int numLegs() const;
+// deprecated
int numWaypts() const
- { return _route.size(); }
-
+ { return numLegs(); }
+
+// deprecated
flightgear::Waypt* wayptAtIndex(int index) const;
-
+
SGPropertyNode_ptr wayptNodeAtIndex(int index) const;
-
- /**
- * Find a waypoint in the route, by position, and return its index, or
- * -1 if no matching waypoint was found in the route.
- */
- int findWayptIndex(const SGGeod& aPos) const;
-
+
+ void removeLegAtIndex(int aIndex);
+
/**
* Activate a built route. This checks for various mandatory pieces of
* data, such as departure and destination airports, and creates waypoints
bool saveRoute(const SGPath& p);
bool loadRoute(const SGPath& p);
+ flightgear::WayptRef waypointFromString(const std::string& target);
+
/**
* Helper command to setup current airport/runway if necessary
*/
void initAtPosition();
-
- /**
- * Create a WayPoint from a string in the following format:
- * - simple identifier
- * - decimal-lon,decimal-lat
- * - airport-id/runway-id
- * - navaid/radial-deg/offset-nm
- */
- flightgear::WayptRef waypointFromString(const std::string& target);
-
- FGAirportRef departureAirport() const;
- FGAirportRef destinationAirport() const;
-
- FGRunway* departureRunway() const;
- FGRunway* destinationRunway() const;
+
private:
- flightgear::WayptVec _route;
- int _currentIndex;
+ flightgear::FlightPlan* _plan;
time_t _takeoffTime;
time_t _touchdownTime;
- FGAirportRef _departure;
- FGAirportRef _destination;
-
+
// automatic inputs
- SGPropertyNode_ptr lon;
- SGPropertyNode_ptr lat;
- SGPropertyNode_ptr alt;
SGPropertyNode_ptr magvar;
// automatic outputs
InputListener *listener;
SGPropertyNode_ptr mirror;
-
- void departureChanged();
+
+ virtual void departureChanged();
void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
- void arrivalChanged();
+ virtual void arrivalChanged();
void buildArrival(flightgear::WayptRef enroute, flightgear::WayptVec& wps);
/**
* modified (waypoints added, inserted, removed). Notably, this fires the
* 'edited' signal.
*/
- void waypointsChanged();
+ virtual void waypointsChanged();
void update_mirror();
- void currentWaypointChanged();
-
- /**
- * Parse a route/wp node (from a saved, property-lsit formatted route)
- */
- void parseRouteWaypoint(SGPropertyNode* aWP);
+ virtual void currentWaypointChanged();
/**
* Check if we've reached the final waypoint.
*/
bool checkFinished();
-
- bool loadPlainTextRoute(const SGPath& path);
-
- void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
- void loadVersion2XMLRoute(SGPropertyNode_ptr routeData);
- void loadXMLRouteHeader(SGPropertyNode_ptr routeData);
- flightgear::WayptRef parseVersion1XMLWaypt(SGPropertyNode* aWP);
-
/**
* Predicate for helping the UI - test if at least one waypoint was
* entered by the user (as opposed to being generated by the route-manager)
const char* getDepartureName() const;
void setDepartureICAO(const char* aIdent);
+ const char* getDepartureRunway() const;
+ void setDepartureRunway(const char* aIdent);
+
+ const char* getSID() const;
+ void setSID(const char* aIdent);
+
const char* getDestinationICAO() const;
const char* getDestinationName() const;
void setDestinationICAO(const char* aIdent);
- PropertyWatcher* _departureWatcher;
- PropertyWatcher* _arrivalWatcher;
+ const char* getDestinationRunway() const;
+ void setDestinationRunway(const char* aIdent);
+
+ const char* getApproach() const;
+ void setApproach(const char* aIdent);
+
+ const char* getSTAR() const;
+ void setSTAR(const char* aIdent);
+
+ double getDepartureFieldElevation() const;
+ double getDestinationFieldElevation() const;
};
return;
}
- RoutePath path(_route->waypts());
+ RoutePath path(_route->flightPlan());
// first pass, draw the actual lines
glLineWidth(2.0);
static const double BLINK_TIME = 0.3;
static const int DRAG_START_DISTANCE_PX = 5;
-class RouteManagerWaypointModel :
+class FlightPlanWaypointModel :
public WaypointList::Model,
public SGPropertyChangeListener
{
public:
- RouteManagerWaypointModel()
- {
- _rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
-
+ FlightPlanWaypointModel(flightgear::FlightPlan* fp) :
+ _fp(fp)
+ {
SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
routeEdited->addChangeListener(this);
}
- virtual ~RouteManagerWaypointModel()
+ ~FlightPlanWaypointModel()
{
SGPropertyNode* routeEdited = fgGetNode("/autopilot/route-manager/signals/edited", true);
routeEdited->removeChangeListener(this);
// implement WaypointList::Model
virtual unsigned int numWaypoints() const
{
- return _rm->numWaypts();
+ return _fp->numLegs();
}
virtual int currentWaypoint() const
{
- return _rm->currentIndex();
+ return _fp->currentIndex();
}
virtual flightgear::Waypt* waypointAt(unsigned int index) const
return NULL;
}
- return _rm->wayptAtIndex(index);
+ return _fp->legAtIndex(index)->waypoint();
}
virtual void deleteAt(unsigned int index)
{
- _rm->removeWayptAtIndex(index);
+ _fp->deleteIndex(index);
}
virtual void moveWaypointToIndex(unsigned int srcIndex, unsigned int destIndex)
}
unsigned int currentWpIndex = currentWaypoint();
- WayptRef w(_rm->removeWayptAtIndex(srcIndex));
+ WayptRef w(waypointAt(currentWpIndex));
+ _fp->deleteIndex(currentWpIndex);
+
SG_LOG(SG_GENERAL, SG_INFO, "wpt:" << w->ident());
- _rm->insertWayptAtIndex(w, destIndex);
+ _fp->insertWayptAtIndex(w, destIndex);
if (srcIndex == currentWpIndex) {
// current waypoint was moved
- _rm->jumpToIndex(destIndex);
+ _fp->setCurrentIndex(destIndex);
}
}
}
}
private:
- FGRouteMgr* _rm;
+ flightgear::FlightPlan* _fp;
SGCallback* _cb;
};
{
// pretend to be a list, so fgPopup doesn't mess with our mouse events
type |= PUCLASS_LIST;
- setModel(new RouteManagerWaypointModel());
+ flightgear::FlightPlan* fp =
+ static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"))->flightPlan();
+ setModel(new FlightPlanWaypointModel(fp));
setSize(width, height);
setValue(-1);
virtual void valueChanged (SGPropertyNode * prop)
{
_nd->invalidatePositionedCache();
- SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache");
}
private:
NavDisplay* _nd;
virtual void valueChanged (SGPropertyNode * prop)
{
- SG_LOG(SG_INSTR, SG_INFO, "forcing NavDisplay update");
_nd->forceUpdate();
}
private:
SGVec3d cartNow(SGVec3d::fromGeod(_pos));
double movedNm = dist(_cachedPos, cartNow) * SG_METER_TO_NM;
_cachedItemsValid = (movedNm < 1.0);
- if (!_cachedItemsValid) {
- SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache due to moving: " << movedNm);
- }
}
_vertices->clear();
void NavDisplay::findItems()
{
if (!_cachedItemsValid) {
- SG_LOG(SG_INSTR, SG_INFO, "re-validating NavDisplay cache");
Filter filt;
filt.minRunwayLengthFt = 2000;
_itemsInRange = FGPositioned::findWithinRange(_pos, _rangeNm, &filt);
void NavDisplay::processRoute()
{
_routeSources.clear();
- RoutePath path(_route->waypts());
+ flightgear::FlightPlan* fp = _route->flightPlan();
+ RoutePath path(fp);
int current = _route->currentIndex();
- for (int w=0; w<_route->numWaypts(); ++w) {
- flightgear::WayptRef wpt(_route->wayptAtIndex(w));
+ for (int l=0; l<fp->numLegs(); ++l) {
+ flightgear::FlightPlan::Leg* leg = fp->legAtIndex(l);
+ flightgear::WayptRef wpt(leg->waypoint());
_routeSources.insert(wpt->source());
string_set state;
state.insert("on-active-route");
- if (w < current) {
+ if (l < current) {
state.insert("passed");
}
- if (w == current) {
+ if (l == current) {
state.insert("current-wp");
}
- if (w > current) {
+ if (l > current) {
state.insert("future");
}
- if (w == (current + 1)) {
+ if (l == (current + 1)) {
state.insert("next-wp");
}
return; // no rules matched, we can skip this item
}
- SGGeod g = path.positionForIndex(w);
- SGPropertyNode* vars = _route->wayptNodeAtIndex(w);
+ SGGeod g = path.positionForIndex(l);
+ SGPropertyNode* vars = _route->wayptNodeAtIndex(l);
+ if (!vars) {
+ continue; // shouldn't happen, but let's guard against it
+ }
+
double heading;
computeWayptPropsAndHeading(wpt, g, vars, heading);
addSymbolInstance(projected, heading, r->getDefinition(), vars);
if (r->getDefinition()->drawRouteLeg) {
- SGGeodVec gv(path.pathForIndex(w));
+ SGGeodVec gv(path.pathForIndex(l));
if (!gv.empty()) {
osg::Vec2 pr = projectGeod(gv[0]);
for (unsigned int i=1; i<gv.size(); ++i) {
states.insert("on-active-route");
}
+ flightgear::FlightPlan* fp = _route->flightPlan();
switch (pos->type()) {
case FGPositioned::VOR:
case FGPositioned::LOC:
// mark alternates!
// once the FMS system has some way to tell us about them, of course
- if (pos == _route->departureAirport()) {
+ if (pos == fp->departureAirport()) {
states.insert("departure");
}
- if (pos == _route->destinationAirport()) {
+ if (pos == fp->destinationAirport()) {
states.insert("destination");
}
break;
case FGPositioned::RUNWAY:
- if (pos == _route->departureRunway()) {
+ if (pos == fp->departureRunway()) {
states.insert("departure");
}
- if (pos == _route->destinationRunway()) {
+ if (pos == fp->destinationRunway()) {
states.insert("destination");
}
break;
SG_LOG(SG_INSTR, SG_INFO, "GPS waypoint index is now " << index);
if (index > 0) {
- _prevWaypt = _routeMgr->previousWaypt();
+ _prevWaypt = _routeMgr->wayptAtIndex(index - 1);
if (_prevWaypt->flag(WPT_DYNAMIC)) {
_wp0_position = _indicated_pos;
} else {
// check for wp1 being on active route - resume leg mode
if (_routeMgr->isRouteActive()) {
- int index = _routeMgr->findWayptIndex(_currentWaypt->position());
+ int index = _routeMgr->flightPlan()->findWayptIndex(_currentWaypt->position());
if (index >= 0) {
SG_LOG(SG_INSTR, SG_INFO, "GPS DTO, resuming LEG mode at wp:" << index);
_mode = "leg";
return;
}
- WayptRef next = _routeMgr->nextWaypt();
+ WayptRef next = _routeMgr->wayptAtIndex(_routeMgr->currentIndex() + 1);
if (!next || next->flag(WPT_DYNAMIC)) {
_anticipateTurn = false;
return;
string ident = _scratchNode->getStringValue("ident");
WayptRef wpt = new BasicWaypt(_scratchPos, ident, NULL);
- _routeMgr->insertWayptAtIndex(wpt, aIndex);
+ _routeMgr->flightPlan()->insertWayptAtIndex(wpt, aIndex);
}
void GPS::removeWaypointAtIndex(int aIndex)
throw sg_range_exception("GPS::removeWaypointAtIndex: index out of bounds");
}
- _routeMgr->removeWayptAtIndex(aIndex);
+ _routeMgr->removeLegAtIndex(aIndex);
}
void GPS::tieSGGeod(SGPropertyNode* aNode, SGGeod& aRef,
double curAlt = _rnav->position().getElevationFt();
switch (_waypt->altitudeRestriction()) {
- case RESTRICT_AT: {
+ case RESTRICT_AT:
+ case RESTRICT_COMPUTED:
+ {
double d = curAlt - _waypt->altitudeFt();
if (fabs(d) < 50.0) {
SG_LOG(SG_INSTR, SG_INFO, "ConstHdgToAltCtl, reached target altitude " << _waypt->altitudeFt());
}
break;
- case RESTRICT_NONE:
- assert(false);
- break;
- case SPEED_RESTRICT_MACH:
- assert(false);
+ default:
break;
}
}
route.cxx
routePath.cxx
waypoint.cxx
-)
+ LevelDXML.cxx
+ )
set(HEADERS
airways.hxx
route.hxx
routePath.hxx
waypoint.hxx
-)
+ LevelDXML.hxx
+ )
flightgear_component(Navaids "${SOURCES}" "${HEADERS}")
\ No newline at end of file
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "LevelDXML.hxx"
+
+#include <boost/algorithm/string.hpp>
+
+#include <simgear/structure/exception.hxx>
+#include <simgear/misc/sg_path.hxx>
+
+#include <Navaids/waypoint.hxx>
+#include <Airports/simple.hxx>
+
+using std::string;
+using std::vector;
+
+namespace flightgear
+{
+
+NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
+ _airport(aApt),
+ _path(aPath),
+ _sid(NULL),
+ _star(NULL),
+ _approach(NULL),
+ _transition(NULL),
+ _procedure(NULL)
+{
+}
+
+void NavdataVisitor::startXML()
+{
+}
+
+void NavdataVisitor::endXML()
+{
+}
+
+void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
+{
+ _text.clear();
+ string tag(name);
+ if (tag == "Airport") {
+ string icao(atts.getValue("ICAOcode"));
+ if (_airport->ident() != icao) {
+ throw sg_format_exception("Airport and ICAO mismatch", icao, _path.str());
+ }
+ } else if (tag == "Sid") {
+ string ident(atts.getValue("Name"));
+ _sid = new SID(ident, _airport);
+ _procedure = _sid;
+ _waypoints.clear();
+ processRunways(_sid, atts);
+ } else if (tag == "Star") {
+ string ident(atts.getValue("Name"));
+ _star = new STAR(ident, _airport);
+ _procedure = _star;
+ _waypoints.clear();
+ processRunways(_star, atts);
+ } else if ((tag == "Sid_Waypoint") ||
+ (tag == "App_Waypoint") ||
+ (tag == "Star_Waypoint") ||
+ (tag == "AppTr_Waypoint") ||
+ (tag == "SidTr_Waypoint") ||
+ (tag == "RwyTr_Waypoint"))
+ {
+ // reset waypoint data
+ _speed = 0.0;
+ _altRestrict = RESTRICT_NONE;
+ _altitude = 0.0;
+ } else if (tag == "Approach") {
+ _ident = atts.getValue("Name");
+ _waypoints.clear();
+ ProcedureType ty = PROCEDURE_APPROACH_RNAV;
+ _approach = new Approach(_ident, ty);
+ _procedure = _approach;
+ } else if ((tag == "Sid_Transition") ||
+ (tag == "App_Transition") ||
+ (tag == "Star_Transition")) {
+ _transIdent = atts.getValue("Name");
+ _transition = new Transition(_transIdent, PROCEDURE_TRANSITION, _procedure);
+ _transWaypts.clear();
+ } else if (tag == "RunwayTransition") {
+ _transIdent = atts.getValue("Runway");
+ _transition = new Transition(_transIdent, PROCEDURE_RUNWAY_TRANSITION, _procedure);
+ _transWaypts.clear();
+ } else {
+
+ }
+}
+
+void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
+{
+ string v("All");
+ if (atts.hasAttribute("Runways")) {
+ v = atts.getValue("Runways");
+ }
+
+ if (v == "All") {
+ for (unsigned int r=0; r<_airport->numRunways(); ++r) {
+ aProc->addRunway(_airport->getRunwayByIndex(r));
+ }
+ return;
+ }
+
+ vector<string> rwys;
+ boost::split(rwys, v, boost::is_any_of(" ,"));
+ for (unsigned int r=0; r<rwys.size(); ++r) {
+ FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
+ aProc->addRunway(rwy);
+ }
+}
+
+void NavdataVisitor::endElement(const char* name)
+{
+ string tag(name);
+ if ((tag == "Sid_Waypoint") ||
+ (tag == "App_Waypoint") ||
+ (tag == "Star_Waypoint"))
+ {
+ _waypoints.push_back(buildWaypoint(_procedure));
+ } else if ((tag == "AppTr_Waypoint") ||
+ (tag == "SidTr_Waypoint") ||
+ (tag == "RwyTr_Waypoint") ||
+ (tag == "StarTr_Waypoint"))
+ {
+ _transWaypts.push_back(buildWaypoint(_transition));
+ } else if (tag == "Sid_Transition") {
+ assert(_sid);
+ // SID waypoints are stored backwards, to share code with STARs
+ std::reverse(_transWaypts.begin(), _transWaypts.end());
+ _transition->setPrimary(_transWaypts);
+ _sid->addTransition(_transition);
+ } else if (tag == "Star_Transition") {
+ assert(_star);
+ _transition->setPrimary(_transWaypts);
+ _star->addTransition(_transition);
+ } else if (tag == "App_Transition") {
+ assert(_approach);
+ _transition->setPrimary(_transWaypts);
+ _approach->addTransition(_transition);
+ } else if (tag == "RunwayTransition") {
+ ArrivalDeparture* ad;
+ if (_sid) {
+ // SID waypoints are stored backwards, to share code with STARs
+ std::reverse(_transWaypts.begin(), _transWaypts.end());
+ ad = _sid;
+ } else {
+ ad = _star;
+ }
+
+ _transition->setPrimary(_transWaypts);
+ FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
+ ad->addRunwayTransition(rwy, _transition);
+ } else if (tag == "Approach") {
+ finishApproach();
+ } else if (tag == "Sid") {
+ finishSid();
+ } else if (tag == "Star") {
+ finishStar();
+ } else if (tag == "Longitude") {
+ _longitude = atof(_text.c_str());
+ } else if (tag == "Latitude") {
+ _latitude = atof(_text.c_str());
+ } else if (tag == "Name") {
+ _wayptName = _text;
+ } else if (tag == "Type") {
+ _wayptType = _text;
+ } else if (tag == "Speed") {
+ _speed = atoi(_text.c_str());
+ } else if (tag == "Altitude") {
+ _altitude = atof(_text.c_str());
+ } else if (tag == "AltitudeRestriction") {
+ if (_text == "at") {
+ _altRestrict = RESTRICT_AT;
+ } else if (_text == "above") {
+ _altRestrict = RESTRICT_ABOVE;
+ } else if (_text == "below") {
+ _altRestrict = RESTRICT_BELOW;
+ } else {
+ throw sg_format_exception("Unrecognized altitude restriction", _text);
+ }
+ } else if (tag == "Hld_Rad_or_Inbd") {
+ if (_text == "Inbd") {
+ _holdRadial = -1.0;
+ }
+ } else if (tag == "Hld_Time_or_Dist") {
+ _holdDistance = (_text == "Dist");
+ } else if (tag == "Hld_Rad_value") {
+ _holdRadial = atof(_text.c_str());
+ } else if (tag == "Hld_Turn") {
+ _holdRighthanded = (_text == "Right");
+ } else if (tag == "Hld_td_value") {
+ _holdTD = atof(_text.c_str());
+ } else if (tag == "Hdg_Crs_value") {
+ _course = atof(_text.c_str());
+ } else if (tag == "DMEtoIntercept") {
+ _dmeDistance = atof(_text.c_str());
+ } else if (tag == "RadialtoIntercept") {
+ _radial = atof(_text.c_str());
+ } else {
+
+ }
+}
+
+Waypt* NavdataVisitor::buildWaypoint(RouteBase* owner)
+{
+ Waypt* wp = NULL;
+ if (_wayptType == "Normal") {
+ // new LatLonWaypoint
+ SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
+ wp = new BasicWaypt(pos, _wayptName, owner);
+ } else if (_wayptType == "Runway") {
+ string ident = _wayptName.substr(2);
+ FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
+ wp = new RunwayWaypt(rwy, owner);
+ } else if (_wayptType == "Hold") {
+ SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
+ Hold* h = new Hold(pos, _wayptName, owner);
+ wp = h;
+ if (_holdRighthanded) {
+ h->setRightHanded();
+ } else {
+ h->setLeftHanded();
+ }
+
+ if (_holdDistance) {
+ h->setHoldDistance(_holdTD);
+ } else {
+ h->setHoldTime(_holdTD * 60.0);
+ }
+
+ if (_holdRadial >= 0.0) {
+ h->setHoldRadial(_holdRadial);
+ }
+ } else if (_wayptType == "Vectors") {
+ wp = new ATCVectors(owner, _airport);
+ } else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
+ SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
+ wp = new RadialIntercept(owner, _wayptName, pos, _course, _radial);
+ } else if (_wayptType == "DmeIntc") {
+ SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
+ wp = new DMEIntercept(owner, _wayptName, pos, _course, _dmeDistance);
+ } else if (_wayptType == "ConstHdgtoAlt") {
+ wp = new HeadingToAltitude(owner, _wayptName, _course);
+ } else if (_wayptType == "PBD") {
+ SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
+ double az2;
+ SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
+ wp = new BasicWaypt(pos2, _wayptName, owner);
+ } else {
+ SG_LOG(SG_GENERAL, SG_ALERT, "implement waypoint type:" << _wayptType);
+ throw sg_format_exception("Unrecognized waypt type", _wayptType);
+ }
+
+ assert(wp);
+ if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
+ wp->setAltitude(_altitude,_altRestrict);
+ }
+
+ if (_speed > 0.0) {
+ wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
+ }
+
+ return wp;
+}
+
+void NavdataVisitor::finishApproach()
+{
+ WayptVec::iterator it;
+ FGRunwayRef rwy;
+
+// find the runway node
+ for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
+ FGPositionedRef navid = (*it)->source();
+ if (!navid) {
+ continue;
+ }
+
+ if (navid->type() == FGPositioned::RUNWAY) {
+ rwy = (FGRunway*) navid.get();
+ break;
+ }
+ }
+
+ if (!rwy) {
+ throw sg_format_exception("Malformed approach, no runway waypt", _ident);
+ }
+
+ WayptVec primary(_waypoints.begin(), it);
+ // erase all points up to and including the runway, to leave only the
+ // missed segments
+ _waypoints.erase(_waypoints.begin(), ++it);
+
+ _approach->setRunway(rwy);
+ _approach->setPrimaryAndMissed(primary, _waypoints);
+ _airport->addApproach(_approach);
+ _approach = NULL;
+}
+
+void NavdataVisitor::finishSid()
+{
+ // reverse order, because that's how we deal with commonality between
+ // STARs and SIDs. SID::route undoes this
+ std::reverse(_waypoints.begin(), _waypoints.end());
+ _sid->setCommon(_waypoints);
+ _airport->addSID(_sid);
+ _sid = NULL;
+}
+
+void NavdataVisitor::finishStar()
+{
+ _star->setCommon(_waypoints);
+ _airport->addSTAR(_star);
+ _star = NULL;
+}
+
+void NavdataVisitor::data (const char * s, int len)
+{
+ _text += string(s, len);
+}
+
+
+void NavdataVisitor::pi (const char * target, const char * data) {
+ //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void NavdataVisitor::warning (const char * message, int line, int column) {
+ SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
+}
+
+void NavdataVisitor::error (const char * message, int line, int column) {
+ SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
+}
+
+}
--- /dev/null
+#ifndef FG_NAV_LEVELDXML_HXX
+#define FG_NAV_LEVELDXML_HXX
+
+class FGAirport;
+class SGPath;
+
+#include <simgear/xml/easyxml.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <Navaids/procedure.hxx>
+
+namespace flightgear
+{
+
+class NavdataVisitor : public XMLVisitor {
+public:
+ NavdataVisitor(FGAirport* aApt, const SGPath& aPath);
+
+protected:
+ virtual void startXML ();
+ virtual void endXML ();
+ virtual void startElement (const char * name, const XMLAttributes &atts);
+ virtual void endElement (const char * name);
+ virtual void data (const char * s, int len);
+ virtual void pi (const char * target, const char * data);
+ virtual void warning (const char * message, int line, int column);
+ virtual void error (const char * message, int line, int column);
+
+private:
+ Waypt* buildWaypoint(RouteBase* owner);
+ void processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts);
+
+ void finishApproach();
+ void finishSid();
+ void finishStar();
+
+ FGAirport* _airport;
+ SGPath _path;
+ std::string _text; ///< last element text value
+
+ SID* _sid;
+ STAR* _star;
+ Approach* _approach;
+ Transition* _transition;
+ Procedure* _procedure;
+
+ WayptVec _waypoints; ///< waypoint list for current approach/sid/star
+ WayptVec _transWaypts; ///< waypoint list for current transition
+
+ std::string _wayptName;
+ std::string _wayptType;
+ std::string _ident; // id of segment under construction
+ std::string _transIdent;
+ double _longitude, _latitude, _altitude, _speed;
+ RouteRestriction _altRestrict;
+
+ double _holdRadial; // inbound hold radial, or -1 if radial is 'inbound'
+ double _holdTD; ///< hold time (seconds) or distance (nm), based on flag below
+ bool _holdRighthanded;
+ bool _holdDistance; // true, TD is distance in nm; false, TD is time in seconds
+
+ double _course, _radial, _dmeDistance;
+};
+
+}
+
+#endif
\ No newline at end of file
class AdjacentWaypoint;
class InAirwayFilter;
-class Airway : public Route
+class Airway : public RouteBase
{
public:
virtual std::string ident() const
namespace flightgear
{
+
+static void markWaypoints(WayptVec& wps, WayptFlag f)
+{
+ for (unsigned int i=0; i<wps.size(); ++i) {
+ wps[i]->setFlag(f, true);
+ }
+}
Procedure::Procedure(const string& aIdent) :
_ident(aIdent)
{
}
-Approach::Approach(const string& aIdent) :
- Procedure(aIdent)
+Approach::Approach(const string& aIdent, ProcedureType ty) :
+ Procedure(aIdent),
+ _type(ty)
{
}
_runway = aRwy;
}
+FGAirport* Approach::airport() const
+{
+ return _runway->airport();
+}
+
+RunwayVec Approach::runways() const
+{
+ RunwayVec r;
+ r.push_back(_runway);
+ return r;
+}
+
void Approach::setPrimaryAndMissed(const WayptVec& aPrimary, const WayptVec& aMissed)
{
_primary = aPrimary;
_primary[0]->setFlag(WPT_IAF, true);
_primary[_primary.size()-1]->setFlag(WPT_FAF, true);
+ markWaypoints(_primary, WPT_APPROACH);
_missed = aMissed;
if (!_missed.empty()) {
// mark the first point as the published missed-approach point
_missed[0]->setFlag(WPT_MAP, true);
-
- // mark all the points as being on the missed approach route
- for (unsigned int i=0; i<_missed.size(); ++i) {
- _missed[i]->setFlag(WPT_MISS, true);
- }
+ markWaypoints(_missed, WPT_MISS);
+ markWaypoints(_missed, WPT_APPROACH);
}
}
{
WayptRef entry = aTrans->enroute();
_transitions[entry] = aTrans;
+ aTrans->mark(WPT_APPROACH);
}
bool Approach::route(WayptRef aIAF, WayptVec& aWps)
bool haveTrans = false;
for (it = _transitions.begin(); it != _transitions.end(); ++it) {
Transition* t= it->second;
- if (t->route(aIAF, aWps)) {
- haveTrans = true;
+ if (t->enroute()->matches(aIAF)) {
+ t->route(aWps);
+ haveTrans = true;
break;
}
} // of transitions iteration
return false;
}
- aWps.insert(aWps.end(), _primary.begin(), _primary.end());
- aWps.push_back(new RunwayWaypt(_runway, NULL));
- aWps.insert(aWps.end(), _missed.begin(), _missed.end());
- return true;
+ return routeFromVectors(aWps);
}
bool Approach::routeFromVectors(WayptVec& aWps)
return true;
}
+bool Approach::isApproach(ProcedureType ty)
+{
+ return (ty >= PROCEDURE_APPROACH_ILS) && (ty <= PROCEDURE_APPROACH_RNAV);
+}
+
//////////////////////////////////////////////////////////////////////////////
-ArrivalDeparture::ArrivalDeparture(const string& aIdent) :
- Procedure(aIdent)
+ArrivalDeparture::ArrivalDeparture(const string& aIdent, FGAirport* apt) :
+ Procedure(aIdent),
+ _airport(apt)
{
}
void ArrivalDeparture::addRunway(FGRunwayRef aWay)
{
+ assert(aWay->airport() == _airport);
_runways[aWay] = NULL;
}
-bool ArrivalDeparture::isForRunway(FGRunwayRef aWay) const
+bool ArrivalDeparture::isForRunway(const FGRunway* aWay) const
{
// null runway always passes
if (!aWay) {
return true;
}
- return (_runways.count(aWay));
+ FGRunwayRef r(const_cast<FGRunway*>(aWay));
+ return (_runways.count(r));
}
+RunwayVec ArrivalDeparture::runways() const
+{
+ RunwayVec r;
+ RunwayTransitionMap::const_iterator it = _runways.begin();
+ for (; it != _runways.end(); ++it) {
+ r.push_back(it->first);
+ }
+
+ return r;
+}
+
void ArrivalDeparture::addTransition(Transition* aTrans)
{
WayptRef entry = aTrans->enroute();
+ aTrans->mark(flagType());
_enrouteTransitions[entry] = aTrans;
}
+string_list ArrivalDeparture::transitionIdents() const
+{
+ string_list r;
+ WptTransitionMap::const_iterator eit;
+ for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
+ r.push_back(eit->second->ident());
+ }
+ return r;
+}
+
void ArrivalDeparture::addRunwayTransition(FGRunwayRef aWay, Transition* aTrans)
{
assert(aWay->ident() == aTrans->ident());
throw sg_io_exception("adding transition for unspecified runway:" + aWay->ident(), ident());
}
+ aTrans->mark(flagType());
_runways[aWay] = aTrans;
}
void ArrivalDeparture::setCommon(const WayptVec& aWps)
{
_common = aWps;
+ markWaypoints(_common, flagType());
}
-bool ArrivalDeparture::commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef aRwy)
+bool ArrivalDeparture::commonRoute(Transition* t, WayptVec& aPath, FGRunwayRef aRwy)
{
// assume we're routing from enroute, to the runway.
// for departures, we'll flip the result points
- Transition* t = findTransitionByEnroute(aEnroute);
WayptVec::iterator firstCommon = _common.begin();
if (t) {
- t->route(aEnroute, aPath);
+ t->route(aPath);
Waypt* transEnd = t->procedureEnd();
for (; firstCommon != _common.end(); ++firstCommon) {
// common section after the transition.
firstCommon = _common.begin();
} else {
- if (aEnroute && !(*firstCommon)->matches(aEnroute)) {
- return false;
- }
+ // no tranasition
} // of not using a transition
// append (some) common points
}
SG_LOG(SG_GENERAL, SG_INFO, ident() << " using runway transition for " << r->first->ident());
- r->second->route(NULL, aPath);
+ r->second->route(aPath);
return true;
}
return w;
}
-WayptRef ArrivalDeparture::findTransitionByName(const string& aIdent) const
+Transition* ArrivalDeparture::findTransitionByName(const string& aIdent) const
{
WptTransitionMap::const_iterator eit;
for (eit = _enrouteTransitions.begin(); eit != _enrouteTransitions.end(); ++eit) {
- WayptRef c = eit->second->enroute();
- if (c->ident() == aIdent) {
- return c;
+ if (eit->second->ident() == aIdent) {
+ return eit->second;
}
}
////////////////////////////////////////////////////////////////////////////
-SID::SID(const string& aIdent) :
- ArrivalDeparture(aIdent)
+SID::SID(const string& aIdent, FGAirport* apt) :
+ ArrivalDeparture(aIdent, apt)
{
}
-bool SID::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
+bool SID::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
{
if (!isForRunway(aWay)) {
SG_LOG(SG_GENERAL, SG_WARN, "SID " << ident() << " not for runway " << aWay->ident());
}
WayptVec path;
- if (!commonRoute(aEnroute, path, aWay)) {
+ if (!commonRoute(trans, path, aWay)) {
return false;
}
////////////////////////////////////////////////////////////////////////////
-STAR::STAR(const string& aIdent) :
- ArrivalDeparture(aIdent)
+STAR::STAR(const string& aIdent, FGAirport* apt) :
+ ArrivalDeparture(aIdent, apt)
{
}
-bool STAR::route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath)
+bool STAR::route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath)
{
if (aWay && !isForRunway(aWay)) {
return false;
}
- return commonRoute(aEnroute, aPath, aWay);
+ return commonRoute(trans, aPath, aWay);
}
/////////////////////////////////////////////////////////////////////////////
-Transition::Transition(const std::string& aIdent, Procedure* aPr) :
- _ident(aIdent),
+Transition::Transition(const std::string& aIdent, ProcedureType ty, Procedure* aPr) :
+ Procedure(aIdent),
+ _type(ty),
_parent(aPr)
{
assert(aPr);
return _primary[_primary.size() - 1];
}
-bool Transition::route(Waypt* aEnroute, WayptVec& aPath)
+bool Transition::route(WayptVec& aPath)
{
- if (aEnroute && !enroute()->matches(aEnroute)) {
- return false;
- }
-
aPath.insert(aPath.end(), _primary.begin(), _primary.end());
return true;
}
+FGAirport* Transition::airport() const
+{
+ return _parent->airport();
+}
+
+void Transition::mark(WayptFlag f)
+{
+ markWaypoints(_primary, f);
+}
+
} // of namespace
#include <set>
+#include <simgear/math/sg_types.hxx> // for string_list
+
#include <Navaids/route.hxx>
#include <Airports/runways.hxx>
// forward decls
class NavdataVisitor;
-class Procedure : public Route
+typedef std::vector<FGRunwayRef> RunwayVec;
+
+typedef enum {
+ PROCEDURE_INVALID,
+ PROCEDURE_APPROACH_ILS,
+ PROCEDURE_APPROACH_VOR,
+ PROCEDURE_APPROACH_NDB,
+ PROCEDURE_APPROACH_RNAV,
+ PROCEDURE_SID,
+ PROCEDURE_STAR,
+ PROCEDURE_TRANSITION,
+ PROCEDURE_RUNWAY_TRANSITION
+} ProcedureType;
+
+class Procedure : public RouteBase
{
-public:
-
+public:
+ virtual ProcedureType type() const = 0;
+
virtual std::string ident() const
{ return _ident; }
+
+ virtual FGAirport* airport() const = 0;
+
+ virtual RunwayVec runways() const
+ { return RunwayVec(); }
protected:
Procedure(const std::string& aIdent);
/**
* Encapsulate a transition segment
*/
-class Transition : public Route
+class Transition : public Procedure
{
public:
- bool route(Waypt* aEnroute, WayptVec& aPath);
+ bool route(WayptVec& aPath);
Procedure* parent() const
{ return _parent; }
+ virtual FGAirport* airport() const;
+
/**
* Return the enroute end of the transition
*/
*/
WayptRef procedureEnd() const;
- virtual std::string ident() const
- { return _ident; }
+
+ virtual ProcedureType type() const
+ { return _type; }
+
+ void mark(WayptFlag f);
private:
friend class NavdataVisitor;
- Transition(const std::string& aIdent, Procedure* aPr);
+ Transition(const std::string& aIdent, ProcedureType ty, Procedure* aPr);
void setPrimary(const WayptVec& aWps);
- std::string _ident;
+ ProcedureType _type;
Procedure* _parent;
WayptVec _primary;
};
FGRunwayRef runway()
{ return _runway; }
+ static bool isApproach(ProcedureType ty);
+
+ virtual FGAirport* airport() const;
+
+ virtual RunwayVec runways() const;
+
/**
* Build a route from a valid IAF to the runway, including the missed
* segment. Return false if no valid transition from the specified IAF
const WayptVec& missed() const
{ return _missed; }
+ virtual ProcedureType type() const
+ { return _type; }
private:
friend class NavdataVisitor;
- Approach(const std::string& aIdent);
+ Approach(const std::string& aIdent, ProcedureType ty);
void setRunway(FGRunwayRef aRwy);
void setPrimaryAndMissed(const WayptVec& aPrimary, const WayptVec& aMissed);
void addTransition(Transition* aTrans);
FGRunwayRef _runway;
+ ProcedureType _type;
typedef std::map<WayptRef, Transition*> WptTransitionMap;
WptTransitionMap _transitions;
class ArrivalDeparture : public Procedure
{
public:
+ virtual FGAirport* airport() const
+ { return _airport; }
+
/**
* Predicate, test if this procedure applies to the requested runway
*/
- virtual bool isForRunway(FGRunwayRef aWay) const;
+ virtual bool isForRunway(const FGRunway* aWay) const;
+
+ virtual RunwayVec runways() const;
/**
* Find a path between the runway and enroute structure. Waypoints
* corresponding to the appropriate transitions and segments will be created.
*/
- virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath) = 0;
+ virtual bool route(FGRunwayRef aWay, Transition* trans, WayptVec& aPath) = 0;
const WayptVec& common() const
{ return _common; }
+ string_list transitionIdents() const;
+
/**
* Given an enroute location, find the best enroute transition point for
* this arrival/departure. Best is currently determined as 'closest to the
* for the route-manager and similar code that that needs to talk about
* transitions in a human-meaningful way (including persistence).
*/
- WayptRef findTransitionByName(const std::string& aIdent) const;
+ Transition* findTransitionByName(const std::string& aIdent) const;
Transition* findTransitionByEnroute(Waypt* aEnroute) const;
protected:
- bool commonRoute(Waypt* aEnroute, WayptVec& aPath, FGRunwayRef aRwy);
+ bool commonRoute(Transition* t, WayptVec& aPath, FGRunwayRef aRwy);
- ArrivalDeparture(const std::string& aIdent);
+ ArrivalDeparture(const std::string& aIdent, FGAirport* apt);
void addRunway(FGRunwayRef aRwy);
typedef std::map<FGRunwayRef, Transition*> RunwayTransitionMap;
RunwayTransitionMap _runways;
+ virtual WayptFlag flagType() const = 0;
private:
friend class NavdataVisitor;
void addRunwayTransition(FGRunwayRef aRwy, Transition* aTrans);
+ FGAirport* _airport;
WayptVec _common;
typedef std::map<WayptRef, Transition*> WptTransitionMap;
class SID : public ArrivalDeparture
{
public:
- virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath);
+ virtual bool route(FGRunwayRef aWay, Transition* aTrans, WayptVec& aPath);
+
+ virtual ProcedureType type() const
+ { return PROCEDURE_SID; }
+
+protected:
+ virtual WayptFlag flagType() const
+ { return WPT_DEPARTURE; }
private:
friend class NavdataVisitor;
- SID(const std::string& aIdent);
+ SID(const std::string& aIdent, FGAirport* apt);
};
class STAR : public ArrivalDeparture
{
public:
- virtual bool route(FGRunwayRef aWay, Waypt* aEnroute, WayptVec& aPath);
+ virtual bool route(FGRunwayRef aWay, Transition* aTrans, WayptVec& aPath);
+
+ virtual ProcedureType type() const
+ { return PROCEDURE_STAR; }
+
+protected:
+ virtual WayptFlag flagType() const
+ { return WPT_ARRIVAL; }
private:
friend class NavdataVisitor;
- STAR(const std::string& aIdent);
+ STAR(const std::string& aIdent, FGAirport* apt);
};
} // of namespace
// Boost
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
// SimGear
#include <simgear/structure/exception.hxx>
-#include <simgear/xml/easyxml.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/magvar/magvar.hxx>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/misc/strutils.hxx>
+#include <simgear/props/props_io.hxx>
// FlightGear
#include <Main/globals.hxx>
+#include "Main/fg_props.hxx"
#include <Navaids/procedure.hxx>
#include <Navaids/waypoint.hxx>
+#include <Navaids/LevelDXML.hxx>
#include <Airports/simple.hxx>
using std::string;
const double NO_MAG_VAR = -1000.0; // an impossible mag-var value
-Waypt::Waypt(Route* aOwner) :
+bool isMachRestrict(RouteRestriction rr)
+{
+ return (rr == SPEED_RESTRICT_MACH) || (rr == SPEED_COMPUTED_MACH);
+}
+
+Waypt::Waypt(RouteBase* aOwner) :
_altitudeFt(0.0),
_speed(0.0),
_altRestrict(RESTRICT_NONE),
}
}
-Waypt* Waypt::createInstance(Route* aOwner, const std::string& aTypeName)
+Waypt* Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName)
{
Waypt* r = NULL;
if (aTypeName == "basic") {
return r;
}
-WayptRef Waypt::createFromProperties(Route* aOwner, SGPropertyNode_ptr aProp)
+WayptRef Waypt::createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp)
{
if (!aProp->hasChild("type")) {
throw sg_io_exception("bad props node, no type provided",
setFlag(WPT_ARRIVAL, aProp->getBoolValue("arrival"));
}
+ if (aProp->hasChild("approach")) {
+ setFlag(WPT_APPROACH, aProp->getBoolValue("approach"));
+ }
+
if (aProp->hasChild("departure")) {
setFlag(WPT_DEPARTURE, aProp->getBoolValue("departure"));
}
aProp->setBoolValue("arrival", true);
}
+ if (flag(WPT_APPROACH)) {
+ aProp->setBoolValue("approach", true);
+ }
+
if (flag(WPT_MISS)) {
aProp->setBoolValue("miss", true);
}
}
}
-void Route::dumpRouteToFile(const WayptVec& aRoute, const std::string& aName)
+void RouteBase::dumpRouteToKML(const WayptVec& aRoute, const std::string& aName)
{
SGPath p = "/Users/jmt/Desktop/" + aName + ".kml";
std::fstream f;
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
"<Document>\n";
- dumpRouteToLineString(aName, aRoute, f);
+ dumpRouteToKMLLineString(aName, aRoute, f);
// post-amble
f << "</Document>\n"
f.close();
}
-void Route::dumpRouteToLineString(const std::string& aIdent,
+void RouteBase::dumpRouteToKMLLineString(const std::string& aIdent,
const WayptVec& aRoute, std::ostream& aStream)
{
// preamble
"</Placemark>\n" << endl;
}
-///////////////////////////////////////////////////////////////////////////
-
-class NavdataVisitor : public XMLVisitor {
-public:
- NavdataVisitor(FGAirport* aApt, const SGPath& aPath);
-
-protected:
- virtual void startXML ();
- virtual void endXML ();
- virtual void startElement (const char * name, const XMLAttributes &atts);
- virtual void endElement (const char * name);
- virtual void data (const char * s, int len);
- virtual void pi (const char * target, const char * data);
- virtual void warning (const char * message, int line, int column);
- virtual void error (const char * message, int line, int column);
-
-private:
- Waypt* buildWaypoint(Route* owner);
- void processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts);
-
- void finishApproach();
- void finishSid();
- void finishStar();
-
- FGAirport* _airport;
- SGPath _path;
- string _text; ///< last element text value
-
- SID* _sid;
- STAR* _star;
- Approach* _approach;
- Transition* _transition;
- Procedure* _procedure;
-
- WayptVec _waypoints; ///< waypoint list for current approach/sid/star
- WayptVec _transWaypts; ///< waypoint list for current transition
-
- string _wayptName;
- string _wayptType;
- string _ident; // id of segment under construction
- string _transIdent;
- double _longitude, _latitude, _altitude, _speed;
- RouteRestriction _altRestrict;
-
- double _holdRadial; // inbound hold radial, or -1 if radial is 'inbound'
- double _holdTD; ///< hold time (seconds) or distance (nm), based on flag below
- bool _holdRighthanded;
- bool _holdDistance; // true, TD is distance in nm; false, TD is time in seconds
-
- double _course, _radial, _dmeDistance;
-};
-
-void Route::loadAirportProcedures(const SGPath& aPath, FGAirport* aApt)
+void RouteBase::loadAirportProcedures(const SGPath& aPath, FGAirport* aApt)
{
assert(aApt);
try {
}
}
-NavdataVisitor::NavdataVisitor(FGAirport* aApt, const SGPath& aPath):
- _airport(aApt),
- _path(aPath),
+////////////////////////////////////////////////////////////////////////////
+
+FlightPlan::FlightPlan() :
+ _currentIndex(-1),
+ _departureRunway(NULL),
+ _destinationRunway(NULL),
_sid(NULL),
_star(NULL),
_approach(NULL),
- _transition(NULL),
- _procedure(NULL)
+ _delegate(NULL)
{
+
}
-
-void NavdataVisitor::startXML()
+
+FlightPlan::~FlightPlan()
+{
+
+}
+
+FlightPlan* FlightPlan::clone(const string& newIdent) const
{
+ FlightPlan* c = new FlightPlan();
+ c->_ident = newIdent.empty() ? _ident : newIdent;
+
+// copy destination / departure data.
+ c->setDeparture(_departure);
+ c->setDeparture(_departureRunway);
+
+ if (_approach) {
+ c->setApproach(_approach);
+ } else if (_destinationRunway) {
+ c->setDestination(_destinationRunway);
+ } else if (_destination) {
+ c->setDestination(_destination);
+ }
+
+ c->setSTAR(_star);
+ c->setSID(_sid);
+
+// copy legs
+ for (int l=0; l < numLegs(); ++l) {
+ c->_legs.push_back(_legs[l]->cloneFor(c));
+ }
+
+ return c;
}
-void NavdataVisitor::endXML()
+void FlightPlan::setIdent(const string& s)
+{
+ _ident = s;
+}
+
+string FlightPlan::ident() const
+{
+ return _ident;
+}
+
+FlightPlan::Leg* FlightPlan::insertWayptAtIndex(Waypt* aWpt, int aIndex)
+{
+ if (!aWpt) {
+ return NULL;
+ }
+
+ WayptVec wps;
+ wps.push_back(aWpt);
+
+ int index = aIndex;
+ if ((aIndex == -1) || (aIndex > (int) _legs.size())) {
+ index = _legs.size();
+ }
+
+ insertWayptsAtIndex(wps, index);
+ return legAtIndex(aIndex);
+}
+
+void FlightPlan::insertWayptsAtIndex(const WayptVec& wps, int aIndex)
{
+ if (wps.empty()) {
+ return;
+ }
+
+ int index = aIndex;
+ if ((aIndex == -1) || (aIndex > (int) _legs.size())) {
+ index = _legs.size();
+ }
+
+ LegVec::iterator it = _legs.begin();
+ it += index;
+
+ int endIndex = index + wps.size() - 1;
+ if (_currentIndex >= endIndex) {
+ _currentIndex += wps.size();
+ }
+
+ LegVec newLegs;
+ BOOST_FOREACH(WayptRef wp, wps) {
+ newLegs.push_back(new Leg(this, wp));
+ }
+
+ _legs.insert(it, newLegs.begin(), newLegs.end());
+ rebuildLegData();
+
+ if (_delegate) {
+ _delegate->runWaypointsChanged();
+ }
}
-void NavdataVisitor::startElement(const char* name, const XMLAttributes &atts)
+void FlightPlan::deleteIndex(int aIndex)
{
- _text.clear();
- string tag(name);
- if (tag == "Airport") {
- string icao(atts.getValue("ICAOcode"));
- if (_airport->ident() != icao) {
- throw sg_format_exception("Airport and ICAO mismatch", icao, _path.str());
+ int index = aIndex;
+ if (aIndex < 0) { // negative indices count the the end
+ index = _legs.size() + index;
+ }
+
+ if ((index < 0) || (index >= numLegs())) {
+ SG_LOG(SG_AUTOPILOT, SG_WARN, "removeAtIndex with invalid index:" << aIndex);
+ return;
+ }
+ LegVec::iterator it = _legs.begin();
+ it += index;
+ Leg* l = *it;
+ _legs.erase(it);
+ delete l;
+
+ bool curChanged = false;
+ if (_currentIndex == index) {
+ // current waypoint was removed
+ curChanged = true;
+ } else if (_currentIndex > index) {
+ --_currentIndex; // shift current index down if necessary
+ }
+
+ rebuildLegData();
+ if (_delegate) {
+ _delegate->runWaypointsChanged();
+ if (curChanged) {
+ _delegate->runCurrentWaypointChanged();
+ }
+ }
+}
+
+void FlightPlan::clear()
+{
+ _currentIndex = -1;
+ BOOST_FOREACH(Leg* l, _legs) {
+ delete l;
+ }
+ _legs.clear();
+ rebuildLegData();
+ if (_delegate) {
+ _delegate->runDepartureChanged();
+ _delegate->runArrivalChanged();
+ _delegate->runWaypointsChanged();
+ _delegate->runCurrentWaypointChanged();
+ }
+}
+
+int FlightPlan::clearWayptsWithFlag(WayptFlag flag)
+{
+ int count = 0;
+ for (unsigned int i=0; i<_legs.size(); ++i) {
+ Leg* l = _legs[i];
+ if (!l->waypoint()->flag(flag)) {
+ continue;
}
- } else if (tag == "Sid") {
- string ident(atts.getValue("Name"));
- _sid = new SID(ident);
- _procedure = _sid;
- _waypoints.clear();
- processRunways(_sid, atts);
- } else if (tag == "Star") {
- string ident(atts.getValue("Name"));
- _star = new STAR(ident);
- _procedure = _star;
- _waypoints.clear();
- processRunways(_star, atts);
- } else if ((tag == "Sid_Waypoint") ||
- (tag == "App_Waypoint") ||
- (tag == "Star_Waypoint") ||
- (tag == "AppTr_Waypoint") ||
- (tag == "SidTr_Waypoint") ||
- (tag == "RwyTr_Waypoint"))
- {
- // reset waypoint data
- _speed = 0.0;
- _altRestrict = RESTRICT_NONE;
- _altitude = 0.0;
- } else if (tag == "Approach") {
- _ident = atts.getValue("Name");
- _waypoints.clear();
- _approach = new Approach(_ident);
- _procedure = _approach;
- } else if ((tag == "Sid_Transition") ||
- (tag == "App_Transition") ||
- (tag == "Star_Transition")) {
- _transIdent = atts.getValue("Name");
- _transition = new Transition(_transIdent, _procedure);
- _transWaypts.clear();
- } else if (tag == "RunwayTransition") {
- _transIdent = atts.getValue("Runway");
- _transition = new Transition(_transIdent, _procedure);
- _transWaypts.clear();
- } else {
+ // okay, we're going to clear this leg
+ ++count;
+ if (_currentIndex > (int) i) {
+ --_currentIndex;
+ }
+
+ delete l;
+ LegVec::iterator it = _legs.begin();
+ it += i;
+ _legs.erase(it);
}
+
+ if (count == 0) {
+ return 0; // nothing was cleared, don't fire the delegate
+ }
+
+ rebuildLegData();
+ if (_delegate) {
+ _delegate->runWaypointsChanged();
+ _delegate->runCurrentWaypointChanged();
+ }
+
+ return count;
+}
+
+void FlightPlan::setCurrentIndex(int index)
+{
+ if ((index < 0) || (index >= numLegs())) {
+ throw sg_range_exception("invalid leg index", "FlightPlan::setCurrentIndex");
+ }
+
+ if (index == _currentIndex) {
+ return;
+ }
+
+ _currentIndex = index;
+ if (_delegate) {
+ _delegate->runCurrentWaypointChanged();
+ }
+}
+
+int FlightPlan::findWayptIndex(const SGGeod& aPos) const
+{
+ for (int i=0; i<numLegs(); ++i) {
+ if (_legs[i]->waypoint()->matches(aPos)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+FlightPlan::Leg* FlightPlan::currentLeg() const
+{
+ if ((_currentIndex < 0) || (_currentIndex >= numLegs()))
+ return NULL;
+ return legAtIndex(_currentIndex);
}
-void NavdataVisitor::processRunways(ArrivalDeparture* aProc, const XMLAttributes &atts)
+FlightPlan::Leg* FlightPlan::previousLeg() const
{
- string v("All");
- if (atts.hasAttribute("Runways")) {
- v = atts.getValue("Runways");
+ if (_currentIndex == 0) {
+ return NULL;
}
- if (v == "All") {
- for (unsigned int r=0; r<_airport->numRunways(); ++r) {
- aProc->addRunway(_airport->getRunwayByIndex(r));
+ return legAtIndex(_currentIndex - 1);
+}
+
+FlightPlan::Leg* FlightPlan::nextLeg() const
+{
+ if ((_currentIndex < 0) || ((_currentIndex + 1) >= numLegs())) {
+ return NULL;
+ }
+
+ return legAtIndex(_currentIndex + 1);
+}
+
+FlightPlan::Leg* FlightPlan::legAtIndex(int index) const
+{
+ if ((index < 0) || (index >= numLegs())) {
+ throw sg_range_exception("index out of range", "FlightPlan::legAtIndex");
+ }
+
+ return _legs[index];
+}
+
+int FlightPlan::findLegIndex(const Leg *l) const
+{
+ for (unsigned int i=0; i<_legs.size(); ++i) {
+ if (_legs[i] == l) {
+ return i;
}
+ }
+
+ return -1;
+}
+
+void FlightPlan::setDeparture(FGAirport* apt)
+{
+ if (apt == _departure) {
return;
}
- vector<string> rwys;
- boost::split(rwys, v, boost::is_any_of(" ,"));
- for (unsigned int r=0; r<rwys.size(); ++r) {
- FGRunway* rwy = _airport->getRunwayByIdent(rwys[r]);
- aProc->addRunway(rwy);
+ _departure = apt;
+ _departureRunway = NULL;
+ setSID((SID*)NULL);
+
+ if (_delegate) {
+ _delegate->runDepartureChanged();
+ }
+}
+
+void FlightPlan::setDeparture(FGRunway* rwy)
+{
+ if (_departureRunway == rwy) {
+ return;
+ }
+
+ _departureRunway = rwy;
+ if (rwy->airport() != _departure) {
+ _departure = rwy->airport();
+ setSID((SID*)NULL);
+ }
+
+ if (_delegate) {
+ _delegate->runDepartureChanged();
+ }
+}
+
+void FlightPlan::setSID(SID* sid, const std::string& transition)
+{
+ if (sid == _sid) {
+ return;
+ }
+
+ _sid = sid;
+ _sidTransition = transition;
+
+ if (_delegate) {
+ _delegate->runDepartureChanged();
+ }
+}
+
+void FlightPlan::setSID(Transition* trans)
+{
+ if (!trans) {
+ setSID((SID*) NULL);
+ return;
+ }
+
+ if (trans->parent()->type() != PROCEDURE_SID)
+ throw sg_exception("FlightPlan::setSID: transition does not belong to a SID");
+
+ setSID((SID*) trans->parent(), trans->ident());
+}
+
+Transition* FlightPlan::sidTransition() const
+{
+ if (!_sid || _sidTransition.empty()) {
+ return NULL;
+ }
+
+ return _sid->findTransitionByName(_sidTransition);
+}
+
+void FlightPlan::setDestination(FGAirport* apt)
+{
+ if (apt == _destination) {
+ return;
+ }
+
+ _destination = apt;
+ _destinationRunway = NULL;
+ setSTAR((STAR*)NULL);
+
+ if (_delegate) {
+ _delegate->runArrivalChanged();
+ }
+}
+
+void FlightPlan::setDestination(FGRunway* rwy)
+{
+ if (_destinationRunway == rwy) {
+ return;
+ }
+
+ _destinationRunway = rwy;
+ if (_destination != rwy->airport()) {
+ _destination = rwy->airport();
+ setSTAR((STAR*)NULL);
+ }
+
+ if (_delegate) {
+ _delegate->runArrivalChanged();
+ }
+}
+
+void FlightPlan::setSTAR(STAR* star, const std::string& transition)
+{
+ if (_star == star) {
+ return;
+ }
+
+ _star = star;
+ _starTransition = transition;
+
+ if (_delegate) {
+ _delegate->runArrivalChanged();
+ }
+}
+
+void FlightPlan::setSTAR(Transition* trans)
+{
+ if (!trans) {
+ setSTAR((STAR*) NULL);
+ return;
+ }
+
+ if (trans->parent()->type() != PROCEDURE_STAR)
+ throw sg_exception("FlightPlan::setSTAR: transition does not belong to a STAR");
+
+ setSTAR((STAR*) trans->parent(), trans->ident());
+}
+
+Transition* FlightPlan::starTransition() const
+{
+ if (!_star || _starTransition.empty()) {
+ return NULL;
}
+
+ return _star->findTransitionByName(_starTransition);
}
+
+void FlightPlan::setApproach(flightgear::Approach *app)
+{
+ if (_approach == app) {
+ return;
+ }
+
+ _approach = app;
+ if (app) {
+ // keep runway + airport in sync
+ if (_destinationRunway != _approach->runway()) {
+ _destinationRunway = _approach->runway();
+ }
+
+ if (_destination != _destinationRunway->airport()) {
+ _destination = _destinationRunway->airport();
+ }
+ }
-void NavdataVisitor::endElement(const char* name)
+ if (_delegate) {
+ _delegate->runArrivalChanged();
+ }
+}
+
+bool FlightPlan::save(const SGPath& path)
+{
+ SG_LOG(SG_IO, SG_INFO, "Saving route to " << path.str());
+ try {
+ SGPropertyNode_ptr d(new SGPropertyNode);
+ d->setIntValue("version", 2);
+
+ if (_departure) {
+ d->setStringValue("departure/airport", _departure->ident());
+ if (_sid) {
+ d->setStringValue("departure/sid", _sid->ident());
+ }
+
+ if (_departureRunway) {
+ d->setStringValue("departure/runway", _departureRunway->ident());
+ }
+ }
+
+ if (_destination) {
+ d->setStringValue("destination/airport", _destination->ident());
+ if (_star) {
+ d->setStringValue("destination/star", _star->ident());
+ }
+
+ if (_approach) {
+ d->setStringValue("destination/approach", _approach->ident());
+ }
+
+ //d->setStringValue("destination/transition", destination->getStringValue("transition"));
+
+ if (_destinationRunway) {
+ d->setStringValue("destination/runway", _destinationRunway->ident());
+ }
+ }
+
+ // route nodes
+ SGPropertyNode* routeNode = d->getChild("route", 0, true);
+ for (unsigned int i=0; i<_legs.size(); ++i) {
+ Waypt* wpt = _legs[i]->waypoint();
+ wpt->saveAsNode(routeNode->getChild("wp", i, true));
+ } // of waypoint iteration
+ writeProperties(path.str(), d, true /* write-all */);
+ return true;
+ } catch (sg_exception& e) {
+ SG_LOG(SG_IO, SG_ALERT, "Failed to save flight-plan '" << path.str() << "'. " << e.getMessage());
+ return false;
+ }
+}
+
+bool FlightPlan::load(const SGPath& path)
{
- string tag(name);
- if ((tag == "Sid_Waypoint") ||
- (tag == "App_Waypoint") ||
- (tag == "Star_Waypoint"))
+ if (!path.exists())
{
- _waypoints.push_back(buildWaypoint(_procedure));
- } else if ((tag == "AppTr_Waypoint") ||
- (tag == "SidTr_Waypoint") ||
- (tag == "RwyTr_Waypoint") ||
- (tag == "StarTr_Waypoint"))
+ SG_LOG(SG_IO, SG_ALERT, "Failed to load flight-plan '" << path.str()
+ << "'. The file does not exist.");
+ return false;
+ }
+
+ SGPropertyNode_ptr routeData(new SGPropertyNode);
+ SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
+
+ bool Status = false;
+ try {
+ readProperties(path.str(), routeData);
+ } catch (sg_exception& ) {
+ // if XML parsing fails, the file might be simple textual list of waypoints
+ Status = loadPlainTextRoute(path);
+ routeData = 0;
+ }
+
+ if (routeData.valid())
{
- _transWaypts.push_back(buildWaypoint(_transition));
- } else if (tag == "Sid_Transition") {
- assert(_sid);
- // SID waypoints are stored backwards, to share code with STARs
- std::reverse(_transWaypts.begin(), _transWaypts.end());
- _transition->setPrimary(_transWaypts);
- _sid->addTransition(_transition);
- } else if (tag == "Star_Transition") {
- assert(_star);
- _transition->setPrimary(_transWaypts);
- _star->addTransition(_transition);
- } else if (tag == "App_Transition") {
- assert(_approach);
- _transition->setPrimary(_transWaypts);
- _approach->addTransition(_transition);
- } else if (tag == "RunwayTransition") {
- ArrivalDeparture* ad;
- if (_sid) {
- // SID waypoints are stored backwards, to share code with STARs
- std::reverse(_transWaypts.begin(), _transWaypts.end());
- ad = _sid;
- } else {
- ad = _star;
+ try {
+ int version = routeData->getIntValue("version", 1);
+ if (version == 1) {
+ loadVersion1XMLRoute(routeData);
+ } else if (version == 2) {
+ loadVersion2XMLRoute(routeData);
+ } else {
+ throw sg_io_exception("unsupported XML route version");
+ }
+ Status = true;
+ } catch (sg_exception& e) {
+ SG_LOG(SG_IO, SG_ALERT, "Failed to load flight-plan '" << e.getOrigin()
+ << "'. " << e.getMessage());
+ Status = false;
}
+ }
+
+ rebuildLegData();
+ if (_delegate) {
+ _delegate->runWaypointsChanged();
+ }
+
+ return Status;
+}
+
+void FlightPlan::loadXMLRouteHeader(SGPropertyNode_ptr routeData)
+{
+ // departure nodes
+ SGPropertyNode* dep = routeData->getChild("departure");
+ if (dep) {
+ string depIdent = dep->getStringValue("airport");
+ setDeparture((FGAirport*) fgFindAirportID(depIdent));
+ if (_departure) {
+ if (dep->hasChild("runway")) {
+ setDeparture(_departure->getRunwayByIdent(dep->getStringValue("runway")));
+ }
- _transition->setPrimary(_transWaypts);
- FGRunwayRef rwy = _airport->getRunwayByIdent(_transIdent);
- ad->addRunwayTransition(rwy, _transition);
- } else if (tag == "Approach") {
- finishApproach();
- } else if (tag == "Sid") {
- finishSid();
- } else if (tag == "Star") {
- finishStar();
- } else if (tag == "Longitude") {
- _longitude = atof(_text.c_str());
- } else if (tag == "Latitude") {
- _latitude = atof(_text.c_str());
- } else if (tag == "Name") {
- _wayptName = _text;
- } else if (tag == "Type") {
- _wayptType = _text;
- } else if (tag == "Speed") {
- _speed = atoi(_text.c_str());
- } else if (tag == "Altitude") {
- _altitude = atof(_text.c_str());
- } else if (tag == "AltitudeRestriction") {
- if (_text == "at") {
- _altRestrict = RESTRICT_AT;
- } else if (_text == "above") {
- _altRestrict = RESTRICT_ABOVE;
- } else if (_text == "below") {
- _altRestrict = RESTRICT_BELOW;
- } else {
- throw sg_format_exception("Unrecognized altitude restriction", _text);
+ if (dep->hasChild("sid")) {
+ setSID(_departure->findSIDWithIdent(dep->getStringValue("sid")));
+ }
+ // departure->setStringValue("transition", dep->getStringValue("transition"));
}
- } else if (tag == "Hld_Rad_or_Inbd") {
- if (_text == "Inbd") {
- _holdRadial = -1.0;
+ }
+
+ // destination
+ SGPropertyNode* dst = routeData->getChild("destination");
+ if (dst) {
+ setDestination((FGAirport*) fgFindAirportID(dst->getStringValue("airport")));
+ if (_destination) {
+ if (dst->hasChild("runway")) {
+ setDestination(_destination->getRunwayByIdent(dst->getStringValue("runway")));
+ }
+
+ if (dst->hasChild("star")) {
+ setSTAR(_destination->findSTARWithIdent(dst->getStringValue("star")));
+ }
+
+ if (dst->hasChild("approach")) {
+ setApproach(_destination->findApproachWithIdent(dst->getStringValue("approach")));
+ }
}
- } else if (tag == "Hld_Time_or_Dist") {
- _holdDistance = (_text == "Dist");
- } else if (tag == "Hld_Rad_value") {
- _holdRadial = atof(_text.c_str());
- } else if (tag == "Hld_Turn") {
- _holdRighthanded = (_text == "Right");
- } else if (tag == "Hld_td_value") {
- _holdTD = atof(_text.c_str());
- } else if (tag == "Hdg_Crs_value") {
- _course = atof(_text.c_str());
- } else if (tag == "DMEtoIntercept") {
- _dmeDistance = atof(_text.c_str());
- } else if (tag == "RadialtoIntercept") {
- _radial = atof(_text.c_str());
- } else {
+ // destination->setStringValue("transition", dst->getStringValue("transition"));
+ }
+
+ // alternate
+ SGPropertyNode* alt = routeData->getChild("alternate");
+ if (alt) {
+ //alternate->setStringValue(alt->getStringValue("airport"));
}
+
+ // cruise
+ SGPropertyNode* crs = routeData->getChild("cruise");
+ if (crs) {
+ // cruise->setDoubleValue("speed-kts", crs->getDoubleValue("speed-kts"));
+ // cruise->setDoubleValue("mach", crs->getDoubleValue("mach"));
+ // cruise->setDoubleValue("altitude-ft", crs->getDoubleValue("altitude-ft"));
+ } // of cruise data loading
+
}
-Waypt* NavdataVisitor::buildWaypoint(Route* owner)
-{
- Waypt* wp = NULL;
- if (_wayptType == "Normal") {
- // new LatLonWaypoint
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new BasicWaypt(pos, _wayptName, owner);
- } else if (_wayptType == "Runway") {
- string ident = _wayptName.substr(2);
- FGRunwayRef rwy = _airport->getRunwayByIdent(ident);
- wp = new RunwayWaypt(rwy, owner);
- } else if (_wayptType == "Hold") {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- Hold* h = new Hold(pos, _wayptName, owner);
- wp = h;
- if (_holdRighthanded) {
- h->setRightHanded();
- } else {
- h->setLeftHanded();
- }
+void FlightPlan::loadVersion2XMLRoute(SGPropertyNode_ptr routeData)
+{
+ loadXMLRouteHeader(routeData);
+
+ // route nodes
+ _legs.clear();
+ SGPropertyNode_ptr routeNode = routeData->getChild("route", 0);
+ for (int i=0; i<routeNode->nChildren(); ++i) {
+ SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i);
+ Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode));
+ _legs.push_back(l);
+ } // of route iteration
+}
+
+void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData)
+{
+ loadXMLRouteHeader(routeData);
+
+ // _legs nodes
+ _legs.clear();
+ SGPropertyNode_ptr routeNode = routeData->getChild("route", 0);
+ for (int i=0; i<routeNode->nChildren(); ++i) {
+ SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i);
+ Leg* l = new Leg(this, parseVersion1XMLWaypt(wpNode));
+ _legs.push_back(l);
+ } // of route iteration
+
+}
+
+WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP)
+{
+ SGGeod lastPos;
+ if (!_legs.empty()) {
+ lastPos = _legs.back()->waypoint()->position();
+ } else if (_departure) {
+ lastPos = _departure->geod();
+ }
+
+ WayptRef w;
+ string ident(aWP->getStringValue("ident"));
+ if (aWP->hasChild("longitude-deg")) {
+ // explicit longitude/latitude
+ w = new BasicWaypt(SGGeod::fromDeg(aWP->getDoubleValue("longitude-deg"),
+ aWP->getDoubleValue("latitude-deg")), ident, NULL);
- if (_holdDistance) {
- h->setHoldDistance(_holdTD);
- } else {
- h->setHoldTime(_holdTD * 60.0);
+ } else {
+ string nid = aWP->getStringValue("navid", ident.c_str());
+ FGPositionedRef p = FGPositioned::findClosestWithIdent(nid, lastPos);
+ if (!p) {
+ throw sg_io_exception("bad route file, unknown navid:" + nid);
}
- if (_holdRadial >= 0.0) {
- h->setHoldRadial(_holdRadial);
+ SGGeod pos(p->geod());
+ if (aWP->hasChild("offset-nm") && aWP->hasChild("offset-radial")) {
+ double radialDeg = aWP->getDoubleValue("offset-radial");
+ // convert magnetic radial to a true radial!
+ radialDeg += magvarDegAt(pos);
+ double offsetNm = aWP->getDoubleValue("offset-nm");
+ double az2;
+ SGGeodesy::direct(p->geod(), radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
}
- } else if (_wayptType == "Vectors") {
- wp = new ATCVectors(owner, _airport);
- } else if ((_wayptType == "Intc") || (_wayptType == "VorRadialIntc")) {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new RadialIntercept(owner, _wayptName, pos, _course, _radial);
- } else if (_wayptType == "DmeIntc") {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude));
- wp = new DMEIntercept(owner, _wayptName, pos, _course, _dmeDistance);
- } else if (_wayptType == "ConstHdgtoAlt") {
- wp = new HeadingToAltitude(owner, _wayptName, _course);
- } else if (_wayptType == "PBD") {
- SGGeod pos(SGGeod::fromDeg(_longitude, _latitude)), pos2;
- double az2;
- SGGeodesy::direct(pos, _course, _dmeDistance, pos2, az2);
- wp = new BasicWaypt(pos2, _wayptName, owner);
- } else {
- SG_LOG(SG_GENERAL, SG_ALERT, "implement waypoint type:" << _wayptType);
- throw sg_format_exception("Unrecognized waypt type", _wayptType);
+
+ w = new BasicWaypt(pos, ident, NULL);
}
- assert(wp);
- if ((_altitude > 0.0) && (_altRestrict != RESTRICT_NONE)) {
- wp->setAltitude(_altitude,_altRestrict);
+ double altFt = aWP->getDoubleValue("altitude-ft", -9999.9);
+ if (altFt > -9990.0) {
+ w->setAltitude(altFt, RESTRICT_AT);
}
- if (_speed > 0.0) {
- wp->setSpeed(_speed, RESTRICT_AT); // or _BELOW?
+ return w;
+}
+
+bool FlightPlan::loadPlainTextRoute(const SGPath& path)
+{
+ try {
+ sg_gzifstream in(path.str().c_str());
+ if (!in.is_open()) {
+ throw sg_io_exception("Cannot open file for reading.");
+ }
+
+ _legs.clear();
+ while (!in.eof()) {
+ string line;
+ getline(in, line, '\n');
+ // trim CR from end of line, if found
+ if (line[line.size() - 1] == '\r') {
+ line.erase(line.size() - 1, 1);
+ }
+
+ line = simgear::strutils::strip(line);
+ if (line.empty() || (line[0] == '#')) {
+ continue; // ignore empty/comment lines
+ }
+
+ WayptRef w = waypointFromString(line);
+ if (!w) {
+ throw sg_io_exception("Failed to create waypoint from line '" + line + "'.");
+ }
+
+ _legs.push_back(new Leg(this, w));
+ } // of line iteration
+ } catch (sg_exception& e) {
+ SG_LOG(SG_IO, SG_ALERT, "Failed to load route from: '" << path.str() << "'. " << e.getMessage());
+ _legs.clear();
+ return false;
}
- return wp;
-}
+ return true;
+}
-void NavdataVisitor::finishApproach()
+double FlightPlan::magvarDegAt(const SGGeod& pos) const
{
- WayptVec::iterator it;
- FGRunwayRef rwy;
+ double jd = globals->get_time_params()->getJD();
+ return sgGetMagVar(pos, jd) * SG_RADIANS_TO_DEGREES;
+}
-// find the runway node
- for (it = _waypoints.begin(); it != _waypoints.end(); ++it) {
- FGPositionedRef navid = (*it)->source();
- if (!navid) {
- continue;
+WayptRef FlightPlan::waypointFromString(const string& tgt )
+{
+ string target(boost::to_upper_copy(tgt));
+ WayptRef wpt;
+
+ // extract altitude
+ double altFt = 0.0;
+ RouteRestriction altSetting = RESTRICT_NONE;
+
+ size_t pos = target.find( '@' );
+ if ( pos != string::npos ) {
+ altFt = atof( target.c_str() + pos + 1 );
+ target = target.substr( 0, pos );
+ if ( !strcmp(fgGetString("/sim/startup/units"), "meter") )
+ altFt *= SG_METER_TO_FEET;
+ altSetting = RESTRICT_AT;
+ }
+
+ // check for lon,lat
+ pos = target.find( ',' );
+ if ( pos != string::npos ) {
+ double lon = atof( target.substr(0, pos).c_str());
+ double lat = atof( target.c_str() + pos + 1);
+ 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));
+
+ wpt = new BasicWaypt(SGGeod::fromDeg(lon, lat), buf, NULL);
+ if (altSetting != RESTRICT_NONE) {
+ wpt->setAltitude(altFt, altSetting);
+ }
+ return wpt;
+ }
+
+ SGGeod basePosition;
+ if (_legs.empty()) {
+ // route is empty, use current position
+ basePosition = globals->get_aircraft_position();
+ } else {
+ basePosition = _legs.back()->waypoint()->position();
+ }
+
+ string_list pieces(simgear::strutils::split(target, "/"));
+ FGPositionedRef p = FGPositioned::findClosestWithIdent(pieces.front(), basePosition);
+ if (!p) {
+ SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << pieces.front());
+ return NULL;
+ }
+
+ double magvar = magvarDegAt(basePosition);
+
+ if (pieces.size() == 1) {
+ wpt = new NavaidWaypoint(p, NULL);
+ } else if (pieces.size() == 3) {
+ // navaid/radial/distance-nm notation
+ double radial = atof(pieces[1].c_str()),
+ distanceNm = atof(pieces[2].c_str());
+ radial += magvar;
+ wpt = new OffsetNavaidWaypoint(p, NULL, radial, distanceNm);
+ } else if (pieces.size() == 2) {
+ FGAirport* apt = dynamic_cast<FGAirport*>(p.ptr());
+ if (!apt) {
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "Waypoint is not an airport:" << pieces.front());
+ return NULL;
}
- if (navid->type() == FGPositioned::RUNWAY) {
- rwy = (FGRunway*) navid.get();
- break;
+ if (!apt->hasRunwayWithIdent(pieces[1])) {
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "No runway: " << pieces[1] << " at " << pieces[0]);
+ return NULL;
}
+
+ FGRunway* runway = apt->getRunwayByIdent(pieces[1]);
+ wpt = new NavaidWaypoint(runway, NULL);
+ } else if (pieces.size() == 4) {
+ // navid/radial/navid/radial notation
+ FGPositionedRef p2 = FGPositioned::findClosestWithIdent(pieces[2], basePosition);
+ if (!p2) {
+ SG_LOG( SG_AUTOPILOT, SG_INFO, "Unable to find FGPositioned with ident:" << pieces[2]);
+ return NULL;
+ }
+
+ double r1 = atof(pieces[1].c_str()),
+ r2 = atof(pieces[3].c_str());
+ r1 += magvar;
+ r2 += magvar;
+
+ SGGeod intersection;
+ bool ok = SGGeodesy::radialIntersection(p->geod(), r1, p2->geod(), r2, intersection);
+ if (!ok) {
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "no valid intersection for:" << target);
+ return NULL;
+ }
+
+ std::string name = p->ident() + "-" + p2->ident();
+ wpt = new BasicWaypt(intersection, name, NULL);
}
- if (!rwy) {
- throw sg_format_exception("Malformed approach, no runway waypt", _ident);
+ if (!wpt) {
+ SG_LOG(SG_AUTOPILOT, SG_INFO, "Unable to parse waypoint:" << target);
+ return NULL;
}
- WayptVec primary(_waypoints.begin(), it);
- // erase all points up to and including the runway, to leave only the
- // missed segments
- _waypoints.erase(_waypoints.begin(), ++it);
+ if (altSetting != RESTRICT_NONE) {
+ wpt->setAltitude(altFt, altSetting);
+ }
+ return wpt;
+}
- _approach->setRunway(rwy);
- _approach->setPrimaryAndMissed(primary, _waypoints);
- _airport->addApproach(_approach);
- _approach = NULL;
+FlightPlan::Leg::Leg(FlightPlan* owner, WayptRef wpt) :
+ _parent(owner),
+ _speedRestrict(RESTRICT_NONE),
+ _altRestrict(RESTRICT_NONE),
+ _waypt(wpt)
+{
+ if (!wpt.valid()) {
+ throw sg_exception("can't create FlightPlan::Leg without underlying waypoint");
+ }
+ _speed = _altitudeFt = 0;
}
-void NavdataVisitor::finishSid()
+FlightPlan::Leg* FlightPlan::Leg::cloneFor(FlightPlan* owner) const
{
- // reverse order, because that's how we deal with commonality between
- // STARs and SIDs. SID::route undoes this
- std::reverse(_waypoints.begin(), _waypoints.end());
- _sid->setCommon(_waypoints);
- _airport->addSID(_sid);
- _sid = NULL;
+ Leg* c = new Leg(owner, _waypt);
+// clone local data
+ c->_speed = _speed;
+ c->_speedRestrict = _speedRestrict;
+ c->_altitudeFt = _altitudeFt;
+ c->_altRestrict = _altRestrict;
+
+ return c;
+}
+
+FlightPlan::Leg* FlightPlan::Leg::nextLeg() const
+{
+ return _parent->legAtIndex(index() + 1);
}
-void NavdataVisitor::finishStar()
+unsigned int FlightPlan::Leg::index() const
{
- _star->setCommon(_waypoints);
- _airport->addSTAR(_star);
- _star = NULL;
+ return _parent->findLegIndex(this);
}
-void NavdataVisitor::data (const char * s, int len)
+int FlightPlan::Leg::altitudeFt() const
{
- _text += string(s, len);
+ if (_altRestrict != RESTRICT_NONE) {
+ return _altitudeFt;
+ }
+
+ return _waypt->altitudeFt();
}
+int FlightPlan::Leg::speed() const
+{
+ if (_speedRestrict != RESTRICT_NONE) {
+ return _speed;
+ }
+
+ return _waypt->speed();
+}
-void NavdataVisitor::pi (const char * target, const char * data) {
- //cout << "Processing instruction " << target << ' ' << data << endl;
+int FlightPlan::Leg::speedKts() const
+{
+ return speed();
+}
+
+double FlightPlan::Leg::speedMach() const
+{
+ if (!isMachRestrict(_speedRestrict)) {
+ return 0.0;
+ }
+
+ return -(_speed / 100.0);
}
-void NavdataVisitor::warning (const char * message, int line, int column) {
- SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
+RouteRestriction FlightPlan::Leg::altitudeRestriction() const
+{
+ if (_altRestrict != RESTRICT_NONE) {
+ return _altRestrict;
+ }
+
+ return _waypt->altitudeRestriction();
+}
+
+RouteRestriction FlightPlan::Leg::speedRestriction() const
+{
+ if (_speedRestrict != RESTRICT_NONE) {
+ return _speedRestrict;
+ }
+
+ return _waypt->speedRestriction();
+}
+
+void FlightPlan::Leg::setSpeed(RouteRestriction ty, double speed)
+{
+ _speedRestrict = ty;
+ if (isMachRestrict(ty)) {
+ _speed = (speed * -100);
+ } else {
+ _speed = speed;
+ }
+}
+
+void FlightPlan::Leg::setAltitude(RouteRestriction ty, int altFt)
+{
+ _altRestrict = ty;
+ _altitudeFt = altFt;
}
-void NavdataVisitor::error (const char * message, int line, int column) {
- SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
+double FlightPlan::Leg::courseDeg() const
+{
+ return _courseDeg;
+}
+
+double FlightPlan::Leg::distanceNm() const
+{
+ return _pathDistance;
+}
+
+double FlightPlan::Leg::distanceAlongRoute() const
+{
+ return _distanceAlongPath;
+}
+
+void FlightPlan::rebuildLegData()
+{
+ _totalDistance = 0.0;
+ int lastLeg = static_cast<int>(_legs.size()) - 1;
+ for (int l=0; l<lastLeg; ++l) {
+ Leg* cur = _legs[l];
+ Leg* next = _legs[l + 1];
+
+ 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;
+ } // of legs iteration
+}
+
+void FlightPlan::setDelegate(Delegate* d)
+{
+ // wrap any existing delegate(s) in the new one
+ d->_inner = _delegate;
+ _delegate = d;
}
+void FlightPlan::removeDelegate(Delegate* d)
+{
+ if (d == _delegate) {
+ _delegate = _delegate->_inner;
+ } else if (_delegate) {
+ _delegate->removeInner(d);
+ }
+}
+
+FlightPlan::Delegate::Delegate() :
+ _inner(NULL)
+{
+
+}
+
+FlightPlan::Delegate::~Delegate()
+{
+
+}
+
+void FlightPlan::Delegate::removeInner(Delegate* d)
+{
+ if (!_inner) {
+ return;
+ }
+
+ if (_inner == d) {
+ // replace with grand-child
+ _inner = d->_inner;
+ } else { // recurse downwards
+ _inner->removeInner(d);
+ }
+}
+
+void FlightPlan::Delegate::runDepartureChanged()
+{
+ if (_inner) _inner->runDepartureChanged();
+ departureChanged();
+}
+
+void FlightPlan::Delegate::runArrivalChanged()
+{
+ if (_inner) _inner->runArrivalChanged();
+ arrivalChanged();
+}
+
+void FlightPlan::Delegate::runWaypointsChanged()
+{
+ if (_inner) _inner->runWaypointsChanged();
+ waypointsChanged();
+}
+
+void FlightPlan::Delegate::runCurrentWaypointChanged()
+{
+ if (_inner) _inner->runCurrentWaypointChanged();
+ currentWaypointChanged();
+}
+
} // of namespace flightgear
// forward decls
class FGPositioned;
class SGPath;
-class FGAirport;
+class FGRunway;
+
+#include <Airports/simple.hxx>
+typedef SGSharedPtr<FGAirport> FGAirportRef;
namespace flightgear
{
// forward decls
-class Route;
+class RouteBase;
class Waypt;
class NavdataVisitor;
-
+class SID;
+class STAR;
+class Transition;
+
typedef SGSharedPtr<Waypt> WayptRef;
typedef enum {
WPT_GENERATED = 1 << 7,
WPT_DEPARTURE = 1 << 8,
- WPT_ARRIVAL = 1 << 9
+ WPT_ARRIVAL = 1 << 9,
+
+ /// waypoint generated by VNAV / speed management profile,
+ /// for step climbs or top of descent
+ WPT_PSEUDO = 1 << 10,
+ WPT_APPROACH = 1 << 11
} WayptFlag;
typedef enum {
RESTRICT_AT,
RESTRICT_ABOVE,
RESTRICT_BELOW,
- SPEED_RESTRICT_MACH
+ SPEED_RESTRICT_MACH, ///< encode an 'AT' restriction in Mach, not IAS
+ RESTRICT_DELETE, ///< ignore underlying restriction (on a leg)
+ RESTRICT_COMPUTED, ///< data is computed, not a real restriction
+ SPEED_COMPUTED_MACH ///< variant on above to encode a Mach value
} RouteRestriction;
+bool isMachRestrict(RouteRestriction rr);
+
/**
* Abstract base class for waypoints (and things that are treated similarly
* by navigation systems)
public:
virtual ~Waypt();
- Route* owner() const
+ RouteBase* owner() const
{ return _owner; }
/**
/**
* Factory method
*/
- static WayptRef createFromProperties(Route* aOwner, SGPropertyNode_ptr aProp);
+ static WayptRef createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp);
void saveAsNode(SGPropertyNode* node) const;
protected:
friend class NavdataVisitor;
- Waypt(Route* aOwner);
+ Waypt(RouteBase* aOwner);
/**
* Persistence helper - read node properties from a file
*/
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
- typedef Waypt* (FactoryFunction)(Route* aOwner) ;
+ typedef Waypt* (FactoryFunction)(RouteBase* aOwner) ;
static void registerFactory(const std::string aNodeType, FactoryFunction* aFactory);
double _altitudeFt;
/**
* Create an instance of a concrete subclass, or throw an exception
*/
- static Waypt* createInstance(Route* aOwner, const std::string& aTypeName);
+ static Waypt* createInstance(RouteBase* aOwner, const std::string& aTypeName);
- Route* _owner;
+ RouteBase* _owner;
unsigned short _flags;
mutable double _magVarDeg;
};
typedef std::vector<WayptRef> WayptVec;
-class Route
+class RouteBase
{
public:
/**
static void loadAirportProcedures(const SGPath& aPath, FGAirport* aApt);
- static void dumpRouteToFile(const WayptVec& aRoute, const std::string& aName);
+ static void dumpRouteToKML(const WayptVec& aRoute, const std::string& aName);
- static void dumpRouteToLineString(const std::string& aIdent,
+ static void dumpRouteToKMLLineString(const std::string& aIdent,
const WayptVec& aRoute, std::ostream& aStream);
private:
};
-
+
+class FlightPlan : public RouteBase
+{
+public:
+ FlightPlan();
+ virtual ~FlightPlan();
+
+ virtual std::string ident() const;
+ void setIdent(const std::string& s);
+
+ FlightPlan* clone(const std::string& newIdent = std::string()) const;
+
+ /**
+ * flight-plan leg encapsulation
+ */
+ class Leg
+ {
+ public:
+ FlightPlan* owner() const
+ { return _parent; }
+
+ Waypt* waypoint() const
+ { return _waypt; }
+
+ // reutrn the next leg after this one
+ Leg* nextLeg() const;
+
+ unsigned int index() const;
+
+ int altitudeFt() const;
+ int speed() const;
+
+ int speedKts() const;
+ double speedMach() const;
+
+ RouteRestriction altitudeRestriction() const;
+ RouteRestriction speedRestriction() const;
+
+ void setSpeed(RouteRestriction ty, double speed);
+ void setAltitude(RouteRestriction ty, int altFt);
+
+ double courseDeg() const;
+ double distanceNm() const;
+ double distanceAlongRoute() const;
+ private:
+ friend class FlightPlan;
+
+ Leg(FlightPlan* owner, WayptRef wpt);
+
+ Leg* cloneFor(FlightPlan* owner) const;
+
+ FlightPlan* _parent;
+ RouteRestriction _speedRestrict, _altRestrict;
+ int _speed;
+ int _altitudeFt;
+ WayptRef _waypt;
+ /// length of this leg following the flown path
+ mutable double _pathDistance;
+ mutable double _courseDeg;
+ /// total distance of this leg from departure point
+ mutable double _distanceAlongPath;
+ };
+
+ class Delegate
+ {
+ public:
+ virtual ~Delegate();
+
+ virtual void departureChanged() { }
+ virtual void arrivalChanged() { }
+ virtual void waypointsChanged() { }
+
+ virtual void currentWaypointChanged() { }
+
+ protected:
+ Delegate();
+
+ private:
+ void removeInner(Delegate* d);
+
+ void runDepartureChanged();
+ void runArrivalChanged();
+ void runWaypointsChanged();
+ void runCurrentWaypointChanged();
+
+ friend class FlightPlan;
+
+ Delegate* _inner;
+ };
+
+ Leg* insertWayptAtIndex(Waypt* aWpt, int aIndex);
+ void insertWayptsAtIndex(const WayptVec& wps, int aIndex);
+
+ void deleteIndex(int index);
+ void clear();
+ int clearWayptsWithFlag(WayptFlag flag);
+
+ int currentIndex() const
+ { return _currentIndex; }
+
+ void setCurrentIndex(int index);
+
+ Leg* currentLeg() const;
+ Leg* nextLeg() const;
+ Leg* previousLeg() const;
+
+ int numLegs() const
+ { return _legs.size(); }
+
+ Leg* legAtIndex(int index) const;
+ int findLegIndex(const Leg* l) const;
+
+ int findWayptIndex(const SGGeod& aPos) const;
+
+ bool load(const SGPath& p);
+ bool save(const SGPath& p);
+
+ FGAirportRef departureAirport() const
+ { return _departure; }
+
+ FGAirportRef destinationAirport() const
+ { return _destination; }
+
+ FGRunway* departureRunway() const
+ { return _departureRunway; }
+
+ FGRunway* destinationRunway() const
+ { return _destinationRunway; }
+
+ Approach* approach() const
+ { return _approach; }
+
+ void setDeparture(FGAirport* apt);
+ void setDeparture(FGRunway* rwy);
+
+ SID* sid() const
+ { return _sid; }
+
+ Transition* sidTransition() const;
+
+ void setSID(SID* sid, const std::string& transition = std::string());
+
+ void setSID(Transition* sidWithTrans);
+
+ void setDestination(FGAirport* apt);
+ void setDestination(FGRunway* rwy);
+
+ /**
+ * note setting an approach will implicitly update the destination
+ * airport and runway to match
+ */
+ void setApproach(Approach* app);
+
+ STAR* star() const
+ { return _star; }
+
+ Transition* starTransition() const;
+
+ void setSTAR(STAR* star, const std::string& transition = std::string());
+
+ void setSTAR(Transition* starWithTrans);
+
+ double totalDistanceNm() const
+ { return _totalDistance; }
+
+ /**
+ * Create a WayPoint from a string in the following format:
+ * - simple identifier
+ * - decimal-lon,decimal-lat
+ * - airport-id/runway-id
+ * - navaid/radial-deg/offset-nm
+ */
+ WayptRef waypointFromString(const std::string& target);
+
+ void setDelegate(Delegate* d);
+ void removeDelegate(Delegate* d);
+private:
+
+ bool loadPlainTextRoute(const SGPath& path);
+
+ void loadVersion1XMLRoute(SGPropertyNode_ptr routeData);
+ void loadVersion2XMLRoute(SGPropertyNode_ptr routeData);
+ void loadXMLRouteHeader(SGPropertyNode_ptr routeData);
+ WayptRef parseVersion1XMLWaypt(SGPropertyNode* aWP);
+
+ double magvarDegAt(const SGGeod& pos) const;
+
+ std::string _ident;
+ int _currentIndex;
+
+ FGAirportRef _departure, _destination;
+ FGRunway* _departureRunway, *_destinationRunway;
+ SID* _sid;
+ STAR* _star;
+ Approach* _approach;
+ std::string _sidTransition, _starTransition;
+
+ double _totalDistance;
+ void rebuildLegData();
+
+ typedef std::vector<Leg*> LegVec;
+ LegVec _legs;
+
+ Delegate* _delegate;
+};
+
} // of namespace flightgear
#endif // of FG_ROUTE_HXX
RoutePath::RoutePath(const flightgear::WayptVec& wpts) :
_waypts(wpts)
+{
+ commonInit();
+}
+
+RoutePath::RoutePath(const flightgear::FlightPlan* fp)
+{
+ for (int l=0; l<fp->numLegs(); ++l) {
+ _waypts.push_back(fp->legAtIndex(l)->waypoint());
+ }
+ commonInit();
+}
+
+void RoutePath::commonInit()
{
_pathClimbFPM = 1200;
_pathDescentFPM = 800;
_pathIAS = 190;
- _pathTurnRate = 3.0; // 3 deg/sec = 180def/min = standard rate turn
+ _pathTurnRate = 3.0; // 3 deg/sec = 180def/min = standard rate turn
}
SGGeodVec RoutePath::pathForIndex(int index) const
{
public:
RoutePath(const flightgear::WayptVec& wpts);
-
+ RoutePath(const flightgear::FlightPlan* fp);
+
SGGeodVec pathForIndex(int index) const;
SGGeod positionForIndex(int index) const;
private:
+ void commonInit();
+
class PathCtx;
SGGeodVec pathForHold(flightgear::Hold* hold) const;
namespace flightgear
{
-BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
+BasicWaypt::BasicWaypt(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
Waypt(aOwner),
_pos(aPos),
_ident(aIdent)
}
}
-BasicWaypt::BasicWaypt(const SGWayPoint& aWP, Route* aOwner) :
+BasicWaypt::BasicWaypt(const SGWayPoint& aWP, RouteBase* aOwner) :
Waypt(aOwner),
_pos(aWP.get_target()),
_ident(aWP.get_id())
{
}
-BasicWaypt::BasicWaypt(Route* aOwner) :
+BasicWaypt::BasicWaypt(RouteBase* aOwner) :
Waypt(aOwner)
{
}
//////////////////////////////////////////////////////////////////////////////
-NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, Route* aOwner) :
+NavaidWaypoint::NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner) :
Waypt(aOwner),
_navaid(aPos)
{
}
}
-NavaidWaypoint::NavaidWaypoint(Route* aOwner) :
+NavaidWaypoint::NavaidWaypoint(RouteBase* aOwner) :
Waypt(aOwner)
{
}
aProp->setDoubleValue("lat", _navaid->geod().getLatitudeDeg());
}
-OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, Route* aOwner,
+OffsetNavaidWaypoint::OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner,
double aRadial, double aDistNm) :
NavaidWaypoint(aPos, aOwner),
_radial(aRadial),
init();
}
-OffsetNavaidWaypoint::OffsetNavaidWaypoint(Route* aOwner) :
+OffsetNavaidWaypoint::OffsetNavaidWaypoint(RouteBase* aOwner) :
NavaidWaypoint(aOwner)
{
}
/////////////////////////////////////////////////////////////////////////////
-RunwayWaypt::RunwayWaypt(FGRunway* aPos, Route* aOwner) :
+RunwayWaypt::RunwayWaypt(FGRunway* aPos, RouteBase* aOwner) :
Waypt(aOwner),
_runway(aPos)
{
}
-RunwayWaypt::RunwayWaypt(Route* aOwner) :
+RunwayWaypt::RunwayWaypt(RouteBase* aOwner) :
Waypt(aOwner)
{
}
/////////////////////////////////////////////////////////////////////////////
-Hold::Hold(const SGGeod& aPos, const string& aIdent, Route* aOwner) :
+Hold::Hold(const SGGeod& aPos, const string& aIdent, RouteBase* aOwner) :
BasicWaypt(aPos, aIdent, aOwner),
_righthanded(true),
_isDistance(false)
setFlag(WPT_DYNAMIC);
}
-Hold::Hold(Route* aOwner) :
+Hold::Hold(RouteBase* aOwner) :
BasicWaypt(aOwner),
_righthanded(true),
_isDistance(false)
/////////////////////////////////////////////////////////////////////////////
-HeadingToAltitude::HeadingToAltitude(Route* aOwner, const string& aIdent,
+HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner, const string& aIdent,
double aMagHdg) :
Waypt(aOwner),
_ident(aIdent),
setFlag(WPT_DYNAMIC);
}
-HeadingToAltitude::HeadingToAltitude(Route* aOwner) :
+HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) :
Waypt(aOwner)
{
}
/////////////////////////////////////////////////////////////////////////////
-DMEIntercept::DMEIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
+DMEIntercept::DMEIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aDistanceNm) :
Waypt(aOwner),
_ident(aIdent),
setFlag(WPT_DYNAMIC);
}
-DMEIntercept::DMEIntercept(Route* aOwner) :
+DMEIntercept::DMEIntercept(RouteBase* aOwner) :
Waypt(aOwner)
{
}
/////////////////////////////////////////////////////////////////////////////
-RadialIntercept::RadialIntercept(Route* aOwner, const string& aIdent, const SGGeod& aPos,
+RadialIntercept::RadialIntercept(RouteBase* aOwner, const string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aRadial) :
Waypt(aOwner),
_ident(aIdent),
setFlag(WPT_DYNAMIC);
}
-RadialIntercept::RadialIntercept(Route* aOwner) :
+RadialIntercept::RadialIntercept(RouteBase* aOwner) :
Waypt(aOwner)
{
}
/////////////////////////////////////////////////////////////////////////////
-ATCVectors::ATCVectors(Route* aOwner, FGAirport* aFacility) :
+ATCVectors::ATCVectors(RouteBase* aOwner, FGAirport* aFacility) :
Waypt(aOwner),
_facility(aFacility)
{
{
}
-ATCVectors::ATCVectors(Route* aOwner) :
+ATCVectors::ATCVectors(RouteBase* aOwner) :
Waypt(aOwner)
{
}
{
public:
- BasicWaypt(const SGGeod& aPos, const std::string& aIdent, Route* aOwner);
+ BasicWaypt(const SGGeod& aPos, const std::string& aIdent, RouteBase* aOwner);
- BasicWaypt(const SGWayPoint& aWP, Route* aOwner);
+ BasicWaypt(const SGWayPoint& aWP, RouteBase* aOwner);
- BasicWaypt(Route* aOwner);
+ BasicWaypt(RouteBase* aOwner);
virtual SGGeod position() const
{ return _pos; }
class NavaidWaypoint : public Waypt
{
public:
- NavaidWaypoint(FGPositioned* aPos, Route* aOwner);
+ NavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner);
- NavaidWaypoint(Route* aOwner);
+ NavaidWaypoint(RouteBase* aOwner);
virtual SGGeod position() const;
class OffsetNavaidWaypoint : public NavaidWaypoint
{
public:
- OffsetNavaidWaypoint(FGPositioned* aPos, Route* aOwner, double aRadial, double aDistNm);
+ OffsetNavaidWaypoint(FGPositioned* aPos, RouteBase* aOwner, double aRadial, double aDistNm);
- OffsetNavaidWaypoint(Route* aOwner);
+ OffsetNavaidWaypoint(RouteBase* aOwner);
virtual SGGeod position() const
{ return _geod; }
class RunwayWaypt : public Waypt
{
public:
- RunwayWaypt(FGRunway* aPos, Route* aOwner);
+ RunwayWaypt(FGRunway* aPos, RouteBase* aOwner);
- RunwayWaypt(Route* aOwner);
+ RunwayWaypt(RouteBase* aOwner);
virtual SGGeod position() const;
class Hold : public BasicWaypt
{
public:
- Hold(const SGGeod& aPos, const std::string& aIdent, Route* aOwner);
+ Hold(const SGGeod& aPos, const std::string& aIdent, RouteBase* aOwner);
- Hold(Route* aOwner);
+ Hold(RouteBase* aOwner);
void setHoldRadial(double aInboundRadial);
void setHoldDistance(double aDistanceNm);
class HeadingToAltitude : public Waypt
{
public:
- HeadingToAltitude(Route* aOwner, const std::string& aIdent, double aMagHdg);
+ HeadingToAltitude(RouteBase* aOwner, const std::string& aIdent, double aMagHdg);
- HeadingToAltitude(Route* aOwner);
+ HeadingToAltitude(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
class DMEIntercept : public Waypt
{
public:
- DMEIntercept(Route* aOwner, const std::string& aIdent, const SGGeod& aPos,
+ DMEIntercept(RouteBase* aOwner, const std::string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aDistanceNm);
- DMEIntercept(Route* aOwner);
+ DMEIntercept(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
class RadialIntercept : public Waypt
{
public:
- RadialIntercept(Route* aOwner, const std::string& aIdent, const SGGeod& aPos,
+ RadialIntercept(RouteBase* aOwner, const std::string& aIdent, const SGGeod& aPos,
double aCourseDeg, double aRadialDeg);
- RadialIntercept(Route* aOwner);
+ RadialIntercept(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
class ATCVectors : public Waypt
{
public:
- ATCVectors(Route* aOwner, FGAirport* aFacility);
+ ATCVectors(RouteBase* aOwner, FGAirport* aFacility);
virtual ~ATCVectors();
- ATCVectors(Route* aOwner);
+ ATCVectors(RouteBase* aOwner);
virtual void initFromProperties(SGPropertyNode_ptr aProp);
virtual void writeToProperties(SGPropertyNode_ptr aProp) const;
#include "NasalPositioned.hxx"
#include <boost/foreach.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/sg_inlines.h>
#include <simgear/scene/material/mat.hxx>
#include <Autopilot/route_mgr.hxx>
#include <Navaids/procedure.hxx>
+using namespace flightgear;
+
static void positionedGhostDestroy(void* g);
static void wayptGhostDestroy(void* g);
+static void legGhostDestroy(void* g);
+static void routeBaseGhostDestroy(void* g);
+
naGhostType PositionedGhostType = { positionedGhostDestroy, "positioned" };
static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out);
naGhostType RunwayGhostType = { positionedGhostDestroy, "runway", runwayGhostGetMember, 0 };
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out);
-
naGhostType WayptGhostType = { wayptGhostDestroy,
"waypoint",
wayptGhostGetMember,
0};
+static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+naGhostType FPLegGhostType = { legGhostDestroy,
+ "flightplan-leg",
+ legGhostGetMember,
+ 0};
+
+static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef value);
+
+naGhostType FlightPlanGhostType = { routeBaseGhostDestroy,
+ "flightplan",
+ flightplanGhostGetMember,
+ flightplanGhostSetMember
+};
+
+static const char* procedureGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+naGhostType ProcedureGhostType = { routeBaseGhostDestroy,
+ "procedure",
+ procedureGhostGetMember,
+ 0};
+
static void hashset(naContext c, naRef hash, const char* key, naRef val)
{
naRef s = naNewString(c);
delete pos;
}
-static flightgear::Waypt* wayptGhost(naRef r)
+static Waypt* wayptGhost(naRef r)
{
if (naGhost_type(r) == &WayptGhostType)
- return (flightgear::Waypt*) naGhost_ptr(r);
+ return (Waypt*) naGhost_ptr(r);
return 0;
}
static void wayptGhostDestroy(void* g)
{
- flightgear::Waypt* wpt = (flightgear::Waypt*)g;
- if (!flightgear::Waypt::put(wpt)) // unref
+ Waypt* wpt = (Waypt*)g;
+ if (!Waypt::put(wpt)) // unref
delete wpt;
}
+static void legGhostDestroy(void* g)
+{
+ // nothing for now
+}
+
+
+static FlightPlan::Leg* fpLegGhost(naRef r)
+{
+ if (naGhost_type(r) == &FPLegGhostType)
+ return (FlightPlan::Leg*) naGhost_ptr(r);
+ return 0;
+}
+
+static Procedure* procedureGhost(naRef r)
+{
+ if (naGhost_type(r) == &ProcedureGhostType)
+ return (Procedure*) naGhost_ptr(r);
+ return 0;
+}
+
+static FlightPlan* flightplanGhost(naRef r)
+{
+ if (naGhost_type(r) == &FlightPlanGhostType)
+ return (FlightPlan*) naGhost_ptr(r);
+ return 0;
+}
+
+static void routeBaseGhostDestroy(void* g)
+{
+ // nothing for now
+}
+
static naRef airportPrototype;
-static naRef routePrototype;
+static naRef flightplanPrototype;
static naRef waypointPrototype;
static naRef geoCoordClass;
+static naRef fpLegPrototype;
+static naRef procedurePrototype;
naRef ghostForPositioned(naContext c, const FGPositioned* pos)
{
return naNewGhost2(c, &RunwayGhostType, (void*) r);
}
-naRef ghostForWaypt(naContext c, const flightgear::Waypt* wpt)
+naRef ghostForWaypt(naContext c, const Waypt* wpt)
{
if (!wpt) {
return naNil();
}
- flightgear::Waypt::get(wpt); // take a ref
+ Waypt::get(wpt); // take a ref
return naNewGhost2(c, &WayptGhostType, (void*) wpt);
}
+naRef ghostForLeg(naContext c, const FlightPlan::Leg* leg)
+{
+ if (!leg) {
+ return naNil();
+ }
+
+ return naNewGhost2(c, &FPLegGhostType, (void*) leg);
+}
+
+naRef ghostForFlightPlan(naContext c, const FlightPlan* fp)
+{
+ if (!fp) {
+ return naNil();
+ }
+
+ return naNewGhost2(c, &FlightPlanGhostType, (void*) fp);
+}
+
+naRef ghostForProcedure(naContext c, const Procedure* proc)
+{
+ if (!proc) {
+ return naNil();
+ }
+
+ return naNewGhost2(c, &ProcedureGhostType, (void*) proc);
+}
+
static const char* airportGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
return "";
}
-static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* fieldName, naRef* out)
{
- const char* fieldName = naStr_data(field);
- flightgear::Waypt* wpt = (flightgear::Waypt*) g;
-
- if (!strcmp(fieldName, "parents")) {
- *out = naNewVector(c);
- naVec_append(*out, waypointPrototype);
- } else if (!strcmp(fieldName, "wp_name")) *out =stringToNasal(c, wpt->ident());
+ if (!strcmp(fieldName, "wp_name")) *out = stringToNasal(c, wpt->ident());
else if (!strcmp(fieldName, "wp_type")) *out = stringToNasal(c, wpt->type());
else if (!strcmp(fieldName, "wp_lat")) *out = naNum(wpt->position().getLatitudeDeg());
else if (!strcmp(fieldName, "wp_lon")) *out = naNum(wpt->position().getLongitudeDeg());
else if (!strcmp(fieldName, "wp_parent_name")) {
- flightgear::Procedure* proc = dynamic_cast<flightgear::Procedure*>(wpt->owner());
+ Procedure* proc = dynamic_cast<Procedure*>(wpt->owner());
*out = proc ? stringToNasal(c, proc->ident()) : naNil();
+ } else if (!strcmp(fieldName, "wp_parent")) {
+ Procedure* proc = dynamic_cast<Procedure*>(wpt->owner());
+ *out = ghostForProcedure(c, proc);
} else if (!strcmp(fieldName, "fly_type")) {
if (wpt->type() == "hold") {
*out = stringToNasal(c, "Hold");
} else {
- *out = stringToNasal(c, wpt->flag(flightgear::WPT_OVERFLIGHT) ? "flyOver" : "flyBy");
+ *out = stringToNasal(c, wpt->flag(WPT_OVERFLIGHT) ? "flyOver" : "flyBy");
}
- } else if (!strcmp(fieldName, "alt_cstr")) *out = naNum(wpt->altitudeFt());
- else if (!strcmp(fieldName, "speed_cstr")) {
- double s = (wpt->speedRestriction() == flightgear::SPEED_RESTRICT_MACH)
- ? wpt->speedMach() : wpt->speedKts();
+ } else {
+ return NULL; // member not found
+ }
+
+ return "";
+}
+
+static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ Waypt* wpt = (flightgear::Waypt*) g;
+ return waypointCommonGetMember(c, wpt, fieldName, out);
+}
+
+static RouteRestriction routeRestrictionFromString(const char* s)
+{
+ string u(s);
+ boost::to_lower(u);
+ if (u == "computed") return RESTRICT_COMPUTED;
+ if (u == "at") return RESTRICT_AT;
+ if (u == "mach") return SPEED_RESTRICT_MACH;
+ if (u == "computed-mach") return SPEED_COMPUTED_MACH;
+ if (u == "delete") return RESTRICT_DELETE;
+ return RESTRICT_NONE;
+};
+
+naRef routeRestrictionToNasal(naContext c, RouteRestriction rr)
+{
+ switch (rr) {
+ case RESTRICT_NONE: return naNil();
+ case RESTRICT_AT: return stringToNasal(c, "at");
+ case RESTRICT_ABOVE: return stringToNasal(c, "above");
+ case RESTRICT_BELOW: return stringToNasal(c, "below");
+ case SPEED_RESTRICT_MACH: return stringToNasal(c, "mach");
+ case RESTRICT_COMPUTED: return stringToNasal(c, "computed");
+ case SPEED_COMPUTED_MACH: return stringToNasal(c, "computed-mach");
+ case RESTRICT_DELETE: return stringToNasal(c, "delete");
+ }
+
+ return naNil();
+}
+
+static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ FlightPlan::Leg* leg = (FlightPlan::Leg*) g;
+ Waypt* wpt = leg->waypoint();
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, fpLegPrototype);
+ } else if (!strcmp(fieldName, "alt_cstr")) {
+ *out = naNum(leg->altitudeFt());
+ } else if (!strcmp(fieldName, "alt_cstr_type")) {
+ *out = routeRestrictionToNasal(c, leg->altitudeRestriction());
+ } else if (!strcmp(fieldName, "speed_cstr")) {
+ double s = isMachRestrict(leg->speedRestriction()) ? leg->speedMach() : leg->speedKts();
*out = naNum(s);
+ } else if (!strcmp(fieldName, "speed_cstr_type")) {
+ *out = routeRestrictionToNasal(c, leg->speedRestriction());
} else if (!strcmp(fieldName, "leg_distance")) {
- return "please implement me";
+ *out = naNum(leg->distanceNm());
} else if (!strcmp(fieldName, "leg_bearing")) {
- return "please implement me";
- } else {
- return NULL; // member not found
+ *out = naNum(leg->courseDeg());
+ } else if (!strcmp(fieldName, "distance_along_route")) {
+ *out = naNum(leg->distanceAlongRoute());
+ } else { // check for fields defined on the underlying waypoint
+ return waypointCommonGetMember(c, wpt, fieldName, out);
}
return ""; // success
}
+static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ FlightPlan* fp = (FlightPlan*) g;
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, flightplanPrototype);
+ } else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, fp->ident());
+ else if (!strcmp(fieldName, "departure")) *out = ghostForAirport(c, fp->departureAirport());
+ else if (!strcmp(fieldName, "destination")) *out = ghostForAirport(c, fp->destinationAirport());
+ else if (!strcmp(fieldName, "departure_runway")) *out = ghostForRunway(c, fp->departureRunway());
+ else if (!strcmp(fieldName, "destination_runway")) *out = ghostForRunway(c, fp->destinationRunway());
+ else if (!strcmp(fieldName, "sid")) *out = ghostForProcedure(c, fp->sid());
+ else if (!strcmp(fieldName, "sid_trans")) *out = ghostForProcedure(c, fp->sidTransition());
+ else if (!strcmp(fieldName, "star")) *out = ghostForProcedure(c, fp->star());
+ else if (!strcmp(fieldName, "star_trans")) *out = ghostForProcedure(c, fp->starTransition());
+ else if (!strcmp(fieldName, "approach")) *out = ghostForProcedure(c, fp->approach());
+ else if (!strcmp(fieldName, "current")) *out = naNum(fp->currentIndex());
+ else {
+ return 0;
+ }
+
+ return "";
+}
+
+static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef value)
+{
+ const char* fieldName = naStr_data(field);
+ FlightPlan* fp = (FlightPlan*) g;
+
+ if (!strcmp(fieldName, "id")) {
+ if (!naIsString(value)) naRuntimeError(c, "flightplan.id must be a string");
+ fp->setIdent(naStr_data(value));
+ } else if (!strcmp(fieldName, "current")) {
+ int index = value.num;
+ if ((index < 0) || (index >= fp->numLegs())) {
+ return;
+ }
+ fp->setCurrentIndex(index);
+ } else if (!strcmp(fieldName, "departure")) {
+ FGAirport* apt = airportGhost(value);
+ if (apt) {
+ fp->setDeparture(apt);
+ return;
+ }
+
+ FGRunway* rwy = runwayGhost(value);
+ if (rwy){
+ fp->setDeparture(rwy);
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting departure");
+ } else if (!strcmp(fieldName, "destination")) {
+ FGAirport* apt = airportGhost(value);
+ if (apt) {
+ fp->setDestination(apt);
+ return;
+ }
+
+ FGRunway* rwy = runwayGhost(value);
+ if (rwy){
+ fp->setDestination(rwy);
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting destination");
+ } else if (!strcmp(fieldName, "departure_runway")) {
+ FGRunway* rwy = runwayGhost(value);
+ if (rwy){
+ fp->setDeparture(rwy);
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting departure");
+ } else if (!strcmp(fieldName, "destination_runway")) {
+ FGRunway* rwy = runwayGhost(value);
+ if (rwy){
+ fp->setDestination(rwy);
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting departure");
+ } else if (!strcmp(fieldName, "sid")) {
+ Procedure* proc = procedureGhost(value);
+ if (proc && (proc->type() == PROCEDURE_SID)) {
+ fp->setSID((SID*) proc);
+ return;
+ }
+ // allow a SID transition to be set, implicitly include the SID itself
+ if (proc && (proc->type() == PROCEDURE_TRANSITION)) {
+ fp->setSID((Transition*) proc);
+ return;
+ }
+
+ if (naIsString(value)) {
+ FGAirport* apt = fp->departureAirport();
+ fp->setSID(apt->findSIDWithIdent(naStr_data(value)));
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting SID");
+ } else if (!strcmp(fieldName, "star")) {
+ Procedure* proc = procedureGhost(value);
+ if (proc && (proc->type() == PROCEDURE_STAR)) {
+ fp->setSTAR((STAR*) proc);
+ return;
+ }
+
+ if (proc && (proc->type() == PROCEDURE_TRANSITION)) {
+ fp->setSTAR((Transition*) proc);
+ return;
+ }
+
+ if (naIsString(value)) {
+ FGAirport* apt = fp->destinationAirport();
+ fp->setSTAR(apt->findSTARWithIdent(naStr_data(value)));
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting STAR");
+ } else if (!strcmp(fieldName, "approach")) {
+ Procedure* proc = procedureGhost(value);
+ if (proc && Approach::isApproach(proc->type())) {
+ fp->setApproach((Approach*) proc);
+ return;
+ }
+
+ if (naIsString(value)) {
+ FGAirport* apt = fp->destinationAirport();
+ fp->setApproach(apt->findApproachWithIdent(naStr_data(value)));
+ return;
+ }
+
+ naRuntimeError(c, "bad argument type setting approach");
+ }
+}
+
+
+static naRef procedureTpType(naContext c, ProcedureType ty)
+{
+ switch (ty) {
+ case PROCEDURE_SID: return stringToNasal(c, "sid");
+ case PROCEDURE_STAR: return stringToNasal(c, "star");
+ case PROCEDURE_APPROACH_VOR:
+ case PROCEDURE_APPROACH_ILS:
+ case PROCEDURE_APPROACH_RNAV:
+ case PROCEDURE_APPROACH_NDB:
+ return stringToNasal(c, "IAP");
+ default:
+ return naNil();
+ }
+}
+
+static naRef procedureRadioType(naContext c, ProcedureType ty)
+{
+ switch (ty) {
+ case PROCEDURE_APPROACH_VOR: return stringToNasal(c, "VOR");
+ case PROCEDURE_APPROACH_ILS: return stringToNasal(c, "ILS");
+ case PROCEDURE_APPROACH_RNAV: return stringToNasal(c, "RNAV");
+ case PROCEDURE_APPROACH_NDB: return stringToNasal(c, "NDB");
+ default:
+ return naNil();
+ }
+}
+
+static const char* procedureGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ Procedure* proc = (Procedure*) g;
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, procedurePrototype);
+ } else if (!strcmp(fieldName, "id")) *out = stringToNasal(c, proc->ident());
+ else if (!strcmp(fieldName, "airport")) *out = ghostForAirport(c, proc->airport());
+ else if (!strcmp(fieldName, "tp_type")) *out = procedureTpType(c, proc->type());
+ else if (!strcmp(fieldName, "radio")) *out = procedureRadioType(c, proc->type());
+ else if (!strcmp(fieldName, "runways")) {
+ *out = naNewVector(c);
+ BOOST_FOREACH(FGRunwayPtr rwy, proc->runways()) {
+ naVec_append(*out, stringToNasal(c, rwy->ident()));
+ }
+ } else if (!strcmp(fieldName, "transitions")) {
+ if ((proc->type() != PROCEDURE_SID) && (proc->type() != PROCEDURE_STAR)) {
+ *out = naNil();
+ return "";
+ }
+
+ ArrivalDeparture* ad = static_cast<ArrivalDeparture*>(proc);
+ *out = naNewVector(c);
+ BOOST_FOREACH(string id, ad->transitionIdents()) {
+ naVec_append(*out, stringToNasal(c, id));
+ }
+ } else {
+ return 0;
+ }
+
+ return "";
+}
+
static const char* runwayGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
}
std::string ident(naStr_data(args[0]));
+ boost::to_upper(ident);
if (!apt->hasRunwayWithIdent(ident)) {
return naNil();
}
naRef sids = naNewVector(c);
+ FGRunway* rwy = NULL;
if (argc > 0 && naIsString(args[0])) {
if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
return naNil();
}
- FGRunway* rwy = apt->getRunwayByIdent(naStr_data(args[0]));
+ rwy = apt->getRunwayByIdent(naStr_data(args[0]));
+ } else if (argc > 0) {
+ rwy = runwayGhost(args[0]);
+ }
+
+ if (rwy) {
BOOST_FOREACH(flightgear::SID* sid, rwy->getSIDs()) {
naRef procId = stringToNasal(c, sid->ident());
naVec_append(sids, procId);
naRef stars = naNewVector(c);
+ FGRunway* rwy = NULL;
if (argc > 0 && naIsString(args[0])) {
if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
return naNil();
}
- FGRunway* rwy = apt->getRunwayByIdent(naStr_data(args[0]));
+ rwy = apt->getRunwayByIdent(naStr_data(args[0]));
+ } else if (argc > 0) {
+ rwy = runwayGhost(args[0]);
+ }
+
+ if (rwy) {
BOOST_FOREACH(flightgear::STAR* s, rwy->getSTARs()) {
naRef procId = stringToNasal(c, s->ident());
naVec_append(stars, procId);
return stars;
}
+static naRef f_airport_approaches(naContext c, naRef me, int argc, naRef* args)
+{
+ FGAirport* apt = airportGhost(me);
+ if (!apt) {
+ naRuntimeError(c, "airport.getApproachList called on non-airport object");
+ }
+
+ naRef approaches = naNewVector(c);
+
+ ProcedureType ty = PROCEDURE_INVALID;
+ if ((argc > 1) && naIsString(args[1])) {
+ std::string u(naStr_data(args[1]));
+ boost::to_upper(u);
+ if (u == "NDB") ty = PROCEDURE_APPROACH_NDB;
+ if (u == "VOR") ty = PROCEDURE_APPROACH_VOR;
+ if (u == "ILS") ty = PROCEDURE_APPROACH_ILS;
+ if (u == "RNAV") ty = PROCEDURE_APPROACH_RNAV;
+ }
+
+ FGRunway* rwy = NULL;
+ if (argc > 0 && (rwy = runwayGhost(args[0]))) {
+ // ok
+ } else if (argc > 0 && naIsString(args[0])) {
+ if (!apt->hasRunwayWithIdent(naStr_data(args[0]))) {
+ return naNil();
+ }
+
+ rwy = apt->getRunwayByIdent(naStr_data(args[0]));
+ }
+
+ if (rwy) {
+ BOOST_FOREACH(Approach* s, rwy->getApproaches()) {
+ if ((ty != PROCEDURE_INVALID) && (s->type() != ty)) {
+ continue;
+ }
+
+ naRef procId = stringToNasal(c, s->ident());
+ naVec_append(approaches, procId);
+ }
+ } else {
+ // no runway specified, report them all
+ for (unsigned int s=0; s<apt->numApproaches(); ++s) {
+ Approach* app = apt->getApproachByIndex(s);
+ if ((ty != PROCEDURE_INVALID) && (app->type() != ty)) {
+ continue;
+ }
+
+ naRef procId = stringToNasal(c, app->ident());
+ naVec_append(approaches, procId);
+ }
+ }
+
+ return approaches;
+}
+
static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
{
FGAirport* apt = airportGhost(me);
return r;
}
+static naRef f_airport_getSid(naContext c, naRef me, int argc, naRef* args)
+{
+ FGAirport* apt = airportGhost(me);
+ if (!apt) {
+ naRuntimeError(c, "airport.getSid called on non-airport object");
+ }
+
+ if ((argc != 1) || !naIsString(args[0])) {
+ naRuntimeError(c, "airport.getSid passed invalid argument");
+ }
+
+ string ident = naStr_data(args[0]);
+ return ghostForProcedure(c, apt->findSIDWithIdent(ident));
+}
+
+static naRef f_airport_getStar(naContext c, naRef me, int argc, naRef* args)
+{
+ FGAirport* apt = airportGhost(me);
+ if (!apt) {
+ naRuntimeError(c, "airport.getStar called on non-airport object");
+ }
+
+ if ((argc != 1) || !naIsString(args[0])) {
+ naRuntimeError(c, "airport.getStar passed invalid argument");
+ }
+
+ string ident = naStr_data(args[0]);
+ return ghostForProcedure(c, apt->findSTARWithIdent(ident));
+}
+
+static naRef f_airport_getApproach(naContext c, naRef me, int argc, naRef* args)
+{
+ FGAirport* apt = airportGhost(me);
+ if (!apt) {
+ naRuntimeError(c, "airport.getIAP called on non-airport object");
+ }
+
+ if ((argc != 1) || !naIsString(args[0])) {
+ naRuntimeError(c, "airport.getIAP passed invalid argument");
+ }
+
+ string ident = naStr_data(args[0]);
+ return ghostForProcedure(c, apt->findApproachWithIdent(ident));
+}
+
// Returns vector of data hash for navaid of a <type>, nil on error
// navaids sorted by ascending distance
// navinfo([<lat>,<lon>],[<type>],[<id>])
static naRef f_route(naContext c, naRef me, int argc, naRef* args)
{
- naRef route = naNewHash(c);
-
- // return active route hash by default,
- // other routes in the future
+ if (argc == 0) {
+ FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
+ return ghostForFlightPlan(c, rm->flightPlan());
+ }
- naRef parents = naNewVector(c);
- naVec_append(parents, routePrototype);
- hashset(c, route, "parents", parents);
+ if ((argc > 0) && naIsString(args[0])) {
+ flightgear::FlightPlan* fp = new flightgear::FlightPlan;
+ SGPath path(naStr_data(args[0]));
+ if (!path.exists()) {
+ naRuntimeError(c, "flightplan, no file at path %s", path.c_str());
+ }
+
+ if (!fp->load(path)) {
+ SG_LOG(SG_NASAL, SG_WARN, "failed to load flight-plan from " << path);
+ delete fp;
+ return naNil();
+ }
+
+ return ghostForFlightPlan(c, fp);
+ }
- return route;
+ naRuntimeError(c, "bad arguments to flightplan()");
+ return naNil();
}
-static naRef f_route_getWP(naContext c, naRef me, int argc, naRef* args)
+static naRef f_flightplan_getWP(naContext c, naRef me, int argc, naRef* args)
{
- FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
-
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.getWP called on non-flightplan object");
+ }
+
int index;
if (argc == 0) {
- index = rm->currentIndex();
+ index = fp->currentIndex();
} else {
index = (int) naNumValue(args[0]).num;
}
- if ((index < 0) || (index >= rm->numWaypts())) {
+ if ((index < 0) || (index >= fp->numLegs())) {
return naNil();
}
- return ghostForWaypt(c, rm->wayptAtIndex(index));
+ return ghostForLeg(c, fp->legAtIndex(index));
}
-static naRef f_route_currentWP(naContext c, naRef me, int argc, naRef* args)
+static naRef f_flightplan_currentWP(naContext c, naRef me, int argc, naRef* args)
{
- FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
- return ghostForWaypt(c, rm->currentWaypt());
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.currentWP called on non-flightplan object");
+ }
+ return ghostForLeg(c, fp->currentLeg());
}
-static naRef f_route_nextWP(naContext c, naRef me, int argc, naRef* args)
+static naRef f_flightplan_nextWP(naContext c, naRef me, int argc, naRef* args)
{
- FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
- flightgear::WayptRef wp = rm->nextWaypt();
- if (!wp) {
- return naNil();
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.nextWP called on non-flightplan object");
+ }
+ return ghostForLeg(c, fp->nextLeg());
+}
+
+static naRef f_flightplan_numWaypoints(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.numWaypoints called on non-flightplan object");
+ }
+ return naNum(fp->numLegs());
+}
+
+static naRef f_flightplan_appendWP(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.appendWP called on non-flightplan object");
}
- return ghostForWaypt(c, wp);
+
+ WayptRef wp = wayptGhost(args[0]);
+ int index = fp->numLegs();
+ fp->insertWayptAtIndex(wp.get(), index);
+ return naNum(index);
+}
+
+static naRef f_flightplan_insertWP(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.insertWP called on non-flightplan object");
+ }
+
+ WayptRef wp = wayptGhost(args[0]);
+ int index = -1; // append
+ if ((argc > 1) && naIsNum(args[1])) {
+ index = (int) args[1].num;
+ }
+
+ fp->insertWayptAtIndex(wp.get(), index);
+ return naNil();
+}
+
+static naRef f_flightplan_insertWPAfter(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.insertWPAfter called on non-flightplan object");
+ }
+
+ WayptRef wp = wayptGhost(args[0]);
+ int index = -1; // append
+ if ((argc > 1) && naIsNum(args[1])) {
+ index = (int) args[1].num;
+ }
+
+ fp->insertWayptAtIndex(wp.get(), index + 1);
+ return naNil();
+}
+
+static naRef f_flightplan_insertWaypoints(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.insertWaypoints called on non-flightplan object");
+ }
+
+ WayptVec wps;
+ if (!naIsVector(args[0])) {
+ naRuntimeError(c, "flightplan.insertWaypoints expects vector as first arg");
+ }
+
+ int count = naVec_size(args[0]);
+ for (int i=0; i<count; ++i) {
+ Waypt* wp = wayptGhost(naVec_get(args[0], i));
+ if (wp) {
+ wps.push_back(wp);
+ }
+ }
+
+ int index = -1; // append
+ if ((argc > 1) && naIsNum(args[1])) {
+ index = (int) args[1].num;
+ }
+
+ fp->insertWayptsAtIndex(wps, index);
+ return naNil();
+}
+
+static naRef f_flightplan_clearPlan(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.clearPlan called on non-flightplan object");
+ }
+
+ fp->clear();
+ return naNil();
}
-static naRef f_route_currentIndex(naContext c, naRef me, int argc, naRef* args)
+static WayptFlag wayptFlagFromString(const char* s)
{
- FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
- return naNum(rm->currentIndex());
+ if (!strcmp(s, "sid")) return WPT_DEPARTURE;
+ if (!strcmp(s, "star")) return WPT_ARRIVAL;
+ if (!strcmp(s, "approach")) return WPT_APPROACH;
+ if (!strcmp(s, "missed")) return WPT_MISS;
+ if (!strcmp(s, "pseudo")) return WPT_PSEUDO;
+
+ return (WayptFlag) 0;
+}
+
+static naRef f_flightplan_clearWPType(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.clearWPType called on non-flightplan object");
+ }
+
+ if (argc < 1) {
+ naRuntimeError(c, "insufficent args to flightplan.clearWPType");
+ }
+
+ WayptFlag flag = wayptFlagFromString(naStr_data(args[0]));
+ fp->clearWayptsWithFlag(flag);
+ return naNil();
+}
+
+static naRef f_flightplan_clone(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan* fp = flightplanGhost(me);
+ if (!fp) {
+ naRuntimeError(c, "flightplan.clone called on non-flightplan object");
+ }
+
+ return ghostForFlightPlan(c, fp->clone());
}
-static naRef f_route_numWaypoints(naContext c, naRef me, int argc, naRef* args)
+static naRef f_leg_setSpeed(naContext c, naRef me, int argc, naRef* args)
{
- FGRouteMgr* rm = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
- return naNum(rm->numWaypts());
+ FlightPlan::Leg* leg = fpLegGhost(me);
+ if (!leg) {
+ naRuntimeError(c, "leg.setSpeed called on non-flightplan-leg object");
+ }
+
+ if (argc < 2) {
+ naRuntimeError(c, "bad arguments to leg.setSpeed");
+ }
+
+ RouteRestriction rr = routeRestrictionFromString(naStr_data(args[1]));
+ leg->setSpeed(rr, args[0].num);
+ return naNil();
+}
+
+static naRef f_leg_setAltitude(naContext c, naRef me, int argc, naRef* args)
+{
+ FlightPlan::Leg* leg = fpLegGhost(me);
+ if (!leg) {
+ naRuntimeError(c, "leg.setAltitude called on non-flightplan-leg object");
+ }
+
+ if (argc < 2) {
+ naRuntimeError(c, "bad arguments to leg.setAltitude");
+ }
+
+ RouteRestriction rr = routeRestrictionFromString(naStr_data(args[1]));
+ leg->setAltitude(rr, args[0].num);
+ return naNil();
}
static naRef f_waypoint_navaid(naContext c, naRef me, int argc, naRef* args)
return ghostForRunway(c, (FGRunway*) pos);
}
+static naRef f_procedure_transition(naContext c, naRef me, int argc, naRef* args)
+{
+ Procedure* proc = procedureGhost(me);
+ if (!proc) {
+ naRuntimeError(c, "procedure.transition called on non-procedure object");
+ }
+
+ if ((proc->type() != PROCEDURE_SID) && (proc->type() != PROCEDURE_STAR)) {
+ naRuntimeError(c, "procedure.transition called on non-SID or -STAR");
+ }
+
+ ArrivalDeparture* ad = (ArrivalDeparture*) proc;
+ Transition* trans = ad->findTransitionByName(naStr_data(args[0]));
+
+ return ghostForProcedure(c, trans);
+}
+
// Table of extension functions. Terminate with zeros.
static struct { const char* name; naCFunction func; } funcs[] = {
{ "carttogeod", f_carttogeod },
{ "findNavaidByFrequency", f_findNavaidByFrequency },
{ "findNavaidsByFrequency", f_findNavaidsByFrequency },
{ "findNavaidsByID", f_findNavaidsByIdent },
- { "route", f_route },
+ { "flightplan", f_route },
{ "magvar", f_magvar },
{ "courseAndDistance", f_courseAndDistance },
{ "greatCircleMove", f_greatCircleMove },
hashset(c, airportPrototype, "comms", naNewFunc(c, naNewCCode(c, f_airport_comms)));
hashset(c, airportPrototype, "sids", naNewFunc(c, naNewCCode(c, f_airport_sids)));
hashset(c, airportPrototype, "stars", naNewFunc(c, naNewCCode(c, f_airport_stars)));
+ hashset(c, airportPrototype, "getApproachList", naNewFunc(c, naNewCCode(c, f_airport_approaches)));
hashset(c, airportPrototype, "parking", naNewFunc(c, naNewCCode(c, f_airport_parking)));
+ hashset(c, airportPrototype, "getSid", naNewFunc(c, naNewCCode(c, f_airport_getSid)));
+ hashset(c, airportPrototype, "getStar", naNewFunc(c, naNewCCode(c, f_airport_getStar)));
+ hashset(c, airportPrototype, "getIAP", naNewFunc(c, naNewCCode(c, f_airport_getApproach)));
- routePrototype = naNewHash(c);
- hashset(c, gcSave, "routeProto", routePrototype);
+ flightplanPrototype = naNewHash(c);
+ hashset(c, gcSave, "flightplanProto", flightplanPrototype);
- hashset(c, routePrototype, "getWP", naNewFunc(c, naNewCCode(c, f_route_getWP)));
- hashset(c, routePrototype, "currentWP", naNewFunc(c, naNewCCode(c, f_route_currentWP)));
- hashset(c, routePrototype, "nextWP", naNewFunc(c, naNewCCode(c, f_route_nextWP)));
- hashset(c, routePrototype, "currentIndex", naNewFunc(c, naNewCCode(c, f_route_currentIndex)));
- hashset(c, routePrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_route_numWaypoints)));
-
+ hashset(c, flightplanPrototype, "getWP", naNewFunc(c, naNewCCode(c, f_flightplan_getWP)));
+ hashset(c, flightplanPrototype, "currentWP", naNewFunc(c, naNewCCode(c, f_flightplan_currentWP)));
+ hashset(c, flightplanPrototype, "nextWP", naNewFunc(c, naNewCCode(c, f_flightplan_nextWP)));
+ hashset(c, flightplanPrototype, "getPlanSize", naNewFunc(c, naNewCCode(c, f_flightplan_numWaypoints)));
+ hashset(c, flightplanPrototype, "appendWP", naNewFunc(c, naNewCCode(c, f_flightplan_appendWP)));
+ hashset(c, flightplanPrototype, "insertWP", naNewFunc(c, naNewCCode(c, f_flightplan_insertWP)));
+ hashset(c, flightplanPrototype, "insertWPAfter", naNewFunc(c, naNewCCode(c, f_flightplan_insertWPAfter)));
+ hashset(c, flightplanPrototype, "insertWaypoints", naNewFunc(c, naNewCCode(c, f_flightplan_insertWaypoints)));
+ hashset(c, flightplanPrototype, "cleanPlan", naNewFunc(c, naNewCCode(c, f_flightplan_clearPlan)));
+ hashset(c, flightplanPrototype, "clearWPType", naNewFunc(c, naNewCCode(c, f_flightplan_clearWPType)));
+ hashset(c, flightplanPrototype, "clone", naNewFunc(c, naNewCCode(c, f_flightplan_clone)));
+
waypointPrototype = naNewHash(c);
hashset(c, gcSave, "wayptProto", waypointPrototype);
hashset(c, waypointPrototype, "runway", naNewFunc(c, naNewCCode(c, f_waypoint_runway)));
hashset(c, waypointPrototype, "airport", naNewFunc(c, naNewCCode(c, f_waypoint_airport)));
+ procedurePrototype = naNewHash(c);
+ hashset(c, gcSave, "procedureProto", procedurePrototype);
+ // hashset(c, procedurePrototype, "runwayTransition", naNewFunc(c, naNewCCode(c, f_procedure_runwayTransition)));
+ hashset(c, procedurePrototype, "transition", naNewFunc(c, naNewCCode(c, f_procedure_transition)));
+ // hashset(c, procedurePrototype, "buildPath", naNewFunc(c, naNewCCode(c, f_procedure_build)));
+
+ fpLegPrototype = naNewHash(c);
+ hashset(c, gcSave, "fpLegProto", fpLegPrototype);
+ hashset(c, fpLegPrototype, "setSpeed", naNewFunc(c, naNewCCode(c, f_leg_setSpeed)));
+ hashset(c, fpLegPrototype, "setAltitude", naNewFunc(c, naNewCCode(c, f_leg_setAltitude)));
+
for(int i=0; funcs[i].name; i++) {
hashset(c, globals, funcs[i].name,
naNewFunc(c, naNewCCode(c, funcs[i].func)));