]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/FlightPlan.cxx
Work-around for bug 1134, crash with flightplans.
[flightgear.git] / src / Navaids / FlightPlan.cxx
index 3f3eff4f6dc7e11836349cabd0ccfbd8dd700b2b..5b190e97270c5059ae90a37027d326e1a0232a98 100644 (file)
@@ -91,6 +91,11 @@ FlightPlan::~FlightPlan()
       delete cur;
     }
   }
+    
+// delete legs
+    BOOST_FOREACH(Leg* l, _legs) {
+        delete l;
+    }
 }
   
 FlightPlan* FlightPlan::clone(const string& newIdent) const
@@ -226,6 +231,9 @@ void FlightPlan::clear()
   }
   _legs.clear();  
   
+  if (_delegate) {
+    _delegate->runCleared();
+  }
   unlockDelegate();
 }
   
@@ -261,8 +269,24 @@ int FlightPlan::clearWayptsWithFlag(WayptFlag flag)
       ++count;
     }
   }
+
+  // test if the current leg will be removed
+  bool currentIsBeingCleared = false;
+  Leg* curLeg = currentLeg();
+  if (curLeg) {
+    currentIsBeingCleared = curLeg->waypoint()->flag(flag);
+  }
   
   _currentIndex -= count;
+    
+    // if we're clearing the current waypoint, what shall we do with the
+    // index? there's various options, but safest is to select no waypoint
+    // and let the use re-activate.
+    // http://code.google.com/p/flightgear-bugs/issues/detail?id=1134
+    if (currentIsBeingCleared) {
+        SG_LOG(SG_GENERAL, SG_INFO, "currentIsBeingCleared:" << currentIsBeingCleared);
+        _currentIndex = -1;
+    }
   
 // now delete and remove
   RemoveWithFlag rf(flag);
@@ -273,11 +297,18 @@ int FlightPlan::clearWayptsWithFlag(WayptFlag flag)
   
   lockDelegate();
   _waypointsChanged = true;
-  if (count > 0) {
+  if ((count > 0) || currentIsBeingCleared) {
     _currentWaypointChanged = true;
   }
   
   _legs.erase(it, _legs.end());
+    
+  if (_legs.empty()) { // maybe all legs were deleted
+    if (_delegate) {
+      _delegate->runCleared();
+    }
+  }
+  
   unlockDelegate();
   return rf.numDeleted();
 }
@@ -297,6 +328,23 @@ void FlightPlan::setCurrentIndex(int index)
   _currentWaypointChanged = true;
   unlockDelegate();
 }
+    
+void FlightPlan::finish()
+{
+    if (_currentIndex == -1) {
+        return;
+    }
+    
+    lockDelegate();
+    _currentIndex = -1;
+    _currentWaypointChanged = true;
+    
+    if (_delegate) {
+        _delegate->runFinished();
+    }
+    
+    unlockDelegate();
+}
   
 int FlightPlan::findWayptIndex(const SGGeod& aPos) const
 {  
@@ -612,8 +660,9 @@ void FlightPlan::loadXMLRouteHeader(SGPropertyNode_ptr routeData)
     string depIdent = dep->getStringValue("airport");
     setDeparture((FGAirport*) fgFindAirportID(depIdent));
     if (_departure) {
-      if (dep->hasChild("runway")) {
-        setDeparture(_departure->getRunwayByIdent(dep->getStringValue("runway")));
+      string rwy(dep->getStringValue("runway"));
+      if (_departure->hasRunwayWithIdent(rwy)) {
+        setDeparture(_departure->getRunwayByIdent(rwy));
       }
     
       if (dep->hasChild("sid")) {
@@ -628,8 +677,9 @@ void FlightPlan::loadXMLRouteHeader(SGPropertyNode_ptr routeData)
   if (dst) {
     setDestination((FGAirport*) fgFindAirportID(dst->getStringValue("airport")));
     if (_destination) {
-      if (dst->hasChild("runway")) {
-        setDestination(_destination->getRunwayByIdent(dst->getStringValue("runway")));
+      string rwy(dst->getStringValue("runway"));
+      if (_destination->hasRunwayWithIdent(rwy)) {
+        setDestination(_destination->getRunwayByIdent(rwy));
       }
       
       if (dst->hasChild("star")) {
@@ -709,18 +759,23 @@ WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP)
   } 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;
+    
+    if (p) {
+      pos = p->geod();
+    } else {
+      SG_LOG(SG_GENERAL, SG_WARN, "unknown navaid in flightplan:" << nid);
+      pos = SGGeod::fromDeg(aWP->getDoubleValue("longitude-deg"),
+                            aWP->getDoubleValue("latitude-deg"));
     }
     
-    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);
+      SGGeodesy::direct(pos, radialDeg, offsetNm * SG_NM_TO_METER, pos, az2);
     }
     
     w = new BasicWaypt(pos, ident, NULL);
@@ -1028,6 +1083,39 @@ void FlightPlan::rebuildLegData()
   }
 }
   
+SGGeod FlightPlan::pointAlongRoute(int aIndex, double aOffsetNm) const
+{
+  if (aIndex >= (int) _legs.size()) {
+    throw sg_range_exception();
+  }
+  
+  const int lastLeg = static_cast<int>(_legs.size()) - 1;
+// convert the relative offset and leg index into an absolute, positive
+// distance in nm from the route origin. This means we can simply walk
+// forwards to find the actual leg.
+  Leg* leg = _legs[(aIndex >= 0) ? aIndex : lastLeg];
+  double absolutePathDistance = leg->_distanceAlongPath + aOffsetNm;
+  if (absolutePathDistance < 0.0) {
+    return _legs[0]->waypoint()->position(); // begining of route
+  }
+  
+  if (absolutePathDistance > _totalDistance) {
+    return _legs[lastLeg]->waypoint()->position(); // end of route
+  }
+  
+// find the leg containing the absolute distance
+  for (int l=0; l<lastLeg; ++l) {
+    leg = _legs[l];
+    if (absolutePathDistance < leg->_pathDistance) {
+      break; // found our matching leg
+    }
+    absolutePathDistance -= leg->_pathDistance;
+  } // of forwards walk along route to find leg
+  
+  return SGGeodesy::direct(leg->waypoint()->position(),
+                               leg->_courseDeg, absolutePathDistance * SG_NM_TO_METER);
+}
+    
 void FlightPlan::lockDelegate()
 {
   if (_delegateLock == 0) {
@@ -1120,18 +1208,16 @@ FlightPlan::Delegate::Delegate() :
   _deleteWithPlan(false),
   _inner(NULL)
 {
-  
 }
 
 FlightPlan::Delegate::~Delegate()
-{
-  
+{  
 }
 
 void FlightPlan::Delegate::removeInner(Delegate* d)
 {
   if (!_inner) {
-    return;
+      throw sg_exception("FlightPlan delegate not found");
   }
   
   if (_inner == d) {
@@ -1165,5 +1251,17 @@ void FlightPlan::Delegate::runCurrentWaypointChanged()
   if (_inner) _inner->runCurrentWaypointChanged();
   currentWaypointChanged();
 }
-  
+
+void FlightPlan::Delegate::runCleared()
+{
+  if (_inner) _inner->runCleared();
+  cleared();
+}  
+
+void FlightPlan::Delegate::runFinished()
+{
+    if (_inner) _inner->runFinished();
+    endOfFlightPlan();
+}
+    
 } // of namespace flightgear