The following commit has been merged in the master branch:
commit ad955e26bf9fe7281c286c18b3b41fde6846b3bd
Author: Martin Dobias <wonder...@gmail.com>
Date:   Fri Mar 2 00:06:02 2012 +0100

    Added willRenderFeature() and symbolsForFeature() utility methods.

diff --git a/python/core/symbology-ng-core.sip 
b/python/core/symbology-ng-core.sip
index 6e3784e..a1b25e8 100644
--- a/python/core/symbology-ng-core.sip
+++ b/python/core/symbology-ng-core.sip
@@ -77,6 +77,17 @@ public:
 
   virtual QString dump();
 
+  enum Capabilities
+  {
+    SymbolLevels = 1,     // rendering with symbol levels (i.e. implements 
symbols(), symbolForFeature())
+    RotationField = 2,    // rotate symbols by attribute value
+    MoreSymbolsPerFeature = 4  // may use more than one symbol to render a 
feature: symbolsForFeature() will return them
+  };
+
+  //! returns bitwise OR-ed capabilities of the renderer
+  //! \note added in 2.0
+  virtual int capabilities();
+
   virtual QgsFeatureRendererV2* clone()=0 /Factory/;
 
   virtual QgsSymbolV2List symbols()=0;
@@ -105,6 +116,18 @@ public:
   //! @note added in 1.9
   virtual void setRotationField( QString fieldName );
 
+  //! return whether the renderer will render a feature or not.
+  //! Must be called between startRender() and stopRender() calls.
+  //! Default implementation uses symbolForFeature().
+  //! @note added in 1.9
+  virtual bool willRenderFeature( QgsFeature& feat );
+
+  //! return list of symbols used for rendering the feature.
+  //! For renderers that do not support MoreSymbolsPerFeature it is more 
efficient
+  //! to use symbolForFeature()
+  //! @note added in 1.9
+  virtual QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
+
 protected:
   QgsFeatureRendererV2(QString type);
 
@@ -154,6 +177,10 @@ public:
 
   virtual QString dump();
 
+  //! returns bitwise OR-ed capabilities of the renderer
+  //! \note added in 2.0
+  virtual int capabilities();
+
   virtual QgsFeatureRendererV2* clone() /Factory/;
 
   virtual QgsSymbolV2List symbols();
@@ -221,6 +248,10 @@ public:
 
   virtual QString dump();
 
+  //! returns bitwise OR-ed capabilities of the renderer
+  //! \note added in 2.0
+  virtual int capabilities();
+
   virtual QgsFeatureRendererV2* clone() /Factory/;
 
   virtual QgsSymbolV2List symbols();
@@ -320,6 +351,10 @@ public:
 
   virtual QString dump();
 
+  //! returns bitwise OR-ed capabilities of the renderer
+  //! \note added in 2.0
+  virtual int capabilities();
+
   virtual QgsFeatureRendererV2* clone() /Factory/;
 
   virtual QgsSymbolV2List symbols();
