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