From 1ef77b2bc2cc98ff665161b0f7cc7ea80327cb5c Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 15 May 2012 17:53:30 +0100 Subject: [PATCH] More route-manager functionality moved to Nasal. The routing behaviour now happens entirely in Nasal, using a delegate, and can be over-ridden or disable by aircraft authors. Default behaviour should be unchanged. --- src/Autopilot/route_mgr.cxx | 71 ---------- src/Autopilot/route_mgr.hxx | 6 - src/Navaids/FlightPlan.cxx | 227 +++++++++++++++++++----------- src/Navaids/FlightPlan.hxx | 8 ++ src/Navaids/procedure.cxx | 4 +- src/Scripting/NasalPositioned.cxx | 36 +++-- 6 files changed, 183 insertions(+), 169 deletions(-) diff --git a/src/Autopilot/route_mgr.cxx b/src/Autopilot/route_mgr.cxx index ffb9dc306..3be33129f 100644 --- a/src/Autopilot/route_mgr.cxx +++ b/src/Autopilot/route_mgr.cxx @@ -585,77 +585,6 @@ void FGRouteMgr::removeLegAtIndex(int aIndex) _plan->deleteIndex(aIndex); } -void FGRouteMgr::departureChanged() -{ - _plan->clearWayptsWithFlag(WPT_DEPARTURE); - WayptRef enroute; - WayptVec wps; - buildDeparture(enroute, wps); - _plan->insertWayptsAtIndex(wps, 0); -} - -void FGRouteMgr::buildDeparture(WayptRef enroute, WayptVec& wps) -{ - if (!_plan->departureAirport()) { - return; - } - - 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; - } - - 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() -{ - _plan->clearWayptsWithFlag(WPT_ARRIVAL); - _plan->clearWayptsWithFlag(WPT_APPROACH); - WayptVec wps; - WayptRef enroute; - buildArrival(enroute, wps); - _plan->insertWayptsAtIndex(wps, -1); -} - -void FGRouteMgr::buildArrival(WayptRef enroute, WayptVec& wps) -{ - FGAirportRef apt = _plan->destinationAirport(); - if (!apt.valid()) { - return; - } - - if (!_plan->destinationRunway()) { - WayptRef w = new NavaidWaypoint(apt.ptr(), _plan); - w->setFlag(WPT_ARRIVAL); - wps.push_back(w); - return; - } - - if (_plan->star()) { - _plan->star()->route(_plan->destinationRunway(), _plan->starTransition(), wps); - } - - 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); - } -} - void FGRouteMgr::waypointsChanged() { update_mirror(); diff --git a/src/Autopilot/route_mgr.hxx b/src/Autopilot/route_mgr.hxx index bb16fc668..d0adfb4a1 100644 --- a/src/Autopilot/route_mgr.hxx +++ b/src/Autopilot/route_mgr.hxx @@ -172,12 +172,6 @@ private: InputListener *listener; SGPropertyNode_ptr mirror; - virtual void departureChanged(); - void buildDeparture(flightgear::WayptRef enroute, flightgear::WayptVec& wps); - - virtual void arrivalChanged(); - void buildArrival(flightgear::WayptRef enroute, flightgear::WayptVec& wps); - /** * Helper to keep various pieces of state in sync when the route is * modified (waypoints added, inserted, removed). Notably, this fires the diff --git a/src/Navaids/FlightPlan.cxx b/src/Navaids/FlightPlan.cxx index 5630bea67..5f5ba5e71 100644 --- a/src/Navaids/FlightPlan.cxx +++ b/src/Navaids/FlightPlan.cxx @@ -27,6 +27,7 @@ // std #include #include +#include // Boost #include @@ -59,6 +60,7 @@ typedef std::vector FPDelegateFactoryVec; static FPDelegateFactoryVec static_delegateFactories; FlightPlan::FlightPlan() : + _delegateLock(0), _currentIndex(-1), _departureRunway(NULL), _destinationRunway(NULL), @@ -67,6 +69,8 @@ FlightPlan::FlightPlan() : _approach(NULL), _delegate(NULL) { + _departureChanged = _arrivalChanged = _waypointsChanged = _currentWaypointChanged = false; + BOOST_FOREACH(DelegateFactory* factory, static_delegateFactories) { Delegate* d = factory->createFlightPlanDelegate(this); if (d) { // factory might not always create a delegate @@ -93,6 +97,7 @@ FlightPlan* FlightPlan::clone(const string& newIdent) const { FlightPlan* c = new FlightPlan(); c->_ident = newIdent.empty() ? _ident : newIdent; + c->lockDelegate(); // copy destination / departure data. c->setDeparture(_departure); @@ -110,10 +115,11 @@ FlightPlan* FlightPlan::clone(const string& newIdent) const c->setSID(_sid); // copy legs + c->_waypointsChanged = true; for (int l=0; l < numLegs(); ++l) { c->_legs.push_back(_legs[l]->cloneFor(c)); } - + c->unlockDelegate(); return c; } @@ -169,12 +175,10 @@ void FlightPlan::insertWayptsAtIndex(const WayptVec& wps, int aIndex) newLegs.push_back(new Leg(this, wp)); } + lockDelegate(); + _waypointsChanged = true; _legs.insert(it, newLegs.begin(), newLegs.end()); - rebuildLegData(); - - if (_delegate) { - _delegate->runWaypointsChanged(); - } + unlockDelegate(); } void FlightPlan::deleteIndex(int aIndex) @@ -188,77 +192,95 @@ void FlightPlan::deleteIndex(int aIndex) SG_LOG(SG_AUTOPILOT, SG_WARN, "removeAtIndex with invalid index:" << aIndex); return; } + + lockDelegate(); + _waypointsChanged = true; + 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; + _currentWaypointChanged = true; } else if (_currentIndex > index) { --_currentIndex; // shift current index down if necessary } - - rebuildLegData(); - if (_delegate) { - _delegate->runWaypointsChanged(); - if (curChanged) { - _delegate->runCurrentWaypointChanged(); - } - } + + unlockDelegate(); } void FlightPlan::clear() { + lockDelegate(); + _waypointsChanged = true; + _currentWaypointChanged = true; + _arrivalChanged = true; + _departureChanged = true; + _currentIndex = -1; BOOST_FOREACH(Leg* l, _legs) { delete l; } _legs.clear(); - rebuildLegData(); - if (_delegate) { - _delegate->runDepartureChanged(); - _delegate->runArrivalChanged(); - _delegate->runWaypointsChanged(); - _delegate->runCurrentWaypointChanged(); - } + + unlockDelegate(); } +class RemoveWithFlag +{ +public: + RemoveWithFlag(WayptFlag f) : flag(f), delCount(0) { } + + int numDeleted() const { return delCount; } + + bool operator()(FlightPlan::Leg* leg) const + { + if (leg->waypoint()->flag(flag)) { + std::cout << "deleting" << leg << std::endl; + delete leg; + ++delCount; + return true; + } + + return false; + } +private: + WayptFlag flag; + mutable int delCount; +}; + int FlightPlan::clearWayptsWithFlag(WayptFlag flag) { int count = 0; - for (unsigned int i=0; i<_legs.size(); ++i) { +// first pass, fix up currentIndex + for (int i=0; i<_currentIndex; ++i) { Leg* l = _legs[i]; - if (!l->waypoint()->flag(flag)) { - continue; + if (l->waypoint()->flag(flag)) { + ++count; } - - // 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) { + + _currentIndex -= count; + +// now delete and remove + RemoveWithFlag rf(flag); + LegVec::iterator it = std::remove_if(_legs.begin(), _legs.end(), rf); + if (it == _legs.end()) { return 0; // nothing was cleared, don't fire the delegate } - rebuildLegData(); - if (_delegate) { - _delegate->runWaypointsChanged(); - _delegate->runCurrentWaypointChanged(); + lockDelegate(); + _waypointsChanged = true; + if (count > 0) { + _currentWaypointChanged = true; } - return count; + _legs.erase(it, _legs.end()); + unlockDelegate(); + return rf.numDeleted(); } void FlightPlan::setCurrentIndex(int index) @@ -271,10 +293,10 @@ void FlightPlan::setCurrentIndex(int index) return; } + lockDelegate(); _currentIndex = index; - if (_delegate) { - _delegate->runCurrentWaypointChanged(); - } + _currentWaypointChanged = true; + unlockDelegate(); } int FlightPlan::findWayptIndex(const SGGeod& aPos) const @@ -339,13 +361,12 @@ void FlightPlan::setDeparture(FGAirport* apt) return; } + lockDelegate(); + _departureChanged = true; _departure = apt; _departureRunway = NULL; setSID((SID*)NULL); - - if (_delegate) { - _delegate->runDepartureChanged(); - } + unlockDelegate(); } void FlightPlan::setDeparture(FGRunway* rwy) @@ -354,15 +375,15 @@ void FlightPlan::setDeparture(FGRunway* rwy) return; } + lockDelegate(); + _departureChanged = true; + _departureRunway = rwy; if (rwy->airport() != _departure) { _departure = rwy->airport(); setSID((SID*)NULL); } - - if (_delegate) { - _delegate->runDepartureChanged(); - } + unlockDelegate(); } void FlightPlan::setSID(SID* sid, const std::string& transition) @@ -371,12 +392,11 @@ void FlightPlan::setSID(SID* sid, const std::string& transition) return; } + lockDelegate(); + _departureChanged = true; _sid = sid; _sidTransition = transition; - - if (_delegate) { - _delegate->runDepartureChanged(); - } + unlockDelegate(); } void FlightPlan::setSID(Transition* trans) @@ -407,13 +427,13 @@ void FlightPlan::setDestination(FGAirport* apt) return; } + lockDelegate(); + _arrivalChanged = true; _destination = apt; _destinationRunway = NULL; setSTAR((STAR*)NULL); - - if (_delegate) { - _delegate->runArrivalChanged(); - } + setApproach(NULL); + unlockDelegate(); } void FlightPlan::setDestination(FGRunway* rwy) @@ -422,15 +442,15 @@ void FlightPlan::setDestination(FGRunway* rwy) return; } + lockDelegate(); + _arrivalChanged = true; _destinationRunway = rwy; if (_destination != rwy->airport()) { _destination = rwy->airport(); setSTAR((STAR*)NULL); } - if (_delegate) { - _delegate->runArrivalChanged(); - } + unlockDelegate(); } void FlightPlan::setSTAR(STAR* star, const std::string& transition) @@ -439,12 +459,11 @@ void FlightPlan::setSTAR(STAR* star, const std::string& transition) return; } + lockDelegate(); + _arrivalChanged = true; _star = star; _starTransition = transition; - - if (_delegate) { - _delegate->runArrivalChanged(); - } + unlockDelegate(); } void FlightPlan::setSTAR(Transition* trans) @@ -475,6 +494,8 @@ void FlightPlan::setApproach(flightgear::Approach *app) return; } + lockDelegate(); + _arrivalChanged = true; _approach = app; if (app) { // keep runway + airport in sync @@ -486,10 +507,7 @@ void FlightPlan::setApproach(flightgear::Approach *app) _destination = _destinationRunway->airport(); } } - - if (_delegate) { - _delegate->runArrivalChanged(); - } + unlockDelegate(); } bool FlightPlan::save(const SGPath& path) @@ -554,12 +572,14 @@ bool FlightPlan::load(const SGPath& path) SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str()); bool Status = false; + lockDelegate(); 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; + _waypointsChanged = true; } if (routeData.valid()) @@ -581,11 +601,7 @@ bool FlightPlan::load(const SGPath& path) } } - rebuildLegData(); - if (_delegate) { - _delegate->runWaypointsChanged(); - } - + unlockDelegate(); return Status; } @@ -657,6 +673,7 @@ void FlightPlan::loadVersion2XMLRoute(SGPropertyNode_ptr routeData) Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode)); _legs.push_back(l); } // of route iteration + _waypointsChanged = true; } void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData) @@ -671,7 +688,7 @@ void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData) Leg* l = new Leg(this, parseVersion1XMLWaypt(wpNode)); _legs.push_back(l); } // of route iteration - + _waypointsChanged = true; } WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP) @@ -1003,6 +1020,56 @@ void FlightPlan::rebuildLegData() } // of legs iteration } +void FlightPlan::lockDelegate() +{ + if (_delegateLock == 0) { + assert(!_departureChanged && !_arrivalChanged && + !_waypointsChanged && !_currentWaypointChanged); + } + + ++_delegateLock; +} + +void FlightPlan::unlockDelegate() +{ + assert(_delegateLock > 0); + if (_delegateLock > 1) { + --_delegateLock; + return; + } + + if (_departureChanged) { + _departureChanged = false; + if (_delegate) { + _delegate->runDepartureChanged(); + } + } + + if (_arrivalChanged) { + _arrivalChanged = false; + if (_delegate) { + _delegate->runArrivalChanged(); + } + } + + if (_waypointsChanged) { + _waypointsChanged = false; + rebuildLegData(); + if (_delegate) { + _delegate->runWaypointsChanged(); + } + } + + if (_currentWaypointChanged) { + _currentWaypointChanged = false; + if (_delegate) { + _delegate->runCurrentWaypointChanged(); + } + } + + --_delegateLock; +} + void FlightPlan::registerDelegateFactory(DelegateFactory* df) { FPDelegateFactoryVec::iterator it = std::find(static_delegateFactories.begin(), diff --git a/src/Navaids/FlightPlan.hxx b/src/Navaids/FlightPlan.hxx index 4558d16dd..78dc7e6ab 100644 --- a/src/Navaids/FlightPlan.hxx +++ b/src/Navaids/FlightPlan.hxx @@ -224,6 +224,14 @@ public: void addDelegate(Delegate* d); void removeDelegate(Delegate* d); private: + void lockDelegate(); + void unlockDelegate(); + + int _delegateLock; + bool _arrivalChanged, + _departureChanged, + _waypointsChanged, + _currentWaypointChanged; bool loadPlainTextRoute(const SGPath& path); diff --git a/src/Navaids/procedure.cxx b/src/Navaids/procedure.cxx index be3df3204..bb53a6429 100644 --- a/src/Navaids/procedure.cxx +++ b/src/Navaids/procedure.cxx @@ -118,7 +118,9 @@ bool Approach::route(WayptRef aIAF, WayptVec& aWps) bool Approach::routeFromVectors(WayptVec& aWps) { aWps.insert(aWps.end(), _primary.begin(), _primary.end()); - aWps.push_back(new RunwayWaypt(_runway, NULL)); + RunwayWaypt* rwy = new RunwayWaypt(_runway, NULL); + rwy->setFlag(WPT_APPROACH); + aWps.push_back(rwy); aWps.insert(aWps.end(), _missed.begin(), _missed.end()); return true; } diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index 1baf07d04..53a3a41e7 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -75,10 +75,12 @@ static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* o naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, 0 }; static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out); +static void waypointGhostSetMember(naContext c, void* g, naRef field, naRef value); + naGhostType WayptGhostType = { wayptGhostDestroy, "waypoint", wayptGhostGetMember, - 0}; + waypointGhostSetMember}; static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out); static void legGhostSetMember(naContext c, void* g, naRef field, naRef value); @@ -382,6 +384,20 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char* return ""; } +static void waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldName, naRef value) +{ + if (!strcmp(fieldName, "wp_role")) { + if (!naIsString(value)) naRuntimeError(c, "wp_role must be a string"); + if (wpt->owner() != NULL) naRuntimeError(c, "cannot override wp_role on waypoint with parent"); + WayptFlag f = wayptFlagFromString(naStr_data(value)); + if (f == 0) { + naRuntimeError(c, "unrecognized wp_role value %s", naStr_data(value)); + } + + wpt->setFlag(f, true); + } +} + static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -450,21 +466,19 @@ static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* o return ""; // success } +static void waypointGhostSetMember(naContext c, void* g, naRef field, naRef value) +{ + const char* fieldName = naStr_data(field); + Waypt* wpt = (Waypt*) g; + waypointCommonSetMember(c, wpt, fieldName, value); +} + static void legGhostSetMember(naContext c, void* g, naRef field, naRef value) { const char* fieldName = naStr_data(field); FlightPlan::Leg* leg = (FlightPlan::Leg*) g; - - if (!strcmp(fieldName, "wp_role")) { - if (!naIsString(value)) naRuntimeError(c, "wp_role must be a string"); - if (leg->waypoint()->owner() != NULL) naRuntimeError(c, "cannot override wp_role on waypoint with parent"); - WayptFlag f = wayptFlagFromString(naStr_data(value)); - if (f == 0) { - naRuntimeError(c, "unrecognized wp_role value %s", naStr_data(value)); - } - leg->waypoint()->setFlag(f, true); - } + waypointCommonSetMember(c, leg->waypoint(), fieldName, value); } static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out)