Quantum GIS API Documentation  1.7.4
src/core/symbology-ng/qgsrulebasedrendererv2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsrulebasedrendererv2.cpp - Rule-based renderer (symbology-ng)
00003     ---------------------
00004     begin                : May 2010
00005     copyright            : (C) 2010 by Martin Dobias
00006     email                : wonder.sk at gmail.com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgsrulebasedrendererv2.h"
00017 #include "qgssymbollayerv2.h"
00018 #include "qgssearchtreenode.h"
00019 #include "qgssymbollayerv2utils.h"
00020 #include "qgsrendercontext.h"
00021 #include "qgsvectorlayer.h"
00022 #include "qgslogger.h"
00023 
00024 #include <QSet>
00025 
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 
00029 
00030 
00031 QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description )
00032     : mSymbol( symbol ),
00033     mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
00034     mFilterExp( filterExp ), mLabel( label ), mDescription( description )
00035 {
00036   initFilter();
00037 }
00038 
00039 QgsRuleBasedRendererV2::Rule::Rule( const QgsRuleBasedRendererV2::Rule& other )
00040     : mSymbol( NULL )
00041 {
00042   *this = other;
00043 }
00044 
00045 QgsRuleBasedRendererV2::Rule::~Rule()
00046 {
00047   delete mSymbol;
00048 }
00049 
00050 void QgsRuleBasedRendererV2::Rule::initFilter()
00051 {
00052   if ( !mFilterExp.isEmpty() )
00053   {
00054     mFilterParsed.setString( mFilterExp );
00055     mFilterTree = mFilterParsed.tree(); // may be NULL if there's no input
00056   }
00057   else
00058   {
00059     mFilterTree = NULL;
00060   }
00061 }
00062 
00063 QString QgsRuleBasedRendererV2::Rule::dump() const
00064 {
00065   return QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5" )
00066          .arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
00067          .arg( mFilterExp ).arg( mSymbol->dump() );
00068 
00069 }
00070 
00071 QStringList QgsRuleBasedRendererV2::Rule::needsFields() const
00072 {
00073   if ( ! mFilterTree )
00074     return QStringList();
00075 
00076   return mFilterTree->referencedColumns();
00077 }
00078 
00079 bool QgsRuleBasedRendererV2::Rule::isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const
00080 {
00081   if ( ! mFilterTree )
00082     return true;
00083 
00084   bool res = mFilterTree->checkAgainst( fields, f );
00085   //print "is_ok", res, feature.id(), feature.attributeMap()
00086   return res;
00087 }
00088 
00089 bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
00090 {
00091   if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
00092     return true;
00093   if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
00094     return false;
00095   if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
00096     return false;
00097   return true;
00098 }
00099 
00100 QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::Rule::operator=( const QgsRuleBasedRendererV2::Rule & other )
00101 {
00102   if ( this != &other )
00103   {
00104     delete mSymbol;
00105     mSymbol = other.mSymbol->clone();
00106 
00107     mScaleMinDenom = other.mScaleMinDenom;
00108     mScaleMaxDenom = other.mScaleMaxDenom;
00109     mFilterExp = other.mFilterExp;
00110     mLabel = other.mLabel;
00111     mDescription = other.mDescription;
00112     initFilter();
00113   }
00114   return *this;
00115 }
00116 
00118 
00119 QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
00120     : QgsFeatureRendererV2( "RuleRenderer" ), mDefaultSymbol( defaultSymbol ), mCurrentSymbol( 0 )
00121 {
00122   // add the default rule
00123   mRules << Rule( defaultSymbol->clone() );
00124 }
00125 
00126 
00127 QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& feature )
00128 {
00129 
00130   if( ! usingFirstRule() )
00131     return mCurrentSymbol;
00132 
00133   for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
00134   {
00135     Rule* rule = *it;
00136 
00137     if ( rule->isFilterOK( mCurrentFields, feature ) )
00138     {
00139       return rule->symbol(); //works with levels but takes only first rule
00140     }
00141   }
00142   return mCurrentSymbol;
00143 }
00144 
00145 void QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature,
00146     QgsRenderContext& context,
00147     int layer,
00148     bool selected,
00149     bool drawVertexMarker )
00150 {
00151   for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
00152   {
00153     Rule* rule = *it;
00154     if ( rule->isFilterOK( mCurrentFields, feature ) )
00155     {
00156       mCurrentSymbol = rule->symbol();
00157       // will ask for mCurrentSymbol
00158       QgsFeatureRendererV2::renderFeature( feature, context, layer, selected, drawVertexMarker );
00159     }
00160   }
00161 }
00162 
00163 
00164 void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
00165 {
00166   double currentScale = context.rendererScale();
00167   // filter out rules which are not compatible with this scale
00168 
00169   mCurrentRules.clear();
00170   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
00171   {
00172     Rule& rule = *it;
00173     if ( rule.isScaleOK( currentScale ) )
00174       mCurrentRules.append( &rule );
00175   }
00176 
00177   mCurrentFields = vlayer->pendingFields();
00178 
00179   for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
00180   {
00181     Rule* rule = *it;
00182     rule->symbol()->startRender( context );
00183   }
00184 }
00185 
00186 void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
00187 {
00188   for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
00189   {
00190     Rule* rule = *it;
00191     rule->symbol()->stopRender( context );
00192   }
00193 
00194   mCurrentRules.clear();
00195   mCurrentFields.clear();
00196 }
00197 
00198 QList<QString> QgsRuleBasedRendererV2::usedAttributes()
00199 {
00200   QSet<QString> attrs;
00201   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
00202   {
00203     Rule& rule = *it;
00204     attrs.unite( rule.needsFields().toSet() );
00205   }
00206   return attrs.values();
00207 }
00208 
00209 QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
00210 {
00211   QgsSymbolV2* s = mDefaultSymbol->clone();
00212   QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( s );
00213   r->mRules = mRules;
00214   r->setUsingSymbolLevels( usingSymbolLevels() );
00215   r->setUsingFirstRule( usingFirstRule() );
00216   setUsingFirstRule( usingFirstRule() );
00217   setUsingSymbolLevels( usingSymbolLevels() );
00218   return r;
00219 }
00220 
00221 QgsSymbolV2List QgsRuleBasedRendererV2::symbols()
00222 {
00223   QgsSymbolV2List lst;
00224   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
00225   {
00226     Rule& rule = *it;
00227     lst.append( rule.symbol() );
00228   }
00229 
00230   return lst;
00231 }
00232 
00233 QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
00234 {
00235   QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
00236   rendererElem.setAttribute( "type", "RuleRenderer" );
00237   rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
00238   rendererElem.setAttribute( "firstrule", ( mUsingFirstRule ? "1" : "0" ) );
00239 
00240   QDomElement rulesElem = doc.createElement( "rules" );
00241 
00242   QgsSymbolV2Map symbols;
00243   symbols["default"] = mDefaultSymbol;
00244 
00245   int i = 0;
00246   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++i, ++it )
00247   {
00248     Rule& rule = *it;
00249     symbols[QString::number( i )] = rule.symbol();
00250     QDomElement ruleElem = doc.createElement( "rule" );
00251     ruleElem.setAttribute( "symbol", i );
00252     ruleElem.setAttribute( "filter", rule.filterExpression() );
00253     ruleElem.setAttribute( "scalemindenom", rule.scaleMinDenom() );
00254     ruleElem.setAttribute( "scalemaxdenom", rule.scaleMaxDenom() );
00255     ruleElem.setAttribute( "label", rule.label() );
00256     ruleElem.setAttribute( "description", rule.description() );
00257     rulesElem.appendChild( ruleElem );
00258   }
00259   rendererElem.appendChild( rulesElem );
00260 
00261   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
00262   rendererElem.appendChild( symbolsElem );
00263 
00264   return rendererElem;
00265 }
00266 
00267 
00268 QgsLegendSymbologyList QgsRuleBasedRendererV2::legendSymbologyItems( QSize iconSize )
00269 {
00270   QgsLegendSymbologyList lst;
00271   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
00272   {
00273     QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( it->symbol(), iconSize );
00274     lst << qMakePair( it->label(), pix );
00275   }
00276   return lst;
00277 }
00278 
00279 QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems()
00280 {
00281   QgsLegendSymbolList lst;
00282   for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
00283   {
00284     lst << qMakePair( it->label(), it->symbol() );
00285   }
00286   return lst;
00287 }
00288 
00289 
00290 QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
00291 {
00292   // load symbols
00293   QDomElement symbolsElem = element.firstChildElement( "symbols" );
00294   if ( symbolsElem.isNull() )
00295     return NULL;
00296 
00297   QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
00298 
00299   if ( !symbolMap.contains( "default" ) )
00300   {
00301     QgsDebugMsg( "default symbol not found!" );
00302     return NULL;
00303   }
00304 
00305   QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( symbolMap.take( "default" ) );
00306   r->mRules.clear();
00307 
00308   QDomElement rulesElem = element.firstChildElement( "rules" );
00309   QDomElement ruleElem = rulesElem.firstChildElement( "rule" );
00310   while ( !ruleElem.isNull() )
00311   {
00312     QString symbolIdx = ruleElem.attribute( "symbol" );
00313     if ( symbolMap.contains( symbolIdx ) )
00314     {
00315       QString filterExp = ruleElem.attribute( "filter" );
00316       QString label = ruleElem.attribute( "label" );
00317       QString description = ruleElem.attribute( "description" );
00318       int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
00319       int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
00320       r->mRules.append( Rule( symbolMap.take( symbolIdx ), scaleMinDenom, scaleMaxDenom, filterExp, label, description ) );
00321     }
00322     else
00323     {
00324       QgsDebugMsg( "symbol for rule " + symbolIdx + " not found! (skipping)" );
00325     }
00326     ruleElem = ruleElem.nextSiblingElement( "rule" );
00327   }
00328 
00329   // delete symbols if there are any more
00330   QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
00331 
00332   return r;
00333 }
00334 
00335 
00336 int QgsRuleBasedRendererV2::ruleCount()
00337 {
00338   return mRules.count();
00339 }
00340 
00341 QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::ruleAt( int index )
00342 {
00343   return mRules[index];
00344 }
00345 
00346 void QgsRuleBasedRendererV2::addRule( const QgsRuleBasedRendererV2::Rule& rule )
00347 {
00348   mRules.append( rule );
00349 }
00350 
00351 void QgsRuleBasedRendererV2::insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule )
00352 {
00353   mRules.insert( index, rule );
00354 }
00355 
00356 void QgsRuleBasedRendererV2::updateRuleAt( int index, const QgsRuleBasedRendererV2::Rule& rule )
00357 {
00358   mRules[index] = rule;
00359 }
00360 
00361 void QgsRuleBasedRendererV2::removeRuleAt( int index )
00362 {
00363   mRules.removeAt( index );
00364 }
00365 
00366 void QgsRuleBasedRendererV2::swapRules( int index1,  int index2 )
00367 {
00368   mRules.swap( index1, index2 );
00369 }
00370 
00371 
00372 #include "qgscategorizedsymbolrendererv2.h"
00373 #include "qgsgraduatedsymbolrendererv2.h"
00374 
00375 QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r )
00376 {
00377   QList<Rule> rules;
00378   foreach( const QgsRendererCategoryV2& cat, r->categories() )
00379   {
00380     QString newfilter = QString( "%1 = '%2'" ).arg( r->classAttribute() ).arg( cat.value().toString() );
00381     QString filter = initialRule.filterExpression();
00382     QString label = initialRule.label();
00383     QString description = initialRule.description();
00384     if ( filter.isEmpty() )
00385       filter = newfilter;
00386     else
00387       filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
00388     rules.append( Rule( cat.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter, initialRule.label(), initialRule.description() ) );
00389   }
00390   return rules;
00391 }
00392 
00393 QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r )
00394 {
00395   QList<Rule> rules;
00396   foreach( const QgsRendererRangeV2& rng, r->ranges() )
00397   {
00398     QString newfilter = QString( "%1 >= '%2' AND %1 <= '%3'" ).arg( r->classAttribute() ).arg( rng.lowerValue() ).arg( rng.upperValue() );
00399     QString filter = initialRule.filterExpression();
00400     QString label = initialRule.label();
00401     QString description = initialRule.description();
00402     if ( filter.isEmpty() )
00403       filter = newfilter;
00404     else
00405       filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
00406     rules.append( Rule( rng.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter, initialRule.label(), initialRule.description() ) );
00407   }
00408   return rules;
00409 }
00410 
00411 QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList<int> scales )
00412 {
00413   qSort( scales ); // make sure the scales are in ascending order
00414   QList<Rule> rules;
00415   int oldScale = initialRule.scaleMinDenom();
00416   int maxDenom = initialRule.scaleMaxDenom();
00417   foreach( int scale, scales )
00418   {
00419     if ( initialRule.scaleMinDenom() >= scale )
00420       continue; // jump over the first scales out of the interval
00421     if ( maxDenom != 0 && maxDenom  <= scale )
00422       break; // ignore the latter scales out of the interval
00423     rules.append( Rule( initialRule.symbol()->clone(), oldScale, scale, initialRule.filterExpression(), initialRule.label(), initialRule.description() ) );
00424     oldScale = scale;
00425   }
00426   // last rule
00427   rules.append( Rule( initialRule.symbol()->clone(), oldScale, maxDenom, initialRule.filterExpression(), initialRule.label(), initialRule.description() ) );
00428   return rules;
00429 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines