QGIS API Documentation  master-3f58142
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 dot sk at gmail dot 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 "qgsexpression.h"
00019 #include "qgssymbollayerv2utils.h"
00020 #include "qgsrendercontext.h"
00021 #include "qgsvectorlayer.h"
00022 #include "qgslogger.h"
00023 #include "qgsogcutils.h"
00024 
00025 #include <QSet>
00026 
00027 #include <QDomDocument>
00028 #include <QDomElement>
00029 
00030 
00031 
00032 QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description )
00033     : mParent( NULL ), mSymbol( symbol ),
00034     mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
00035     mFilterExp( filterExp ), mLabel( label ), mDescription( description ),
00036     mFilter( NULL )
00037 {
00038   initFilter();
00039 }
00040 
00041 QgsRuleBasedRendererV2::Rule::~Rule()
00042 {
00043   delete mSymbol;
00044   delete mFilter;
00045   qDeleteAll( mChildren );
00046   // do NOT delete parent
00047 }
00048 
00049 void QgsRuleBasedRendererV2::Rule::initFilter()
00050 {
00051   if ( !mFilterExp.isEmpty() )
00052   {
00053     delete mFilter;
00054     mFilter = new QgsExpression( mFilterExp );
00055   }
00056   else
00057   {
00058     mFilter = NULL;
00059   }
00060 }
00061 
00062 QString QgsRuleBasedRendererV2::Rule::dump( int offset ) const
00063 {
00064   QString off;
00065   off.fill( QChar( ' ' ), offset );
00066   QString symbolDump = ( mSymbol ? mSymbol->dump() : QString( "[]" ) );
00067   QString msg = off + QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
00068                 .arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
00069                 .arg( mFilterExp ).arg( symbolDump );
00070 
00071   QStringList lst;
00072   foreach ( Rule* rule, mChildren )
00073   {
00074     lst.append( rule->dump( offset + 2 ) );
00075   }
00076   msg += lst.join( "\n" );
00077   return msg;
00078 }
00079 
00080 QSet<QString> QgsRuleBasedRendererV2::Rule::usedAttributes()
00081 {
00082   // attributes needed by this rule
00083   QSet<QString> attrs;
00084   if ( mFilter )
00085     attrs.unite( mFilter->referencedColumns().toSet() );
00086   if ( mSymbol )
00087     attrs.unite( mSymbol->usedAttributes() );
00088 
00089   // attributes needed by child rules
00090   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00091   {
00092     Rule* rule = *it;
00093     attrs.unite( rule->usedAttributes() );
00094   }
00095   return attrs;
00096 }
00097 
00098 QgsSymbolV2List QgsRuleBasedRendererV2::Rule::symbols()
00099 {
00100   QgsSymbolV2List lst;
00101   if ( mSymbol )
00102     lst.append( mSymbol );
00103 
00104   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00105   {
00106     Rule* rule = *it;
00107     lst += rule->symbols();
00108   }
00109   return lst;
00110 }
00111 
00112 void QgsRuleBasedRendererV2::Rule::setSymbol( QgsSymbolV2* sym )
00113 {
00114   delete mSymbol;
00115   mSymbol = sym;
00116 }
00117 
00118 QgsLegendSymbolList QgsRuleBasedRendererV2::Rule::legendSymbolItems()
00119 {
00120   QgsLegendSymbolList lst;
00121   if ( mSymbol )
00122     lst << qMakePair( mLabel, mSymbol );
00123 
00124   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00125   {
00126     Rule* rule = *it;
00127     lst << rule->legendSymbolItems();
00128   }
00129   return lst;
00130 }
00131 
00132 
00133 bool QgsRuleBasedRendererV2::Rule::isFilterOK( QgsFeature& f ) const
00134 {
00135   if ( ! mFilter )
00136     return true;
00137 
00138   QVariant res = mFilter->evaluate( &f );
00139   return res.toInt() != 0;
00140 }
00141 
00142 bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
00143 {
00144   if ( scale == 0 ) // so that we can count features in classes without scale context
00145     return true;
00146   if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
00147     return true;
00148   if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
00149     return false;
00150   if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
00151     return false;
00152   return true;
00153 }
00154 
00155 QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::clone() const
00156 {
00157   QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL;
00158   Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
00159   // clone children
00160   foreach ( Rule* rule, mChildren )
00161     newrule->appendChild( rule->clone() );
00162   return newrule;
00163 }
00164 
00165 QDomElement QgsRuleBasedRendererV2::Rule::save( QDomDocument& doc, QgsSymbolV2Map& symbolMap )
00166 {
00167   QDomElement ruleElem = doc.createElement( "rule" );
00168 
00169   if ( mSymbol )
00170   {
00171     int symbolIndex = symbolMap.size();
00172     symbolMap[QString::number( symbolIndex )] = mSymbol;
00173     ruleElem.setAttribute( "symbol", symbolIndex );
00174   }
00175   if ( !mFilterExp.isEmpty() )
00176     ruleElem.setAttribute( "filter", mFilterExp );
00177   if ( mScaleMinDenom != 0 )
00178     ruleElem.setAttribute( "scalemindenom", mScaleMinDenom );
00179   if ( mScaleMaxDenom != 0 )
00180     ruleElem.setAttribute( "scalemaxdenom", mScaleMaxDenom );
00181   if ( !mLabel.isEmpty() )
00182     ruleElem.setAttribute( "label", mLabel );
00183   if ( !mDescription.isEmpty() )
00184     ruleElem.setAttribute( "description", mDescription );
00185 
00186   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00187   {
00188     Rule* rule = *it;
00189     ruleElem.appendChild( rule->save( doc, symbolMap ) );
00190   }
00191   return ruleElem;
00192 }
00193 
00194 void QgsRuleBasedRendererV2::Rule::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props )
00195 {
00196   // do not convert this rule if there are no symbols
00197   if ( symbols().isEmpty() )
00198     return;
00199 
00200   if ( !mFilterExp.isEmpty() )
00201   {
00202     if ( !props.value( "filter", "" ).isEmpty() )
00203       props[ "filter" ] += " AND ";
00204     props[ "filter" ] += mFilterExp;
00205   }
00206 
00207   if ( mScaleMinDenom != 0 )
00208   {
00209     bool ok;
00210     int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
00211     if ( !ok || parentScaleMinDenom <= 0 )
00212       props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
00213     else
00214       props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
00215   }
00216 
00217   if ( mScaleMaxDenom != 0 )
00218   {
00219     bool ok;
00220     int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
00221     if ( !ok || parentScaleMaxDenom <= 0 )
00222       props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
00223     else
00224       props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
00225   }
00226 
00227   if ( mSymbol )
00228   {
00229     QDomElement ruleElem = doc.createElement( "se:Rule" );
00230     element.appendChild( ruleElem );
00231 
00232     //XXX: <se:Name> is the rule identifier, but our the Rule objects
00233     // have no properties could be used as identifier. Use the label.
00234     QDomElement nameElem = doc.createElement( "se:Name" );
00235     nameElem.appendChild( doc.createTextNode( mLabel ) );
00236     ruleElem.appendChild( nameElem );
00237 
00238     if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
00239     {
00240       QDomElement descrElem = doc.createElement( "se:Description" );
00241       if ( !mLabel.isEmpty() )
00242       {
00243         QDomElement titleElem = doc.createElement( "se:Title" );
00244         titleElem.appendChild( doc.createTextNode( mLabel ) );
00245         descrElem.appendChild( titleElem );
00246       }
00247       if ( !mDescription.isEmpty() )
00248       {
00249         QDomElement abstractElem = doc.createElement( "se:Abstract" );
00250         abstractElem.appendChild( doc.createTextNode( mDescription ) );
00251         descrElem.appendChild( abstractElem );
00252       }
00253       ruleElem.appendChild( descrElem );
00254     }
00255 
00256     if ( !props.value( "filter", "" ).isEmpty() )
00257     {
00258       QDomElement filterElem = doc.createElement( "ogc:Filter" );
00259       QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, props.value( "filter", "" ) );
00260       ruleElem.appendChild( filterElem );
00261     }
00262 
00263     if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
00264     {
00265       QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
00266       scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
00267       ruleElem.appendChild( scaleMinDenomElem );
00268     }
00269 
00270     if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
00271     {
00272       QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
00273       scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
00274       ruleElem.appendChild( scaleMaxDenomElem );
00275     }
00276 
00277     mSymbol->toSld( doc, ruleElem, props );
00278   }
00279 
00280   // loop into childern rule list
00281   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00282   {
00283     ( *it )->toSld( doc, element, props );
00284   }
00285 }
00286 
00287 bool QgsRuleBasedRendererV2::Rule::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
00288 {
00289   mActiveChildren.clear();
00290 
00291   // filter out rules which are not compatible with this scale
00292   if ( !isScaleOK( context.rendererScale() ) )
00293     return false;
00294 
00295   // init this rule
00296   if ( mFilter )
00297     mFilter->prepare( vlayer->pendingFields() );
00298   if ( mSymbol )
00299     mSymbol->startRender( context, vlayer );
00300 
00301   // init children
00302   // build temporary list of active rules (usable with this scale)
00303   for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
00304   {
00305     Rule* rule = *it;
00306     if ( rule->startRender( context, vlayer ) )
00307     {
00308       // only add those which are active with current scale
00309       mActiveChildren.append( rule );
00310     }
00311   }
00312   return true;
00313 }
00314 
00315 QSet<int> QgsRuleBasedRendererV2::Rule::collectZLevels()
00316 {
00317   QSet<int> symbolZLevelsSet;
00318 
00319   // process this rule
00320   if ( mSymbol )
00321   {
00322     // find out which Z-levels are used
00323     for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
00324     {
00325       symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
00326     }
00327   }
00328 
00329   // process children
00330   QList<Rule*>::iterator it;
00331   for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00332   {
00333     Rule* rule = *it;
00334     symbolZLevelsSet.unite( rule->collectZLevels() );
00335   }
00336   return symbolZLevelsSet;
00337 }
00338 
00339 void QgsRuleBasedRendererV2::Rule::setNormZLevels( const QMap<int, int>& zLevelsToNormLevels )
00340 {
00341   if ( mSymbol )
00342   {
00343     for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
00344     {
00345       int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
00346       mSymbolNormZLevels.append( normLevel );
00347     }
00348   }
00349 
00350   // prepare list of normalized levels for each rule
00351   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00352   {
00353     Rule* rule = *it;
00354     rule->setNormZLevels( zLevelsToNormLevels );
00355   }
00356 }
00357 
00358 
00359 bool QgsRuleBasedRendererV2::Rule::renderFeature( QgsRuleBasedRendererV2::FeatureToRender& featToRender, QgsRenderContext& context, QgsRuleBasedRendererV2::RenderQueue& renderQueue )
00360 {
00361   if ( !isFilterOK( featToRender.feat ) )
00362     return false;
00363 
00364   bool rendered = false;
00365 
00366   // create job for this feature and this symbol, add to list of jobs
00367   if ( mSymbol )
00368   {
00369     // add job to the queue: each symbol's zLevel must be added
00370     foreach ( int normZLevel, mSymbolNormZLevels )
00371     {
00372       //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
00373       renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol ) );
00374     }
00375     rendered = true;
00376   }
00377 
00378   // process children
00379   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00380   {
00381     Rule* rule = *it;
00382     rendered |= rule->renderFeature( featToRender, context, renderQueue );
00383   }
00384   return rendered;
00385 }
00386 
00387 bool QgsRuleBasedRendererV2::Rule::willRenderFeature( QgsFeature& feat )
00388 {
00389   if ( !isFilterOK( feat ) )
00390     return false;
00391   if ( mSymbol )
00392     return true;
00393 
00394   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00395   {
00396     Rule* rule = *it;
00397     if ( rule->willRenderFeature( feat ) )
00398       return true;
00399   }
00400   return false;
00401 }
00402 
00403 QgsSymbolV2List QgsRuleBasedRendererV2::Rule::symbolsForFeature( QgsFeature& feat )
00404 {
00405   QgsSymbolV2List lst;
00406   if ( !isFilterOK( feat ) )
00407     return lst;
00408   if ( mSymbol )
00409     lst.append( mSymbol );
00410 
00411   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00412   {
00413     Rule* rule = *it;
00414     lst += rule->symbolsForFeature( feat );
00415   }
00416   return lst;
00417 }
00418 
00419 QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::Rule::rulesForFeature( QgsFeature& feat )
00420 {
00421   RuleList lst;
00422   if ( !isFilterOK( feat ) )
00423     return lst;
00424 
00425   if ( mSymbol )
00426     lst.append( this );
00427 
00428   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00429   {
00430     Rule* rule = *it;
00431     lst += rule->rulesForFeature( feat );
00432   }
00433   return lst;
00434 }
00435 
00436 void QgsRuleBasedRendererV2::Rule::stopRender( QgsRenderContext& context )
00437 {
00438   if ( mSymbol )
00439     mSymbol->stopRender( context );
00440 
00441   for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
00442   {
00443     Rule* rule = *it;
00444     rule->stopRender( context );
00445   }
00446 
00447   mActiveChildren.clear();
00448   mSymbolNormZLevels.clear();
00449 }
00450 
00451 QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::create( QDomElement& ruleElem, QgsSymbolV2Map& symbolMap )
00452 {
00453   QString symbolIdx = ruleElem.attribute( "symbol" );
00454   QgsSymbolV2* symbol = NULL;
00455   if ( !symbolIdx.isEmpty() )
00456   {
00457     if ( symbolMap.contains( symbolIdx ) )
00458     {
00459       symbol = symbolMap.take( symbolIdx );
00460     }
00461     else
00462     {
00463       QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
00464     }
00465   }
00466 
00467   QString filterExp = ruleElem.attribute( "filter" );
00468   QString label = ruleElem.attribute( "label" );
00469   QString description = ruleElem.attribute( "description" );
00470   int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
00471   int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
00472   Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
00473 
00474   QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
00475   while ( !childRuleElem.isNull() )
00476   {
00477     Rule* childRule = create( childRuleElem, symbolMap );
00478     if ( childRule )
00479     {
00480       rule->appendChild( childRule );
00481     }
00482     else
00483     {
00484       QgsDebugMsg( "failed to init a child rule!" );
00485     }
00486     childRuleElem = childRuleElem.nextSiblingElement( "rule" );
00487   }
00488 
00489   return rule;
00490 }
00491 
00492 QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::createFromSld( QDomElement& ruleElem, QGis::GeometryType geomType )
00493 {
00494   if ( ruleElem.localName() != "Rule" )
00495   {
00496     QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
00497     return NULL;
00498   }
00499 
00500   QString label, description, filterExp;
00501   int scaleMinDenom = 0, scaleMaxDenom = 0;
00502   QgsSymbolLayerV2List layers;
00503 
00504   // retrieve the Rule element child nodes
00505   QDomElement childElem = ruleElem.firstChildElement();
00506   while ( !childElem.isNull() )
00507   {
00508     if ( childElem.localName() == "Name" )
00509     {
00510       // <se:Name> tag contains the rule identifier,
00511       // so prefer title tag for the label property value
00512       if ( label.isEmpty() )
00513         label = childElem.firstChild().nodeValue();
00514     }
00515     else if ( childElem.localName() == "Description" )
00516     {
00517       // <se:Description> can contains a title and an abstract
00518       QDomElement titleElem = childElem.firstChildElement( "Title" );
00519       if ( !titleElem.isNull() )
00520       {
00521         label = titleElem.firstChild().nodeValue();
00522       }
00523 
00524       QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
00525       if ( !abstractElem.isNull() )
00526       {
00527         description = abstractElem.firstChild().nodeValue();
00528       }
00529     }
00530     else if ( childElem.localName() == "Abstract" )
00531     {
00532       // <sld:Abstract> (v1.0)
00533       description = childElem.firstChild().nodeValue();
00534     }
00535     else if ( childElem.localName() == "Title" )
00536     {
00537       // <sld:Title> (v1.0)
00538       label = childElem.firstChild().nodeValue();
00539     }
00540     else if ( childElem.localName() == "Filter" )
00541     {
00542       QgsExpression *filter = QgsOgcUtils::expressionFromOgcFilter( childElem );
00543       if ( filter )
00544       {
00545         if ( filter->hasParserError() )
00546         {
00547           QgsDebugMsg( "parser error: " + filter->parserErrorString() );
00548         }
00549         else
00550         {
00551           filterExp = filter->dump();
00552         }
00553         delete filter;
00554       }
00555     }
00556     else if ( childElem.localName() == "MinScaleDenominator" )
00557     {
00558       bool ok;
00559       int v = childElem.firstChild().nodeValue().toInt( &ok );
00560       if ( ok )
00561         scaleMinDenom = v;
00562     }
00563     else if ( childElem.localName() == "MaxScaleDenominator" )
00564     {
00565       bool ok;
00566       int v = childElem.firstChild().nodeValue().toInt( &ok );
00567       if ( ok )
00568         scaleMaxDenom = v;
00569     }
00570     else if ( childElem.localName().endsWith( "Symbolizer" ) )
00571     {
00572       // create symbol layers for this symbolizer
00573       QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
00574     }
00575 
00576     childElem = childElem.nextSiblingElement();
00577   }
00578 
00579   // now create the symbol
00580   QgsSymbolV2 *symbol = 0;
00581   if ( layers.size() > 0 )
00582   {
00583     switch ( geomType )
00584     {
00585       case QGis::Line:
00586         symbol = new QgsLineSymbolV2( layers );
00587         break;
00588 
00589       case QGis::Polygon:
00590         symbol = new QgsFillSymbolV2( layers );
00591         break;
00592 
00593       case QGis::Point:
00594         symbol = new QgsMarkerSymbolV2( layers );
00595         break;
00596 
00597       default:
00598         QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
00599         return NULL;
00600     }
00601   }
00602 
00603   // and then create and return the new rule
00604   return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
00605 }
00606 
00607 
00609 
00610 QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsRuleBasedRendererV2::Rule* root )
00611     : QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
00612 {
00613 }
00614 
00615 QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
00616     : QgsFeatureRendererV2( "RuleRenderer" )
00617 {
00618   mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
00619   mRootRule->appendChild( new Rule( defaultSymbol ) );
00620 }
00621 
00622 QgsRuleBasedRendererV2::~QgsRuleBasedRendererV2()
00623 {
00624   delete mRootRule;
00625 }
00626 
00627 
00628 QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& )
00629 {
00630   // not used at all
00631   return 0;
00632 }
00633 
00634 bool QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature,
00635     QgsRenderContext& context,
00636     int layer,
00637     bool selected,
00638     bool drawVertexMarker )
00639 {
00640   Q_UNUSED( layer );
00641 
00642   int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
00643   mCurrentFeatures.append( FeatureToRender( feature, flags ) );
00644 
00645   // check each active rule
00646   return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue );
00647 }
00648 
00649 
00650 void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
00651 {
00652   // prepare active children
00653   mRootRule->startRender( context, vlayer );
00654 
00655   QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
00656   QList<int> symbolZLevels = symbolZLevelsSet.toList();
00657   qSort( symbolZLevels );
00658 
00659   // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
00660   // and prepare rendering queue
00661   QMap<int, int> zLevelsToNormLevels;
00662   int maxNormLevel = -1;
00663   foreach ( int zLevel, symbolZLevels )
00664   {
00665     zLevelsToNormLevels[zLevel] = ++maxNormLevel;
00666     mRenderQueue.append( RenderLevel( zLevel ) );
00667     QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
00668   }
00669 
00670   mRootRule->setNormZLevels( zLevelsToNormLevels );
00671 }
00672 
00673 void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
00674 {
00675   //
00676   // do the actual rendering
00677   //
00678 
00679   // go through all levels
00680   foreach ( const RenderLevel& level, mRenderQueue )
00681   {
00682     //QgsDebugMsg(QString("level %1").arg(level.zIndex));
00683     // go through all jobs at the level
00684     foreach ( const RenderJob* job, level.jobs )
00685     {
00686       //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
00687       // render feature - but only with symbol layers with specified zIndex
00688       QgsSymbolV2* s = job->symbol;
00689       int count = s->symbolLayerCount();
00690       for ( int i = 0; i < count; i++ )
00691       {
00692         // TODO: better solution for this
00693         // renderFeatureWithSymbol asks which symbol layer to draw
00694         // but there are multiple transforms going on!
00695         if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
00696         {
00697           int flags = job->ftr.flags;
00698           renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
00699         }
00700       }
00701     }
00702   }
00703 
00704   // clean current features
00705   mCurrentFeatures.clear();
00706 
00707   // clean render queue
00708   mRenderQueue.clear();
00709 
00710   // clean up rules from temporary stuff
00711   mRootRule->stopRender( context );
00712 }
00713 
00714 QList<QString> QgsRuleBasedRendererV2::usedAttributes()
00715 {
00716   QSet<QString> attrs = mRootRule->usedAttributes();
00717   return attrs.values();
00718 }
00719 
00720 QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
00721 {
00722   QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( mRootRule->clone() );
00723 
00724   r->setUsingSymbolLevels( usingSymbolLevels() );
00725   setUsingSymbolLevels( usingSymbolLevels() );
00726   return r;
00727 }
00728 
00729 void QgsRuleBasedRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
00730 {
00731   mRootRule->toSld( doc, element, QgsStringMap() );
00732 }
00733 
00734 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
00735 QgsSymbolV2List QgsRuleBasedRendererV2::symbols()
00736 {
00737   return mRootRule->symbols();
00738 }
00739 
00740 QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
00741 {
00742   QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
00743   rendererElem.setAttribute( "type", "RuleRenderer" );
00744   rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
00745 
00746   QgsSymbolV2Map symbols;
00747 
00748   QDomElement rulesElem = mRootRule->save( doc, symbols );
00749   rulesElem.setTagName( "rules" ); // instead of just "rule"
00750   rendererElem.appendChild( rulesElem );
00751 
00752   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
00753   rendererElem.appendChild( symbolsElem );
00754 
00755   return rendererElem;
00756 }
00757 
00758 QgsLegendSymbologyList QgsRuleBasedRendererV2::legendSymbologyItems( QSize iconSize )
00759 {
00760   QgsLegendSymbologyList lst;
00761   QgsLegendSymbolList items = legendSymbolItems();
00762   for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); it++ )
00763   {
00764     QPair<QString, QgsSymbolV2*> pair = *it;
00765     QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
00766     lst << qMakePair( pair.first, pix );
00767   }
00768   return lst;
00769 }
00770 
00771 QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems()
00772 {
00773   return mRootRule->legendSymbolItems();
00774 }
00775 
00776 
00777 QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
00778 {
00779   // load symbols
00780   QDomElement symbolsElem = element.firstChildElement( "symbols" );
00781   if ( symbolsElem.isNull() )
00782     return NULL;
00783 
00784   QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
00785 
00786   QDomElement rulesElem = element.firstChildElement( "rules" );
00787 
00788   Rule* root = Rule::create( rulesElem, symbolMap );
00789   if ( root == NULL )
00790     return NULL;
00791 
00792   QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( root );
00793 
00794   // delete symbols if there are any more
00795   QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
00796 
00797   return r;
00798 }
00799 
00800 QgsFeatureRendererV2* QgsRuleBasedRendererV2::createFromSld( QDomElement& element, QGis::GeometryType geomType )
00801 {
00802   // retrieve child rules
00803   Rule* root = 0;
00804 
00805   QDomElement ruleElem = element.firstChildElement( "Rule" );
00806   while ( !ruleElem.isNull() )
00807   {
00808     Rule *child = Rule::createFromSld( ruleElem, geomType );
00809     if ( child )
00810     {
00811       // create the root rule if not done before
00812       if ( !root )
00813         root = new Rule( 0 );
00814 
00815       root->appendChild( child );
00816     }
00817 
00818     ruleElem = ruleElem.nextSiblingElement( "Rule" );
00819   }
00820 
00821   if ( !root )
00822   {
00823     // no valid rules was found
00824     return NULL;
00825   }
00826 
00827   // create and return the new renderer
00828   return new QgsRuleBasedRendererV2( root );
00829 }
00830 
00831 #include "qgscategorizedsymbolrendererv2.h"
00832 #include "qgsgraduatedsymbolrendererv2.h"
00833 
00834 void QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r )
00835 {
00836   foreach ( const QgsRendererCategoryV2& cat, r->categories() )
00837   {
00838     QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
00839     QString value;
00840     // not quoting numbers saves a type cast
00841     if ( cat.value().type() == QVariant::Int )
00842       value = cat.value().toString();
00843     else if ( cat.value().type() == QVariant::Double )
00844       // we loose precision here - so we may miss some categories :-(
00845       // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
00846       value = QString::number( cat.value().toDouble(), 'f', 4 );
00847     else
00848       value = QgsExpression::quotedString( cat.value().toString() );
00849     QString filter = QString( "%1 = %2" ).arg( attr ).arg( value );
00850     QString label = filter;
00851     initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
00852   }
00853 }
00854 
00855 void QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r )
00856 {
00857   foreach ( const QgsRendererRangeV2& rng, r->ranges() )
00858   {
00859     // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
00860     // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
00861     QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
00862     QString filter = QString( "%1 >= %2 AND %1 <= %3" ).arg( attr )
00863                      .arg( QString::number( rng.lowerValue(), 'f', 4 ) )
00864                      .arg( QString::number( rng.upperValue(), 'f', 4 ) );
00865     QString label = filter;
00866     initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
00867   }
00868 }
00869 
00870 void QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales )
00871 {
00872   qSort( scales ); // make sure the scales are in ascending order
00873   int oldScale = initialRule->scaleMinDenom();
00874   int maxDenom = initialRule->scaleMaxDenom();
00875   QgsSymbolV2* symbol = initialRule->symbol();
00876   foreach ( int scale, scales )
00877   {
00878     if ( initialRule->scaleMinDenom() >= scale )
00879       continue; // jump over the first scales out of the interval
00880     if ( maxDenom != 0 && maxDenom  <= scale )
00881       break; // ignore the latter scales out of the interval
00882     initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
00883     oldScale = scale;
00884   }
00885   // last rule
00886   initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
00887 }
00888 
00889 QString QgsRuleBasedRendererV2::dump()
00890 {
00891   QString msg( "Rule-based renderer:\n" );
00892   msg += mRootRule->dump();
00893   return msg;
00894 }
00895 
00896 bool QgsRuleBasedRendererV2::willRenderFeature( QgsFeature& feat )
00897 {
00898   return mRootRule->willRenderFeature( feat );
00899 }
00900 
00901 QgsSymbolV2List QgsRuleBasedRendererV2::symbolsForFeature( QgsFeature& feat )
00902 {
00903   return mRootRule->symbolsForFeature( feat );
00904 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines