QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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"
28 #include "qgsexpression.h"
29 #include "qgsfeature.h"
31 #include "qgslogger.h"
32 #include "qgspainteffect.h"
33 #include "qgspainteffectregistry.h"
35 #include "qgsproperty.h"
36 #include "qgssymbol.h"
37 #include "qgssymbollayer.h"
38 #include "qgssymbollayerutils.h"
39 #include "qgsvectordataprovider.h"
40 #include "qgsvectorlayer.h"
41 #include "qgsvectorlayerutils.h"
43 #include "qgsstyleentityvisitor.h"
46 #include "qgsapplication.h"
49 #include "qgsmarkersymbol.h"
50 #include "qgslinesymbol.h"
51 
53  : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
54  , mAttrName( attrName )
55 {
56  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
57 
58  //important - we need a deep copy of the ranges list, not a shared copy. This is required because
59  //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
60  //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
61  const auto constRanges = ranges;
62  for ( const QgsRendererRange &range : constRanges )
63  {
64  mRanges << range;
65  }
66 
68 }
69 
71 {
72  mRanges.clear(); // should delete all the symbols
73 }
74 
75 
77 {
78  for ( const QgsRendererRange &range : mRanges )
79  {
80  if ( range.lowerValue() <= value && range.upperValue() >= value )
81  {
82  if ( range.renderState() || mCounting )
83  return &range;
84  else
85  return nullptr;
86  }
87  }
88 
89  // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
90  // if a value falls just outside of a range, but within acceptable double precision tolerance
91  // then we accept it anyway
92  for ( const QgsRendererRange &range : mRanges )
93  {
94  if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
95  {
96  if ( range.renderState() || mCounting )
97  return &range;
98  else
99  return nullptr;
100  }
101  }
102  // the value is out of the range: return NULL instead of symbol
103  return nullptr;
104 }
105 
107 {
108  if ( const QgsRendererRange *range = rangeForValue( value ) )
109  return range->symbol();
110  return nullptr;
111 }
112 
114 {
115  if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
116  {
117  int i = 0;
118  for ( const QgsRendererRange &range : mRanges )
119  {
120  if ( matchingRange == &range )
121  return QString::number( i );
122  i++;
123  }
124  }
125  return QString();
126 }
127 
129 {
130  return originalSymbolForFeature( feature, context );
131 }
132 
133 QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
134 {
135  QgsAttributes attrs = feature.attributes();
136  QVariant value;
137  if ( mExpression )
138  {
139  value = mExpression->evaluate( &context.expressionContext() );
140  }
141  else
142  {
143  value = attrs.value( mAttrNum );
144  }
145 
146  return value;
147 }
148 
150 {
151  QVariant value = valueForFeature( feature, context );
152 
153  // Null values should not be categorized
154  if ( value.isNull() )
155  return nullptr;
156 
157  // find the right category
158  return symbolForValue( value.toDouble() );
159 }
160 
162 {
163  QgsFeatureRenderer::startRender( context, fields );
164 
165  mCounting = context.rendererScale() == 0.0;
166 
167  // find out classification attribute index from name
168  mAttrNum = fields.lookupField( mAttrName );
169 
170  if ( mAttrNum == -1 )
171  {
172  mExpression.reset( new QgsExpression( mAttrName ) );
173  mExpression->prepare( &context.expressionContext() );
174  }
175 
176  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
177  {
178  if ( !range.symbol() )
179  continue;
180 
181  range.symbol()->startRender( context, fields );
182  }
183 }
184 
186 {
188 
189  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
190  {
191  if ( !range.symbol() )
192  continue;
193 
194  range.symbol()->stopRender( context );
195  }
196 }
197 
199 {
200  QSet<QString> attributes;
201 
202  // mAttrName can contain either attribute name or an expression.
203  // Sometimes it is not possible to distinguish between those two,
204  // e.g. "a - b" can be both a valid attribute name or expression.
205  // Since we do not have access to fields here, try both options.
206  attributes << mAttrName;
207 
208  QgsExpression testExpr( mAttrName );
209  if ( !testExpr.hasParserError() )
210  attributes.unite( testExpr.referencedColumns() );
211 
212  QgsRangeList::const_iterator range_it = mRanges.constBegin();
213  for ( ; range_it != mRanges.constEnd(); ++range_it )
214  {
215  QgsSymbol *symbol = range_it->symbol();
216  if ( symbol )
217  {
218  attributes.unite( symbol->usedAttributes( context ) );
219  }
220  }
221  return attributes;
222 }
223 
225 {
226  QgsExpression testExpr( mAttrName );
227  if ( !testExpr.hasParserError() )
228  {
229  QgsExpressionContext context;
230  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
231  testExpr.prepare( &context );
232  return testExpr.needsGeometry();
233  }
234  return false;
235 }
236 
238 {
239  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
240  return false;
241  mRanges[rangeIndex].setSymbol( symbol );
242  return true;
243 }
244 
245 bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
246 {
247  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
248  return false;
249  mRanges[rangeIndex].setLabel( label );
250  return true;
251 }
252 
253 bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
254 {
255  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
256  return false;
257  QgsRendererRange &range = mRanges[rangeIndex];
259  if ( rangeIndex == 0 )
261  else if ( rangeIndex == mRanges.count() )
263 
264  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
265  range.setUpperValue( value );
266  if ( isDefaultLabel )
267  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
268 
269  return true;
270 }
271 
272 bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
273 {
274  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
275  return false;
276 
277  QgsRendererRange &range = mRanges[rangeIndex];
279  if ( rangeIndex == 0 )
281  else if ( rangeIndex == mRanges.count() )
283 
284  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
285  range.setLowerValue( value );
286  if ( isDefaultLabel )
287  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
288 
289  return true;
290 }
291 
292 bool QgsGraduatedSymbolRenderer::updateRangeRenderState( int rangeIndex, bool value )
293 {
294  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
295  return false;
296  mRanges[rangeIndex].setRenderState( value );
297  return true;
298 }
299 
301 {
302  QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
303  for ( int i = 0; i < mRanges.count(); i++ )
304  s += mRanges[i].dump();
305  return s;
306 }
307 
309 {
311 
313 
314  if ( mSourceSymbol )
315  r->setSourceSymbol( mSourceSymbol->clone() );
316  if ( mSourceColorRamp )
317  {
318  r->setSourceColorRamp( mSourceColorRamp->clone() );
319  }
322  copyRendererData( r );
323  return r;
324 }
325 
326 void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
327 {
328  QVariantMap newProps = props;
329  newProps[ QStringLiteral( "attribute" )] = mAttrName;
330  newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
331 
332  // create a Rule for each range
333  bool first = true;
334  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
335  {
336  it->toSld( doc, element, newProps, first );
337  first = false;
338  }
339 }
340 
342 {
343  Q_UNUSED( context )
344  QgsSymbolList lst;
345  lst.reserve( mRanges.count() );
346  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
347  {
348  lst.append( range.symbol() );
349  }
350  return lst;
351 }
352 
354 {
355  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
356  {
357  QgsStyleSymbolEntity entity( range.symbol() );
358  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
359  return false;
360  }
361 
362  if ( mSourceColorRamp )
363  {
365  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
366  return false;
367  }
368 
369  return true;
370 }
371 
372 void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
373 {
375 }
376 
377 QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
378 {
381  QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
382  return QgsClassificationMethod::rangesToBreaks( _classes );
383 }
384 
387  QgsVectorLayer *vlayer,
388  const QString &attrName,
389  int classes,
390  Mode mode,
391  QgsSymbol *symbol,
392  QgsColorRamp *ramp,
393  const QgsRendererRangeLabelFormat &labelFormat,
394  bool useSymmetricMode,
395  double symmetryPoint,
396  const QStringList &listForCboPrettyBreaks,
397  bool astride
398 )
399 {
400  Q_UNUSED( listForCboPrettyBreaks )
401 
404  r->setSourceSymbol( symbol->clone() );
405  r->setSourceColorRamp( ramp->clone() );
406 
407  QString methodId = methodIdFromMode( mode );
409 
410  if ( method )
411  {
413  method->setLabelFormat( labelFormat.format() );
416  }
417  r->setClassificationMethod( method );
418 
419  r->updateClasses( vlayer, classes );
420  return r;
421 }
423 
425  bool useSymmetricMode, double symmetryPoint, bool astride )
426 {
427  if ( mAttrName.isEmpty() )
428  return;
429 
430  QString methodId = methodIdFromMode( mode );
433  setClassificationMethod( method );
434 
435  updateClasses( vlayer, nclasses );
436 }
437 
439 {
441  return;
442 
443  QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
444 
446 
447  for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
448  {
450  addClass( QgsRendererRange( *it, newSymbol ) );
451  }
452  updateColorRamp( nullptr );
453 }
454 
457 {
458  return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
459 }
461 
463 {
464  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
465  if ( symbolsElem.isNull() )
466  return nullptr;
467 
468  QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
469  if ( rangesElem.isNull() )
470  return nullptr;
471 
472  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
474 
475  QDomElement rangeElem = rangesElem.firstChildElement();
476  while ( !rangeElem.isNull() )
477  {
478  if ( rangeElem.tagName() == QLatin1String( "range" ) )
479  {
480  double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
481  double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
482  QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
483  QString label = rangeElem.attribute( QStringLiteral( "label" ) );
484  bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
485  if ( symbolMap.contains( symbolName ) )
486  {
487  QgsSymbol *symbol = symbolMap.take( symbolName );
488  ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render ) );
489  }
490  }
491  rangeElem = rangeElem.nextSiblingElement();
492  }
493 
494  QString attrName = element.attribute( QStringLiteral( "attr" ) );
495 
497 
498  QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
499  if ( !attrMethod.isEmpty() )
500  {
501  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
503  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
505  }
506 
507 
508  // delete symbols if there are any more
510 
511  // try to load source symbol (optional)
512  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
513  if ( !sourceSymbolElem.isNull() )
514  {
515  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
516  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
517  {
518  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
519  }
520  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
521  }
522 
523  // try to load color ramp (optional)
524  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
525  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
526  {
527  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
528  }
529 
530  // try to load mode
531 
532  QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
533  QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
534  QgsClassificationMethod *method = nullptr;
535 
536  // TODO QGIS 4 Remove
537  // backward compatibility for QGIS project < 3.10
538  if ( !modeElem.isNull() )
539  {
540  QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
541  QString methodId;
542  // the strings saved in the project does not match with the old Mode enum
543  if ( modeString == QLatin1String( "equal" ) )
544  methodId = QStringLiteral( "EqualInterval" );
545  else if ( modeString == QLatin1String( "quantile" ) )
546  methodId = QStringLiteral( "Quantile" );
547  else if ( modeString == QLatin1String( "jenks" ) )
548  methodId = QStringLiteral( "Jenks" );
549  else if ( modeString == QLatin1String( "stddev" ) )
550  methodId = QStringLiteral( "StdDev" );
551  else if ( modeString == QLatin1String( "pretty" ) )
552  methodId = QStringLiteral( "Pretty" );
553 
555 
556  // symmetric mode
557  QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
558  if ( !symmetricModeElem.isNull() )
559  {
560  // symmetry
561  QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
562  QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
563  QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
564  method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
565  }
566  QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
567  if ( !labelFormatElem.isNull() )
568  {
569  // label format
570  QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
571  int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
572  bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
573  method->setLabelFormat( format );
574  method->setLabelPrecision( precision );
575  method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
576  }
577  // End of backward compatibility
578  }
579  else
580  {
581  // QGIS project 3.10+
582  method = QgsClassificationMethod::create( methodElem, context );
583  }
584 
585  // apply the method
586  r->setClassificationMethod( method );
587 
588  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
589  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
590  {
591  for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
592  {
593  convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
594  }
595  if ( r->mSourceSymbol )
596  {
597  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
598  }
599  }
600  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
601  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
602  {
603  for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
604  {
605  convertSymbolSizeScale( range.symbol(),
606  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
607  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
608  }
609  if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
610  {
612  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
613  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
614  }
615  }
616 
617  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
618  if ( !ddsLegendSizeElem.isNull() )
619  {
620  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
621  }
622 // TODO: symbol levels
623  return r;
624 }
625 
626 QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
627 {
628  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
629  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
630  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
631  rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
632 
633  // ranges
634  int i = 0;
636  QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
637  QgsRangeList::const_iterator it = mRanges.constBegin();
638  for ( ; it != mRanges.constEnd(); ++it )
639  {
640  const QgsRendererRange &range = *it;
641  QString symbolName = QString::number( i );
642  symbols.insert( symbolName, range.symbol() );
643 
644  QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
645  rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
646  rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
647  rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
648  rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
649  rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
650  rangesElem.appendChild( rangeElem );
651  i++;
652  }
653 
654  rendererElem.appendChild( rangesElem );
655 
656  // save symbols
657  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
658  rendererElem.appendChild( symbolsElem );
659 
660  // save source symbol
661  if ( mSourceSymbol )
662  {
663  QgsSymbolMap sourceSymbols;
664  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
665  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
666  rendererElem.appendChild( sourceSymbolElem );
667  }
668 
669  // save source color ramp
670  if ( mSourceColorRamp )
671  {
672  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
673  rendererElem.appendChild( colorRampElem );
674  }
675 
676  // save classification method
677  QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
678  rendererElem.appendChild( classificationMethodElem );
679 
680  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
681  rendererElem.appendChild( rotationElem );
682 
683  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
684  rendererElem.appendChild( sizeScaleElem );
685 
687  {
688  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
689  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
690  rendererElem.appendChild( ddsLegendElem );
691  }
692 
693  saveRendererData( doc, rendererElem, context );
694 
695  return rendererElem;
696 }
697 
698 QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
699 {
701  int i = 0;
702  lst.reserve( mRanges.size() );
703  for ( const QgsRendererRange &range : mRanges )
704  {
705  lst << QgsLegendSymbolItem( range.symbol(), range.label(), QString::number( i++ ), true );
706  }
707  return lst;
708 }
709 
711 QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
712 {
713  switch ( mode )
714  {
715  case EqualInterval:
716  return QStringLiteral( "EqualInterval" );
717  case Quantile:
718  return QStringLiteral( "Quantile" );
719  case Jenks:
720  return QStringLiteral( "Jenks" );
721  case StdDev:
722  return QStringLiteral( "StdDev" );
723  case Pretty:
724  return QStringLiteral( "Pretty" );
725  case Custom:
726  return QString();
727  }
728  return QString();
729 }
730 
731 QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
732 {
733  if ( methodId == QLatin1String( "EqualInterval" ) )
734  return EqualInterval;
735  if ( methodId == QLatin1String( "Quantile" ) )
736  return Quantile;
737  if ( methodId == QLatin1String( "Jenks" ) )
738  return Jenks;
739  if ( methodId == QLatin1String( "StdDev" ) )
740  return StdDev;
741  if ( methodId == QLatin1String( "Pretty" ) )
742  return Pretty;
743  else
744  return Custom;
745 }
747 
749 {
751  {
752  // check that all symbols that have the same size expression
753  QgsProperty ddSize;
754  for ( const QgsRendererRange &range : mRanges )
755  {
756  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
757  if ( ddSize )
758  {
759  QgsProperty sSize( symbol->dataDefinedSize() );
760  if ( sSize && sSize != ddSize )
761  {
762  // no common size expression
763  return baseLegendSymbolItems();
764  }
765  }
766  else
767  {
768  ddSize = symbol->dataDefinedSize();
769  }
770  }
771 
772  if ( ddSize && ddSize.isActive() )
773  {
775 
777  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
778  lst += ddSizeLegend.legendSymbolList();
779 
780  lst += baseLegendSymbolItems();
781  return lst;
782  }
783  }
784 
785  return baseLegendSymbolItems();
786 }
787 
788 QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
789 {
790  QVariant value = valueForFeature( feature, context );
791 
792  // Null values should not be categorized
793  if ( value.isNull() )
794  return QSet< QString >();
795 
796  // find the right category
797  QString key = legendKeyForValue( value.toDouble() );
798  if ( !key.isNull() )
799  return QSet< QString >() << key;
800  else
801  return QSet< QString >();
802 }
803 
805 {
806  return mSourceSymbol.get();
807 }
808 
810 {
811  return mSourceSymbol.get();
812 }
813 
815 {
816  mSourceSymbol.reset( sym );
817 }
818 
820 {
821  return mSourceColorRamp.get();
822 }
823 
825 {
826  return mSourceColorRamp.get();
827 }
828 
830 {
831  if ( ramp == mSourceColorRamp.get() )
832  return;
833 
834  mSourceColorRamp.reset( ramp );
835 }
836 
838 {
839  double min = std::numeric_limits<double>::max();
840  for ( int i = 0; i < mRanges.count(); i++ )
841  {
842  double sz = 0;
843  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
844  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
845  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
846  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
847  min = std::min( sz, min );
848  }
849  return min;
850 }
851 
853 {
854  double max = std::numeric_limits<double>::min();
855  for ( int i = 0; i < mRanges.count(); i++ )
856  {
857  double sz = 0;
858  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
859  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
860  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
861  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
862  max = std::max( sz, max );
863  }
864  return max;
865 }
866 
867 void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
868 {
869  for ( int i = 0; i < mRanges.count(); i++ )
870  {
871  std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
872  const double size = mRanges.count() > 1
873  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
874  : .5 * ( maxSize + minSize );
875  if ( symbol->type() == Qgis::SymbolType::Marker )
876  static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
877  if ( symbol->type() == Qgis::SymbolType::Line )
878  static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
879  updateRangeSymbol( i, symbol.release() );
880  }
881 }
882 
884 {
885  int i = 0;
886  if ( ramp )
887  {
888  setSourceColorRamp( ramp );
889  }
890 
891  if ( mSourceColorRamp )
892  {
893  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
894  {
895  QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
896  if ( symbol )
897  {
898  double colorValue;
899  colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
900  symbol->setColor( mSourceColorRamp->color( colorValue ) );
901  }
902  updateRangeSymbol( i, symbol );
903  ++i;
904  }
905  }
906 
907 }
908 
910 {
911  if ( !sym )
912  return;
913 
914  int i = 0;
915  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
916  {
917  std::unique_ptr<QgsSymbol> symbol( sym->clone() );
919  {
920  symbol->setColor( range.symbol()->color() );
921  }
922  else if ( mGraduatedMethod == GraduatedSize )
923  {
924  if ( symbol->type() == Qgis::SymbolType::Marker )
925  static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
926  static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
927  else if ( symbol->type() == Qgis::SymbolType::Line )
928  static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
929  static_cast<QgsLineSymbol *>( range.symbol() )->width() );
930  }
931  updateRangeSymbol( i, symbol.release() );
932  ++i;
933  }
934  setSourceSymbol( sym->clone() );
935 }
936 
938 {
939  return true;
940 }
941 
943 {
944  bool ok;
945  int index = key.toInt( &ok );
946  if ( ok && index >= 0 && index < mRanges.size() )
947  return mRanges.at( index ).renderState();
948  else
949  return true;
950 }
951 
952 void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
953 {
954  bool ok;
955  int index = key.toInt( &ok );
956  if ( ok )
957  updateRangeRenderState( index, state );
958 }
959 
961 {
962  bool ok;
963  int index = key.toInt( &ok );
964  if ( ok )
965  updateRangeSymbol( index, symbol );
966  else
967  delete symbol;
968 }
969 
971 {
972  QgsSymbol *newSymbol = symbol->clone();
973  QString label = QStringLiteral( "0.0 - 0.0" );
974  mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
975 }
976 
977 void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
978 {
979  QgsSymbol *newSymbol = mSourceSymbol->clone();
980  QString label = mClassificationMethod->labelForRange( lower, upper );
981  mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
982 }
983 
984 void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
985 {
986  QMutableListIterator< QgsRendererRange > it( mRanges );
987  while ( it.hasNext() )
988  {
989  QgsRendererRange range = it.next();
990  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
991  {
992  QgsRendererRange newRange = QgsRendererRange();
993  newRange.setLowerValue( breakValue );
994  newRange.setUpperValue( range.upperValue() );
995  newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
996  newRange.setSymbol( mSourceSymbol->clone() );
997 
998  //update old range
999  bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1000  range.setUpperValue( breakValue );
1001  if ( isDefaultLabel )
1002  range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1003  it.setValue( range );
1004 
1005  it.insert( newRange );
1006  break;
1007  }
1008  }
1009 
1010  if ( updateSymbols )
1011  {
1012  switch ( mGraduatedMethod )
1013  {
1014  case GraduatedColor:
1016  break;
1017  case GraduatedSize:
1019  break;
1020  }
1021  }
1022 }
1023 
1025 {
1026  mRanges.append( range );
1027 }
1028 
1030 {
1031  mRanges.removeAt( idx );
1032 }
1033 
1035 {
1036  mRanges.clear();
1037 }
1038 
1041 {
1042  mClassificationMethod->setLabelFormat( labelFormat.format() );
1043  mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1044  mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1045 
1046  if ( updateRanges )
1047  {
1049  }
1050 }
1052 
1054 {
1055  for ( int i = 0; i < mRanges.count(); i++ )
1056  {
1058  if ( i == 0 )
1060  else if ( i == mRanges.count() - 1 )
1062  mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1063  }
1064 }
1065 
1067 {
1068  // Find the minimum size of a class
1069  double minClassRange = 0.0;
1070  for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1071  {
1072  double range = rendererRange.upperValue() - rendererRange.lowerValue();
1073  if ( range <= 0.0 )
1074  continue;
1075  if ( minClassRange == 0.0 || range < minClassRange )
1076  minClassRange = range;
1077  }
1078  if ( minClassRange <= 0.0 )
1079  return;
1080 
1081  // Now set the number of decimal places to ensure no more than 20% error in
1082  // representing this range (up to 10% at upper and lower end)
1083 
1084  int ndp = 10;
1085  double nextDpMinRange = 0.0000000099;
1086  while ( ndp > 0 && nextDpMinRange < minClassRange )
1087  {
1088  ndp--;
1089  nextDpMinRange *= 10.0;
1090  }
1091  mClassificationMethod->setLabelPrecision( ndp );
1092  if ( updateRanges )
1094 }
1095 
1097 {
1098  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1099  return;
1100  mRanges.move( from, to );
1101 }
1102 
1104 {
1105  return r1 < r2;
1106 }
1107 
1109 {
1110  return !valueLessThan( r1, r2 );
1111 }
1112 
1113 void QgsGraduatedSymbolRenderer::sortByValue( Qt::SortOrder order )
1114 {
1115  if ( order == Qt::AscendingOrder )
1116  {
1117  std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1118  }
1119  else
1120  {
1121  std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1122  }
1123 }
1124 
1126 {
1127  QgsRangeList sortedRanges = mRanges;
1128  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1129 
1130  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1131  if ( it == sortedRanges.constEnd() )
1132  return false;
1133 
1134  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1135  return true;
1136 
1137  double prevMax = ( *it ).upperValue();
1138  ++it;
1139 
1140  for ( ; it != sortedRanges.constEnd(); ++it )
1141  {
1142  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1143  return true;
1144 
1145  if ( ( *it ).lowerValue() < prevMax )
1146  return true;
1147 
1148  prevMax = ( *it ).upperValue();
1149  }
1150  return false;
1151 }
1152 
1154 {
1155  QgsRangeList sortedRanges = mRanges;
1156  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1157 
1158  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1159  if ( it == sortedRanges.constEnd() )
1160  return false;
1161 
1162  double prevMax = ( *it ).upperValue();
1163  ++it;
1164 
1165  for ( ; it != sortedRanges.constEnd(); ++it )
1166  {
1167  if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1168  return true;
1169 
1170  prevMax = ( *it ).upperValue();
1171  }
1172  return false;
1173 }
1174 
1176 {
1177  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1178 }
1179 
1181 {
1182  return !labelLessThan( r1, r2 );
1183 }
1184 
1185 void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
1186 {
1187  if ( order == Qt::AscendingOrder )
1188  {
1189  std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1190  }
1191  else
1192  {
1193  std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1194  }
1195 }
1196 
1198 {
1199  return mClassificationMethod.get();
1200 }
1201 
1203 {
1204  mClassificationMethod.reset( method );
1205 }
1206 
1208 {
1209  QString methodId = methodIdFromMode( mode );
1211  setClassificationMethod( method );
1212 }
1213 
1215 {
1216  mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1217 }
1218 
1220 {
1221  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1222 }
1223 
1225 {
1226  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1227 }
1228 
1230 {
1231  std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1232  if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1233  {
1234  r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1235  }
1236  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1237  {
1238  const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1239  if ( categorizedSymbolRenderer )
1240  {
1241  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1242  if ( categorizedSymbolRenderer->sourceSymbol() )
1243  r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1244  if ( categorizedSymbolRenderer->sourceColorRamp() )
1245  {
1246  bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1247  dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1248  if ( !isRandom )
1249  r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1250  }
1251  r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1252  }
1253  }
1254  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1255  {
1256  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1257  if ( pointDistanceRenderer )
1258  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1259  }
1260  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1261  {
1262  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1263  if ( invertedPolygonRenderer )
1264  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1265  }
1266 
1267  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1268  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1269 
1270  if ( !r )
1271  {
1272  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1273  QgsRenderContext context;
1274  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1275  if ( !symbols.isEmpty() )
1276  {
1277  r->setSourceSymbol( symbols.at( 0 )->clone() );
1278  }
1279  }
1280 
1281  renderer->copyRendererData( r.get() );
1282 
1283  return r.release();
1284 }
1285 
1287 {
1288  mDataDefinedSizeLegend.reset( settings );
1289 }
1290 
1292 {
1293  return mDataDefinedSizeLegend.get();
1294 }
1295 
1297 {
1298  switch ( method )
1299  {
1300  case GraduatedColor:
1301  return QStringLiteral( "GraduatedColor" );
1302  case GraduatedSize:
1303  return QStringLiteral( "GraduatedSize" );
1304  }
1305  return QString();
1306 }
1307 
1308 
@ 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:32
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:344
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.
Definition: qgscolorramp.h:305
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:232
bool isActive() const
Returns whether the property is currently active.
Totally random color ramp.
Definition: qgscolorramp.h:457
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:1251
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:1219
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:817
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:1742
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1741
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1246
#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.