]> git.mxchange.org Git - flightgear.git/blobdiff - src/Instrumentation/NavDisplay.cxx
Merge branch 'next' of git://gitorious.org/fg/flightgear into next
[flightgear.git] / src / Instrumentation / NavDisplay.cxx
index 164fb40fd903eafbddb1a32f6336f9a5389e7ad8..4cc9d5b3b1ce28dfba986a4a0b8a750c5afbaad1 100644 (file)
@@ -124,12 +124,12 @@ static string formatPropertyValue(SGPropertyNode* nd, const string& format)
 {
     assert(nd);
     static char buf[512];
-    if (format.find('d') >= 0) {
+    if (format.find('d') != string::npos) {
         ::snprintf(buf, 512, format.c_str(), nd->getIntValue());
         return buf;
     }
     
-    if (format.find('s') >= 0) {
+    if (format.find('s') != string::npos) {
         ::snprintf(buf, 512, format.c_str(), nd->getStringValue());
         return buf;
     }
@@ -145,15 +145,39 @@ static osg::Vec2 mult(const osg::Vec2& v, const osg::Matrixf& m)
     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
 {
 public:
-    void initFromNode(SGPropertyNode* node)
+  SymbolDef() :
+      enable(NULL)
+    {}
+  
+    bool initFromNode(SGPropertyNode* node)
     {
         type = node->getStringValue("type");
-        enable = sgReadCondition(fgGetNode("/"), node->getChild("enable"));
+        SGPropertyNode* enableNode = node->getChild("enable");
+        if (enableNode) { 
+            enable = sgReadCondition(fgGetNode("/"), enableNode);
+        }
+      
         int n=0;
         while (node->hasChild("state", n)) {
             string m = node->getChild("state", n++)->getStringValue();
@@ -164,11 +188,20 @@ public:
             }
         } // 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;
@@ -193,7 +226,7 @@ public:
         
         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) {
@@ -202,6 +235,8 @@ public:
             stretchV2 = node->getFloatValue("v2");
             stretchV3 = node->getFloatValue("v3");
         }
+      
+        return true;
     }
     
     SGCondition* enable;
@@ -240,21 +275,19 @@ public:
     
     bool matches(const string_set& states) const
     {
-        string_set::const_iterator it = states.begin(),
-            end = states.end();
-        for (; it != end; ++it) {
-            if (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;
     }
 };
 
@@ -277,29 +310,27 @@ public:
     string text() const
     {
         assert(definition->hasText);
-        string r;
-        
-        int pos = 0;
-        int lastPos = 0;
+        string r;        
+        size_t lastPos = 0;
         
-        for (; pos < (int) definition->textTemplate.size();) {
-            pos = definition->textTemplate.find('{', pos);
-            if (pos == -1) { // 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;
             }
             
             r.append(definition->textTemplate.substr(lastPos, pos - lastPos));
             
-            int endReplacement = definition->textTemplate.find('}', pos+1);
+            size_t endReplacement = definition->textTemplate.find('}', pos+1);
             if (endReplacement <= pos) {
                 return "bad replacement";
             }
 
             string spec = definition->textTemplate.substr(pos + 1, endReplacement - (pos + 1));
         // look for formatter in spec
-            int colonPos = spec.find(':');
-            if (colonPos < 0) {
+            size_t colonPos = spec.find(':');
+            if (colonPos == string::npos) {
             // simple replacement
                 r.append(props->getStringValue(spec));
             } else {
@@ -343,6 +374,18 @@ NavDisplay::NavDisplay(SGPropertyNode *node) :
     INITFONT("color/alpha", 1, Float);
 #undef INITFONT
 
+    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)) {
+          delete def;
+          continue;
+        }
+        
+        _rules.push_back(def);
+    } // of symbol definition parsing
 }
 
 
@@ -354,8 +397,14 @@ NavDisplay::~NavDisplay()
 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");
@@ -364,7 +413,10 @@ NavDisplay::init ()
     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);
 
@@ -372,16 +424,14 @@ NavDisplay::init ()
     _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);
     _navRadio2Node = fgGetNode("/instrumentation/nav[1]", true);
     
+    _excessDataNode = _Instrument->getChild("excess-data", 0, true);
+    _excessDataNode->setBoolValue(false);
+  
 // OSG geometry setup
     _radarGeode = new osg::Geode;
 
@@ -402,6 +452,7 @@ NavDisplay::init ()
     _geom->setTexCoordArray(0, _texCoords);
     
     _quadColors = new osg::Vec4Array;
+    _quadColors->setDataVariance(osg::Object::DYNAMIC);
     _geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
     _geom->setColorArray(_quadColors);
     
@@ -411,6 +462,7 @@ NavDisplay::init ()
     
     _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
@@ -473,7 +525,7 @@ NavDisplay::update (double delta_time_sec)
   }
   _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 {
@@ -492,18 +544,36 @@ NavDisplay::update (double delta_time_sec)
   _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();
+    } else {
+      def->enabled = true;
+    }
   }
   
   processRoute();
