QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
16 #include <QDomDocument>
17 #include <QDomElement>
18 
19 #include <ctime>
20 #include <cmath>
21 
23 
24 #include "qgsattributes.h"
26 #include "qgscolorramp.h"
27 #include "qgscolorrampimpl.h"
29 #include "qgsexpression.h"
30 #include "qgsfeature.h"
32 #include "qgslogger.h"
33 #include "qgspainteffect.h"
34 #include "qgspainteffectregistry.h"
36 #include "qgsproperty.h"
37 #include "qgssymbol.h"
38 #include "qgssymbollayer.h"
39 #include "qgssymbollayerutils.h"
40 #include "qgsvectordataprovider.h"
41 #include "qgsvectorlayer.h"
42 #include "qgsvectorlayerutils.h"
44 #include "qgsstyleentityvisitor.h"
47 #include "qgsapplication.h"
50 #include "qgsmarkersymbol.h"
51 #include "qgslinesymbol.h"
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 
69 }
70 
72 {
73  mRanges.clear(); // should delete all the symbols
74 }
75 
76 
78 {
79  for ( const QgsRendererRange &range : mRanges )
80  {
81  if ( range.lowerValue() <= value && range.upperValue() >= value )
82  {
83  if ( range.renderState() || mCounting )
84  return &range;
85  else
86  return nullptr;
87  }
88  }
89 
90  // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
91  // if a value falls just outside of a range, but within acceptable double precision tolerance
92  // then we accept it anyway
93  for ( const QgsRendererRange &range : mRanges )
94  {
95  if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
96  {
97  if ( range.renderState() || mCounting )
98  return &range;
99  else
100  return nullptr;
101  }
102  }
103  // the value is out of the range: return NULL instead of symbol
104  return nullptr;
105 }
106 
108 {
109  if ( const QgsRendererRange *range = rangeForValue( value ) )
110  return range->symbol();
111  return nullptr;
112 }
113 
115 {
116  if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
117  {
118  int i = 0;
119  for ( const QgsRendererRange &range : mRanges )
120  {
121  if ( matchingRange == &range )
122  return QString::number( i );
123  i++;
124  }
125  }
126  return QString();
127 }
128 
130 {
131  return originalSymbolForFeature( feature, context );
132 }
133 
134 QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
135 {
136  QgsAttributes attrs = feature.attributes();
137  QVariant value;
138  if ( mExpression )
139  {
140  value = mExpression->evaluate( &context.expressionContext() );
141  }
142  else
143  {
144  value = attrs.value( mAttrNum );
145  }
146 
147  return value;
148 }
149 
151 {
152  QVariant value = valueForFeature( feature, context );
153 
154  // Null values should not be categorized
155  if ( value.isNull() )
156  return nullptr;
157 
158  // find the right category
159  return symbolForValue( value.toDouble() );
160 }
161 
163 {
164  QgsFeatureRenderer::startRender( context, fields );
165 
166  mCounting = context.rendererScale() == 0.0;
167 
168  // find out classification attribute index from name
169  mAttrNum = fields.lookupField( mAttrName );
170 
171  if ( mAttrNum == -1 )
172  {
173  mExpression.reset( new QgsExpression( mAttrName ) );
174  mExpression->prepare( &context.expressionContext() );
175  }
176 
177  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
178  {
179  if ( !range.symbol() )
180  continue;
181 
182  range.symbol()->startRender( context, fields );
183  }
184 }
185 
187 {
189 
190  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
191  {
192  if ( !range.symbol() )
193  continue;
194 
195  range.symbol()->stopRender( context );
196  }
197 }
198 
200 {
201  QSet<QString> attributes;
202 
203  // mAttrName can contain either attribute name or an expression.
204  // Sometimes it is not possible to distinguish between those two,
205  // e.g. "a - b" can be both a valid attribute name or expression.
206  // Since we do not have access to fields here, try both options.
207  attributes << mAttrName;
208 
209  QgsExpression testExpr( mAttrName );
210  if ( !testExpr.hasParserError() )
211  attributes.unite( testExpr.referencedColumns() );
212 
213  QgsRangeList::const_iterator range_it = mRanges.constBegin();
214  for ( ; range_it != mRanges.constEnd(); ++range_it )
215  {
216  QgsSymbol *symbol = range_it->symbol();
217  if ( symbol )
218  {
219  attributes.unite( symbol->usedAttributes( context ) );
220  }
221  }
222  return attributes;
223 }
224 
226 {
227  QgsExpression testExpr( mAttrName );
228  if ( !testExpr.hasParserError() )
229  {
230  QgsExpressionContext context;
231  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
232  testExpr.prepare( &context );
233  return testExpr.needsGeometry();
234  }
235  return false;
236 }
237 
239 {
240  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
241  return false;
242  mRanges[rangeIndex].setSymbol( symbol );
243  return true;
244 }
245 
246 bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
247 {
248  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
249  return false;
250  mRanges[rangeIndex].setLabel( label );
251  return true;
252 }
253 
254 bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
255 {
256  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
257  return false;
258  QgsRendererRange &range = mRanges[rangeIndex];
260  if ( rangeIndex == 0 )
262  else if ( rangeIndex == mRanges.count() )
264 
265  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
266  range.setUpperValue( value );
267  if ( isDefaultLabel )
268  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
269 
270  return true;
271 }
272 
273 bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
274 {
275  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
276  return false;
277 
278  QgsRendererRange &range = mRanges[rangeIndex];
280  if ( rangeIndex == 0 )
282  else if ( rangeIndex == mRanges.count() )
284 
285  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
286  range.setLowerValue( value );
287  if ( isDefaultLabel )
288  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
289 
290  return true;
291 }
292 
293 bool QgsGraduatedSymbolRenderer::updateRangeRenderState( int rangeIndex, bool value )
294 {
295  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
296  return false;
297  mRanges[rangeIndex].setRenderState( value );
298  return true;
299 }
300 
302 {
303  QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
304  for ( int i = 0; i < mRanges.count(); i++ )
305  s += mRanges[i].dump();
306  return s;
307 }
308 
310 {
312 
314 
315  if ( mSourceSymbol )
316  r->setSourceSymbol( mSourceSymbol->clone() );
317  if ( mSourceColorRamp )
318  {
319  r->setSourceColorRamp( mSourceColorRamp->clone() );
320  }
323  copyRendererData( r );
324  return r;
325 }
326 
327 void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
328 {
329  QVariantMap newProps = props;
330  newProps[ QStringLiteral( "attribute" )] = mAttrName;
331  newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
332 
333  // create a Rule for each range
334  bool first = true;
335  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
336  {
337  it->toSld( doc, element, newProps, first );
338  first = false;
339  }
340 }
341 
343 {
344  Q_UNUSED( context )
345  QgsSymbolList lst;
346  lst.reserve( mRanges.count() );
347  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
348  {
349  lst.append( range.symbol() );
350  }
351  return lst;
352 }
353 
355 {
356  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
357  {
358  QgsStyleSymbolEntity entity( range.symbol() );
359  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
360  return false;
361  }
362 
363  if ( mSourceColorRamp )
364  {
366  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
367  return false;
368  }
369 
370  return true;
371 }
372 
373 void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
374 {
376 }
377 
378 QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
379 {
382  QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
383  return QgsClassificationMethod::rangesToBreaks( _classes );
384 }
385 
388  QgsVectorLayer *vlayer,
389  const QString &attrName,
390  int classes,
391  Mode mode,
392  QgsSymbol *symbol,
393  QgsColorRamp *ramp,
394  const QgsRendererRangeLabelFormat &labelFormat,
395  bool useSymmetricMode,
396  double symmetryPoint,
397  const QStringList &listForCboPrettyBreaks,
398  bool astride
399 )
400 {
401  Q_UNUSED( listForCboPrettyBreaks )
402 
405  r->setSourceSymbol( symbol->clone() );
406  r->setSourceColorRamp( ramp->clone() );
407 
408  QString methodId = methodIdFromMode( mode );
410 
411  if ( method )
412  {
414  method->setLabelFormat( labelFormat.format() );
417  }
418  r->setClassificationMethod( method );
419 
420  r->updateClasses( vlayer, classes );
421  return r;
422 }
424 
426  bool useSymmetricMode, double symmetryPoint, bool astride )
427 {
428  if ( mAttrName.isEmpty() )
429  return;
430 
431  QString methodId = methodIdFromMode( mode );
434  setClassificationMethod( method );
435 
436  updateClasses( vlayer, nclasses );
437 }
438 
440 {
442  return;
443 
444  QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
445 
447 
448  for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
449  {
451  addClass( QgsRendererRange( *it, newSymbol ) );
452  }
453  updateColorRamp( nullptr );
454 }
455 
458 {
459  return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
460 }
462 
464 {
465  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
466  if ( symbolsElem.isNull() )
467  return nullptr;
468 
469  QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
470  if ( rangesElem.isNull() )
471  return nullptr;
472 
473  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
475 
476  QDomElement rangeElem = rangesElem.firstChildElement();
477  while ( !rangeElem.isNull() )
478  {
479  if ( rangeElem.tagName() == QLatin1String( "range" ) )
480  {
481  double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
482  double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
483  QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
484  QString label = rangeElem.attribute( QStringLiteral( "label" ) );
485  bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
486  if ( symbolMap.contains( symbolName ) )
487  {
488  QgsSymbol *symbol = symbolMap.take( symbolName );
489  ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render ) );
490  }
491  }
492  rangeElem = rangeElem.nextSiblingElement();
493  }
494 
495  QString attrName = element.attribute( QStringLiteral( "attr" ) );
496 
498 
499  QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
500  if ( !attrMethod.isEmpty() )
501  {
502  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
504  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
506  }
507 
508 
509  // delete symbols if there are any more
511 
512  // try to load source symbol (optional)
513  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
514  if ( !sourceSymbolElem.isNull() )
515  {
516  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
517  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
518  {
519  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
520  }
521  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
522  }
523 
524  // try to load color ramp (optional)
525  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
526  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
527  {
528  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
529  }
530 
531  // try to load mode
532 
533  QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
534  QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
535  QgsClassificationMethod *method = nullptr;
536 
537  // TODO QGIS 4 Remove
538  // backward compatibility for QGIS project < 3.10
539  if ( !modeElem.isNull() )
540  {
541  QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
542  QString methodId;
543  // the strings saved in the project does not match with the old Mode enum
544  if ( modeString == QLatin1String( "equal" ) )
545  methodId = QStringLiteral( "EqualInterval" );
546  else if ( modeString == QLatin1String( "quantile" ) )
547  methodId = QStringLiteral( "Quantile" );
548  else if ( modeString == QLatin1String( "jenks" ) )
549  methodId = QStringLiteral( "Jenks" );
550  else if ( modeString == QLatin1String( "stddev" ) )
551  methodId = QStringLiteral( "StdDev" );
552  else if ( modeString == QLatin1String( "pretty" ) )
553  methodId = QStringLiteral( "Pretty" );
554 
556 
557  // symmetric mode
558  QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
559  if ( !symmetricModeElem.isNull() )
560  {
561  // symmetry
562  QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
563  QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
564  QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
565  method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
566  }
567  QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
568  if ( !labelFormatElem.isNull() )
569  {
570  // label format
571  QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
572  int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
573  bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
574  method->setLabelFormat( format );
575  method->setLabelPrecision( precision );
576  method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
577  }
578  // End of backward compatibility
579  }
580  else
581  {
582  // QGIS project 3.10+
583  method = QgsClassificationMethod::create( methodElem, context );
584  }
585 
586  // apply the method
587  r->setClassificationMethod( method );
588 
589  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
590  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
591  {
592  for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
593  {
594  convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
595  }
596  if ( r->mSourceSymbol )
597  {
598  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
599  }
600  }
601  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
602  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
603  {
604  for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
605  {
606  convertSymbolSizeScale( range.symbol(),
607  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
608  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
609  }
610  if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
611  {
613  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
614  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
615  }
616  }
617 
618  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
619  if ( !ddsLegendSizeElem.isNull() )
620  {
621  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
622  }
623 // TODO: symbol levels
624  return r;
625 }
626 
627 QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
628 {
629  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
630  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
631  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
632  rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
633 
634  // ranges
635  int i = 0;
637  QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
638  QgsRangeList::const_iterator it = mRanges.constBegin();
639  for ( ; it != mRanges.constEnd(); ++it )
640  {
641  const QgsRendererRange &range = *it;
642  QString symbolName = QString::number( i );
643  symbols.insert( symbolName, range.symbol() );
644 
645  QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
646  rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
647  rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
648  rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
649  rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
650  rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
651  rangesElem.appendChild( rangeElem );
652  i++;
653  }
654 
655  rendererElem.appendChild( rangesElem );
656 
657  // save symbols
658  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
659  rendererElem.appendChild( symbolsElem );
660 
661  // save source symbol
662  if ( mSourceSymbol )
663  {
664  QgsSymbolMap sourceSymbols;
665  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
666  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
667  rendererElem.appendChild( sourceSymbolElem );
668  }
669 
670  // save source color ramp
671  if ( mSourceColorRamp )
672  {
673  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
674  rendererElem.appendChild( colorRampElem );
675  }
676 
677  // save classification method
678  QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
679  rendererElem.appendChild( classificationMethodElem );
680 
681  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
682  rendererElem.appendChild( rotationElem );
683 
684  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
685  rendererElem.appendChild( sizeScaleElem );
686 
688  {
689  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
690  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
691  rendererElem.appendChild( ddsLegendElem );
692  }
693 
694  saveRendererData( doc, rendererElem, context );
695 
696  return rendererElem;
697 }
698 
699 QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
700 {
702  int i = 0;
703  lst.reserve( mRanges.size() );
704  for ( const QgsRendererRange &range : mRanges )
705  {
706  lst << QgsLegendSymbolItem( range.symbol(), range.label(), QString::number( i++ ), true );
707  }
708  return lst;
709 }
710 
712 QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
713 {
714  switch ( mode )
715  {
716  case EqualInterval:
717  return QStringLiteral( "EqualInterval" );
718  case Quantile:
719  return QStringLiteral( "Quantile" );
720  case Jenks:
721  return QStringLiteral( "Jenks" );
722  case StdDev:
723  return QStringLiteral( "StdDev" );
724  case Pretty:
725  return QStringLiteral( "Pretty" );
726  case Custom:
727  return QString();
728  }
729  return QString();
730 }
731 
732 QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
733 {
734  if ( methodId == QLatin1String( "EqualInterval" ) )
735  return EqualInterval;
736  if ( methodId == QLatin1String( "Quantile" ) )
737  return Quantile;
738  if ( methodId == QLatin1String( "Jenks" ) )
739  return Jenks;
740  if ( methodId == QLatin1String( "StdDev" ) )
741  return StdDev;
742  if ( methodId == QLatin1String( "Pretty" ) )
743  return Pretty;
744  else
745  return Custom;
746 }
748 
750 {
752  {
753  // check that all symbols that have the same size expression
754  QgsProperty ddSize;
755  for ( const QgsRendererRange &range : mRanges )
756  {
757  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
758  if ( ddSize )
759  {
760  QgsProperty sSize( symbol->dataDefinedSize() );
761  if ( sSize && sSize != ddSize )
762  {
763  // no common size expression
764  return baseLegendSymbolItems();
765  }
766  }
767  else
768  {
769  ddSize = symbol->dataDefinedSize();
770  }
771  }
772 
773  if ( ddSize && ddSize.isActive() )
774  {
776 
778  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
779  lst += ddSizeLegend.legendSymbolList();
780 
781  lst += baseLegendSymbolItems();
782  return lst;
783  }
784  }
785 
786  return baseLegendSymbolItems();
787 }
788 
789 QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
790 {
791  QVariant value = valueForFeature( feature, context );
792 
793  // Null values should not be categorized
794  if ( value.isNull() )
795  return QSet< QString >();
796 
797  // find the right category
798  QString key = legendKeyForValue( value.toDouble() );
799  if ( !key.isNull() )
800  return QSet< QString >() << key;
801  else
802  return QSet< QString >();
803 }
804 
806 {
807  return mSourceSymbol.get();
808 }
809 
811 {
812  return mSourceSymbol.get();
813 }
814 
816 {
817  mSourceSymbol.reset( sym );
818 }
819 
821 {
822  return mSourceColorRamp.get();
823 }
824 
826 {
827  return mSourceColorRamp.get();
828 }
829 
831 {
832  if ( ramp == mSourceColorRamp.get() )
833  return;
834 
835  mSourceColorRamp.reset( ramp );
836 }
837 
839 {
840  double min = std::numeric_limits<double>::max();
841  for ( int i = 0; i < mRanges.count(); i++ )
842  {
843  double sz = 0;
844  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
845  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
846  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
847  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
848  min = std::min( sz, min );
849  }
850  return min;
851 }
852 
854 {
855  double max = std::numeric_limits<double>::min();
856  for ( int i = 0; i < mRanges.count(); i++ )
857  {
858  double sz = 0;
859  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
860  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
861  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
862  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
863  max = std::max( sz, max );
864  }
865  return max;
866 }
867 
868 void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
869 {
870  for ( int i = 0; i < mRanges.count(); i++ )
871  {
872  std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
873  const double size = mRanges.count() > 1
874  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
875  : .5 * ( maxSize + minSize );
876  if ( symbol->type() == Qgis::SymbolType::Marker )
877  static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
878  if ( symbol->type() == Qgis::SymbolType::Line )
879  static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
880  updateRangeSymbol( i, symbol.release() );
881  }
882 }
883 
885 {
886  int i = 0;
887  if ( ramp )
888  {
889  setSourceColorRamp( ramp );
890  }
891 
892  if ( mSourceColorRamp )
893  {
894  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
895  {
896  QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
897  if ( symbol )
898  {
899  double colorValue;
900  colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
901  symbol->setColor( mSourceColorRamp->color( colorValue ) );
902  }
903  updateRangeSymbol( i, symbol );
904  ++i;
905  }
906  }
907 
908 }
909 
911 {
912  if ( !sym )
913  return;
914 
915  int i = 0;
916  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
917  {
918  std::unique_ptr<QgsSymbol> symbol( sym->clone() );
920  {
921  symbol->setColor( range.symbol()->color() );
922  }
923  else if ( mGraduatedMethod == GraduatedSize )
924  {
925  if ( symbol->type() == Qgis::SymbolType::Marker )
926  static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
927  static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
928  else if ( symbol->type() == Qgis::SymbolType::Line )
929  static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
930  static_cast<QgsLineSymbol *>( range.symbol() )->width() );
931  }
932  updateRangeSymbol( i, symbol.release() );
933  ++i;
934  }
935  setSourceSymbol( sym->clone() );
936 }
937 
939 {
940  return true;
941 }
942 
944 {
945  bool ok;
946  int index = key.toInt( &ok );
947  if ( ok && index >= 0 && index < mRanges.size() )
948  return mRanges.at( index ).renderState();
949  else
950  return true;
951 }
952 
953 void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
954 {
955  bool ok;
956  int index = key.toInt( &ok );
957  if ( ok )
958  updateRangeRenderState( index, state );
959 }
960 
962 {
963  bool ok;
964  int index = key.toInt( &ok );
965  if ( ok )
966  updateRangeSymbol( index, symbol );
967  else
968  delete symbol;
969 }
970 
972 {
973  QgsSymbol *newSymbol = symbol->clone();
974  QString label = QStringLiteral( "0.0 - 0.0" );
975  mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
976 }
977 
978 void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
979 {
980  QgsSymbol *newSymbol = mSourceSymbol->clone();
981  QString label = mClassificationMethod->labelForRange( lower, upper );
982  mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
983 }
984 
985 void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
986 {
987  QMutableListIterator< QgsRendererRange > it( mRanges );
988  while ( it.hasNext() )
989  {
990  QgsRendererRange range = it.next();
991  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
992  {
993  QgsRendererRange newRange = QgsRendererRange();
994  newRange.setLowerValue( breakValue );
995  newRange.setUpperValue( range.upperValue() );
996  newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
997  newRange.setSymbol( mSourceSymbol->clone() );
998 
999  //update old range
1000  bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1001  range.setUpperValue( breakValue );
1002  if ( isDefaultLabel )
1003  range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1004  it.setValue( range );
1005 
1006  it.insert( newRange );
1007  break;
1008  }
1009  }
1010 
1011  if ( updateSymbols )
1012  {
1013  switch ( mGraduatedMethod )
1014  {
1015  case GraduatedColor:
1017  break;
1018  case GraduatedSize:
1020  break;
1021  }
1022  }
1023 }
1024 
1026 {
1027  mRanges.append( range );
1028 }
1029 
1031 {
1032  mRanges.removeAt( idx );
1033 }
1034 
1036 {
1037  mRanges.clear();
1038 }
1039 
1042 {
1043  mClassificationMethod->setLabelFormat( labelFormat.format() );
1044  mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1045  mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1046 
1047  if ( updateRanges )
1048  {
1050  }
1051 }
1053 
1055 {
1056  for ( int i = 0; i < mRanges.count(); i++ )
1057  {
1059  if ( i == 0 )
1061  else if ( i == mRanges.count() - 1 )
1063  mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1064  }
1065 }
1066 
1068 {
1069  // Find the minimum size of a class
1070  double minClassRange = 0.0;
1071  for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1072  {
1073  double range = rendererRange.upperValue() - rendererRange.lowerValue();
1074  if ( range <= 0.0 )
1075  continue;
1076  if ( minClassRange == 0.0 || range < minClassRange )
1077  minClassRange = range;
1078  }
1079  if ( minClassRange <= 0.0 )
1080  return;
1081 
1082  // Now set the number of decimal places to ensure no more than 20% error in
1083  // representing this range (up to 10% at upper and lower end)
1084 
1085  int ndp = 10;
1086  double nextDpMinRange = 0.0000000099;
1087  while ( ndp > 0 && nextDpMinRange < minClassRange )
1088  {
1089  ndp--;
1090  nextDpMinRange *= 10.0;
1091  }
1092  mClassificationMethod->setLabelPrecision( ndp );
1093  if ( updateRanges )
1095 }
1096 
1098 {
1099  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1100  return;
1101  mRanges.move( from, to );
1102 }
1103 
1105 {
1106  return r1 < r2;
1107 }
1108 
1110 {
1111  return !valueLessThan( r1, r2 );
1112 }
1113 
1114 void QgsGraduatedSymbolRenderer::sortByValue( Qt::SortOrder order )
1115 {
1116  if ( order == Qt::AscendingOrder )
1117  {
1118  std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1119  }
1120  else
1121  {
1122  std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1123  }
1124 }
1125 
1127 {
1128  QgsRangeList sortedRanges = mRanges;
1129  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1130 
1131  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1132  if ( it == sortedRanges.constEnd() )
1133  return false;
1134 
1135  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1136  return true;
1137 
1138  double prevMax = ( *it ).upperValue();
1139  ++it;
1140 
1141  for ( ; it != sortedRanges.constEnd(); ++it )
1142  {
1143  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1144  return true;
1145 
1146  if ( ( *it ).lowerValue() < prevMax )
1147  return true;
1148 
1149  prevMax = ( *it ).upperValue();
1150  }
1151  return false;
1152 }
1153 
1155 {
1156  QgsRangeList sortedRanges = mRanges;
1157  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1158 
1159  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1160  if ( it == sortedRanges.constEnd() )
1161  return false;
1162 
1163  double prevMax = ( *it ).upperValue();
1164  ++it;
1165 
1166  for ( ; it != sortedRanges.constEnd(); ++it )
1167  {
1168  if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1169  return true;
1170 
1171  prevMax = ( *it ).upperValue();
1172  }
1173  return false;
1174 }
1175 
1177 {
1178  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1179 }
1180 
1182 {
1183  return !labelLessThan( r1, r2 );
1184 }
1185 
1186 void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
1187 {
1188  if ( order == Qt::AscendingOrder )
1189  {
1190  std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1191  }
1192  else
1193  {
1194  std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1195  }
1196 }
1197 
1199 {
1200  return mClassificationMethod.get();
1201 }
1202 
1204 {
1205  mClassificationMethod.reset( method );
1206 }
1207 
1209 {
1210  QString methodId = methodIdFromMode( mode );
1212  setClassificationMethod( method );
1213 }
1214 
1216 {
1217  mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1218 }
1219 
1221 {
1222  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1223 }
1224 
1226 {
1227  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1228 }
1229 
1231 {
1232  std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1233  if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1234  {
1235  r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1236  }
1237  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1238  {
1239  const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1240  if ( categorizedSymbolRenderer )
1241  {
1242  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1243  if ( categorizedSymbolRenderer->sourceSymbol() )
1244  r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1245  if ( categorizedSymbolRenderer->sourceColorRamp() )
1246  {
1247  bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1248  dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1249  if ( !isRandom )
1250  r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1251  }
1252  r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1253  }
1254  }
1255  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1256  {
1257  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1258  if ( pointDistanceRenderer )
1259  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1260  }
1261  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1262  {
1263  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1264  if ( invertedPolygonRenderer )
1265  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1266  }
1267 
1268  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1269  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1270 
1271  if ( !r )
1272  {
1273  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1274  QgsRenderContext context;
1275  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1276  if ( !symbols.isEmpty() )
1277  {
1278  r->setSourceSymbol( symbols.at( 0 )->clone() );
1279  }
1280  }
1281 
1282  renderer->copyRendererData( r.get() );
1283 
1284  return r.release();
1285 }
1286 
1288 {
1289  mDataDefinedSizeLegend.reset( settings );
1290 }
1291 
1293 {
1294  return mDataDefinedSizeLegend.get();
1295 }
1296 
1298 {
1299  switch ( method )
1300  {
1301  case GraduatedColor:
1302  return QStringLiteral( "GraduatedColor" );
1303  case GraduatedSize:
1304  return QStringLiteral( "GraduatedSize" );
1305  }
1306  return QString();
1307 }
1308 
1309 
@ Marker
Marker symbol.
@ Line
Line symbol.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
Definition: qgsattributes.h:58
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.
QgsClassificationCustom is a dummy implementation of QgsClassification which does not compute any bre...
static const QString METHOD_ID
QgsClassificationEqualInterval is an implementation of QgsClassificationMethod for equal intervals.
QgsClassificationMethod * method(const QString &id)
Returns a new instance of the method for the given id.
QgsClassificationMethod is 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...
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 setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
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.
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
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.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
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.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
Definition: qgsrenderer.h:142
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:52
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
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.
Definition: qgsrenderer.cpp:96
static void convertSymbolSizeScale(QgsSymbol *symbol, Qgis::ScaleMethod method, const QString &field)
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
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.
GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color)
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)
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)
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 QString graduatedMethodStr(GraduatedMethod method)
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was 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.
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 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
items of symbology items in legend 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
items of symbology items in legend should be 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.
const QgsRangeList & ranges() const
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())
void setGraduatedMethod(GraduatedMethod method)
set the method used for graduation (either size or color)
double minSymbolSize() const
Returns the min symbol size when graduated by size.
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
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...
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.
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...
Constrained random color ramp, which returns random colors based on preset parameters.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
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.
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.
Definition: qgsproperty.h:231
bool isActive() const
Returns whether the property is currently active.
Totally random color ramp.
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.
void setUpperValue(double upperValue)
QString label() const
void setSymbol(QgsSymbol *s)
QgsSymbol * symbol() const
void setLabel(const QString &label)
bool renderState() const
double upperValue() const
void setLowerValue(double lowerValue)
double lowerValue() const
A color ramp entity for QgsStyle databases.
Definition: qgsstyle.h:1254
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:1222
static 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, 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:38
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:355
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:825
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:541
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2065
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
#define SIP_DEPRECATED
Definition: qgis_sip.h:106
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:50
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:45
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:44
QList< QgsRendererRange > QgsRangeList
int precision
Contains information relating to the style entity currently being visited.