X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInstrumentation%2FNavDisplay.cxx;h=015f8ff595d0f173fdef4ee6eae1876c8b6ee882;hb=0f462d4a6e8ac37126dc91b52999e6bf47f5f17d;hp=e27c04361dd39978b12304ca877b063bfae7a220;hpb=c6062ad93cf3bfbffb6dec63cd6844167bb56980;p=flightgear.git diff --git a/src/Instrumentation/NavDisplay.cxx b/src/Instrumentation/NavDisplay.cxx index e27c04361..015f8ff59 100644 --- a/src/Instrumentation/NavDisplay.cxx +++ b/src/Instrumentation/NavDisplay.cxx @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include @@ -56,6 +58,8 @@ using std::setw; using std::setfill; using std::cout; using std::endl; +using std::map; +using std::string; #include
#include
@@ -145,23 +149,61 @@ static osg::Vec2 mult(const osg::Vec2& v, const osg::Matrixf& m) return osg::Vec2(r.x(), r.y()); } -/////////////////////////////////////////////////////////////////// - -class SymbolDef +class NavDisplay::CacheListener : public SGPropertyChangeListener { public: - SymbolDef() : - enable(NULL) + CacheListener(NavDisplay *nd) : + _nd(nd) {} + + virtual void valueChanged (SGPropertyNode * prop) + { + _nd->invalidatePositionedCache(); + SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache"); + } +private: + NavDisplay* _nd; +}; + +class NavDisplay::ForceUpdateListener : public SGPropertyChangeListener +{ +public: + ForceUpdateListener(NavDisplay *nd) : + _nd(nd) + {} - bool initFromNode(SGPropertyNode* node) + virtual void valueChanged (SGPropertyNode * prop) + { + SG_LOG(SG_INSTR, SG_INFO, "forcing NavDisplay update"); + _nd->forceUpdate(); + } +private: + NavDisplay* _nd; +}; + +/////////////////////////////////////////////////////////////////// + +class SymbolRule +{ +public: + SymbolRule() { + + } + + bool initFromNode(SGPropertyNode* node, NavDisplay* owner) + { + if (!node->getChild("type")) { + return false; + } + type = node->getStringValue("type"); + boost::to_lower(type); SGPropertyNode* enableNode = node->getChild("enable"); if (enableNode) { - enable = sgReadCondition(fgGetNode("/"), enableNode); + enable.reset(sgReadCondition(fgGetNode("/"), enableNode)); } - + int n=0; while (node->hasChild("state", n)) { string m = node->getChild("state", n++)->getStringValue(); @@ -172,21 +214,81 @@ public: } } // of matches parsing - if (node->hasChild("width")) { - float w = node->getFloatValue("width"); - float h = node->getFloatValue("height", w); - xy0.x() = -w * 0.5; - xy0.y() = -h * 0.5; - xy1.x() = w * 0.5; - xy1.y() = h * 0.5; - } else { - xy0.x() = node->getFloatValue("x0", 0.0); - xy0.y() = node->getFloatValue("y0", 0.0); - xy1.x() = node->getFloatValue("x1", 5); - xy1.y() = node->getFloatValue("y1", 5); - } + return true; + } + + void setDefinition(SymbolDef* d) + { + definition = d; + } + + SymbolDef* getDefinition() const + { return definition; } + + bool matches(const string_set& states) const + { + BOOST_FOREACH(const string& s, required_states) { + if (states.count(s) == 0) { + return false; + } + } + + BOOST_FOREACH(const string& s, excluded_states) { + if (states.count(s) != 0) { + return false; + } + } + + return true; + } + + void checkEnabled() + { + if (enable.get()) { + enabled = enable->test(); + } else { + enabled = true; + } + } + + bool enabled; // cached enabled state + std::string type; +private: + SymbolDef* definition; + + std::auto_ptr enable; + string_set required_states; + string_set excluded_states; + +}; + +class SymbolDef +{ +public: + bool initFromNode(SGPropertyNode* node, NavDisplay* owner) + { + if (node->getChild("type")) { + SymbolRule* builtinRule = new SymbolRule; + builtinRule->initFromNode(node, owner); + builtinRule->setDefinition(this); + owner->addRule(builtinRule); + } + + if (node->hasChild("width")) { + float w = node->getFloatValue("width"); + float h = node->getFloatValue("height", w); + xy0.x() = -w * 0.5; + xy0.y() = -h * 0.5; + xy1.x() = w * 0.5; + xy1.y() = h * 0.5; + } else { + xy0.x() = node->getFloatValue("x0", 0.0); + xy0.y() = node->getFloatValue("y0", 0.0); + xy1.x() = node->getFloatValue("x1", 5); + xy1.y() = node->getFloatValue("y1", 5); + } - double texSize = node->getFloatValue("texture-size", 1.0); + double texSize = node->getFloatValue("texture-size", owner->textureSize()); uv0.x() = node->getFloatValue("u0", 0) / texSize; uv0.y() = node->getFloatValue("v0", 0) / texSize; @@ -216,20 +318,13 @@ public: if (stretchSymbol) { stretchY2 = node->getFloatValue("y2"); stretchY3 = node->getFloatValue("y3"); - stretchV2 = node->getFloatValue("v2"); - stretchV3 = node->getFloatValue("v3"); + stretchV2 = node->getFloatValue("v2") / texSize; + stretchV3 = node->getFloatValue("v3") / texSize; } return true; } - SGCondition* enable; - bool enabled; // cached enabled state - - std::string type; - string_set required_states; - string_set excluded_states; - osg::Vec2 xy0, xy1; osg::Vec2 uv0, uv1; osg::Vec4 color; @@ -257,22 +352,6 @@ public: bool drawRouteLeg; - bool matches(const string_set& states) const - { - BOOST_FOREACH(const string& s, required_states) { - if (states.count(s) == 0) { - return false; - } - } - - BOOST_FOREACH(const string& s, excluded_states) { - if (states.count(s) != 0) { - return false; - } - } - - return true; - } }; class SymbolInstance @@ -337,10 +416,10 @@ NavDisplay::NavDisplay(SGPropertyNode *node) : _num(node->getIntValue("number", 0)), _time(0.0), _updateInterval(node->getDoubleValue("update-interval-sec", 0.1)), + _forceUpdate(true), _odg(0), _scale(0), _view_heading(0), - _resultTexture(0), _font_size(0), _font_spacing(0), _rangeNm(0) @@ -358,35 +437,87 @@ NavDisplay::NavDisplay(SGPropertyNode *node) : INITFONT("color/alpha", 1, Float); #undef INITFONT + _textureSize = _Instrument->getNode("symbol-texture-size", true)->getIntValue(); SGPropertyNode* symbolsNode = node->getNode("symbols"); SGPropertyNode* symbol; - + + map definitionDict; for (int i = 0; (symbol = symbolsNode->getChild("symbol", i)) != NULL; ++i) { SymbolDef* def = new SymbolDef; - if (!def->initFromNode(symbol)) { + if (!def->initFromNode(symbol, this)) { delete def; continue; } - _rules.push_back(def); + const char* id = symbol->getStringValue("id"); + if (id && strlen(id)) { + definitionDict[id] = def; + } + + _definitions.push_back(def); } // of symbol definition parsing + + SGPropertyNode* rulesNode = node->getNode("rules"); + if (rulesNode) { + SGPropertyNode* rule; + + for (int i = 0; (rule = rulesNode->getChild("rule", i)) != NULL; ++i) { + SymbolRule* r = new SymbolRule; + if (!r->initFromNode(rule, this)) { + delete r; + continue; + } + + const char* id = symbol->getStringValue("symbol"); + if (id && strlen(id) && (definitionDict.find(id) != definitionDict.end())) { + r->setDefinition(definitionDict[id]); + } else { + SG_LOG(SG_INSTR, SG_WARN, "symbol rule has missing/unknown definition id:" << id); + delete r; + continue; + } + + addRule(r); + } // of symbol rule parsing + } + } NavDisplay::~NavDisplay() { + delete _odg; } - void NavDisplay::init () { + _cachedItemsValid = false; + _cacheListener.reset(new CacheListener(this)); + _forceUpdateListener.reset(new ForceUpdateListener(this)); + _serviceable_node = _Instrument->getNode("serviceable", true); - + _rangeNode = _Instrument->getNode("range", true); + if (!_rangeNode->hasValue()) { + _rangeNode->setDoubleValue(40.0); + } + _rangeNode->addChangeListener(_cacheListener.get()); + _rangeNode->addChangeListener(_forceUpdateListener.get()); + + _xCenterNode = _Instrument->getNode("x-center"); + if (!_xCenterNode->hasValue()) { + _xCenterNode->setDoubleValue(0.5); + } + _xCenterNode->addChangeListener(_forceUpdateListener.get()); + _yCenterNode = _Instrument->getNode("y-center"); + if (!_yCenterNode->hasValue()) { + _yCenterNode->setDoubleValue(0.5); + } + _yCenterNode->addChangeListener(_forceUpdateListener.get()); + // 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"); @@ -398,15 +529,9 @@ NavDisplay::init () // no mipmap or else alpha will mix with pixels on the border of shapes, ruining the effect _symbolTexture = SGLoadTexture2D(tpath, NULL, false, false); - FGInstrumentMgr *imgr = (FGInstrumentMgr *)globals->get_subsystem("instrumentation"); - _odg = (FGODGauge *)imgr->get_subsystem("od_gauge"); + _odg = new FGODGauge; _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); - _route = static_cast(globals->get_subsystem("route-manager")); _navRadio1Node = fgGetNode("/instrumentation/nav[0]", true); @@ -414,7 +539,10 @@ NavDisplay::init () _excessDataNode = _Instrument->getChild("excess-data", 0, true); _excessDataNode->setBoolValue(false); + _testModeNode = _Instrument->getChild("test-mode", 0, true); + _testModeNode->setBoolValue(false); + _viewHeadingNode = _Instrument->getChild("view-heading-deg", 0, true); // OSG geometry setup _radarGeode = new osg::Geode; @@ -423,7 +551,8 @@ NavDisplay::init () osg::StateSet *stateSet = _geom->getOrCreateStateSet(); stateSet->setTextureAttributeAndModes(0, _symbolTexture.get()); - + stateSet->setDataVariance(osg::Object::STATIC); + // Initially allocate space for 128 quads _vertices = new osg::Vec2Array; _vertices->setDataVariance(osg::Object::DYNAMIC); @@ -502,34 +631,62 @@ NavDisplay::update (double delta_time_sec) return; } - _time += delta_time_sec; - if (_time < _updateInterval){ - return; + if (_forceUpdate) { + _forceUpdate = false; + _time = 0.0; + } else { + _time += delta_time_sec; + if (_time < _updateInterval){ + return; + } + _time -= _updateInterval; } - _time -= _updateInterval; - _rangeNm = _Instrument->getFloatValue("range", 40.0); - if (_Instrument->getBoolValue("aircraft-heading-up", true)) { + _rangeNm = _rangeNode->getFloatValue(); + if (_testModeNode->getBoolValue()) { + _view_heading = 90; + } else if (_Instrument->getBoolValue("aircraft-heading-up", true)) { _view_heading = fgGetDouble("/orientation/heading-deg"); } else { _view_heading = _Instrument->getFloatValue("heading-up-deg", 0.0); } + _viewHeadingNode->setDoubleValue(_view_heading); + + double xCenterFrac = _xCenterNode->getDoubleValue(); + double yCenterFrac = _yCenterNode->getDoubleValue(); + int pixelSize = _odg->size(); + + int rangePixels = _Instrument->getIntValue("range-pixels", -1); + if (rangePixels < 0) { + // hacky - assume (as is very common) that x-frac doesn't vary, and + // y-frac is used to position the center at either the top or bottom of + // the pixel area. Measure from the center to the furthest edge (top or bottom) + rangePixels = pixelSize * std::max(fabs(1.0 - yCenterFrac), fabs(yCenterFrac)); + } + + _scale = rangePixels / _rangeNm; + _Instrument->setDoubleValue("scale", _scale); - _scale = _odg->size() / _rangeNm; - double xCenterFrac = _Instrument->getDoubleValue("x-center", 0.5); - double yCenterFrac = _Instrument->getDoubleValue("y-center", 0.5); - _centerTrans = osg::Matrixf::translate(xCenterFrac * _odg->size(), - yCenterFrac * _odg->size(), 0.0); + _centerTrans = osg::Matrixf::translate(xCenterFrac * pixelSize, + yCenterFrac * pixelSize, 0.0); // scale from nm to display units, rotate so aircraft heading is up // (as opposed to north), and compensate for centering _projectMat = osg::Matrixf::scale(_scale, _scale, 1.0) * degRotation(-_view_heading) * _centerTrans; - _pos = SGGeod::fromDegFt(_user_lon_node->getDoubleValue(), - _user_lat_node->getDoubleValue(), - _user_alt_node->getDoubleValue()); + _pos = globals->get_aircraft_position(); + + // invalidate the cache of positioned items, if we travelled more than 1nm + if (_cachedItemsValid) { + SGVec3d cartNow(SGVec3d::fromGeod(_pos)); + double movedNm = dist(_cachedPos, cartNow) * SG_METER_TO_NM; + _cachedItemsValid = (movedNm < 1.0); + if (!_cachedItemsValid) { + SG_LOG(SG_INSTR, SG_INFO, "invalidating NavDisplay cache due to moving: " << movedNm); + } + } _vertices->clear(); _lineVertices->clear(); @@ -538,19 +695,25 @@ NavDisplay::update (double delta_time_sec) _texCoords->clear(); _textGeode->removeDrawables(0, _textGeode->getNumDrawables()); - BOOST_FOREACH(SymbolDef* def, _rules) { - if (def->enable) { - def->enabled = def->enable->test(); - } else { - def->enabled = true; - } + BOOST_FOREACH(SymbolInstance* si, _symbols) { + delete si; + } + _symbols.clear(); + + BOOST_FOREACH(SymbolRule* r, _rules) { + r->checkEnabled(); } - processRoute(); - processNavRadios(); - processAI(); - findItems(); - limitDisplayedSymbols(); + if (_testModeNode->getBoolValue()) { + addTestSymbols(); + } else { + processRoute(); + processNavRadios(); + processAI(); + findItems(); + limitDisplayedSymbols(); + } + addSymbolsToScene(); _symbolPrimSet->set(osg::PrimitiveSet::QUADS, 0, _vertices->size()); @@ -605,7 +768,7 @@ void NavDisplay::addSymbolToScene(SymbolInstance* sym) verts[3] = osg::Vec2(def->xy0.x(), def->xy1.y()); if (def->rotateToHeading) { - osg::Matrixf m(degRotation(sym->headingDeg)); + osg::Matrixf m(degRotation(sym->headingDeg - _view_heading)); for (int i=0; i<4; ++i) { verts[i] = mult(verts[i], m); } @@ -633,7 +796,7 @@ void NavDisplay::addSymbolToScene(SymbolInstance* sym) stretchVerts[2] = osg::Vec2(def->xy1.x(), def->stretchY3); stretchVerts[3] = osg::Vec2(def->xy0.x(), def->stretchY3); - osg::Matrixf m(degRotation(sym->headingDeg)); + osg::Matrixf m(degRotation(sym->headingDeg - _view_heading)); for (int i=0; i<4; ++i) { stretchVerts[i] = mult(stretchVerts[i], m); } @@ -787,15 +950,17 @@ public: void NavDisplay::findItems() { - Filter filt; - filt.minRunwayLengthFt = 2000; - - FGPositioned::List items = - FGPositioned::findWithinRange(_pos, _rangeNm, &filt); - - FGPositioned::List::const_iterator it; - for (it = items.begin(); it != items.end(); ++it) { - foundPositionedItem(*it); + if (!_cachedItemsValid) { + SG_LOG(SG_INSTR, SG_INFO, "re-validating NavDisplay cache"); + Filter filt; + filt.minRunwayLengthFt = 2000; + _itemsInRange = FGPositioned::findWithinRange(_pos, _rangeNm, &filt); + _cachedItemsValid = true; + _cachedPos = SGVec3d::fromGeod(_pos); + } + + BOOST_FOREACH(FGPositioned* pos, _itemsInRange) { + foundPositionedItem(pos); } } @@ -828,7 +993,7 @@ void NavDisplay::processRoute() state.insert("next-wp"); } - SymbolDefVector rules; + SymbolRuleVector rules; findRules("waypoint" , state, rules); if (rules.empty()) { return; // no rules matched, we can skip this item @@ -840,16 +1005,16 @@ void NavDisplay::processRoute() computeWayptPropsAndHeading(wpt, g, vars, heading); osg::Vec2 projected = projectGeod(g); - BOOST_FOREACH(SymbolDef* r, rules) { - addSymbolInstance(projected, heading, r, vars); + BOOST_FOREACH(SymbolRule* r, rules) { + addSymbolInstance(projected, heading, r->getDefinition(), vars); - if (r->drawRouteLeg) { + if (r->getDefinition()->drawRouteLeg) { SGGeodVec gv(path.pathForIndex(w)); if (!gv.empty()) { osg::Vec2 pr = projectGeod(gv[0]); for (unsigned int i=1; ilineColor); + addLine(pr, p, r->getDefinition()->lineColor); pr = p; } } @@ -892,7 +1057,7 @@ FGNavRecord* NavDisplay::processNavRadio(const SGPropertyNode_ptr& radio) bool NavDisplay::anyRuleForType(const string& type) const { - BOOST_FOREACH(SymbolDef* r, _rules) { + BOOST_FOREACH(SymbolRule* r, _rules) { if (!r->enabled) { continue; } @@ -907,7 +1072,7 @@ bool NavDisplay::anyRuleForType(const string& type) const bool NavDisplay::anyRuleMatches(const string& type, const string_set& states) const { - BOOST_FOREACH(SymbolDef* r, _rules) { + BOOST_FOREACH(SymbolRule* r, _rules) { if (!r->enabled || (r->type != type)) { continue; } @@ -920,9 +1085,9 @@ bool NavDisplay::anyRuleMatches(const string& type, const string_set& states) co return false; } -void NavDisplay::findRules(const string& type, const string_set& states, SymbolDefVector& rules) +void NavDisplay::findRules(const string& type, const string_set& states, SymbolRuleVector& rules) { - BOOST_FOREACH(SymbolDef* candidate, _rules) { + BOOST_FOREACH(SymbolRule* candidate, _rules) { if (!candidate->enabled || (candidate->type != type)) { continue; } @@ -940,6 +1105,7 @@ void NavDisplay::foundPositionedItem(FGPositioned* pos) } string type = FGPositioned::nameForType(pos->type()); + //boost::to_lower(type); if (!anyRuleForType(type)) { return; // not diplayed at all, we're done } @@ -947,7 +1113,7 @@ void NavDisplay::foundPositionedItem(FGPositioned* pos) string_set states; computePositionedState(pos, states); - SymbolDefVector rules; + SymbolRuleVector rules; findRules(type, states, rules); if (rules.empty()) { return; // no rules matched, we can skip this item @@ -958,8 +1124,17 @@ void NavDisplay::foundPositionedItem(FGPositioned* pos) computePositionedPropsAndHeading(pos, vars, heading); osg::Vec2 projected = projectGeod(pos->geod()); - BOOST_FOREACH(SymbolDef* r, rules) { - addSymbolInstance(projected, heading, r, vars); + if (pos->type() == FGPositioned::RUNWAY) { + FGRunway* rwy = (FGRunway*) pos; + projected = projectGeod(rwy->threshold()); + } + + BOOST_FOREACH(SymbolRule* r, rules) { + SymbolInstance* ins = addSymbolInstance(projected, heading, r->getDefinition(), vars); + if (pos->type() == FGPositioned::RUNWAY) { + FGRunway* rwy = (FGRunway*) pos; + ins->endPos = projectGeod(rwy->end()); + } } } @@ -969,6 +1144,7 @@ void NavDisplay::computePositionedPropsAndHeading(FGPositioned* pos, SGPropertyN nd->setStringValue("name", pos->name()); nd->setDoubleValue("elevation-ft", pos->elevation()); nd->setIntValue("heading-deg", 0); + heading = 0.0; switch (pos->type()) { case FGPositioned::VOR: @@ -978,11 +1154,12 @@ void NavDisplay::computePositionedPropsAndHeading(FGPositioned* pos, SGPropertyN nd->setDoubleValue("frequency-mhz", nav->get_freq()); if (pos == _nav1Station) { - nd->setIntValue("heading-deg", _navRadio1Node->getDoubleValue("radials/target-radial-deg")); + heading = _navRadio1Node->getDoubleValue("radials/target-radial-deg"); } else if (pos == _nav2Station) { - nd->setIntValue("heading-deg", _navRadio2Node->getDoubleValue("radials/target-radial-deg")); + heading = _navRadio2Node->getDoubleValue("radials/target-radial-deg"); } + nd->setIntValue("heading-deg", heading); break; } @@ -994,7 +1171,8 @@ void NavDisplay::computePositionedPropsAndHeading(FGPositioned* pos, SGPropertyN case FGPositioned::RUNWAY: { FGRunway* rwy = static_cast(pos); - nd->setDoubleValue("heading-deg", rwy->headingDeg()); + heading = rwy->headingDeg(); + nd->setDoubleValue("heading-deg", heading); nd->setIntValue("length-ft", rwy->lengthFt()); nd->setStringValue("airport", rwy->airport()->ident()); break; @@ -1068,6 +1246,16 @@ void NavDisplay::computePositionedState(FGPositioned* pos, string_set& states) } // FGPositioned::Type switch } +static string mapAINodeToType(SGPropertyNode* model) +{ + // assume all multiplayer items are aircraft for the moment. Not ideal. + if (!strcmp(model->getName(), "multiplayer")) { + return "ai-aircraft"; + } + + return string("ai-") + model->getName(); +} + void NavDisplay::processAI() { SGPropertyNode *ai = fgGetNode("/ai/models", true); @@ -1081,8 +1269,8 @@ void NavDisplay::processAI() // with fg-positioned. string_set ss; computeAIStates(model, ss); - SymbolDefVector rules; - findRules(string("ai-") + model->getName(), ss, rules); + SymbolRuleVector rules; + findRules(mapAINodeToType(model), ss, rules); if (rules.empty()) { return; // no rules matched, we can skip this item } @@ -1096,8 +1284,8 @@ void NavDisplay::processAI() model->setIntValue("flight-level", fl * 10); osg::Vec2 projected = projectGeod(aiModelPos); - BOOST_FOREACH(SymbolDef* r, rules) { - addSymbolInstance(projected, heading, r, (SGPropertyNode*) model); + BOOST_FOREACH(SymbolRule* r, rules) { + addSymbolInstance(projected, heading, r->getDefinition(), (SGPropertyNode*) model); } } // of ai models iteration } @@ -1105,11 +1293,15 @@ void NavDisplay::processAI() void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states) { int threatLevel = ai->getIntValue("tcas/threat-level",-1); - if (threatLevel >= 0) { - states.insert("tcas"); - // states.insert("tcas-threat-level-" + itoa(threatLevel)); - } - + if (threatLevel < 1) + threatLevel = 0; + + states.insert("tcas"); + + std::ostringstream os; + os << "tcas-threat-level-" << threatLevel; + states.insert(os.str()); + double vspeed = ai->getDoubleValue("velocities/vertical-speed-fps"); if (vspeed < -3.0) { states.insert("descending"); @@ -1118,11 +1310,79 @@ void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states) } } -void NavDisplay::addSymbolInstance(const osg::Vec2& proj, double heading, SymbolDef* def, SGPropertyNode* vars) +SymbolInstance* NavDisplay::addSymbolInstance(const osg::Vec2& proj, double heading, SymbolDef* def, SGPropertyNode* vars) { + if (isProjectedClipped(proj)) { + return NULL; + } + SymbolInstance* sym = new SymbolInstance(proj, heading, def, vars); _symbols.push_back(sym); + return sym; +} + +bool NavDisplay::isProjectedClipped(const osg::Vec2& projected) const +{ + double size = _odg->size(); + return (projected.x() < 0.0) || + (projected.y() < 0.0) || + (projected.x() >= size) || + (projected.y() >= size); +} + +void NavDisplay::addTestSymbol(const std::string& type, const std::string& states, const SGGeod& pos, double heading, SGPropertyNode* vars) +{ + string_set stateSet; + BOOST_FOREACH(std::string s, simgear::strutils::split(states, ",")) { + stateSet.insert(s); + } + + SymbolRuleVector rules; + findRules(type, stateSet, rules); + if (rules.empty()) { + return; // no rules matched, we can skip this item + } + + osg::Vec2 projected = projectGeod(pos); + BOOST_FOREACH(SymbolRule* r, rules) { + addSymbolInstance(projected, heading, r->getDefinition(), vars); + } } +void NavDisplay::addTestSymbols() +{ + _pos = SGGeod::fromDeg(-122.3748889, 37.6189722); // KSFO + + SGGeod a1; + double dummy; + SGGeodesy::direct(_pos, 45.0, 20.0 * SG_NM_TO_METER, a1, dummy); + + addTestSymbol("airport", "", a1, 0.0, NULL); + + SGGeodesy::direct(_pos, 95.0, 40.0 * SG_NM_TO_METER, a1, dummy); + + addTestSymbol("vor", "", a1, 0.0, NULL); + + SGGeodesy::direct(_pos, 120, 80.0 * SG_NM_TO_METER, a1, dummy); + + addTestSymbol("airport", "destination", a1, 0.0, NULL); + + SGGeodesy::direct(_pos, 80.0, 20.0 * SG_NM_TO_METER, a1, dummy); + addTestSymbol("fix", "", a1, 0.0, NULL); + + + SGGeodesy::direct(_pos, 140.0, 20.0 * SG_NM_TO_METER, a1, dummy); + addTestSymbol("fix", "", a1, 0.0, NULL); + + SGGeodesy::direct(_pos, 110.0, 10.0 * SG_NM_TO_METER, a1, dummy); + addTestSymbol("fix", "", a1, 0.0, NULL); + + SGGeodesy::direct(_pos, 110.0, 5.0 * SG_NM_TO_METER, a1, dummy); + addTestSymbol("fix", "", a1, 0.0, NULL); +} +void NavDisplay::addRule(SymbolRule* r) +{ + _rules.push_back(r); +}