_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();
// std
#include <map>
#include <fstream>
+#include <cassert>
// Boost
#include <boost/algorithm/string/case_conv.hpp>
static FPDelegateFactoryVec static_delegateFactories;
FlightPlan::FlightPlan() :
+ _delegateLock(0),
_currentIndex(-1),
_departureRunway(NULL),
_destinationRunway(NULL),
_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
{
FlightPlan* c = new FlightPlan();
c->_ident = newIdent.empty() ? _ident : newIdent;
+ c->lockDelegate();
// copy destination / departure data.
c->setDeparture(_departure);
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;
}
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)
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)
return;
}
+ lockDelegate();
_currentIndex = index;
- if (_delegate) {
- _delegate->runCurrentWaypointChanged();
- }
+ _currentWaypointChanged = true;
+ unlockDelegate();
}
int FlightPlan::findWayptIndex(const SGGeod& aPos) const
return;
}
+ lockDelegate();
+ _departureChanged = true;
_departure = apt;
_departureRunway = NULL;
setSID((SID*)NULL);
-
- if (_delegate) {
- _delegate->runDepartureChanged();
- }
+ unlockDelegate();
}
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)
return;
}
+ lockDelegate();
+ _departureChanged = true;
_sid = sid;
_sidTransition = transition;
-
- if (_delegate) {
- _delegate->runDepartureChanged();
- }
+ unlockDelegate();
}
void FlightPlan::setSID(Transition* trans)
return;
}
+ lockDelegate();
+ _arrivalChanged = true;
_destination = apt;
_destinationRunway = NULL;
setSTAR((STAR*)NULL);
-
- if (_delegate) {
- _delegate->runArrivalChanged();
- }
+ setApproach(NULL);
+ unlockDelegate();
}
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)
return;
}
+ lockDelegate();
+ _arrivalChanged = true;
_star = star;
_starTransition = transition;
-
- if (_delegate) {
- _delegate->runArrivalChanged();
- }
+ unlockDelegate();
}
void FlightPlan::setSTAR(Transition* trans)
return;
}
+ lockDelegate();
+ _arrivalChanged = true;
_approach = app;
if (app) {
// keep runway + airport in sync
_destination = _destinationRunway->airport();
}
}
-
- if (_delegate) {
- _delegate->runArrivalChanged();
- }
+ unlockDelegate();
}
bool FlightPlan::save(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())
}
}
- rebuildLegData();
- if (_delegate) {
- _delegate->runWaypointsChanged();
- }
-
+ unlockDelegate();
return Status;
}
Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode));
_legs.push_back(l);
} // of route iteration
+ _waypointsChanged = true;
}
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)
} // 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(),
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);
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);
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)