From: James Turner Date: Thu, 8 Jan 2015 19:46:04 +0000 (+0000) Subject: Route-path bug fixes. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=e94371ebfc8a32758841a500d9d6adda65c3acea;p=flightgear.git Route-path bug fixes. - explicit aircraft performance categories for turn radius - allow overflight leg course behaviour to be selected --- diff --git a/src/Instrumentation/gps.cxx b/src/Instrumentation/gps.cxx index 2a3560355..1d0acf23b 100644 --- a/src/Instrumentation/gps.cxx +++ b/src/Instrumentation/gps.cxx @@ -70,7 +70,8 @@ GPS::Config::Config() : _requireHardSurface(true), _cdiMaxDeflectionNm(3.0), // linear mode, 3nm at the peg _driveAutopilot(true), - _courseSelectable(false) + _courseSelectable(false), + _followLegTrackToFix(true) { _enableTurnAnticipation = false; } @@ -84,6 +85,7 @@ void GPS::Config::bind(GPS* aOwner, SGPropertyNode* aCfg) aOwner->tie(aCfg, "cdi-max-deflection-nm", SGRawValuePointer(&_cdiMaxDeflectionNm)); aOwner->tie(aCfg, "drive-autopilot", SGRawValuePointer(&_driveAutopilot)); aOwner->tie(aCfg, "course-selectable", SGRawValuePointer(&_courseSelectable)); + aOwner->tie(aCfg, "follow-leg-track-to-fix", SGRawValuePointer(&_followLegTrackToFix)); aOwner->tie(aCfg, "over-flight-distance-nm", SGRawValuePointer(&_overflightDistance)); aOwner->tie(aCfg, "over-flight-arm-distance-nm", SGRawValuePointer(&_overflightArmDistance)); aOwner->tie(aCfg, "over-flight-arm-angle-deg", SGRawValuePointer(&_overflightArmAngle)); diff --git a/src/Instrumentation/gps.hxx b/src/Instrumentation/gps.hxx index 100d236b6..ada60638e 100644 --- a/src/Instrumentation/gps.hxx +++ b/src/Instrumentation/gps.hxx @@ -139,6 +139,15 @@ private: bool courseSelectable() const { return _courseSelectable; } + /** + * Select whether we fly the leg track between waypoints, or + * use a direct course from the turn end. Since this is likely confusing, + * look at: http://fgfs.goneabitbursar.com//screenshots/FlyByType-LegType.svg + * For fly-by waypoints, there is no difference. For fly-over waypoints, + * this selects if we fly TF or DF mode. + */ + bool followLegTrackToFix() const { return _followLegTrackToFix; } + private: bool _enableTurnAnticipation; @@ -168,6 +177,9 @@ private: // is selected-course-deg read to set desired-course or not? bool _courseSelectable; + + // do we fly direct to fixes, or follow the leg track closely? + bool _followLegTrackToFix; }; class SearchFilter : public FGPositioned::Filter diff --git a/src/Navaids/FlightPlan.cxx b/src/Navaids/FlightPlan.cxx index 83edf5c78..ee1e90815 100644 --- a/src/Navaids/FlightPlan.cxx +++ b/src/Navaids/FlightPlan.cxx @@ -64,6 +64,8 @@ static FPDelegateFactoryVec static_delegateFactories; FlightPlan::FlightPlan() : _delegateLock(0), _currentIndex(-1), + _followLegTrackToFix(true), + _aircraftCategory(ICAO_AIRCRAFT_CATEGORY_C), _departureRunway(NULL), _destinationRunway(NULL), _sid(NULL), @@ -1359,5 +1361,36 @@ void FlightPlan::Delegate::runFinished() if (_inner) _inner->runFinished(); endOfFlightPlan(); } + +void FlightPlan::setFollowLegTrackToFixes(bool tf) +{ + _followLegTrackToFix = tf; +} + +bool FlightPlan::followLegTrackToFixes() const +{ + return _followLegTrackToFix; +} + +std::string FlightPlan::icaoAircraftCategory() const +{ + std::string r; + r.push_back(_aircraftCategory); + return r; +} + +void FlightPlan::setIcaoAircraftCategory(const std::string& cat) +{ + if (cat.empty()) { + throw sg_range_exception("Invalid ICAO aircraft category:", cat); + } + + if ((cat[0] < ICAO_AIRCRAFT_CATEGORY_A) || (cat[0] > ICAO_AIRCRAFT_CATEGORY_E)) { + throw sg_range_exception("Invalid ICAO aircraft category:", cat); + } + + _aircraftCategory = cat[0]; +} + } // of namespace flightgear diff --git a/src/Navaids/FlightPlan.hxx b/src/Navaids/FlightPlan.hxx index 93e421b3b..50747b6df 100644 --- a/src/Navaids/FlightPlan.hxx +++ b/src/Navaids/FlightPlan.hxx @@ -34,7 +34,13 @@ class Transition; class FlightPlan; typedef SGSharedPtr FlightPlanRef; - + +const char ICAO_AIRCRAFT_CATEGORY_A = 'A'; +const char ICAO_AIRCRAFT_CATEGORY_B = 'B'; +const char ICAO_AIRCRAFT_CATEGORY_C = 'C'; +const char ICAO_AIRCRAFT_CATEGORY_D = 'D'; +const char ICAO_AIRCRAFT_CATEGORY_E = 'E'; + class FlightPlan : public RouteBase { public: @@ -43,7 +49,16 @@ public: virtual std::string ident() const; void setIdent(const std::string& s); - + + // propogate the GPS/FMS setting for this through to the RoutePath + void setFollowLegTrackToFixes(bool tf); + bool followLegTrackToFixes() const; + + // aircraft approach category as per CFR 97.3, etc + // http://www.flightsimaviation.com/data/FARS/part_97-3.html + std::string icaoAircraftCategory() const; + void setIcaoAircraftCategory(const std::string& cat); + FlightPlan* clone(const std::string& newIdent = std::string()) const; /** @@ -259,7 +274,9 @@ private: std::string _ident; int _currentIndex; - + bool _followLegTrackToFix; + char _aircraftCategory; + FGAirportRef _departure, _destination; FGRunway* _departureRunway, *_destinationRunway; SGSharedPtr _sid; diff --git a/src/Navaids/routePath.cxx b/src/Navaids/routePath.cxx index e5d86e63e..8aa51815c 100644 --- a/src/Navaids/routePath.cxx +++ b/src/Navaids/routePath.cxx @@ -173,7 +173,7 @@ public: } } - void computeTurn(double radiusM, const WayptData& previous, WayptData& next) + void computeTurn(double radiusM, bool constrainLegCourse, const WayptData& previous, WayptData& next) { assert(!skipped); assert(legCourseValid && next.legCourseValid); @@ -201,7 +201,7 @@ public: // through turnAngle double xtk = turnRadius * (1 - cos(turnAngle * SG_DEGREES_TO_RADIANS)); - if (next.isCourseConstrained()) { + if (constrainLegCourse || next.isCourseConstrained()) { // next leg course is constrained. We need to swing back onto the // desired course, using a compensation turn @@ -409,9 +409,12 @@ bool isDescentWaypoint(const WayptRef& wpt) class RoutePath::RoutePathPrivate { public: - WayptDataVec waypoints; - PerformanceBracketVec perf; - + WayptDataVec waypoints; + + char aircraftCategory; + PerformanceBracketVec perf; + double pathTurnRate; + bool constrainLegCourses; PerformanceBracketVec::const_iterator findPerformanceBracket(double altFt) const @@ -621,10 +624,16 @@ public: double groundSpeedForAltitude(double altitude) const { - // FIXME + PerformanceBracketVec::const_iterator it = findPerformanceBracket(altitude); + if (it->speedIsMach) { + return 300.0; + } else { + // FIXME - convert IAS to ground-speed, using standard atmosphere / temperature model + return it->speedIASOrMach; + } + #if 0 if (0) { - PerformanceBracketVec::const_iterator it = findPerformanceBracket(altitude); double mach; if (it->speedIsMach) { @@ -652,8 +661,6 @@ public: #endif } #endif - - return 250.0; } double distanceBetweenIndices(int from, int to) const @@ -669,11 +676,36 @@ public: void initPerfData() { - // assume category C/D aircraft for now - perf.push_back(PerformanceBracket(4000, 1800, 1800, 180)); - perf.push_back(PerformanceBracket(10000, 1800, 1800, 230)); - perf.push_back(PerformanceBracket(18000, 1200, 1800, 270)); - perf.push_back(PerformanceBracket(60000, 800, 1200, 0.85, true /* is Mach */)); + pathTurnRate = 3.0; // 3 deg/sec = 180deg/min = standard rate turn + switch (aircraftCategory) { + case ICAO_AIRCRAFT_CATEGORY_A: + perf.push_back(PerformanceBracket(4000, 600, 1200, 75)); + perf.push_back(PerformanceBracket(10000, 600, 1200, 140)); + break; + + case ICAO_AIRCRAFT_CATEGORY_B: + perf.push_back(PerformanceBracket(4000, 100, 1200, 100)); + perf.push_back(PerformanceBracket(10000, 800, 1200, 160)); + perf.push_back(PerformanceBracket(18000, 600, 1800, 200)); + break; + + case ICAO_AIRCRAFT_CATEGORY_C: + perf.push_back(PerformanceBracket(4000, 1800, 1800, 150)); + perf.push_back(PerformanceBracket(10000, 1800, 1800, 200)); + perf.push_back(PerformanceBracket(18000, 1200, 1800, 270)); + perf.push_back(PerformanceBracket(60000, 800, 1200, 0.80, true /* is Mach */)); + break; + + case ICAO_AIRCRAFT_CATEGORY_D: + case ICAO_AIRCRAFT_CATEGORY_E: + default: + + perf.push_back(PerformanceBracket(4000, 1800, 1800, 180)); + perf.push_back(PerformanceBracket(10000, 1800, 1800, 230)); + perf.push_back(PerformanceBracket(18000, 1200, 1800, 270)); + perf.push_back(PerformanceBracket(60000, 800, 1200, 0.87, true /* is Mach */)); + break; + } } const WayptData& previousValidWaypoint(int index) const @@ -688,29 +720,20 @@ public: }; // of RoutePathPrivate class -RoutePath::RoutePath(const flightgear::WayptVec& wpts) : - d(new RoutePathPrivate) -{ - WayptVec::const_iterator it; - for (it = wpts.begin(); it != wpts.end(); ++it) { - d->waypoints.push_back(WayptData(*it)); - } - commonInit(); -} - RoutePath::RoutePath(const flightgear::FlightPlan* fp) : d(new RoutePathPrivate) { for (int l=0; lnumLegs(); ++l) { d->waypoints.push_back(WayptData(fp->legAtIndex(l)->waypoint())); } + + d->aircraftCategory = fp->icaoAircraftCategory()[0]; + d->constrainLegCourses = fp->followLegTrackToFixes(); commonInit(); } void RoutePath::commonInit() { - _pathTurnRate = 3.0; // 3 deg/sec = 180deg/min = standard rate turn - d->initPerfData(); WayptDataVec::iterator it; @@ -734,7 +757,7 @@ void RoutePath::commonInit() double alt = 0.0; // FIXME double gs = d->groundSpeedForAltitude(alt); - double radiusM = ((360.0 / _pathTurnRate) * gs * SG_KT_TO_MPS) / SGMiscd::twopi(); + double radiusM = ((360.0 / d->pathTurnRate) * gs * SG_KT_TO_MPS) / SGMiscd::twopi(); if (i < (d->waypoints.size() - 1)) { int nextIndex = i + 1; @@ -745,7 +768,7 @@ void RoutePath::commonInit() next.computeLegCourse(d->waypoints[i]); if (next.legCourseValid) { - d->waypoints[i].computeTurn(radiusM, prev, next); + d->waypoints[i].computeTurn(radiusM, d->constrainLegCourses, prev, next); } else { // next waypoint has indeterminate course. Let's create a sharp turn // this can happen when the following point is ATC vectors, for example. @@ -861,7 +884,7 @@ SGGeodVec RoutePath::pathForHold(Hold* hold) const SGGeodVec r; double az2; - double stepTime = turnDelta / _pathTurnRate; // in seconds + double stepTime = turnDelta / d->pathTurnRate; // in seconds double stepDist = gsKts * (stepTime / 3600.0) * SG_NM_TO_METER; double legDist = hold->isDistance() ? hold->timeOrDistance() diff --git a/src/Navaids/routePath.hxx b/src/Navaids/routePath.hxx index e94060607..ac9e87130 100644 --- a/src/Navaids/routePath.hxx +++ b/src/Navaids/routePath.hxx @@ -37,7 +37,6 @@ typedef std::vector SGGeodVec; class RoutePath { public: - RoutePath(const flightgear::WayptVec& wpts); RoutePath(const flightgear::FlightPlan* fp); SGGeodVec pathForIndex(int index) const; @@ -66,9 +65,6 @@ private: RoutePathPrivate* d; - - - double _pathTurnRate; ///< degrees-per-second, defaults to 3, i.e 180 in a minute }; #endif diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index b8e4e62df..4b2af7f77 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -463,6 +463,10 @@ static void waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldNa } wpt->setFlag(f, true); + } else if (!strcmp(fieldName, "fly_type")) { + if (!naIsString(value)) naRuntimeError(c, "fly_type must be a string"); + bool flyOver = (strcmp(naStr_data(value), "flyOver") == 0); + wpt->setFlag(WPT_OVERFLIGHT, flyOver); } } @@ -569,6 +573,8 @@ static const char* flightplanGhostGetMember(naContext c, void* g, naRef field, n else if (!strcmp(fieldName, "star_trans")) *out = ghostForProcedure(c, fp->starTransition()); else if (!strcmp(fieldName, "approach")) *out = ghostForProcedure(c, fp->approach()); else if (!strcmp(fieldName, "current")) *out = naNum(fp->currentIndex()); + else if (!strcmp(fieldName, "aircraftCategory")) *out = stringToNasal(c, fp->icaoAircraftCategory()); + else if (!strcmp(fieldName, "followLegTrackToFix")) *out = naNum(fp->followLegTrackToFixes()); else { return 0; } @@ -691,6 +697,12 @@ static void flightplanGhostSetMember(naContext c, void* g, naRef field, naRef va } naRuntimeError(c, "bad argument type setting approach"); + } else if (!strcmp(fieldName, "aircraftCategory")) { + if (!naIsString(value)) naRuntimeError(c, "aircraftCategory must be a string"); + fp->setIcaoAircraftCategory(naStr_data(value)); + } else if (!strcmp(fieldName, "followLegTrackToFix")) { + int b = (int) value.num; + fp->setFollowLegTrackToFixes(b); } }