1
0
Fork 0

Merge branch 'jmt/gps' into next

Conflicts:
	src/Instrumentation/navradio.cxx
This commit is contained in:
Tim Moore 2010-03-28 15:32:59 +02:00
commit ebdeb3eed3
13 changed files with 1798 additions and 48 deletions

View file

@ -1828,6 +1828,8 @@
</File> </File>
<File RelativePath="..\..\..\src\GUI\WaypointList.cxx"></File> <File RelativePath="..\..\..\src\GUI\WaypointList.cxx"></File>
<File RelativePath="..\..\..\src\GUI\WaypointList.hxx"></File> <File RelativePath="..\..\..\src\GUI\WaypointList.hxx"></File>
<File RelativePath="..\..\..\src\GUI\MapWidget.cxx"></File>
<File RelativePath="..\..\..\src\GUI\MapWidget.hxx"></File>
</Filter> </Filter>
<Filter <Filter
Name="Lib_Input" Name="Lib_Input"

View file

@ -2647,6 +2647,8 @@
</File> </File>
<File RelativePath="..\..\..\src\GUI\WaypointList.cxx"></File> <File RelativePath="..\..\..\src\GUI\WaypointList.cxx"></File>
<File RelativePath="..\..\..\src\GUI\WaypointList.hxx"></File> <File RelativePath="..\..\..\src\GUI\WaypointList.hxx"></File>
<File RelativePath="..\..\..\src\GUI\MapWidget.cxx"></File>
<File RelativePath="..\..\..\src\GUI\MapWidget.hxx"></File>
</Filter> </Filter>
<Filter <Filter
Name="Lib_Input" Name="Lib_Input"

View file

@ -597,6 +597,7 @@ void FGRouteMgr::jumpToIndex(int index)
_route->set_current(index); _route->set_current(index);
currentWaypointChanged(); currentWaypointChanged();
_currentWpt->fireValueChanged();
} }
void FGRouteMgr::currentWaypointChanged() void FGRouteMgr::currentWaypointChanged()

View file

@ -23,7 +23,8 @@ libGUI_a_SOURCES = \
property_list.cxx property_list.hxx \ property_list.cxx property_list.hxx \
layout.cxx layout-props.cxx layout.hxx \ layout.cxx layout-props.cxx layout.hxx \
SafeTexFont.cxx SafeTexFont.hxx \ SafeTexFont.cxx SafeTexFont.hxx \
WaypointList.cxx WaypointList.hxx WaypointList.cxx WaypointList.hxx \
MapWidget.cxx MapWidget.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

1613
src/GUI/MapWidget.cxx Normal file

File diff suppressed because it is too large Load diff

109
src/GUI/MapWidget.hxx Normal file
View file

@ -0,0 +1,109 @@
#ifndef GUI_MAPWIDGET_HXX
#define GUI_MAPWIDGET_HXX
#include <simgear/compiler.h>
#include <simgear/math/SGMath.hxx>
#include <simgear/props/props.hxx>
#include <plib/pu.h>
#include "dialog.hxx" // for GUI_ID
// forward decls
class FGRouteMgr;
class FGRunway;
class FGAirport;
class FGNavRecord;
class FGFix;
class MapData;
class SGMagVar;
class MapWidget : public puObject
{
public:
MapWidget(int x, int y, int width, int height);
virtual ~MapWidget();
virtual void setSize(int width, int height);
virtual void doHit( int button, int updown, int x, int y ) ;
virtual void draw( int dx, int dy ) ;
virtual int checkKey(int key, int updown);
void setProperty(SGPropertyNode_ptr prop);
private:
void handlePan(int x, int y);
void pan(const SGVec2d& delta);
void zoomIn();
void zoomOut();
void paintAircraftLocation(const SGGeod& aircraftPos);
void paintRoute();
void paintRuler();
void drawGPSData();
void drawNavRadio(SGPropertyNode_ptr radio);
void drawTunedLocalizer(SGPropertyNode_ptr radio);
void drawLatLonGrid();
SGVec2d gridPoint(int ix, int iy);
bool drawLineClipped(const SGVec2d& a, const SGVec2d& b);
void drawAirports();
void drawAirport(FGAirport* apt);
int scoreAirportRunways(FGAirport* apt);
void drawRunwayPre(FGRunway* rwy);
void drawRunway(FGRunway* rwy);
void drawILS(bool tuned, FGRunway* rwy);
void drawNavaids();
void drawNDB(bool tuned, FGNavRecord* nav);
void drawVOR(bool tuned, FGNavRecord* nav);
void drawFix(FGFix* fix);
void drawTraffic();
void drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg);
void drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg);
void drawData();
bool validDataForKey(void* key);
MapData* getOrCreateDataForKey(void* key);
MapData* createDataForKey(void* key);
void setAnchorForKey(void* key, const SGVec2d& anchor);
SGVec2d project(const SGGeod& geod) const;
SGGeod unproject(const SGVec2d& p) const;
double currentScale() const;
void circleAt(const SGVec2d& center, int nSides, double r);
void circleAtAlt(const SGVec2d& center, int nSides, double r, double r2);
void drawLine(const SGVec2d& p1, const SGVec2d& p2);
void drawLegendBox(const SGVec2d& pos, const std::string& t);
int _width, _height;
int _zoom;
double _drawRangeNm;
double _upHeading; // true heading corresponding to +ve y-axis
bool _magneticHeadings;
SGGeod _projectionCenter;
SGGeod _aircraft;
SGGeod _clickGeod;
SGVec2d _hitLocation;
FGRouteMgr* _route;
SGPropertyNode_ptr _root;
SGPropertyNode_ptr _gps;
typedef std::map<void*, MapData*> KeyDataMap;
KeyDataMap _mapData;
std::vector<MapData*> _dataQueue;
SGMagVar* _magVar;
typedef std::map<int, SGVec2d> GridPointCache;
GridPointCache _gridCache;
double _gridSpacing;
SGGeod _gridCenter;
};
#endif // of GUI_MAPWIDGET_HXX

View file

@ -14,6 +14,7 @@
#include "property_list.hxx" #include "property_list.hxx"
#include "layout.hxx" #include "layout.hxx"
#include "WaypointList.hxx" #include "WaypointList.hxx"
#include "MapWidget.hxx"
enum format_type { f_INVALID, f_INT, f_LONG, f_FLOAT, f_DOUBLE, f_STRING }; enum format_type { f_INVALID, f_INT, f_LONG, f_FLOAT, f_DOUBLE, f_STRING };
static const int FORMAT_BUFSIZE = 255; static const int FORMAT_BUFSIZE = 255;
@ -815,7 +816,10 @@ FGDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeight)
setupObject(obj, props); setupObject(obj, props);
setColor(obj, props); setColor(obj, props);
return obj; return obj;
} else if (type == "map") {
MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
setupObject(mapWidget, props);
return mapWidget;
} else if (type == "combo") { } else if (type == "combo") {
fgComboBox *obj = new fgComboBox(x, y, x + width, y + height, props, fgComboBox *obj = new fgComboBox(x, y, x + width, y + height, props,
props->getBoolValue("editable", false)); props->getBoolValue("editable", false));
@ -953,12 +957,21 @@ FGDialog::setupObject (puObject *object, SGPropertyNode *props)
name = ""; name = "";
const char *propname = props->getStringValue("property"); const char *propname = props->getStringValue("property");
SGPropertyNode_ptr node = fgGetNode(propname, true); SGPropertyNode_ptr node = fgGetNode(propname, true);
copy_to_pui(node, object); if (type == "map") {
// mapWidget binds to a sub-tree of properties, and
// ignroes the puValue mechanism, so special case things here
MapWidget* mw = static_cast<MapWidget*>(object);
mw->setProperty(node);
} else {
// normal widget, creating PropertyObject
copy_to_pui(node, object);
PropertyObject *po = new PropertyObject(name, object, node);
_propertyObjects.push_back(po);
if (props->getBoolValue("live"))
_liveObjects.push_back(po);
}
PropertyObject *po = new PropertyObject(name, object, node);
_propertyObjects.push_back(po);
if (props->getBoolValue("live"))
_liveObjects.push_back(po);
} }
SGPropertyNode *dest = fgGetNode("/sim/bindings/gui", true); SGPropertyNode *dest = fgGetNode("/sim/bindings/gui", true);

