diff --git a/src/Navaids/FlightPlan.cxx b/src/Navaids/FlightPlan.cxx index 840e8616b..421494c90 100644 --- a/src/Navaids/FlightPlan.cxx +++ b/src/Navaids/FlightPlan.cxx @@ -1198,6 +1198,10 @@ void FlightPlan::loadVersion2XMLRoute(SGPropertyNode_ptr routeData) if (routeNode.valid()) { for (auto wpNode : routeNode->getChildren("wp")) { auto wp = Waypt::createFromProperties(this, wpNode); + if (!wp) { + continue; + } + LegRef l = new Leg{this, wp}; // sync leg restrictions with waypoint ones if (wp->speedRestriction() != RESTRICT_NONE) { diff --git a/src/Navaids/route.cxx b/src/Navaids/route.cxx index 2990f0b3a..fa77b2c0c 100644 --- a/src/Navaids/route.cxx +++ b/src/Navaids/route.cxx @@ -236,8 +236,8 @@ WayptRef Waypt::createInstance(RouteBase* aOwner, const std::string& aTypeName) WayptRef Waypt::createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp) { if (!aProp->hasChild("type")) { - throw sg_io_exception("bad props node, no type provided", - "Waypt::createFromProperties"); + SG_LOG(SG_GENERAL, SG_WARN, "Bad waypoint node: missing type"); + return {}; } flightgear::AirwayRef via; @@ -250,22 +250,24 @@ WayptRef Waypt::createFromProperties(RouteBase* aOwner, SGPropertyNode_ptr aProp } } - try { WayptRef nd(createInstance(aOwner, aProp->getStringValue("type"))); - nd->initFromProperties(aProp); - return nd; - } catch (sg_exception& e) { - SG_LOG(SG_GENERAL, SG_WARN, "failed to create waypoint, trying basic:" << e.getMessage()); - } + if (nd->initFromProperties(aProp)) { + return nd; + } + SG_LOG(SG_GENERAL, SG_WARN, "failed to create waypoint, trying basic"); -// if we failed to make the waypoint, try again making a basic waypoint. -// this handles the case where a navaid waypoint is missing, for example -// we also reject navaids that don't look correct (too far form the specified -// lat-lon, eg see https://sourceforge.net/p/flightgear/codetickets/1814/ ) -// and again fallback to here. - WayptRef nd(new BasicWaypt(aOwner)); - nd->initFromProperties(aProp); - return nd; + + // if we failed to make the waypoint, try again making a basic waypoint. + // this handles the case where a navaid waypoint is missing, for example + // we also reject navaids that don't look correct (too far form the specified + // lat-lon, eg see https://sourceforge.net/p/flightgear/codetickets/1814/ ) + // and again fallback to here. + WayptRef bw(new BasicWaypt(aOwner)); + if (bw->initFromProperties(aProp)) { + return bw; + } + + return {}; // total failure } void Waypt::saveAsNode(SGPropertyNode* n) const @@ -274,7 +276,7 @@ void Waypt::saveAsNode(SGPropertyNode* n) const writeToProperties(n); } -void Waypt::initFromProperties(SGPropertyNode_ptr aProp) +bool Waypt::initFromProperties(SGPropertyNode_ptr aProp) { if (aProp->hasChild("generated")) { setFlag(WPT_GENERATED, aProp->getBoolValue("generated")); @@ -314,7 +316,7 @@ void Waypt::initFromProperties(SGPropertyNode_ptr aProp) _speed = aProp->getDoubleValue("speed"); } - + return true; } void Waypt::writeToProperties(SGPropertyNode_ptr aProp) const diff --git a/src/Navaids/route.hxx b/src/Navaids/route.hxx index 283456f5d..41a384ac3 100644 --- a/src/Navaids/route.hxx +++ b/src/Navaids/route.hxx @@ -208,16 +208,16 @@ protected: /** * Persistence helper - read node properties from a file */ - virtual void initFromProperties(SGPropertyNode_ptr aProp); - - /** + virtual bool initFromProperties(SGPropertyNode_ptr aProp); + + /** * Persistence helper - save this element to a node */ - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - - typedef Waypt* (FactoryFunction)(RouteBase* aOwner) ; - static void registerFactory(const std::string aNodeType, FactoryFunction* aFactory); - + virtual void writeToProperties(SGPropertyNode_ptr aProp) const; + + typedef Waypt*(FactoryFunction)(RouteBase* aOwner); + static void registerFactory(const std::string aNodeType, FactoryFunction* aFactory); + double _altitudeFt = 0.0; double _speed = 0.0; // knots IAS or mach RouteRestriction _altRestrict = RESTRICT_NONE; diff --git a/src/Navaids/waypoint.cxx b/src/Navaids/waypoint.cxx index 9f8d0fa17..03ee819a6 100644 --- a/src/Navaids/waypoint.cxx +++ b/src/Navaids/waypoint.cxx @@ -47,18 +47,20 @@ BasicWaypt::BasicWaypt(RouteBase* aOwner) : { } -void BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp) +bool BasicWaypt::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) { - throw sg_io_exception("missing lon/lat properties", - "BasicWaypt::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "missing lon/lat properties"); + return false; } - Waypt::initFromProperties(aProp); + if (!Waypt::initFromProperties(aProp)) + return false; _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat")); _ident = aProp->getStringValue("ident"); + return true; } void BasicWaypt::writeToProperties(SGPropertyNode_ptr aProp) const @@ -102,15 +104,16 @@ std::string NavaidWaypoint::ident() const return _navaid->ident(); } -void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) +bool NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("ident")) { - throw sg_io_exception("missing navaid value", - "NavaidWaypoint::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "missing navaid ident"); + return false; } - - Waypt::initFromProperties(aProp); - + + if (!Waypt::initFromProperties(aProp)) + return false; + std::string idn(aProp->getStringValue("ident")); SGGeod p; if (aProp->hasChild("lon")) { @@ -121,8 +124,8 @@ void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) // is it sufficent just to ignore DMEs, actually? FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, nullptr); if (!nav) { - throw sg_io_exception("unknown navaid ident:" + idn, - "NavaidWaypoint::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "unknown navdaid ident:" << idn); + return false; } if (p.isValid() && (SGGeodesy::distanceM(nav->geod(), p) > 4000)) { @@ -130,12 +133,12 @@ void NavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) // in this case, throw an exception here so we fall back to using // a basic waypoint // see https://sourceforge.net/p/flightgear/codetickets/1814/ - throw sg_io_exception("Waypoint navaid for ident:" + idn + - " is too far from specified lat/lon in flight-plan", - "NavaidWaypoint::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "Waypoint navaid for ident:" << idn << " is too far from the specified lat/lon"); + return false; } _navaid = nav; + return true; } void NavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const @@ -170,17 +173,20 @@ void OffsetNavaidWaypoint::init() _geod = SGGeod::fromGeodFt(offset, _altitudeFt); } -void OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) +bool OffsetNavaidWaypoint::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("radial-deg") || !aProp->hasChild("distance-nm")) { - throw sg_io_exception("missing radial/offset distance", - "OffsetNavaidWaypoint::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "missing radial/offset distance creating offset waypoint"); + return false; } - - NavaidWaypoint::initFromProperties(aProp); + + if (!NavaidWaypoint::initFromProperties(aProp)) + return false; + _radial = aProp->getDoubleValue("radial-deg"); _distanceNm = aProp->getDoubleValue("distance-nm"); init(); + return true; } void OffsetNavaidWaypoint::writeToProperties(SGPropertyNode_ptr aProp) const @@ -224,17 +230,31 @@ double RunwayWaypt::headingRadialDeg() const return _runway->headingDeg(); } -void RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp) +bool RunwayWaypt::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("icao") || !aProp->hasChild("ident")) { - throw sg_io_exception("missing values: icao or ident", - "RunwayWaypoint::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "missing ICAO/ident on runway waypoint"); + return false; } - - Waypt::initFromProperties(aProp); + + if (!Waypt::initFromProperties(aProp)) + return false; + std::string idn(aProp->getStringValue("ident")); const FGAirport* apt = FGAirport::getByIdent(aProp->getStringValue("icao")); - _runway = apt->getRunwayByIdent(aProp->getStringValue("ident")); + if (!apt) { + SG_LOG(SG_AUTOPILOT, SG_WARN, "Unknown airport:" << aProp->getStringValue("icao")); + return false; + } + + const std::string ident = aProp->getStringValue("ident"); + if (!apt->hasRunwayWithIdent(ident)) { + SG_LOG(SG_AUTOPILOT, SG_WARN, "Unknown runway " << ident << " at " << aProp->getStringValue("icao")); + return false; + } + + _runway = apt->getRunwayByIdent(ident); + return true; } void RunwayWaypt::writeToProperties(SGPropertyNode_ptr aProp) const @@ -286,20 +306,18 @@ void Hold::setLeftHanded() { _righthanded = false; } - -void Hold::initFromProperties(SGPropertyNode_ptr aProp) -{ - BasicWaypt::initFromProperties(aProp); - - if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) { - throw sg_io_exception("missing lon/lat properties", - "Hold::initFromProperties"); - } - _righthanded = aProp->getBoolValue("right-handed"); - _isDistance = aProp->getBoolValue("is-distance"); - _bearing = aProp->getDoubleValue("inbound-radial-deg"); - _holdTD = aProp->getDoubleValue("td"); +bool Hold::initFromProperties(SGPropertyNode_ptr aProp) +{ + if (!BasicWaypt::initFromProperties(aProp)) + return false; + + _righthanded = aProp->getBoolValue("right-handed"); + _isDistance = aProp->getBoolValue("is-distance"); + _bearing = aProp->getDoubleValue("inbound-radial-deg"); + _holdTD = aProp->getDoubleValue("td"); + + return true; } void Hold::writeToProperties(SGPropertyNode_ptr aProp) const @@ -328,16 +346,19 @@ HeadingToAltitude::HeadingToAltitude(RouteBase* aOwner) : { } -void HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp) +bool HeadingToAltitude::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("heading-deg")) { - throw sg_io_exception("missing heading/alt properties", - "HeadingToAltitude::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "Missing heading property creating HdgToAlt waypoint"); + return false; } - Waypt::initFromProperties(aProp); + if (!Waypt::initFromProperties(aProp)) + return false; + _magHeading = aProp->getDoubleValue("heading-deg"); _ident = aProp->getStringValue("ident"); + return true; } void HeadingToAltitude::writeToProperties(SGPropertyNode_ptr aProp) const @@ -365,20 +386,23 @@ DMEIntercept::DMEIntercept(RouteBase* aOwner) : { } -void DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp) +bool DMEIntercept::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) { - throw sg_io_exception("missing lon/lat properties", - "DMEIntercept::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "Missing lat/lom properties creating DMEIntc waypoint"); + return false; } - Waypt::initFromProperties(aProp); + if (!Waypt::initFromProperties(aProp)) + return false; + _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat")); _ident = aProp->getStringValue("ident"); // check it's a real DME? _magCourse = aProp->getDoubleValue("course-deg"); _dmeDistanceNm = aProp->getDoubleValue("dme-distance-nm"); - + + return true; } void DMEIntercept::writeToProperties(SGPropertyNode_ptr aProp) const @@ -409,21 +433,24 @@ RadialIntercept::RadialIntercept(RouteBase* aOwner) : Waypt(aOwner) { } - -void RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp) + +bool RadialIntercept::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("lon") || !aProp->hasChild("lat")) { - throw sg_io_exception("missing lon/lat properties", - "RadialIntercept::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "Missing lat/lom properties creating RadialIntercept waypoint"); + return false; } - Waypt::initFromProperties(aProp); + if (!Waypt::initFromProperties(aProp)) + return false; + _pos = SGGeod::fromDeg(aProp->getDoubleValue("lon"), aProp->getDoubleValue("lat")); _ident = aProp->getStringValue("ident"); // check it's a real VOR? _magCourse = aProp->getDoubleValue("course-deg"); _radial = aProp->getDoubleValue("radial-deg"); - + + return true; } void RadialIntercept::writeToProperties(SGPropertyNode_ptr aProp) const @@ -465,21 +492,21 @@ string ATCVectors::ident() const return "VECTORS-" + _facility->ident(); } -void ATCVectors::initFromProperties(SGPropertyNode_ptr aProp) -{ - if (!aProp->hasChild("icao")) { - throw sg_io_exception("missing icao propertie", - "ATCVectors::initFromProperties"); - } +bool ATCVectors::initFromProperties(SGPropertyNode_ptr aProp) +{ + if (!Waypt::initFromProperties(aProp)) + return false; - Waypt::initFromProperties(aProp); - _facility = FGAirport::getByIdent(aProp->getStringValue("icao")); + _facility = FGAirport::getByIdent(aProp->getStringValue("icao")); + return true; } void ATCVectors::writeToProperties(SGPropertyNode_ptr aProp) const { Waypt::writeToProperties(aProp); - aProp->setStringValue("icao", _facility->ident()); + if (_facility) { + aProp->setStringValue("icao", _facility->ident()); + } } ///////////////////////////////////////////////////////////////////////////// @@ -505,8 +532,9 @@ string Discontinuity::ident() const return "DISCONTINUITY"; } -void Discontinuity::initFromProperties(SGPropertyNode_ptr aProp) +bool Discontinuity::initFromProperties(SGPropertyNode_ptr aProp) { + return true; } void Discontinuity::writeToProperties(SGPropertyNode_ptr aProp) const @@ -542,21 +570,22 @@ Via::~Via() { } -void Via::initFromProperties(SGPropertyNode_ptr aProp) +bool Via::initFromProperties(SGPropertyNode_ptr aProp) { if (!aProp->hasChild("airway") || !aProp->hasChild("to")) { - throw sg_io_exception("missing airway/to properties", - "Via::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "Missingairway/to properties on Via wp"); + return false; } - Waypt::initFromProperties(aProp); + if (!Waypt::initFromProperties(aProp)) + return false; const std::string ident = aProp->getStringValue("airway"); const Airway::Level level = static_cast<Airway::Level>(aProp->getIntValue("level", Airway::Both)); _airway = Airway::findByIdent(ident, level); if (!_airway) { - throw sg_io_exception("unknown airway ident: '" + ident + "'", - "Via::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "VIA: unknown airway:" << ident); + return false; } std::string idn(aProp->getStringValue("to")); @@ -568,8 +597,8 @@ void Via::initFromProperties(SGPropertyNode_ptr aProp) FGPositionedRef nav = FGPositioned::findClosestWithIdent(idn, p, nullptr); if (!nav) { - throw sg_io_exception("unknown navaid ident:" + idn, - "Via::initFromProperties"); + SG_LOG(SG_AUTOPILOT, SG_WARN, "VIA TO navaid: " << idn << " not found"); + return false; } if (!_airway->containsNavaid(nav)) { @@ -578,6 +607,7 @@ void Via::initFromProperties(SGPropertyNode_ptr aProp) } _to = nav; + return true; } void Via::writeToProperties(SGPropertyNode_ptr aProp) const diff --git a/src/Navaids/waypoint.hxx b/src/Navaids/waypoint.hxx index cb67bd147..2aefae9e4 100644 --- a/src/Navaids/waypoint.hxx +++ b/src/Navaids/waypoint.hxx @@ -44,10 +44,10 @@ public: std::string icaoDescription() const override; protected: - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; - virtual std::string type() const + virtual std::string type() const { return "basic"; } SGGeod _pos; @@ -72,12 +72,13 @@ public: { return _navaid; } virtual std::string ident() const; -protected: - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; + + protected: + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; virtual std::string type() const - { return "navaid"; } + { return "navaid"; } FGPositionedRef _navaid; }; @@ -93,10 +94,10 @@ public: { return _geod; } protected: - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - - virtual std::string type() const + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + + virtual std::string type() const { return "offset-navaid"; } private: @@ -132,9 +133,9 @@ public: protected: virtual std::string type() const { return "runway"; } - - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; + + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; private: FGRunway* _runway; @@ -169,10 +170,10 @@ public: virtual double headingRadialDeg() const { return inboundRadial(); } protected: - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - - virtual std::string type() const + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + + virtual std::string type() const { return "hold"; } private: @@ -188,10 +189,10 @@ public: HeadingToAltitude(RouteBase* aOwner, const std::string& aIdent, double aMagHdg); HeadingToAltitude(RouteBase* aOwner); - - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - + + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + virtual std::string type() const { return "hdgToAlt"; } @@ -221,10 +222,10 @@ public: double aCourseDeg, double aDistanceNm); DMEIntercept(RouteBase* aOwner); - - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - + + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + virtual std::string type() const { return "dmeIntercept"; } @@ -256,10 +257,10 @@ public: double aCourseDeg, double aRadialDeg); RadialIntercept(RouteBase* aOwner); - - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - + + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + virtual std::string type() const { return "radialIntercept"; } @@ -296,10 +297,10 @@ public: virtual ~ATCVectors(); ATCVectors(RouteBase* aOwner); - - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; - + + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; + virtual std::string type() const { return "vectors"; } @@ -326,8 +327,8 @@ public: virtual ~Discontinuity(); Discontinuity(RouteBase* aOwner); - virtual void initFromProperties(SGPropertyNode_ptr aProp); - virtual void writeToProperties(SGPropertyNode_ptr aProp) const; + bool initFromProperties(SGPropertyNode_ptr aProp) override; + void writeToProperties(SGPropertyNode_ptr aProp) const override; virtual std::string type() const { return "discontinuity"; } @@ -348,7 +349,7 @@ public: Via(RouteBase* aOwner, AirwayRef airway, FGPositionedRef to); virtual ~Via(); - void initFromProperties(SGPropertyNode_ptr aProp) override; + bool initFromProperties(SGPropertyNode_ptr aProp) override; void writeToProperties(SGPropertyNode_ptr aProp) const override; std::string type() const override