@@ -410,27 +445,76 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
     class Rule
     {
       public:
-        //! Constructor takes ownership of the symbol
-        Rule( QgsSymbolV2* symbol /Transfer/, int scaleMinDenom = 0, int 
scaleMaxDenom = 0, QString filterExp = QString() );
-        //Rule( const QgsRuleBasedRendererV2::Rule& other );
+
+        Rule( QgsSymbolV2* symbol /Transfer/, int scaleMinDenom = 0, int 
scaleMaxDenom = 0, QString filterExp = QString(),
+              QString label = QString(), QString description = QString() );
         ~Rule();
-        QString dump() const;
-        //QStringList needsFields() const;
+        QString dump( int offset = 0 ) const;
+        QSet<QString> usedAttributes();
+        QgsSymbolV2List symbols();
+        // TODO QgsLegendSymbolList legendSymbolItems();
         bool isFilterOK( QgsFeature& f ) const;
         bool isScaleOK( double scale ) const;
 
         QgsSymbolV2* symbol();
+        QString label() const;
         bool dependsOnScale() const;
         int scaleMinDenom() const;
         int scaleMaxDenom() const;
-        QString filterExpression() const;
         QgsExpression* filter() const;
+        QString filterExpression() const;
+        QString description() const;
 
+        //! set a new symbol (or NULL). Deletes old symbol.
+        void setSymbol( QgsSymbolV2* sym /Transfer/ );
+        void setLabel( QString label );
         void setScaleMinDenom( int scaleMinDenom );
         void setScaleMaxDenom( int scaleMaxDenom );
         void setFilterExpression( QString filterExp );
+        void setDescription( QString description );
+
+        //! clone this rule, return new instance
+        QgsRuleBasedRendererV2::Rule* clone() const /Factory/;
+
+        QDomElement save( QDomDocument& doc, QgsSymbolV2Map& symbolMap );
+
+        //! prepare the rule for rendering and its children (build active 
children array)
+        bool startRender( QgsRenderContext& context, const QgsVectorLayer 
*vlayer );
+        //! get all used z-levels from this rule and children
+        QSet<int> collectZLevels();
+        //! assign normalized z-levels [0..N-1] for this rule's symbol for 
quick access during rendering
+        // TODO void setNormZLevels( const QMap<int, int>& zLevelsToNormLevels 
);
+
+        // TODO bool renderFeature( FeatureToRender& featToRender, 
QgsRenderContext& context, RenderQueue& renderQueue );
+
+        //! only tell whether a feature will be rendered without actually 
rendering it
+        //! @note added in 1.9
+        bool willRenderFeature( QgsFeature& feat );
+
+        //! tell which symbols will be used to render the feature
+        //! @note added in 1.9
+        QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
+
+        void stopRender( QgsRenderContext& context );
+
+        static QgsRuleBasedRendererV2::Rule* create( QDomElement& ruleElem, 
QgsSymbolV2Map& symbolMap ) /Factory/;
+
+        QList<QgsRuleBasedRendererV2::Rule*>& children();
+        QgsRuleBasedRendererV2::Rule* parent();
+
+        //! add child rule, take ownership, sets this as parent
+        void appendChild( QgsRuleBasedRendererV2::Rule* rule /Transfer/ );
+        //! add child rule, take ownership, sets this as parent
+        void insertChild( int i, QgsRuleBasedRendererV2::Rule* rule /Transfer/ 
);
+        //! delete child rule
+        void removeChild( QgsRuleBasedRendererV2::Rule* rule );
+        //! delete child rule
+        void removeChildAt( int i );
+        //! take child rule out, set parent as null
+        void takeChild( QgsRuleBasedRendererV2::Rule* rule );
+        //! take child rule out, set parent as null
+        QgsRuleBasedRendererV2::Rule* takeChildAt( int i );
 
-        //Rule& operator=( const Rule& other );
     };
 
     /////
@@ -453,6 +537,12 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
 
     virtual QList<QString> usedAttributes();
 
+    virtual QString dump();
+
+    //! returns bitwise OR-ed capabilities of the renderer
+    //! \note added in 2.0
+    virtual int capabilities();
+
     virtual QgsFeatureRendererV2* clone() /Factory/;
 
     virtual QgsSymbolV2List symbols();
@@ -463,6 +553,17 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
     //! return a list of symbology items for the legend 
     virtual QgsLegendSymbologyList legendSymbologyItems( QSize iconSize ); 
 
+    //! return whether the renderer will render a feature or not.
+    //! Must be called between startRender() and stopRender() calls.
+    //! @note added in 1.9
+    virtual bool willRenderFeature( QgsFeature& feat );
+
+    //! return list of symbols used for rendering the feature.
+    //! For renderers that do not support MoreSymbolsPerFeature it is more 
efficient
+    //! to use symbolForFeature()
+    //! @note added in 1.9
+    virtual QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
+
     /////
 
 
diff --git a/src/core/symbology-ng/qgsrendererv2.cpp 
b/src/core/symbology-ng/qgsrendererv2.cpp
index 7f09f47..be5ab2b 100644
--- a/src/core/symbology-ng/qgsrendererv2.cpp
+++ b/src/core/symbology-ng/qgsrendererv2.cpp
@@ -417,3 +417,11 @@ void QgsFeatureRendererV2::renderVertexMarkerPolygon( 
QPolygonF& pts, QList<QPol
     }
   }
 }
