QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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  for ( const QgsRendererRange &range : mRanges )
119  {
120  if ( matchingRange == &range )
121  return range.uuid();
122  }
123  }
124  return QString();
125 }
126 
128 {
129  return originalSymbolForFeature( feature, context );
130 }
131 
132 QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
133 {
134  QgsAttributes attrs = feature.attributes();
135  QVariant value;
136  if ( mExpression )
137  {
138  value = mExpression->evaluate( &context.expressionContext() );
139  }
140  else
141  {
142  value = attrs.value( mAttrNum );
143  }
144 
145  return value;
146 }
147 
149 {
150  QVariant value = valueForFeature( feature, context );
151 
152  // Null values should not be categorized
153  if ( QgsVariantUtils::isNull( value ) )
154  return nullptr;
155 
156  // find the right category
157  return symbolForValue( value.toDouble() );
158 }
159 
161 {
162  QgsFeatureRenderer::startRender( context, fields );
163 
164  mCounting = context.rendererScale() == 0.0;
165 
166  // find out classification attribute index from name
167  mAttrNum = fields.lookupField( mAttrName );
168 
169  if ( mAttrNum == -1 )
170  {
171  mExpression.reset( new QgsExpression( mAttrName ) );
172  mExpression->prepare( &context.expressionContext() );
173  }
174 
175  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
176  {
177  if ( !range.symbol() )
178  continue;
179 
180  range.symbol()->startRender( context, fields );
181  }
182 }
183 
185 {
187 
188  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
189  {
190  if ( !range.symbol() )
191  continue;
192 
193  range.symbol()->stopRender( context );
194  }
195 }
196 
198 {
199  QSet<QString> attributes;
200 
201  // mAttrName can contain either attribute name or an expression.
202  // Sometimes it is not possible to distinguish between those two,
203  // e.g. "a - b" can be both a valid attribute name or expression.
204  // Since we do not have access to fields here, try both options.
205  attributes << mAttrName;
206 
207  QgsExpression testExpr( mAttrName );
208  if ( !testExpr.hasParserError() )
209  attributes.unite( testExpr.referencedColumns() );
210 
211  QgsRangeList::const_iterator range_it = mRanges.constBegin();
212  for ( ; range_it != mRanges.constEnd(); ++range_it )
213  {
214  QgsSymbol *symbol = range_it->symbol();
215  if ( symbol )
216  {
217  attributes.unite( symbol->usedAttributes( context ) );
218  }
219  }
220  return attributes;
221 }
222 
224 {
225  QgsExpression testExpr( mAttrName );
226  if ( !testExpr.hasParserError() )
227  {
228  QgsExpressionContext context;
229  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
230  testExpr.prepare( &context );
231  return testExpr.needsGeometry();
232  }
233  return false;
234 }
235 
237 {
238  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
239  return false;
240  mRanges[rangeIndex].setSymbol( symbol );
241  return true;
242 }
243 
244 bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
245 {
246  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
247  return false;
248  mRanges[rangeIndex].setLabel( label );
249  return true;
250 }
251 
252 bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
253 {
254  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
255  return false;
256  QgsRendererRange &range = mRanges[rangeIndex];
258  if ( rangeIndex == 0 )
260  else if ( rangeIndex == mRanges.count() )
262 
263  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
264  range.setUpperValue( value );
265  if ( isDefaultLabel )
266  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
267 
268  return true;
269 }
270 
271 bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
272 {
273  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
274  return false;
275 
276  QgsRendererRange &range = mRanges[rangeIndex];
278  if ( rangeIndex == 0 )
280  else if ( rangeIndex == mRanges.count() )
282 
283  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
284  range.setLowerValue( value );
285  if ( isDefaultLabel )
286  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
287 
288  return true;
289 }
290 
291 bool QgsGraduatedSymbolRenderer::updateRangeRenderState( int rangeIndex, bool value )
292 {
293  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
294  return false;
295  mRanges[rangeIndex].setRenderState( value );
296  return true;
297 }
298 
300 {
301  QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
302  for ( int i = 0; i < mRanges.count(); i++ )
303  s += mRanges[i].dump();
304  return s;
305 }
306 
308 {
310 
312 
313  if ( mSourceSymbol )
314  r->setSourceSymbol( mSourceSymbol->clone() );
315  if ( mSourceColorRamp )
316  {
317  r->setSourceColorRamp( mSourceColorRamp->clone() );
318  }
321  copyRendererData( r );
322  return r;
323 }
324 
325 void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
326 {
327  QVariantMap newProps = props;
328  newProps[ QStringLiteral( "attribute" )] = mAttrName;
329  newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
330 
331  // create a Rule for each range
332  bool first = true;
333  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
334  {
335  it->toSld( doc, element, newProps, first );
336  first = false;
337  }
338 }
339 
341 {
342  Q_UNUSED( context )
343  QgsSymbolList lst;
344  lst.reserve( mRanges.count() );
345  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
346  {
347  lst.append( range.symbol() );
348  }
349  return lst;
350 }
351 
353 {
354  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
355  {
356  QgsStyleSymbolEntity entity( range.symbol() );
357  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
358  return false;
359  }
360 
361  if ( mSourceColorRamp )
362  {
364  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
365  return false;
366  }
367 
368  return true;
369 }
370 
371 void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
372 {
374 }
375 
376 QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
377 {
380  QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
381  return QgsClassificationMethod::rangesToBreaks( _classes );
382 }
383 
386  QgsVectorLayer *vlayer,
387  const QString &attrName,
388  int classes,
389  Mode mode,
390  QgsSymbol *symbol,
391  QgsColorRamp *ramp,
392  const QgsRendererRangeLabelFormat &labelFormat,
393  bool useSymmetricMode,
394  double symmetryPoint,
395  const QStringList &listForCboPrettyBreaks,
396  bool astride
397 )
398 {
399  Q_UNUSED( listForCboPrettyBreaks )
400 
403  r->setSourceSymbol( symbol->clone() );
404  r->setSourceColorRamp( ramp->clone() );
405 
406  QString methodId = methodIdFromMode( mode );
408 
409  if ( method )
410  {
412  method->setLabelFormat( labelFormat.format() );
415  }
416  r->setClassificationMethod( method );
417 
418  r->updateClasses( vlayer, classes );
419  return r;
420 }
422 
424  bool useSymmetricMode, double symmetryPoint, bool astride )
425 {
426  if ( mAttrName.isEmpty() )
427  return;
428 
429  QString methodId = methodIdFromMode( mode );
432  setClassificationMethod( method );
433 
434  updateClasses( vlayer, nclasses );
435 }
436 
438 {
440  return;
441 
442  QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
443 
445 
446  for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
447  {
449  addClass( QgsRendererRange( *it, newSymbol ) );
450  }
451  updateColorRamp( nullptr );
452 }
453 
456 {
457  return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
458 }
460 
462 {
463  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
464  if ( symbolsElem.isNull() )
465  return nullptr;
466 
467  QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
468  if ( rangesElem.isNull() )
469  return nullptr;
470 
471  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
473 
474  QDomElement rangeElem = rangesElem.firstChildElement();
475  int i = 0;
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  QString uuid = rangeElem.attribute( QStringLiteral( "uuid" ), QString::number( i++ ) );
486  if ( symbolMap.contains( symbolName ) )
487  {
488  QgsSymbol *symbol = symbolMap.take( symbolName );
489  ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
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( Qgis::GraduatedMethod::Color ) )
504  else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
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  rangeElem.setAttribute( QStringLiteral( "uuid" ), range.uuid() );
652  rangesElem.appendChild( rangeElem );
653  i++;
654  }
655 
656  rendererElem.appendChild( rangesElem );
657 
658  // save symbols
659  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
660  rendererElem.appendChild( symbolsElem );
661 
662  // save source symbol
663  if ( mSourceSymbol )
664  {
665  QgsSymbolMap sourceSymbols;
666  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
667  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
668  rendererElem.appendChild( sourceSymbolElem );
669  }
670 
671  // save source color ramp
672  if ( mSourceColorRamp )
673  {
674  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
675  rendererElem.appendChild( colorRampElem );
676  }
677 
678  // save classification method
679  QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
680  rendererElem.appendChild( classificationMethodElem );
681 
682  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
683  rendererElem.appendChild( rotationElem );
684 
685  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
686  rendererElem.appendChild( sizeScaleElem );
687 
689  {
690  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
691  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
692  rendererElem.appendChild( ddsLegendElem );
693  }
694 
695  saveRendererData( doc, rendererElem, context );
696 
697  return rendererElem;
698 }
699 
700 QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
701 {
703  lst.reserve( mRanges.size() );
704  for ( const QgsRendererRange &range : mRanges )
705  {
706  lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), 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 ( QgsVariantUtils::isNull( value ) )
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 
805 QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
806 {
807  ok = false;
808  int i = 0;
809  for ( i = 0; i < mRanges.size(); i++ )
810  {
811  if ( mRanges[i].uuid() == key )
812  {
813  ok = true;
814  break;
815  }
816  }
817 
818  if ( !ok )
819  {
820  ok = false;
821  return QString();
822  }
823 
824  const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
825  const QgsRendererRange &range = mRanges[i];
826 
827  return QStringLiteral( "(%1 >= %2) AND (%1 <= %3)" ).arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QVariant::Double ),
828  QgsExpression::quotedValue( range.upperValue(), QVariant::Double ) );
829 }
830 
832 {
833  return mSourceSymbol.get();
834 }
835 
837 {
838  return mSourceSymbol.get();
839 }
840 
842 {
843  mSourceSymbol.reset( sym );
844 }
845 
847 {
848  return mSourceColorRamp.get();
849 }
850 
852 {
853  return mSourceColorRamp.get();
854 }
855 
857 {
858  if ( ramp == mSourceColorRamp.get() )
859  return;
860 
861  mSourceColorRamp.reset( ramp );
862 }
863 
865 {
866  double min = std::numeric_limits<double>::max();
867  for ( int i = 0; i < mRanges.count(); i++ )
868  {
869  double sz = 0;
870  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
871  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
872  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
873  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
874  min = std::min( sz, min );
875  }
876  return min;
877 }
878 
880 {
881  double max = std::numeric_limits<double>::min();
882  for ( int i = 0; i < mRanges.count(); i++ )
883  {
884  double sz = 0;
885  if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
886  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
887  else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
888  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
889  max = std::max( sz, max );
890  }
891  return max;
892 }
893 
894 void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
895 {
896  for ( int i = 0; i < mRanges.count(); i++ )
897  {
898  std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
899  const double size = mRanges.count() > 1
900  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
901  : .5 * ( maxSize + minSize );
902  if ( symbol->type() == Qgis::SymbolType::Marker )
903  static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
904  if ( symbol->type() == Qgis::SymbolType::Line )
905  static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
906  updateRangeSymbol( i, symbol.release() );
907  }
908 }
909 
911 {
912  int i = 0;
913  if ( ramp )
914  {
915  setSourceColorRamp( ramp );
916  }
917 
918  if ( mSourceColorRamp )
919  {
920  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
921  {
922  QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
923  if ( symbol )
924  {
925  double colorValue;
926  colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
927  symbol->setColor( mSourceColorRamp->color( colorValue ) );
928  }
929  updateRangeSymbol( i, symbol );
930  ++i;
931  }
932  }
933 
934 }
935 
937 {
938  if ( !sym )
939  return;
940 
941  int i = 0;
942  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
943  {
944  std::unique_ptr<QgsSymbol> symbol( sym->clone() );
945  switch ( mGraduatedMethod )
946  {
948  {
949  symbol->setColor( range.symbol()->color() );
950  break;
951  }
953  {
954  if ( symbol->type() == Qgis::SymbolType::Marker )
955  static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
956  static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
957  else if ( symbol->type() == Qgis::SymbolType::Line )
958  static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
959  static_cast<QgsLineSymbol *>( range.symbol() )->width() );
960  break;
961  }
962  }
963  updateRangeSymbol( i, symbol.release() );
964  ++i;
965  }
966  setSourceSymbol( sym->clone() );
967 }
968 
970 {
971  return true;
972 }
973 
975 {
976  for ( const QgsRendererRange &range : std::as_const( mRanges ) )
977  {
978  if ( range.uuid() == key )
979  {
980  return range.renderState();
981  }
982  }
983  return true;
984 }
985 
986 void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
987 {
988  for ( int i = 0; i < mRanges.size(); i++ )
989  {
990  if ( mRanges[i].uuid() == key )
991  {
992  updateRangeRenderState( i, state );
993  break;
994  }
995  }
996 }
997 
999 {
1000  bool ok = false;
1001  int i = 0;
1002  for ( i = 0; i < mRanges.size(); i++ )
1003  {
1004  if ( mRanges[i].uuid() == key )
1005  {
1006  ok = true;
1007  break;
1008  }
1009  }
1010 
1011  if ( ok )
1012  updateRangeSymbol( i, symbol );
1013  else
1014  delete symbol;
1015 }
1016 
1018 {
1019  QgsSymbol *newSymbol = symbol->clone();
1020  QString label = QStringLiteral( "0.0 - 0.0" );
1021  mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1022 }
1023 
1024 void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1025 {
1026  QgsSymbol *newSymbol = mSourceSymbol->clone();
1027  QString label = mClassificationMethod->labelForRange( lower, upper );
1028  mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1029 }
1030 
1031 void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
1032 {
1033  QMutableListIterator< QgsRendererRange > it( mRanges );
1034  while ( it.hasNext() )
1035  {
1036  QgsRendererRange range = it.next();
1037  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1038  {
1039  QgsRendererRange newRange = QgsRendererRange();
1040  newRange.setLowerValue( breakValue );
1041  newRange.setUpperValue( range.upperValue() );
1042  newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1043  newRange.setSymbol( mSourceSymbol->clone() );
1044 
1045  //update old range
1046  bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1047  range.setUpperValue( breakValue );
1048  if ( isDefaultLabel )
1049  range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1050  it.setValue( range );
1051 
1052  it.insert( newRange );
1053  break;
1054  }
1055  }
1056 
1057  if ( updateSymbols )
1058  {
1059  switch ( mGraduatedMethod )
1060  {
1063  break;
1066  break;
1067  }
1068  }
1069 }
1070 
1072 {
1073  mRanges.append( range );
1074 }
1075 
1077 {
1078  mRanges.removeAt( idx );
1079 }
1080 
1082 {
1083  mRanges.clear();
1084 }
1085 
1088 {
1089  mClassificationMethod->setLabelFormat( labelFormat.format() );
1090  mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1091  mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1092 
1093  if ( updateRanges )
1094  {
1096  }
1097 }
1099 
1101 {
1102  for ( int i = 0; i < mRanges.count(); i++ )
1103  {
1105  if ( i == 0 )
1107  else if ( i == mRanges.count() - 1 )
1109  mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1110  }
1111 }
1112 
1114 {
1115  // Find the minimum size of a class
1116  double minClassRange = 0.0;
1117  for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1118  {
1119  double range = rendererRange.upperValue() - rendererRange.lowerValue();
1120  if ( range <= 0.0 )
1121  continue;
1122  if ( minClassRange == 0.0 || range < minClassRange )
1123  minClassRange = range;
1124  }
1125  if ( minClassRange <= 0.0 )
1126  return;
1127 
1128  // Now set the number of decimal places to ensure no more than 20% error in
1129  // representing this range (up to 10% at upper and lower end)
1130 
1131  int ndp = 10;
1132  double nextDpMinRange = 0.0000000099;
1133  while ( ndp > 0 && nextDpMinRange < minClassRange )
1134  {
1135  ndp--;
1136  nextDpMinRange *= 10.0;
1137  }
1138  mClassificationMethod->setLabelPrecision( ndp );
1139  if ( updateRanges )
1141 }
1142 
1144 {
1145  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1146  return;
1147  mRanges.move( from, to );
1148 }
1149 
1151 {
1152  return r1 < r2;
1153 }
1154 
1156 {
1157  return !valueLessThan( r1, r2 );
1158 }
1159 
1160 void QgsGraduatedSymbolRenderer::sortByValue( Qt::SortOrder order )
1161 {
1162  if ( order == Qt::AscendingOrder )
1163  {
1164  std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1165  }
1166  else
1167  {
1168  std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1169  }
1170 }
1171 
1173 {
1174  QgsRangeList sortedRanges = mRanges;
1175  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1176 
1177  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1178  if ( it == sortedRanges.constEnd() )
1179  return false;
1180 
1181  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1182  return true;
1183 
1184  double prevMax = ( *it ).upperValue();
1185  ++it;
1186 
1187  for ( ; it != sortedRanges.constEnd(); ++it )
1188  {
1189  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1190  return true;
1191 
1192  if ( ( *it ).lowerValue() < prevMax )
1193  return true;
1194 
1195  prevMax = ( *it ).upperValue();
1196  }
1197  return false;
1198 }
1199 
1201 {
1202  QgsRangeList sortedRanges = mRanges;
1203  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1204 
1205  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1206  if ( it == sortedRanges.constEnd() )
1207  return false;
1208 
1209  double prevMax = ( *it ).upperValue();
1210  ++it;
1211 
1212  for ( ; it != sortedRanges.constEnd(); ++it )
1213  {
1214  if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1215  return true;
1216 
1217  prevMax = ( *it ).upperValue();
1218  }
1219  return false;
1220 }
1221 
1223 {
1224  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1225 }
1226 
1228 {
1229  return !labelLessThan( r1, r2 );
1230 }
1231 
1232 void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
1233 {
1234  if ( order == Qt::AscendingOrder )
1235  {
1236  std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1237  }
1238  else
1239  {
1240  std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1241  }
1242 }
1243 
1245 {
1246  return mClassificationMethod.get();
1247 }
1248 
1250 {
1251  mClassificationMethod.reset( method );
1252 }
1253 
1255 {
1256  QString methodId = methodIdFromMode( mode );
1258  setClassificationMethod( method );
1259 }
1260 
1262 {
1263  mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1264 }
1265 
1267 {
1268  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1269 }
1270 
1272 {
1273  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1274 }
1275 
1277 {
1278  std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1279  if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1280  {
1281  r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1282  }
1283  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1284  {
1285  const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1286  if ( categorizedSymbolRenderer )
1287  {
1288  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1289  if ( categorizedSymbolRenderer->sourceSymbol() )
1290  r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1291  if ( categorizedSymbolRenderer->sourceColorRamp() )
1292  {
1293  bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1294  dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1295  if ( !isRandom )
1296  r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1297  }
1298  r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1299  }
1300  }
1301  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1302  {
1303  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1304  if ( pointDistanceRenderer )
1305  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1306  }
1307  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1308  {
1309  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1310  if ( invertedPolygonRenderer )
1311  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1312  }
1313 
1314  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1315  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1316 
1317  if ( !r )
1318  {
1319  r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1320  QgsRenderContext context;
1321  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1322  if ( !symbols.isEmpty() )
1323  {
1324  r->setSourceSymbol( symbols.at( 0 )->clone() );
1325  }
1326  }
1327 
1328  renderer->copyRendererData( r.get() );
1329 
1330  return r.release();
1331 }
1332 
1334 {
1335  mDataDefinedSizeLegend.reset( settings );
1336 }
1337 
1339 {
1340  return mDataDefinedSizeLegend.get();
1341 }
1342 
1344 {
1345  switch ( method )
1346  {
1348  return QStringLiteral( "GraduatedColor" );
1350  return QStringLiteral( "GraduatedSize" );
1351  }
1352  return QString();
1353 }
1354 
1355 
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition: qgis.h:2670
@ Size
Alter size of symbols.
@ Color
Alter color of symbols.
@ 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:59
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:29
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.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
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:46
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:90
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:359
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
const QgsRendererRange * rangeForValue(double value) const
Returns the renderer range matching the provided value, or nullptr if no range matches the value.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
QgsGraduatedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
static Q_DECL_DEPRECATED void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
bool updateRangeLabel(int rangeIndex, const QString &label)
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
void checkLegendSymbolItem(const QString &key, bool state=true) override
Sets whether the legend symbology item with the specified ley should be checked.
std::unique_ptr< QgsSymbol > mSourceSymbol
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
void setGraduatedMethod(Qgis::GraduatedMethod method)
Set the method used for graduation (either size or color).
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
Q_DECL_DEPRECATED void setMode(Mode mode)
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
Q_DECL_DEPRECATED void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode=false, double symmetryPoint=0.0, bool astride=false)
Recalculate classes for a layer.
QString dump() const override
Returns debug information about this renderer.
bool updateRangeUpperValue(int rangeIndex, double value)
QString legendKeyToExpression(const QString &key, QgsVectorLayer *layer, bool &ok) const override
Attempts to convert the specified legend rule key to a QGIS expression matching the features displaye...
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
bool legendSymbolItemChecked(const QString &key) override
Returns true if the legend symbology item with the specified key is checked.
bool updateRangeLowerValue(int rangeIndex, double value)
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
Returns true if symbology items in legend are checkable.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void updateRangeLabels()
Updates the labels of the ranges.
const QgsRangeList & ranges() const
Returns a list of all ranges used in the classification.
bool updateRangeRenderState(int rangeIndex, bool render)
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
double minSymbolSize() const
Returns the min symbol size when graduated by size.
Qgis::GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color).
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
int mAttrNum
attribute index (derived from attribute name in startRender)
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
std::unique_ptr< QgsExpression > mExpression
static QString graduatedMethodStr(Qgis::GraduatedMethod method)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
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:228
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)
Sets the upper bound of the range.
QString label() const
Returns the label used for the range.
void setSymbol(QgsSymbol *s)
Sets the symbol used for the range.
QgsSymbol * symbol() const
Returns the symbol used for the range.
void setLabel(const QString &label)
Sets the label used for the range.
bool renderState() const
Returns true if the range should be rendered.
double upperValue() const
Returns the upper bound of the range.
void setLowerValue(double lowerValue)
Sets the lower bound of the range.
QString uuid() const
Returns the unique identifier for this range.
double lowerValue() const
Returns the lower bound of the range.
A color ramp entity for QgsStyle databases.
Definition: qgsstyle.h:1404
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:1372
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:94
void setColor(const QColor &color) const
Sets the color for the symbol.
Definition: qgssymbol.cpp:902
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:1201
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:705
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:337
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:5741
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5740
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5172
#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.