QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsrulebasedrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrulebasedrenderer.cpp - Rule-based renderer (symbology)
3  ---------------------
4  begin : May 2010
5  copyright : (C) 2010 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsrulebasedrenderer.h"
17 #include "qgssymbollayer.h"
18 #include "qgsexpression.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgsrendercontext.h"
21 #include "qgsvectorlayer.h"
22 #include "qgslogger.h"
23 #include "qgsogcutils.h"
27 #include "qgspainteffect.h"
28 #include "qgspainteffectregistry.h"
29 #include "qgsproperty.h"
30 #include "qgsstyleentityvisitor.h"
31 
32 #include <QSet>
33 
34 #include <QDomDocument>
35 #include <QDomElement>
36 #include <QUuid>
37 
38 
39 QgsRuleBasedRenderer::Rule::Rule( QgsSymbol *symbol, int scaleMinDenom, int scaleMaxDenom, const QString &filterExp, const QString &label, const QString &description, bool elseRule )
40  : mParent( nullptr )
41  , mSymbol( symbol )
42  , mMaximumScale( scaleMinDenom )
43  , mMinimumScale( scaleMaxDenom )
44  , mFilterExp( filterExp )
45  , mLabel( label )
46  , mDescription( description )
47  , mElseRule( elseRule )
48 {
49  if ( mElseRule )
50  mFilterExp = QStringLiteral( "ELSE" );
51 
52  mRuleKey = QUuid::createUuid().toString();
53  initFilter();
54 }
55 
57 {
58  qDeleteAll( mChildren );
59  // do NOT delete parent
60 }
61 
63 {
64  if ( mFilterExp.trimmed().compare( QLatin1String( "ELSE" ), Qt::CaseInsensitive ) == 0 )
65  {
66  mElseRule = true;
67  mFilter.reset();
68  }
69  else if ( mFilterExp.trimmed().isEmpty() )
70  {
71  mElseRule = false;
72  mFilter.reset();
73  }
74  else
75  {
76  mElseRule = false;
77  mFilter = qgis::make_unique< QgsExpression >( mFilterExp );
78  }
79 }
80 
82 {
83  mChildren.append( rule );
84  rule->mParent = this;
85  updateElseRules();
86 }
87 
89 {
90  mChildren.insert( i, rule );
91  rule->mParent = this;
92  updateElseRules();
93 }
94 
96 {
97  mChildren.removeAll( rule );
98  delete rule;
99  updateElseRules();
100 }
101 
103 {
104  delete mChildren.takeAt( i );
105  updateElseRules();
106 }
107 
109 {
110  mChildren.removeAll( rule );
111  rule->mParent = nullptr;
112  updateElseRules();
113  return rule;
114 }
115 
117 {
118  Rule *rule = mChildren.takeAt( i );
119  rule->mParent = nullptr;
120  updateElseRules();
121  return rule;
122 }
123 
125 {
126  // we could use a hash / map for search if this will be slow...
127 
128  if ( key == mRuleKey )
129  return this;
130 
131  const auto constMChildren = mChildren;
132  for ( Rule *rule : constMChildren )
133  {
134  Rule *r = rule->findRuleByKey( key );
135  if ( r )
136  return r;
137  }
138  return nullptr;
139 }
140 
141 void QgsRuleBasedRenderer::Rule::updateElseRules()
142 {
143  mElseRules.clear();
144  const auto constMChildren = mChildren;
145  for ( Rule *rule : constMChildren )
146  {
147  if ( rule->isElse() )
148  mElseRules << rule;
149  }
150 }
151 
153 {
154  mFilterExp = QStringLiteral( "ELSE" );
155  mElseRule = iselse;
156  mFilter.reset();
157 }
158 
160 {
161  // NOTE: if visitEnter returns false it means "don't visit the rule", not "abort all further visitations"
163  return true;
164 
165  if ( mSymbol )
166  {
167  QgsStyleSymbolEntity entity( mSymbol.get() );
168  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
169  return false;
170  }
171 
172  if ( !mChildren.empty() )
173  {
174  for ( const Rule *rule : mChildren )
175  {
176 
177  if ( !rule->accept( visitor ) )
178  return false;
179  }
180  }
181 
183  return false;
184 
185  return true;
186 }
187 
188 QString QgsRuleBasedRenderer::Rule::dump( int indent ) const
189 {
190  QString off;
191  off.fill( QChar( ' ' ), indent );
192  QString symbolDump = ( mSymbol ? mSymbol->dump() : QStringLiteral( "[]" ) );
193  QString msg = off + QStringLiteral( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
194  .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
195  .arg( mFilterExp, symbolDump );
196 
197  QStringList lst;
198  const auto constMChildren = mChildren;
199  for ( Rule *rule : constMChildren )
200  {
201  lst.append( rule->dump( indent + 2 ) );
202  }
203  msg += lst.join( QLatin1Char( '\n' ) );
204  return msg;
205 }
206 
208 {
209  // attributes needed by this rule
210  QSet<QString> attrs;
211  if ( mFilter )
212  attrs.unite( mFilter->referencedColumns() );
213  if ( mSymbol )
214  attrs.unite( mSymbol->usedAttributes( context ) );
215 
216  // attributes needed by child rules
217  const auto constMChildren = mChildren;
218  for ( Rule *rule : constMChildren )
219  {
220  attrs.unite( rule->usedAttributes( context ) );
221  }
222  return attrs;
223 }
224 
226 {
227  if ( mFilter && mFilter->needsGeometry() )
228  return true;
229 
230  const auto constMChildren = mChildren;
231  for ( Rule *rule : constMChildren )
232  {
233  if ( rule->needsGeometry() )
234  return true;
235  }
236 
237  return false;
238 }
239 
241 {
242  QgsSymbolList lst;
243  if ( mSymbol )
244  lst.append( mSymbol.get() );
245 
246  const auto constMChildren = mChildren;
247  for ( Rule *rule : constMChildren )
248  {
249  lst += rule->symbols( context );
250  }
251  return lst;
252 }
253 
255 {
256  mSymbol.reset( sym );
257 }
258 
259 void QgsRuleBasedRenderer::Rule::setFilterExpression( const QString &filterExp )
260 {
261  mFilterExp = filterExp;
262  initFilter();
263 }
264 
266 {
268  if ( currentLevel != -1 ) // root rule should not be shown
269  {
270  lst << QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey, true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
271  }
272 
273  for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
274  {
275  Rule *rule = *it;
276  lst << rule->legendSymbolItems( currentLevel + 1 );
277  }
278  return lst;
279 }
280 
281 
283 {
284  if ( ! mFilter || mElseRule || ! context )
285  return true;
286 
287  context->expressionContext().setFeature( f );
288  QVariant res = mFilter->evaluate( &context->expressionContext() );
289  return res.toBool();
290 }
291 
292 bool QgsRuleBasedRenderer::Rule::isScaleOK( double scale ) const
293 {
294  if ( qgsDoubleNear( scale, 0.0 ) ) // so that we can count features in classes without scale context
295  return true;
296  if ( qgsDoubleNear( mMaximumScale, 0.0 ) && qgsDoubleNear( mMinimumScale, 0.0 ) )
297  return true;
298  if ( !qgsDoubleNear( mMaximumScale, 0.0 ) && mMaximumScale > scale )
299  return false;
300  if ( !qgsDoubleNear( mMinimumScale, 0.0 ) && mMinimumScale < scale )
301  return false;
302  return true;
303 }
304 
306 {
307  QgsSymbol *sym = mSymbol ? mSymbol->clone() : nullptr;
308  Rule *newrule = new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
309  newrule->setActive( mIsActive );
310  // clone children
311  const auto constMChildren = mChildren;
312  for ( Rule *rule : constMChildren )
313  newrule->appendChild( rule->clone() );
314  return newrule;
315 }
316 
317 QDomElement QgsRuleBasedRenderer::Rule::save( QDomDocument &doc, QgsSymbolMap &symbolMap ) const
318 {
319  QDomElement ruleElem = doc.createElement( QStringLiteral( "rule" ) );
320 
321  if ( mSymbol )
322  {
323  int symbolIndex = symbolMap.size();
324  symbolMap[QString::number( symbolIndex )] = mSymbol.get();
325  ruleElem.setAttribute( QStringLiteral( "symbol" ), symbolIndex );
326  }
327  if ( !mFilterExp.isEmpty() )
328  ruleElem.setAttribute( QStringLiteral( "filter" ), mFilterExp );
329  if ( mMaximumScale != 0 )
330  ruleElem.setAttribute( QStringLiteral( "scalemindenom" ), mMaximumScale );
331  if ( mMinimumScale != 0 )
332  ruleElem.setAttribute( QStringLiteral( "scalemaxdenom" ), mMinimumScale );
333  if ( !mLabel.isEmpty() )
334  ruleElem.setAttribute( QStringLiteral( "label" ), mLabel );
335  if ( !mDescription.isEmpty() )
336  ruleElem.setAttribute( QStringLiteral( "description" ), mDescription );
337  if ( !mIsActive )
338  ruleElem.setAttribute( QStringLiteral( "checkstate" ), 0 );
339  ruleElem.setAttribute( QStringLiteral( "key" ), mRuleKey );
340 
341  const auto constMChildren = mChildren;
342  for ( Rule *rule : constMChildren )
343  {
344  ruleElem.appendChild( rule->save( doc, symbolMap ) );
345  }
346  return ruleElem;
347 }
348 
349 void QgsRuleBasedRenderer::Rule::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
350 {
351  // do not convert this rule if there are no symbols
352  QgsRenderContext context;
353  if ( symbols( context ).isEmpty() )
354  return;
355 
356  if ( !mFilterExp.isEmpty() )
357  {
358  if ( !props.value( QStringLiteral( "filter" ), QString() ).isEmpty() )
359  props[ QStringLiteral( "filter" )] += QLatin1String( " AND " );
360  props[ QStringLiteral( "filter" )] += mFilterExp;
361  }
362 
363  QgsSymbolLayerUtils::mergeScaleDependencies( mMaximumScale, mMinimumScale, props );
364 
365  if ( mSymbol )
366  {
367  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
368  element.appendChild( ruleElem );
369 
370  //XXX: <se:Name> is the rule identifier, but our the Rule objects
371  // have no properties could be used as identifier. Use the label.
372  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
373  nameElem.appendChild( doc.createTextNode( mLabel ) );
374  ruleElem.appendChild( nameElem );
375 
376  if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
377  {
378  QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
379  if ( !mLabel.isEmpty() )
380  {
381  QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
382  titleElem.appendChild( doc.createTextNode( mLabel ) );
383  descrElem.appendChild( titleElem );
384  }
385  if ( !mDescription.isEmpty() )
386  {
387  QDomElement abstractElem = doc.createElement( QStringLiteral( "se:Abstract" ) );
388  abstractElem.appendChild( doc.createTextNode( mDescription ) );
389  descrElem.appendChild( abstractElem );
390  }
391  ruleElem.appendChild( descrElem );
392  }
393 
394  if ( !props.value( QStringLiteral( "filter" ), QString() ).isEmpty() )
395  {
396  QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, props.value( QStringLiteral( "filter" ), QString() ) );
397  }
398 
399  QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, props );
400 
401  mSymbol->toSld( doc, ruleElem, props );
402  }
403 
404  // loop into children rule list
405  const auto constMChildren = mChildren;
406  for ( Rule *rule : constMChildren )
407  {
408  rule->toSld( doc, element, props );
409  }
410 }
411 
413 {
414  mActiveChildren.clear();
415 
416  if ( ! mIsActive )
417  return false;
418 
419  // filter out rules which are not compatible with this scale
420  if ( !isScaleOK( context.rendererScale() ) )
421  return false;
422 
423  // init this rule
424  if ( mFilter )
425  mFilter->prepare( &context.expressionContext() );
426  if ( mSymbol )
427  mSymbol->startRender( context, fields );
428 
429  // init children
430  // build temporary list of active rules (usable with this scale)
431  QStringList subfilters;
432  const auto constMChildren = mChildren;
433  for ( Rule *rule : constMChildren )
434  {
435  QString subfilter;
436  if ( rule->startRender( context, fields, subfilter ) )
437  {
438  // only add those which are active with current scale
439  mActiveChildren.append( rule );
440  subfilters.append( subfilter );
441  }
442  }
443 
444  // subfilters (on the same level) are joined with OR
445  // Finally they are joined with their parent (this) with AND
446  QString sf;
447  // If there are subfilters present (and it's not a single empty one), group them and join them with OR
448  if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
449  {
450  if ( subfilters.contains( QStringLiteral( "TRUE" ) ) )
451  {
452  sf = QStringLiteral( "TRUE" );
453  }
454  // If we have more than 50 rules (to stay on the safe side) make a binary tree or SQLITE will fail,
455  // see: https://github.com/qgis/QGIS/issues/27269
456  else if ( subfilters.count() > 50 )
457  {
458  std::function<QString( const QStringList & )>bt = [ &bt ]( const QStringList & subf )
459  {
460  if ( subf.count( ) == 1 )
461  {
462  return subf.at( 0 );
463  }
464  else if ( subf.count( ) == 2 )
465  {
466  return subf.join( QLatin1String( ") OR (" ) ).prepend( '(' ).append( ')' );
467  }
468  else
469  {
470  int midpos = static_cast<int>( subf.length() / 2 );
471  return QStringLiteral( "(%1) OR (%2)" ).arg( bt( subf.mid( 0, midpos ) ) ).arg( bt( subf.mid( midpos ) ) );
472  }
473  };
474  sf = bt( subfilters );
475  }
476  else
477  {
478  sf = subfilters.join( QLatin1String( ") OR (" ) ).prepend( '(' ).append( ')' );
479  }
480  }
481 
482  // Now join the subfilters with their parent (this) based on if
483  // * The parent is an else rule
484  // * The existence of parent filter and subfilters
485 
486  // No filter expression: ELSE rule or catchall rule
487  if ( !mFilter )
488  {
489  if ( mSymbol || sf.isEmpty() )
490  filter = QStringLiteral( "TRUE" );
491  else
492  filter = sf;
493  }
494  else if ( mSymbol )
495  filter = mFilterExp;
496  else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
497  filter = QStringLiteral( "(%1) AND (%2)" ).arg( mFilterExp, sf );
498  else if ( !mFilterExp.trimmed().isEmpty() )
499  filter = mFilterExp;
500  else if ( sf.isEmpty() )
501  filter = QStringLiteral( "TRUE" );
502  else
503  filter = sf;
504 
505  filter = filter.trimmed();
506 
507  return true;
508 }
509 
511 {
512  QSet<int> symbolZLevelsSet;
513 
514  // process this rule
515  if ( mSymbol )
516  {
517  // find out which Z-levels are used
518  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
519  {
520  symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
521  }
522  }
523 
524  // process children
525  QList<Rule *>::iterator it;
526  for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
527  {
528  Rule *rule = *it;
529  symbolZLevelsSet.unite( rule->collectZLevels() );
530  }
531  return symbolZLevelsSet;
532 }
533 
534 void QgsRuleBasedRenderer::Rule::setNormZLevels( const QMap<int, int> &zLevelsToNormLevels )
535 {
536  if ( mSymbol )
537  {
538  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
539  {
540  int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
541  mSymbolNormZLevels.insert( normLevel );
542  }
543  }
544 
545  // prepare list of normalized levels for each rule
546  const auto constMActiveChildren = mActiveChildren;
547  for ( Rule *rule : constMActiveChildren )
548  {
549  rule->setNormZLevels( zLevelsToNormLevels );
550  }
551 }
552 
553 
555 {
556  if ( !isFilterOK( featToRender.feat, &context ) )
557  return Filtered;
558 
559  bool rendered = false;
560 
561  // create job for this feature and this symbol, add to list of jobs
562  if ( mSymbol && mIsActive )
563  {
564  // add job to the queue: each symbol's zLevel must be added
565  const auto constMSymbolNormZLevels = mSymbolNormZLevels;
566  for ( int normZLevel : constMSymbolNormZLevels )
567  {
568  //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
569  renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol.get() ) );
570  rendered = true;
571  }
572  }
573 
574  bool willrendersomething = false;
575 
576  // process children
577  const auto constMChildren = mChildren;
578  for ( Rule *rule : constMChildren )
579  {
580  // Don't process else rules yet
581  if ( !rule->isElse() )
582  {
583  RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
584  // consider inactive items as "rendered" so the else rule will ignore them
585  willrendersomething |= ( res == Rendered || res == Inactive );
586  rendered |= ( res == Rendered );
587  }
588  }
589 
590  // If none of the rules passed then we jump into the else rules and process them.
591  if ( !willrendersomething )
592  {
593  const auto constMElseRules = mElseRules;
594  for ( Rule *rule : constMElseRules )
595  {
596  rendered |= rule->renderFeature( featToRender, context, renderQueue ) == Rendered;
597  }
598  }
599  if ( !mIsActive || ( mSymbol && !rendered ) )
600  return Inactive;
601  else if ( rendered )
602  return Rendered;
603  else
604  return Filtered;
605 }
606 
608 {
609  if ( !isFilterOK( feature, context ) )
610  return false;
611 
612  if ( mSymbol )
613  return true;
614 
615  const auto constMActiveChildren = mActiveChildren;
616  for ( Rule *rule : constMActiveChildren )
617  {
618  if ( rule->isElse() )
619  {
620  if ( rule->children().isEmpty() )
621  {
622  RuleList lst = rulesForFeature( feature, context, false );
623  lst.removeOne( rule );
624 
625  if ( lst.empty() )
626  {
627  return true;
628  }
629  }
630  else
631  {
632  return rule->willRenderFeature( feature, context );
633  }
634  }
635  else if ( rule->willRenderFeature( feature, context ) )
636  {
637  return true;
638  }
639  }
640  return false;
641 }
642 
644 {
645  QgsSymbolList lst;
646  if ( !isFilterOK( feature, context ) )
647  return lst;
648  if ( mSymbol )
649  lst.append( mSymbol.get() );
650 
651  const auto constMActiveChildren = mActiveChildren;
652  for ( Rule *rule : constMActiveChildren )
653  {
654  lst += rule->symbolsForFeature( feature, context );
655  }
656  return lst;
657 }
658 
660 {
661  QSet< QString> lst;
662  if ( !isFilterOK( feature, context ) )
663  return lst;
664  lst.insert( mRuleKey );
665 
666  const auto constMActiveChildren = mActiveChildren;
667  for ( Rule *rule : constMActiveChildren )
668  {
669  bool validKey = false;
670  if ( rule->isElse() )
671  {
672  RuleList lst = rulesForFeature( feature, context, false );
673  lst.removeOne( rule );
674 
675  if ( lst.empty() )
676  {
677  validKey = true;
678  }
679  }
680  else if ( !rule->isElse( ) && rule->willRenderFeature( feature, context ) )
681  {
682  validKey = true;
683  }
684 
685  if ( validKey )
686  {
687  lst.unite( rule->legendKeysForFeature( feature, context ) );
688  }
689  }
690  return lst;
691 }
692 
694 {
695  RuleList lst;
696  if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->rendererScale() ) ) )
697  return lst;
698 
699  if ( mSymbol )
700  lst.append( this );
701 
702  RuleList listChildren = children();
703  if ( onlyActive )
704  listChildren = mActiveChildren;
705 
706  const auto constListChildren = listChildren;
707  for ( Rule *rule : constListChildren )
708  {
709  lst += rule->rulesForFeature( feature, context, onlyActive );
710  }
711  return lst;
712 }
713 
715 {
716  if ( mSymbol )
717  mSymbol->stopRender( context );
718 
719  const auto constMActiveChildren = mActiveChildren;
720  for ( Rule *rule : constMActiveChildren )
721  {
722  rule->stopRender( context );
723  }
724 
725  mActiveChildren.clear();
726  mSymbolNormZLevels.clear();
727 }
728 
730 {
731  QString symbolIdx = ruleElem.attribute( QStringLiteral( "symbol" ) );
732  QgsSymbol *symbol = nullptr;
733  if ( !symbolIdx.isEmpty() )
734  {
735  if ( symbolMap.contains( symbolIdx ) )
736  {
737  symbol = symbolMap.take( symbolIdx );
738  }
739  else
740  {
741  QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
742  }
743  }
744 
745  QString filterExp = ruleElem.attribute( QStringLiteral( "filter" ) );
746  QString label = ruleElem.attribute( QStringLiteral( "label" ) );
747  QString description = ruleElem.attribute( QStringLiteral( "description" ) );
748  int scaleMinDenom = ruleElem.attribute( QStringLiteral( "scalemindenom" ), QStringLiteral( "0" ) ).toInt();
749  int scaleMaxDenom = ruleElem.attribute( QStringLiteral( "scalemaxdenom" ), QStringLiteral( "0" ) ).toInt();
750  QString ruleKey = ruleElem.attribute( QStringLiteral( "key" ) );
751  Rule *rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
752 
753  if ( !ruleKey.isEmpty() )
754  rule->mRuleKey = ruleKey;
755 
756  rule->setActive( ruleElem.attribute( QStringLiteral( "checkstate" ), QStringLiteral( "1" ) ).toInt() );
757 
758  QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral( "rule" ) );
759  while ( !childRuleElem.isNull() )
760  {
761  Rule *childRule = create( childRuleElem, symbolMap );
762  if ( childRule )
763  {
764  rule->appendChild( childRule );
765  }
766  else
767  {
768  QgsDebugMsg( QStringLiteral( "failed to init a child rule!" ) );
769  }
770  childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral( "rule" ) );
771  }
772 
773  return rule;
774 }
775 
777 {
778  RuleList l;
779  for ( QgsRuleBasedRenderer::Rule *c : mChildren )
780  {
781  l += c;
782  l += c->descendants();
783  }
784  return l;
785 }
786 
788 {
789  if ( ruleElem.localName() != QLatin1String( "Rule" ) )
790  {
791  QgsDebugMsg( QStringLiteral( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
792  return nullptr;
793  }
794 
795  QString label, description, filterExp;
796  int scaleMinDenom = 0, scaleMaxDenom = 0;
797  QgsSymbolLayerList layers;
798 
799  // retrieve the Rule element child nodes
800  QDomElement childElem = ruleElem.firstChildElement();
801  while ( !childElem.isNull() )
802  {
803  if ( childElem.localName() == QLatin1String( "Name" ) )
804  {
805  // <se:Name> tag contains the rule identifier,
806  // so prefer title tag for the label property value
807  if ( label.isEmpty() )
808  label = childElem.firstChild().nodeValue();
809  }
810  else if ( childElem.localName() == QLatin1String( "Description" ) )
811  {
812  // <se:Description> can contains a title and an abstract
813  QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
814  if ( !titleElem.isNull() )
815  {
816  label = titleElem.firstChild().nodeValue();
817  }
818 
819  QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
820  if ( !abstractElem.isNull() )
821  {
822  description = abstractElem.firstChild().nodeValue();
823  }
824  }
825  else if ( childElem.localName() == QLatin1String( "Abstract" ) )
826  {
827  // <sld:Abstract> (v1.0)
828  description = childElem.firstChild().nodeValue();
829  }
830  else if ( childElem.localName() == QLatin1String( "Title" ) )
831  {
832  // <sld:Title> (v1.0)
833  label = childElem.firstChild().nodeValue();
834  }
835  else if ( childElem.localName() == QLatin1String( "Filter" ) )
836  {
838  if ( filter )
839  {
840  if ( filter->hasParserError() )
841  {
842  QgsDebugMsg( "parser error: " + filter->parserErrorString() );
843  }
844  else
845  {
846  filterExp = filter->expression();
847  }
848  delete filter;
849  }
850  }
851  else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
852  {
853  bool ok;
854  int v = childElem.firstChild().nodeValue().toInt( &ok );
855  if ( ok )
856  scaleMinDenom = v;
857  }
858  else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
859  {
860  bool ok;
861  int v = childElem.firstChild().nodeValue().toInt( &ok );
862  if ( ok )
863  scaleMaxDenom = v;
864  }
865  else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
866  {
867  // create symbol layers for this symbolizer
868  QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
869  }
870 
871  childElem = childElem.nextSiblingElement();
872  }
873 
874  // now create the symbol
875  QgsSymbol *symbol = nullptr;
876  if ( !layers.isEmpty() )
877  {
878  switch ( geomType )
879  {
881  symbol = new QgsLineSymbol( layers );
882  break;
883 
885  symbol = new QgsFillSymbol( layers );
886  break;
887 
889  symbol = new QgsMarkerSymbol( layers );
890  break;
891 
892  default:
893  QgsDebugMsg( QStringLiteral( "invalid geometry type: found %1" ).arg( geomType ) );
894  return nullptr;
895  }
896  }
897 
898  // and then create and return the new rule
899  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
900 }
901 
902 
904 
906  : QgsFeatureRenderer( QStringLiteral( "RuleRenderer" ) )
907  , mRootRule( root )
908 {
909 }
910 
912  : QgsFeatureRenderer( QStringLiteral( "RuleRenderer" ) )
913 {
914  mRootRule = new Rule( nullptr ); // root has no symbol, no filter etc - just a container
915  mRootRule->appendChild( new Rule( defaultSymbol ) );
916 }
917 
919 {
920  delete mRootRule;
921 }
922 
923 
925 {
926  // not used at all
927  return nullptr;
928 }
929 
931  QgsRenderContext &context,
932  int layer,
933  bool selected,
934  bool drawVertexMarker )
935 {
936  Q_UNUSED( layer )
937 
938  int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
939  mCurrentFeatures.append( FeatureToRender( feature, flags ) );
940 
941  // check each active rule
942  return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue ) == Rule::Rendered;
943 }
944 
945 
947 {
948  QgsFeatureRenderer::startRender( context, fields );
949 
950  // prepare active children
951  mRootRule->startRender( context, fields, mFilter );
952 
953  QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
954  QList<int> symbolZLevels = qgis::setToList( symbolZLevelsSet );
955  std::sort( symbolZLevels.begin(), symbolZLevels.end() );
956 
957  // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
958  // and prepare rendering queue
959  QMap<int, int> zLevelsToNormLevels;
960  int maxNormLevel = -1;
961  const auto constSymbolZLevels = symbolZLevels;
962  for ( int zLevel : constSymbolZLevels )
963  {
964  zLevelsToNormLevels[zLevel] = ++maxNormLevel;
965  mRenderQueue.append( RenderLevel( zLevel ) );
966  QgsDebugMsgLevel( QStringLiteral( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
967  }
968 
969  mRootRule->setNormZLevels( zLevelsToNormLevels );
970 }
971 
973 {
975 
976  //
977  // do the actual rendering
978  //
979 
980  // go through all levels
981  if ( !context.renderingStopped() )
982  {
983  const auto constMRenderQueue = mRenderQueue;
984  for ( const RenderLevel &level : constMRenderQueue )
985  {
986  //QgsDebugMsg(QString("level %1").arg(level.zIndex));
987  // go through all jobs at the level
988  for ( const RenderJob *job : qgis::as_const( level.jobs ) )
989  {
990  context.expressionContext().setFeature( job->ftr.feat );
991  //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
992  // render feature - but only with symbol layers with specified zIndex
993  QgsSymbol *s = job->symbol;
994  int count = s->symbolLayerCount();
995  for ( int i = 0; i < count; i++ )
996  {
997  // TODO: better solution for this
998  // renderFeatureWithSymbol asks which symbol layer to draw
999  // but there are multiple transforms going on!
1000  if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
1001  {
1002  int flags = job->ftr.flags;
1003  renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
1004  }
1005  }
1006  }
1007  }
1008  }
1009 
1010  // clean current features
1011  mCurrentFeatures.clear();
1012 
1013  // clean render queue
1014  mRenderQueue.clear();
1015 
1016  // clean up rules from temporary stuff
1017  mRootRule->stopRender( context );
1018 }
1019 
1021 {
1022  return mFilter;
1023 }
1024 
1025 QSet<QString> QgsRuleBasedRenderer::usedAttributes( const QgsRenderContext &context ) const
1026 {
1027  return mRootRule->usedAttributes( context );
1028 }
1029 
1031 {
1032  return mRootRule->needsGeometry();
1033 }
1034 
1036 {
1037  QgsRuleBasedRenderer::Rule *clonedRoot = mRootRule->clone();
1038 
1039  // normally with clone() the individual rules get new keys (UUID), but here we want to keep
1040  // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. map themes)
1041  clonedRoot->setRuleKey( mRootRule->ruleKey() );
1042  RuleList origDescendants = mRootRule->descendants();
1043  RuleList clonedDescendants = clonedRoot->descendants();
1044  Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
1045  for ( int i = 0; i < origDescendants.count(); ++i )
1046  clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
1047 
1048  QgsRuleBasedRenderer *r = new QgsRuleBasedRenderer( clonedRoot );
1049 
1051  copyRendererData( r );
1052  return r;
1053 }
1054 
1055 void QgsRuleBasedRenderer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
1056 {
1057  mRootRule->toSld( doc, element, props );
1058 }
1059 
1060 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
1062 {
1063  return mRootRule->symbols( context );
1064 }
1065 
1066 QDomElement QgsRuleBasedRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
1067 {
1068  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1069  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "RuleRenderer" ) );
1070  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
1071  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
1072 
1074 
1075  QDomElement rulesElem = mRootRule->save( doc, symbols );
1076  rulesElem.setTagName( QStringLiteral( "rules" ) ); // instead of just "rule"
1077  rendererElem.appendChild( rulesElem );
1078 
1079  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
1080  rendererElem.appendChild( symbolsElem );
1081 
1083  mPaintEffect->saveProperties( doc, rendererElem );
1084 
1085  if ( !mOrderBy.isEmpty() )
1086  {
1087  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
1088  mOrderBy.save( orderBy );
1089  rendererElem.appendChild( orderBy );
1090  }
1091  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
1092 
1093  return rendererElem;
1094 }
1095 
1097 {
1098  return true;
1099 }
1100 
1102 {
1103  Rule *rule = mRootRule->findRuleByKey( key );
1104  return rule ? rule->active() : true;
1105 }
1106 
1107 void QgsRuleBasedRenderer::checkLegendSymbolItem( const QString &key, bool state )
1108 {
1109  Rule *rule = mRootRule->findRuleByKey( key );
1110  if ( rule )
1111  rule->setActive( state );
1112 }
1113 
1114 void QgsRuleBasedRenderer::setLegendSymbolItem( const QString &key, QgsSymbol *symbol )
1115 {
1116  Rule *rule = mRootRule->findRuleByKey( key );
1117  if ( rule )
1118  rule->setSymbol( symbol );
1119  else
1120  delete symbol;
1121 }
1122 
1124 {
1125  return mRootRule->legendSymbolItems();
1126 }
1127 
1128 
1130 {
1131  // load symbols
1132  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
1133  if ( symbolsElem.isNull() )
1134  return nullptr;
1135 
1136  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
1137 
1138  QDomElement rulesElem = element.firstChildElement( QStringLiteral( "rules" ) );
1139 
1140  Rule *root = Rule::create( rulesElem, symbolMap );
1141  if ( !root )
1142  return nullptr;
1143 
1144  QgsRuleBasedRenderer *r = new QgsRuleBasedRenderer( root );
1145 
1146  // delete symbols if there are any more
1148 
1149  return r;
1150 }
1151 
1153 {
1154  // retrieve child rules
1155  Rule *root = nullptr;
1156 
1157  QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) );
1158  while ( !ruleElem.isNull() )
1159  {
1160  Rule *child = Rule::createFromSld( ruleElem, geomType );
1161  if ( child )
1162  {
1163  // create the root rule if not done before
1164  if ( !root )
1165  root = new Rule( nullptr );
1166 
1167  root->appendChild( child );
1168  }
1169 
1170  ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
1171  }
1172 
1173  if ( !root )
1174  {
1175  // no valid rules was found
1176  return nullptr;
1177  }
1178 
1179  // create and return the new renderer
1180  return new QgsRuleBasedRenderer( root );
1181 }
1182 
1185 
1187 {
1188  QString attr = r->classAttribute();
1189  // categorizedAttr could be either an attribute name or an expression.
1190  // the only way to differentiate is to test it as an expression...
1191  QgsExpression testExpr( attr );
1192  if ( testExpr.hasParserError() || ( testExpr.isField() && !attr.startsWith( '\"' ) ) )
1193  {
1194  //not an expression, so need to quote column name
1195  attr = QgsExpression::quotedColumnRef( attr );
1196  }
1197 
1198  const auto constCategories = r->categories();
1199  for ( const QgsRendererCategory &cat : constCategories )
1200  {
1201  QString value;
1202  // not quoting numbers saves a type cast
1203  if ( cat.value().type() == QVariant::Int )
1204  value = cat.value().toString();
1205  else if ( cat.value().type() == QVariant::Double )
1206  // we loose precision here - so we may miss some categories :-(
1207  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1208  value = QString::number( cat.value().toDouble(), 'f', 4 );
1209  else
1210  value = QgsExpression::quotedString( cat.value().toString() );
1211  QString filter = QStringLiteral( "%1 = %2" ).arg( attr, value );
1212  QString label = filter;
1213  initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
1214  }
1215 }
1216 
1218 {
1219  QString attr = r->classAttribute();
1220  // categorizedAttr could be either an attribute name or an expression.
1221  // the only way to differentiate is to test it as an expression...
1222  QgsExpression testExpr( attr );
1223  if ( testExpr.hasParserError() || ( testExpr.isField() && !attr.startsWith( '\"' ) ) )
1224  {
1225  //not an expression, so need to quote column name
1226  attr = QgsExpression::quotedColumnRef( attr );
1227  }
1228  else if ( !testExpr.isField() )
1229  {
1230  //otherwise wrap expression in brackets
1231  attr = QStringLiteral( "(%1)" ).arg( attr );
1232  }
1233 
1234  bool firstRange = true;
1235  const auto constRanges = r->ranges();
1236  for ( const QgsRendererRange &rng : constRanges )
1237  {
1238  // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
1239  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1240  QString filter = QStringLiteral( "%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
1241  QString::number( rng.lowerValue(), 'f', 4 ),
1242  QString::number( rng.upperValue(), 'f', 4 ) );
1243  firstRange = false;
1244  QString label = rng.label().isEmpty() ? filter : rng.label();
1245  initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
1246  }
1247 }
1248 
1250 {
1251  std::sort( scales.begin(), scales.end() ); // make sure the scales are in ascending order
1252  double oldScale = initialRule->maximumScale();
1253  double maxDenom = initialRule->minimumScale();
1254  QgsSymbol *symbol = initialRule->symbol();
1255  const auto constScales = scales;
1256  for ( int scale : constScales )
1257  {
1258  if ( initialRule->maximumScale() >= scale )
1259  continue; // jump over the first scales out of the interval
1260  if ( maxDenom != 0 && maxDenom <= scale )
1261  break; // ignore the latter scales out of the interval
1262  initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QStringLiteral( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1263  oldScale = scale;
1264  }
1265  // last rule
1266  initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QStringLiteral( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1267 }
1268 
1270 {
1271  QString msg( QStringLiteral( "Rule-based renderer:\n" ) );
1272  msg += mRootRule->dump();
1273  return msg;
1274 }
1275 
1277 {
1278  return mRootRule->willRenderFeature( feature, &context );
1279 }
1280 
1282 {
1283  return mRootRule->symbolsForFeature( feature, &context );
1284 }
1285 
1287 {
1288  return mRootRule->symbolsForFeature( feature, &context );
1289 }
1290 
1291 QSet< QString > QgsRuleBasedRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
1292 {
1293  return mRootRule->legendKeysForFeature( feature, &context );
1294 }
1295 
1297 {
1298  return mRootRule->accept( visitor );
1299 }
1300 
1302 {
1303  std::unique_ptr< QgsRuleBasedRenderer > r;
1304  if ( renderer->type() == QLatin1String( "RuleRenderer" ) )
1305  {
1306  r.reset( dynamic_cast<QgsRuleBasedRenderer *>( renderer->clone() ) );
1307  }
1308  else if ( renderer->type() == QLatin1String( "singleSymbol" ) )
1309  {
1310  const QgsSingleSymbolRenderer *singleSymbolRenderer = dynamic_cast<const QgsSingleSymbolRenderer *>( renderer );
1311  if ( !singleSymbolRenderer )
1312  return nullptr;
1313 
1314  std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->symbol()->clone() );
1315  r = qgis::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
1316  }
1317  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1318  {
1319  const QgsCategorizedSymbolRenderer *categorizedRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1320  if ( !categorizedRenderer )
1321  return nullptr;
1322 
1323  QString attr = categorizedRenderer->classAttribute();
1324  // categorizedAttr could be either an attribute name or an expression.
1325  // the only way to differentiate is to test it as an expression...
1326  QgsExpression testExpr( attr );
1327  if ( testExpr.hasParserError() || ( testExpr.isField() && !attr.startsWith( '\"' ) ) )
1328  {
1329  //not an expression, so need to quote column name
1330  attr = QgsExpression::quotedColumnRef( attr );
1331  }
1332 
1333  std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = qgis::make_unique< QgsRuleBasedRenderer::Rule >( nullptr );
1334 
1335  QString expression;
1336  QString value;
1337  QgsRendererCategory category;
1338  for ( const QgsRendererCategory &category : categorizedRenderer->categories() )
1339  {
1340  std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = qgis::make_unique< QgsRuleBasedRenderer::Rule >( nullptr );
1341 
1342  rule->setLabel( category.label() );
1343 
1344  //We first define the rule corresponding to the category
1345  if ( category.value().type() == QVariant::List )
1346  {
1347  QStringList values;
1348  const QVariantList list = category.value().toList();
1349  for ( const QVariant &v : list )
1350  {
1351  //If the value is a number, we can use it directly, otherwise we need to quote it in the rule
1352  if ( QVariant( v ).convert( QVariant::Double ) )
1353  {
1354  values << v.toString();
1355  }
1356  else
1357  {
1358  values << QgsExpression::quotedString( v.toString() );
1359  }
1360  }
1361 
1362  if ( values.empty() )
1363  {
1364  expression = QStringLiteral( "ELSE" );
1365  }
1366  else
1367  {
1368  expression = QStringLiteral( "%1 IN (%2)" ).arg( attr, values.join( ',' ) );
1369  }
1370  }
1371  else
1372  {
1373  //If the value is a number, we can use it directly, otherwise we need to quote it in the rule
1374  if ( category.value().convert( QVariant::Double ) )
1375  {
1376  value = category.value().toString();
1377  }
1378  else
1379  {
1380  value = QgsExpression::quotedString( category.value().toString() );
1381  }
1382 
1383  //An empty category is equivalent to the ELSE keyword
1384  if ( value == QLatin1String( "''" ) )
1385  {
1386  expression = QStringLiteral( "ELSE" );
1387  }
1388  else
1389  {
1390  expression = QStringLiteral( "%1 = %2" ).arg( attr, value );
1391  }
1392  }
1393  rule->setFilterExpression( expression );
1394 
1395  //Then we construct an equivalent symbol.
1396  //Ideally we could simply copy the symbol, but the categorized renderer allows a separate interface to specify
1397  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1398 
1399  std::unique_ptr< QgsSymbol > origSymbol( category.symbol()->clone() );
1400  rule->setSymbol( origSymbol.release() );
1401 
1402  rootrule->appendChild( rule.release() );
1403  }
1404 
1405  r = qgis::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1406  }
1407  else if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1408  {
1409  const QgsGraduatedSymbolRenderer *graduatedRenderer = dynamic_cast<const QgsGraduatedSymbolRenderer *>( renderer );
1410  if ( !graduatedRenderer )
1411  return nullptr;
1412 
1413  QString attr = graduatedRenderer->classAttribute();
1414  // categorizedAttr could be either an attribute name or an expression.
1415  // the only way to differentiate is to test it as an expression...
1416  QgsExpression testExpr( attr );
1417  if ( testExpr.hasParserError() || ( testExpr.isField() && !attr.startsWith( '\"' ) ) )
1418  {
1419  //not an expression, so need to quote column name
1420  attr = QgsExpression::quotedColumnRef( attr );
1421  }
1422  else if ( !testExpr.isField() )
1423  {
1424  //otherwise wrap expression in brackets
1425  attr = QStringLiteral( "(%1)" ).arg( attr );
1426  }
1427 
1428  std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = qgis::make_unique< QgsRuleBasedRenderer::Rule >( nullptr );
1429 
1430  QString expression;
1431  QgsRendererRange range;
1432  for ( int i = 0; i < graduatedRenderer->ranges().size(); ++i )
1433  {
1434  range = graduatedRenderer->ranges().value( i );
1435  std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = qgis::make_unique< QgsRuleBasedRenderer::Rule >( nullptr );
1436  rule->setLabel( range.label() );
1437  if ( i == 0 )//The lower boundary of the first range is included, while it is excluded for the others
1438  {
1439  expression = attr + " >= " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1440  attr + " <= " + QString::number( range.upperValue(), 'f' );
1441  }
1442  else
1443  {
1444  expression = attr + " > " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1445  attr + " <= " + QString::number( range.upperValue(), 'f' );
1446  }
1447  rule->setFilterExpression( expression );
1448 
1449  //Then we construct an equivalent symbol.
1450  //Ideally we could simply copy the symbol, but the graduated renderer allows a separate interface to specify
1451  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1452 
1453  std::unique_ptr< QgsSymbol > symbol( range.symbol()->clone() );
1454  rule->setSymbol( symbol.release() );
1455 
1456  rootrule->appendChild( rule.release() );
1457  }
1458 
1459  r = qgis::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1460  }
1461  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1462  {
1463  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1464  if ( pointDistanceRenderer )
1465  return convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
1466  }
1467  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1468  {
1469  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1470  if ( invertedPolygonRenderer )
1471  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1472  }
1473 
1474  if ( r )
1475  {
1476  r->setOrderBy( renderer->orderBy() );
1477  r->setOrderByEnabled( renderer->orderByEnabled() );
1478  }
1479 
1480  return r.release();
1481 }
1482 
1483 void QgsRuleBasedRenderer::convertToDataDefinedSymbology( QgsSymbol *symbol, const QString &sizeScaleField, const QString &rotationField )
1484 {
1485  QString sizeExpression;
1486  switch ( symbol->type() )
1487  {
1488  case QgsSymbol::Marker:
1489  for ( int j = 0; j < symbol->symbolLayerCount(); ++j )
1490  {
1491  QgsMarkerSymbolLayer *msl = static_cast<QgsMarkerSymbolLayer *>( symbol->symbolLayer( j ) );
1492  if ( ! sizeScaleField.isEmpty() )
1493  {
1494  sizeExpression = QStringLiteral( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1496  }
1497  if ( ! rotationField.isEmpty() )
1498  {
1500  }
1501  }
1502  break;
1503  case QgsSymbol::Line:
1504  if ( ! sizeScaleField.isEmpty() )
1505  {
1506  for ( int j = 0; j < symbol->symbolLayerCount(); ++j )
1507  {
1508  if ( symbol->symbolLayer( j )->layerType() == QLatin1String( "SimpleLine" ) )
1509  {
1510  QgsLineSymbolLayer *lsl = static_cast<QgsLineSymbolLayer *>( symbol->symbolLayer( j ) );
1511  sizeExpression = QStringLiteral( "%1*(%2)" ).arg( lsl->width() ).arg( sizeScaleField );
1513  }
1514  if ( symbol->symbolLayer( j )->layerType() == QLatin1String( "MarkerLine" ) )
1515  {
1516  QgsSymbol *marker = symbol->symbolLayer( j )->subSymbol();
1517  for ( int k = 0; k < marker->symbolLayerCount(); ++k )
1518  {
1519  QgsMarkerSymbolLayer *msl = static_cast<QgsMarkerSymbolLayer *>( marker->symbolLayer( k ) );
1520  sizeExpression = QStringLiteral( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1522  }
1523  }
1524  }
1525  }
1526  break;
1527  default:
1528  break;
1529  }
1530 }
QgsRuleBasedRenderer::Rule::create
static QgsRuleBasedRenderer::Rule * create(QDomElement &ruleElem, QgsSymbolMap &symbolMap)
Create a rule from an XML definition.
Definition: qgsrulebasedrenderer.cpp:729
QgsRuleBasedRenderer::Rule::willRenderFeature
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
only tell whether a feature will be rendered without actually rendering it
Definition: qgsrulebasedrenderer.cpp:607
QgsLineSymbolLayer
Definition: qgssymbollayer.h:901
QgsFeatureRenderer::copyRendererData
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:49
QgsFeatureRenderer::mOrderByEnabled
bool mOrderByEnabled
Definition: qgsrenderer.h:547
QgsRuleBasedRenderer::Rule::save
QDomElement save(QDomDocument &doc, QgsSymbolMap &symbolMap) const
Definition: qgsrulebasedrenderer.cpp:317
QgsFeatureRenderer::mForceRaster
bool mForceRaster
Definition: qgsrenderer.h:531
QgsProperty::fromField
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
Definition: qgsproperty.cpp:220
QgsExpression::quotedString
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
Definition: qgsexpression.cpp:70
QgsOgcUtils::expressionFromOgcFilter
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
Definition: qgsogcutils.cpp:1648
QgsRuleBasedRenderer::Rule::needsGeometry
bool needsGeometry() const
Returns true if this rule or one of its children needs the geometry to be applied.
Definition: qgsrulebasedrenderer.cpp:225
QgsFeatureRenderer::mPaintEffect
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:529
QgsSymbolLayerUtils::loadSymbols
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
Definition: qgssymbollayerutils.cpp:2946
QgsMarkerSymbolLayer::size
double size() const
Returns the symbol size.
Definition: qgssymbollayer.h:661
QgsRuleBasedRenderer
When drawing a vector layer with rule-based renderer, it goes through the rules and draws features wi...
Definition: qgsrulebasedrenderer.h:38
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:596
QgsRuleBasedRenderer::Rule::isFilterOK
bool isFilterOK(const QgsFeature &f, QgsRenderContext *context=nullptr) const
Check if a given feature shall be rendered by this rule.
Definition: qgsrulebasedrenderer.cpp:282
QgsRendererRange::label
QString label() const
Definition: qgsrendererrange.cpp:83
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsLineSymbolLayer::width
virtual double width() const
Returns the estimated width for the line symbol layer.
Definition: qgssymbollayer.h:965
qgscategorizedsymbolrenderer.h
QgsGraduatedSymbolRenderer::classAttribute
QString classAttribute() const
Definition: qgsgraduatedsymbolrenderer.h:56
QgsRuleBasedRenderer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
Definition: qgsrulebasedrenderer.cpp:1025
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgssinglesymbolrenderer.h
QgsFeatureRequest::OrderBy::save
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
Definition: qgsfeaturerequest.cpp:448
QgsRuleBasedRenderer::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
Definition: qgsrulebasedrenderer.cpp:1296
QgsStyleSymbolEntity
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1201
QgsRuleBasedRenderer::symbols
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
Definition: qgsrulebasedrenderer.cpp:1061
qgsexpression.h
QgsRuleBasedRenderer::checkLegendSymbolItem
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
Definition: qgsrulebasedrenderer.cpp:1107
QgsRuleBasedRenderer::Rule::stopRender
void stopRender(QgsRenderContext &context)
Stop a rendering process.
Definition: qgsrulebasedrenderer.cpp:714
QgsRuleBasedRenderer::save
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
Definition: qgsrulebasedrenderer.cpp:1066
QgsSymbolMap
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QgsRuleBasedRenderer::Rule::startRender
bool startRender(QgsRenderContext &context, const QgsFields &fields, QString &filter)
prepare the rule for rendering and its children (build active children array)
Definition: qgsrulebasedrenderer.cpp:412
QgsCategorizedSymbolRenderer::categories
const QgsCategoryList & categories() const
Returns a list of all categories recognized by the renderer.
Definition: qgscategorizedsymbolrenderer.h:191
qgssymbollayerutils.h
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsRuleBasedRenderer::Rule::collectZLevels
QSet< int > collectZLevels()
Gets all used z-levels from this rule and children.
Definition: qgsrulebasedrenderer.cpp:510
QgsRendererRange::symbol
QgsSymbol * symbol() const
Definition: qgsrendererrange.cpp:78
QgsRendererRange
Definition: qgsrendererrange.h:37
QgsFeatureRenderer::renderFeatureWithSymbol
void renderFeatureWithSymbol(const QgsFeature &feature, QgsSymbol *symbol, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker) SIP_THROW(QgsCsException)
Render the feature with the symbol using context.
Definition: qgsrenderer.cpp:133
QgsRuleBasedRenderer::legendSymbolItems
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
Definition: qgsrulebasedrenderer.cpp:1123
QgsFeatureRenderer::type
QString type() const
Definition: qgsrenderer.h:141
QgsRendererCategory
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
Definition: qgscategorizedsymbolrenderer.h:36
QgsRuleBasedRenderer::setLegendSymbolItem
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
Definition: qgsrulebasedrenderer.cpp:1114
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g.
Definition: qgsstyleentityvisitor.h:34
QgsRuleBasedRenderer::Rule::dump
QString dump(int indent=0) const
Dump for debug purpose.
Definition: qgsrulebasedrenderer.cpp:188
QgsStyleEntityVisitorInterface::visitExit
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
Definition: qgsstyleentityvisitor.h:183
QgsSingleSymbolRenderer
Definition: qgssinglesymbolrenderer.h:30
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:582
QgsRuleBasedRenderer::Rule::ruleKey
QString ruleKey() const
Unique rule identifier (for identification of rule within renderer)
Definition: qgsrulebasedrenderer.h:253
qgspainteffectregistry.h
QgsRendererRange::lowerValue
double lowerValue() const
Definition: qgsrendererrange.cpp:68
QgsRuleBasedRenderer::Rule::symbolsForFeature
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
tell which symbols will be used to render the feature
Definition: qgsrulebasedrenderer.cpp:643
QgsRuleBasedRenderer::willRenderFeature
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns whether the renderer will render a feature or not.
Definition: qgsrulebasedrenderer.cpp:1276
QgsRuleBasedRenderer::createFromSld
static QgsFeatureRenderer * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
Definition: qgsrulebasedrenderer.cpp:1152
QgsPointDistanceRenderer::embeddedRenderer
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
Definition: qgspointdistancerenderer.cpp:164
QgsRuleBasedRenderer::RuleList
QList< QgsRuleBasedRenderer::Rule * > RuleList
Definition: qgsrulebasedrenderer.h:124
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:64
QgsProperty::fromExpression
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
Definition: qgsproperty.cpp:212
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgspainteffect.h
QgsRuleBasedRenderer::Rule::takeChild
QgsRuleBasedRenderer::Rule * takeChild(QgsRuleBasedRenderer::Rule *rule)
take child rule out, set parent as nullptr
Definition: qgsrulebasedrenderer.cpp:108
QgsSymbol::symbolLayer
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:385
QgsRuleBasedRenderer::convertToDataDefinedSymbology
static void convertToDataDefinedSymbology(QgsSymbol *symbol, const QString &sizeScaleField, const QString &rotationField=QString())
helper function to convert the size scale and rotation fields present in some other renderers to data...
Definition: qgsrulebasedrenderer.cpp:1483
QgsPaintEffect::saveProperties
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Definition: qgspainteffect.cpp:54
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:61
QgsRuleBasedRenderer::legendSymbolItemChecked
bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
Definition: qgsrulebasedrenderer.cpp:1101
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
qgsogcutils.h
QgsRuleBasedRenderer::FeatIsSelected
@ FeatIsSelected
Definition: qgsrulebasedrenderer.h:44
QgsFeatureRenderer::stopRender
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
Definition: qgsrenderer.cpp:107
QgsRuleBasedRenderer::RenderQueue
QList< QgsRuleBasedRenderer::RenderLevel > RenderQueue
Rendering queue: a list of rendering levels.
Definition: qgsrulebasedrenderer.h:122
QgsSymbolLayerUtils::mergeScaleDependencies
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QgsStringMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
Definition: qgssymbollayerutils.cpp:4540
QgsRuleBasedRenderer::Rule::descendants
QgsRuleBasedRenderer::RuleList descendants() const
Returns all children, grand-children, grand-grand-children, grand-gra...
Definition: qgsrulebasedrenderer.cpp:776
QgsRuleBasedRenderer::Rule::symbols
QgsSymbolList symbols(const QgsRenderContext &context=QgsRenderContext()) const
Definition: qgsrulebasedrenderer.cpp:240
QgsRuleBasedRenderer::Rule::minimumScale
double minimumScale() const
Returns the minimum map scale (i.e.
Definition: qgsrulebasedrenderer.h:221
QgsRuleBasedRenderer::Rule::maximumScale
double maximumScale() const
Returns the maximum map scale (i.e.
Definition: qgsrulebasedrenderer.h:211
QgsFeatureRenderer::orderBy
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
Definition: qgsrenderer.cpp:435
QgsRuleBasedRenderer::dump
QString dump() const override
Returns debug information about this renderer.
Definition: qgsrulebasedrenderer.cpp:1269
QgsRuleBasedRenderer::~QgsRuleBasedRenderer
~QgsRuleBasedRenderer() override
Definition: qgsrulebasedrenderer.cpp:918
QgsRuleBasedRenderer::Rule::findRuleByKey
QgsRuleBasedRenderer::Rule * findRuleByKey(const QString &key)
Try to find a rule given its unique key.
Definition: qgsrulebasedrenderer.cpp:124
QgsRuleBasedRenderer::legendKeysForFeature
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
Definition: qgsrulebasedrenderer.cpp:1291
QgsRuleBasedRenderer::clone
QgsRuleBasedRenderer * clone() const override
Create a deep copy of this renderer.
Definition: qgsrulebasedrenderer.cpp:1035
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:341
QgsRuleBasedRenderer::Rule::rulesForFeature
QgsRuleBasedRenderer::RuleList rulesForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr, bool onlyActive=true)
Returns the list of rules used to render the feature in a specific context.
Definition: qgsrulebasedrenderer.cpp:693
QgsLegendSymbolItem
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Definition: qgslegendsymbolitem.h:37
QgsRuleBasedRenderer::Rule::setRuleKey
void setRuleKey(const QString &key)
Override the assigned rule key (should be used just internally by rule-based renderer)
Definition: qgsrulebasedrenderer.h:259
QgsRuleBasedRenderer::Rule::setSymbol
void setSymbol(QgsSymbol *sym)
Sets a new symbol (or nullptr). Deletes old symbol.
Definition: qgsrulebasedrenderer.cpp:254
QgsPaintEffectRegistry::isDefaultStack
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Definition: qgspainteffectregistry.cpp:134
QgsRuleBasedRenderer::FeatDrawMarkers
@ FeatDrawMarkers
Definition: qgsrulebasedrenderer.h:45
QgsInvertedPolygonRenderer::embeddedRenderer
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
Definition: qgsinvertedpolygonrenderer.cpp:58
QgsRuleBasedRenderer::Rule::insertChild
void insertChild(int i, QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
Definition: qgsrulebasedrenderer.cpp:88
QgsSymbolLayer::renderingPass
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
Definition: qgssymbollayer.cpp:242
QgsRuleBasedRenderer::mCurrentFeatures
QList< FeatureToRender > mCurrentFeatures
Definition: qgsrulebasedrenderer.h:559
QgsFeatureRenderer::setUsingSymbolLevels
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:284
QgsRuleBasedRenderer::FeatureToRender
Feature for rendering by a QgsRuleBasedRenderer.
Definition: qgsrulebasedrenderer.h:53
QgsRuleBasedRenderer::mRenderQueue
RenderQueue mRenderQueue
Definition: qgsrulebasedrenderer.h:558
QgsRuleBasedRenderer::filter
QString filter(const QgsFields &fields=QgsFields()) override
If a renderer does not require all the features this method may be overridden and return an expressio...
Definition: qgsrulebasedrenderer.cpp:1020
QgsRuleBasedRenderer::Rule::takeChildAt
QgsRuleBasedRenderer::Rule * takeChildAt(int i)
take child rule out, set parent as nullptr
Definition: qgsrulebasedrenderer.cpp:116
QgsSymbolList
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:45
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:931
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
QgsRuleBasedRenderer::Rule::setIsElse
void setIsElse(bool iselse)
Sets if this rule is an ELSE rule.
Definition: qgsrulebasedrenderer.cpp:152
QgsRuleBasedRenderer::mFilter
QString mFilter
Definition: qgsrulebasedrenderer.h:561
QgsFeatureRenderer::clone
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsGraduatedSymbolRenderer
Definition: qgsgraduatedsymbolrenderer.h:36
QgsRendererCategory::symbol
QgsSymbol * symbol() const
Returns the symbol which will be used to render this category.
Definition: qgscategorizedsymbolrenderer.cpp:79
QgsSymbolLayer::PropertySize
@ PropertySize
Symbol size.
Definition: qgssymbollayer.h:132
QgsRuleBasedRenderer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props=QgsStringMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
Definition: qgsrulebasedrenderer.cpp:1055
RENDERER_TAG_NAME
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:51
QgsPointDistanceRenderer
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
Definition: qgspointdistancerenderer.h:39
QgsRuleBasedRenderer::Rule::symbol
QgsSymbol * symbol()
Definition: qgsrulebasedrenderer.h:199
QgsRuleBasedRenderer::Rule::setNormZLevels
void setNormZLevels(const QMap< int, int > &zLevelsToNormLevels)
assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering
Definition: qgsrulebasedrenderer.cpp:534
qgsrendercontext.h
QgsRuleBasedRenderer::refineRuleScales
static void refineRuleScales(QgsRuleBasedRenderer::Rule *initialRule, QList< int > scales)
take a rule and create a list of new rules with intervals of scales given by the passed scale denomin...
Definition: qgsrulebasedrenderer.cpp:1249
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1131
QgsRuleBasedRenderer::mRootRule
Rule * mRootRule
the root node with hierarchical list of rules
Definition: qgsrulebasedrenderer.h:555
QgsFeatureRenderer::usingSymbolLevels
bool usingSymbolLevels() const
Definition: qgsrenderer.h:283
QgsRuleBasedRenderer::renderFeature
bool renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override SIP_THROW(QgsCsException)
Render a feature using this renderer in the given context.
Definition: qgsrulebasedrenderer.cpp:930
qgssymbollayer.h
QgsRuleBasedRenderer::Rule::legendKeysForFeature
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
Returns which legend keys match the feature.
Definition: qgsrulebasedrenderer.cpp:659
QgsRendererRange::upperValue
double upperValue() const
Definition: qgsrendererrange.cpp:73
QgsRuleBasedRenderer::Rule::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all child rules associated with the rule...
Definition: qgsrulebasedrenderer.cpp:159
QgsRuleBasedRenderer::refineRuleRanges
static void refineRuleRanges(QgsRuleBasedRenderer::Rule *initialRule, QgsGraduatedSymbolRenderer *r)
take a rule and create a list of new rules based on the ranges from graduated symbol renderer
Definition: qgsrulebasedrenderer.cpp:1217
QgsRuleBasedRenderer::Rule::removeChild
void removeChild(QgsRuleBasedRenderer::Rule *rule)
delete child rule
Definition: qgsrulebasedrenderer.cpp:95
QgsRuleBasedRenderer::QgsRuleBasedRenderer
QgsRuleBasedRenderer(QgsRuleBasedRenderer::Rule *root)
Constructs the renderer from given tree of rules (takes ownership)
Definition: qgsrulebasedrenderer.cpp:905
QgsRuleBasedRenderer::FeatureToRender::feat
QgsFeature feat
Definition: qgsrulebasedrenderer.h:58
QgsStyleEntityVisitorInterface::NodeType::SymbolRule
@ SymbolRule
Rule based symbology or label child rule.
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:111
QgsRuleBasedRenderer::originalSymbolsForFeature
QgsSymbolList originalSymbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
Definition: qgsrulebasedrenderer.cpp:1286
QgsSymbolLayer::PropertyStrokeWidth
@ PropertyStrokeWidth
Stroke width.
Definition: qgssymbollayer.h:137
qgsrulebasedrenderer.h
QgsRuleBasedRenderer::Rule::Rule
Rule(QgsSymbol *symbol, int maximumScale=0, int minimumScale=0, const QString &filterExp=QString(), const QString &label=QString(), const QString &description=QString(), bool elseRule=false)
Constructor takes ownership of the symbol.
Definition: qgsrulebasedrenderer.cpp:39
QgsSymbolLayer::subSymbol
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Definition: qgssymbollayer.h:353
QgsRuleBasedRenderer::Rule::renderFeature
QgsRuleBasedRenderer::Rule::RenderResult renderFeature(QgsRuleBasedRenderer::FeatureToRender &featToRender, QgsRenderContext &context, QgsRuleBasedRenderer::RenderQueue &renderQueue)
Render a given feature, will recursively call subclasses and only render if the constraints apply.
Definition: qgsrulebasedrenderer.cpp:554
QgsRuleBasedRenderer::legendSymbolItemsCheckable
bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
Definition: qgsrulebasedrenderer.cpp:1096
QgsSymbolLayerUtils::createSymbolLayerListFromSld
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QgsSymbolLayerList &layers)
Definition: qgssymbollayerutils.cpp:1238
QgsSymbolLayerUtils::applyScaleDependency
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QgsStringMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
Definition: qgssymbollayerutils.cpp:4523
QgsFeatureRenderer::mOrderBy
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:545
qgsvectorlayer.h
QgsRuleBasedRenderer::Rule::RenderResult
RenderResult
The result of rendering a rule.
Definition: qgsrulebasedrenderer.h:141
QgsStyleEntityVisitorInterface::visitEnter
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
Definition: qgsstyleentityvisitor.h:169
QgsRuleBasedRenderer::symbolForFeature
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for current feature. Should not be used individually: there could be more symbols for ...
Definition: qgsrulebasedrenderer.cpp:924
QgsSymbol::clone
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
QgsGraduatedSymbolRenderer::ranges
const QgsRangeList & ranges() const
Definition: qgsgraduatedsymbolrenderer.h:59
QgsRendererCategory::label
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
Definition: qgscategorizedsymbolrenderer.cpp:84
QgsRuleBasedRenderer::filterNeedsGeometry
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
Definition: qgsrulebasedrenderer.cpp:1030
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:758
QgsFeatureRenderer::mUsingSymbolLevels
bool mUsingSymbolLevels
Definition: qgsrenderer.h:522
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsFeatureRenderer
Definition: qgsrenderer.h:103
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QgsRuleBasedRenderer::RenderJob
A QgsRuleBasedRenderer rendering job, consisting of a feature to be rendered with a particular symbol...
Definition: qgsrulebasedrenderer.h:67
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsRuleBasedRenderer::Rule::toSld
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Definition: qgsrulebasedrenderer.cpp:349
QgsRuleBasedRenderer::Rule::createFromSld
static QgsRuleBasedRenderer::Rule * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
Create a rule from the SLD provided in element and for the specified geometry type.
Definition: qgsrulebasedrenderer.cpp:787
QgsSymbolLayerUtils::saveSymbols
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Definition: qgssymbollayerutils.cpp:3024
QgsFeatureRenderer::orderByEnabled
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
Definition: qgsrenderer.cpp:445
QgsRuleBasedRenderer::Rule::clone
QgsRuleBasedRenderer::Rule * clone() const
clone this rule, return new instance
Definition: qgsrulebasedrenderer.cpp:305
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
QgsSymbolLayerUtils::clearSymbolMap
static void clearSymbolMap(QgsSymbolMap &symbols)
Definition: qgssymbollayerutils.cpp:3038
QgsSymbolLayer::PropertyAngle
@ PropertyAngle
Symbol angle.
Definition: qgssymbollayer.h:133
QgsFillSymbol
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1234
QgsRuleBasedRenderer::refineRuleCategories
static void refineRuleCategories(QgsRuleBasedRenderer::Rule *initialRule, QgsCategorizedSymbolRenderer *r)
take a rule and create a list of new rules based on the categories from categorized symbol renderer
Definition: qgsrulebasedrenderer.cpp:1186
qgspointdisplacementrenderer.h
qgsproperty.h
QgsRuleBasedRenderer::Rule::~Rule
~Rule()
Definition: qgsrulebasedrenderer.cpp:56
QgsSymbol::Line
@ Line
Line symbol.
Definition: qgssymbol.h:88
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
QgsSymbol::type
SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:122
QgsSymbol::Marker
@ Marker
Marker symbol.
Definition: qgssymbol.h:87
QgsStyleEntityVisitorInterface::visit
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Definition: qgsstyleentityvisitor.h:153
QgsRuleBasedRenderer::Rule::isScaleOK
bool isScaleOK(double scale) const
Check if this rule applies for a given scale.
Definition: qgsrulebasedrenderer.cpp:292
QgsFeatureRenderer::setOrderBy
void setOrderBy(const QgsFeatureRequest::OrderBy &orderBy)
Define the order in which features shall be processed by this renderer.
Definition: qgsrenderer.cpp:440
qgsinvertedpolygonrenderer.h
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsCategorizedSymbolRenderer
Definition: qgscategorizedsymbolrenderer.h:152
QgsRuleBasedRenderer::startRender
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
Definition: qgsrulebasedrenderer.cpp:946
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsExpression::isField
bool isField() const
Checks whether an expression consists only of a single field reference.
Definition: qgsexpression.cpp:1096
QgsRuleBasedRenderer::Rule::Rendered
@ Rendered
Something was rendered.
Definition: qgsrulebasedrenderer.h:144
QgsExpression::hasParserError
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.cpp:202
QgsRuleBasedRenderer::Rule::legendSymbolItems
QgsLegendSymbolList legendSymbolItems(int currentLevel=-1) const
Definition: qgsrulebasedrenderer.cpp:265
qgslogger.h
QgsRenderContext::rendererScale
double rendererScale() const
Returns the renderer map scale.
Definition: qgsrendercontext.h:377
QgsRuleBasedRenderer::Rule::setActive
void setActive(bool state)
Sets if this rule is active.
Definition: qgsrulebasedrenderer.h:301
QgsRuleBasedRenderer::Rule::appendChild
void appendChild(QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
Definition: qgsrulebasedrenderer.cpp:81
QgsRuleBasedRenderer::Rule::setFilterExpression
void setFilterExpression(const QString &filterExp)
Set the expression used to check if a given feature shall be rendered with this rule.
Definition: qgsrulebasedrenderer.cpp:259
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsSingleSymbolRenderer::symbol
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
Definition: qgssinglesymbolrenderer.cpp:96
qgsgraduatedsymbolrenderer.h
QgsLegendSymbolList
QList< QgsLegendSymbolItem > QgsLegendSymbolList
Definition: qgslegendsymbolitem.h:144
QgsFeatureRenderer::startRender
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:93
QgsRuleBasedRenderer::symbolsForFeature
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns list of symbols used for rendering the feature.
Definition: qgsrulebasedrenderer.cpp:1281
QgsRuleBasedRenderer::Rule::initFilter
void initFilter()
Definition: qgsrulebasedrenderer.cpp:62
QgsRendererCategory::value
QVariant value() const
Returns the value corresponding to this category.
Definition: qgscategorizedsymbolrenderer.cpp:74
QgsCategorizedSymbolRenderer::classAttribute
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
Definition: qgscategorizedsymbolrenderer.h:299
QgsSymbolLayer::setDataDefinedProperty
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
Definition: qgssymbollayer.cpp:113
QgsRuleBasedRenderer::Rule::removeChildAt
void removeChildAt(int i)
delete child rule
Definition: qgsrulebasedrenderer.cpp:102
QgsRuleBasedRenderer::convertFromRenderer
static QgsRuleBasedRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsRuleBasedRenderer from an existing renderer.
Definition: qgsrulebasedrenderer.cpp:1301
QgsRuleBasedRenderer::Rule
This class keeps data about a rules for rule-based renderer.
Definition: qgsrulebasedrenderer.h:137
QgsRuleBasedRenderer::stopRender
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
Definition: qgsrulebasedrenderer.cpp:972
qgsstyleentityvisitor.h
QgsRuleBasedRenderer::create
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new rule-based renderer instance from XML.
Definition: qgsrulebasedrenderer.cpp:1129
QgsRuleBasedRenderer::RenderLevel
Render level: a list of jobs to be drawn at particular level for a QgsRuleBasedRenderer.
Definition: qgsrulebasedrenderer.h:90
QgsRuleBasedRenderer::Rule::active
bool active() const
Returns if this rule is active.
Definition: qgsrulebasedrenderer.h:247
QgsSymbolLayerUtils::createFunctionElement
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Definition: qgssymbollayerutils.cpp:2756
QgsSymbol::symbolLayerCount
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:183
QgsInvertedPolygonRenderer
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
Definition: qgsinvertedpolygonrenderer.h:42
QgsRuleBasedRenderer::Rule::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the attributes used to evaluate the expression of this rule.
Definition: qgsrulebasedrenderer.cpp:207
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:521