|
QGIS API Documentation
master-3f58142
|
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 }