+
+QgsSymbolV2List QgsFeatureRendererV2::symbolsForFeature( QgsFeature& feat )
+{
+  QgsSymbolV2List lst;
+  QgsSymbolV2* s = symbolForFeature( feat );
+  if ( s ) lst.append( s );
+  return lst;
+}
diff --git a/src/core/symbology-ng/qgsrendererv2.h 
b/src/core/symbology-ng/qgsrendererv2.h
index 7b3b45b..968e8e8 100644
--- a/src/core/symbology-ng/qgsrendererv2.h
+++ b/src/core/symbology-ng/qgsrendererv2.h
@@ -81,7 +81,8 @@ class CORE_EXPORT QgsFeatureRendererV2
     enum Capabilities
     {
       SymbolLevels = 1,     // rendering with symbol levels (i.e. implements 
symbols(), symbolForFeature())
-      RotationField = 1 <<  1    // rotate symbols by attribute value
+      RotationField = 1 <<  1,    // rotate symbols by attribute value
+      MoreSymbolsPerFeature = 1 << 2  // may use more than one symbol to 
render a feature: symbolsForFeature() will return them
     };
 
     //! returns bitwise OR-ed capabilities of the renderer
@@ -117,7 +118,17 @@ class CORE_EXPORT QgsFeatureRendererV2
     //! @note added in 1.9
     virtual void setRotationField( QString fieldName ) { Q_UNUSED( fieldName 
); }
 
+    //! return whether the renderer will render a feature or not.
+    //! Must be called between startRender() and stopRender() calls.
+    //! Default implementation uses symbolForFeature().
+    //! @note added in 1.9
+    virtual bool willRenderFeature( QgsFeature& feat ) { return 
symbolForFeature( feat ) != NULL; }
 
+    //! return list of symbols used for rendering the feature.
+    //! For renderers that do not support MoreSymbolsPerFeature it is more 
efficient
+    //! to use symbolForFeature()
+    //! @note added in 1.9
+    virtual QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
 
   protected:
     QgsFeatureRendererV2( QString type );
diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp 
b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
index 68ee914..665ec9d 100644
--- a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
+++ b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
@@ -288,6 +288,38 @@ bool QgsRuleBasedRendererV2::Rule::renderFeature( 
QgsRuleBasedRendererV2::Featur
   return rendered;
 }
 
+bool QgsRuleBasedRendererV2::Rule::willRenderFeature( QgsFeature& feat )
+{
+  if ( !isFilterOK( feat ) )
+    return false;
+  if ( mSymbol )
+    return true;
+
+  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != 
mActiveChildren.end(); ++it )
+  {
+    Rule* rule = *it;
+    if ( rule->willRenderFeature( feat ) )
+      return true;
+  }
+  return false;
+}
+
+QgsSymbolV2List QgsRuleBasedRendererV2::Rule::symbolsForFeature( QgsFeature& 
feat )
+{
+  QgsSymbolV2List lst;
+  if ( !isFilterOK( feat ) )
+    return lst;
+  if ( mSymbol )
+    lst.append( mSymbol );
+
+  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != 
mActiveChildren.end(); ++it )
+  {
+    Rule* rule = *it;
+    lst += rule->symbolsForFeature( feat );
+  }
+  return lst;
+}
+
 
 void QgsRuleBasedRendererV2::Rule::stopRender( QgsRenderContext& context )
 {
@@ -581,3 +613,13 @@ QString QgsRuleBasedRendererV2::dump()
   msg += mRootRule->dump();
   return msg;
 }
+
+bool QgsRuleBasedRendererV2::willRenderFeature( QgsFeature& feat )
+{
+  return mRootRule->willRenderFeature( feat );
+}
+
+QgsSymbolV2List QgsRuleBasedRendererV2::symbolsForFeature( QgsFeature& feat )
+{
+  return mRootRule->symbolsForFeature( feat );
+}
diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.h 
b/src/core/symbology-ng/qgsrulebasedrendererv2.h
index d3cab4e..6a773ed 100644
--- a/src/core/symbology-ng/qgsrulebasedrendererv2.h
+++ b/src/core/symbology-ng/qgsrulebasedrendererv2.h
@@ -127,6 +127,14 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public 
QgsFeatureRendererV2
 
         bool renderFeature( FeatureToRender& featToRender, QgsRenderContext& 
context, RenderQueue& renderQueue );
 
