NavDisplay* _nd;
};
+class NavDisplay::ForceUpdateListener : public SGPropertyChangeListener
+{
+public:
+ ForceUpdateListener(NavDisplay *nd) :
+ _nd(nd)
+ {}
+
+ virtual void valueChanged (SGPropertyNode * prop)
+ {
+ SG_LOG(SG_INSTR, SG_INFO, "forcing NavDisplay update");
+ _nd->forceUpdate();
+ }
+private:
+ NavDisplay* _nd;
+};
+
///////////////////////////////////////////////////////////////////
class SymbolDef
enable(NULL)
{}
- bool initFromNode(SGPropertyNode* node)
+ bool initFromNode(SGPropertyNode* node, NavDisplay* owner)
{
type = node->getStringValue("type");
SGPropertyNode* enableNode = node->getChild("enable");
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;
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;
_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),
INITFONT("color/alpha", 1, Float);
#undef INITFONT
+ _textureSize = _Instrument->getNode("symbol-teture-size", true)->getIntValue();
SGPropertyNode* symbolsNode = node->getNode("symbols");
SGPropertyNode* symbol;
-
+
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;
}
{
_cachedItemsValid = false;
_cacheListener.reset(new CacheListener(this));
-
+ _forceUpdateListener.reset(new ForceUpdateListener(this));
+
_serviceable_node = _Instrument->getNode("serviceable", true);
_rangeNode = _Instrument->getNode("range", true);
_rangeNode->setDoubleValue(40.0);
_rangeNode->addChangeListener(_cacheListener.get());
-
+ _rangeNode->addChangeListener(_forceUpdateListener.get());
+
+ _xCenterNode = _Instrument->getNode("x-center");
+ _xCenterNode->setDoubleValue(0.5);
+ _xCenterNode->addChangeListener(_forceUpdateListener.get());
+ _yCenterNode = _Instrument->getNode("y-center");
+ _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");
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 = _rangeNode->getFloatValue();
if (_testModeNode->getBoolValue()) {
_view_heading = _Instrument->getFloatValue("heading-up-deg", 0.0);
}
- double xCenterFrac = _Instrument->getDoubleValue("x-center", 0.5);
- double yCenterFrac = _Instrument->getDoubleValue("y-center", 0.5);
+ double xCenterFrac = _xCenterNode->getDoubleValue();
+ double yCenterFrac = _yCenterNode->getDoubleValue();
int pixelSize = _odg->size();
int rangePixels = _Instrument->getIntValue("range-pixels", -1);
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);
}
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);
}
computePositionedPropsAndHeading(pos, vars, heading);
osg::Vec2 projected = projectGeod(pos->geod());
+ if (pos->type() == FGPositioned::RUNWAY) {
+ FGRunway* rwy = (FGRunway*) pos;
+ projected = projectGeod(rwy->threshold());
+ }
+
BOOST_FOREACH(SymbolDef* r, rules) {
- addSymbolInstance(projected, heading, r, vars);
+ SymbolInstance* ins = addSymbolInstance(projected, heading, r, vars);
+ if (pos->type() == FGPositioned::RUNWAY) {
+ FGRunway* rwy = (FGRunway*) pos;
+ ins->endPos = projectGeod(rwy->end());
+ }
}
}
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:
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;
}
case FGPositioned::RUNWAY: {
FGRunway* rwy = static_cast<FGRunway*>(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;
} // 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);
string_set ss;
computeAIStates(model, ss);
SymbolDefVector rules;
- findRules(string("ai-") + model->getName(), ss, rules);
+ findRules(mapAINodeToType(model), ss, rules);
if (rules.empty()) {
return; // no rules matched, we can skip this item
}
void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states)
{
int threatLevel = ai->getIntValue("tcas/threat-level",-1);
- if (threatLevel >= 0) {
- states.insert("tcas");
-
- std::ostringstream os;
- os << "tcas-threat-level-" << threatLevel;
- states.insert(os.str());
- }
-
+ 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");
}
}
-bool 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 false;
+ return NULL;
}
SymbolInstance* sym = new SymbolInstance(proj, heading, def, vars);
_symbols.push_back(sym);
- return true;
+ return sym;
}
bool NavDisplay::isProjectedClipped(const osg::Vec2& projected) const