38#include <QDomDocument>
46 , mMaximumScale( scaleMinDenom )
47 , mMinimumScale( scaleMaxDenom )
48 , mFilterExp( filterExp )
50 , mDescription( description )
51 , mElseRule( elseRule )
54 mFilterExp = QStringLiteral(
"ELSE" );
56 mRuleKey = QUuid::createUuid().toString();
62 qDeleteAll( mChildren );
68 if ( mFilterExp.trimmed().compare( QLatin1String(
"ELSE" ), Qt::CaseInsensitive ) == 0 )
73 else if ( mFilterExp.trimmed().isEmpty() )
81 mFilter = std::make_unique< QgsExpression >( mFilterExp );
87 mChildren.append( rule );
94 mChildren.insert( i, rule );
101 mChildren.removeAll( rule );
108 delete mChildren.takeAt( i );
114 mChildren.removeAll( rule );
115 rule->mParent =
nullptr;
122 Rule *rule = mChildren.takeAt( i );
123 rule->mParent =
nullptr;
132 if ( key == mRuleKey )
135 const auto constMChildren = mChildren;
136 for (
Rule *rule : constMChildren )
145void QgsRuleBasedRenderer::Rule::updateElseRules()
148 const auto constMChildren = mChildren;
149 for (
Rule *rule : constMChildren )
151 if ( rule->isElse() )
158 mFilterExp = QStringLiteral(
"ELSE" );
176 if ( !mChildren.empty() )
178 for (
const Rule *rule : mChildren )
181 if ( !rule->accept( visitor ) )
195 off.fill( QChar(
' ' ), indent );
196 QString symbolDump = ( mSymbol ? mSymbol->dump() : QStringLiteral(
"[]" ) );
197 QString msg = off + QStringLiteral(
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
198 .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
199 .arg( mFilterExp, symbolDump );
202 const auto constMChildren = mChildren;
203 for (
Rule *rule : constMChildren )
205 lst.append( rule->dump( indent + 2 ) );
207 msg += lst.join( QLatin1Char(
'\n' ) );
216 attrs.unite(
mFilter->referencedColumns() );
218 attrs.unite( mSymbol->usedAttributes( context ) );
221 const auto constMChildren = mChildren;
222 for (
Rule *rule : constMChildren )
224 attrs.unite( rule->usedAttributes( context ) );
234 const auto constMChildren = mChildren;
235 for (
Rule *rule : constMChildren )
237 if ( rule->needsGeometry() )
248 lst.append( mSymbol.get() );
250 const auto constMChildren = mChildren;
251 for (
Rule *rule : constMChildren )
253 lst += rule->symbols( context );
260 mSymbol.reset( sym );
265 mFilterExp = filterExp;
272 if ( currentLevel != -1 )
274 lst <<
QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey,
true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
277 for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
288 if ( !
mFilter || mElseRule || ! context )
317 Rule *newrule =
new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
320 const auto constMChildren = mChildren;
321 for (
Rule *rule : constMChildren )
328 QDomElement ruleElem = doc.createElement( QStringLiteral(
"rule" ) );
332 int symbolIndex = symbolMap.size();
333 symbolMap[QString::number( symbolIndex )] = mSymbol.get();
334 ruleElem.setAttribute( QStringLiteral(
"symbol" ), symbolIndex );
336 if ( !mFilterExp.isEmpty() )
337 ruleElem.setAttribute( QStringLiteral(
"filter" ), mFilterExp );
338 if ( mMaximumScale != 0 )
339 ruleElem.setAttribute( QStringLiteral(
"scalemindenom" ), mMaximumScale );
340 if ( mMinimumScale != 0 )
341 ruleElem.setAttribute( QStringLiteral(
"scalemaxdenom" ), mMinimumScale );
342 if ( !mLabel.isEmpty() )
343 ruleElem.setAttribute( QStringLiteral(
"label" ), mLabel );
344 if ( !mDescription.isEmpty() )
345 ruleElem.setAttribute( QStringLiteral(
"description" ), mDescription );
347 ruleElem.setAttribute( QStringLiteral(
"checkstate" ), 0 );
348 ruleElem.setAttribute( QStringLiteral(
"key" ), mRuleKey );
350 const auto constMChildren = mChildren;
351 for (
Rule *rule : constMChildren )
353 ruleElem.
appendChild( rule->save( doc, symbolMap ) );
362 toSld( doc, element, context );
369 if (
symbols( context ).isEmpty() )
373 QVariantMap props = oldProps;
374 if ( !mFilterExp.isEmpty() )
376 QString
filter = props.value( QStringLiteral(
"filter" ), QString() ).toString();
378 filter += QLatin1String(
" AND " );
380 props[ QStringLiteral(
"filter" )] =
filter;
388 QDomElement ruleElem = doc.createElement( QStringLiteral(
"se:Rule" ) );
392 QDomElement nameElem = doc.createElement( QStringLiteral(
"se:Name" ) );
393 nameElem.appendChild( doc.createTextNode( mLabel ) );
394 ruleElem.appendChild( nameElem );
396 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
398 QDomElement descrElem = doc.createElement( QStringLiteral(
"se:Description" ) );
399 if ( !mLabel.isEmpty() )
401 QDomElement titleElem = doc.createElement( QStringLiteral(
"se:Title" ) );
402 titleElem.appendChild( doc.createTextNode( mLabel ) );
403 descrElem.appendChild( titleElem );
405 if ( !mDescription.isEmpty() )
407 QDomElement abstractElem = doc.createElement( QStringLiteral(
"se:Abstract" ) );
408 abstractElem.appendChild( doc.createTextNode( mDescription ) );
409 descrElem.appendChild( abstractElem );
411 ruleElem.appendChild( descrElem );
414 if ( !props.value( QStringLiteral(
"filter" ), QString() ).toString().isEmpty() )
422 mSymbol->toSld( doc, ruleElem, exportContext );
428 element.appendChild( ruleElem );
434 for (
Rule *rule : std::as_const( mChildren ) )
436 if ( !rule->toSld( doc, element, exportContext ) )
445 mActiveChildren.clear();
458 mSymbol->startRender( context, fields );
462 QStringList subfilters;
463 const auto constMChildren = mChildren;
464 for (
Rule *rule : constMChildren )
467 if ( rule->startRender( context, fields, subfilter ) )
470 mActiveChildren.append( rule );
471 subfilters.append( subfilter );
479 if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
481 if ( subfilters.contains( QStringLiteral(
"TRUE" ) ) )
483 sf = QStringLiteral(
"TRUE" );
494 else if ( subfilters.count() > 50 )
496 std::function<QString(
const QStringList & )>bt = [ &bt ](
const QStringList & subf )
498 if ( subf.count( ) == 1 )
502 else if ( subf.count( ) == 2 )
504 return subf.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
508 int midpos =
static_cast<int>( subf.length() / 2 );
509 return QStringLiteral(
"(%1) OR (%2)" ).arg( bt( subf.mid( 0, midpos ) ), bt( subf.mid( midpos ) ) );
512 sf = bt( subfilters );
516 sf = subfilters.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
528 if ( mSymbol || sf.isEmpty() )
529 filter = QStringLiteral(
"TRUE" );
535 else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
536 filter = QStringLiteral(
"(%1) AND (%2)" ).arg( mFilterExp, sf );
537 else if ( !mFilterExp.trimmed().isEmpty() )
539 else if ( sf.isEmpty() )
540 filter = QStringLiteral(
"TRUE" );
551 return !mActiveChildren.empty();
556 QSet<int> symbolZLevelsSet;
562 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
564 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
569 QList<Rule *>::iterator it;
570 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
575 return symbolZLevelsSet;
582 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
584 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
585 mSymbolNormZLevels.insert( normLevel );
590 const auto constMActiveChildren = mActiveChildren;
591 for (
Rule *rule : constMActiveChildren )
600 if ( !isFilterOK( featToRender.
feat, &context ) )
603 bool rendered =
false;
606 if ( mSymbol && mIsActive )
609 const auto constMSymbolNormZLevels = mSymbolNormZLevels;
610 for (
int normZLevel : constMSymbolNormZLevels )
613 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol.get() ) );
618 bool matchedAChild =
false;
621 const auto constMChildren = mChildren;
622 for (
Rule *rule : constMChildren )
625 if ( !rule->isElse() )
627 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
629 matchedAChild |= ( res == Rendered || res == Inactive );
630 rendered |= ( res == Rendered );
635 if ( !matchedAChild )
637 const auto constMElseRules = mElseRules;
638 for (
Rule *rule : constMElseRules )
640 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
641 matchedAChild |= ( res == Rendered || res == Inactive );
642 rendered |= res == Rendered;
645 if ( !mIsActive || ( mSymbol && !rendered ) || ( matchedAChild && !rendered ) )
655 if ( !isFilterOK( feature, context ) )
661 const auto constMActiveChildren = mActiveChildren;
662 for (
Rule *rule : constMActiveChildren )
664 if ( rule->isElse() )
666 if ( rule->children().isEmpty() )
668 RuleList lst = rulesForFeature( feature, context,
false );
669 lst.removeOne( rule );
678 return rule->willRenderFeature( feature, context );
681 else if ( rule->willRenderFeature( feature, context ) )
692 if ( !isFilterOK( feature, context ) )
695 lst.append( mSymbol.get() );
697 const auto constMActiveChildren = mActiveChildren;
698 for (
Rule *rule : constMActiveChildren )
700 lst += rule->symbolsForFeature( feature, context );
708 if ( !isFilterOK( feature, context ) )
711 res.insert( mRuleKey );
714 bool matchedNonElseRule =
false;
715 for (
Rule *rule : std::as_const( mActiveChildren ) )
717 if ( rule->isElse() )
721 if ( rule->willRenderFeature( feature, context ) )
723 res.unite( rule->legendKeysForFeature( feature, context ) );
724 matchedNonElseRule =
true;
729 if ( !matchedNonElseRule )
731 for (
Rule *rule : std::as_const( mActiveChildren ) )
733 if ( rule->isElse() )
735 if ( rule->children().isEmpty() )
737 RuleList lst = rulesForFeature( feature, context,
false );
738 lst.removeOne( rule );
742 res.unite( rule->legendKeysForFeature( feature, context ) );
747 res.unite( rule->legendKeysForFeature( feature, context ) );
758 if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->
rendererScale() ) ) )
766 listChildren = mActiveChildren;
768 for (
Rule *rule : std::as_const( listChildren ) )
770 lst += rule->rulesForFeature( feature, context, onlyActive );
778 mSymbol->stopRender( context );
780 const auto constMActiveChildren = mActiveChildren;
781 for (
Rule *rule : constMActiveChildren )
783 rule->stopRender( context );
786 mActiveChildren.clear();
787 mSymbolNormZLevels.clear();
792 QString symbolIdx = ruleElem.attribute( QStringLiteral(
"symbol" ) );
794 if ( !symbolIdx.isEmpty() )
796 if ( symbolMap.contains( symbolIdx ) )
798 symbol = symbolMap.take( symbolIdx );
802 QgsDebugError(
"symbol for rule " + symbolIdx +
" not found!" );
806 QString filterExp = ruleElem.attribute( QStringLiteral(
"filter" ) );
807 QString label = ruleElem.attribute( QStringLiteral(
"label" ) );
808 QString description = ruleElem.attribute( QStringLiteral(
"description" ) );
809 int scaleMinDenom = ruleElem.attribute( QStringLiteral(
"scalemindenom" ), QStringLiteral(
"0" ) ).toInt();
810 int scaleMaxDenom = ruleElem.attribute( QStringLiteral(
"scalemaxdenom" ), QStringLiteral(
"0" ) ).toInt();
813 ruleKey = ruleElem.attribute( QStringLiteral(
"key" ) );
815 ruleKey = QUuid::createUuid().toString();
816 Rule *rule =
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
818 if ( !ruleKey.isEmpty() )
819 rule->mRuleKey = ruleKey;
821 rule->
setActive( ruleElem.attribute( QStringLiteral(
"checkstate" ), QStringLiteral(
"1" ) ).toInt() );
823 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
824 while ( !childRuleElem.isNull() )
826 Rule *childRule =
create( childRuleElem, symbolMap );
833 QgsDebugError( QStringLiteral(
"failed to init a child rule!" ) );
835 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
854 if ( ruleElem.localName() != QLatin1String(
"Rule" ) )
856 QgsDebugError( QStringLiteral(
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
860 QString label, description, filterExp;
861 int scaleMinDenom = 0, scaleMaxDenom = 0;
865 QDomElement childElem = ruleElem.firstChildElement();
866 while ( !childElem.isNull() )
868 if ( childElem.localName() == QLatin1String(
"Name" ) )
872 if ( label.isEmpty() )
873 label = childElem.firstChild().nodeValue();
875 else if ( childElem.localName() == QLatin1String(
"Description" ) )
878 QDomElement titleElem = childElem.firstChildElement( QStringLiteral(
"Title" ) );
879 if ( !titleElem.isNull() )
881 label = titleElem.firstChild().nodeValue();
884 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral(
"Abstract" ) );
885 if ( !abstractElem.isNull() )
887 description = abstractElem.firstChild().nodeValue();
890 else if ( childElem.localName() == QLatin1String(
"Abstract" ) )
893 description = childElem.firstChild().nodeValue();
895 else if ( childElem.localName() == QLatin1String(
"Title" ) )
898 label = childElem.firstChild().nodeValue();
900 else if ( childElem.localName() == QLatin1String(
"Filter" ) )
905 if (
filter->hasParserError() )
911 filterExp =
filter->expression();
916 else if ( childElem.localName() == QLatin1String(
"ElseFilter" ) )
918 filterExp = QLatin1String(
"ELSE" );
921 else if ( childElem.localName() == QLatin1String(
"MinScaleDenominator" ) )
924 int v = childElem.firstChild().nodeValue().toInt( &ok );
928 else if ( childElem.localName() == QLatin1String(
"MaxScaleDenominator" ) )
931 int v = childElem.firstChild().nodeValue().toInt( &ok );
935 else if ( childElem.localName().endsWith( QLatin1String(
"Symbolizer" ) ) )
941 childElem = childElem.nextSiblingElement();
946 if ( !layers.isEmpty() )
969 return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
1004 std::function< void(
Rule *rule ) > exploreRule;
1005 exploreRule = [&res, &exploreRule](
Rule * rule )
1018 exploreRule( child );
1030 bool drawVertexMarker )
1050 QList<int> symbolZLevels( symbolZLevelsSet.begin(), symbolZLevelsSet.end() );
1051 std::sort( symbolZLevels.begin(), symbolZLevels.end() );
1055 QMap<int, int> zLevelsToNormLevels;
1056 int maxNormLevel = -1;
1057 const auto constSymbolZLevels = symbolZLevels;
1058 for (
int zLevel : constSymbolZLevels )
1060 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
1062 QgsDebugMsgLevel( QStringLiteral(
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
1085 for (
const RenderLevel &level : constMRenderQueue )
1089 for (
const RenderJob *job : std::as_const( level.jobs ) )
1096 for (
int i = 0; i < count; i++ )
1103 int flags = job->ftr.flags;
1145 Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
1146 for (
int i = 0; i < origDescendants.count(); ++i )
1147 clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
1159 toSld( doc, element, context );
1176 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"RuleRenderer" ) );
1181 rulesElem.setTagName( QStringLiteral(
"rules" ) );
1182 rendererElem.appendChild( rulesElem );
1185 rendererElem.appendChild( symbolsElem );
1189 return rendererElem;
1200 return rule ? rule->
active() :
true;
1217 std::function<QString(
Rule *rule )> ruleToExpression;
1218 ruleToExpression = [&ruleToExpression](
Rule * rule ) -> QString
1224 QStringList otherRules;
1225 const QList<QgsRuleBasedRenderer::Rule *> siblings = rule->
parent()->
children();
1226 for (
Rule *sibling : siblings )
1228 if ( sibling == rule || sibling->
isElse() )
1231 const QString siblingExpression = ruleToExpression( sibling );
1232 if ( siblingExpression.isEmpty() )
1233 return QStringLiteral(
"FALSE" );
1235 otherRules.append( siblingExpression );
1238 if ( otherRules.empty() )
1239 return QStringLiteral(
"TRUE" );
1242 otherRules.size() > 1
1243 ? QStringLiteral(
"NOT ((%1))" ).arg( otherRules.join( QLatin1String(
") OR (" ) ) )
1244 : QStringLiteral(
"NOT (%1)" ).arg( otherRules.at( 0 ) )
1249 QStringList ruleParts;
1254 ruleParts.append( QStringLiteral(
"@map_scale <= %1" ).arg( rule->
minimumScale() ) );
1257 ruleParts.append( QStringLiteral(
"@map_scale >= %1" ).arg( rule->
maximumScale() ) );
1259 if ( !ruleParts.empty() )
1262 ruleParts.size() > 1
1263 ? QStringLiteral(
"(%1)" ).arg( ruleParts.join( QLatin1String(
") AND (" ) ) )
1277 const QString ruleFilter = ruleToExpression( rule );
1278 if ( !ruleFilter.isEmpty() )
1279 parts.append( ruleFilter );
1285 return parts.empty() ? QStringLiteral(
"TRUE" )
1286 : ( parts.size() > 1
1287 ? QStringLiteral(
"(%1)" ).arg( parts.join( QLatin1String(
") AND (" ) ) )
1309 QDomElement symbolsElem = element.firstChildElement( QStringLiteral(
"symbols" ) );
1310 if ( symbolsElem.isNull() )
1315 QDomElement rulesElem = element.firstChildElement( QStringLiteral(
"rules" ) );
1332 Rule *root =
nullptr;
1334 QDomElement ruleElem = element.firstChildElement( QStringLiteral(
"Rule" ) );
1335 while ( !ruleElem.isNull() )
1342 root =
new Rule(
nullptr );
1347 ruleElem = ruleElem.nextSiblingElement( QStringLiteral(
"Rule" ) );
1375 const auto constCategories = r->
categories();
1382 else if ( cat.value().userType() == QMetaType::Type::Int )
1383 value = cat.value().toString();
1384 else if ( cat.value().userType() == QMetaType::Type::Double )
1387 value = QString::number( cat.value().toDouble(),
'f', 4 );
1390 const QString
filter = QStringLiteral(
"%1 %2 %3" ).arg( attr,
QgsVariantUtils::isNull( cat.value() ) ? QStringLiteral(
"IS" ) : QStringLiteral(
"=" ), value );
1391 const QString label = !cat.label().isEmpty() ? cat.label() :
1392 cat.value().isValid() ? value : QString();
1408 else if ( !testExpr.
isField() )
1411 attr = QStringLiteral(
"(%1)" ).arg( attr );
1414 bool firstRange =
true;
1415 const auto constRanges = r->
ranges();
1420 QString
filter = QStringLiteral(
"%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
1421 QString::number( rng.lowerValue(),
'f', 4 ),
1422 QString::number( rng.upperValue(),
'f', 4 ) );
1424 QString label = rng.label().isEmpty() ?
filter : rng.label();
1431 std::sort( scales.begin(), scales.end() );
1435 const auto constScales = scales;
1436 for (
int scale : constScales )
1440 if ( maxDenom != 0 && maxDenom <= scale )
1442 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1446 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1451 QString msg( QStringLiteral(
"Rule-based renderer:\n" ) );
1483 std::unique_ptr< QgsRuleBasedRenderer > r;
1484 if ( renderer->
type() == QLatin1String(
"RuleRenderer" ) )
1488 else if ( renderer->
type() == QLatin1String(
"singleSymbol" ) )
1491 if ( !singleSymbolRenderer )
1494 std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
1495 r = std::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
1497 else if ( renderer->
type() == QLatin1String(
"categorizedSymbol" ) )
1500 if ( !categorizedRenderer )
1505 bool isField =
false;
1515 if ( isField && !attr.contains(
'\"' ) )
1521 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1528 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1530 rule->setLabel( category.
label() );
1533 if ( category.
value().userType() == QMetaType::Type::QVariantList )
1536 const QVariantList list = category.
value().toList();
1537 for (
const QVariant &v : list )
1540 if ( QVariant( v ).convert( QMetaType::Type::Double ) )
1542 values << v.toString();
1550 if ( values.empty() )
1552 expression = QStringLiteral(
"ELSE" );
1556 expression = QStringLiteral(
"%1 IN (%2)" ).arg( attr, values.join(
',' ) );
1562 if ( category.
value().convert( QMetaType::Type::Double ) )
1564 value = category.
value().toString();
1572 if ( value == QLatin1String(
"''" ) )
1574 expression = QStringLiteral(
"ELSE" );
1578 expression = QStringLiteral(
"%1 = %2" ).arg( attr, value );
1581 rule->setFilterExpression( expression );
1587 std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
1588 rule->setSymbol( origSymbol.release() );
1590 rootrule->appendChild( rule.release() );
1593 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1595 else if ( renderer->
type() == QLatin1String(
"graduatedSymbol" ) )
1598 if ( !graduatedRenderer )
1604 bool isField =
false;
1614 if ( isField && !attr.contains(
'\"' ) )
1619 else if ( !isField )
1622 attr = QStringLiteral(
"(%1)" ).arg( attr );
1625 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1629 for (
int i = 0; i < graduatedRenderer->
ranges().size(); ++i )
1631 range = graduatedRenderer->
ranges().value( i );
1632 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1633 rule->setLabel( range.
label() );
1636 expression = attr +
" >= " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1637 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1641 expression = attr +
" > " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1642 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1644 rule->setFilterExpression( expression );
1650 std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
1651 rule->setSymbol( symbol.release() );
1653 rootrule->appendChild( rule.release() );
1656 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1658 else if ( renderer->
type() == QLatin1String(
"pointDisplacement" ) || renderer->
type() == QLatin1String(
"pointCluster" ) )
1663 else if ( renderer->
type() == QLatin1String(
"invertedPolygonRenderer" ) )
1668 else if ( renderer->
type() == QLatin1String(
"mergedFeatureRenderer" ) )
1673 else if ( renderer->
type() == QLatin1String(
"embeddedSymbol" ) && layer )
1677 auto rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1684 while ( it.
nextFeature( feature ) && rootrule->children().size() < 500 )
1688 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1689 rule->setFilterExpression( QStringLiteral(
"$id=%1" ).arg( feature.
id() ) );
1690 rule->setLabel( QString::number( feature.
id() ) );
1692 rootrule->appendChild( rule.release() );
1696 auto rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1697 rule->setFilterExpression( QStringLiteral(
"ELSE" ) );
1698 rule->setLabel( QObject::tr(
"All other features" ) );
1700 rootrule->appendChild( rule.release() );
1702 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1715 QString sizeExpression;
1716 switch ( symbol->
type() )
1722 if ( ! sizeScaleField.isEmpty() )
1724 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
1727 if ( ! rotationField.isEmpty() )
1734 if ( ! sizeScaleField.isEmpty() )
1741 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( lsl->
width() ).arg( sizeScaleField );
1750 sizeExpression = QStringLiteral(
"%1*(%2)" ).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.
Abstract base class for all 2D vector feature renderers.
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...
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.
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
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.
@ 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.
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.
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)
static QgsRuleBasedRenderer::Rule * create(QDomElement &ruleElem, QgsSymbolMap &symbolMap, bool reuseId=true)
Create a rule from an XML definition.
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< 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.