1
0
Fork 0

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.
This commit is contained in:
James Turner 2012-05-15 17:53:30 +01:00
parent 73a3434421
commit 1ef77b2bc2
6 changed files with 183 additions and 169 deletions

View file

@ -585,77 +585,6 @@ void FGRouteMgr::removeLegAtIndex(int aIndex)
_plan->deleteIndex(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() void FGRouteMgr::waypointsChanged()
{ {
update_mirror(); update_mirror();

View file

@ -172,12 +172,6 @@ private:
InputListener *listener; InputListener *listener;
SGPropertyNode_ptr mirror; 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 * Helper to keep various pieces of state in sync when the route is
* modified (waypoints added, inserted, removed). Notably, this fires the * modified (waypoints added, inserted, removed). Notably, this fires the

View file

@ -27,6 +27,7 @@
// std // std
#include <map> #include <map>
#include <fstream> #include <fstream>
#include <cassert>
// Boost // Boost
#include <boost/algorithm/string/case_conv.hpp> #include <boost/algorithm/string/case_conv.hpp>
@ -59,6 +60,7 @@ typedef std::vector<FlightPlan::DelegateFactory*> FPDelegateFactoryVec;
static FPDelegateFactoryVec static_delegateFactories; static FPDelegateFactoryVec static_delegateFactories;
FlightPlan::FlightPlan() : FlightPlan::FlightPlan() :
_delegateLock(0),
_currentIndex(-1), _currentIndex(-1),
_departureRunway(NULL), _departureRunway(NULL),
_destinationRunway(NULL), _destinationRunway(NULL),
@ -67,6 +69,8 @@ FlightPlan::FlightPlan() :
_approach(NULL), _approach(NULL),
_delegate(NULL) _delegate(NULL)
{ {
_departureChanged = _arrivalChanged = _waypointsChanged = _currentWaypointChanged = false;
BOOST_FOREACH(DelegateFactory* factory, static_delegateFactories) { BOOST_FOREACH(DelegateFactory* factory, static_delegateFactories) {
Delegate* d = factory->createFlightPlanDelegate(this); Delegate* d = factory->createFlightPlanDelegate(this);
if (d) { // factory might not always create a delegate if (d) { // factory might not always create a delegate
@ -93,6 +97,7 @@ FlightPlan* FlightPlan::clone(const string& newIdent) const
{ {
FlightPlan* c = new FlightPlan(); FlightPlan* c = new FlightPlan();
c->_ident = newIdent.empty() ? _ident : newIdent; c->_ident = newIdent.empty() ? _ident : newIdent;
c->lockDelegate();
// copy destination / departure data. // copy destination / departure data.
c->setDeparture(_departure); c->setDeparture(_departure);
@ -110,10 +115,11 @@ FlightPlan* FlightPlan::clone(const string& newIdent) const
c->setSID(_sid); c->setSID(_sid);
// copy legs // copy legs
c->_waypointsChanged = true;
for (int l=0; l < numLegs(); ++l) { for (int l=0; l < numLegs(); ++l) {
c->_legs.push_back(_legs[l]->cloneFor(c)); c->_legs.push_back(_legs[l]->cloneFor(c));
} }
c->unlockDelegate();
return c; return c;
} }
@ -169,12 +175,10 @@ void FlightPlan::insertWayptsAtIndex(const WayptVec& wps, int aIndex)
newLegs.push_back(new Leg(this, wp)); newLegs.push_back(new Leg(this, wp));
} }
lockDelegate();
_waypointsChanged = true;
_legs.insert(it, newLegs.begin(), newLegs.end()); _legs.insert(it, newLegs.begin(), newLegs.end());
rebuildLegData(); unlockDelegate();
if (_delegate) {
_delegate->runWaypointsChanged();
}
} }
void FlightPlan::deleteIndex(int aIndex) 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); SG_LOG(SG_AUTOPILOT, SG_WARN, "removeAtIndex with invalid index:" << aIndex);
return; return;
} }
lockDelegate();
_waypointsChanged = true;
LegVec::iterator it = _legs.begin(); LegVec::iterator it = _legs.begin();
it += index; it += index;
Leg* l = *it; Leg* l = *it;
_legs.erase(it); _legs.erase(it);
delete l; delete l;
bool curChanged = false;
if (_currentIndex == index) { if (_currentIndex == index) {
// current waypoint was removed // current waypoint was removed
curChanged = true; _currentWaypointChanged = true;
} else if (_currentIndex > index) { } else if (_currentIndex > index) {
--_currentIndex; // shift current index down if necessary --_currentIndex; // shift current index down if necessary
} }
rebuildLegData(); unlockDelegate();
if (_delegate) {
_delegate->runWaypointsChanged();
if (curChanged) {
_delegate->runCurrentWaypointChanged();
}
}
} }
void FlightPlan::clear() void FlightPlan::clear()
{ {
lockDelegate();
_waypointsChanged = true;
_currentWaypointChanged = true;
_arrivalChanged = true;
_departureChanged = true;
_currentIndex = -1; _currentIndex = -1;
BOOST_FOREACH(Leg* l, _legs) { BOOST_FOREACH(Leg* l, _legs) {
delete l; delete l;
} }
_legs.clear(); _legs.clear();
rebuildLegData();
if (_delegate) { unlockDelegate();
_delegate->runDepartureChanged();
_delegate->runArrivalChanged();
_delegate->runWaypointsChanged();
_delegate->runCurrentWaypointChanged();
}
} }
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 FlightPlan::clearWayptsWithFlag(WayptFlag flag)
{ {
int count = 0; 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]; Leg* l = _legs[i];
if (!l->waypoint()->flag(flag)) { if (l->waypoint()->flag(flag)) {
continue; ++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 return 0; // nothing was cleared, don't fire the delegate
} }
rebuildLegData(); lockDelegate();
if (_delegate) { _waypointsChanged = true;
_delegate->runWaypointsChanged(); if (count > 0) {
_delegate->runCurrentWaypointChanged(); _currentWaypointChanged = true;
} }
return count; _legs.erase(it, _legs.end());
unlockDelegate();
return rf.numDeleted();
} }
void FlightPlan::setCurrentIndex(int index) void FlightPlan::setCurrentIndex(int index)
@ -271,10 +293,10 @@ void FlightPlan::setCurrentIndex(int index)
return; return;
} }
lockDelegate();
_currentIndex = index; _currentIndex = index;
if (_delegate) { _currentWaypointChanged = true;
_delegate->runCurrentWaypointChanged(); unlockDelegate();
}
} }
int FlightPlan::findWayptIndex(const SGGeod& aPos) const int FlightPlan::findWayptIndex(const SGGeod& aPos) const
@ -339,13 +361,12 @@ void FlightPlan::setDeparture(FGAirport* apt)
return; return;
} }
lockDelegate();
_departureChanged = true;
_departure = apt; _departure = apt;
_departureRunway = NULL; _departureRunway = NULL;
setSID((SID*)NULL); setSID((SID*)NULL);
unlockDelegate();
if (_delegate) {
_delegate->runDepartureChanged();
}
} }
void FlightPlan::setDeparture(FGRunway* rwy) void FlightPlan::setDeparture(FGRunway* rwy)
@ -354,15 +375,15 @@ void FlightPlan::setDeparture(FGRunway* rwy)
return; return;
} }
lockDelegate();
_departureChanged = true;
_departureRunway = rwy; _departureRunway = rwy;
if (rwy->airport() != _departure) { if (rwy->airport() != _departure) {
_departure = rwy->airport(); _departure = rwy->airport();
setSID((SID*)NULL); setSID((SID*)NULL);
} }
unlockDelegate();
if (_delegate) {
_delegate->runDepartureChanged();
}
} }
void FlightPlan::setSID(SID* sid, const std::string& transition) void FlightPlan::setSID(SID* sid, const std::string& transition)
@ -371,12 +392,11 @@ void FlightPlan::setSID(SID* sid, const std::string& transition)
return; return;
} }
lockDelegate();
_departureChanged = true;
_sid = sid; _sid = sid;
_sidTransition = transition; _sidTransition = transition;
unlockDelegate();
if (_delegate) {
_delegate->runDepartureChanged();
}
} }
void FlightPlan::setSID(Transition* trans) void FlightPlan::setSID(Transition* trans)
@ -407,13 +427,13 @@ void FlightPlan::setDestination(FGAirport* apt)
return; return;
} }
lockDelegate();
_arrivalChanged = true;
_destination = apt; _destination = apt;
_destinationRunway = NULL; _destinationRunway = NULL;
setSTAR((STAR*)NULL); setSTAR((STAR*)NULL);
setApproach(NULL);
if (_delegate) { unlockDelegate();
_delegate->runArrivalChanged();
}
} }
void FlightPlan::setDestination(FGRunway* rwy) void FlightPlan::setDestination(FGRunway* rwy)
@ -422,15 +442,15 @@ void FlightPlan::setDestination(FGRunway* rwy)
return; return;
} }
lockDelegate();
_arrivalChanged = true;
_destinationRunway = rwy; _destinationRunway = rwy;
if (_destination != rwy->airport()) { if (_destination != rwy->airport()) {
_destination = rwy->airport(); _destination = rwy->airport();
setSTAR((STAR*)NULL); setSTAR((STAR*)NULL);
} }
if (_delegate) { unlockDelegate();
_delegate->runArrivalChanged();
}
} }
void FlightPlan::setSTAR(STAR* star, const std::string& transition) void FlightPlan::setSTAR(STAR* star, const std::string& transition)
@ -439,12 +459,11 @@ void FlightPlan::setSTAR(STAR* star, const std::string& transition)
return; return;
} }
lockDelegate();
_arrivalChanged = true;
_star = star; _star = star;
_starTransition = transition; _starTransition = transition;
unlockDelegate();
if (_delegate) {
_delegate->runArrivalChanged();
}
} }
void FlightPlan::setSTAR(Transition* trans) void FlightPlan::setSTAR(Transition* trans)
@ -475,6 +494,8 @@ void FlightPlan::setApproach(flightgear::Approach *app)
return; return;
} }
lockDelegate();
_arrivalChanged = true;
_approach = app; _approach = app;
if (app) { if (app) {
// keep runway + airport in sync // keep runway + airport in sync
@ -486,10 +507,7 @@ void FlightPlan::setApproach(flightgear::Approach *app)
_destination = _destinationRunway->airport(); _destination = _destinationRunway->airport();
} }
} }
unlockDelegate();
if (_delegate) {
_delegate->runArrivalChanged();
}
} }
bool FlightPlan::save(const SGPath& path) 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()); SG_LOG(SG_IO, SG_INFO, "going to read flight-plan from:" << path.str());
bool Status = false; bool Status = false;
lockDelegate();
try { try {
readProperties(path.str(), routeData); readProperties(path.str(), routeData);
} catch (sg_exception& ) { } catch (sg_exception& ) {
// if XML parsing fails, the file might be simple textual list of waypoints // if XML parsing fails, the file might be simple textual list of waypoints
Status = loadPlainTextRoute(path); Status = loadPlainTextRoute(path);
routeData = 0; routeData = 0;
_waypointsChanged = true;
} }
if (routeData.valid()) if (routeData.valid())
@ -581,11 +601,7 @@ bool FlightPlan::load(const SGPath& path)
} }
} }
rebuildLegData(); unlockDelegate();
if (_delegate) {
_delegate->runWaypointsChanged();
}
return Status; return Status;
} }
@ -657,6 +673,7 @@ void FlightPlan::loadVersion2XMLRoute(SGPropertyNode_ptr routeData)
Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode)); Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode));
_legs.push_back(l); _legs.push_back(l);
} // of route iteration } // of route iteration
_waypointsChanged = true;
} }
void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData) void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData)
@ -671,7 +688,7 @@ void FlightPlan::loadVersion1XMLRoute(SGPropertyNode_ptr routeData)
Leg* l = new Leg(this, parseVersion1XMLWaypt(wpNode)); Leg* l = new Leg(this, parseVersion1XMLWaypt(wpNode));
_legs.push_back(l); _legs.push_back(l);
} // of route iteration } // of route iteration
_waypointsChanged = true;
} }
WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP) WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP)
@ -1003,6 +1020,56 @@ void FlightPlan::rebuildLegData()
} // of legs iteration } // 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) void FlightPlan::registerDelegateFactory(DelegateFactory* df)
{ {
FPDelegateFactoryVec::iterator it = std::find(static_delegateFactories.begin(), FPDelegateFactoryVec::iterator it = std::find(static_delegateFactories.begin(),

View file

@ -224,6 +224,14 @@ public:
void addDelegate(Delegate* d); void addDelegate(Delegate* d);
void removeDelegate(Delegate* d); void removeDelegate(Delegate* d);
private: private:
void lockDelegate();
void unlockDelegate();
int _delegateLock;
bool _arrivalChanged,
_departureChanged,
_waypointsChanged,
_currentWaypointChanged;
bool loadPlainTextRoute(const SGPath& path); bool loadPlainTextRoute(const SGPath& path);

View file

@ -118,7 +118,9 @@ bool Approach::route(WayptRef aIAF, WayptVec& aWps)
bool Approach::routeFromVectors(WayptVec& aWps) bool Approach::routeFromVectors(WayptVec& aWps)
{ {
aWps.insert(aWps.end(), _primary.begin(), _primary.end()); 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()); aWps.insert(aWps.end(), _missed.begin(), _missed.end());
return true; return true;
} }

View file

@ -75,10 +75,12 @@ static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* o
naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, 0 }; naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, 0 };
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out); 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, naGhostType WayptGhostType = { wayptGhostDestroy,
"waypoint", "waypoint",
wayptGhostGetMember, wayptGhostGetMember,
0}; waypointGhostSetMember};
static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out); static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* out);
static void legGhostSetMember(naContext c, void* g, naRef field, naRef value); 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 ""; 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) static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{ {
const char* fieldName = naStr_data(field); const char* fieldName = naStr_data(field);
@ -450,21 +466,19 @@ static const char* legGhostGetMember(naContext c, void* g, naRef field, naRef* o
return ""; // success 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) static void legGhostSetMember(naContext c, void* g, naRef field, naRef value)
{ {
const char* fieldName = naStr_data(field); const char* fieldName = naStr_data(field);
FlightPlan::Leg* leg = (FlightPlan::Leg*) g; 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) static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, naRef* out)