QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
qgsgraduatedsymbolrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgraduatedsymbolrenderer.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <cmath>
19#include <ctime>
20#include <memory>
21
22#include "qgsapplication.h"
23#include "qgsattributes.h"
29#include "qgscolorramp.h"
30#include "qgscolorrampimpl.h"
32#include "qgsexpression.h"
34#include "qgsfeature.h"
36#include "qgslinesymbol.h"
37#include "qgsmarkersymbol.h"
38#include "qgspainteffect.h"
40#include "qgsproperty.h"
41#include "qgssldexportcontext.h"
43#include "qgssymbol.h"
44#include "qgssymbollayer.h"
45#include "qgssymbollayerutils.h"
47#include "qgsvectorlayer.h"
48#include "qgsvectorlayerutils.h"
49
50#include <QDomDocument>
51#include <QDomElement>
52
54 : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
55 , mAttrName( attrName )
56{
57 // TODO: check ranges for sanity (NULL symbols, invalid ranges)
58
59 //important - we need a deep copy of the ranges list, not a shared copy. This is required because
60 //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
61 //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
62 const auto constRanges = ranges;
63 for ( const QgsRendererRange &range : constRanges )
64 {
65 mRanges << range;
66 }
67
68 mClassificationMethod = std::make_shared<QgsClassificationCustom>( );
69}
70
72{
73 mRanges.clear(); // should delete all the symbols
74}
75
77{
79 auto catIt = mRanges.constBegin();
80 for ( ; catIt != mRanges.constEnd(); ++catIt )
81 {
82 if ( QgsSymbol *catSymbol = catIt->symbol() )
83 {
84 if ( catSymbol->flags().testFlag( Qgis::SymbolFlag::AffectsLabeling ) )
86 }
87 }
88
89 return res;
90}
91
93{
94 for ( const QgsRendererRange &range : mRanges )
95 {
96 if ( range.lowerValue() <= value && range.upperValue() >= value )
97 {
98 if ( range.renderState() || mCounting )
99 return &range;
100 else
101 return nullptr;
102 }
103 }
104
105 // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
106 // if a value falls just outside of a range, but within acceptable double precision tolerance
107 // then we accept it anyway
108 for ( const QgsRendererRange &range : mRanges )
109 {
110 if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
111 {
112 if ( range.renderState() || mCounting )
113 return &range;
114 else
115 return nullptr;
116 }
117 }
118 // the value is out of the range: return NULL instead of symbol
119 return nullptr;
120}
121
123{
124 if ( const QgsRendererRange *range = rangeForValue( value ) )
125 return range->symbol();
126 return nullptr;
127}
128
130{
131 if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
132 {
133 for ( const QgsRendererRange &range : mRanges )
134 {
135 if ( matchingRange == &range )
136 return range.uuid();
137 }
138 }
139 return QString();
140}
141
143{
144 return originalSymbolForFeature( feature, context );
145}
146
147QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
148{
149 QgsAttributes attrs = feature.attributes();
150 QVariant value;
151 if ( mExpression )
152 {
153 value = mExpression->evaluate( &context.expressionContext() );
154 }
155 else
156 {
157 value = attrs.value( mAttrNum );
158 }
159
160 return value;
161}
162
164{
165 QVariant value = valueForFeature( feature, context );
166
167 // Null values should not be categorized
168 if ( QgsVariantUtils::isNull( value ) )
169 return nullptr;
170
171 // find the right category
172 return symbolForValue( value.toDouble() );
173}
174
176{
177 QgsFeatureRenderer::startRender( context, fields );
178
179 mCounting = context.rendererScale() == 0.0;
180
181 // find out classification attribute index from name
182 mAttrNum = fields.lookupField( mAttrName );
183
184 if ( mAttrNum == -1 )
185 {
186 mExpression = std::make_unique<QgsExpression>( mAttrName );
187 mExpression->prepare( &context.expressionContext() );
188 }
189
190 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
191 {
192 if ( !range.symbol() )
193 continue;
194
195 range.symbol()->startRender( context, fields );
196 }
197}
198
200{
202
203 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
204 {
205 if ( !range.symbol() )
206 continue;
207
208 range.symbol()->stopRender( context );
209 }
210}
211
213{
214 QSet<QString> attributes;
215
216 // mAttrName can contain either attribute name or an expression.
217 // Sometimes it is not possible to distinguish between those two,
218 // e.g. "a - b" can be both a valid attribute name or expression.
219 // Since we do not have access to fields here, try both options.
220 attributes << mAttrName;
221
222 QgsExpression testExpr( mAttrName );
223 if ( !testExpr.hasParserError() )
224 attributes.unite( testExpr.referencedColumns() );
225
226 QgsRangeList::const_iterator range_it = mRanges.constBegin();
227 for ( ; range_it != mRanges.constEnd(); ++range_it )
228 {
229 QgsSymbol *symbol = range_it->symbol();
230 if ( symbol )
231 {
232 attributes.unite( symbol->usedAttributes( context ) );
233 }
234 }
235 return attributes;
236}
237
239{
240 QgsExpression testExpr( mAttrName );
241 if ( !testExpr.hasParserError() )
242 {
243 QgsExpressionContext context;
244 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
245 testExpr.prepare( &context );
246 return testExpr.needsGeometry();
247 }
248 return false;
249}
250
252{
253 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
254 return false;
255 mRanges[rangeIndex].setSymbol( symbol );
256 return true;
257}
258
259bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
260{
261 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
262 return false;
263 mRanges[rangeIndex].setLabel( label );
264 return true;
265}
266
267bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
268{
269 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
270 return false;
271 QgsRendererRange &range = mRanges[rangeIndex];
273 if ( rangeIndex == 0 )
275 else if ( rangeIndex == mRanges.count() )
277
278 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
279 range.setUpperValue( value );
280 if ( isDefaultLabel )
281 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
282
283 return true;
284}
285
286bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
287{
288 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
289 return false;
290
291 QgsRendererRange &range = mRanges[rangeIndex];
293 if ( rangeIndex == 0 )
295 else if ( rangeIndex == mRanges.count() )
297
298 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
299 range.setLowerValue( value );
300 if ( isDefaultLabel )
301 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
302
303 return true;
304}
305
307{
308 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
309 return false;
310 mRanges[rangeIndex].setRenderState( value );
311 return true;
312}
313
315{
316 QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
317 for ( int i = 0; i < mRanges.count(); i++ )
318 s += mRanges[i].dump();
319 return s;
320}
321
339
340void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
341{
342 QgsSldExportContext context;
343 context.setExtraProperties( props );
344 toSld( doc, element, context );
345}
346
347bool QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
348{
349 const QVariantMap oldProps = context.extraProperties();
350 QVariantMap newProps = oldProps;
351 newProps[ QStringLiteral( "attribute" )] = mAttrName;
352 newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
353 context.setExtraProperties( newProps );
354
355 // create a Rule for each range
356 bool first = true;
357 bool result = true;
358 for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
359 {
360 if ( !it->toSld( doc, element, mAttrName, context, first ) )
361 result = false;
362 first = false;
363 }
364 context.setExtraProperties( oldProps );
365 return result;
366}
367
369{
370 Q_UNUSED( context )
371 QgsSymbolList lst;
372 lst.reserve( mRanges.count() );
373 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
374 {
375 lst.append( range.symbol() );
376 }
377 return lst;
378}
379
381{
382 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
383 {
384 QgsStyleSymbolEntity entity( range.symbol() );
385 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
386 return false;
387 }
388
389 if ( mSourceColorRamp )
390 {
392 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
393 return false;
394 }
395
396 return true;
397}
398
403
404QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
405{
408 QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
410}
411
414 QgsVectorLayer *vlayer,
415 const QString &attrName,
416 int classes,
417 Mode mode,
418 QgsSymbol *symbol,
419 QgsColorRamp *ramp,
421 bool useSymmetricMode,
422 double symmetryPoint,
423 const QStringList &listForCboPrettyBreaks,
424 bool astride
425)
426{
427 Q_UNUSED( listForCboPrettyBreaks )
428
430 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
431 r->setSourceSymbol( symbol->clone() );
432 r->setSourceColorRamp( ramp->clone() );
433
434 QString methodId = methodIdFromMode( mode );
435 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
436
437 if ( method )
438 {
439 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
440 method->setLabelFormat( labelFormat.format() );
441 method->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
442 method->setLabelPrecision( labelFormat.precision() );
443 }
444 r->setClassificationMethod( method.release() );
445
446 QString error;
447 r->updateClasses( vlayer, classes, error );
448 ( void )error;
449
450 return r.release();
451}
453
455 bool useSymmetricMode, double symmetryPoint, bool astride )
456{
457 if ( mAttrName.isEmpty() )
458 return;
459
460 QString methodId = methodIdFromMode( mode );
461 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
462 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
463 setClassificationMethod( method.release() );
464
465 QString error;
466 updateClasses( vlayer, nclasses, error );
467 ( void )error;
468}
469
470void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int nclasses, QString &error )
471{
472 Q_UNUSED( error )
474 return;
475
476 QList<QgsClassificationRange> classes = mClassificationMethod->classesV2( vl, mAttrName, nclasses, error );
477
479
480 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
481 {
483 addClass( QgsRendererRange( *it, newSymbol ) );
484 }
485 updateColorRamp( nullptr );
486}
487
494
496{
497 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
498 if ( symbolsElem.isNull() )
499 return nullptr;
500
501 QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
502 if ( rangesElem.isNull() )
503 return nullptr;
504
505 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
507
508 QDomElement rangeElem = rangesElem.firstChildElement();
509 int i = 0;
510 QSet<QString> usedUuids;
511 while ( !rangeElem.isNull() )
512 {
513 if ( rangeElem.tagName() == QLatin1String( "range" ) )
514 {
515 double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
516 double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
517 QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
518 QString label = rangeElem.attribute( QStringLiteral( "label" ) );
519 bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
520 QString uuid = rangeElem.attribute( QStringLiteral( "uuid" ), QString::number( i++ ) );
521 while ( usedUuids.contains( uuid ) )
522 {
523 uuid = QUuid::createUuid().toString();
524 }
525 if ( symbolMap.contains( symbolName ) )
526 {
527 QgsSymbol *symbol = symbolMap.take( symbolName );
528 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
529 usedUuids << uuid;
530 }
531 }
532 rangeElem = rangeElem.nextSiblingElement();
533 }
534
535 QString attrName = element.attribute( QStringLiteral( "attr" ) );
536
537 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
538
539 QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
540 if ( !attrMethod.isEmpty() )
541 {
543 r->setGraduatedMethod( Qgis::GraduatedMethod::Color );
544 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
545 r->setGraduatedMethod( Qgis::GraduatedMethod::Size );
546 }
547
548
549 // delete symbols if there are any more
551
552 // try to load source symbol (optional)
553 QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
554 if ( !sourceSymbolElem.isNull() )
555 {
556 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
557 if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
558 {
559 r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
560 }
561 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
562 }
563
564 // try to load color ramp (optional)
565 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
566 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
567 {
568 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ).release() );
569 }
570
571 // try to load mode
572
573 QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
574 QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
575 std::unique_ptr< QgsClassificationMethod > method;
576
577 // TODO QGIS 4 Remove
578 // backward compatibility for QGIS project < 3.10
579 if ( !modeElem.isNull() )
580 {
581 QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
582 QString methodId;
583 // the strings saved in the project does not match with the old Mode enum
584 if ( modeString == QLatin1String( "equal" ) )
585 methodId = QStringLiteral( "EqualInterval" );
586 else if ( modeString == QLatin1String( "quantile" ) )
587 methodId = QStringLiteral( "Quantile" );
588 else if ( modeString == QLatin1String( "jenks" ) )
589 methodId = QStringLiteral( "Jenks" );
590 else if ( modeString == QLatin1String( "stddev" ) )
591 methodId = QStringLiteral( "StdDev" );
592 else if ( modeString == QLatin1String( "pretty" ) )
593 methodId = QStringLiteral( "Pretty" );
594
596
597 // symmetric mode
598 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
599 if ( !symmetricModeElem.isNull() )
600 {
601 // symmetry
602 QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
603 QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
604 QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
605 method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
606 }
607 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
608 if ( !labelFormatElem.isNull() )
609 {
610 // label format
611 QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
612 int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
613 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
614 method->setLabelFormat( format );
615 method->setLabelPrecision( precision );
616 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
617 }
618 // End of backward compatibility
619 }
620 else
621 {
622 // QGIS project 3.10+
623 method = QgsClassificationMethod::create( methodElem, context );
624 }
625
626 // apply the method
627 r->setClassificationMethod( method.release() );
628
629 QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
630 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
631 {
632 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
633 {
634 convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
635 }
636 if ( r->mSourceSymbol )
637 {
638 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
639 }
640 }
641 QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
642 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
643 {
644 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
645 {
646 convertSymbolSizeScale( range.symbol(),
647 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
648 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
649 }
650 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
651 {
652 convertSymbolSizeScale( r->mSourceSymbol.get(),
653 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
654 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
655 }
656 }
657
658 QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
659 if ( !ddsLegendSizeElem.isNull() )
660 {
661 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
662 }
663// TODO: symbol levels
664 return r.release();
665}
666
667QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
668{
669 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
670 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
671 rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
672 rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
673
674 // ranges
675 int i = 0;
677 QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
678 QgsRangeList::const_iterator it = mRanges.constBegin();
679 for ( ; it != mRanges.constEnd(); ++it )
680 {
681 const QgsRendererRange &range = *it;
682 QString symbolName = QString::number( i );
683 symbols.insert( symbolName, range.symbol() );
684
685 QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
686 rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
687 rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
688 rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
689 rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
690 rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
691 rangeElem.setAttribute( QStringLiteral( "uuid" ), range.uuid() );
692 rangesElem.appendChild( rangeElem );
693 i++;
694 }
695
696 rendererElem.appendChild( rangesElem );
697
698 // save symbols
699 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
700 rendererElem.appendChild( symbolsElem );
701
702 // save source symbol
703 if ( mSourceSymbol )
704 {
705 QgsSymbolMap sourceSymbols;
706 sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
707 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
708 rendererElem.appendChild( sourceSymbolElem );
709 }
710
711 // save source color ramp
712 if ( mSourceColorRamp )
713 {
714 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
715 rendererElem.appendChild( colorRampElem );
716 }
717
718 // save classification method
719 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
720 rendererElem.appendChild( classificationMethodElem );
721
722 QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
723 rendererElem.appendChild( rotationElem );
724
725 QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
726 rendererElem.appendChild( sizeScaleElem );
727
729 {
730 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
731 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
732 rendererElem.appendChild( ddsLegendElem );
733 }
734
735 saveRendererData( doc, rendererElem, context );
736
737 return rendererElem;
738}
739
740QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
741{
743 lst.reserve( mRanges.size() );
744 for ( const QgsRendererRange &range : mRanges )
745 {
746 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
747 }
748 return lst;
749}
750
752QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
753{
754 switch ( mode )
755 {
756 case EqualInterval:
757 return QStringLiteral( "EqualInterval" );
758 case Quantile:
759 return QStringLiteral( "Quantile" );
760 case Jenks:
761 return QStringLiteral( "Jenks" );
762 case StdDev:
763 return QStringLiteral( "StdDev" );
764 case Pretty:
765 return QStringLiteral( "Pretty" );
766 case Custom:
767 return QString();
768 }
769 return QString();
770}
771
772QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
773{
774 if ( methodId == QLatin1String( "EqualInterval" ) )
775 return EqualInterval;
776 if ( methodId == QLatin1String( "Quantile" ) )
777 return Quantile;
778 if ( methodId == QLatin1String( "Jenks" ) )
779 return Jenks;
780 if ( methodId == QLatin1String( "StdDev" ) )
781 return StdDev;
782 if ( methodId == QLatin1String( "Pretty" ) )
783 return Pretty;
784 else
785 return Custom;
786}
788
790{
792 {
793 // check that all symbols that have the same size expression
794 QgsProperty ddSize;
795 for ( const QgsRendererRange &range : mRanges )
796 {
797 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
798 if ( ddSize )
799 {
800 QgsProperty sSize( symbol->dataDefinedSize() );
801 if ( sSize && sSize != ddSize )
802 {
803 // no common size expression
804 return baseLegendSymbolItems();
805 }
806 }
807 else
808 {
809 ddSize = symbol->dataDefinedSize();
810 }
811 }
812
813 if ( ddSize && ddSize.isActive() )
814 {
816
818 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
819 lst += ddSizeLegend.legendSymbolList();
820
821 lst += baseLegendSymbolItems();
822 return lst;
823 }
824 }
825
826 return baseLegendSymbolItems();
827}
828
829QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
830{
831 QVariant value = valueForFeature( feature, context );
832
833 // Null values should not be categorized
834 if ( QgsVariantUtils::isNull( value ) )
835 return QSet< QString >();
836
837 // find the right category
838 QString key = legendKeyForValue( value.toDouble() );
839 if ( !key.isNull() )
840 return QSet< QString >() << key;
841 else
842 return QSet< QString >();
843}
844
845QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
846{
847 ok = false;
848 int i = 0;
849 for ( i = 0; i < mRanges.size(); i++ )
850 {
851 if ( mRanges[i].uuid() == key )
852 {
853 ok = true;
854 break;
855 }
856 }
857
858 if ( !ok )
859 {
860 ok = false;
861 return QString();
862 }
863
864 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
865 const QgsRendererRange &range = mRanges[i];
866
867 return QStringLiteral( "(%1 >= %2) AND (%1 <= %3)" ).arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QMetaType::Type::Double ),
868 QgsExpression::quotedValue( range.upperValue(), QMetaType::Type::Double ) );
869}
870
875
877{
878 return mSourceSymbol.get();
879}
880
885
890
895
897{
898 if ( ramp == mSourceColorRamp.get() )
899 return;
900
901 mSourceColorRamp.reset( ramp );
902}
903
905{
906 double min = std::numeric_limits<double>::max();
907 for ( int i = 0; i < mRanges.count(); i++ )
908 {
909 double sz = 0;
910 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
911 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
912 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
913 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
914 min = std::min( sz, min );
915 }
916 return min;
917}
918
920{
921 double max = std::numeric_limits<double>::min();
922 for ( int i = 0; i < mRanges.count(); i++ )
923 {
924 double sz = 0;
925 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
926 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
927 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
928 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
929 max = std::max( sz, max );
930 }
931 return max;
932}
933
934void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
935{
936 for ( int i = 0; i < mRanges.count(); i++ )
937 {
938 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
939 const double size = mRanges.count() > 1
940 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
941 : .5 * ( maxSize + minSize );
942 if ( symbol )
943 {
944 switch ( symbol->type() )
945 {
947 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
948 break;
950 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
951 break;
954 break;
955 }
956 updateRangeSymbol( i, symbol.release() );
957 }
958 }
959}
960
962{
963 int i = 0;
964 if ( ramp )
965 {
966 setSourceColorRamp( ramp );
967 }
968
969 if ( mSourceColorRamp )
970 {
971 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
972 {
973 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
974 if ( symbol )
975 {
976 double colorValue;
977 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
978 symbol->setColor( mSourceColorRamp->color( colorValue ) );
979 }
980 updateRangeSymbol( i, symbol );
981 ++i;
982 }
983 }
984
985}
986
988{
989 if ( !sym )
990 return;
991
992 int i = 0;
993 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
994 {
995 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
996 switch ( mGraduatedMethod )
997 {
999 {
1000 symbol->setColor( range.symbol()->color() );
1001 break;
1002 }
1004 {
1005 if ( symbol->type() == Qgis::SymbolType::Marker )
1006 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
1007 static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
1008 else if ( symbol->type() == Qgis::SymbolType::Line )
1009 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
1010 static_cast<QgsLineSymbol *>( range.symbol() )->width() );
1011 break;
1012 }
1013 }
1014 updateRangeSymbol( i, symbol.release() );
1015 ++i;
1016 }
1017 setSourceSymbol( sym->clone() );
1018}
1019
1021{
1022 return true;
1023}
1024
1026{
1027 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
1028 {
1029 if ( range.uuid() == key )
1030 {
1031 return range.renderState();
1032 }
1033 }
1034 return true;
1035}
1036
1037void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1038{
1039 for ( int i = 0; i < mRanges.size(); i++ )
1040 {
1041 if ( mRanges[i].uuid() == key )
1042 {
1043 updateRangeRenderState( i, state );
1044 break;
1045 }
1046 }
1047}
1048
1050{
1051 bool ok = false;
1052 int i = 0;
1053 for ( i = 0; i < mRanges.size(); i++ )
1054 {
1055 if ( mRanges[i].uuid() == key )
1056 {
1057 ok = true;
1058 break;
1059 }
1060 }
1061
1062 if ( ok )
1063 updateRangeSymbol( i, symbol );
1064 else
1065 delete symbol;
1066}
1067
1069{
1070 QgsSymbol *newSymbol = symbol->clone();
1071 QString label = QStringLiteral( "0.0 - 0.0" );
1072 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1073}
1074
1075void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1076{
1077 QgsSymbol *newSymbol = mSourceSymbol->clone();
1078 QString label = mClassificationMethod->labelForRange( lower, upper );
1079 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1080}
1081
1083{
1084 QMutableListIterator< QgsRendererRange > it( mRanges );
1085 while ( it.hasNext() )
1086 {
1087 QgsRendererRange range = it.next();
1088 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1089 {
1091 newRange.setLowerValue( breakValue );
1092 newRange.setUpperValue( range.upperValue() );
1093 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1094 newRange.setSymbol( mSourceSymbol->clone() );
1095
1096 //update old range
1097 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1098 range.setUpperValue( breakValue );
1099 if ( isDefaultLabel )
1100 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1101 it.setValue( range );
1102
1103 it.insert( newRange );
1104 break;
1105 }
1106 }
1107
1108 if ( updateSymbols )
1109 {
1110 switch ( mGraduatedMethod )
1111 {
1114 break;
1117 break;
1118 }
1119 }
1120}
1121
1123{
1124 mRanges.append( range );
1125}
1126
1128{
1129 mRanges.removeAt( idx );
1130}
1131
1136
1139{
1140 mClassificationMethod->setLabelFormat( labelFormat.format() );
1141 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1142 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1143
1144 if ( updateRanges )
1145 {
1147 }
1148}
1150
1152{
1153 for ( int i = 0; i < mRanges.count(); i++ )
1154 {
1156 if ( i == 0 )
1158 else if ( i == mRanges.count() - 1 )
1160 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1161 }
1162}
1163
1165{
1166 // Find the minimum size of a class
1167 double minClassRange = 0.0;
1168 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1169 {
1170 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1171 if ( range <= 0.0 )
1172 continue;
1173 if ( minClassRange == 0.0 || range < minClassRange )
1174 minClassRange = range;
1175 }
1176 if ( minClassRange <= 0.0 )
1177 return;
1178
1179 // Now set the number of decimal places to ensure no more than 20% error in
1180 // representing this range (up to 10% at upper and lower end)
1181
1182 int ndp = 10;
1183 double nextDpMinRange = 0.0000000099;
1184 while ( ndp > 0 && nextDpMinRange < minClassRange )
1185 {
1186 ndp--;
1187 nextDpMinRange *= 10.0;
1188 }
1189 mClassificationMethod->setLabelPrecision( ndp );
1190 if ( updateRanges )
1192}
1193
1195{
1196 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1197 return;
1198 mRanges.move( from, to );
1199}
1200
1202{
1203 return r1 < r2;
1204}
1205
1207{
1208 return !valueLessThan( r1, r2 );
1209}
1210
1212{
1213 if ( order == Qt::AscendingOrder )
1214 {
1215 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1216 }
1217 else
1218 {
1219 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1220 }
1221}
1222
1224{
1225 QgsRangeList sortedRanges = mRanges;
1226 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1227
1228 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1229 if ( it == sortedRanges.constEnd() )
1230 return false;
1231
1232 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1233 return true;
1234
1235 double prevMax = ( *it ).upperValue();
1236 ++it;
1237
1238 for ( ; it != sortedRanges.constEnd(); ++it )
1239 {
1240 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1241 return true;
1242
1243 if ( ( *it ).lowerValue() < prevMax )
1244 return true;
1245
1246 prevMax = ( *it ).upperValue();
1247 }
1248 return false;
1249}
1250
1252{
1253 QgsRangeList sortedRanges = mRanges;
1254 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1255
1256 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1257 if ( it == sortedRanges.constEnd() )
1258 return false;
1259
1260 double prevMax = ( *it ).upperValue();
1261 ++it;
1262
1263 for ( ; it != sortedRanges.constEnd(); ++it )
1264 {
1265 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1266 return true;
1267
1268 prevMax = ( *it ).upperValue();
1269 }
1270 return false;
1271}
1272
1274{
1275 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1276}
1277
1279{
1280 return !labelLessThan( r1, r2 );
1281}
1282
1284{
1285 if ( order == Qt::AscendingOrder )
1286 {
1287 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1288 }
1289 else
1290 {
1291 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1292 }
1293}
1294
1299
1304
1306{
1307 QString methodId = methodIdFromMode( mode );
1308 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
1309 setClassificationMethod( method.release() );
1310}
1311
1316
1318{
1319 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1320}
1321
1323{
1324 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1325}
1326
1328{
1329 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1330 if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1331 {
1332 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1333 }
1334 else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1335 {
1336 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1337 if ( categorizedSymbolRenderer )
1338 {
1339 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1340 if ( categorizedSymbolRenderer->sourceSymbol() )
1341 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1342 if ( categorizedSymbolRenderer->sourceColorRamp() )
1343 {
1344 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1345 dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1346 if ( !isRandom )
1347 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1348 }
1349 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1350 }
1351 }
1352 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1353 {
1354 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1355 if ( pointDistanceRenderer )
1356 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1357 }
1358 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1359 {
1360 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1361 if ( invertedPolygonRenderer )
1362 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1363 }
1364
1365 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1366 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1367
1368 if ( !r )
1369 {
1370 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1371 QgsRenderContext context;
1372 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1373 if ( !symbols.isEmpty() )
1374 {
1375 r->setSourceSymbol( symbols.at( 0 )->clone() );
1376 }
1377 }
1378
1379 renderer->copyRendererData( r.get() );
1380
1381 return r.release();
1382}
1383
1388
1393
1395{
1396 switch ( method )
1397 {
1399 return QStringLiteral( "GraduatedColor" );
1401 return QStringLiteral( "GraduatedSize" );
1402 }
1403 return QString();
1404}
1405
1406
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:838
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition qgis.h:3306
@ Size
Alter size of symbols.
Definition qgis.h:3308
@ Color
Alter color of symbols.
Definition qgis.h:3307
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:829
@ Marker
Marker symbol.
Definition qgis.h:611
@ Line
Line symbol.
Definition qgis.h:612
@ Fill
Fill symbol.
Definition qgis.h:613
@ Hybrid
Hybrid symbol.
Definition qgis.h:614
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Definition qgis.h:849
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
A feature renderer which represents features using a list of renderer categories.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol b...
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each categories' color is derived.
A classification method which uses equal width intervals.
std::unique_ptr< QgsClassificationMethod > method(const QString &id)
Returns a new instance of the method for the given id.
An abstract class for implementations of classification methods.
static void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
static std::unique_ptr< QgsClassificationMethod > create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
Q_DECL_DEPRECATED QList< QgsClassificationRange > classes(const QgsVectorLayer *layer, const QString &expression, int nclasses)
This will calculate the classes for a given layer to define the classes.
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
ClassPosition
Defines the class position.
@ LowerBound
The class is at the lower bound.
@ UpperBound
The class is at the upper bound.
@ Inner
The class is not at a bound.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
Abstract base class for color ramps.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
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.
QString type() const
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
Converts old rotation expressions to symbol level data defined angles.
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
static void convertSymbolSizeScale(QgsSymbol *symbol, Qgis::ScaleMethod method, const QString &field)
Converts old sizeScale expressions to symbol level data defined sizes.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsAttributes attributes
Definition qgsfeature.h:67
Container of fields for a vector layer.
Definition qgsfields.h:46
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
const QgsRendererRange * rangeForValue(double value) const
Returns the renderer range matching the provided value, or nullptr if no range matches the value.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
QgsGraduatedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
static Q_DECL_DEPRECATED void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
bool updateRangeLabel(int rangeIndex, const QString &label)
void addClass(QgsSymbol *symbol)
Adds a class to the renderer, with the specified symbol.
QgsClassificationMethod * classificationMethod() const
Returns the classification method.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
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.
void checkLegendSymbolItem(const QString &key, bool state=true) override
Sets whether the legend symbology item with the specified ley should be checked.
std::unique_ptr< QgsSymbol > mSourceSymbol
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
Qgis::FeatureRendererFlags flags() const override
Returns flags associated with the renderer.
void setGraduatedMethod(Qgis::GraduatedMethod method)
Set the method used for graduation (either size or color).
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
Q_DECL_DEPRECATED void setMode(Mode mode)
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
Q_DECL_DEPRECATED void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode=false, double symmetryPoint=0.0, bool astride=false)
Recalculate classes for a layer.
QString dump() const override
Returns debug information about this renderer.
bool updateRangeUpperValue(int rangeIndex, double value)
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...
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
bool legendSymbolItemChecked(const QString &key) override
Returns true if the legend symbology item with the specified key is checked.
bool updateRangeLowerValue(int rangeIndex, double value)
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
Returns true if symbology items in legend are checkable.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void updateRangeLabels()
Updates the labels of the ranges.
bool updateRangeRenderState(int rangeIndex, bool render)
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
double minSymbolSize() const
Returns the min symbol size when graduated by size.
Qgis::GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color).
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
int mAttrNum
attribute index (derived from attribute name in startRender)
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
std::unique_ptr< QgsExpression > mExpression
static QString graduatedMethodStr(Qgis::GraduatedMethod method)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
const QgsRangeList & ranges() const
Returns a list of all ranges used in the classification.
Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const
Returns the label format used to generate default classification labels.
static Q_DECL_DEPRECATED QgsGraduatedSymbolRenderer * createRenderer(QgsVectorLayer *vlayer, const QString &attrName, int classes, Mode mode, QgsSymbol *symbol, QgsColorRamp *ramp, const QgsRendererRangeLabelFormat &legendFormat=QgsRendererRangeLabelFormat(), bool useSymmetricMode=false, double symmetryPoint=0.0, const QStringList &listForCboPrettyBreaks=QStringList(), bool astride=false)
Creates a new graduated renderer.
Q_DECL_DEPRECATED double symmetryPoint() const
Returns the pivot value for symmetric classification.
Q_DECL_DEPRECATED void setUseSymmetricMode(bool useSymmetricMode)
Set if we want to classify symmetric around a given value.
QgsSymbol * symbolForValue(double value) const
Gets the symbol which is used to represent value.
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
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 ...
Constrained random color ramp, which returns random colors based on preset parameters.
A line symbol type, for rendering LineString and MultiLineString geometries.
void setWidth(double width) const
Sets the width for the whole line symbol.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
A marker symbol type, for rendering Point and MultiPoint geometries.
void setSize(double size) const
Sets the size for the whole symbol.
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
A store for object properties.
bool isActive() const
Returns whether the property is currently active.
A color ramp consisting of random colors, constrained within component ranges.
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.
Encapsulates the formatting for a QgsRendererRange label.
Represents a value range for a QgsGraduatedSymbolRenderer.
void setUpperValue(double upperValue)
Sets the upper bound of the range.
QString label() const
Returns the label used for the range.
void setSymbol(QgsSymbol *s)
Sets the symbol used for the range.
QgsSymbol * symbol() const
Returns the symbol used for the range.
void setLabel(const QString &label)
Sets the label used for the range.
bool renderState() const
Returns true if the range should be rendered.
double upperValue() const
Returns the upper bound of the range.
void setLowerValue(double lowerValue)
Sets the lower bound of the range.
QString uuid() const
Returns the unique identifier for this range.
double lowerValue() const
Returns the lower bound of the range.
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.
A color ramp entity for QgsStyle databases.
Definition qgsstyle.h:1429
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1397
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
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.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
void setColor(const QColor &color) const
Sets the color for the symbol.
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry 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.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
#define SIP_DEPRECATED
Definition qgis_sip.h:114
bool labelGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool labelLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool labelGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool labelLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool valueGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:55
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:50
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:49
QList< QgsRendererRange > QgsRangeList
Contains information relating to the style entity currently being visited.