+        //! only tell whether a feature will be rendered without actually 
rendering it
+        //! @note added in 1.9
+        bool willRenderFeature( QgsFeature& feat );
+
+        //! tell which symbols will be used to render the feature
+        //! @note added in 1.9
+        QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
+
         void stopRender( QgsRenderContext& context );
 
         static Rule* create( QDomElement& ruleElem, QgsSymbolV2Map& symbolMap 
);
@@ -204,6 +212,21 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public 
QgsFeatureRendererV2
     //! for debugging
     virtual QString dump();
 
+    //! return whether the renderer will render a feature or not.
+    //! Must be called between startRender() and stopRender() calls.
+    //! @note added in 1.9
+    virtual bool willRenderFeature( QgsFeature& feat );
+
+    //! return list of symbols used for rendering the feature.
+    //! For renderers that do not support MoreSymbolsPerFeature it is more 
efficient
+    //! to use symbolForFeature()
+    //! @note added in 1.9
+    virtual QgsSymbolV2List symbolsForFeature( QgsFeature& feat );
+
+    //! returns bitwise OR-ed capabilities of the renderer
+    //! \note added in 2.0
+    virtual int capabilities() { return MoreSymbolsPerFeature; }
+
     /////
 
     Rule* rootRule() { return mRootRule; }
diff --git a/tests/src/core/testqgsrulebasedrenderer.cpp 
b/tests/src/core/testqgsrulebasedrenderer.cpp
index 206bc72..e6ca922 100644
--- a/tests/src/core/testqgsrulebasedrenderer.cpp
+++ b/tests/src/core/testqgsrulebasedrenderer.cpp
@@ -18,75 +18,128 @@
 //header for class being tested
 #include <qgsrulebasedrendererv2.h>
 
+#include <qgsapplication.h>
+#include <qgssymbolv2.h>
+#include <qgsvectorlayer.h>
+
 #if QT_VERSION < 0x40701
 // See http://hub.qgis.org/issues/4284
 Q_DECLARE_METATYPE( QVariant )
 #endif
 
