37#include <QDomDocument>
45 , mMaximumScale( scaleMinDenom )
46 , mMinimumScale( scaleMaxDenom )
47 , mFilterExp( filterExp )
49 , mDescription( description )
50 , mElseRule( elseRule )
53 mFilterExp = QStringLiteral(
"ELSE" );
55 mRuleKey = QUuid::createUuid().toString();
61 qDeleteAll( mChildren );
67 if ( mFilterExp.trimmed().compare( QLatin1String(
"ELSE" ), Qt::CaseInsensitive ) == 0 )
72 else if ( mFilterExp.trimmed().isEmpty() )
80 mFilter = std::make_unique< QgsExpression >( mFilterExp );
86 mChildren.append( rule );
93 mChildren.insert( i, rule );
100 mChildren.removeAll( rule );
107 delete mChildren.takeAt( i );
113 mChildren.removeAll( rule );
114 rule->mParent =
nullptr;
121 Rule *rule = mChildren.takeAt( i );
122 rule->mParent =
nullptr;
131 if ( key == mRuleKey )
134 const auto constMChildren = mChildren;
135 for (
Rule *rule : constMChildren )
144void QgsRuleBasedRenderer::Rule::updateElseRules()
147 const auto constMChildren = mChildren;
148 for (
Rule *rule : constMChildren )
150 if ( rule->isElse() )
157 mFilterExp = QStringLiteral(
"ELSE" );
175 if ( !mChildren.empty() )
177 for (
const Rule *rule : mChildren )
180 if ( !rule->accept( visitor ) )
194 off.fill( QChar(
' ' ), indent );
195 QString symbolDump = ( mSymbol ? mSymbol->dump() : QStringLiteral(
"[]" ) );
196 QString msg = off + QStringLiteral(
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
197 .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
198 .arg( mFilterExp, symbolDump );
201 const auto constMChildren = mChildren;
202 for (
Rule *rule : constMChildren )
204 lst.append( rule->dump( indent + 2 ) );
206 msg += lst.join( QLatin1Char(
'\n' ) );
215 attrs.unite(
mFilter->referencedColumns() );
217 attrs.unite( mSymbol->usedAttributes( context ) );
220 const auto constMChildren = mChildren;
221 for (
Rule *rule : constMChildren )
223 attrs.unite( rule->usedAttributes( context ) );
233 const auto constMChildren = mChildren;
234 for (
Rule *rule : constMChildren )
236 if ( rule->needsGeometry() )
247 lst.append( mSymbol.get() );
249 const auto constMChildren = mChildren;
250 for (
Rule *rule : constMChildren )
252 lst += rule->symbols( context );
259 mSymbol.reset( sym );
264 mFilterExp = filterExp;
271 if ( currentLevel != -1 )
273 lst <<
QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey,
true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
276 for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
287 if ( !
mFilter || mElseRule || ! context )
316 Rule *newrule =
new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
319 const auto constMChildren = mChildren;
320 for (
Rule *rule : constMChildren )
327 QDomElement ruleElem = doc.createElement( QStringLiteral(
"rule" ) );
331 int symbolIndex = symbolMap.size();
332 symbolMap[QString::number( symbolIndex )] = mSymbol.get();
333 ruleElem.setAttribute( QStringLiteral(
"symbol" ), symbolIndex );
335 if ( !mFilterExp.isEmpty() )
336 ruleElem.setAttribute( QStringLiteral(
"filter" ), mFilterExp );
337 if ( mMaximumScale != 0 )
338 ruleElem.setAttribute( QStringLiteral(
"scalemindenom" ), mMaximumScale );
339 if ( mMinimumScale != 0 )
340 ruleElem.setAttribute( QStringLiteral(
"scalemaxdenom" ), mMinimumScale );
341 if ( !mLabel.isEmpty() )
342 ruleElem.setAttribute( QStringLiteral(
"label" ), mLabel );
343 if ( !mDescription.isEmpty() )
344 ruleElem.setAttribute( QStringLiteral(
"description" ), mDescription );
346 ruleElem.setAttribute( QStringLiteral(
"checkstate" ), 0 );
347 ruleElem.setAttribute( QStringLiteral(
"key" ), mRuleKey );
349 const auto constMChildren = mChildren;
350 for (
Rule *rule : constMChildren )
352 ruleElem.
appendChild( rule->save( doc, symbolMap ) );
361 if (
symbols( context ).isEmpty() )
364 if ( !mFilterExp.isEmpty() )
366 QString
filter = props.value( QStringLiteral(
"filter" ), QString() ).toString();
368 filter += QLatin1String(
" AND " );
370 props[ QStringLiteral(
"filter" )] =
filter;
377 QDomElement ruleElem = doc.createElement( QStringLiteral(
"se:Rule" ) );
381 QDomElement nameElem = doc.createElement( QStringLiteral(
"se:Name" ) );
382 nameElem.appendChild( doc.createTextNode( mLabel ) );
383 ruleElem.appendChild( nameElem );
385 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
387 QDomElement descrElem = doc.createElement( QStringLiteral(
"se:Description" ) );
388 if ( !mLabel.isEmpty() )
390 QDomElement titleElem = doc.createElement( QStringLiteral(
"se:Title" ) );
391 titleElem.appendChild( doc.createTextNode( mLabel ) );
392 descrElem.appendChild( titleElem );
394 if ( !mDescription.isEmpty() )
396 QDomElement abstractElem = doc.createElement( QStringLiteral(
"se:Abstract" ) );
397 abstractElem.appendChild( doc.createTextNode( mDescription ) );
398 descrElem.appendChild( abstractElem );
400 ruleElem.appendChild( descrElem );
403 if ( !props.value( QStringLiteral(
"filter" ), QString() ).toString().isEmpty() )
410 mSymbol->toSld( doc, ruleElem, props );
416 element.appendChild( ruleElem );
421 const auto constMChildren = mChildren;
422 for (
Rule *rule : constMChildren )
424 rule->toSld( doc, element, props );
430 mActiveChildren.clear();
443 mSymbol->startRender( context, fields );
447 QStringList subfilters;
448 const auto constMChildren = mChildren;
449 for (
Rule *rule : constMChildren )
452 if ( rule->startRender( context, fields, subfilter ) )
455 mActiveChildren.append( rule );
456 subfilters.append( subfilter );
464 if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
466 if ( subfilters.contains( QStringLiteral(
"TRUE" ) ) )
468 sf = QStringLiteral(
"TRUE" );
479 else if ( subfilters.count() > 50 )
481 std::function<QString(
const QStringList & )>bt = [ &bt ](
const QStringList & subf )
483 if ( subf.count( ) == 1 )
487 else if ( subf.count( ) == 2 )
489 return subf.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
493 int midpos =
static_cast<int>( subf.length() / 2 );
494 return QStringLiteral(
"(%1) OR (%2)" ).arg( bt( subf.mid( 0, midpos ) ), bt( subf.mid( midpos ) ) );
497 sf = bt( subfilters );
501 sf = subfilters.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
513 if ( mSymbol || sf.isEmpty() )
514 filter = QStringLiteral(
"TRUE" );
520 else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
521 filter = QStringLiteral(
"(%1) AND (%2)" ).arg( mFilterExp, sf );
522 else if ( !mFilterExp.trimmed().isEmpty() )
524 else if ( sf.isEmpty() )
525 filter = QStringLiteral(
"TRUE" );
536 return !mActiveChildren.empty();
541 QSet<int> symbolZLevelsSet;
547 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
549 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
554 QList<Rule *>::iterator it;
555 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
560 return symbolZLevelsSet;
567 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
569 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
570 mSymbolNormZLevels.insert( normLevel );
575 const auto constMActiveChildren = mActiveChildren;
576 for (
Rule *rule : constMActiveChildren )
585 if ( !isFilterOK( featToRender.
feat, &context ) )
588 bool rendered =
false;
591 if ( mSymbol && mIsActive )
594 const auto constMSymbolNormZLevels = mSymbolNormZLevels;
595 for (
int normZLevel : constMSymbolNormZLevels )
598 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol.get() ) );
603 bool matchedAChild =
false;
606 const auto constMChildren = mChildren;
607 for (
Rule *rule : constMChildren )
610 if ( !rule->isElse() )
612 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
614 matchedAChild |= ( res == Rendered || res == Inactive );
615 rendered |= ( res == Rendered );
620 if ( !matchedAChild )
622 const auto constMElseRules = mElseRules;
623 for (
Rule *rule : constMElseRules )
625 const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
626 matchedAChild |= ( res == Rendered || res == Inactive );
627 rendered |= res == Rendered;
630 if ( !mIsActive || ( mSymbol && !rendered ) || ( matchedAChild && !rendered ) )
640 if ( !isFilterOK( feature, context ) )
646 const auto constMActiveChildren = mActiveChildren;
647 for (
Rule *rule : constMActiveChildren )
649 if ( rule->isElse() )
651 if ( rule->children().isEmpty() )
653 RuleList lst = rulesForFeature( feature, context,
false );
654 lst.removeOne( rule );
663 return rule->willRenderFeature( feature, context );
666 else if ( rule->willRenderFeature( feature, context ) )
677 if ( !isFilterOK( feature, context ) )
680 lst.append( mSymbol.get() );
682 const auto constMActiveChildren = mActiveChildren;
683 for (
Rule *rule : constMActiveChildren )
685 lst += rule->symbolsForFeature( feature, context );
693 if ( !isFilterOK( feature, context ) )
696 res.insert( mRuleKey );
699 bool matchedNonElseRule =
false;
700 for (
Rule *rule : std::as_const( mActiveChildren ) )
702 if ( rule->isElse() )
706 if ( rule->willRenderFeature( feature, context ) )
708 res.unite( rule->legendKeysForFeature( feature, context ) );
709 matchedNonElseRule =
true;
714 if ( !matchedNonElseRule )
716 for (
Rule *rule : std::as_const( mActiveChildren ) )
718 if ( rule->isElse() )
720 if ( rule->children().isEmpty() )
722 RuleList lst = rulesForFeature( feature, context,
false );
723 lst.removeOne( rule );
727 res.unite( rule->legendKeysForFeature( feature, context ) );
732 res.unite( rule->legendKeysForFeature( feature, context ) );
743 if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->
rendererScale() ) ) )
751 listChildren = mActiveChildren;
753 for (
Rule *rule : std::as_const( listChildren ) )
755 lst += rule->rulesForFeature( feature, context, onlyActive );
763 mSymbol->stopRender( context );
765 const auto constMActiveChildren = mActiveChildren;
766 for (
Rule *rule : constMActiveChildren )
768 rule->stopRender( context );
771 mActiveChildren.clear();
772 mSymbolNormZLevels.clear();
777 QString symbolIdx = ruleElem.attribute( QStringLiteral(
"symbol" ) );
779 if ( !symbolIdx.isEmpty() )
781 if ( symbolMap.contains( symbolIdx ) )
783 symbol = symbolMap.take( symbolIdx );
787 QgsDebugError(
"symbol for rule " + symbolIdx +
" not found!" );
791 QString filterExp = ruleElem.attribute( QStringLiteral(
"filter" ) );
792 QString label = ruleElem.attribute( QStringLiteral(
"label" ) );
793 QString description = ruleElem.attribute( QStringLiteral(
"description" ) );
794 int scaleMinDenom = ruleElem.attribute( QStringLiteral(
"scalemindenom" ), QStringLiteral(
"0" ) ).toInt();
795 int scaleMaxDenom = ruleElem.attribute( QStringLiteral(
"scalemaxdenom" ), QStringLiteral(
"0" ) ).toInt();
798 ruleKey = ruleElem.attribute( QStringLiteral(
"key" ) );
800 ruleKey = QUuid::createUuid().toString();
801 Rule *rule =
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
803 if ( !ruleKey.isEmpty() )
804 rule->mRuleKey = ruleKey;
806 rule->
setActive( ruleElem.attribute( QStringLiteral(
"checkstate" ), QStringLiteral(
"1" ) ).toInt() );
808 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
809 while ( !childRuleElem.isNull() )
811 Rule *childRule =
create( childRuleElem, symbolMap );
818 QgsDebugError( QStringLiteral(
"failed to init a child rule!" ) );
820 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
839 if ( ruleElem.localName() != QLatin1String(
"Rule" ) )
841 QgsDebugError( QStringLiteral(
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
845 QString label, description, filterExp;
846 int scaleMinDenom = 0, scaleMaxDenom = 0;
850 QDomElement childElem = ruleElem.firstChildElement();
851 while ( !childElem.isNull() )
853 if ( childElem.localName() == QLatin1String(
"Name" ) )
857 if ( label.isEmpty() )
858 label = childElem.firstChild().nodeValue();
860 else if ( childElem.localName() == QLatin1String(
"Description" ) )
863 QDomElement titleElem = childElem.firstChildElement( QStringLiteral(
"Title" ) );
864 if ( !titleElem.isNull() )
866 label = titleElem.firstChild().nodeValue();
869 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral(
"Abstract" ) );
870 if ( !abstractElem.isNull() )
872 description = abstractElem.firstChild().nodeValue();
875 else if ( childElem.localName() == QLatin1String(
"Abstract" ) )
878 description = childElem.firstChild().nodeValue();
880 else if ( childElem.localName() == QLatin1String(
"Title" ) )
883 label = childElem.firstChild().nodeValue();
885 else if ( childElem.localName() == QLatin1String(
"Filter" ) )
890 if (
filter->hasParserError() )
896 filterExp =
filter->expression();
901 else if ( childElem.localName() == QLatin1String(
"ElseFilter" ) )
903 filterExp = QLatin1String(
"ELSE" );
906 else if ( childElem.localName() == QLatin1String(
"MinScaleDenominator" ) )
909 int v = childElem.firstChild().nodeValue().toInt( &ok );
913 else if ( childElem.localName() == QLatin1String(
"MaxScaleDenominator" ) )
916 int v = childElem.firstChild().nodeValue().toInt( &ok );
920 else if ( childElem.localName().endsWith( QLatin1String(
"Symbolizer" ) ) )
926 childElem = childElem.nextSiblingElement();
931 if ( !layers.isEmpty() )
954 return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
989 std::function< void(
Rule *rule ) > exploreRule;
990 exploreRule = [&res, &exploreRule](
Rule * rule )
1003 exploreRule( child );
1015 bool drawVertexMarker )
1035 QList<int> symbolZLevels( symbolZLevelsSet.begin(), symbolZLevelsSet.end() );
1036 std::sort( symbolZLevels.begin(), symbolZLevels.end() );
1040 QMap<int, int> zLevelsToNormLevels;
1041 int maxNormLevel = -1;
1042 const auto constSymbolZLevels = symbolZLevels;
1043 for (
int zLevel : constSymbolZLevels )
1045 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
1047 QgsDebugMsgLevel( QStringLiteral(
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
1070 for (
const RenderLevel &level : constMRenderQueue )
1074 for (
const RenderJob *job : std::as_const( level.jobs ) )
1081 for (
int i = 0; i < count; i++ )
1088 int flags = job->ftr.flags;
1130 Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
1131 for (
int i = 0; i < origDescendants.count(); ++i )
1132 clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
1154 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"RuleRenderer" ) );
1159 rulesElem.setTagName( QStringLiteral(
"rules" ) );
1160 rendererElem.appendChild( rulesElem );
1163 rendererElem.appendChild( symbolsElem );
1167 return rendererElem;
1178 return rule ? rule->
active() :
true;
1195 std::function<QString(
Rule *rule )> ruleToExpression;
1196 ruleToExpression = [&ruleToExpression](
Rule * rule ) -> QString
1202 QStringList otherRules;
1203 const QList<QgsRuleBasedRenderer::Rule *> siblings = rule->
parent()->
children();
1204 for (
Rule *sibling : siblings )
1206 if ( sibling == rule || sibling->
isElse() )
1209 const QString siblingExpression = ruleToExpression( sibling );
1210 if ( siblingExpression.isEmpty() )
1211 return QStringLiteral(
"FALSE" );
1213 otherRules.append( siblingExpression );
1216 if ( otherRules.empty() )
1217 return QStringLiteral(
"TRUE" );
1220 otherRules.size() > 1
1221 ? QStringLiteral(
"NOT ((%1))" ).arg( otherRules.join( QLatin1String(
") OR (" ) ) )
1222 : QStringLiteral(
"NOT (%1)" ).arg( otherRules.at( 0 ) )
1227 QStringList ruleParts;
1232 ruleParts.append( QStringLiteral(
"@map_scale <= %1" ).arg( rule->
minimumScale() ) );
1235 ruleParts.append( QStringLiteral(
"@map_scale >= %1" ).arg( rule->
maximumScale() ) );
1237 if ( !ruleParts.empty() )
1240 ruleParts.size() > 1
1241 ? QStringLiteral(
"(%1)" ).arg( ruleParts.join( QLatin1String(
") AND (" ) ) )
1255 const QString ruleFilter = ruleToExpression( rule );
1256 if ( !ruleFilter.isEmpty() )
1257 parts.append( ruleFilter );
1263 return parts.empty() ? QStringLiteral(
"TRUE" )
1264 : ( parts.size() > 1
1265 ? QStringLiteral(
"(%1)" ).arg( parts.join( QLatin1String(
") AND (" ) ) )
1287 QDomElement symbolsElem = element.firstChildElement( QStringLiteral(
"symbols" ) );
1288 if ( symbolsElem.isNull() )
1293 QDomElement rulesElem = element.firstChildElement( QStringLiteral(
"rules" ) );
1310 Rule *root =
nullptr;
1312 QDomElement ruleElem = element.firstChildElement( QStringLiteral(
"Rule" ) );
1313 while ( !ruleElem.isNull() )
1320 root =
new Rule(
nullptr );
1325 ruleElem = ruleElem.nextSiblingElement( QStringLiteral(
"Rule" ) );
1353 const auto constCategories = r->
categories();
1360 else if ( cat.value().userType() == QMetaType::Type::Int )
1361 value = cat.value().toString();
1362 else if ( cat.value().userType() == QMetaType::Type::Double )
1365 value = QString::number( cat.value().toDouble(),
'f', 4 );
1368 const QString
filter = QStringLiteral(
"%1 %2 %3" ).arg( attr,
QgsVariantUtils::isNull( cat.value() ) ? QStringLiteral(
"IS" ) : QStringLiteral(
"=" ), value );
1369 const QString label = !cat.label().isEmpty() ? cat.label() :
1370 cat.value().isValid() ? value : QString();
1386 else if ( !testExpr.
isField() )
1389 attr = QStringLiteral(
"(%1)" ).arg( attr );
1392 bool firstRange =
true;
1393 const auto constRanges = r->
ranges();
1398 QString
filter = QStringLiteral(
"%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
1399 QString::number( rng.lowerValue(),
'f', 4 ),
1400 QString::number( rng.upperValue(),
'f', 4 ) );
1402 QString label = rng.label().isEmpty() ?
filter : rng.label();
1409 std::sort( scales.begin(), scales.end() );
1413 const auto constScales = scales;
1414 for (
int scale : constScales )
1418 if ( maxDenom != 0 && maxDenom <= scale )
1420 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1424 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1429 QString msg( QStringLiteral(
"Rule-based renderer:\n" ) );
1461 std::unique_ptr< QgsRuleBasedRenderer > r;
1462 if ( renderer->
type() == QLatin1String(
"RuleRenderer" ) )
1466 else if ( renderer->
type() == QLatin1String(
"singleSymbol" ) )
1469 if ( !singleSymbolRenderer )
1472 std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
1473 r = std::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
1475 else if ( renderer->
type() == QLatin1String(
"categorizedSymbol" ) )
1478 if ( !categorizedRenderer )
1483 bool isField =
false;
1493 if ( isField && !attr.contains(
'\"' ) )
1499 std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1506 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1508 rule->setLabel( category.
label() );
1511 if ( category.
value().userType() == QMetaType::Type::QVariantList )
1514 const QVariantList list = category.
value().toList();
1515 for (
const QVariant &v : list )
1518 if ( QVariant( v ).convert( QMetaType::Type::Double ) )
1520 values << v.toString();
1528 if ( values.empty() )
1530 expression = QStringLiteral(
"ELSE" );
1534 expression = QStringLiteral(
"%1 IN (%2)" ).arg( attr, values.join(
',' ) );
1540 if ( category.
value().convert( QMetaType::Type::Double ) )
1542 value = category.
value().toString();
1550 if ( value == QLatin1String(
"''" ) )
1552 expression = QStringLiteral(
"ELSE" );
1556 expression = QStringLiteral(
"%1 = %2" ).arg( attr, value );
1559 rule->setFilterExpression( expression );
1565 std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
1566 rule->setSymbol( origSymbol.release() );
1568 rootrule->appendChild( rule.release() );
1571 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1573 else if ( renderer->
type() == QLatin1String(
"graduatedSymbol" ) )
1576 if ( !graduatedRenderer )
1582 bool isField =
false;
1592 if ( isField && !attr.contains(
'\"' ) )
1597 else if ( !isField )
1600 attr = QStringLiteral(
"(%1)" ).arg( attr );
1603 std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1607 for (
int i = 0; i < graduatedRenderer->
ranges().size(); ++i )
1609 range = graduatedRenderer->
ranges().value( i );
1610 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1611 rule->setLabel( range.
label() );
1614 expression = attr +
" >= " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1615 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1619 expression = attr +
" > " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1620 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1622 rule->setFilterExpression( expression );
1628 std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
1629 rule->setSymbol( symbol.release() );
1631 rootrule->appendChild( rule.release() );
1634 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1636 else if ( renderer->
type() == QLatin1String(
"pointDisplacement" ) || renderer->
type() == QLatin1String(
"pointCluster" ) )
1641 else if ( renderer->
type() == QLatin1String(
"invertedPolygonRenderer" ) )
1646 else if ( renderer->
type() == QLatin1String(
"mergedFeatureRenderer" ) )
1651 else if ( renderer->
type() == QLatin1String(
"embeddedSymbol" ) && layer )
1655 std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1662 while ( it.
nextFeature( feature ) && rootrule->children().size() < 500 )
1666 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1667 rule->setFilterExpression( QStringLiteral(
"$id=%1" ).arg( feature.
id() ) );
1668 rule->setLabel( QString::number( feature.
id() ) );
1670 rootrule->appendChild( rule.release() );
1674 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1675 rule->setFilterExpression( QStringLiteral(
"ELSE" ) );
1676 rule->setLabel( QObject::tr(
"All other features" ) );
1678 rootrule->appendChild( rule.release() );
1680 r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1693 QString sizeExpression;
1694 switch ( symbol->
type() )
1700 if ( ! sizeScaleField.isEmpty() )
1702 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
1705 if ( ! rotationField.isEmpty() )
1712 if ( ! sizeScaleField.isEmpty() )
1719 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( lsl->
width() ).arg( sizeScaleField );
1728 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.
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.
Class for 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.
This class 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.
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
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.
QgsMergedFeatureRenderer is a polygon or line-only feature renderer used to renderer a set of feature...
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.
The class is used as a container of context for various read/write operations on other 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...
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.
This class keeps data about a rules for 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
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.
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.
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.
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
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 bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
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 data sets.
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.