57cb0a809b
Overhaul and simplify the GPS search logic based on experience and testing with the API. Also fix search-by-name, which was broken.
425 lines
12 KiB
C++
425 lines
12 KiB
C++
// gps.hxx - distance-measuring equipment.
|
|
// Written by David Megginson, started 2003.
|
|
//
|
|
// This file is in the Public Domain and comes with no warranty.
|
|
|
|
|
|
#ifndef __INSTRUMENTS_GPS_HXX
|
|
#define __INSTRUMENTS_GPS_HXX 1
|
|
|
|
#include <cassert>
|
|
|
|
#include <simgear/props/props.hxx>
|
|
#include <simgear/structure/subsystem_mgr.hxx>
|
|
#include <simgear/math/SGMath.hxx>
|
|
|
|
#include "Navaids/positioned.hxx"
|
|
|
|
// forward decls
|
|
class SGRoute;
|
|
class FGRouteMgr;
|
|
class FGAirport;
|
|
class GPSListener;
|
|
|
|
class SGGeodProperty
|
|
{
|
|
public:
|
|
SGGeodProperty()
|
|
{
|
|
}
|
|
|
|
void init(SGPropertyNode* base, const char* lonStr, const char* latStr, const char* altStr = NULL);
|
|
void init(const char* lonStr, const char* latStr, const char* altStr = NULL);
|
|
void clear();
|
|
void operator=(const SGGeod& geod);
|
|
SGGeod get() const;
|
|
private:
|
|
SGPropertyNode_ptr _lon, _lat, _alt;
|
|
};
|
|
|
|
/**
|
|
* Model a GPS radio.
|
|
*
|
|
* Input properties:
|
|
*
|
|
* /position/longitude-deg
|
|
* /position/latitude-deg
|
|
* /position/altitude-ft
|
|
* /environment/magnetic-variation-deg
|
|
* /systems/electrical/outputs/gps
|
|
* /instrumentation/gps/serviceable
|
|
*
|
|
*
|
|
* Output properties:
|
|
*
|
|
* /instrumentation/gps/indicated-longitude-deg
|
|
* /instrumentation/gps/indicated-latitude-deg
|
|
* /instrumentation/gps/indicated-altitude-ft
|
|
* /instrumentation/gps/indicated-vertical-speed-fpm
|
|
* /instrumentation/gps/indicated-track-true-deg
|
|
* /instrumentation/gps/indicated-track-magnetic-deg
|
|
* /instrumentation/gps/indicated-ground-speed-kt
|
|
*
|
|
* /instrumentation/gps/wp-distance-nm
|
|
* /instrumentation/gps/wp-bearing-deg
|
|
* /instrumentation/gps/wp-bearing-mag-deg
|
|
* /instrumentation/gps/TTW
|
|
* /instrumentation/gps/course-deviation-deg
|
|
* /instrumentation/gps/course-error-nm
|
|
* /instrumentation/gps/to-flag
|
|
* /instrumentation/gps/odometer
|
|
* /instrumentation/gps/trip-odometer
|
|
* /instrumentation/gps/true-bug-error-deg
|
|
* /instrumentation/gps/magnetic-bug-error-deg
|
|
|
|
*/
|
|
class GPS : public SGSubsystem
|
|
{
|
|
|
|
public:
|
|
|
|
GPS (SGPropertyNode *node);
|
|
GPS ();
|
|
virtual ~GPS ();
|
|
|
|
virtual void init ();
|
|
virtual void update (double delta_time_sec);
|
|
|
|
virtual void bind();
|
|
virtual void unbind();
|
|
private:
|
|
friend class GPSListener;
|
|
friend class SearchFilter;
|
|
|
|
/**
|
|
* Configuration manager, track data relating to aircraft installation
|
|
*/
|
|
class Config
|
|
{
|
|
public:
|
|
Config();
|
|
|
|
void bind(GPS* aOwner, SGPropertyNode* aCfg);
|
|
|
|
bool turnAnticipationEnabled() const
|
|
{ return _enableTurnAnticipation; }
|
|
|
|
/**
|
|
* Desired turn rate in degrees/second. From this we derive the turn
|
|
* radius and hence how early we need to anticipate it.
|
|
*/
|
|
double turnRateDegSec() const
|
|
{ return _turnRate; }
|
|
|
|
/**
|
|
* Distance at which we arm overflight sequencing. Once inside this
|
|
* distance, a change of the wp1 'TO' flag to false will be considered
|
|
* overlight of the wp.
|
|
*/
|
|
double overflightArmDistanceNm() const
|
|
{ return _overflightArmDistance; }
|
|
|
|
/**
|
|
* Time before the next WP to activate an external annunciator
|
|
*/
|
|
double waypointAlertTime() const
|
|
{ return _waypointAlertTime; }
|
|
|
|
bool requireHardSurface() const
|
|
{ return _requireHardSurface; }
|
|
|
|
double minRunwayLengthFt() const
|
|
{ return _minRunwayLengthFt; }
|
|
|
|
bool cdiDeflectionIsAngular() const
|
|
{ return (_cdiMaxDeflectionNm <= 0.0); }
|
|
|
|
double cdiDeflectionLinearPeg() const
|
|
{
|
|
assert(_cdiMaxDeflectionNm > 0.0);
|
|
return _cdiMaxDeflectionNm;
|
|
}
|
|
|
|
bool driveAutopilot() const
|
|
{ return _driveAutopilot; }
|
|
|
|
bool courseSelectable() const
|
|
{ return _courseSelectable; }
|
|
private:
|
|
bool _enableTurnAnticipation;
|
|
|
|
// desired turn rate in degrees per second
|
|
double _turnRate;
|
|
|
|
// distance from waypoint to arm overflight sequencing (in nm)
|
|
double _overflightArmDistance;
|
|
|
|
// time before reaching a waypoint to trigger annunicator light/sound
|
|
// (in seconds)
|
|
double _waypointAlertTime;
|
|
|
|
// minimum runway length to require when filtering
|
|
double _minRunwayLengthFt;
|
|
|
|
// should we require a hard-surfaced runway when filtering?
|
|
bool _requireHardSurface;
|
|
|
|
double _cdiMaxDeflectionNm;
|
|
|
|
// should we drive the autopilot directly or not?
|
|
bool _driveAutopilot;
|
|
|
|
// is selected-course-deg read to set desired-course or not?
|
|
bool _courseSelectable;
|
|
};
|
|
|
|
class SearchFilter : public FGPositioned::Filter
|
|
{
|
|
public:
|
|
virtual bool pass(FGPositioned* aPos) const;
|
|
|
|
virtual FGPositioned::Type minType() const;
|
|
virtual FGPositioned::Type maxType() const;
|
|
};
|
|
|
|
/**
|
|
* reset all output properties to default / non-service values
|
|
*/
|
|
void clearOutput();
|
|
|
|
void updateBasicData(double dt);
|
|
void updateWaypoints();
|
|
|
|
void updateTrackingBug();
|
|
void updateReferenceNavaid(double dt);
|
|
void referenceNavaidSet(const std::string& aNavaid);
|
|
void updateRouteData();
|
|
void driveAutopilot();
|
|
|
|
void routeActivated();
|
|
void routeManagerSequenced();
|
|
void routeEdited();
|
|
void routeFinished();
|
|
|
|
void updateTurn();
|
|
void updateOverflight();
|
|
void beginTurn();
|
|
void endTurn();
|
|
|
|
double computeTurnProgress(double aBearing) const;
|
|
void computeTurnData();
|
|
void updateTurnData();
|
|
double computeTurnRadiusNm(double aGroundSpeedKts) const;
|
|
|
|
/**
|
|
* Update one-shot things when WP1 / leg data change
|
|
*/
|
|
void wp1Changed();
|
|
|
|
// scratch maintenence utilities
|
|
void setScratchFromPositioned(FGPositioned* aPos, int aIndex);
|
|
void setScratchFromCachedSearchResult();
|
|
void setScratchFromRouteWaypoint(int aIndex);
|
|
|
|
/**
|
|
* Add airport-specific information to a scratch result
|
|
*/
|
|
void addAirportToScratch(FGAirport* aAirport);
|
|
|
|
void clearScratch();
|
|
|
|
/**
|
|
* Predicate, determine if the lon/lat position in the scratch is
|
|
* valid or not.
|
|
*/
|
|
bool isScratchPositionValid() const;
|
|
|
|
FGPositioned::Filter* createFilter(FGPositioned::Type aTy);
|
|
|
|
/**
|
|
* Search kernel - called each time we step through a result
|
|
*/
|
|
void performSearch();
|
|
|
|
// command handlers
|
|
void selectLegMode();
|
|
void selectOBSMode();
|
|
void directTo();
|
|
void loadRouteWaypoint();
|
|
void loadNearest();
|
|
void search();
|
|
void nextResult();
|
|
void previousResult();
|
|
void defineWaypoint();
|
|
void insertWaypointAtIndex(int aIndex);
|
|
void removeWaypointAtIndex(int aIndex);
|
|
|
|
// tied-property getter/setters
|
|
void setCommand(const char* aCmd);
|
|
const char* getCommand() const { return ""; }
|
|
|
|
const char* getMode() const { return _mode.c_str(); }
|
|
|
|
bool getScratchValid() const { return _scratchValid; }
|
|
double getScratchDistance() const;
|
|
double getScratchMagBearing() const;
|
|
double getScratchTrueBearing() const;
|
|
bool getScratchHasNext() const;
|
|
|
|
double getSelectedCourse() const { return _selectedCourse; }
|
|
void setSelectedCourse(double crs);
|
|
double getDesiredCourse() const { return _desiredCourse; }
|
|
|
|
double getCDIDeflection() const;
|
|
|
|
double getLegDistance() const;
|
|
double getLegCourse() const;
|
|
double getLegMagCourse() const;
|
|
double getAltDistanceRatio() const;
|
|
|
|
double getTrueTrack() const { return _last_true_track; }
|
|
double getMagTrack() const;
|
|
double getGroundspeedKts() const { return _last_speed_kts; }
|
|
double getVerticalSpeed() const { return _last_vertical_speed; }
|
|
|
|
//bool getLegMode() const { return _mode == "leg"; }
|
|
//bool getObsMode() const { return _mode == "obs"; }
|
|
|
|
const char* getWP0Ident() const;
|
|
const char* getWP0Name() const;
|
|
|
|
const char* getWP1Ident() const;
|
|
const char* getWP1Name() const;
|
|
|
|
double getWP1Distance() const;
|
|
double getWP1TTW() const;
|
|
const char* getWP1TTWString() const;
|
|
double getWP1Bearing() const;
|
|
double getWP1MagBearing() const;
|
|
double getWP1CourseDeviation() const;
|
|
double getWP1CourseErrorNm() const;
|
|
bool getWP1ToFlag() const;
|
|
bool getWP1FromFlag() const;
|
|
|
|
// true-bearing-error and mag-bearing-error
|
|
|
|
|
|
/**
|
|
* Tied-properties helper, record nodes which are tied for easy un-tie-ing
|
|
*/
|
|
template <typename T>
|
|
void tie(SGPropertyNode* aNode, const char* aRelPath, const SGRawValue<T>& aRawValue)
|
|
{
|
|
SGPropertyNode* nd = aNode->getNode(aRelPath, true);
|
|
_tiedNodes.push_back(nd);
|
|
nd->tie(aRawValue);
|
|
}
|
|
|
|
/// helper, tie the lat/lon/elev of a SGGeod to the named children of aNode
|
|
void tieSGGeod(SGPropertyNode* aNode, SGGeod& aRef,
|
|
const char* lonStr, const char* latStr, const char* altStr);
|
|
|
|
/// helper, tie a SGGeod to proeprties, but read-only
|
|
void tieSGGeodReadOnly(SGPropertyNode* aNode, SGGeod& aRef,
|
|
const char* lonStr, const char* latStr, const char* altStr);
|
|
|
|
// members
|
|
SGPropertyNode_ptr _gpsNode;
|
|
SGPropertyNode_ptr _magvar_node;
|
|
SGPropertyNode_ptr _serviceable_node;
|
|
SGPropertyNode_ptr _electrical_node;
|
|
SGPropertyNode_ptr _tracking_bug_node;
|
|
SGPropertyNode_ptr _raim_node;
|
|
|
|
SGPropertyNode_ptr _odometer_node;
|
|
SGPropertyNode_ptr _trip_odometer_node;
|
|
SGPropertyNode_ptr _true_bug_error_node;
|
|
SGPropertyNode_ptr _magnetic_bug_error_node;
|
|
SGPropertyNode_ptr _eastWestVelocity;
|
|
SGPropertyNode_ptr _northSouthVelocity;
|
|
|
|
SGPropertyNode_ptr _ref_navaid_id_node;
|
|
SGPropertyNode_ptr _ref_navaid_bearing_node;
|
|
SGPropertyNode_ptr _ref_navaid_distance_node;
|
|
SGPropertyNode_ptr _ref_navaid_mag_bearing_node;
|
|
SGPropertyNode_ptr _ref_navaid_frequency_node;
|
|
SGPropertyNode_ptr _ref_navaid_name_node;
|
|
|
|
SGPropertyNode_ptr _route_active_node;
|
|
SGPropertyNode_ptr _route_current_wp_node;
|
|
SGPropertyNode_ptr _routeDistanceNm;
|
|
SGPropertyNode_ptr _routeETE;
|
|
SGPropertyNode_ptr _routeEditedSignal;
|
|
SGPropertyNode_ptr _routeFinishedSignal;
|
|
SGPropertyNode_ptr _desiredCourseNode;
|
|
|
|
double _selectedCourse;
|
|
double _desiredCourse;
|
|
|
|
bool _dataValid;
|
|
SGGeod _last_pos;
|
|
bool _lastPosValid;
|
|
double _last_speed_kts;
|
|
double _last_true_track;
|
|
double _last_vertical_speed;
|
|
double _lastEWVelocity;
|
|
double _lastNSVelocity;
|
|
|
|
std::string _mode;
|
|
GPSListener* _listener;
|
|
Config _config;
|
|
FGRouteMgr* _routeMgr;
|
|
|
|
bool _ref_navaid_set;
|
|
double _ref_navaid_elapsed;
|
|
FGPositionedRef _ref_navaid;
|
|
|
|
std::string _name;
|
|
int _num;
|
|
|
|
SGGeodProperty _position;
|
|
SGGeod _wp0_position;
|
|
SGGeod _wp1_position;
|
|
SGGeod _indicated_pos;
|
|
std::string _wp0Ident, _wp0Name, _wp1Ident, _wp1Name;
|
|
double _wp1DistanceM, _wp1TrueBearing;
|
|
|
|
// scratch data
|
|
SGGeod _scratchPos;
|
|
SGPropertyNode_ptr _scratchNode;
|
|
bool _scratchValid;
|
|
|
|
// search data
|
|
int _searchResultIndex;
|
|
std::string _searchQuery;
|
|
FGPositioned::Type _searchType;
|
|
bool _searchExact;
|
|
FGPositioned::List _searchResults;
|
|
bool _searchIsRoute; ///< set if 'search' is actually the current route
|
|
bool _searchHasNext; ///< is there a result after this one?
|
|
bool _searchNames; ///< set if we're searching names instead of idents
|
|
|
|
// turn data
|
|
bool _computeTurnData; ///< do we need to update the turn data?
|
|
bool _anticipateTurn; ///< are we anticipating the next turn or not?
|
|
bool _inTurn; // is a turn in progress?
|
|
bool _turnSequenced; // have we sequenced the new leg?
|
|
double _turnAngle; // angle to turn through, in degrees
|
|
double _turnStartBearing; // bearing of inbound leg
|
|
double _turnRadius; // radius of turn in nm
|
|
SGGeod _turnPt;
|
|
SGGeod _turnCentre;
|
|
|
|
SGPropertyNode_ptr _realismSimpleGps; ///< should the GPS be simple or realistic?
|
|
|
|
// autopilot drive properties
|
|
SGPropertyNode_ptr _apDrivingFlag;
|
|
SGPropertyNode_ptr _apTrueHeading;
|
|
SGPropertyNode_ptr _apTargetAltitudeFt;
|
|
SGPropertyNode_ptr _apAltitudeLock;
|
|
|
|
std::vector<SGPropertyNode_ptr> _tiedNodes;
|
|
};
|
|
|
|
|
|
#endif // __INSTRUMENTS_GPS_HXX
|