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