Crashfix: move spatial, AI queries in map-widget
In threaded OSG drawing, MapWidget::draw runs in the render thread context, but touches lots of main thread state. Move most of the work to an update() helper run on the main thread instead, so draw() mostly makes pure GL calls. (This is a fix for 3.0, the real solution is to migrate to a Canvas-based map and GUI)
This commit is contained in:
parent
976f3115a9
commit
1b9394fc37
3 changed files with 359 additions and 375 deletions
|
@ -977,6 +977,7 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
|
||||||
} else if (type == "map") {
|
} else if (type == "map") {
|
||||||
MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
|
MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
|
||||||
setupObject(mapWidget, props);
|
setupObject(mapWidget, props);
|
||||||
|
_activeWidgets.push_back(mapWidget);
|
||||||
return mapWidget;
|
return mapWidget;
|
||||||
} else if (type == "canvas") {
|
} else if (type == "canvas") {
|
||||||
CanvasWidget* canvasWidget = new CanvasWidget( x, y,
|
CanvasWidget* canvasWidget = new CanvasWidget( x, y,
|
||||||
|
|
|
@ -69,7 +69,7 @@ static bool puBoxIntersect(const puBox& a, const puBox& b)
|
||||||
|
|
||||||
return (x0 <= x1) && (y0 <= y1);
|
return (x0 <= x1) && (y0 <= y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapData;
|
class MapData;
|
||||||
typedef std::vector<MapData*> MapDataVec;
|
typedef std::vector<MapData*> MapDataVec;
|
||||||
|
|
||||||
|
@ -380,6 +380,76 @@ int MapData::_fontDescender = 0;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// anonymous namespace
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class MapAirportFilter : public FGAirport::AirportFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapAirportFilter(SGPropertyNode_ptr nd)
|
||||||
|
{
|
||||||
|
_heliports = nd->getBoolValue("show-heliports", false);
|
||||||
|
_hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true);
|
||||||
|
_minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual FGPositioned::Type maxType() const {
|
||||||
|
return _heliports ? FGPositioned::HELIPORT : FGPositioned::AIRPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool passAirport(FGAirport* aApt) const {
|
||||||
|
if (_hardRunwaysOnly) {
|
||||||
|
return aApt->hasHardRunwayOfLengthFt(_minLengthFt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showAll()
|
||||||
|
{
|
||||||
|
_hardRunwaysOnly = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _heliports;
|
||||||
|
bool _hardRunwaysOnly;
|
||||||
|
double _minLengthFt;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NavaidFilter : public FGPositioned::Filter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NavaidFilter(bool fixesEnabled, bool navaidsEnabled) :
|
||||||
|
_fixes(fixesEnabled),
|
||||||
|
_navaids(navaidsEnabled)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual bool pass(FGPositioned* aPos) const {
|
||||||
|
if (_fixes && (aPos->type() == FGPositioned::FIX)) {
|
||||||
|
// ignore fixes which end in digits - expirmental
|
||||||
|
if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual FGPositioned::Type minType() const {
|
||||||
|
return _fixes ? FGPositioned::FIX : FGPositioned::NDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual FGPositioned::Type maxType() const {
|
||||||
|
return _navaids ? FGPositioned::VOR : FGPositioned::FIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _fixes, _navaids;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // of anonymous namespace
|
||||||
|
|
||||||
const int MAX_ZOOM = 12;
|
const int MAX_ZOOM = 12;
|
||||||
const int SHOW_DETAIL_ZOOM = 8;
|
const int SHOW_DETAIL_ZOOM = 8;
|
||||||
const int SHOW_DETAIL2_ZOOM = 5;
|
const int SHOW_DETAIL2_ZOOM = 5;
|
||||||
|
@ -544,41 +614,127 @@ void MapWidget::zoomOut()
|
||||||
_root->setIntValue("zoom", zoom() - 1);
|
_root->setIntValue("zoom", zoom() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapWidget::update()
|
||||||
|
{
|
||||||
|
_aircraft = globals->get_aircraft_position();
|
||||||
|
|
||||||
|
bool mag = _root->getBoolValue("magnetic-headings");
|
||||||
|
if (mag != _magneticHeadings) {
|
||||||
|
clearData(); // flush cached data text, since it often includes heading
|
||||||
|
_magneticHeadings = mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hasPanned) {
|
||||||
|
_root->setBoolValue("centre-on-aircraft", false);
|
||||||
|
_hasPanned = false;
|
||||||
|
}
|
||||||
|
else if (_root->getBoolValue("centre-on-aircraft")) {
|
||||||
|
_projectionCenter = _aircraft;
|
||||||
|
}
|
||||||
|
|
||||||
|
double julianDate = globals->get_time_params()->getJD();
|
||||||
|
_magVar->update(_projectionCenter, julianDate);
|
||||||
|
|
||||||
|
_aircraftUp = _root->getBoolValue("aircraft-heading-up");
|
||||||
|
if (_aircraftUp) {
|
||||||
|
_upHeading = fgGetDouble("/orientation/heading-deg");
|
||||||
|
} else {
|
||||||
|
_upHeading = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_magneticHeadings) {
|
||||||
|
_displayHeading = (int) fgGetDouble("/orientation/heading-magnetic-deg");
|
||||||
|
} else {
|
||||||
|
_displayHeading = (int) _upHeading;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedZoom = MAX_ZOOM - zoom();
|
||||||
|
SGGeod topLeft = unproject(SGVec2d(_width/2, _height/2));
|
||||||
|
// compute draw range, including a fudge factor for ILSs and other 'long'
|
||||||
|
// symbols
|
||||||
|
_drawRangeNm = SGGeodesy::distanceNm(_projectionCenter, topLeft) + 10.0;
|
||||||
|
|
||||||
|
|
||||||
|
FGFlightHistory* history = (FGFlightHistory*) globals->get_subsystem("history");
|
||||||
|
if (history && _root->getBoolValue("draw-flight-history")) {
|
||||||
|
_flightHistoryPath = history->pathForHistory();
|
||||||
|
} else {
|
||||||
|
_flightHistoryPath.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// make spatial queries. This can trigger loading of XML files, etc, so we do
|
||||||
|
// not want to do it in draw(), which can be called from an arbitrary OSG
|
||||||
|
// rendering thread.
|
||||||
|
|
||||||
|
MapAirportFilter af(_root);
|
||||||
|
if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
|
||||||
|
// show all airports when zoomed in sufficently
|
||||||
|
af.showAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool partial = false;
|
||||||
|
FGPositionedList newItemsToDraw =
|
||||||
|
FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
|
||||||
|
|
||||||
|
bool fixes = _root->getBoolValue("draw-fixes");
|
||||||
|
NavaidFilter f(fixes, _root->getBoolValue("draw-navaids"));
|
||||||
|
if (f.minType() <= f.maxType()) {
|
||||||
|
FGPositionedList navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
|
||||||
|
newItemsToDraw.insert(newItemsToDraw.end(), navs.begin(), navs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
FGPositioned::TypeFilter tf(FGPositioned::COUNTRY);
|
||||||
|
if (_cachedZoom <= SHOW_DETAIL_ZOOM) {
|
||||||
|
tf.addType(FGPositioned::CITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
|
||||||
|
tf.addType(FGPositioned::TOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
FGPositionedList poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &tf);
|
||||||
|
newItemsToDraw.insert(newItemsToDraw.end(), poi.begin(), poi.end());
|
||||||
|
|
||||||
|
_itemsToDraw.swap(newItemsToDraw);
|
||||||
|
|
||||||
|
updateAIObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapWidget::updateAIObjects()
|
||||||
|
{
|
||||||
|
if (!_root->getBoolValue("draw-traffic") || (_cachedZoom > SHOW_DETAIL_ZOOM)) {
|
||||||
|
_aiDrawVec.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AIDrawVec newDrawVec;
|
||||||
|
|
||||||
|
const SGPropertyNode* ai = fgGetNode("/ai/models", true);
|
||||||
|
for (int i = 0; i < ai->nChildren(); ++i) {
|
||||||
|
const SGPropertyNode *model = ai->getChild(i);
|
||||||
|
// skip bad or dead entries
|
||||||
|
if (!model || model->getIntValue("id", -1) == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGGeod pos = SGGeod::fromDegFt(
|
||||||
|
model->getDoubleValue("position/longitude-deg"),
|
||||||
|
model->getDoubleValue("position/latitude-deg"),
|
||||||
|
model->getDoubleValue("position/altitude-ft"));
|
||||||
|
|
||||||
|
double dist = SGGeodesy::distanceNm(_projectionCenter, pos);
|
||||||
|
if (dist > _drawRangeNm) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newDrawVec.push_back(DrawAIObject((SGPropertyNode*) model, pos));
|
||||||
|
} // of ai/models iteration
|
||||||
|
|
||||||
|
_aiDrawVec.swap(newDrawVec);
|
||||||
|
}
|
||||||
|
|
||||||
void MapWidget::draw(int dx, int dy)
|
void MapWidget::draw(int dx, int dy)
|
||||||
{
|
{
|
||||||
_aircraft = globals->get_aircraft_position();
|
|
||||||
|
|
||||||
bool mag = _root->getBoolValue("magnetic-headings");
|
|
||||||
if (mag != _magneticHeadings) {
|
|
||||||
clearData(); // flush cached data text, since it often includes heading
|
|
||||||
_magneticHeadings = mag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_hasPanned) {
|
|
||||||
_root->setBoolValue("centre-on-aircraft", false);
|
|
||||||
_hasPanned = false;
|
|
||||||
}
|
|
||||||
else if (_root->getBoolValue("centre-on-aircraft")) {
|
|
||||||
_projectionCenter = _aircraft;
|
|
||||||
}
|
|
||||||
|
|
||||||
double julianDate = globals->get_time_params()->getJD();
|
|
||||||
_magVar->update(_projectionCenter, julianDate);
|
|
||||||
|
|
||||||
bool aircraftUp = _root->getBoolValue("aircraft-heading-up");
|
|
||||||
if (aircraftUp) {
|
|
||||||
_upHeading = fgGetDouble("/orientation/heading-deg");
|
|
||||||
} else {
|
|
||||||
_upHeading = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cachedZoom = MAX_ZOOM - zoom();
|
|
||||||
SGGeod topLeft = unproject(SGVec2d(_width/2, _height/2));
|
|
||||||
// compute draw range, including a fudge factor for ILSs and other 'long'
|
|
||||||
// symbols
|
|
||||||
_drawRangeNm = SGGeodesy::distanceNm(_projectionCenter, topLeft) + 10.0;
|
|
||||||
|
|
||||||
// drawing operations
|
|
||||||
GLint sx = (int) abox.min[0],
|
GLint sx = (int) abox.min[0],
|
||||||
sy = (int) abox.min[1];
|
sy = (int) abox.min[1];
|
||||||
glScissor(dx + sx, dy + sy, _width, _height);
|
glScissor(dx + sx, dy + sy, _width, _height);
|
||||||
|
@ -592,7 +748,7 @@ void MapWidget::draw(int dx, int dy)
|
||||||
|
|
||||||
drawLatLonGrid();
|
drawLatLonGrid();
|
||||||
|
|
||||||
if (aircraftUp) {
|
if (_aircraftUp) {
|
||||||
int textHeight = legendFont.getStringHeight() + 5;
|
int textHeight = legendFont.getStringHeight() + 5;
|
||||||
|
|
||||||
// draw heading line
|
// draw heading line
|
||||||
|
@ -600,23 +756,14 @@ void MapWidget::draw(int dx, int dy)
|
||||||
glColor3f(1.0, 1.0, 1.0);
|
glColor3f(1.0, 1.0, 1.0);
|
||||||
drawLine(loc, SGVec2d(loc.x(), (_height / 2) - textHeight));
|
drawLine(loc, SGVec2d(loc.x(), (_height / 2) - textHeight));
|
||||||
|
|
||||||
int displayHdg;
|
|
||||||
if (_magneticHeadings) {
|
|
||||||
displayHdg = (int) fgGetDouble("/orientation/heading-magnetic-deg");
|
|
||||||
} else {
|
|
||||||
displayHdg = (int) _upHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
double y = (_height / 2) - textHeight;
|
double y = (_height / 2) - textHeight;
|
||||||
char buf[16];
|
char buf[16];
|
||||||
::snprintf(buf, 16, "%d", displayHdg);
|
::snprintf(buf, 16, "%d", _displayHeading);
|
||||||
int sw = legendFont.getStringWidth(buf);
|
int sw = legendFont.getStringWidth(buf);
|
||||||
legendFont.drawString(buf, loc.x() - sw/2, y);
|
legendFont.drawString(buf, loc.x() - sw/2, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawAirports();
|
drawPositioned();
|
||||||
drawNavaids();
|
|
||||||
drawPOIs();
|
|
||||||
drawTraffic();
|
drawTraffic();
|
||||||
drawGPSData();
|
drawGPSData();
|
||||||
drawNavRadio(fgGetNode("/instrumentation/nav[0]", false));
|
drawNavRadio(fgGetNode("/instrumentation/nav[0]", false));
|
||||||
|
@ -657,8 +804,6 @@ void MapWidget::paintRuler()
|
||||||
d->setAnchor(clickPos);
|
d->setAnchor(clickPos);
|
||||||
d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 15);
|
d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 15);
|
||||||
d->setPriority(20000);
|
d->setPriority(20000);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::paintAircraftLocation(const SGGeod& aircraftPos)
|
void MapWidget::paintAircraftLocation(const SGGeod& aircraftPos)
|
||||||
|
@ -762,20 +907,17 @@ void MapWidget::paintRoute()
|
||||||
|
|
||||||
void MapWidget::drawFlightHistory()
|
void MapWidget::drawFlightHistory()
|
||||||
{
|
{
|
||||||
FGFlightHistory* history = (FGFlightHistory*) globals->get_subsystem("history");
|
if (_flightHistoryPath.empty())
|
||||||
if (!history || !_root->getBoolValue("draw-flight-history")) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// first pass, draw the actual lines
|
// first pass, draw the actual lines
|
||||||
glLineWidth(2.0);
|
glLineWidth(2.0);
|
||||||
|
|
||||||
SGGeodVec gv(history->pathForHistory());
|
|
||||||
glColor4f(0.0, 0.0, 1.0, 0.7);
|
glColor4f(0.0, 0.0, 1.0, 0.7);
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP);
|
glBegin(GL_LINE_STRIP);
|
||||||
for (unsigned int i=0; i<gv.size(); ++i) {
|
for (unsigned int i=0; i<_flightHistoryPath.size(); ++i) {
|
||||||
SGVec2d p = project(gv[i]);
|
SGVec2d p = project(_flightHistoryPath[i]);
|
||||||
glVertex2d(p.x(), p.y());
|
glVertex2d(p.x(), p.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,125 +1056,33 @@ void MapWidget::drawGPSData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapAirportFilter : public FGAirport::AirportFilter
|
void MapWidget::drawPositioned()
|
||||||
{
|
{
|
||||||
public:
|
for (unsigned int i=0; i<_itemsToDraw.size(); ++i) {
|
||||||
MapAirportFilter(SGPropertyNode_ptr nd)
|
FGPositionedRef p = _itemsToDraw[i];
|
||||||
{
|
switch (p->type()) {
|
||||||
_heliports = nd->getBoolValue("show-heliports", false);
|
case FGPositioned::AIRPORT:
|
||||||
_hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true);
|
drawAirport((FGAirport*) p.get());
|
||||||
_minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
|
break;
|
||||||
}
|
case FGPositioned::NDB:
|
||||||
|
drawNDB(false, (FGNavRecord*) p.get());
|
||||||
virtual FGPositioned::Type maxType() const {
|
break;
|
||||||
return _heliports ? FGPositioned::HELIPORT : FGPositioned::AIRPORT;
|
case FGPositioned::VOR:
|
||||||
}
|
drawVOR(false, (FGNavRecord*) p.get());
|
||||||
|
break;
|
||||||
virtual bool passAirport(FGAirport* aApt) const {
|
case FGPositioned::FIX:
|
||||||
if (_hardRunwaysOnly) {
|
drawFix((FGFix*) p.get());
|
||||||
return aApt->hasHardRunwayOfLengthFt(_minLengthFt);
|
break;
|
||||||
}
|
case FGPositioned::TOWN:
|
||||||
|
case FGPositioned::CITY:
|
||||||
return true;
|
case FGPositioned::COUNTRY:
|
||||||
}
|
drawPOI(p);
|
||||||
|
break;
|
||||||
void showAll()
|
|
||||||
{
|
default:
|
||||||
_hardRunwaysOnly = false;
|
SG_LOG(SG_GENERAL, SG_WARN, "unhandled type in MapWidget::drawPositioned");
|
||||||
}
|
} // of positioned type switch
|
||||||
|
} // of items to draw iteration
|
||||||
private:
|
|
||||||
bool _heliports;
|
|
||||||
bool _hardRunwaysOnly;
|
|
||||||
double _minLengthFt;
|
|
||||||
};
|
|
||||||
|
|
||||||
void MapWidget::drawAirports()
|
|
||||||
{
|
|
||||||
MapAirportFilter af(_root);
|
|
||||||
if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
|
|
||||||
// show all airports when zoomed in sufficently
|
|
||||||
af.showAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool partial = false;
|
|
||||||
FGPositionedList apts = FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
|
|
||||||
for (unsigned int i=0; i<apts.size(); ++i) {
|
|
||||||
drawAirport((FGAirport*) apts[i].get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NavaidFilter : public FGPositioned::Filter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NavaidFilter(bool fixesEnabled, bool navaidsEnabled) :
|
|
||||||
_fixes(fixesEnabled),
|
|
||||||
_navaids(navaidsEnabled)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual bool pass(FGPositioned* aPos) const {
|
|
||||||
if (_fixes && (aPos->type() == FGPositioned::FIX)) {
|
|
||||||
// ignore fixes which end in digits - expirmental
|
|
||||||
if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual FGPositioned::Type minType() const {
|
|
||||||
return _fixes ? FGPositioned::FIX : FGPositioned::NDB;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual FGPositioned::Type maxType() const {
|
|
||||||
return _navaids ? FGPositioned::VOR : FGPositioned::FIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _fixes, _navaids;
|
|
||||||
};
|
|
||||||
|
|
||||||
void MapWidget::drawNavaids()
|
|
||||||
{
|
|
||||||
bool fixes = _root->getBoolValue("draw-fixes");
|
|
||||||
NavaidFilter f(fixes, _root->getBoolValue("draw-navaids"));
|
|
||||||
|
|
||||||
if (f.minType() <= f.maxType()) {
|
|
||||||
FGPositionedList navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
|
|
||||||
|
|
||||||
glLineWidth(1.0);
|
|
||||||
for (unsigned int i=0; i<navs.size(); ++i) {
|
|
||||||
FGPositioned::Type ty = navs[i]->type();
|
|
||||||
if (ty == FGPositioned::NDB) {
|
|
||||||
drawNDB(false, (FGNavRecord*) navs[i].get());
|
|
||||||
} else if (ty == FGPositioned::VOR) {
|
|
||||||
drawVOR(false, (FGNavRecord*) navs[i].get());
|
|
||||||
} else if (ty == FGPositioned::FIX) {
|
|
||||||
drawFix((FGFix*) navs[i].get());
|
|
||||||
}
|
|
||||||
} // of navaid iteration
|
|
||||||
} // of navaids || fixes are drawn test
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWidget::drawPOIs()
|
|
||||||
{
|
|
||||||
FGPositioned::TypeFilter f(FGPositioned::COUNTRY);
|
|
||||||
f.addType(FGPositioned::CITY);
|
|
||||||
f.addType(FGPositioned::TOWN);
|
|
||||||
FGPositionedList poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
|
|
||||||
|
|
||||||
glLineWidth(1.0);
|
|
||||||
for (unsigned int i=0; i<poi.size(); ++i) {
|
|
||||||
FGPositioned::Type ty = poi[i]->type();
|
|
||||||
if (ty == FGPositioned::COUNTRY) {
|
|
||||||
drawCountries((FGNavRecord*) poi[i].get());
|
|
||||||
} else if (ty == FGPositioned::CITY) {
|
|
||||||
drawCities((FGNavRecord*) poi[i].get());
|
|
||||||
} else if (ty == FGPositioned::TOWN) {
|
|
||||||
drawTowns((FGNavRecord*) poi[i].get());
|
|
||||||
}
|
|
||||||
} // of navaid iteration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::drawNDB(bool tuned, FGNavRecord* ndb)
|
void MapWidget::drawNDB(bool tuned, FGNavRecord* ndb)
|
||||||
|
@ -1193,91 +1243,38 @@ void MapWidget::drawTunedLocalizer(SGPropertyNode_ptr radio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::drawCountries(FGNavRecord* rec)
|
void MapWidget::drawPOI(FGPositioned* poi)
|
||||||
{
|
{
|
||||||
if (_cachedZoom < 9) {
|
SGVec2d pos = project(poi->geod());
|
||||||
return; // hide labels beyond a certain zoom level
|
|
||||||
}
|
|
||||||
|
|
||||||
SGVec2d pos = project(rec->geod());
|
|
||||||
glColor3f(1.0, 1.0, 0.0);
|
glColor3f(1.0, 1.0, 0.0);
|
||||||
|
glLineWidth(1.0);
|
||||||
|
|
||||||
circleAt(pos, 4, 10);
|
int radius = 10;
|
||||||
|
if (poi->type() == FGPositioned::CITY) {
|
||||||
|
radius = 8;
|
||||||
|
glColor3f(0.0, 1.0, 0.0);
|
||||||
|
} else if (poi->type() == FGPositioned::TOWN) {
|
||||||
|
radius = 5;
|
||||||
|
glColor3f(0.2, 1.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
circleAt(pos, 4, radius);
|
||||||
|
|
||||||
if (validDataForKey(rec)) {
|
if (validDataForKey(poi)) {
|
||||||
setAnchorForKey(rec, pos);
|
setAnchorForKey(poi, pos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
::snprintf(buffer, 1024, "%s",
|
::snprintf(buffer, 1024, "%s",
|
||||||
rec->name().c_str());
|
poi->name().c_str());
|
||||||
|
|
||||||
MapData* d = createDataForKey(rec);
|
MapData* d = createDataForKey(poi);
|
||||||
d->setPriority(200);
|
d->setPriority(200);
|
||||||
d->setLabel(rec->ident());
|
d->setLabel(poi->ident());
|
||||||
d->setText(buffer);
|
d->setText(buffer);
|
||||||
d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
|
d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
|
||||||
d->setAnchor(pos);
|
d->setAnchor(pos);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWidget::drawCities(FGNavRecord* rec)
|
|
||||||
{
|
|
||||||
if (_cachedZoom > SHOW_DETAIL_ZOOM) {
|
|
||||||
return; // hide labels beyond a certain zoom level
|
|
||||||
}
|
|
||||||
|
|
||||||
SGVec2d pos = project(rec->geod());
|
|
||||||
glColor3f(0.0, 1.0, 0.0);
|
|
||||||
|
|
||||||
circleAt(pos, 4, 8);
|
|
||||||
|
|
||||||
if (validDataForKey(rec)) {
|
|
||||||
setAnchorForKey(rec, pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[1024];
|
|
||||||
::snprintf(buffer, 1024, "%s",
|
|
||||||
rec->name().c_str());
|
|
||||||
|
|
||||||
MapData* d = createDataForKey(rec);
|
|
||||||
d->setPriority(40);
|
|
||||||
d->setLabel(rec->ident());
|
|
||||||
d->setText(buffer);
|
|
||||||
d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
|
|
||||||
d->setAnchor(pos);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapWidget::drawTowns(FGNavRecord* rec)
|
|
||||||
{
|
|
||||||
if (_cachedZoom > SHOW_DETAIL2_ZOOM) {
|
|
||||||
return; // hide labels beyond a certain zoom level
|
|
||||||
}
|
|
||||||
|
|
||||||
SGVec2d pos = project(rec->geod());
|
|
||||||
glColor3f(0.2, 1.0, 0.0);
|
|
||||||
|
|
||||||
circleAt(pos, 4, 5);
|
|
||||||
|
|
||||||
if (validDataForKey(rec)) {
|
|
||||||
setAnchorForKey(rec, pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[1024];
|
|
||||||
::snprintf(buffer, 1024, "%s",
|
|
||||||
rec->name().c_str());
|
|
||||||
|
|
||||||
MapData* d = createDataForKey(rec);
|
|
||||||
d->setPriority(40);
|
|
||||||
d->setLabel(rec->ident());
|
|
||||||
d->setText(buffer);
|
|
||||||
d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
|
|
||||||
d->setAnchor(pos);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1491,42 +1488,10 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy)
|
||||||
|
|
||||||
void MapWidget::drawTraffic()
|
void MapWidget::drawTraffic()
|
||||||
{
|
{
|
||||||
if (!_root->getBoolValue("draw-traffic")) {
|
AIDrawVec::const_iterator it;
|
||||||
return;
|
for (it = _aiDrawVec.begin(); it != _aiDrawVec.end(); ++it) {
|
||||||
}
|
drawAI(*it);
|
||||||
|
|
||||||
if (_cachedZoom > SHOW_DETAIL_ZOOM) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SGPropertyNode* ai = fgGetNode("/ai/models", true);
|
|
||||||
|
|
||||||
for (int i = 0; i < ai->nChildren(); ++i) {
|
|
||||||
const SGPropertyNode *model = ai->getChild(i);
|
|
||||||
// skip bad or dead entries
|
|
||||||
if (!model || model->getIntValue("id", -1) == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& name(model->getName());
|
|
||||||
SGGeod pos = SGGeod::fromDegFt(
|
|
||||||
model->getDoubleValue("position/longitude-deg"),
|
|
||||||
model->getDoubleValue("position/latitude-deg"),
|
|
||||||
model->getDoubleValue("position/altitude-ft"));
|
|
||||||
|
|
||||||
double dist = SGGeodesy::distanceNm(_projectionCenter, pos);
|
|
||||||
if (dist > _drawRangeNm) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
double heading = model->getDoubleValue("orientation/true-heading-deg");
|
|
||||||
if ((name == "aircraft") || (name == "multiplayer") ||
|
|
||||||
(name == "wingman") || (name == "tanker")) {
|
|
||||||
drawAIAircraft(model, pos, heading);
|
|
||||||
} else if ((name == "ship") || (name == "carrier") || (name == "escort")) {
|
|
||||||
drawAIShip(model, pos, heading);
|
|
||||||
}
|
|
||||||
} // of ai/models iteration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::drawHelipad(FGHelipad* hp)
|
void MapWidget::drawHelipad(FGHelipad* hp)
|
||||||
|
@ -1555,105 +1520,36 @@ void MapWidget::drawHelipad(FGHelipad* hp)
|
||||||
d->setAnchor(pos);
|
d->setAnchor(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg)
|
void MapWidget::drawAI(const DrawAIObject& dai)
|
||||||
{
|
{
|
||||||
|
SGVec2d p = project(dai.pos);
|
||||||
|
|
||||||
SGVec2d p = project(pos);
|
if (dai.boat) {
|
||||||
|
glColor3f(0.0, 0.0, 0.5);
|
||||||
|
|
||||||
glColor3f(0.0, 0.0, 0.0);
|
} else {
|
||||||
|
glColor3f(0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
glLineWidth(2.0);
|
glLineWidth(2.0);
|
||||||
circleAt(p, 4, 6.0); // black diamond
|
circleAt(p, 4, 6.0); // black diamond
|
||||||
|
|
||||||
// draw heading vector
|
// draw heading vector
|
||||||
int speedKts = static_cast<int>(model->getDoubleValue("velocities/true-airspeed-kt"));
|
if (dai.speedKts > 1) {
|
||||||
if (speedKts > 1) {
|
|
||||||
glLineWidth(1.0);
|
glLineWidth(1.0);
|
||||||
|
|
||||||
const double dt = 15.0 / (3600.0); // 15 seconds look-ahead
|
const double dt = 15.0 / (3600.0); // 15 seconds look-ahead
|
||||||
double distanceM = speedKts * SG_NM_TO_METER * dt;
|
double distanceM = dai.speedKts * SG_NM_TO_METER * dt;
|
||||||
|
SGGeod advance = SGGeodesy::direct(dai.pos, dai.heading, distanceM);
|
||||||
SGGeod advance;
|
|
||||||
double az2;
|
|
||||||
SGGeodesy::direct(pos, hdg, distanceM, advance, az2);
|
|
||||||
|
|
||||||
drawLine(p, project(advance));
|
drawLine(p, project(advance));
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to access the flight-plan of the aircraft. There are several layers
|
MapData* d = getOrCreateDataForKey((void*) dai.model);
|
||||||
// of potential NULL-ness here, so we have to be defensive at each stage.
|
d->setText(dai.legend);
|
||||||
std::string originICAO, destinationICAO;
|
d->setLabel(dai.label);
|
||||||
FGAIManager* aiManager = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
|
d->setPriority(dai.speedKts > 5 ? 60 : 10); // low priority for parked aircraft
|
||||||
FGAIBasePtr aircraft = aiManager ? aiManager->getObjectFromProperty(model) : NULL;
|
|
||||||
if (aircraft) {
|
|
||||||
FGAIAircraft* p = static_cast<FGAIAircraft*>(aircraft.get());
|
|
||||||
if (p->GetFlightPlan()) {
|
|
||||||
if (p->GetFlightPlan()->departureAirport()) {
|
|
||||||
originICAO = p->GetFlightPlan()->departureAirport()->ident();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->GetFlightPlan()->arrivalAirport()) {
|
|
||||||
destinationICAO = p->GetFlightPlan()->arrivalAirport()->ident();
|
|
||||||
}
|
|
||||||
} // of flight-plan exists
|
|
||||||
} // of check for AIBase-derived instance
|
|
||||||
|
|
||||||
// draw callsign / altitude / speed
|
|
||||||
int altFt50 = static_cast<int>(pos.getElevationFt() / 50.0) * 50;
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << model->getStringValue("callsign", "<>");
|
|
||||||
if (speedKts > 1) {
|
|
||||||
ss << "\n" << altFt50 << "' " << speedKts << "kts";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!originICAO.empty() || ! destinationICAO.empty()) {
|
|
||||||
ss << "\n" << originICAO << " -> " << destinationICAO;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapData* d = getOrCreateDataForKey((void*) model);
|
|
||||||
d->setText(ss.str().c_str());
|
|
||||||
d->setLabel(model->getStringValue("callsign", "<>"));
|
|
||||||
d->setPriority(speedKts > 5 ? 60 : 10); // low priority for parked aircraft
|
|
||||||
d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
|
d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
|
||||||
d->setAnchor(p);
|
d->setAnchor(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapWidget::drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg)
|
|
||||||
{
|
|
||||||
SGVec2d p = project(pos);
|
|
||||||
|
|
||||||
glColor3f(0.0, 0.0, 0.5);
|
|
||||||
glLineWidth(2.0);
|
|
||||||
circleAt(p, 4, 6.0); // blue diamond (to differentiate from aircraft.
|
|
||||||
|
|
||||||
// draw heading vector
|
|
||||||
int speedKts = static_cast<int>(model->getDoubleValue("velocities/speed-kts"));
|
|
||||||
if (speedKts > 1) {
|
|
||||||
glLineWidth(1.0);
|
|
||||||
|
|
||||||
const double dt = 15.0 / (3600.0); // 15 seconds look-ahead
|
|
||||||
double distanceM = speedKts * SG_NM_TO_METER * dt;
|
|
||||||
|
|
||||||
SGGeod advance;
|
|
||||||
double az2;
|
|
||||||
SGGeodesy::direct(pos, hdg, distanceM, advance, az2);
|
|
||||||
|
|
||||||
drawLine(p, project(advance));
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw callsign / speed
|
|
||||||
char buffer[1024];
|
|
||||||
::snprintf(buffer, 1024, "%s\n%dkts",
|
|
||||||
model->getStringValue("name", "<>"),
|
|
||||||
speedKts);
|
|
||||||
|
|
||||||
MapData* d = getOrCreateDataForKey((void*) model);
|
|
||||||
d->setText(buffer);
|
|
||||||
d->setLabel(model->getStringValue("name", "<>"));
|
|
||||||
d->setPriority(speedKts > 2 ? 30 : 10); // low priority for slow moving ships
|
|
||||||
d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
|
|
||||||
d->setAnchor(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
SGVec2d MapWidget::project(const SGGeod& geod) const
|
SGVec2d MapWidget::project(const SGGeod& geod) const
|
||||||
{
|
{
|
||||||
SGVec2d p;
|
SGVec2d p;
|
||||||
|
@ -1979,3 +1875,63 @@ int MapWidget::displayHeading(double h) const
|
||||||
SG_NORMALIZE_RANGE(h, 0.0, 360.0);
|
SG_NORMALIZE_RANGE(h, 0.0, 360.0);
|
||||||
return SGMiscd::roundToInt(h);
|
return SGMiscd::roundToInt(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapWidget::DrawAIObject::DrawAIObject(SGPropertyNode* m, const SGGeod& g) :
|
||||||
|
model(m),
|
||||||
|
boat(false),
|
||||||
|
pos(g),
|
||||||
|
speedKts(0)
|
||||||
|
{
|
||||||
|
std::string name(model->getNameString());
|
||||||
|
heading = model->getDoubleValue("orientation/true-heading-deg");
|
||||||
|
|
||||||
|
if ((name == "aircraft") || (name == "multiplayer") ||
|
||||||
|
(name == "wingman") || (name == "tanker"))
|
||||||
|
{
|
||||||
|
speedKts = static_cast<int>(model->getDoubleValue("velocities/true-airspeed-kt"));
|
||||||
|
label = model->getStringValue("callsign", "<>");
|
||||||
|
|
||||||
|
// try to access the flight-plan of the aircraft. There are several layers
|
||||||
|
// of potential NULL-ness here, so we have to be defensive at each stage.
|
||||||
|
std::string originICAO, destinationICAO;
|
||||||
|
FGAIManager* aiManager = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
|
||||||
|
FGAIBasePtr aircraft = aiManager ? aiManager->getObjectFromProperty(model) : NULL;
|
||||||
|
if (aircraft) {
|
||||||
|
FGAIAircraft* p = static_cast<FGAIAircraft*>(aircraft.get());
|
||||||
|
if (p->GetFlightPlan()) {
|
||||||
|
if (p->GetFlightPlan()->departureAirport()) {
|
||||||
|
originICAO = p->GetFlightPlan()->departureAirport()->ident();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->GetFlightPlan()->arrivalAirport()) {
|
||||||
|
destinationICAO = p->GetFlightPlan()->arrivalAirport()->ident();
|
||||||
|
}
|
||||||
|
} // of flight-plan exists
|
||||||
|
} // of check for AIBase-derived instance
|
||||||
|
|
||||||
|
// draw callsign / altitude / speed
|
||||||
|
int altFt50 = static_cast<int>(pos.getElevationFt() / 50.0) * 50;
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << model->getStringValue("callsign", "<>");
|
||||||
|
if (speedKts > 1) {
|
||||||
|
ss << "\n" << altFt50 << "' " << speedKts << "kts";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!originICAO.empty() || ! destinationICAO.empty()) {
|
||||||
|
ss << "\n" << originICAO << " -> " << destinationICAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend = ss.str();
|
||||||
|
} else if ((name == "ship") || (name == "carrier") || (name == "escort")) {
|
||||||
|
boat = true;
|
||||||
|
speedKts = static_cast<int>(model->getDoubleValue("velocities/speed-kts"));
|
||||||
|
label = model->getStringValue("name", "<>");
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
::snprintf(buffer, 1024, "%s\n%dkts",
|
||||||
|
model->getStringValue("name", "<>"),
|
||||||
|
speedKts);
|
||||||
|
legend = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
|
#include <Navaids/positioned.hxx>
|
||||||
#include <plib/pu.h>
|
#include <plib/pu.h>
|
||||||
|
|
||||||
#include "dialog.hxx" // for GUI_ID
|
#include "FGPUIDialog.hxx"
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class FGRouteMgr;
|
class FGRouteMgr;
|
||||||
|
@ -20,18 +21,25 @@ class FGFix;
|
||||||
class MapData;
|
class MapData;
|
||||||
class SGMagVar;
|
class SGMagVar;
|
||||||
|
|
||||||
class MapWidget : public puObject
|
typedef std::vector<SGGeod> SGGeodVec;
|
||||||
|
|
||||||
|
class MapWidget : public puObject, public FGPUIDialog::ActiveWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapWidget(int x, int y, int width, int height);
|
MapWidget(int x, int y, int width, int height);
|
||||||
virtual ~MapWidget();
|
virtual ~MapWidget();
|
||||||
|
|
||||||
|
// puObject over-rides
|
||||||
virtual void setSize(int width, int height);
|
virtual void setSize(int width, int height);
|
||||||
virtual void doHit( int button, int updown, int x, int y ) ;
|
virtual void doHit( int button, int updown, int x, int y ) ;
|
||||||
virtual void draw( int dx, int dy ) ;
|
virtual void draw( int dx, int dy ) ;
|
||||||
virtual int checkKey(int key, int updown);
|
virtual int checkKey(int key, int updown);
|
||||||
|
|
||||||
void setProperty(SGPropertyNode_ptr prop);
|
void setProperty(SGPropertyNode_ptr prop);
|
||||||
|
|
||||||
|
// PUIDialog::ActiveWidget over-rides
|
||||||
|
virtual void update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Projection {
|
enum Projection {
|
||||||
PROJECTION_SAMSON_FLAMSTEED,
|
PROJECTION_SAMSON_FLAMSTEED,
|
||||||
|
@ -60,7 +68,6 @@ private:
|
||||||
SGVec2d gridPoint(int ix, int iy);
|
SGVec2d gridPoint(int ix, int iy);
|
||||||
bool drawLineClipped(const SGVec2d& a, const SGVec2d& b);
|
bool drawLineClipped(const SGVec2d& a, const SGVec2d& b);
|
||||||
|
|
||||||
void drawAirports();
|
|
||||||
void drawAirport(FGAirport* apt);
|
void drawAirport(FGAirport* apt);
|
||||||
int scoreAirportRunways(FGAirport* apt);
|
int scoreAirportRunways(FGAirport* apt);
|
||||||
void drawRunwayPre(FGRunway* rwy);
|
void drawRunwayPre(FGRunway* rwy);
|
||||||
|
@ -68,19 +75,34 @@ private:
|
||||||
void drawHelipad(FGHelipad* hp);
|
void drawHelipad(FGHelipad* hp);
|
||||||
void drawILS(bool tuned, FGRunway* rwy);
|
void drawILS(bool tuned, FGRunway* rwy);
|
||||||
|
|
||||||
void drawNavaids();
|
void drawPositioned();
|
||||||
void drawPOIs();
|
|
||||||
void drawNDB(bool tuned, FGNavRecord* nav);
|
void drawNDB(bool tuned, FGNavRecord* nav);
|
||||||
void drawVOR(bool tuned, FGNavRecord* nav);
|
void drawVOR(bool tuned, FGNavRecord* nav);
|
||||||
void drawFix(FGFix* fix);
|
void drawFix(FGFix* fix);
|
||||||
|
|
||||||
void drawCountries(FGNavRecord* rec);
|
void drawPOI(FGPositioned* rec);
|
||||||
void drawCities(FGNavRecord* rec);
|
|
||||||
void drawTowns(FGNavRecord* rec);
|
|
||||||
|
|
||||||
void drawTraffic();
|
void drawTraffic();
|
||||||
void drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg);
|
|
||||||
void drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg);
|
class DrawAIObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DrawAIObject(SGPropertyNode* model, const SGGeod& g);
|
||||||
|
|
||||||
|
SGPropertyNode* model;
|
||||||
|
bool boat;
|
||||||
|
SGGeod pos;
|
||||||
|
double heading;
|
||||||
|
int speedKts;
|
||||||
|
std::string label;
|
||||||
|
std::string legend;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<DrawAIObject> AIDrawVec;
|
||||||
|
AIDrawVec _aiDrawVec;
|
||||||
|
|
||||||
|
void updateAIObjects();
|
||||||
|
void drawAI(const DrawAIObject& dai);
|
||||||
|
|
||||||
void drawData();
|
void drawData();
|
||||||
bool validDataForKey(void* key);
|
bool validDataForKey(void* key);
|
||||||
|
@ -107,7 +129,9 @@ private:
|
||||||
double _upHeading; // true heading corresponding to +ve y-axis
|
double _upHeading; // true heading corresponding to +ve y-axis
|
||||||
bool _magneticHeadings;
|
bool _magneticHeadings;
|
||||||
bool _hasPanned;
|
bool _hasPanned;
|
||||||
|
bool _aircraftUp;
|
||||||
|
int _displayHeading;
|
||||||
|
|
||||||
SGGeod _projectionCenter;
|
SGGeod _projectionCenter;
|
||||||
Projection _projection;
|
Projection _projection;
|
||||||
SGGeod _aircraft;
|
SGGeod _aircraft;
|
||||||
|
@ -116,7 +140,10 @@ private:
|
||||||
FGRouteMgr* _route;
|
FGRouteMgr* _route;
|
||||||
SGPropertyNode_ptr _root;
|
SGPropertyNode_ptr _root;
|
||||||
SGPropertyNode_ptr _gps;
|
SGPropertyNode_ptr _gps;
|
||||||
|
SGGeodVec _flightHistoryPath;
|
||||||
|
|
||||||
|
FGPositionedList _itemsToDraw;
|
||||||
|
|
||||||
typedef std::map<void*, MapData*> KeyDataMap;
|
typedef std::map<void*, MapData*> KeyDataMap;
|
||||||
KeyDataMap _mapData;
|
KeyDataMap _mapData;
|
||||||
std::vector<MapData*> _dataQueue;
|
std::vector<MapData*> _dataQueue;
|
||||||
|
|
Loading…
Add table
Reference in a new issue