37#include <QDomDocument>
43using namespace Qt::StringLiterals;
47 , mMaximumScale( scaleMinDenom )
48 , mMinimumScale( scaleMaxDenom )
49 , mFilterExp( filterExp )
52 , mElseRule( elseRule )
55 mFilterExp = u
"ELSE"_s;
57 mRuleKey = QUuid::createUuid().toString();
63 qDeleteAll( mChildren );
69 if ( mFilterExp.trimmed().compare(
"ELSE"_L1, Qt::CaseInsensitive ) == 0 )
74 else if ( mFilterExp.trimmed().isEmpty() )
82 mFilter = std::make_unique< QgsExpression >( mFilterExp );
88 mChildren.append( rule );
95 mChildren.insert( i, rule );
102 mChildren.removeAll( rule );
109 delete mChildren.takeAt( i );
115 mChildren.removeAll( rule );
116 rule->mParent =
nullptr;
123 Rule *rule = mChildren.takeAt( i );
124 rule->mParent =
nullptr;
133 if ( key == mRuleKey )
136 const auto constMChildren = mChildren;
137 for (
Rule *rule : constMChildren )
139 Rule *r = rule->findRuleByKey( key );
146void QgsRuleBasedRenderer::Rule::updateElseRules()
149 const auto constMChildren = mChildren;
150 for (
Rule *rule : constMChildren )
152 if ( rule->isElse() )
159 mFilterExp = u
"ELSE"_s;
177 if ( !mChildren.empty() )
179 for (
const Rule *rule : mChildren )
182 if ( !rule->accept( visitor ) )
196 off.fill( QChar(
' ' ), indent );
197 QString symbolDump = ( mSymbol ? mSymbol->dump() : u
"[]"_s );
198 QString msg = off + u
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n"_s
199 .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
200 .arg( mFilterExp, symbolDump );
203 const auto constMChildren = mChildren;
204 for (
Rule *rule : constMChildren )
206 lst.append( rule->dump( indent + 2 ) );
208 msg += lst.join( QLatin1Char(
'\n' ) );
217 attrs.unite( mFilter->referencedColumns() );
219 attrs.unite( mSymbol->usedAttributes( context ) );
222 const auto constMChildren = mChildren;
223 for (
Rule *rule : constMChildren )
225 attrs.unite( rule->usedAttributes( context ) );
232 if ( mFilter && mFilter->needsGeometry() )
235 const auto constMChildren = mChildren;
236 for (
Rule *rule : constMChildren )
238 if ( rule->needsGeometry() )
249 lst.append( mSymbol.get() );
251 const auto constMChildren = mChildren;
252 for (
Rule *rule : constMChildren )
254 lst += rule->symbols( context );
261 mSymbol.reset( sym );
266 mFilterExp = filterExp;
273 if ( currentLevel != -1 )
275 lst <<
QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey,
true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
278 for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
289 if ( ! mFilter || mElseRule || ! context )
318 Rule *newrule =
new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
321 const auto constMChildren = mChildren;
322 for (
Rule *rule : constMChildren )
329 QDomElement ruleElem = doc.createElement( u
"rule"_s );
333 int symbolIndex = symbolMap.size();
334 symbolMap[QString::number( symbolIndex )] = mSymbol.get();
335 ruleElem.setAttribute( u
"symbol"_s, symbolIndex );
337 if ( !mFilterExp.isEmpty() )
338 ruleElem.setAttribute( u
"filter"_s, mFilterExp );
339 if ( mMaximumScale != 0 )
340 ruleElem.setAttribute( u
"scalemindenom"_s, mMaximumScale );
341 if ( mMinimumScale != 0 )
342 ruleElem.setAttribute( u
"scalemaxdenom"_s, mMinimumScale );
343 if ( !mLabel.isEmpty() )
344 ruleElem.setAttribute( u
"label"_s, mLabel );
345 if ( !mDescription.isEmpty() )
346 ruleElem.setAttribute( u
"description"_s, mDescription );
348 ruleElem.setAttribute( u
"checkstate"_s, 0 );
349 ruleElem.setAttribute( u
"key"_s, mRuleKey );
351 const auto constMChildren = mChildren;
352 for (
Rule *rule : constMChildren )
354 ruleElem.appendChild( rule->save( doc, symbolMap ) );
363 toSld( doc, element, context );
370 if (
symbols( context ).isEmpty() )
374 QVariantMap props = oldProps;
375 if ( !mFilterExp.isEmpty() )
377 QString
filter = props.value( u
"filter"_s, QString() ).toString();
381 props[ u
"filter"_s] =
filter;
389 QDomElement ruleElem = doc.createElement( u
"se:Rule"_s );
393 QDomElement nameElem = doc.createElement( u
"se:Name"_s );
394 nameElem.appendChild( doc.createTextNode( mLabel ) );
395 ruleElem.appendChild( nameElem );
397 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
399 QDomElement descrElem = doc.createElement( u
"se:Description"_s );
400 if ( !mLabel.isEmpty() )
402 QDomElement titleElem = doc.createElement( u
"se:Title"_s );
403 titleElem.appendChild( doc.createTextNode( mLabel ) );
404 descrElem.appendChild( titleElem );
406 if ( !mDescription.isEmpty() )
408 QDomElement abstractElem = doc.createElement( u
"se:Abstract"_s );
409 abstractElem.appendChild( doc.createTextNode( mDescription ) );
410 descrElem.appendChild( abstractElem );
412 ruleElem.appendChild( descrElem );
415 if ( !props.value( u
"filter"_s, QString() ).toString().isEmpty() )
423 mSymbol->toSld( doc, ruleElem, exportContext );
429 element.appendChild( ruleElem );
435 for (
Rule *rule : std::as_const( mChildren ) )
437 if ( !rule->toSld( doc, element, exportContext ) )
446 mActiveChildren.clear();
459 mSymbol->startRender( context, fields );
463 QStringList subfilters;
464 const auto constMChildren = mChildren;
465 for (
Rule *rule : constMChildren )
468 if ( rule->startRender( context, fields, subfilter ) )
471 mActiveChildren.append( rule );
472 subfilters.append( subfilter );
480 if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
482 if ( subfilters.contains( u
"TRUE"_s ) )
495 else if ( subfilters.count() > 50 )
497 std::function<QString(
const QStringList & )>bt = [ &bt ](
const QStringList & subf )
499 if ( subf.count( ) == 1 )
503 else if ( subf.count( ) == 2 )
505 return subf.join(
") OR ("_L1 ).prepend(
'(' ).append(
')' );
509 int midpos =
static_cast<int>( subf.length() / 2 );
510 return u
"(%1) OR (%2)"_s.arg( bt( subf.mid( 0, midpos ) ), bt( subf.mid( midpos ) ) );
513 sf = bt( subfilters );
517 sf = subfilters.join(
") OR ("_L1 ).prepend(
'(' ).append(
')' );
529 if ( mSymbol || sf.isEmpty() )
536 else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
537 filter = u
"(%1) AND (%2)"_s.arg( mFilterExp, sf );
538 else if ( !mFilterExp.trimmed().isEmpty() )
540 else if ( sf.isEmpty() )
552 return !mActiveChildren.empty();
557 QSet<int> symbolZLevelsSet;
563 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
565 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
570 QList<Rule *>::iterator it;
571 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
576 return symbolZLevelsSet;
583 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
585 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
586 mSymbolNormZLevels.insert( normLevel );
591 const auto constMActiveChildren = mActiveChildren;
592 for (
Rule *rule : constMActiveChildren )
594 rule->setNormZLevels( zLevelsToNormLevels );
604 bool rendered =
false;
607 if ( mSymbol && mIsActive )
610 const auto constMSymbolNormZLevels = mSymbolNormZLevels;
611 for (
int normZLevel : constMSymbolNormZLevels )
614 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol.get() ) );
619 bool matchedAChild =
false;
622 const auto constMChildren = mChildren;
623 for (
Rule *rule : constMChildren )
626 if ( !rule->isElse() )
628 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
636 if ( !matchedAChild )
638 const auto constMElseRules = mElseRules;
639 for (
Rule *rule : constMElseRules )
641 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
646 if ( !mIsActive || ( mSymbol && !rendered ) || ( matchedAChild && !rendered ) )
662 const auto constMActiveChildren = mActiveChildren;
663 for (
Rule *rule : constMActiveChildren )
665 if ( rule->isElse() )
667 if ( rule->children().isEmpty() )
670 lst.removeOne( rule );
679 return rule->willRenderFeature( feature, context );
682 else if ( rule->willRenderFeature( feature, context ) )
696 lst.append( mSymbol.get() );
698 const auto constMActiveChildren = mActiveChildren;
699 for (
Rule *rule : constMActiveChildren )
701 lst += rule->symbolsForFeature( feature, context );
712 res.insert( mRuleKey );
715 bool matchedNonElseRule =
false;
716 for (
Rule *rule : std::as_const( mActiveChildren ) )
718 if ( rule->isElse() )
722 if ( rule->willRenderFeature( feature, context ) )
724 res.unite( rule->legendKeysForFeature( feature, context ) );
725 matchedNonElseRule =
true;
730 if ( !matchedNonElseRule )
732 for (
Rule *rule : std::as_const( mActiveChildren ) )
734 if ( rule->isElse() )
736 if ( rule->children().isEmpty() )
739 lst.removeOne( rule );
743 res.unite( rule->legendKeysForFeature( feature, context ) );
748 res.unite( rule->legendKeysForFeature( feature, context ) );
767 listChildren = mActiveChildren;
769 for (
Rule *rule : std::as_const( listChildren ) )
771 lst += rule->rulesForFeature( feature, context, onlyActive );
779 mSymbol->stopRender( context );
781 const auto constMActiveChildren = mActiveChildren;
782 for (
Rule *rule : constMActiveChildren )
784 rule->stopRender( context );
787 mActiveChildren.clear();
788 mSymbolNormZLevels.clear();
793 QString symbolIdx = ruleElem.attribute( u
"symbol"_s );
795 if ( !symbolIdx.isEmpty() )
797 if ( symbolMap.contains( symbolIdx ) )
799 symbol = symbolMap.take( symbolIdx );
803 QgsDebugError(
"symbol for rule " + symbolIdx +
" not found!" );
807 QString filterExp = ruleElem.attribute( u
"filter"_s );
809 QgsDebugMsgLevel(
"context" + u
"project:layers:%1:legendsymbollabels"_s.arg( context.
currentLayerId() ) +
" source " + ruleElem.attribute( u
"label"_s ), 3 );
810 QString
description = ruleElem.attribute( u
"description"_s );
811 int scaleMinDenom = ruleElem.attribute( u
"scalemindenom"_s, u
"0"_s ).toInt();
812 int scaleMaxDenom = ruleElem.attribute( u
"scalemaxdenom"_s, u
"0"_s ).toInt();
816 ruleKey = ruleElem.attribute( u
"key"_s );
818 ruleKey = QUuid::createUuid().toString();
824 rule->
setActive( ruleElem.attribute( u
"checkstate"_s, u
"1"_s ).toInt() );
826 QDomElement childRuleElem = ruleElem.firstChildElement( u
"rule"_s );
827 while ( !childRuleElem.isNull() )
829 Rule *childRule =
create( childRuleElem, symbolMap,
true, context );
838 childRuleElem = childRuleElem.nextSiblingElement( u
"rule"_s );
850 l +=
c->descendants();
857 if ( ruleElem.localName() !=
"Rule"_L1 )
859 QgsDebugError( u
"invalid element: Rule element expected, %1 found!"_s.arg( ruleElem.tagName() ) );
864 int scaleMinDenom = 0, scaleMaxDenom = 0;
868 QDomElement childElem = ruleElem.firstChildElement();
869 while ( !childElem.isNull() )
871 if ( childElem.localName() ==
"Name"_L1 )
875 if (
label.isEmpty() )
876 label = childElem.firstChild().nodeValue();
878 else if ( childElem.localName() ==
"Description"_L1 )
881 QDomElement titleElem = childElem.firstChildElement( u
"Title"_s );
882 if ( !titleElem.isNull() )
884 label = titleElem.firstChild().nodeValue();
887 QDomElement abstractElem = childElem.firstChildElement( u
"Abstract"_s );
888 if ( !abstractElem.isNull() )
890 description = abstractElem.firstChild().nodeValue();
893 else if ( childElem.localName() ==
"Abstract"_L1 )
898 else if ( childElem.localName() ==
"Title"_L1 )
901 label = childElem.firstChild().nodeValue();
903 else if ( childElem.localName() ==
"Filter"_L1 )
908 if (
filter->hasParserError() )
914 filterExp =
filter->expression();
919 else if ( childElem.localName() ==
"ElseFilter"_L1 )
921 filterExp =
"ELSE"_L1;
924 else if ( childElem.localName() ==
"MinScaleDenominator"_L1 )
927 int v = childElem.firstChild().nodeValue().toInt( &ok );
931 else if ( childElem.localName() ==
"MaxScaleDenominator"_L1 )
934 int v = childElem.firstChild().nodeValue().toInt( &ok );
938 else if ( childElem.localName().endsWith(
"Symbolizer"_L1 ) )
944 childElem = childElem.nextSiblingElement();
949 if ( !layers.isEmpty() )
1007 std::function< void(
Rule *rule ) > exploreRule;
1008 exploreRule = [&res, &exploreRule](
Rule * rule )
1021 exploreRule( child );
1033 bool drawVertexMarker )
1052 QSet<int> symbolZLevelsSet =
mRootRule->collectZLevels();
1053 QList<int> symbolZLevels( symbolZLevelsSet.begin(), symbolZLevelsSet.end() );
1054 std::sort( symbolZLevels.begin(), symbolZLevels.end() );
1058 QMap<int, int> zLevelsToNormLevels;
1059 int maxNormLevel = -1;
1060 const auto constSymbolZLevels = symbolZLevels;
1061 for (
int zLevel : constSymbolZLevels )
1063 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
1065 QgsDebugMsgLevel( u
"zLevel %1 -> %2"_s.arg( zLevel ).arg( maxNormLevel ), 4 );
1068 mRootRule->setNormZLevels( zLevelsToNormLevels );
1088 for (
const RenderLevel &level : constMRenderQueue )
1092 for (
const RenderJob *job : std::as_const( level.jobs ) )
1099 for (
int i = 0; i < count; i++ )
1106 int flags = job->ftr.flags;
1131 return mRootRule->usedAttributes( context );
1148 Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
1149 for (
int i = 0; i < origDescendants.count(); ++i )
1150 clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
1162 toSld( doc, element, context );
1167 return mRootRule->toSld( doc, element, context );
1179 rendererElem.setAttribute( u
"type"_s, u
"RuleRenderer"_s );
1184 rulesElem.setTagName( u
"rules"_s );
1185 rendererElem.appendChild( rulesElem );
1188 rendererElem.appendChild( symbolsElem );
1192 return rendererElem;
1203 return rule ? rule->
active() :
true;
1220 std::function<QString(
Rule *rule )> ruleToExpression;
1221 ruleToExpression = [&ruleToExpression](
Rule * rule ) -> QString
1227 QStringList otherRules;
1228 const QList<QgsRuleBasedRenderer::Rule *> siblings = rule->
parent()->
children();
1229 for (
Rule *sibling : siblings )
1231 if ( sibling == rule || sibling->
isElse() )
1234 const QString siblingExpression = ruleToExpression( sibling );
1235 if ( siblingExpression.isEmpty() )
1238 otherRules.append( siblingExpression );
1241 if ( otherRules.empty() )
1245 otherRules.size() > 1
1246 ? u
"NOT ((%1))"_s.arg( otherRules.join(
") OR ("_L1 ) )
1247 : u
"NOT (%1)"_s.arg( otherRules.at( 0 ) )
1252 QStringList ruleParts;
1257 ruleParts.append( u
"@map_scale <= %1"_s.arg( rule->
minimumScale() ) );
1260 ruleParts.append( u
"@map_scale >= %1"_s.arg( rule->
maximumScale() ) );
1262 if ( !ruleParts.empty() )
1265 ruleParts.size() > 1
1266 ? u
"(%1)"_s.arg( ruleParts.join(
") AND ("_L1 ) )
1280 const QString ruleFilter = ruleToExpression( rule );
1281 if ( !ruleFilter.isEmpty() )
1282 parts.append( ruleFilter );
1288 return parts.empty() ? u
"TRUE"_s
1289 : ( parts.size() > 1
1290 ? u
"(%1)"_s.arg( parts.join(
") AND ("_L1 ) )
1312 QDomElement symbolsElem = element.firstChildElement( u
"symbols"_s );
1313 if ( symbolsElem.isNull() )
1318 QDomElement rulesElem = element.firstChildElement( u
"rules"_s );
1335 Rule *root =
nullptr;
1337 QDomElement ruleElem = element.firstChildElement( u
"Rule"_s );
1338 while ( !ruleElem.isNull() )
1345 root =
new Rule(
nullptr );
1350 ruleElem = ruleElem.nextSiblingElement( u
"Rule"_s );
1378 const auto constCategories = r->
categories();
1385 else if ( cat.value().userType() == QMetaType::Type::Int )
1386 value = cat.value().toString();
1387 else if ( cat.value().userType() == QMetaType::Type::Double )
1390 value = QString::number( cat.value().toDouble(),
'f', 4 );
1394 const QString label = !cat.label().isEmpty() ? cat.label() :
1395 cat.value().isValid() ? value : QString();
1411 else if ( !testExpr.
isField() )
1414 attr = u
"(%1)"_s.arg( attr );
1417 bool firstRange =
true;
1418 const auto constRanges = r->
ranges();
1423 QString
filter = u
"%1 %2 %3 AND %1 <= %4"_s.arg( attr, firstRange ? u
">="_s : u
">"_s,
1424 QString::number( rng.lowerValue(),
'f', 4 ),
1425 QString::number( rng.upperValue(),
'f', 4 ) );
1427 QString label = rng.label().isEmpty() ?
filter : rng.label();
1434 std::sort( scales.begin(), scales.end() );
1438 const auto constScales = scales;
1439 for (
int scale : constScales )
1443 if ( maxDenom != 0 && maxDenom <= scale )
1445 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), u
"%1 - %2"_s.arg( oldScale ).arg( scale ) ) );
1449 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), u
"%1 - %2"_s.arg( oldScale ).arg( maxDenom ) ) );
1454 QString msg( u
"Rule-based renderer:\n"_s );
1461 return mRootRule->willRenderFeature( feature, &context );
1466 return mRootRule->symbolsForFeature( feature, &context );
1471 return mRootRule->symbolsForFeature( feature, &context );
1476 return mRootRule->legendKeysForFeature( feature, &context );
1486 std::unique_ptr< QgsRuleBasedRenderer > r;
1487 if ( renderer->
type() ==
"RuleRenderer"_L1 )
1491 else if ( renderer->
type() ==
"singleSymbol"_L1 )
1494 if ( !singleSymbolRenderer )
1497 std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
1498 r = std::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
1500 else if ( renderer->
type() ==
"categorizedSymbol"_L1 )
1503 if ( !categorizedRenderer )
1508 bool isField =
false;
1518 if ( isField && !attr.contains(
'\"' ) )
1524 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1531 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1533 rule->setLabel( category.
label() );
1536 if ( category.
value().userType() == QMetaType::Type::QVariantList )
1539 const QVariantList list = category.
value().toList();
1540 for (
const QVariant &v : list )
1543 if ( QVariant( v ).convert( QMetaType::Type::Double ) )
1545 values << v.toString();
1553 if ( values.empty() )
1555 expression = u
"ELSE"_s;
1559 expression = u
"%1 IN (%2)"_s.arg( attr, values.join(
',' ) );
1565 if ( category.
value().convert( QMetaType::Type::Double ) )
1567 value = category.
value().toString();
1575 if ( value ==
"''"_L1 )
1577 expression = u
"ELSE"_s;
1581 expression = u
"%1 = %2"_s.arg( attr, value );
1584 rule->setFilterExpression( expression );
1590 std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
1591 rule->setSymbol( origSymbol.release() );
1593 rootrule->appendChild( rule.release() );
1596 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1598 else if ( renderer->
type() ==
"graduatedSymbol"_L1 )
1601 if ( !graduatedRenderer )
1607 bool isField =
false;
1617 if ( isField && !attr.contains(
'\"' ) )
1622 else if ( !isField )
1625 attr = u
"(%1)"_s.arg( attr );
1628 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1632 const bool isInverted = ranges.size() > 1 ?
1633 ranges.at( 0 ).upperValue() > ranges.at( 1 ).upperValue() :
1636 for (
int i = 0; i < ranges.size(); ++i )
1638 range = ranges.value( i );
1639 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1641 rule->setLabel( range.
label() );
1642 const QString upperValue = QString::number( range.
upperValue(),
'f', 16 );
1643 const QString lowerValue = QString::number( range.
lowerValue(),
'f', 16 );
1647 expression = !isInverted ?
1648 u
"%1 <= %2"_s.arg( attr, upperValue ) :
1649 u
"%1 > %2"_s.arg( attr, lowerValue );
1651 else if ( i == ranges.size() - 1 )
1653 expression = !isInverted ?
1654 u
"%1 > %2"_s.arg( attr, lowerValue ) :
1655 u
"%1 <= %2"_s.arg( attr, upperValue );
1659 expression = attr +
" > " + lowerValue +
" AND " + \
1660 attr +
" <= " + upperValue;
1662 rule->setFilterExpression( expression );
1668 std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
1669 rule->setSymbol( symbol.release() );
1671 rootrule->appendChild( rule.release() );
1674 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1676 else if ( renderer->
type() ==
"pointDisplacement"_L1 || renderer->
type() ==
"pointCluster"_L1 )
1681 else if ( renderer->
type() ==
"invertedPolygonRenderer"_L1 )
1686 else if ( renderer->
type() ==
"mergedFeatureRenderer"_L1 )
1691 else if ( renderer->
type() ==
"embeddedSymbol"_L1 && layer )
1695 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1702 while ( it.
nextFeature( feature ) && rootrule->children().size() < 500 )
1706 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1707 rule->setFilterExpression( u
"$id=%1"_s.arg( feature.
id() ) );
1708 rule->setLabel( QString::number( feature.
id() ) );
1710 rootrule->appendChild( rule.release() );
1714 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1715 rule->setFilterExpression( u
"ELSE"_s );
1716 rule->setLabel( QObject::tr(
"All other features" ) );
1718 rootrule->appendChild( rule.release() );
1720 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1733 QString sizeExpression;
1734 switch ( symbol->
type() )
1740 if ( ! sizeScaleField.isEmpty() )
1742 sizeExpression = u
"%1*(%2)"_s.arg( msl->
size() ).arg( sizeScaleField );
1745 if ( ! rotationField.isEmpty() )
1752 if ( ! sizeScaleField.isEmpty() )
1759 sizeExpression = u
"%1*(%2)"_s.arg( lsl->
width() ).arg( sizeScaleField );
1768 sizeExpression = u
"%1*(%2)"_s.arg( msl->
size() ).arg( sizeScaleField );
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ EmbeddedSymbols
Retrieve any embedded feature symbology.
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
A feature renderer which represents features using a list of renderer categories.
const QgsCategoryList & categories() const
Returns a list of all categories recognized by the renderer.
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
A vector feature renderer which uses embedded feature symbology to render per-feature symbols.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes).
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
bool isField() const
Checks whether an expression consists only of a single field reference.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
static int expressionToLayerFieldIndex(const QString &expression, const QgsVectorLayer *layer)
Attempts to resolve an expression to a field index from the given layer.
static bool attemptReduceToInClause(const QStringList &expressions, QString &result)
Attempts to reduce a list of expressions to a single "field IN (val1, val2, ... )" type expression.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
QgsFeatureRenderer(const QString &type)
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
void renderFeatureWithSymbol(const QgsFeature &feature, QgsSymbol *symbol, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker)
Render the feature with the symbol using context.
virtual const QgsFeatureRenderer * embeddedRenderer() const
Returns the current embedded renderer (subrenderer) for this feature renderer.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Container of fields for a vector layer.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
A vector feature renderer which uses numeric attributes to classify features into different ranges.
QString classAttribute() const
Returns the attribute name (or expression) used for the classification.
const QgsRangeList & ranges() const
Returns a list of all ranges used in the classification.
A polygon-only feature renderer used to display features inverted.
Stores information about one class/rule of a vector layer renderer in a unified way that can be used ...
Abstract base class for line symbol layers.
virtual double width() const
Returns the estimated width for the line symbol layer.
A line symbol type, for rendering LineString and MultiLineString geometries.
Abstract base class for marker symbol layers.
double size() const
Returns the symbol size.
A marker symbol type, for rendering Point and MultiPoint geometries.
A polygon or line-only feature renderer used to render a set of features merged (or dissolved) into a...
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
A container for the context for various read/write operations on objects.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
const QString currentLayerId() const
Returns the currently used layer id as string.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
QgsSymbol * symbol() const
Returns the symbol which will be used to render this category.
QVariant value() const
Returns the value corresponding to this category.
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
Represents a value range for a QgsGraduatedSymbolRenderer.
QString label() const
Returns the label used for the range.
QgsSymbol * symbol() const
Returns the symbol used for the range.
double upperValue() const
Returns the upper bound of the range.
double lowerValue() const
Returns the lower bound of the range.
Represents an individual rule for a rule-based renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all child rules associated with the rule...
QgsRuleBasedRenderer::RuleList descendants() const
Returns all children, grand-children, grand-grand-children, grand-gra... you get it.
void setSymbol(QgsSymbol *sym)
Sets a new symbol (or nullptr). Deletes old symbol.
void removeChild(QgsRuleBasedRenderer::Rule *rule)
delete child rule
QgsRuleBasedRenderer::Rule * findRuleByKey(const QString &key)
Try to find a rule given its unique key.
void insertChild(int i, QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
static QgsRuleBasedRenderer::Rule * create(QDomElement &ruleElem, QgsSymbolMap &symbolMap, bool reuseId=true, const QgsReadWriteContext &context=QgsReadWriteContext())
Create a rule from an XML definition.
QString ruleKey() const
Unique rule identifier (for identification of rule within renderer).
bool needsGeometry() const
Returns true if this rule or one of its children needs the geometry to be applied.
QgsRuleBasedRenderer::Rule * takeChild(QgsRuleBasedRenderer::Rule *rule)
take child rule out, set parent as nullptr
const QgsRuleBasedRenderer::RuleList & children() const
Returns all children rules of this rule.
RenderResult
The result of rendering a rule.
@ Inactive
The rule is inactive.
@ Filtered
The rule does not apply.
@ Rendered
Something was rendered.
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.
double maximumScale() const
Returns the maximum map scale (i.e.
QgsRuleBasedRenderer::Rule * parent()
The parent rule.
void setIsElse(bool iselse)
Sets if this rule is an ELSE rule.
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
tell which symbols will be used to render the feature
bool isElse() const
Check if this rule is an ELSE rule.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
Returns which legend keys match the feature.
QgsRuleBasedRenderer::Rule * clone() const
clone this rule, return new instance
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
only tell whether a feature will be rendered without actually rendering it
void removeChildAt(int i)
delete child rule
void setActive(bool state)
Sets if this rule is active.
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.
bool isFilterOK(const QgsFeature &f, QgsRenderContext *context=nullptr) const
Check if a given feature shall be rendered by this rule.
QgsSymbolList symbols(const QgsRenderContext &context=QgsRenderContext()) const
Returns a list of the symbols used by this rule and all children of this rule.
bool isScaleOK(double scale) const
Check if this rule applies for a given scale.
static QgsRuleBasedRenderer::Rule * createFromSld(QDomElement &element, Qgis::GeometryType geomType)
Create a rule from the SLD provided in element and for the specified geometry type.
QgsExpression * filter() const
A filter that will check if this rule applies.
void setNormZLevels(const QMap< int, int > &zLevelsToNormLevels)
assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering
QDomElement save(QDomDocument &doc, QgsSymbolMap &symbolMap) const
void appendChild(QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
QgsRuleBasedRenderer::Rule * takeChildAt(int i)
take child rule out, set parent as nullptr
QSet< int > collectZLevels()
Gets all used z-levels from this rule and children.
double minimumScale() const
Returns the minimum map scale (i.e.
QString description() const
A human readable description for this rule.
void stopRender(QgsRenderContext &context)
Stop a rendering process.
bool hasActiveChildren() const
Returns true if the rule has any active children.
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.
QgsLegendSymbolList legendSymbolItems(int currentLevel=-1) const
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the attributes used to evaluate the expression of this rule.
void setFilterExpression(const QString &filterExp)
Set the expression used to check if a given feature shall be rendered with this rule.
QString dump(int indent=0) const
Dump for debug purpose.
void setRuleKey(const QString &key)
Override the assigned rule key (should be used just internally by rule-based renderer).
bool startRender(QgsRenderContext &context, const QgsFields &fields, QString &filter)
prepare the rule for rendering and its children (build active children array)
QString filterExpression() const
A filter that will check if this rule applies.
bool active() const
Returns if this rule is active.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, QVariantMap props) const
Saves the symbol layer as SLD.
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
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...
bool legendSymbolItemChecked(const QString &key) override
Returns true if the legend symbology item with the specified key is checked.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
bool canSkipRender() override
Returns true if the renderer can be entirely skipped, i.e.
void checkLegendSymbolItem(const QString &key, bool state=true) override
Sets whether the legend symbology item with the specified ley should be checked.
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 ...
QList< QgsRuleBasedRenderer::RenderLevel > RenderQueue
Rendering queue: a list of rendering levels.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
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
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns list of symbols used for rendering the feature.
QString dump() const override
Returns debug information about this renderer.
QgsSymbolList originalSymbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
static QgsRuleBasedRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer, QgsVectorLayer *layer=nullptr)
Creates a new QgsRuleBasedRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
Returns true if symbology items in legend are checkable.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
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...
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns whether the renderer will render a feature or not.
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...
QList< QgsRuleBasedRenderer::Rule * > RuleList
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
Rule * mRootRule
the root node with hierarchical list of rules
~QgsRuleBasedRenderer() override
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
Qgis::FeatureRendererFlags flags() const override
Returns flags associated with the renderer.
QgsRuleBasedRenderer * clone() const override
Create a deep copy of this renderer.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new rule-based renderer instance from XML.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
static QgsFeatureRenderer * createFromSld(QDomElement &element, Qgis::GeometryType geomType)
Creates a new rule based renderer from an SLD XML element.
QList< FeatureToRender > mCurrentFeatures
QString legendKeyToExpression(const QString &key, QgsVectorLayer *layer, bool &ok) const override
Attempts to convert the specified legend rule key to a QGIS expression matching the features displaye...
bool renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
Render a feature using this renderer in the given context.
QgsRuleBasedRenderer(QgsRuleBasedRenderer::Rule *root)
Constructs the renderer from given tree of rules (takes ownership).
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
Used from subclasses to create SLD Rule elements following SLD v1.1 specs.
static bool equalToOrGreaterThanMinimumScale(const double scale, const double minScale)
Returns whether the scale is equal to or greater than the minScale, taking non-round numbers into acc...
static bool lessThanMaximumScale(const double scale, const double maxScale)
Returns whether the scale is less than the maxScale, taking non-round numbers into account.
A feature renderer which renders all features with the same symbol.
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
An interface for classes which can visit style entity (e.g.
@ SymbolRule
Rule based symbology or label child rule.
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QVariantMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
static Q_DECL_DEPRECATED bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates an OGC function element.
static bool hasSldSymbolizer(const QDomElement &element)
Returns true if a DOM element contains an SLD Symbolizer element.
static bool createSymbolLayerListFromSld(QDomElement &element, Qgis::GeometryType geomType, QList< QgsSymbolLayer * > &layers)
Creates a symbol layer list from a DOM element.
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static void clearSymbolMap(QgsSymbolMap &symbols)
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 ...
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.
@ StrokeWidth
Stroke width.
virtual QString layerType() const =0
Returns a string that represents this layer type.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Abstract base class for all rendered symbols.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Qgis::SymbolType type() const
Returns the symbol's type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
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
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define RENDERER_TAG_NAME
QMap< QString, QgsSymbol * > QgsSymbolMap
QList< QgsSymbol * > QgsSymbolList
QList< QgsRendererRange > QgsRangeList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Feature for rendering by a QgsRuleBasedRenderer.
A QgsRuleBasedRenderer rendering job, consisting of a feature to be rendered with a particular symbol...
Render level: a list of jobs to be drawn at particular level for a QgsRuleBasedRenderer.
Contains information relating to a node (i.e.
Contains information relating to the style entity currently being visited.