QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsgraduatedsymbolrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgraduatedsymbolrenderer.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QDomDocument>
17 #include <QDomElement>
18 
19 #include <ctime>
20 #include <cmath>
21 
23 
24 #include "qgsattributes.h"
26 #include "qgscolorramp.h"
28 #include "qgsexpression.h"
29 #include "qgsfeature.h"
31 #include "qgslogger.h"
32 #include "qgspainteffect.h"
33 #include "qgspainteffectregistry.h"
35 #include "qgsproperty.h"
36 #include "qgssymbol.h"
37 #include "qgssymbollayer.h"
38 #include "qgssymbollayerutils.h"
39 #include "qgsvectordataprovider.h"
40 #include "qgsvectorlayer.h"
41 #include "qgsvectorlayerutils.h"
43 #include "qgsstyleentityvisitor.h"
46 #include "qgsapplication.h"
49 
50 
52  : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
53  , mAttrName( attrName )
54 {
55  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
56 
57  //important - we need a deep copy of the ranges list, not a shared copy. This is required because
58  //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
59  //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
60  const auto constRanges = ranges;
61  for ( const QgsRendererRange &range : constRanges )
62  {
63  mRanges << range;
64  }
65 
67 }
68 
70 {
71  mRanges.clear(); // should delete all the symbols
72 }
73 
74 
76 {
77  for ( const QgsRendererRange &range : mRanges )
78  {
79  if ( range.lowerValue() <= value && range.upperValue() >= value )
80  {
81  if ( range.renderState() || mCounting )
82  return &range;
83  else
84  return nullptr;
85  }
86  }
87 
88  // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
89  // if a value falls just outside of a range, but within acceptable double precision tolerance
90  // then we accept it anyway
91  for ( const QgsRendererRange &range : mRanges )
92  {
93  if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
94  {
95  if ( range.renderState() || mCounting )
96  return &range;
97  else
98  return nullptr;
99  }
100  }
101  // the value is out of the range: return NULL instead of symbol
102  return nullptr;
103 }
104 
106 {
107  if ( const QgsRendererRange *range = rangeForValue( value ) )
108  return range->symbol();
109  return nullptr;
110 }
111 
113 {
114  if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
115  {
116  int i = 0;
117  for ( const QgsRendererRange &range : mRanges )
118  {
119  if ( matchingRange == &range )
120  return QString::number( i );
121  i++;
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 ( value.isNull() )
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 : qgis::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 : qgis::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  }
322  copyRendererData( r );
323  return r;
324 }
325 
326 void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
327 {
328  QVariantMap newProps = props;
329  newProps[ QStringLiteral( "attribute" )] = mAttrName;
330  newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
331 
332  // create a Rule for each range
333  bool first = true;
334  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
335  {
336  it->toSld( doc, element, newProps, first );
337  first = false;
338  }
339 }
340 
342 {
343  Q_UNUSED( context )
344  QgsSymbolList lst;
345  lst.reserve( mRanges.count() );
346  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
347  {
348  lst.append( range.symbol() );
349  }
350  return lst;
351 }
352 
354 {
355  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
356  {
357  QgsStyleSymbolEntity entity( range.symbol() );
358  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
359  return false;
360  }
361 
362  if ( mSourceColorRamp )
363  {
365  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
366  return false;
367  }
368 
369  return true;
370 }
371 
372 void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
373 {
375 }
376 
377 QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
378 {
381  QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
382  return QgsClassificationMethod::rangesToBreaks( _classes );
383 }
384 
387  QgsVectorLayer *vlayer,
388  const QString &attrName,
389  int classes,
390  Mode mode,
391  QgsSymbol *symbol,
392  QgsColorRamp *ramp,
393  const QgsRendererRangeLabelFormat &labelFormat,
394  bool useSymmetricMode,
395  double symmetryPoint,
396  const QStringList &listForCboPrettyBreaks,
397  bool astride
398 )
399 {
400  Q_UNUSED( listForCboPrettyBreaks )
401 
404  r->setSourceSymbol( symbol->clone() );
405  r->setSourceColorRamp( ramp->clone() );
406 
407  QString methodId = methodIdFromMode( mode );
409 
410  if ( method )
411  {
413  method->setLabelFormat( labelFormat.format() );
416  }
417  r->setClassificationMethod( method );
418 
419  r->updateClasses( vlayer, classes );
420  return r;
421 }
423 
425  bool useSymmetricMode, double symmetryPoint, bool astride )
426 {
427  if ( mAttrName.isEmpty() )
428  return;
429 
430  QString methodId = methodIdFromMode( mode );
433  setClassificationMethod( method );
434 
435  updateClasses( vlayer, nclasses );
436 }
437 
439 {
441  return;
442 
443  QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
444 
446 
447  for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
448  {
450  addClass( QgsRendererRange( *it, newSymbol ) );
451  }
452  updateColorRamp( nullptr );
453 }
454 
457 {
458  return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
459 }
461 
463 {
464  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
465  if ( symbolsElem.isNull() )
466  return nullptr;
467 
468  QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
469  if ( rangesElem.isNull() )
470  return nullptr;
471 
472  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
474 
475  QDomElement rangeElem = rangesElem.firstChildElement();
476  while ( !rangeElem.isNull() )
477  {
478  if ( rangeElem.tagName() == QLatin1String( "range" ) )
479  {
480  double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
481  double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
482  QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
483  QString label = rangeElem.attribute( QStringLiteral( "label" ) );
484  bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
485  if ( symbolMap.contains( symbolName ) )
486  {
487  QgsSymbol *symbol = symbolMap.take( symbolName );
488  ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render ) );
489  }
490  }
491  rangeElem = rangeElem.nextSiblingElement();
492  }
493 
494  QString attrName = element.attribute( QStringLiteral( "attr" ) );
495 
497 
498  QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
499  if ( !attrMethod.isEmpty() )
500  {
501  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
503  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
505  }
506 
507 
508  // delete symbols if there are any more
510 
511  // try to load source symbol (optional)
512  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
513  if ( !sourceSymbolElem.isNull() )
514  {
515  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
516  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
517  {
518  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
519  }
520  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
521  }
522 
523  // try to load color ramp (optional)
524  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
525  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
526  {
527  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
528  }
529 
530  // try to load mode
531 
532  QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
533  QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
534  QgsClassificationMethod *method = nullptr;
535 
536  // TODO QGIS 4 Remove
537  // backward compatibility for QGIS project < 3.10
538  if ( !modeElem.isNull() )
539  {
540  QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
541  QString methodId;
542  // the strings saved in the project does not match with the old Mode enum
543  if ( modeString == QLatin1String( "equal" ) )
544  methodId = QStringLiteral( "EqualInterval" );
545  else if ( modeString == QLatin1String( "quantile" ) )
546  methodId = QStringLiteral( "Quantile" );
547  else if ( modeString == QLatin1String( "jenks" ) )
548  methodId = QStringLiteral( "Jenks" );
549  else if ( modeString == QLatin1String( "stddev" ) )
550  methodId = QStringLiteral( "StdDev" );
551  else if ( modeString == QLatin1String( "pretty" ) )
552  methodId = QStringLiteral( "Pretty" );
553 
555 
556  // symmetric mode
557  QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
558  if ( !symmetricModeElem.isNull() )
559  {
560  // symmetry
561  QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
562  QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
563  QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
564  method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
565  }
566  QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
567  if ( !labelFormatElem.isNull() )
568  {
569  // label format
570  QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
571  int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
572  bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
573  method->setLabelFormat( format );
574  method->setLabelPrecision( precision );
575  method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
576  }
577  // End of backward compatibility
578  }
579  else
580  {
581  // QGIS project 3.10+
582  method = QgsClassificationMethod::create( methodElem, context );
583  }
584 
585  // apply the method
586  r->setClassificationMethod( method );
587 
588  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
589  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
590  {
591  for ( const QgsRendererRange &range : qgis::as_const( r->mRanges ) )
592  {
593  convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
594  }
595  if ( r->mSourceSymbol )
596  {
597  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
598  }
599  }
600  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
601  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
602  {
603  for ( const QgsRendererRange &range : qgis:: as_const( r->mRanges ) )
604  {
605  convertSymbolSizeScale( range.symbol(),
606  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
607  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
608  }
609  if ( r->mSourceSymbol && r->mSourceSymbol->type() == QgsSymbol::Marker )
610  {
612  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
613  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
614  }
615  }
616 
617  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
618  if ( !ddsLegendSizeElem.isNull() )
619  {
620  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
621  }
622 // TODO: symbol levels
623  return r;
624 }
625 
626 QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
627 {
628  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
629  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
630  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
631  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
632  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
633  rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
634 
635  // ranges
636  int i = 0;
638  QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
639  QgsRangeList::const_iterator it = mRanges.constBegin();
640  for ( ; it != mRanges.constEnd(); ++it )
641  {
642  const QgsRendererRange &range = *it;
643  QString symbolName = QString::number( i );
644  symbols.insert( symbolName, range.symbol() );
645 
646  QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
647  rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
648  rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
649  rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
650  rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
651  rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
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  mPaintEffect->saveProperties( doc, rendererElem );
690 
691  if ( !mOrderBy.isEmpty() )
692  {
693  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
694  mOrderBy.save( orderBy );
695  rendererElem.appendChild( orderBy );
696  }
697  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
698 
700  {
701  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
702  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
703  rendererElem.appendChild( ddsLegendElem );
704  }
705 
706  return rendererElem;
707 }
708 
709 QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
710 {
712  int i = 0;
713  lst.reserve( mRanges.size() );
714  for ( const QgsRendererRange &range : mRanges )
715  {
716  lst << QgsLegendSymbolItem( range.symbol(), range.label(), QString::number( i++ ), true );
717  }
718  return lst;
719 }
720 
722 QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
723 {
724  switch ( mode )
725  {
726  case EqualInterval:
727  return QStringLiteral( "EqualInterval" );
728  case Quantile:
729  return QStringLiteral( "Quantile" );
730  case Jenks:
731  return QStringLiteral( "Jenks" );
732  case StdDev:
733  return QStringLiteral( "StdDev" );
734  case Pretty:
735  return QStringLiteral( "Pretty" );
736  case Custom:
737  return QString();
738  }
739  return QString();
740 }
741 
742 QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
743 {
744  if ( methodId == QLatin1String( "EqualInterval" ) )
745  return EqualInterval;
746  if ( methodId == QLatin1String( "Quantile" ) )
747  return Quantile;
748  if ( methodId == QLatin1String( "Jenks" ) )
749  return Jenks;
750  if ( methodId == QLatin1String( "StdDev" ) )
751  return StdDev;
752  if ( methodId == QLatin1String( "Pretty" ) )
753  return Pretty;
754  else
755  return Custom;
756 }
758 
760 {
762  {
763  // check that all symbols that have the same size expression
764  QgsProperty ddSize;
765  for ( const QgsRendererRange &range : mRanges )
766  {
767  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
768  if ( ddSize )
769  {
770  QgsProperty sSize( symbol->dataDefinedSize() );
771  if ( sSize && sSize != ddSize )
772  {
773  // no common size expression
774  return baseLegendSymbolItems();
775  }
776  }
777  else
778  {
779  ddSize = symbol->dataDefinedSize();
780  }
781  }
782 
783  if ( ddSize && ddSize.isActive() )
784  {
786 
788  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
789  lst += ddSizeLegend.legendSymbolList();
790 
791  lst += baseLegendSymbolItems();
792  return lst;
793  }
794  }
795 
796  return baseLegendSymbolItems();
797 }
798 
799 QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
800 {
801  QVariant value = valueForFeature( feature, context );
802 
803  // Null values should not be categorized
804  if ( value.isNull() )
805  return QSet< QString >();
806 
807  // find the right category
808  QString key = legendKeyForValue( value.toDouble() );
809  if ( !key.isNull() )
810  return QSet< QString >() << key;
811  else
812  return QSet< QString >();
813 }
814 
816 {
817  return mSourceSymbol.get();
818 }
819 
821 {
822  return mSourceSymbol.get();
823 }
824 
826 {
827  mSourceSymbol.reset( sym );
828 }
829 
831 {
832  return mSourceColorRamp.get();
833 }
834 
836 {
837  return mSourceColorRamp.get();
838 }
839 
841 {
842  if ( ramp == mSourceColorRamp.get() )
843  return;
844 
845  mSourceColorRamp.reset( ramp );
846 }
847 
849 {
850  double min = std::numeric_limits<double>::max();
851  for ( int i = 0; i < mRanges.count(); i++ )
852  {
853  double sz = 0;
854  if ( mRanges[i].symbol()->type() == QgsSymbol::Marker )
855  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
856  else if ( mRanges[i].symbol()->type() == QgsSymbol::Line )
857  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
858  min = std::min( sz, min );
859  }
860  return min;
861 }
862 
864 {
865  double max = std::numeric_limits<double>::min();
866  for ( int i = 0; i < mRanges.count(); i++ )
867  {
868  double sz = 0;
869  if ( mRanges[i].symbol()->type() == QgsSymbol::Marker )
870  sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
871  else if ( mRanges[i].symbol()->type() == QgsSymbol::Line )
872  sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
873  max = std::max( sz, max );
874  }
875  return max;
876 }
877 
878 void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
879 {
880  for ( int i = 0; i < mRanges.count(); i++ )
881  {
882  std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
883  const double size = mRanges.count() > 1
884  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
885  : .5 * ( maxSize + minSize );
886  if ( symbol->type() == QgsSymbol::Marker )
887  static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
888  if ( symbol->type() == QgsSymbol::Line )
889  static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
890  updateRangeSymbol( i, symbol.release() );
891  }
892 }
893 
895 {
896  int i = 0;
897  if ( ramp )
898  {
899  setSourceColorRamp( ramp );
900  }
901 
902  if ( mSourceColorRamp )
903  {
904  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
905  {
906  QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
907  if ( symbol )
908  {
909  double colorValue;
910  colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
911  symbol->setColor( mSourceColorRamp->color( colorValue ) );
912  }
913  updateRangeSymbol( i, symbol );
914  ++i;
915  }
916  }
917 
918 }
919 
921 {
922  if ( !sym )
923  return;
924 
925  int i = 0;
926  for ( const QgsRendererRange &range : qgis::as_const( mRanges ) )
927  {
928  std::unique_ptr<QgsSymbol> symbol( sym->clone() );
930  {
931  symbol->setColor( range.symbol()->color() );
932  }
933  else if ( mGraduatedMethod == GraduatedSize )
934  {
935  if ( symbol->type() == QgsSymbol::Marker )
936  static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
937  static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
938  else if ( symbol->type() == QgsSymbol::Line )
939  static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
940  static_cast<QgsLineSymbol *>( range.symbol() )->width() );
941  }
942  updateRangeSymbol( i, symbol.release() );
943  ++i;
944  }
945  setSourceSymbol( sym->clone() );
946 }
947 
949 {
950  return true;
951 }
952 
954 {
955  bool ok;
956  int index = key.toInt( &ok );
957  if ( ok && index >= 0 && index < mRanges.size() )
958  return mRanges.at( index ).renderState();
959  else
960  return true;
961 }
962 
963 void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
964 {
965  bool ok;
966  int index = key.toInt( &ok );
967  if ( ok )
968  updateRangeRenderState( index, state );
969 }
970 
972 {
973  bool ok;
974  int index = key.toInt( &ok );
975  if ( ok )
976  updateRangeSymbol( index, symbol );
977  else
978  delete symbol;
979 }
980 
982 {
983  QgsSymbol *newSymbol = symbol->clone();
984  QString label = QStringLiteral( "0.0 - 0.0" );
985  mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
986 }
987 
988 void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
989 {
990  QgsSymbol *newSymbol = mSourceSymbol->clone();
991  QString label = mClassificationMethod->labelForRange( lower, upper );
992  mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
993 }
994 
995 void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
996 {
997  QMutableListIterator< QgsRendererRange > it( mRanges );
998  while ( it.hasNext() )
999  {
1000  QgsRendererRange range = it.next();
1001  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1002  {
1003  QgsRendererRange newRange = QgsRendererRange();
1004  newRange.setLowerValue( breakValue );
1005  newRange.setUpperValue( range.upperValue() );
1006  newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1007  newRange.setSymbol( mSourceSymbol->clone() );
1008 
1009  //update old range
1010  bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1011  range.setUpperValue( breakValue );
1012  if ( isDefaultLabel )
1013  range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1014  it.setValue( range );
1015 
1016  it.insert( newRange );
1017  break;
1018  }
1019  }
1020 
1021  if ( updateSymbols )
1022  {
1023  switch ( mGraduatedMethod )
1024  {
1025  case GraduatedColor:
1027  break;
1028  case GraduatedSize:
1030  break;
1031  }
1032  }
1033 }
1034 
1036 {
1037  mRanges.append( range );
1038 }
1039 
1041 {
1042  mRanges.removeAt( idx );
1043 }
1044 
1046 {
1047  mRanges.clear();
1048 }
1049 
1052 {
1053  mClassificationMethod->setLabelFormat( labelFormat.format() );
1054  mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1055  mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1056 
1057  if ( updateRanges )
1058  {
1060  }
1061 }
1063 
1065 {
1066  for ( int i = 0; i < mRanges.count(); i++ )
1067  {
1069  if ( i == 0 )
1071  else if ( i == mRanges.count() - 1 )
1073  mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1074  }
1075 }
1076 
1078 {
1079  // Find the minimum size of a class
1080  double minClassRange = 0.0;
1081  for ( const QgsRendererRange &rendererRange : qgis::as_const( mRanges ) )
1082  {
1083  double range = rendererRange.upperValue() - rendererRange.lowerValue();
1084  if ( range <= 0.0 )
1085  continue;
1086  if ( minClassRange == 0.0 || range < minClassRange )
1087  minClassRange = range;
1088  }
1089  if ( minClassRange <= 0.0 )
1090  return;
1091 
1092  // Now set the number of decimal places to ensure no more than 20% error in
1093  // representing this range (up to 10% at upper and lower end)
1094 
1095  int ndp = 10;
1096  double nextDpMinRange = 0.0000000099;
1097  while ( ndp > 0 && nextDpMinRange < minClassRange )
1098  {
1099  ndp--;
1100  nextDpMinRange *= 10.0;
1101  }
1102  mClassificationMethod->setLabelPrecision( ndp );
1103  if ( updateRanges )
1105 }
1106 
1108 {
1109  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1110  return;
1111  mRanges.move( from, to );
1112 }
1113 
1115 {
1116  return r1 < r2;
1117 }
1118 
1120 {
1121  return !valueLessThan( r1, r2 );
1122 }
1123 
1124 void QgsGraduatedSymbolRenderer::sortByValue( Qt::SortOrder order )
1125 {
1126  if ( order == Qt::AscendingOrder )
1127  {
1128  std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1129  }
1130  else
1131  {
1132  std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1133  }
1134 }
1135 
1137 {
1138  QgsRangeList sortedRanges = mRanges;
1139  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1140 
1141  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1142  if ( it == sortedRanges.constEnd() )
1143  return false;
1144 
1145  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1146  return true;
1147 
1148  double prevMax = ( *it ).upperValue();
1149  ++it;
1150 
1151  for ( ; it != sortedRanges.constEnd(); ++it )
1152  {
1153  if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1154  return true;
1155 
1156  if ( ( *it ).lowerValue() < prevMax )
1157  return true;
1158 
1159  prevMax = ( *it ).upperValue();
1160  }
1161  return false;
1162 }
1163 
1165 {
1166  QgsRangeList sortedRanges = mRanges;
1167  std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1168 
1169  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1170  if ( it == sortedRanges.constEnd() )
1171  return false;
1172 
1173  double prevMax = ( *it ).upperValue();
1174  ++it;
1175 
1176  for ( ; it != sortedRanges.constEnd(); ++it )
1177  {
1178  if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1179  return true;
1180 
1181  prevMax = ( *it ).upperValue();
1182  }
1183  return false;
1184 }
1185 
1187 {
1188  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1189 }
1190 
1192 {
1193  return !labelLessThan( r1, r2 );
1194 }
1195 
1196 void QgsGraduatedSymbolRenderer::sortByLabel( Qt::SortOrder order )
1197 {
1198  if ( order == Qt::AscendingOrder )
1199  {
1200  std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1201  }
1202  else
1203  {
1204  std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1205  }
1206 }
1207 
1209 {
1210  return mClassificationMethod.get();
1211 }
1212 
1214 {
1215  mClassificationMethod.reset( method );
1216 }
1217 
1219 {
1220  QString methodId = methodIdFromMode( mode );
1222  setClassificationMethod( method );
1223 }
1224 
1226 {
1227  mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1228 }
1229 
1231 {
1232  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1233 }
1234 
1236 {
1237  mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1238 }
1239 
1241 {
1242  std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1243  if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1244  {
1245  r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1246  }
1247  else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1248  {
1249  const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1250  if ( categorizedSymbolRenderer )
1251  {
1252  r = qgis::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1253  if ( categorizedSymbolRenderer->sourceSymbol() )
1254  r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1255  if ( categorizedSymbolRenderer->sourceColorRamp() )
1256  {
1257  bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1258  dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1259  if ( !isRandom )
1260  r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1261  }
1262  r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1263  }
1264  }
1265  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1266  {
1267  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1268  if ( pointDistanceRenderer )
1269  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1270  }
1271  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1272  {
1273  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1274  if ( invertedPolygonRenderer )
1275  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1276  }
1277 
1278  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1279  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1280 
1281  if ( !r )
1282  {
1283  r = qgis::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1284  QgsRenderContext context;
1285  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1286  if ( !symbols.isEmpty() )
1287  {
1288  r->setSourceSymbol( symbols.at( 0 )->clone() );
1289  }
1290  }
1291 
1292  r->setOrderBy( renderer->orderBy() );
1293  r->setOrderByEnabled( renderer->orderByEnabled() );
1294 
1295  return r.release();
1296 }
1297 
1299 {
1300  mDataDefinedSizeLegend.reset( settings );
1301 }
1302 
1304 {
1305  return mDataDefinedSizeLegend.get();
1306 }
1307 
1309 {
1310  switch ( method )
1311  {
1312  case GraduatedColor:
1313  return QStringLiteral( "GraduatedColor" );
1314  case GraduatedSize:
1315  return QStringLiteral( "GraduatedSize" );
1316  }
1317  return QString();
1318 }
1319 
1320 
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
Definition: qgsattributes.h:58
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol b...
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each categories' color is derived.
QgsClassificationCustom is a dummy implementation of QgsClassification which does not compute any bre...
static const QString METHOD_ID
QgsClassificationEqualInterval is an implementation of QgsClassificationMethod for equal intervals.
QgsClassificationMethod * method(const QString &id)
Returns a new instance of the method for the given id.
QgsClassificationMethod is an abstract class for implementations of classification methods.
static void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
QList< QgsClassificationRange > classes(const QgsVectorLayer *layer, const QString &expression, int nclasses)
This will calculate the classes for a given layer to define the classes.
void setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
ClassPosition
Defines the class position.
@ LowerBound
The class is at the lower bound.
@ UpperBound
The class is at the upper bound.
@ Inner
The class is not at a bound.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
static void convertSymbolSizeScale(QgsSymbol *symbol, QgsSymbol::ScaleMethod method, const QString &field)
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:529
QString type() const
Definition: qgsrenderer.h:141
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:50
bool usingSymbolLevels() const
Definition: qgsrenderer.h:283
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:284
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:545
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:94
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
const QgsRendererRange * rangeForValue(double value) const
Returns the renderer range matching the provided value, or nullptr if no range matches the value.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color)
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
QgsGraduatedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
static Q_DECL_DEPRECATED void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
bool updateRangeLabel(int rangeIndex, const QString &label)
QgsClassificationMethod * classificationMethod() const
Returns the classification method.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
static QString graduatedMethodStr(GraduatedMethod method)
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
std::unique_ptr< QgsSymbol > mSourceSymbol
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
Q_DECL_DEPRECATED void setMode(Mode mode)
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
Q_DECL_DEPRECATED void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode=false, double symmetryPoint=0.0, bool astride=false)
Recalculate classes for a layer.
QString dump() const override
Returns debug information about this renderer.
bool updateRangeUpperValue(int rangeIndex, double value)
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
bool updateRangeLowerValue(int rangeIndex, double value)
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void updateRangeLabels()
Updates the labels of the ranges.
const QgsRangeList & ranges() const
bool updateRangeRenderState(int rangeIndex, bool render)
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
void setGraduatedMethod(GraduatedMethod method)
set the method used for graduation (either size or color)
double minSymbolSize() const
Returns the min symbol size when graduated by size.
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
int mAttrNum
attribute index (derived from attribute name in startRender)
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
std::unique_ptr< QgsExpression > mExpression
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const
Returns the label format used to generate default classification labels.
static Q_DECL_DEPRECATED QgsGraduatedSymbolRenderer * createRenderer(QgsVectorLayer *vlayer, const QString &attrName, int classes, Mode mode, QgsSymbol *symbol, QgsColorRamp *ramp, const QgsRendererRangeLabelFormat &legendFormat=QgsRendererRangeLabelFormat(), bool useSymmetricMode=false, double symmetryPoint=0.0, const QStringList &listForCboPrettyBreaks=QStringList(), bool astride=false)
Creates a new graduated renderer.
Q_DECL_DEPRECATED double symmetryPoint() const
Returns the pivot value for symmetric classification.
Q_DECL_DEPRECATED void setUseSymmetricMode(bool useSymmetricMode)
Set if we want to classify symmetric around a given value.
QgsSymbol * symbolForValue(double value) const
Gets the symbol which is used to represent value.
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Constrained random color ramp, which returns random colors based on preset parameters.
Definition: qgscolorramp.h:303
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1204
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Definition: qgssymbol.cpp:2100
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1735
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1869
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
A store for object properties.
Definition: qgsproperty.h:232
bool isActive() const
Returns whether the property is currently active.
Totally random color ramp.
Definition: qgscolorramp.h:455
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setUpperValue(double upperValue)
QString label() const
void setSymbol(QgsSymbol *s)
QgsSymbol * symbol() const
void setLabel(const QString &label)
bool renderState() const
double upperValue() const
void setLowerValue(double lowerValue)
double lowerValue() const
A color ramp entity for QgsStyle databases.
Definition: qgsstyle.h:1233
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:1201
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
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 QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
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:65
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:346
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:789
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:532
@ Line
Line symbol.
Definition: qgssymbol.h:89
@ Marker
Marker symbol.
Definition: qgssymbol.h:88
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:798
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:797
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
#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:51
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:45
QList< QgsRendererRange > QgsRangeList
int precision
Contains information relating to the style entity currently being visited.