return osg::Vec2(r.x(), r.y());
}
+class NavDisplay::CacheListener : public SGPropertyChangeListener
+{
+public:
+ 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 SymbolDef
}
} // of matches parsing
- xy0.x() = node->getFloatValue("x0", -5);
- xy0.y() = node->getFloatValue("y0", -5);
+ 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);
uv0.x() = node->getFloatValue("u0", 0) / texSize;
drawLine = node->getBoolValue("draw-line", false);
lineColor = readColor(node->getChild("line-color"), color);
- drawRouteLeg = node->getBoolValue("draw-line", false);
+ drawRouteLeg = node->getBoolValue("draw-leg", false);
stretchSymbol = node->getBoolValue("stretch-symbol", false);
if (stretchSymbol) {
bool matches(const string_set& states) const
{
- string_set::const_iterator it = states.begin(),
- end = states.end();
- for (; it != end; ++it) {
- if (!required_states.empty() && (required_states.count(*it) == 0)) {
- // required state not matched
+ BOOST_FOREACH(const string& s, required_states) {
+ if (states.count(s) == 0) {
return false;
}
-
- if (excluded_states.count(*it) > 0) {
- // excluded state matched
+ }
+
+ BOOST_FOREACH(const string& s, excluded_states) {
+ if (states.count(s) != 0) {
return false;
}
- } // of applicable states iteration
-
- return true; // matches!
+ }
+
+ return true;
}
};
string text() const
{
assert(definition->hasText);
- string r;
-
- size_t pos = 0;
- int lastPos = 0;
+ string r;
+ size_t lastPos = 0;
- for (; pos < definition->textTemplate.size();) {
- pos = definition->textTemplate.find('{', pos);
- if (pos == string::npos) { // no more replacements
+ while (true) {
+ size_t pos = definition->textTemplate.find('{', lastPos);
+ if (pos == string::npos) { // no more replacements
r.append(definition->textTemplate.substr(lastPos));
break;
}
string spec = definition->textTemplate.substr(pos + 1, endReplacement - (pos + 1));
// look for formatter in spec
size_t colonPos = spec.find(':');
- if (colonPos == string::npos) {
+ if (colonPos == string::npos) {
// simple replacement
r.append(props->getStringValue(spec));
} else {
void
NavDisplay::init ()
{
+ _cachedItemsValid = false;
+ _cacheListener.reset(new CacheListener(this));
+
_serviceable_node = _Instrument->getNode("serviceable", true);
-
+ _rangeNode = _Instrument->getNode("range", true);
+ _rangeNode->setDoubleValue(40.0);
+ _rangeNode->addChangeListener(_cacheListener.get());
+
// texture name to use in 2D and 3D instruments
_texture_path = _Instrument->getStringValue("radar-texture-path",
"Aircraft/Instruments/Textures/od_wxradar.rgb");
string path = _Instrument->getStringValue("symbol-texture-path",
"Aircraft/Instruments/Textures/nd-symbols.png");
SGPath tpath = globals->resolve_aircraft_path(path);
-
+ if (!tpath.exists()) {
+ SG_LOG(SG_INSTR, SG_WARN, "ND symbol texture not found:" << path);
+ }
+
// no mipmap or else alpha will mix with pixels on the border of shapes, ruining the effect
_symbolTexture = SGLoadTexture2D(tpath, NULL, false, false);
_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);
-
_route = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
_navRadio1Node = fgGetNode("/instrumentation/nav[0]", true);
_geom->setTexCoordArray(0, _texCoords);
_quadColors = new osg::Vec4Array;
+ _quadColors->setDataVariance(osg::Object::DYNAMIC);
_geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
_geom->setColorArray(_quadColors);
_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
}
_time -= _updateInterval;
- _rangeNm = _Instrument->getFloatValue("range", 40.0);
+ _rangeNm = _rangeNode->getFloatValue();
if (_Instrument->getBoolValue("aircraft-heading-up", true)) {
_view_heading = fgGetDouble("/orientation/heading-deg");
} else {
_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();
_lineColors->clear();
+ _quadColors->clear();
_texCoords->clear();
_textGeode->removeDrawables(0, _textGeode->getNumDrawables());
+ BOOST_FOREACH(SymbolInstance* si, _symbols) {
+ delete si;
+ }
+ _symbols.clear();
+
BOOST_FOREACH(SymbolDef* def, _rules) {
if (def->enable) {
def->enabled = def->enable->test();
_texCoords->push_back(osg::Vec2(def->uv1.x(), def->uv0.y()));
_texCoords->push_back(def->uv1);
_texCoords->push_back(osg::Vec2(def->uv0.x(), def->uv1.y()));
-
+
for (int i=0; i<4; ++i) {
_vertices->push_back(verts[i] + pos);
_quadColors->push_back(def->color);
class Filter : public FGPositioned::Filter
{
public:
+ double minRunwayLengthFt;
+
virtual bool pass(FGPositioned* aPos) const
{
if (aPos->type() == FGPositioned::FIX) {
}
}
+ if (aPos->type() == FGPositioned::AIRPORT) {
+ FGAirport* apt = (FGAirport*) aPos;
+ if (!apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) {
+ return false;
+ }
+ }
+
return true;
}
void NavDisplay::findItems()
{
- Filter filt;
- 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);
}
}
switch (pos->type()) {
case FGPositioned::VOR:
- case FGPositioned::LOC: {
+ case FGPositioned::LOC:
+ case FGPositioned::TACAN: {
FGNavRecord* nav = static_cast<FGNavRecord*>(pos);
nd->setDoubleValue("frequency-mhz", nav->get_freq());
}
}
-void NavDisplay::addSymbolInstance(const osg::Vec2& proj, double heading, SymbolDef* def, SGPropertyNode* vars)
+bool NavDisplay::addSymbolInstance(const osg::Vec2& proj, double heading, SymbolDef* def, SGPropertyNode* vars)
{
+ if (isProjectedClipped(proj)) {
+ return false;
+ }
+
SymbolInstance* sym = new SymbolInstance(proj, heading, def, vars);
_symbols.push_back(sym);
+ return true;
}
+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);
+}
+
+