+typedef QgsRuleBasedRendererV2::Rule RRule;
 
 class TestQgsRuleBasedRenderer: public QObject
 {
     Q_OBJECT
   private slots:
 
-  void test_load_xml()
-  {
-    QDomDocument doc;
-    xml2domElement( "rulebasedrenderer_simple.xml", doc );
-    QDomElement elem = doc.documentElement();
-
-    QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( 
QgsRuleBasedRendererV2::create( elem ) );
-    QVERIFY( r );
-    check_tree_valid( r->rootRule() );
-    delete r;
-  }
-
-  void test_load_invalid_xml()
-  {
-    QDomDocument doc;
-    xml2domElement( "rulebasedrenderer_invalid.xml", doc );
-    QDomElement elem = doc.documentElement();
-
-    QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( 
QgsRuleBasedRendererV2::create( elem ) );
-    QVERIFY( r == NULL );
-  }
-
-private:
-  void xml2domElement( QString testFile, QDomDocument& doc )
-  {
-    QString fileName = QString( TEST_DATA_DIR ) + QDir::separator() + testFile;
-    QFile f(fileName);
-    bool fileOpen = f.open(QIODevice::ReadOnly);
-    QVERIFY( fileOpen );
-
-    QString msg;
-    int line, col;
-    bool parse = doc.setContent( &f, &msg, &line, &col );
-    QVERIFY( parse );
-  }
-
-  void check_tree_valid( QgsRuleBasedRendererV2::Rule* root )
-  {
-    // root must always exist (although it does not have children)
-    QVERIFY( root );
-    // and does not have a parent
-    QVERIFY( root->parent() == NULL );
-
-    foreach ( QgsRuleBasedRendererV2::Rule* node, root->children() )
+    void initTestCase()
+    {
+      // we need memory provider, so make sure to load providers
+      QgsApplication::init();
+      QgsApplication::initQgis();
+    }
+
+    void test_load_xml()
+    {
+      QDomDocument doc;
+      xml2domElement( "rulebasedrenderer_simple.xml", doc );
+      QDomElement elem = doc.documentElement();
+
+      QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( 
QgsRuleBasedRendererV2::create( elem ) );
+      QVERIFY( r );
+      check_tree_valid( r->rootRule() );
+      delete r;
+    }
+
+    void test_load_invalid_xml()
+    {
+      QDomDocument doc;
+      xml2domElement( "rulebasedrenderer_invalid.xml", doc );
+      QDomElement elem = doc.documentElement();
+
+      QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( 
QgsRuleBasedRendererV2::create( elem ) );
+      QVERIFY( r == NULL );
+    }
+
+    void test_willRenderFeature_symbolsForFeature()
+    {
+      // prepare features
+      QgsVectorLayer* layer = new QgsVectorLayer( "point?field=fld:int", "x", 
"memory" );
+      int idx = layer->fieldNameIndex( "fld" );
+      QVERIFY( idx != -1 );
+      QgsFeature f1; f1.addAttribute( idx, QVariant( 2 ) );
+      QgsFeature f2; f2.addAttribute( idx, QVariant( 8 ) );
+      QgsFeature f3; f3.addAttribute( idx, QVariant( 100 ) );
+
+      // prepare renderer
+      QgsSymbolV2* s1 = QgsSymbolV2::defaultSymbol( QGis::Point );
+      QgsSymbolV2* s2 = QgsSymbolV2::defaultSymbol( QGis::Point );
+      RRule* rootRule = new RRule( NULL );
+      rootRule->appendChild( new RRule( s1, 0, 0, "fld >= 5 and fld <= 20" ) );
+      rootRule->appendChild( new RRule( s2, 0, 0, "fld <= 10" ) );
+      QgsRuleBasedRendererV2 r( rootRule );
+
+      QVERIFY( r.capabilities() & QgsFeatureRendererV2::MoreSymbolsPerFeature 
);
+
+      QgsRenderContext ctx; // dummy render context
+      r.startRender( ctx, layer );
+
+      // test willRenderFeature
+      QVERIFY( r.willRenderFeature( f1 ) == true );
+      QVERIFY( r.willRenderFeature( f2 ) == true );
+      QVERIFY( r.willRenderFeature( f3 ) == false );
+
+      // test symbolsForFeature
+      QgsSymbolV2List lst1 = r.symbolsForFeature( f1 );
+      QVERIFY( lst1.count() == 1 );
+      QgsSymbolV2List lst2 = r.symbolsForFeature( f2 );
+      QVERIFY( lst2.count() == 2 );
+      QgsSymbolV2List lst3 = r.symbolsForFeature( f3 );
+      QVERIFY( lst3.count() == 0 );
+
+      r.stopRender( ctx );
+
+      delete layer;
+    }
+
+  private:
+    void xml2domElement( QString testFile, QDomDocument& doc )
+    {
+      QString fileName = QString( TEST_DATA_DIR ) + QDir::separator() + 
testFile;
+      QFile f( fileName );
+      bool fileOpen = f.open( QIODevice::ReadOnly );
+      QVERIFY( fileOpen );
+
+      QString msg;
+      int line, col;
+      bool parse = doc.setContent( &f, &msg, &line, &col );
+      QVERIFY( parse );
+    }
+
+    void check_tree_valid( QgsRuleBasedRendererV2::Rule* root )
+    {
+      // root must always exist (although it does not have children)
+      QVERIFY( root );
+      // and does not have a parent
+      QVERIFY( root->parent() == NULL );
+
+      foreach( QgsRuleBasedRendererV2::Rule* node, root->children() )
       check_non_root_rule( node );
-  }
-
-  void check_non_root_rule( QgsRuleBasedRendererV2::Rule* node )
-  {
-    qDebug() << node->dump();
-    // children must not be NULL
-    QVERIFY( node );
-    // and must have a parent
-    QVERIFY( node->parent() );
-    // check that all children are okay
-    foreach ( QgsRuleBasedRendererV2::Rule* child, node->children() )
+    }
+
+    void check_non_root_rule( QgsRuleBasedRendererV2::Rule* node )
+    {
+      qDebug() << node->dump();
+      // children must not be NULL
+      QVERIFY( node );
+      // and must have a parent
+      QVERIFY( node->parent() );
+      // check that all children are okay
+      foreach( QgsRuleBasedRendererV2::Rule* child, node->children() )
       check_non_root_rule( child );
-  }
+    }
 
 };
 

-- 
The Quantum GIS in Debian project

_______________________________________________
Pkg-grass-devel mailing list
Pkg-grass-devel@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

Reply via email to