X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2FFlightPlan.cxx;h=83edf5c78aded2b7b566f55fbaf73da7d0692ff0;hb=5c659b3970e9a4542519e0d528016c08f7ecb6c1;hp=2087d5cc1fb165c1efb6b0f990ad05811854ef6f;hpb=16d1c4766465f41bca9dcdb0a461e69705e4398e;p=flightgear.git diff --git a/src/Navaids/FlightPlan.cxx b/src/Navaids/FlightPlan.cxx index 2087d5cc1..83edf5c78 100644 --- a/src/Navaids/FlightPlan.cxx +++ b/src/Navaids/FlightPlan.cxx @@ -42,12 +42,14 @@ #include #include #include +#include // FlightGear #include
#include "Main/fg_props.hxx" #include #include +#include using std::string; using std::vector; @@ -67,6 +69,7 @@ FlightPlan::FlightPlan() : _sid(NULL), _star(NULL), _approach(NULL), + _totalDistance(0.0), _delegate(NULL) { _departureChanged = _arrivalChanged = _waypointsChanged = _currentWaypointChanged = false; @@ -269,14 +272,24 @@ int FlightPlan::clearWayptsWithFlag(WayptFlag flag) ++count; } } - + // test if the current leg will be removed bool currentIsBeingCleared = false; - if (_currentIndex >= 0) { - currentIsBeingCleared = _legs[_currentIndex]->waypoint()->flag(flag); + 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); @@ -346,6 +359,17 @@ int FlightPlan::findWayptIndex(const SGGeod& aPos) const return -1; } + +int FlightPlan::findWayptIndex(const FGPositionedRef aPos) const +{ + for (int i=0; iwaypoint()->source() == aPos) { + return i; + } + } + + return -1; +} FlightPlan::Leg* FlightPlan::currentLeg() const { @@ -595,7 +619,7 @@ bool FlightPlan::save(const SGPath& path) return false; } } - + bool FlightPlan::load(const SGPath& path) { if (!path.exists()) @@ -604,21 +628,133 @@ bool FlightPlan::load(const SGPath& path) << "'. The file does not exist."); return false; } - - SGPropertyNode_ptr routeData(new SGPropertyNode); + SG_LOG(SG_NAVAID, SG_INFO, "going to read flight-plan from:" << path.str()); bool Status = false; lockDelegate(); + + // try different file formats + if (loadGpxFormat(path)) // GPX format + Status = true; + else + if (loadXmlFormat(path)) // XML property data + Status = true; + else + if (loadPlainTextFormat(path)) // simple textual list of waypoints + Status = true; + + _waypointsChanged = true; + unlockDelegate(); + + return Status; +} + +/** XML loader for GPX file format */ +class GpxXmlVisitor : public XMLVisitor +{ +public: + GpxXmlVisitor(FlightPlan* fp) : _fp(fp), _lat(-9999), _lon(-9999) {} + + virtual void startElement (const char * name, const XMLAttributes &atts); + virtual void endElement (const char * name); + virtual void data (const char * s, int length); + +private: + FlightPlan* _fp; + double _lat, _lon; + string _element; + string _waypoint; +}; + +void GpxXmlVisitor::startElement(const char * name, const XMLAttributes &atts) +{ + _element = name; + if (strcmp(name, "rtept")==0) + { + _waypoint = ""; + _lat = _lon = -9999; + + const char* slat = atts.getValue("lat"); + const char* slon = atts.getValue("lon"); + if (slat && slon) + { + _lat = atof(slat); + _lon = atof(slon); + } + } +} + +void GpxXmlVisitor::data(const char * s, int length) +{ + // use "name" when given, otherwise use "cmt" (comment) as ID + if ((_element == "name")|| + ((_waypoint == "")&&(_element == "cmt"))) + { + char* buf = (char*) malloc(length+1); + memcpy(buf, s, length); + buf[length] = 0; + _waypoint = buf; + free(buf); + } +} + +void GpxXmlVisitor::endElement(const char * name) +{ + _element = ""; + if (strcmp(name, "rtept") == 0) + { + if (_lon > -9990.0) + { + _fp->insertWayptAtIndex(new BasicWaypt(SGGeod::fromDeg(_lon, _lat), _waypoint.c_str(), NULL), -1); + } + } +} + +/** Load a flightplan in GPX format */ +bool FlightPlan::loadGpxFormat(const SGPath& path) +{ + if (path.lower_extension() != "gpx") + { + // not a valid GPX file + return false; + } + + _legs.clear(); + GpxXmlVisitor gpxVistor(this); + try + { + readXML(path.str(), gpxVistor); + } catch (sg_exception& e) + { + // XML parsing fails => not a GPX XML file + SG_LOG(SG_NAVAID, SG_ALERT, "Failed to load flight-plan in GPX format: '" << e.getOrigin() + << "'. " << e.getMessage()); + return false; + } + + if (numLegs() == 0) + { + SG_LOG(SG_NAVAID, SG_ALERT, "Failed to load flight-plan in GPX format. No route found."); + return false; + } + + return true; +} + +/** Load a flightplan in FlightGear XML property format */ +bool FlightPlan::loadXmlFormat(const SGPath& path) +{ + SGPropertyNode_ptr routeData(new SGPropertyNode); 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; + } catch (sg_exception& e) { + SG_LOG(SG_NAVAID, SG_ALERT, "Failed to load flight-plan '" << e.getOrigin() + << "'. " << e.getMessage()); + // XML parsing fails => not a property XML file + return false; } - + if (routeData.valid()) { try { @@ -630,16 +766,14 @@ bool FlightPlan::load(const SGPath& path) } else { throw sg_io_exception("unsupported XML route version"); } - Status = true; + return true; } catch (sg_exception& e) { SG_LOG(SG_NAVAID, SG_ALERT, "Failed to load flight-plan '" << e.getOrigin() << "'. " << e.getMessage()); - Status = false; } } - - unlockDelegate(); - return Status; + + return false; } void FlightPlan::loadXMLRouteHeader(SGPropertyNode_ptr routeData) @@ -706,12 +840,14 @@ void FlightPlan::loadVersion2XMLRoute(SGPropertyNode_ptr routeData) // route nodes _legs.clear(); - SGPropertyNode_ptr routeNode = routeData->getChild("route", 0); - for (int i=0; inChildren(); ++i) { - SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i); - Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode)); - _legs.push_back(l); - } // of route iteration + SGPropertyNode_ptr routeNode = routeData->getChild("route", 0); + if (routeNode.valid()) { + for (int i=0; inChildren(); ++i) { + SGPropertyNode_ptr wpNode = routeNode->getChild("wp", i); + Leg* l = new Leg(this, Waypt::createFromProperties(NULL, wpNode)); + _legs.push_back(l); + } // of route iteration + } _waypointsChanged = true; } @@ -779,7 +915,8 @@ WayptRef FlightPlan::parseVersion1XMLWaypt(SGPropertyNode* aWP) return w; } -bool FlightPlan::loadPlainTextRoute(const SGPath& path) +/** Load a flightplan in FlightGear plain-text format */ +bool FlightPlan::loadPlainTextFormat(const SGPath& path) { try { sg_gzifstream in(path.str().c_str()); @@ -1050,60 +1187,29 @@ double FlightPlan::Leg::distanceAlongRoute() const void FlightPlan::rebuildLegData() { _totalDistance = 0.0; - int lastLeg = static_cast(_legs.size()) - 1; - for (int l=0; l_courseDeg = path.trackForIndex(l); + _legs[l]->_pathDistance = path.distanceForIndex(l) * SG_METER_TO_NM; + + totalDistanceIncludingMissed += _legs[l]->_pathDistance; + // distance along path includes our own leg distance + _legs[l]->_distanceAlongPath = totalDistanceIncludingMissed; - std::pair 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 + // omit missed-approach waypoints from total distance calculation + if (!_legs[l]->waypoint()->flag(WPT_MISS)) { + _totalDistance += _legs[l]->_pathDistance; + } +} // of legs iteration -// set some data on the final leg - if (lastLeg > 0) { - // keep the same course as the final leg, when passing the final - // waypoint - _legs[lastLeg]->_courseDeg = _legs[lastLeg - 1]->_courseDeg; - _legs[lastLeg]->_pathDistance = 0.0; - _legs[lastLeg]->_distanceAlongPath = _totalDistance; - } } SGGeod FlightPlan::pointAlongRoute(int aIndex, double aOffsetNm) const { - if (aIndex >= (int) _legs.size()) { - throw sg_range_exception(); - } - - const int lastLeg = static_cast(_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_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); + RoutePath rp(this); + return rp.positionForDistanceFrom(aIndex, aOffsetNm * SG_NM_TO_METER); } void FlightPlan::lockDelegate()