From: James Turner Date: Sat, 4 Jun 2011 17:41:25 +0000 (+0100) Subject: Initial hacking on nav-display instrument, derived from the wxradar code X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=28c8e6fe1cdf19b517c6d572244b451f93581cf2;p=flightgear.git Initial hacking on nav-display instrument, derived from the wxradar code --- diff --git a/src/Instrumentation/CMakeLists.txt b/src/Instrumentation/CMakeLists.txt index 60d9457d3..96c11b519 100644 --- a/src/Instrumentation/CMakeLists.txt +++ b/src/Instrumentation/CMakeLists.txt @@ -36,6 +36,7 @@ set(SOURCES turn_indicator.cxx vertical_speed_indicator.cxx wxradar.cxx + NavDisplay.cxx HUD/HUD.cxx HUD/HUD_dial.cxx HUD/HUD_gauge.cxx diff --git a/src/Instrumentation/Makefile.am b/src/Instrumentation/Makefile.am index 0edb85433..7930fdbfb 100644 --- a/src/Instrumentation/Makefile.am +++ b/src/Instrumentation/Makefile.am @@ -34,6 +34,7 @@ libInstrumentation_a_SOURCES = \ groundradar.cxx groundradar.hxx \ agradar.cxx agradar.hxx rad_alt.cxx rad_alt.hxx \ rnav_waypt_controller.cxx rnav_waypt_controller.hxx \ - tcas.cxx tcas.hxx + tcas.cxx tcas.hxx \ + NavDisplay.cxx NavDisplay.hxx INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir)/src diff --git a/src/Instrumentation/NavDisplay.cxx b/src/Instrumentation/NavDisplay.cxx new file mode 100644 index 000000000..3d0e401b7 --- /dev/null +++ b/src/Instrumentation/NavDisplay.cxx @@ -0,0 +1,648 @@ +// navigation display texture +// +// Written by James Turner, forked from wxradar code +// +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "NavDisplay.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include // for cout, endl + +using std::stringstream; +using std::endl; +using std::setprecision; +using std::fixed; +using std::setw; +using std::setfill; +using std::cout; +using std::endl; + +#include
+#include
+#include +#include +#include +#include +#include +#include +#include +#include + +#include "instrument_mgr.hxx" +#include "od_gauge.hxx" + +static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture +static const char *DEFAULT_FONT = "typewriter.txf"; + +NavDisplay::NavDisplay(SGPropertyNode *node) : + _name(node->getStringValue("name", "nd")), + _num(node->getIntValue("number", 0)), + _time(0.0), + _interval(node->getDoubleValue("update-interval-sec", 1.0)), + _elapsed_time(0), + _persistance(0), + _sim_init_done(false), + _odg(0), + _scale(0), + _angle_offset(0), + _view_heading(0), + _x_offset(0), + _y_offset(0), + _radar_ref_rng(0), + _lat(0), + _lon(0), + _resultTexture(0), + _font_size(0), + _font_spacing(0), + _rangeNm(0) +{ + _Instrument = fgGetNode(string("/instrumentation/" + _name).c_str(), _num, true); + _font_node = _Instrument->getNode("font", true); + +#define INITFONT(p, val, type) if (!_font_node->hasValue(p)) _font_node->set##type##Value(p, val) + INITFONT("name", DEFAULT_FONT, String); + INITFONT("size", 8, Float); + INITFONT("line-spacing", 0.25, Float); + INITFONT("color/red", 0, Float); + INITFONT("color/green", 0.8, Float); + INITFONT("color/blue", 0, Float); + INITFONT("color/alpha", 1, Float); +#undef INITFONT + +} + + +NavDisplay::~NavDisplay() +{ +} + + +void +NavDisplay::init () +{ + _serviceable_node = _Instrument->getNode("serviceable", true); + + // texture name to use in 2D and 3D instruments + _texture_path = _Instrument->getStringValue("radar-texture-path", + "Aircraft/Instruments/Textures/od_wxradar.rgb"); + _resultTexture = FGTextureManager::createTexture(_texture_path.c_str(), false); + + string path = _Instrument->getStringValue("symbol-texture-path", + "Aircraft/Instruments/Textures/nd-symbols.png"); + SGPath tpath = globals->resolve_aircraft_path(path); + + // no mipmap or else alpha will mix with pixels on the border of shapes, ruining the effect + _symbols = SGLoadTexture2D(tpath, NULL, false, false); + + FGInstrumentMgr *imgr = (FGInstrumentMgr *)globals->get_subsystem("instrumentation"); + _odg = (FGODGauge *)imgr->get_subsystem("od_gauge"); + _odg->setSize(_Instrument->getIntValue("texture-size", 512)); + + + _user_lat_node = fgGetNode("/position/latitude-deg", true); + _user_lon_node = fgGetNode("/position/longitude-deg", true); + _user_alt_node = fgGetNode("/position/altitude-ft", true); + + SGPropertyNode *n = _Instrument->getNode("display-controls", true); + _radar_weather_node = n->getNode("WX", true); + _radar_position_node = n->getNode("pos", true); + _radar_data_node = n->getNode("data", true); + _radar_symbol_node = n->getNode("symbol", true); + _radar_centre_node = n->getNode("centre", true); + _radar_tcas_node = n->getNode("tcas", true); + _radar_absalt_node = n->getNode("abs-altitude", true); + + _ai_enabled_node = fgGetNode("/sim/ai/enabled", true); + _route = static_cast(globals->get_subsystem("route-manager")); + +// OSG geometry setup + _radarGeode = new osg::Geode; + osg::StateSet *stateSet = _radarGeode->getOrCreateStateSet(); + stateSet->setTextureAttributeAndModes(0, _symbols.get()); + + osg::LineWidth *lw = new osg::LineWidth(); + lw->setWidth(2.0); + stateSet->setAttribute(lw); + + _geom = new osg::Geometry; + _geom->setUseDisplayList(false); + // Initially allocate space for 128 quads + _vertices = new osg::Vec2Array; + _vertices->setDataVariance(osg::Object::DYNAMIC); + _vertices->reserve(128 * 4); + _geom->setVertexArray(_vertices); + _texCoords = new osg::Vec2Array; + _texCoords->setDataVariance(osg::Object::DYNAMIC); + _texCoords->reserve(128 * 4); + _geom->setTexCoordArray(0, _texCoords); + + osg::Vec3Array *colors = new osg::Vec3Array; + colors->push_back(osg::Vec3(1.0f, 1.0f, 1.0f)); // color of echos + _geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET); + _geom->setColorArray(colors); + + _symbolPrimSet = new osg::DrawArrays(osg::PrimitiveSet::QUADS); + _symbolPrimSet->setDataVariance(osg::Object::DYNAMIC); + _geom->addPrimitiveSet(_symbolPrimSet); + + _geom->setInitialBound(osg::BoundingBox(osg::Vec3f(-256.0f, -256.0f, 0.0f), + osg::Vec3f(256.0f, 256.0f, 0.0f))); + _radarGeode->addDrawable(_geom); + _odg->allocRT(); + // Texture in the 2D panel system + FGTextureManager::addTexture(_texture_path.c_str(), _odg->getTexture()); + + _lineGeometry = new osg::Geometry; + _lineGeometry->setUseDisplayList(false); + + _lineVertices = new osg::Vec2Array; + _lineVertices->setDataVariance(osg::Object::DYNAMIC); + _lineVertices->reserve(128 * 4); + _lineGeometry->setVertexArray(_vertices); + + + _lineColors = new osg::Vec3Array; + _lineColors->setDataVariance(osg::Object::DYNAMIC); + _lineGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + _lineGeometry->setColorArray(colors); + + _linePrimSet = new osg::DrawArrays(osg::PrimitiveSet::LINES); + _linePrimSet->setDataVariance(osg::Object::DYNAMIC); + _lineGeometry->addPrimitiveSet(_linePrimSet); + + _lineGeometry->setInitialBound(osg::BoundingBox(osg::Vec3f(-256.0f, -256.0f, 0.0f), + osg::Vec3f(256.0f, 256.0f, 0.0f))); + + _radarGeode->addDrawable(_lineGeometry); + + _textGeode = new osg::Geode; + + osg::Camera *camera = _odg->getCamera(); + camera->addChild(_radarGeode.get()); + camera->addChild(_textGeode.get()); + + updateFont(); +} + + +// Local coordinates for each echo +const osg::Vec3f symbolCoords[4] = { + osg::Vec3f(-.7f, -.7f, 0.0f), osg::Vec3f(.7f, -.7f, 0.0f), + osg::Vec3f(.7f, .7f, 0.0f), osg::Vec3f(-.7f, .7f, 0.0f) +}; + + +const osg::Vec2f symbolTexCoords[4] = { + osg::Vec2f(0.0f, 0.0f), osg::Vec2f(UNIT, 0.0f), + osg::Vec2f(UNIT, UNIT), osg::Vec2f(0.0f, UNIT) +}; + + +// helper +static void +addQuad(osg::Vec2Array *vertices, osg::Vec2Array *texCoords, + const osg::Matrixf& transform, const osg::Vec2f& texBase) +{ + for (int i = 0; i < 4; i++) { + const osg::Vec3f coords = transform.preMult(symbolCoords[i]); + texCoords->push_back(texBase + symbolTexCoords[i]); + vertices->push_back(osg::Vec2f(coords.x(), coords.y())); + } +} + + +// Rotate by a heading value +static inline +osg::Matrixf wxRotate(float angle) +{ + return osg::Matrixf::rotate(angle, 0.0f, 0.0f, -1.0f); +} + + +void +NavDisplay::update (double delta_time_sec) +{ + if (!fgGetBool("sim/sceneryloaded", false)) { + return; + } + + if (!_odg || !_serviceable_node->getBoolValue()) { + _Instrument->setStringValue("status", ""); + return; + } + + _time += delta_time_sec; + if (_time < _interval){ + return; + } + _time -= _interval; + + string mode = _Instrument->getStringValue("display-mode", "arc"); + _rangeNm = _Instrument->getFloatValue("range", 40.0); + _view_heading = fgGetDouble("/orientation/heading-deg") * SG_DEGREES_TO_RADIANS; + _scale = 200.0; + + bool centre = _radar_centre_node->getBoolValue(); + if (centre) { + _centerTrans = osg::Matrixf::identity(); + } else { + _centerTrans = osg::Matrixf::identity(); + } + + _drawData = _radar_data_node->getBoolValue(); + _pos = SGGeod::fromDegFt(_user_lon_node->getDoubleValue(), + _user_lat_node->getDoubleValue(), + _user_alt_node->getDoubleValue()); + + _vertices->clear(); + _lineVertices->clear(); + _lineColors->clear(); + _texCoords->clear(); + _textGeode->removeDrawables(0, _textGeode->getNumDrawables()); + + update_aircraft(); + update_route(); + + + _symbolPrimSet->set(osg::PrimitiveSet::QUADS, 0, _vertices->size()); + _symbolPrimSet->dirty(); + _linePrimSet->set(osg::PrimitiveSet::LINES, 0, _lineVertices->size()); + _linePrimSet->dirty(); +} + +osg::Matrixf NavDisplay::project(const SGGeod& geod) const +{ + double rangeM, bearing, az2; + SGGeodesy::inverse(_pos, geod, bearing, az2, rangeM); + + double radius = ((rangeM * SG_METER_TO_NM) / _rangeNm) * _scale; + bearing *= SG_DEGREES_TO_RADIANS; + + return osg::Matrixf(wxRotate(_view_heading - bearing) + * osg::Matrixf::translate(0.0f, radius, 0.0f) + * wxRotate(bearing) * _centerTrans); + +} + +void +NavDisplay::addSymbol(const SGGeod& pos, int symbolIndex, const std::string& data) +{ + int symbolRow = symbolIndex >> 4; + int symbolColumn = symbolIndex & 0x0f; + + const osg::Vec2f texBase(UNIT * symbolColumn, UNIT * symbolRow); + float size = 600 * UNIT; + + osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f) + * project(pos)); + addQuad(_vertices, _texCoords, m, texBase); + + if (!_drawData) { + return; + } + +// add data drawable + osgText::Text* text = new osgText::Text; + text->setFont(_font.get()); + text->setFontResolution(12, 12); + text->setCharacterSize(_font_size); + + osg::Vec3 dataPos = m.preMult(osg::Vec3(16, 16, 0)); + text->setLineSpacing(_font_spacing); + + text->setAlignment(osgText::Text::LEFT_CENTER); + text->setText(data); + text->setPosition(osg::Vec3((int) dataPos.x(), (int)dataPos.y(), 0)); + _textGeode->addDrawable(text); +} + +void +NavDisplay::update_route() +{ + if (_route->numWaypts() < 2) { + return; + } + + RoutePath path(_route->waypts()); + for (int w=0; w<_route->numWaypts(); ++w) { + bool isPast = w < _route->currentIndex(); + SGGeodVec gv(path.pathForIndex(w)); + if (!gv.empty()) { + osg::Vec3 color(1.0, 0.0, 1.0); + if (isPast) { + color = osg::Vec3(0.5, 0.5, 0.5); + } + + osg::Vec3 pr = project(gv[0]).preMult(osg::Vec3(0.0, 0.0, 0.0)); + for (unsigned int i=1; ipush_back(osg::Vec2(pr.x(), pr.y())); + pr = project(gv[i]).preMult(osg::Vec3(0.0, 0.0, 0.0)); + _lineVertices->push_back(osg::Vec2(pr.x(), pr.y())); + + _lineColors->push_back(color); + _lineColors->push_back(color); + } + } // of line drawing + + flightgear::WayptRef wpt(_route->wayptAtIndex(w)); + SGGeod g = path.positionForIndex(w); + int symbolIndex = isPast ? 1 : 0; + if (!(g == SGGeod())) { + std::string data = wpt->ident(); + addSymbol(g, symbolIndex, data); + } + } // of waypoints iteration +} + +void +NavDisplay::update_aircraft() +{ + if (!_ai_enabled_node->getBoolValue()) { + return; + } + + bool draw_tcas = _radar_tcas_node->getBoolValue(); + bool draw_absolute = _radar_absalt_node->getBoolValue(); + bool draw_echoes = _radar_position_node->getBoolValue(); + bool draw_symbols = _radar_symbol_node->getBoolValue(); + bool draw_data = _radar_data_node->getBoolValue(); + if (!draw_echoes && !draw_symbols && !draw_data) + return; + + const SGPropertyNode *ai = fgGetNode("/ai/models", true); + for (int i = ai->nChildren() - 1; i >= 0; i--) { + const SGPropertyNode *model = ai->getChild(i); + if (!model->nChildren()) { + continue; + } + + double echo_radius, sigma; + const string name = model->getName(); + + if (name == "aircraft" || name == "tanker") + echo_radius = 1, sigma = 1; + else if (name == "multiplayer" || name == "wingman" || name == "static") + echo_radius = 1.5, sigma = 1; + else if (name == "ship" || name == "carrier" || name == "escort" ||name == "storm") + echo_radius = 1.5, sigma = 100; + else if (name == "thermal") + echo_radius = 2, sigma = 100; + else if (name == "rocket") + echo_radius = 0.1, sigma = 0.1; + else if (name == "ballistic") + echo_radius = 0.001, sigma = 0.001; + else + continue; + + SGGeod aiModelPos = SGGeod::fromDegFt(model->getDoubleValue("position/longitude-deg"), + model->getDoubleValue("position/latitude-deg"), + model->getDoubleValue("position/altitude-ft")); + + double heading = model->getDoubleValue("orientation/true-heading-deg"); + double rangeM, bearing, az2; + SGGeodesy::inverse(_pos, aiModelPos, bearing, az2, rangeM); + + // if (!inRadarRange(sigma, rangeM)) + // continue; + + bearing *= SG_DEGREES_TO_RADIANS; + heading *= SG_DEGREES_TO_RADIANS; + + float radius = rangeM * _scale; + // float angle = relativeBearing(bearing, _view_heading); + + bool is_tcas_contact = false; + if (draw_tcas) + { + is_tcas_contact = update_tcas(model,rangeM, + _pos.getElevationFt(), + aiModelPos.getElevationFt(), + bearing,radius,draw_absolute); + } + + // data mode + if (draw_symbols && (!draw_tcas)) { + const osg::Vec2f texBase(0, 3 * UNIT); + float size = 600 * UNIT; + osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f) + * wxRotate(heading - bearing) + * osg::Matrixf::translate(0.0f, radius, 0.0f) + * wxRotate(bearing) * _centerTrans); + addQuad(_vertices, _texCoords, m, texBase); + } + + if (draw_data || is_tcas_contact) { + update_data(model, aiModelPos.getElevationFt(), heading, radius, bearing, false); + } + } // of ai models iteration +} + +/** Update TCAS display. + * Return true when processed as TCAS contact, false otherwise. */ +bool +NavDisplay::update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt, + double bearing,double radius,bool absMode) +{ + int threatLevel=0; + { + // update TCAS symbol + osg::Vec2f texBase; + threatLevel = model->getIntValue("tcas/threat-level",-1); + if (threatLevel == -1) + { + // no TCAS information (i.e. no transponder) => not visible to TCAS + return false; + } + int row = 7 - threatLevel; + int col = 4; + double vspeed = model->getDoubleValue("velocities/vertical-speed-fps"); + if (vspeed < -3.0) // descending + col+=1; + else + if (vspeed > 3.0) // climbing + col+=2; + texBase = osg::Vec2f(col*UNIT,row * UNIT); + float size = 200 * UNIT; + osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f) + * wxRotate(-bearing) + * osg::Matrixf::translate(0.0f, radius, 0.0f) + * wxRotate(bearing) * _centerTrans); + addQuad(_vertices, _texCoords, m, texBase); + } + + { + // update TCAS data + osgText::Text *altStr = new osgText::Text; + altStr->setFont(_font.get()); + altStr->setFontResolution(12, 12); + altStr->setCharacterSize(_font_size); + altStr->setColor(_tcas_colors[threatLevel]); + osg::Matrixf m(wxRotate(-bearing) + * osg::Matrixf::translate(0.0f, radius, 0.0f) + * wxRotate(bearing) * _centerTrans); + + osg::Vec3 pos = m.preMult(osg::Vec3(16, 16, 0)); + // cast to int's, otherwise text comes out ugly + altStr->setLineSpacing(_font_spacing); + + stringstream text; + altStr->setAlignment(osgText::Text::LEFT_CENTER); + int altDif = (alt-user_alt+50)/100; + char sign = 0; + int dy=0; + if (altDif>=0) + { + sign='+'; + dy=2; + } + else + if (altDif<0) + { + sign='-'; + altDif = -altDif; + dy=-30; + } + altStr->setPosition(osg::Vec3((int)pos.x()-30, (int)pos.y()+dy, 0)); + if (absMode) + { + // absolute altitude display + text << setprecision(0) << fixed + << setw(3) << setfill('0') << alt/100 << endl; + } + else // relative altitude display + if (sign) + { + text << sign + << setprecision(0) << fixed + << setw(2) << setfill('0') << altDif << endl; + } + + altStr->setText(text.str()); + _textGeode->addDrawable(altStr); + } + + return true; +} + +void NavDisplay::update_data(const SGPropertyNode *ac, double altitude, double heading, + double radius, double bearing, bool selected) +{ + osgText::Text *callsign = new osgText::Text; + callsign->setFont(_font.get()); + callsign->setFontResolution(12, 12); + callsign->setCharacterSize(_font_size); + callsign->setColor(selected ? osg::Vec4(1, 1, 1, 1) : _font_color); + osg::Matrixf m(wxRotate(-bearing) + * osg::Matrixf::translate(0.0f, radius, 0.0f) + * wxRotate(bearing) * _centerTrans); + + osg::Vec3 pos = m.preMult(osg::Vec3(16, 16, 0)); + // cast to int's, otherwise text comes out ugly + callsign->setPosition(osg::Vec3((int)pos.x(), (int)pos.y(), 0)); + callsign->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE); + callsign->setLineSpacing(_font_spacing); + + const char *identity = ac->getStringValue("transponder-id"); + if (!identity[0]) + identity = ac->getStringValue("callsign"); + + stringstream text; + text << identity << endl + << setprecision(0) << fixed + << setw(3) << setfill('0') << heading * SG_RADIANS_TO_DEGREES << "\xB0 " + << setw(0) << altitude << "ft" << endl + << ac->getDoubleValue("velocities/true-airspeed-kt") << "kts"; + + callsign->setText(text.str()); + _textGeode->addDrawable(callsign); +} + +void +NavDisplay::updateFont() +{ + float red = _font_node->getFloatValue("color/red"); + float green = _font_node->getFloatValue("color/green"); + float blue = _font_node->getFloatValue("color/blue"); + float alpha = _font_node->getFloatValue("color/alpha"); + _font_color.set(red, green, blue, alpha); + + _font_size = _font_node->getFloatValue("size"); + _font_spacing = _font_size * _font_node->getFloatValue("line-spacing"); + string path = _font_node->getStringValue("name", DEFAULT_FONT); + + SGPath tpath; + if (path[0] != '/') { + tpath = globals->get_fg_root(); + tpath.append("Fonts"); + tpath.append(path); + } else { + tpath = path; + } + +#if (FG_OSG_VERSION >= 21000) + osg::ref_ptr fontOptions = new osgDB::ReaderWriter::Options("monochrome"); + osg::ref_ptr font = osgText::readFontFile(tpath.c_str(), fontOptions.get()); +#else + osg::ref_ptr font = osgText::readFontFile(tpath.c_str()); +#endif + + if (font != 0) { + _font = font; + _font->setMinFilterHint(osg::Texture::NEAREST); + _font->setMagFilterHint(osg::Texture::NEAREST); + _font->setGlyphImageMargin(0); + _font->setGlyphImageMarginRatio(0); + } + + for (int i=0;i<4;i++) + { + const float defaultColors[4][3] = {{0,1,1},{0,1,1},{1,0.5,0},{1,0,0}}; + SGPropertyNode_ptr color_node = _font_node->getNode("tcas/color",i,true); + float red = color_node->getFloatValue("red",defaultColors[i][0]); + float green = color_node->getFloatValue("green",defaultColors[i][1]); + float blue = color_node->getFloatValue("blue",defaultColors[i][2]); + float alpha = color_node->getFloatValue("alpha",1); + _tcas_colors[i]=osg::Vec4(red, green, blue, alpha); + } +} + + diff --git a/src/Instrumentation/NavDisplay.hxx b/src/Instrumentation/NavDisplay.hxx new file mode 100644 index 000000000..bedaf6fb0 --- /dev/null +++ b/src/Instrumentation/NavDisplay.hxx @@ -0,0 +1,150 @@ +// Wx Radar background texture +// +// Written by Harald JOHNSEN, started May 2005. +// With major amendments by Vivian MEAZZA May 2007 +// Ported to OSG by Tim MOORE Jun 2007 +// +// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef _INST_ND_HXX +#define _INST_ND_HXX + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +class FGODGauge; +class FGRouteMgr; + +class NavDisplay : public SGSubsystem +{ +public: + + NavDisplay(SGPropertyNode *node); + virtual ~NavDisplay(); + + virtual void init(); + virtual void update(double dt); + +protected: + string _name; + int _num; + double _time; + double _interval; + double _elapsed_time; + double _persistance; + bool _sim_init_done; + + SGPropertyNode_ptr _serviceable_node; + SGPropertyNode_ptr _Instrument; + SGPropertyNode_ptr _radar_mode_control_node; + + SGPropertyNode_ptr _user_lat_node; + SGPropertyNode_ptr _user_lon_node; + SGPropertyNode_ptr _user_heading_node; + SGPropertyNode_ptr _user_alt_node; + + FGODGauge *_odg; + + // Convenience function for creating a property node with a + // default value + template + SGPropertyNode *getInstrumentNode(const char *name, DefaultType value); + +private: + string _texture_path; + + typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode; + DisplayMode _display_mode; + + float _scale; // factor to convert nm to display units + float _angle_offset; + float _view_heading; + float _x_offset, _y_offset; + + double _radar_ref_rng; + double _lat, _lon; + + bool _drawData; + + SGPropertyNode_ptr _Radar_controls; + + SGPropertyNode_ptr _radar_weather_node; + SGPropertyNode_ptr _radar_position_node; + SGPropertyNode_ptr _radar_data_node; + SGPropertyNode_ptr _radar_symbol_node; + + SGPropertyNode_ptr _radar_centre_node; + SGPropertyNode_ptr _radar_coverage_node; + SGPropertyNode_ptr _radar_ref_rng_node; + SGPropertyNode_ptr _radar_hdg_marker_node; + SGPropertyNode_ptr _radar_rotate_node; + SGPropertyNode_ptr _radar_tcas_node; + SGPropertyNode_ptr _radar_absalt_node; + + SGPropertyNode_ptr _font_node; + SGPropertyNode_ptr _ai_enabled_node; + + osg::ref_ptr _resultTexture; + osg::ref_ptr _symbols; + osg::ref_ptr _radarGeode; + osg::ref_ptr _textGeode; + + osg::Geometry *_geom; + + osg::DrawArrays* _symbolPrimSet; + osg::Vec2Array *_vertices; + osg::Vec2Array *_texCoords; + + osg::Geometry* _lineGeometry; + osg::DrawArrays* _linePrimSet; + osg::Vec2Array* _lineVertices; + osg::Vec3Array* _lineColors; + + + osg::Matrixf _centerTrans; + osg::ref_ptr _font; + osg::Vec4 _font_color; + osg::Vec4 _tcas_colors[4]; + float _font_size; + float _font_spacing; + + FGRouteMgr* _route; + SGGeod _pos; + double _rangeNm; + + void update_route(); + void update_aircraft(); + bool update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt, + double bearing,double radius, bool absMode); + void update_data(const SGPropertyNode *ac, double altitude, double heading, + double radius, double bearing, bool selected); + void updateFont(); + + osg::Matrixf project(const SGGeod& geod) const; + void addSymbol(const SGGeod& pos, int symbolIndex, const std::string& data); +}; + +#endif // _INST_ND_HXX diff --git a/src/Instrumentation/instrument_mgr.cxx b/src/Instrumentation/instrument_mgr.cxx index 67dfd7623..4ebda4fa1 100644 --- a/src/Instrumentation/instrument_mgr.cxx +++ b/src/Instrumentation/instrument_mgr.cxx @@ -52,6 +52,7 @@ #include "agradar.hxx" #include "rad_alt.hxx" #include "tcas.hxx" +#include "NavDisplay.hxx" FGInstrumentMgr::FGInstrumentMgr () : _explicitGps(false) @@ -227,7 +228,10 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props) } else if ( name == "tcas" ) { set_subsystem( id, new TCAS( node ) ); - + + } else if ( name == "navigation-display" ) { + set_subsystem( id, new NavDisplay( node ) ); + } else { SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: " << name );