Quantum GIS API Documentation
1.8
|
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 }