QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
22 
23 #include "qgsattributes.h"
25 #include "qgscolorramp.h"
27 #include "qgsexpression.h"
28 #include "qgsfeature.h"
30 #include "qgslogger.h"
31 #include "qgspainteffect.h"
32 #include "qgspainteffectregistry.h"
34 #include "qgsproperty.h"
35 #include "qgssymbol.h"
36 #include "qgssymbollayer.h"
37 #include "qgssymbollayerutils.h"
38 #include "qgsvectordataprovider.h"
39 #include "qgsvectorlayer.h"
40 #include "qgsvectorlayerutils.h"
42 #include "qgsstyleentityvisitor.h"
45 #include "qgsapplication.h"
48 
49 
51  : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
52  , mAttrName( attrName )
53 {
54  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
55 
56  //important - we need a deep copy of the ranges list, not a shared copy. This is required because
57  //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
58  //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
59  const auto constRanges = ranges;
60  for ( const QgsRendererRange &range : constRanges )
61  {
62  mRanges << range;
63  }
64 
66 }
67 
69 {
70  mRanges.clear(); // should delete all the symbols
71 }
72 
74 {
75  for ( const QgsRendererRange &range : mRanges )
76  {
77  if ( range.lowerValue() <= value && range.upperValue() >= value )
78  {
79  if ( range.renderState() || mCounting )
80  return range.symbol();
81  else
82  return nullptr;
83  }
84  }
85  // the value is out of the range: return NULL instead of symbol
86  return nullptr;
87 }
88 
89 QString QgsGraduatedSymbolRenderer::legendKeyForValue( double value ) const
90 {
91  int i = 0;
92  for ( const QgsRendererRange &range : mRanges )
93  {
94  if ( range.lowerValue() <= value && range.upperValue() >= value )
95  {
96  if ( range.renderState() || mCounting )
97  return QString::number( i );
98  else
99  return QString();
100  }
101  i++;
102  }
103  // the value is out of the range: return NULL
104  return QString();
105 }
106 
108 {
109  return originalSymbolForFeature( feature, context );
110 }
111 
112 QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
113 {
114  QgsAttributes attrs = feature.attributes();
115  QVariant value;
116  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
117  {
118  value = mExpression->evaluate( &context.expressionContext() );
119  }
120  else
121  {
122  value = attrs.at( mAttrNum );
123  }
124 
125  return value;
126 }
127 
129 {
130  QVariant value = valueForFeature( feature, context );
131 
132  // Null values should not be categorized
133  if ( value.isNull() )
134  return nullptr;
135 
136  // find the right category
137  return symbolForValue( value.toDouble() );
138 }
139 
141 {
142  QgsFeatureRenderer::startRender( context, fields );
143 
144  mCounting = context.rendererScale() == 0.0;
145 
146  // find out classification attribute index from name
147  mAttrNum = fields.lookupField( mAttrName );
148 
149  if ( mAttrNum == -1 )
150  {
151  mExpression.reset( new QgsExpression( mAttrName ) );
152  mExpression->prepare( &context.expressionContext() );
153  }
154 
155  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
156  {
157  if ( !range.symbol() )
158  continue;
159 
160  range.symbol()->startRender( context, fields );
161  }
162 }
163 
165 {
167 
168  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
169  {
170  if ( !range.symbol() )
171  continue;
172 
173  range.symbol()->stopRender( context );
174  }
175 }
176 
178 {
179  QSet<QString> attributes;
180 
181  // mAttrName can contain either attribute name or an expression.
182  // Sometimes it is not possible to distinguish between those two,
183  // e.g. "a - b" can be both a valid attribute name or expression.
184  // Since we do not have access to fields here, try both options.
185  attributes << mAttrName;
186 
187  QgsExpression testExpr( mAttrName );
188  if ( !testExpr.hasParserError() )
189  attributes.unite( testExpr.referencedColumns() );
190 
191  QgsRangeList::const_iterator range_it = mRanges.constBegin();
192  for ( ; range_it != mRanges.constEnd(); ++range_it )
193  {
194  QgsSymbol *symbol = range_it->symbol();
195  if ( symbol )
196  {
197  attributes.unite( symbol->usedAttributes( context ) );
198  }
199  }
200  return attributes;
201 }
202 
204 {
205  QgsExpression testExpr( mAttrName );
206  if ( !testExpr.hasParserError() )
207  {
208  QgsExpressionContext context;
209  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
210  testExpr.prepare( &context );
211  return testExpr.needsGeometry();
212  }
213  return false;
214 }
215 
217 {
218  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
219  return false;
220  mRanges[rangeIndex].setSymbol( symbol );
221  return true;
222 }
223 
224 bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
225 {
226  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
227  return false;
228  mRanges[rangeIndex].setLabel( label );
229  return true;
230 }
231 
232 bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
233 {
234  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
235  return false;
236  QgsRendererRange &range = mRanges[rangeIndex];
238  if ( rangeIndex == 0 )
240  else if ( rangeIndex == mRanges.count() )
242 
243  bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
244  range.setUpperValue( value );
245  if ( isDefaultLabel )
246  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
247 
248  return true;
249 }
250 
251 bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
252 {
253  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
254  return false;
255 
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.setLowerValue( value );
265  if ( isDefaultLabel )
266  range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
267 
268  return true;
269 }
270 
271 bool QgsGraduatedSymbolRenderer::updateRangeRenderState( int rangeIndex, bool value )
272 {
273  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
274  return false;
275  mRanges[rangeIndex].setRenderState( value );
276  return true;
277 }
278 
280 {
281  QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
282  for ( int i = 0; i < mRanges.count(); i++ )
283  s += mRanges[i].dump();
284  return s;
285 }
286 
288 {
290 
292 
293  if ( mSourceSymbol )
294  r->setSourceSymbol( mSourceSymbol->clone() );
295  if ( mSourceColorRamp )
296  {
297  r->setSourceColorRamp( mSourceColorRamp->clone() );
298  }
302  copyRendererData( r );
303  return r;
304 }
305 
306 void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
307 {
308  QgsStringMap newProps = props;
309  newProps[ QStringLiteral( "attribute" )] = mAttrName;
310  newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
311 
312  // create a Rule for each range
313  bool first = true;
314  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
315  {
316  it->toSld( doc, element, newProps, first );
317  first = false;
318  }
319 }
320 
322 {
323  Q_UNUSED( context )
324  QgsSymbolList lst;
325  lst.reserve( mRanges.count() );
326  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
327  {
328  lst.append( range.symbol() );
329  }
330  return lst;
331 }
332 
334 {
335  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
336  {
337  QgsStyleSymbolEntity entity( range.symbol() );
338  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
339  return false;
340  }
341 
342  if ( mSourceColorRamp )
343  {
345  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
346  return false;
347  }
348 
349  return true;
350 }
351 
352 void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
353 {
354  return QgsClassificationMethod::makeBreaksSymmetric( breaks, symmetryPoint, astride );
355 }
356 
357 QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
358 {
360  method.setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
361  QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
362  return QgsClassificationMethod::rangesToBreaks( _classes );
363 }
364 
367  QgsVectorLayer *vlayer,
368  const QString &attrName,
369  int classes,
370  Mode mode,
371  QgsSymbol *symbol,
372  QgsColorRamp *ramp,
374  bool useSymmetricMode,
375  double symmetryPoint,
376  const QStringList &listForCboPrettyBreaks,
377  bool astride
378 )
379 {
380  Q_UNUSED( listForCboPrettyBreaks )
381 
383  QgsGraduatedSymbolRenderer *r = new QgsGraduatedSymbolRenderer( attrName, ranges );
384  r->setSourceSymbol( symbol->clone() );
385  r->setSourceColorRamp( ramp->clone() );
386 
387  QString methodId = methodIdFromMode( mode );
389 
390  if ( method )
391  {
392  method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
393  method->setLabelFormat( labelFormat.format() );
394  method->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
395  method->setLabelPrecision( labelFormat.precision() );
396  }
397  r->setClassificationMethod( method );
398 
399  r->updateClasses( vlayer, classes );
400  return r;
401 }
403 
405  bool useSymmetricMode, double symmetryPoint, bool astride )
406 {
407  if ( mAttrName.isEmpty() )
408  return;
409 
410  QString methodId = methodIdFromMode( mode );
412  method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
413  setClassificationMethod( method );
414 
415  updateClasses( vlayer, nclasses );
416 }
417 
419 {
421  return;
422 
423  QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
424 
426 
427  for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
428  {
430  addClass( QgsRendererRange( *it, newSymbol ) );
431  }
432  updateColorRamp( nullptr );
433 }
434 
437 {
438  return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
439 }
441 
443 {
444  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
445  if ( symbolsElem.isNull() )
446  return nullptr;
447 
448  QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
449  if ( rangesElem.isNull() )
450  return nullptr;
451 
452  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
454 
455  QDomElement rangeElem = rangesElem.firstChildElement();
456  while ( !rangeElem.isNull() )
457  {
458  if ( rangeElem.tagName() == QLatin1String( "range" ) )
459  {
460  double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
461  double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
462  QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
463  QString label = rangeElem.attribute( QStringLiteral( "label" ) );
464  bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
465  if ( symbolMap.contains( symbolName ) )
466  {
467  QgsSymbol *symbol = symbolMap.take( symbolName );
468  ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render ) );
469  }
470  }
471  rangeElem = rangeElem.nextSiblingElement();
472  }
473 
474  QString attrName = element.attribute( QStringLiteral( "attr" ) );
475 
476  QgsGraduatedSymbolRenderer *r = new QgsGraduatedSymbolRenderer( attrName, ranges );
477 
478  QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
479  if ( !attrMethod.isEmpty() )
480  {
481  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
483  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
485  }
486 
487 
488  // delete symbols if there are any more
490 
491  // try to load source symbol (optional)
492  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
493  if ( !sourceSymbolElem.isNull() )
494  {
495  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
496  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
497  {
498  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
499  }
500  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
501  }
502 
503  // try to load color ramp (optional)
504  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
505  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
506  {
507  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
508  }
509 
510  // try to load mode
511 
512  QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
513  QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
514  QgsClassificationMethod *method = nullptr;
515 
516  // TODO QGIS 4 Remove
517  // backward compatibility for QGIS project < 3.10
518  if ( !modeElem.isNull() )
519  {
520  QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
521  QString methodId;
522  // the strings saved in the project does not match with the old Mode enum
523  if ( modeString == QLatin1String( "equal" ) )
524  methodId = QStringLiteral( "EqualInterval" );
525  else if ( modeString == QLatin1String( "quantile" ) )
526  methodId = QStringLiteral( "Quantile" );
527  else if ( modeString == QLatin1String( "jenks" ) )
528  methodId = QStringLiteral( "Jenks" );
529  else if ( modeString == QLatin1String( "stddev" ) )
530  methodId = QStringLiteral( "StdDev" );
531  else if ( modeString == QLatin1String( "pretty" ) )
532  methodId = QStringLiteral( "Pretty" );
533 
535 
536  // symmetric mode
537  QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
538  if ( !symmetricModeElem.isNull() )
539  {
540  // symmetry
541  QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
542  QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
543  QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
544  method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
545  }
546  QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
547  if ( !labelFormatElem.isNull() )
548  {
549  // label format
550  QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
551  int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
552  bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
553  method->setLabelFormat( format );
554  method->setLabelPrecision( precision );
555  method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
556  }
557  // End of backward compatibility
558  }
559  else
560  {
561  // QGIS project 3.10+
562  method = QgsClassificationMethod::create( methodElem, context );
563  }
564 
565  // apply the method
566  r->setClassificationMethod( method );
567 
568  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
569  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
570  {
571  for ( const QgsRendererRange &range : qgis::as_const( r->mRanges ) )
572  {
573  convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
574  }
575  if ( r->mSourceSymbol )
576  {
577  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
578  }
579  }
580  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
581  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
582  {
583  for ( const QgsRendererRange &range : qgis:: as_const( r->mRanges ) )
584  {
585  convertSymbolSizeScale( range.symbol(),
586  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
587  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
588  }
589  if ( r->mSourceSymbol && r->mSourceSymbol->type() == QgsSymbol::Marker )
590  {
592  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
593  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
594  }
595  }
596 
597  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
598  if ( !ddsLegendSizeElem.isNull() )
599  {
600  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
601  }
602 // TODO: symbol levels
603  return r;
604 }
605 
606 QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
607 {
608  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
609  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
610  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
611  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
612  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
613  rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
614 
615  // ranges
616  int i = 0;
618  QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
619  QgsRangeList::const_iterator it = mRanges.constBegin();
620  for ( ; it != mRanges.constEnd(); ++it )
621  {
622  const QgsRendererRange &range = *it;
623  QString symbolName = QString::number( i );
624  symbols.insert( symbolName, range.symbol() );
625 
626  QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
627  rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
628  rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
629  rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
630  rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
631  rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
632  rangesElem.appendChild( rangeElem );
633  i++;
634  }
635 
636  rendererElem.appendChild( rangesElem );
637 
638  // save symbols
639  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
640  rendererElem.appendChild( symbolsElem );
641 
642  // save source symbol
643  if ( mSourceSymbol )
644  {
645  QgsSymbolMap sourceSymbols;
646  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
647  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
648  rendererElem.appendChild( sourceSymbolElem );
649  }
650 
651  // save source color ramp
652  if ( mSourceColorRamp )
653  {
654  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
655  rendererElem.appendChild( colorRampElem );
656  }
657 
658  // save classification method
659  QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
660  rendererElem.appendChild( classificationMethodElem );
661 
662  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
663  rendererElem.appendChild( rotationElem );
664 
665  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
666  rendererElem.appendChild( sizeScaleElem );
667 
669  mPaintEffect->saveProperties( doc, rendererElem );
670 
671  if ( !mOrderBy.isEmpty() )
672  {
673  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
674  mOrderBy.save( orderBy );
675  rendererElem.appendChild( orderBy );
676  }
677  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
678 
680  {
681  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
682  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
683  rendererElem.appendChild( ddsLegendElem );
684  }
685 
686  return rendererElem;
687 }
688 
689 QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
690 {
692  int i = 0;
693  lst.reserve( mRanges.size() );
694  for ( const QgsRendererRange &range : mRanges )
695  {
696  lst << QgsLegendSymbolItem( range.symbol(), range.label(), QString::number( i++ ), true );
697  }
698  return lst;
699 }
700 
702 QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
703 {
704  switch ( mode )
705  {
706  case EqualInterval:
707  return QStringLiteral( "EqualInterval" );
708  case Quantile:
709  return QStringLiteral( "Quantile" );
710  case Jenks:
711  return QStringLiteral( "Jenks" );
712  case StdDev:
713  return QStringLiteral( "StdDev" );
714  case Pretty:
715  return QStringLiteral( "Pretty" );
716  case Custom:
717  return QString();
718  }
719  return QString();
720 }
721 
722 QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
723 {
724  if ( methodId == QLatin1String( "EqualInterval" ) )
725  return EqualInterval;
726  if ( methodId == QLatin1String( "Quantile" ) )
727  return Quantile;
728  if ( methodId == QLatin1String( "Jenks" ) )
729  return Jenks;
730  if ( methodId == QLatin1String( "StdDev" ) )
731  return StdDev;
732  if ( methodId == QLatin1String( "Pretty" ) )
733  return Pretty;
734  else
735  return Custom;
736 }
738 
740 {
742  {
743  // check that all symbols that have the same size expression
744  QgsProperty ddSize;
745  for ( const QgsRendererRange &range : mRanges )
746  {
747  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
748  if ( ddSize )
749  {
750  QgsProperty sSize( symbol->dataDefinedSize() );
751  if ( sSize && sSize != ddSize )
752  {
753  // no common size expression
754  return baseLegendSymbolItems();
755  }
756  }
757  else
758  {
759  ddSize = symbol->dataDefinedSize();
760  }
761  }
762 
763  if ( ddSize && ddSize.isActive() )
764  {
766 
768  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
769  lst += ddSizeLegend.legendSymbolList();
770 
771  lst += baseLegendSymbolItems();
772  return lst;
773  }
774  }
775 
776  return baseLegendSymbolItems();
777 }
778 
779 QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
780 {
781  QVariant value = valueForFeature( feature, context );
782 
783  // Null values should not be categorized
784  if ( value.isNull() )
785  return QSet< QString >();
786 
787  // find the right category
788  QString key = legendKeyForValue( value.toDouble() );
789  if ( !key.isNull() )
790  return QSet< QString >() << key;
791  else
792  return QSet< QString >();
793 }
794 
796 {
797  return mSourceSymbol.get();
798 }
799 
801 {
802  return mSourceSymbol.get();
803 }
804 
806 {
807  mSourceSymbol.reset( sym );
808 }
809 
811 {
812  return mSourceColorRamp.get();
813 }
814 
816 {
817  return mSourceColorRamp.get();
818 }
819 
821 {
822  if ( ramp == mSourceColorRamp.get() )
823  return;
824 
825  mSourceColorRamp.reset( ramp );
826 }
827 
829 {
830  double min = std::numeric_limits<double>::max();
831  for ( int i = 0; i < mRanges.count(); i++ )
832  {
833  double sz = 0;
834  if ( mRanges[i].symbol()->type() == QgsSymbol::Marker )
835  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
836  else if ( mRanges[i].symbol()->type() == QgsSymbol::Line )
837  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
838  min = std::min( sz, min );
839  }
840  return min;
841 }
842 
844 {
845  double max = std::numeric_limits<double>::min();
846  for ( int i = 0; i < mRanges.count(); i++ )
847  {
848  double sz = 0;
849  if ( mRanges[i].symbol()->type() == QgsSymbol::Marker )
850  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
851  else if ( mRanges[i].symbol()->type() == QgsSymbol::Line )
852  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
853  max = std::max( sz, max );
854  }
855  return max;
856 }
857 
858 void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
859 {
860  for ( int i = 0; i < mRanges.count(); i++ )
861  {
862  std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
863  const double size = mRanges.count() > 1
864  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
865  : .5 * ( maxSize + minSize );
866  if ( symbol->type() == QgsSymbol::Marker )
867  static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
868  if ( symbol->type() == QgsSymbol::Line )
869  static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
870  updateRangeSymbol( i, symbol.release() );
871  }
872 }
873 
875 {
876  int i = 0;
877  if ( ramp )
878  {
879  setSourceColorRamp( ramp );
880  }
881 
882  if ( mSourceColorRamp )
883  {
884  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
885  {
886  QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
887  if ( symbol )
888  {
889  double colorValue;
890  colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
891  symbol->setColor( mSourceColorRamp->color( colorValue ) );
892  }
893  updateRangeSymbol( i, symbol );
894  ++i;
895  }
896  }
897 
898 }
899 
901 {
902  if ( !sym )
903  return;
904 
905  int i = 0;
906  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
907  {
908  std::unique_ptr<QgsSymbol> symbol( sym->clone() );
910  {
911  symbol->setColor( range.symbol()->color() );
912  }
913  else if ( mGraduatedMethod == GraduatedSize )
914  {
915  if ( symbol->type() == QgsSymbol::Marker )
916  static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
917  static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
918  else if ( symbol->type() == QgsSymbol::Line )
919  static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
920  static_cast<QgsLineSymbol *>( range.symbol() )->width() );
921  }
922  updateRangeSymbol( i, symbol.release() );
923  ++i;
924  }
925  setSourceSymbol( sym->clone() );
926 }
927 
929 {
930  return true;
931 }
932 
934 {
935  bool ok;
936  int index = key.toInt( &ok );
937  if ( ok && index >= 0 && index < mRanges.size() )
938  return mRanges.at( index ).renderState();
939  else
940  return true;
941 }
942 
943 void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
944 {
945  bool ok;
946  int index = key.toInt( &ok );
947  if ( ok )
948  updateRangeRenderState( index, state );
949 }
950 
952 {
953  bool ok;
954  int index = key.toInt( &ok );
955  if ( ok )
956  updateRangeSymbol( index, symbol );
957  else
958  delete symbol;
959 }
960 
962 {
963  QgsSymbol *newSymbol = symbol->clone();
964  QString label = QStringLiteral( "0.0 - 0.0" );
965  mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
966 }
967 
968 void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
969 {
970  QgsSymbol *newSymbol = mSourceSymbol->clone();
971  QString label = mClassificationMethod->labelForRange( lower, upper );
972  mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
973 }
974 
976 {
977  QMutableListIterator< QgsRendererRange > it( mRanges );
978  while ( it.hasNext() )
979  {
980  QgsRendererRange range = it.next();
981  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
982  {
983  QgsRendererRange newRange = QgsRendererRange();
984  newRange.setLowerValue( breakValue );
985  newRange.setUpperValue( range.upperValue() );
986  newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
987  newRange.setSymbol( mSourceSymbol->clone() );
988 
989  //update old range
990  bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
991  range.setUpperValue( breakValue );
992  if ( isDefaultLabel )
993  range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
994  it.setValue( range );
995 
996  it.insert( newRange );
997  break;
998  }
999  }
1000 
1001  if ( updateSymbols )
1002  {
1003  switch ( mGraduatedMethod )
1004  {
1005  case GraduatedColor:
1007  break;
1008  case GraduatedSize:
1010  break;
1011  }
1012  }
1013 }
1014 
1016 {
1017  mRanges.append( range );
1018 }
1019 
1021 {
1022  mRanges.removeAt( idx );
1023 }
1024 
1026 {
1027  mRanges.clear();
1028 }
1029 
1032 {
1033  mClassificationMethod->setLabelFormat( labelFormat.format() );
1034  mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1035  mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1036 
1037  if ( updateRanges )
1038  {
1040  }
1041 }
1043 
1045 {
1046  for ( int i = 0; i < mRanges.count(); i++ )
1047  {
1049  if ( i == 0 )
1051  else if ( i == mRanges.count() - 1 )
1053  mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1054  }
1055 }
1056 
1057 
1059 {
1060  // Find the minimum size of a class
1061  double minClassRange = 0.0;
1062  for ( const QgsRendererRange &rendererRange : qgis::as_const( mRanges ) )
1063  {
1064  double range = rendererRange.upperValue() - rendererRange.lowerValue();
1065  if ( range <= 0.0 )
1066  continue;
1067  if ( minClassRange == 0.0 || range < minClassRange )
1068  minClassRange = range;
1069  }
1070  if ( minClassRange <= 0.0 )
1071  return;
1072 
1073  // Now set the number of decimal places to ensure no more than 20% error in
1074  // representing this range (up to 10% at upper and lower end)
1075 
1076  int ndp = 10;
1077  double nextDpMinRange = 0.0000000099;
1078  while ( ndp > 0 && nextDpMinRange < minClassRange )
1079  {
1080  ndp--;
1081  nextDpMinRange *= 10.0;
1082  }
1083  mClassificationMethod->setLabelPrecision( ndp );
1084  if ( updateRanges )
1086 }
1087 
1089 {
1090  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1091  return;
1092  mRanges.move( from, to );
1093 }
1094 
1096 {
1097  return r1 < r2;
1098 }
1099 
1101 {
1102  return !valueLessThan( r1, r2 );
1103 }
1104 
1105 void QgsGraduatedSymbolRenderer::sortByValue( Qt::SortOrder order )
1106 {
1107  if ( order == Qt::AscendingOrder )
1108  {
1109  std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1110  }
1111  else
1112  {
1113  std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1114  }
1115 }
1116 
1118 {
1119  QgsRangeList sortedRanges = mRanges;
1120  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1121 
1122  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1123  if ( it == sortedRanges.constEnd() )
1124  return false;
1125 
1126  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1127  return true;
1128 
1129  double prevMax = ( *it ).upperValue();
1130  ++it;
1131 
1132  for ( ; it != sortedRanges.constEnd(); ++it )
1133  {
1134  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1135  return true;
1136 
1137  if ( ( *it ).lowerValue() < prevMax )
1138  return true;
1139 
1140  prevMax = ( *it ).upperValue();
1141  }
1142  return false;
1143 }
1144 
1146 {
1147  QgsRangeList sortedRanges = mRanges;
1148  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1149 
1150  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1151  if ( it == sortedRanges.constEnd() )
1152  return false;
1153 
1154  double prevMax = ( *it ).upperValue();
1155  ++it;
1156 
1157  for ( ; it != sortedRanges.constEnd(); ++it )
1158  {
1159  if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1160  return true;
1161 
1162  prevMax = ( *it ).upperValue();
1163  }
1164  return false;
1165 }
1166 
1168 {
1169  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1170 }
1171 
1173 {
1174  return !labelLessThan( r1, r2 );
1175 }
1176 
1177 void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
1178 {
1179  if ( order == Qt::AscendingOrder )
1180  {
1181  std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1182  }
1183  else
1184  {
1185  std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1186  }
1187 }
1188 
1190 {
1191  return mClassificationMethod.get();
1192 }
1193 
1195 {
1196  mClassificationMethod.reset( method );
1197 }
1198 
1200 {
1201  QString methodId = methodIdFromMode( mode );
1203  setClassificationMethod( method );
1204 }
1205 
1207 {
1208  mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1209 }
1210 
1212 {
1213  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1214 }
1215 
1217 {
1218  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1219 }
1220 
1222 {
1223  std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1224  if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1225  {
1226  r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1227  }
1228  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1229  {
1230  const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1231  if ( categorizedSymbolRenderer )
1232  {
1233  r = qgis::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1234  r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1235  if ( categorizedSymbolRenderer->sourceColorRamp() )
1236  {
1237  bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1238  dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1239  if ( !isRandom )
1240  r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1241  }
1242  r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1243  }
1244  }
1245  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1246  {
1247  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1248  if ( pointDistanceRenderer )
1249  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1250  }
1251  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1252  {
1253  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1254  if ( invertedPolygonRenderer )
1255  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1256  }
1257 
1258  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1259  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1260 
1261  if ( !r )
1262  {
1263  r = qgis::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1264  QgsRenderContext context;
1265  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1266  if ( !symbols.isEmpty() )
1267  {
1268  r->setSourceSymbol( symbols.at( 0 )->clone() );
1269  }
1270  }
1271 
1272  r->setOrderBy( renderer->orderBy() );
1273  r->setOrderByEnabled( renderer->orderByEnabled() );
1274 
1275  return r.release();
1276 }
1277 
1279 {
1280  mDataDefinedSizeLegend.reset( settings );
1281 }
1282 
1284 {
1285  return mDataDefinedSizeLegend.get();
1286 }
1287 
1289 {
1290  switch ( method )
1291  {
1292  case GraduatedColor:
1293  return QStringLiteral( "GraduatedColor" );
1294  case GraduatedSize:
1295  return QStringLiteral( "GraduatedSize" );
1296  }
1297  return QString();
1298 }
1299 
1300 
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QgsClassificationMethod * method(const QString &id)
Returns a new instance of the method for the given id.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
The class is used as a container of context for various read/write operations on other objects...
int precision
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
double rendererScale() const
Returns the renderer map scale.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:971
static QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
std::unique_ptr< QgsSymbol > mSourceSymbol
QList< QgsRendererRange > QgsRangeList
QList< QgsClassificationRange > classes(const QgsVectorLayer *layer, const QString &expression, int nclasses)
This will calculate the classes for a given layer to define the classes.
static const QString METHOD_ID
QList< QgsLegendSymbolItem > QgsLegendSymbolList
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:533
QgsClassificationEqualInterval is an implementation of QgsClassificationMethod for equal intervals...
bool labelLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
bool updateRangeUpperValue(int rangeIndex, double value)
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
void setLabel(const QString &label)
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
QgsClassificationMethod * classificationMethod() const
Returns the classification method.
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp&#39;s settings to an XML element.
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
void setGraduatedMethod(GraduatedMethod method)
set the method used for graduation (either size or color)
void updateRangeLabels()
Updates the labels of the ranges.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Container of fields for a vector layer.
Definition: qgsfields.h:42
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:50
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:273
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
static void clearSymbolMap(QgsSymbolMap &symbols)
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:517
Line symbol.
Definition: qgssymbol.h:86
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.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
QgsClassificationCustom is a dummy implementation of QgsClassification which does not compute any bre...
An interface for classes which can visit style entity (e.g.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
std::unique_ptr< QgsExpression > mExpression
The class is not at a bound.
void setUpperValue(double upperValue)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:612
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const
Returns the label format used to generate default classification labels.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
QString label() const
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
Q_DECL_DEPRECATED void setUseSymmetricMode(bool useSymmetricMode)
Set if we want to classify symmetric around a given value.
Q_DECL_DEPRECATED double symmetryPoint() const
Returns the pivot value for symmetric classification.
double lowerValue() const
The class is at the upper bound.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
The class is at the lower bound.
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:44
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:297
QString type() const
Definition: qgsrenderer.h:130
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
bool updateRangeLowerValue(int rangeIndex, double value)
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.
void setLowerValue(double lowerValue)
bool labelGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds. ...
bool renderState() const
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes&#39; color is derived.
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static void convertSymbolSizeScale(QgsSymbol *symbol, QgsSymbol::ScaleMethod method, const QString &field)
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
QgsSymbol * symbol() const
QgsSymbol * sourceSymbol()
Returns the renderer&#39;s source symbol, which is the base symbol used for the each categories&#39; symbol b...
A store for object properties.
Definition: qgsproperty.h:229
bool valueLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
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 ...
#define SIP_DEPRECATED
Definition: qgis_sip.h:106
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols...
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
Totally random color ramp.
Definition: qgscolorramp.h:427
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1543
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
Q_DECL_DEPRECATED void setMode(Mode mode)
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
Marker symbol.
Definition: qgssymbol.h:85
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
double minSymbolSize() const
Returns the min symbol size when graduated by size.
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:711
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Contains information about the context of a rendering operation.
bool usingSymbolLevels() const
Definition: qgsrenderer.h:272
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each categories&#39; color is derived.
void setSymbol(QgsSymbol *s)
GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color)
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:93
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application&#39;s classification methods registry, used in graduated renderer.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
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.
QString dump() const override
Returns debug information about this renderer.
double upperValue() const
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props=QgsStringMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QgsGraduatedSymbolRenderer * clone() const override
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.
QMap< QString, QgsSymbol *> QgsSymbolMap
Definition: qgsrenderer.h:45
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:49
ClassPosition
Defines the class position.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
bool updateRangeRenderState(int rangeIndex, bool render)
bool valueGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
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...
bool updateRangeLabel(int rangeIndex, const QString &label)
void setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
A color ramp entity for QgsStyle databases.
Definition: qgsstyle.h:1003
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...
int mAttrNum
attribute index (derived from attribute name in startRender)
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
std::unique_ptr< QgsColorRamp > mSourceColorRamp
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
A vector of attributes.
Definition: qgsattributes.h:57
static QString graduatedMethodStr(GraduatedMethod method)
Represents a vector layer which manages a vector based data sets.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
QgsSymbol * symbolForValue(double value) const
Gets the symbol which is used to represent value.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each categories&#39; symbo...
const QgsRangeList & ranges() const
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...
QgsClassificationMethod is an abstract class for implementations of classification methods...
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
Contains information relating to the style entity currently being visited.
QgsSymbol * sourceSymbol()
Returns the renderer&#39;s source symbol, which is the base symbol used for the each classes&#39; symbol befo...
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes&#39; symbol b...
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsAttributes attributes
Definition: qgsfeature.h:65
bool isActive() const
Returns whether the property is currently active.
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:474
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.