1
0
Fork 0
flightgear/src/Instrumentation/gps.hxx
James Turner 57cb0a809b Fix bug 150 (airports not found in GPS search)
Overhaul and simplify the GPS search logic based
on experience and testing with the API. Also fix
search-by-name, which was broken.
2010-08-14 19:16:28 +01:00

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