[SCM] qgis branch, master, updated. a2ee769957385f4e084c5e8b6ba178a8c877d1db
Martin Dobias
wonder.sk at gmail.com
Tue Mar 20 13:42:33 UTC 2012
The following commit has been merged in the master branch:
commit ad955e26bf9fe7281c286c18b3b41fde6846b3bd
Author: Martin Dobias <wonder.sk at 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
More information about the Pkg-grass-devel
mailing list