@@ -542,12 +612,8 @@ NavDisplay::updateFont()
         tpath = path;
     }
 
-#if (FG_OSG_VERSION >= 21000)
     osg::ref_ptr<osgDB::ReaderWriter::Options> fontOptions = new osgDB::ReaderWriter::Options("monochrome");
     osg::ref_ptr<osgText::Font> font = osgText::readFontFile(tpath.c_str(), fontOptions.get());
-#else
-    osg::ref_ptr<osgText::Font> font = osgText::readFontFile(tpath.c_str());
-#endif
 
     if (font != 0) {
         _font = font;
@@ -584,7 +650,7 @@ void NavDisplay::addSymbolToScene(SymbolInstance* sym)
     _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);
@@ -664,7 +730,7 @@ public:
 
 void NavDisplay::limitDisplayedSymbols()
 {
-    unsigned int maxSymbols = _Instrument->getIntValue("max-symbols");
+    unsigned int maxSymbols = _Instrument->getIntValue("max-symbols", 100);
     if (_symbols.size() <= maxSymbols) {
         _excessDataNode->setBoolValue(false);
         return;
@@ -718,6 +784,8 @@ osg::Vec2 NavDisplay::projectGeod(const SGGeod& geod) const
 class Filter : public FGPositioned::Filter
 {
 public:
+    double minRunwayLengthFt;
+  
     virtual bool pass(FGPositioned* aPos) const
     {
         if (aPos->type() == FGPositioned::FIX) {
@@ -728,6 +796,13 @@ public:
             }
         }
 
+        if (aPos->type() == FGPositioned::AIRPORT) {
+          FGAirport* apt = (FGAirport*) aPos;
+          if (!apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) {
+            return false;
+          }
+        }
+      
         return true;
     }
 
@@ -742,13 +817,17 @@ public:
 
 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);
     }
 }
 
@@ -782,7 +861,7 @@ void NavDisplay::processRoute()
         }
         
         SymbolDefVector rules;
-        findRules(wpt->type() , state, rules);
+        findRules("waypoint" , state, rules);
         if (rules.empty()) {
             return; // no rules matched, we can skip this item
         }
@@ -876,7 +955,7 @@ bool NavDisplay::anyRuleMatches(const string& type, const string_set& states) co
 void NavDisplay::findRules(const string& type, const string_set& states, SymbolDefVector& rules)
 {
     BOOST_FOREACH(SymbolDef* candidate, _rules) {
-        if (!candidate->enabled) {
+        if (!candidate->enabled || (candidate->type != type)) {
             continue;
         }
         
@@ -925,7 +1004,8 @@ void NavDisplay::computePositionedPropsAndHeading(FGPositioned* pos, SGPropertyN
     
     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());
         
@@ -1070,11 +1150,26 @@ void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states)
     }
 }
 
-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);
 }
 
 
 
+