View file

@ -220,7 +220,8 @@ GPS::GPS ( SGPropertyNode *node) :
_num(node->getIntValue("number", 0)), _num(node->getIntValue("number", 0)),
_computeTurnData(false), _computeTurnData(false),
_anticipateTurn(false), _anticipateTurn(false),
_inTurn(false) _inTurn(false),
_desiredCourse(0.0)
{ {
string branch = "/instrumentation/" + _name; string branch = "/instrumentation/" + _name;
_gpsNode = fgGetNode(branch.c_str(), _num, true ); _gpsNode = fgGetNode(branch.c_str(), _num, true );
@ -303,6 +304,7 @@ GPS::init ()
fromFlag->alias(wp1_node->getChild("from-flag")); fromFlag->alias(wp1_node->getChild("from-flag"));
// autopilot drive properties // autopilot drive properties
_apDrivingFlag = fgGetNode("/autopilot/settings/gps-driving-true-heading", true);
_apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true); _apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
_apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true); _apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
_apAltitudeLock = fgGetNode("/autopilot/locks/altitude", true); _apAltitudeLock = fgGetNode("/autopilot/locks/altitude", true);
@ -958,12 +960,17 @@ void GPS::updateRouteData()
void GPS::driveAutopilot() void GPS::driveAutopilot()
{ {
if (!_config.driveAutopilot() || !_realismSimpleGps->getBoolValue()) { if (!_config.driveAutopilot() || !_realismSimpleGps->getBoolValue()) {
_apDrivingFlag->setBoolValue(false);
return; return;
} }
// compatability feature - allow the route-manager / GPS to drive the // compatability feature - allow the route-manager / GPS to drive the
// generic autopilot heading hold *in leg mode only* // generic autopilot heading hold *in leg mode only*
if (_mode == "leg") {
bool drive = _mode == "leg";
_apDrivingFlag->setBoolValue(drive);
if (drive) {
// FIXME: we want to set desired track, not heading, here // FIXME: we want to set desired track, not heading, here
_apTrueHeading->setDoubleValue(getWP1Bearing()); _apTrueHeading->setDoubleValue(getWP1Bearing());
} }

View file

@ -413,6 +413,7 @@ private:
SGPropertyNode_ptr _realismSimpleGps; ///< should the GPS be simple or realistic? SGPropertyNode_ptr _realismSimpleGps; ///< should the GPS be simple or realistic?
// autopilot drive properties // autopilot drive properties
SGPropertyNode_ptr _apDrivingFlag;
SGPropertyNode_ptr _apTrueHeading; SGPropertyNode_ptr _apTrueHeading;
SGPropertyNode_ptr _apTargetAltitudeFt; SGPropertyNode_ptr _apTargetAltitudeFt;
SGPropertyNode_ptr _apAltitudeLock; SGPropertyNode_ptr _apAltitudeLock;

View file

@ -891,7 +891,7 @@ void FGNavRadio::search()
} else { // ILS or LOC } else { // ILS or LOC
_gs = globals->get_gslist()->findByFreq(freq, pos); _gs = globals->get_gslist()->findByFreq(freq, pos);
has_gs_node->setBoolValue(_gs != NULL); has_gs_node->setBoolValue(_gs != NULL);
_localizerWidth = localizerWidth(nav); _localizerWidth = nav->localizerWidth();
twist = 0.0; twist = 0.0;
effective_range = nav->get_range(); effective_range = nav->get_range();
@ -941,39 +941,6 @@ void FGNavRadio::search()
id_c4_node->setIntValue( (int)identBuffer[3] ); id_c4_node->setIntValue( (int)identBuffer[3] );
} }
double FGNavRadio::localizerWidth(FGNavRecord* aLOC)
{
FGRunway* rwy = aLOC->runway();
if (!rwy) {
return 6.0; // no runway associated, return default value
}
SGVec3d thresholdCart(SGVec3d::fromGeod(rwy->threshold()));
double axisLength = dist(aLOC->cart(), thresholdCart);
double landingLength = dist(thresholdCart, SGVec3d::fromGeod(rwy->end()));
// Reference: http://dcaa.slv.dk:8000/icaodocs/
// ICAO standard width at threshold is 210 m = 689 feet = approx 700 feet.
// ICAO 3.1.1 half course = DDM = 0.0775
// ICAO 3.1.3.7.1 Sensitivity 0.00145 DDM/m at threshold
// implies peg-to-peg of 214 m ... we will stick with 210.
// ICAO 3.1.3.7.1 "Course sector angle shall not exceed 6 degrees."
// Very short runway: less than 1200 m (4000 ft) landing length:
if (landingLength < 1200.0) {
// ICAO fudges localizer sensitivity for very short runways.
// This produces a non-monotonic sensitivity-versus length relation.
axisLength += 1050.0;
}
// Example: very short: San Diego KMYF (Montgomery Field) ILS RWY 28R
// Example: short: Tom's River KMJX (Robert J. Miller) ILS RWY 6
// Example: very long: Denver KDEN (Denver) ILS RWY 16R
double raw_width = 210.0 / axisLength * SGD_RADIANS_TO_DEGREES;
return raw_width < 6.0? raw_width : 6.0;
}
void FGNavRadio::audioNavidChanged() void FGNavRadio::audioNavidChanged()
{ {
if (_sgr->exists(nav_fx_name)) { if (_sgr->exists(nav_fx_name)) {

View file

@ -191,11 +191,6 @@ class FGNavRadio : public SGSubsystem, public SGPropertyChangeListener
void clearOutputs(); void clearOutputs();
/**
* Compute the localizer width in degrees - see implementation for
* more information on the relevant standards and formulae.
*/
double localizerWidth(FGNavRecord* aLOC);
FGNavRecord* findPrimaryNavaid(const SGGeod& aPos, double aFreqMHz); FGNavRecord* findPrimaryNavaid(const SGGeod& aPos, double aFreqMHz);
/// accessor for tied, read-only 'operable' property /// accessor for tied, read-only 'operable' property

View file

@ -181,6 +181,38 @@ void FGNavRecord::alignLocaliserWithRunway(double aThreshold)
} }
} }
double FGNavRecord::localizerWidth() const
{
if (!mRunway) {
return 6.0;
}
SGVec3d thresholdCart(SGVec3d::fromGeod(mRunway->threshold()));
double axisLength = dist(cart(), thresholdCart);
double landingLength = dist(thresholdCart, SGVec3d::fromGeod(mRunway->end()));
// Reference: http://dcaa.slv.dk:8000/icaodocs/
// ICAO standard width at threshold is 210 m = 689 feet = approx 700 feet.
// ICAO 3.1.1 half course = DDM = 0.0775
// ICAO 3.1.3.7.1 Sensitivity 0.00145 DDM/m at threshold
// implies peg-to-peg of 214 m ... we will stick with 210.
// ICAO 3.1.3.7.1 "Course sector angle shall not exceed 6 degrees."
// Very short runway: less than 1200 m (4000 ft) landing length:
if (landingLength < 1200.0) {
// ICAO fudges localizer sensitivity for very short runways.
// This produces a non-monotonic sensitivity-versus length relation.
axisLength += 1050.0;
}
// Example: very short: San Diego KMYF (Montgomery Field) ILS RWY 28R
// Example: short: Tom's River KMJX (Robert J. Miller) ILS RWY 6
// Example: very long: Denver KDEN (Denver) ILS RWY 16R
double raw_width = 210.0 / axisLength * SGD_RADIANS_TO_DEGREES;
return raw_width < 6.0? raw_width : 6.0;
}
FGTACANRecord::FGTACANRecord(void) : FGTACANRecord::FGTACANRecord(void) :
channel(""), channel(""),
freq(0) freq(0)

View file

@ -96,6 +96,13 @@ public:
* Retrieve the runway this navaid is associated with (for ILS/LOC/GS) * Retrieve the runway this navaid is associated with (for ILS/LOC/GS)
*/ */
FGRunway* runway() const { return mRunway; } FGRunway* runway() const { return mRunway; }
/**
* return the localizer width, in degrees
* computation is based up ICAO stdandard width at the runway threshold
* see implementation for further details.
*/
double localizerWidth() const;
}; };
class FGTACANRecord : public SGReferenced { class FGTACANRecord : public SGReferenced {