Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsgraduatedsymbolrenderer.h
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 : : #ifndef QGSGRADUATEDSYMBOLRENDERER_H
16 : : #define QGSGRADUATEDSYMBOLRENDERER_H
17 : :
18 : : #include "qgis_core.h"
19 : : #include "qgis_sip.h"
20 : : #include "qgis.h"
21 : : #include "qgsrenderer.h"
22 : : #include "qgsrendererrange.h"
23 : : #include "qgsclassificationmethod.h"
24 : :
25 : : class QgsVectorLayer;
26 : : class QgsColorRamp;
27 : : class QgsDataDefinedSizeLegend;
28 : : class QgsSymbol;
29 : : class QgsExpression;
30 : :
31 : : /**
32 : : * \ingroup core
33 : : * \class QgsGraduatedSymbolRenderer
34 : : */
35 : : class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
36 : : {
37 : : public:
38 : :
39 : : QgsGraduatedSymbolRenderer( const QString &attrName = QString(), const QgsRangeList &ranges = QgsRangeList() );
40 : :
41 : : ~QgsGraduatedSymbolRenderer() override;
42 : :
43 : : QgsSymbol *symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
44 : : QgsSymbol *originalSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
45 : : void startRender( QgsRenderContext &context, const QgsFields &fields ) override;
46 : : void stopRender( QgsRenderContext &context ) override;
47 : : QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
48 : : bool filterNeedsGeometry() const override;
49 : : QString dump() const override;
50 : : QgsGraduatedSymbolRenderer *clone() const override SIP_FACTORY;
51 : : void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props = QVariantMap() ) const override;
52 : 0 : QgsFeatureRenderer::Capabilities capabilities() override { return SymbolLevels | Filter; }
53 : : QgsSymbolList symbols( QgsRenderContext &context ) const override;
54 : : bool accept( QgsStyleEntityVisitorInterface *visitor ) const override;
55 : :
56 : 0 : QString classAttribute() const { return mAttrName; }
57 : 0 : void setClassAttribute( const QString &attr ) { mAttrName = attr; }
58 : :
59 : 0 : const QgsRangeList &ranges() const { return mRanges; }
60 : :
61 : : bool updateRangeSymbol( int rangeIndex, QgsSymbol *symbol SIP_TRANSFER );
62 : : bool updateRangeLabel( int rangeIndex, const QString &label );
63 : : bool updateRangeUpperValue( int rangeIndex, double value );
64 : : bool updateRangeLowerValue( int rangeIndex, double value );
65 : : //! \since QGIS 2.5
66 : : bool updateRangeRenderState( int rangeIndex, bool render );
67 : :
68 : : void addClass( QgsSymbol *symbol );
69 : : //! \note available in Python bindings as addClassRange
70 : : void addClass( const QgsRendererRange &range ) SIP_PYNAME( addClassRange );
71 : : //! \note available in Python bindings as addClassLowerUpper
72 : : void addClass( double lower, double upper ) SIP_PYNAME( addClassLowerUpper );
73 : :
74 : : /**
75 : : * Add a breakpoint by splitting existing classes so that the specified
76 : : * value becomes a break between two classes.
77 : : * \param breakValue position to insert break
78 : : * \param updateSymbols set to TRUE to reapply ramp colors to the new
79 : : * symbol ranges
80 : : * \since QGIS 2.9
81 : : */
82 : : void addBreak( double breakValue, bool updateSymbols = true );
83 : :
84 : : void deleteClass( int idx );
85 : : void deleteAllClasses();
86 : :
87 : : //! Moves the category at index position from to index position to.
88 : : void moveClass( int from, int to );
89 : :
90 : : /**
91 : : * Tests whether classes assigned to the renderer have ranges which overlap.
92 : : * \returns TRUE if ranges overlap
93 : : * \since QGIS 2.10
94 : : */
95 : : bool rangesOverlap() const;
96 : :
97 : : /**
98 : : * Tests whether classes assigned to the renderer have gaps between the ranges.
99 : : * \returns TRUE if ranges have gaps
100 : : * \since QGIS 2.10
101 : : */
102 : : bool rangesHaveGaps() const;
103 : :
104 : : void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
105 : : void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
106 : :
107 : : /**
108 : : * Returns the classification method
109 : : * \since QGIS 3.10
110 : : */
111 : : QgsClassificationMethod *classificationMethod() const;
112 : :
113 : : /**
114 : : * Defines the classification method
115 : : * This will take ownership of the method
116 : : * \since QGIS 3.10
117 : : */
118 : : void setClassificationMethod( QgsClassificationMethod *method SIP_TRANSFER );
119 : :
120 : : /**
121 : : * Classification mode
122 : : * \deprecated since QGIS 3.10 use QgsClassificationMethod::MethodId instead
123 : : */
124 : : enum Mode
125 : : {
126 : : EqualInterval,
127 : : Quantile,
128 : : Jenks,
129 : : StdDev,
130 : : Pretty,
131 : : Custom
132 : : };
133 : : // TODO QGIS 4: remove
134 : : // this could not be tagged with Q_DECL_DEPRECATED due to Doxygen warning
135 : : // might be fixed in newer Doxygen (does not on 1.8.13, might be ok on 1.8.16)
136 : :
137 : :
138 : : //! \deprecated since QGIS 3.10 use classficationMethod instead
139 : : Q_DECL_DEPRECATED Mode mode() const SIP_DEPRECATED { return modeFromMethodId( mClassificationMethod->id() ); }
140 : : //! \deprecated since QGIS 3.10 use classficationMethod instead
141 : : Q_DECL_DEPRECATED void setMode( Mode mode ) SIP_DEPRECATED;
142 : :
143 : : /**
144 : : * Returns if we want to classify symmetric around a given value
145 : : * \since QGIS 3.4
146 : : * \deprecated since QGIS 3.10 use classficationMethod instead
147 : : */
148 : : Q_DECL_DEPRECATED bool useSymmetricMode() const SIP_DEPRECATED { return mClassificationMethod->symmetricModeEnabled(); }
149 : :
150 : : /**
151 : : * Set if we want to classify symmetric around a given value
152 : : * \since QGIS 3.4
153 : : * \deprecated since QGIS 3.10 use classficationMethod instead
154 : : */
155 : : Q_DECL_DEPRECATED void setUseSymmetricMode( bool useSymmetricMode ) SIP_DEPRECATED;
156 : :
157 : : /**
158 : : * Returns the pivot value for symmetric classification
159 : : * \since QGIS 3.4
160 : : * \deprecated since QGIS 3.10 use classficationMethod instead
161 : : */
162 : : Q_DECL_DEPRECATED double symmetryPoint() const SIP_DEPRECATED { return mClassificationMethod->symmetryPoint(); }
163 : :
164 : : /**
165 : : * Set the pivot point
166 : : * \since QGIS 3.4
167 : : * \deprecated since QGIS 3.10 use classficationMethod instead
168 : : */
169 : : Q_DECL_DEPRECATED void setSymmetryPoint( double symmetryPoint ) SIP_DEPRECATED;
170 : :
171 : :
172 : : /**
173 : : * Returns if we want to have a central class astride the pivot value
174 : : * \since QGIS 3.4
175 : : * \deprecated since QGIS 3.10 use classficationMethod instead
176 : : */
177 : : Q_DECL_DEPRECATED bool astride() const SIP_DEPRECATED { return mClassificationMethod->symmetryAstride(); }
178 : :
179 : : /**
180 : : * Set if we want a central class astride the pivot value
181 : : * \since QGIS 3.4
182 : : * \deprecated since QGIS 3.10 use classficationMethod instead
183 : : */
184 : : Q_DECL_DEPRECATED void setAstride( bool astride ) SIP_DEPRECATED;
185 : :
186 : : /**
187 : : * Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically balanced around symmetryPoint
188 : : * Does not put a break on the symmetryPoint. This is done before.
189 : : * \param breaks The breaks of an already-done classification
190 : : * \param symmetryPoint The point around which we want a symmetry
191 : : * \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
192 : : * \since QGIS 3.4
193 : : * \deprecated since QGIS 3.10, use QgsClassificationMethod::makeBreaksSymmetric instead
194 : : */
195 : : Q_DECL_DEPRECATED static void makeBreaksSymmetric( QList<double> &breaks SIP_INOUT, double symmetryPoint, bool astride ) SIP_DEPRECATED;
196 : :
197 : : /**
198 : : * Compute the equal interval classification
199 : : * \param minimum The minimum value of the distribution
200 : : * \param maximum The maximum value of the distribution
201 : : * \param classes The number of classes desired
202 : : * \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
203 : : * \param symmetryPoint The point around which we want a symmetry
204 : : * \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
205 : : * \deprecated since QGIS 3.10 use QgsClassificationEqualInterval class instead
206 : : */
207 : : Q_DECL_DEPRECATED static QList<double> calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride ) SIP_DEPRECATED;
208 : :
209 : : /**
210 : : * Recalculate classes for a layer
211 : : * \param vlayer The layer being rendered (from which data values are calculated)
212 : : * \param mode The calculation mode
213 : : * \param nclasses The number of classes to calculate (approximate for some modes)
214 : : * \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
215 : : * \param symmetryPoint The value around which the classes will be symmetric if useSymmetricMode is checked
216 : : * \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
217 : : * \since QGIS 2.6 (three first arguments) and 3.4 (three last arguments)
218 : : * \deprecated since QGIS 3.10
219 : : */
220 : : Q_DECL_DEPRECATED void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode = false, double symmetryPoint = 0.0, bool astride = false ) SIP_DEPRECATED;
221 : :
222 : : /**
223 : : * Recalculate classes for a layer
224 : : * \param vl The layer being rendered (from which data values are calculated)
225 : : * \param nclasses the number of classes
226 : : */
227 : : void updateClasses( const QgsVectorLayer *vl, int nclasses );
228 : :
229 : : Q_NOWARN_DEPRECATED_PUSH;
230 : :
231 : : /**
232 : : * Returns the label format used to generate default classification labels
233 : : * \since QGIS 2.6
234 : : * \deprecated since QGIS 3.10 use classificationMethod() and QgsClassificationMethod::setLabelFormat instead
235 : : */
236 : : Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const SIP_DEPRECATED;
237 : :
238 : : /**
239 : : * Set the label format used to generate default classification labels
240 : : * \param labelFormat The string appended to classification labels
241 : : * \param updateRanges If TRUE then ranges ending with the old unit string are updated to the new.
242 : : * \since QGIS 2.6
243 : : * \deprecated since QGIS 3.10 use classificationMethod() and QgsClassificationMethod::setLabelFormat instead
244 : : */
245 : : Q_DECL_DEPRECATED void setLabelFormat( const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges = false ) SIP_DEPRECATED;
246 : :
247 : : Q_NOWARN_DEPRECATED_POP;
248 : :
249 : : /**
250 : : * Reset the label decimal places to a numberbased on the minimum class interval
251 : : * \param updateRanges if TRUE then ranges currently using the default label will be updated
252 : : * \since QGIS 2.6
253 : : */
254 : : void calculateLabelPrecision( bool updateRanges = true );
255 : :
256 : : Q_NOWARN_DEPRECATED_PUSH;
257 : :
258 : : /**
259 : : * Creates a new graduated renderer.
260 : : * \param vlayer vector layer
261 : : * \param attrName attribute to classify
262 : : * \param classes number of classes
263 : : * \param mode classification mode
264 : : * \param symbol base symbol
265 : : * \param ramp color ramp for classes
266 : : * \param legendFormat
267 : : * \param useSymmetricMode A bool indicating if we want to have classes and hence colors ramp symmetric around a value
268 : : * \param symmetryPoint The value around which the classes will be symmetric if useSymmetricMode is checked
269 : : * \param listForCboPrettyBreaks The list of potential pivot values for symmetric mode with prettybreaks mode
270 : : * \param astride A bool indicating if the symmetry is made astride the symmetryPoint or not ( [-1,1] vs. [-1,0][0,1] )
271 : : * \returns new QgsGraduatedSymbolRenderer object
272 : : * \deprecated since QGIS 3.10
273 : : */
274 : : Q_DECL_DEPRECATED static QgsGraduatedSymbolRenderer *createRenderer( QgsVectorLayer *vlayer,
275 : : const QString &attrName,
276 : : int classes,
277 : : Mode mode,
278 : : QgsSymbol *symbol SIP_TRANSFER,
279 : : QgsColorRamp *ramp SIP_TRANSFER,
280 : : const QgsRendererRangeLabelFormat &legendFormat = QgsRendererRangeLabelFormat(),
281 : : bool useSymmetricMode = false,
282 : : double symmetryPoint = 0.0,
283 : : const QStringList &listForCboPrettyBreaks = QStringList(),
284 : : bool astride = false ) SIP_DEPRECATED;
285 : : Q_NOWARN_DEPRECATED_POP;
286 : :
287 : : //! create renderer from XML element
288 : : static QgsFeatureRenderer *create( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
289 : :
290 : : QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) override;
291 : : QgsLegendSymbolList legendSymbolItems() const override;
292 : : QSet< QString > legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
293 : :
294 : : /**
295 : : * Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol before applying
296 : : * the classes' color.
297 : : * \see setSourceSymbol()
298 : : * \see sourceColorRamp()
299 : : */
300 : : QgsSymbol *sourceSymbol();
301 : :
302 : : /**
303 : : * Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol before applying
304 : : * the classes' color.
305 : : * \see setSourceSymbol()
306 : : * \see sourceColorRamp()
307 : : * \note Not available in Python bindings.
308 : : */
309 : : const QgsSymbol *sourceSymbol() const SIP_SKIP;
310 : :
311 : : /**
312 : : * Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol before applying
313 : : * the classes' color.
314 : : * \param sym source symbol, ownership is transferred to the renderer
315 : : * \see sourceSymbol()
316 : : * \see setSourceColorRamp()
317 : : */
318 : : void setSourceSymbol( QgsSymbol *sym SIP_TRANSFER );
319 : :
320 : : /**
321 : : * Returns the source color ramp, from which each classes' color is derived.
322 : : * \see setSourceColorRamp()
323 : : * \see sourceSymbol()
324 : : */
325 : : QgsColorRamp *sourceColorRamp();
326 : :
327 : : /**
328 : : * Returns the source color ramp, from which each classes' color is derived.
329 : : * \see setSourceColorRamp()
330 : : * \see sourceSymbol()
331 : : * \note Not available in Python bindings.
332 : : */
333 : : const QgsColorRamp *sourceColorRamp() const SIP_SKIP;
334 : :
335 : : /**
336 : : * Sets the source color ramp.
337 : : * \param ramp color ramp. Ownership is transferred to the renderer
338 : : */
339 : : void setSourceColorRamp( QgsColorRamp *ramp SIP_TRANSFER );
340 : :
341 : : /**
342 : : * Update the color ramp used. Also updates all symbols colors.
343 : : * Doesn't alter current breaks.
344 : : * \param ramp color ramp. Ownership is transferred to the renderer
345 : : */
346 : : void updateColorRamp( QgsColorRamp *ramp SIP_TRANSFER = nullptr );
347 : :
348 : : /**
349 : : * Update all the symbols but leave breaks and colors. This method also sets the source
350 : : * symbol for the renderer.
351 : : * \param sym source symbol to use for classes. Ownership is not transferred.
352 : : * \see setSourceSymbol()
353 : : */
354 : : void updateSymbols( QgsSymbol *sym );
355 : :
356 : : /**
357 : : * set varying symbol size for classes
358 : : * \note the classes must already be set so that symbols exist
359 : : * \since QGIS 2.10
360 : : */
361 : : void setSymbolSizes( double minSize, double maxSize );
362 : :
363 : : /**
364 : : * Returns the min symbol size when graduated by size
365 : : * \since QGIS 2.10
366 : : */
367 : : double minSymbolSize() const;
368 : :
369 : : /**
370 : : * Returns the max symbol size when graduated by size
371 : : * \since QGIS 2.10
372 : : */
373 : : double maxSymbolSize() const;
374 : :
375 : : enum GraduatedMethod
376 : : {
377 : : GraduatedColor = 0,
378 : : GraduatedSize = 1
379 : : };
380 : :
381 : : /**
382 : : * Returns the method used for graduation (either size or color)
383 : : * \since QGIS 2.10
384 : : */
385 : 0 : GraduatedMethod graduatedMethod() const { return mGraduatedMethod; }
386 : :
387 : : /**
388 : : * set the method used for graduation (either size or color)
389 : : * \since QGIS 2.10
390 : : */
391 : 0 : void setGraduatedMethod( GraduatedMethod method ) { mGraduatedMethod = method; }
392 : :
393 : : bool legendSymbolItemsCheckable() const override;
394 : : bool legendSymbolItemChecked( const QString &key ) override;
395 : : void checkLegendSymbolItem( const QString &key, bool state = true ) override;
396 : : void setLegendSymbolItem( const QString &key, QgsSymbol *symbol SIP_TRANSFER ) override;
397 : 0 : QString legendClassificationAttribute() const override { return classAttribute(); }
398 : :
399 : : /**
400 : : * creates a QgsGraduatedSymbolRenderer from an existing renderer.
401 : : * \returns a new renderer if the conversion was possible, otherwise NULLPTR.
402 : : * \since QGIS 2.6
403 : : */
404 : : static QgsGraduatedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) SIP_FACTORY;
405 : :
406 : : /**
407 : : * Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
408 : : * This allows configuring for which values (symbol sizes) should be shown in the legend, whether to display
409 : : * different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
410 : : *
411 : : * When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
412 : : * Takes ownership of the passed settings objects. NULLPTR is a valid input that disables data-defined
413 : : * size legend.
414 : : * \since QGIS 3.0
415 : : */
416 : : void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
417 : :
418 : : /**
419 : : * Returns configuration of appearance of legend when using data-defined size for marker symbols.
420 : : * Will return NULLPTR if the functionality is disabled.
421 : : * \since QGIS 3.0
422 : : */
423 : : QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
424 : :
425 : : /**
426 : : * Updates the labels of the ranges
427 : : * \since QGIS 3.10
428 : : */
429 : : void updateRangeLabels();
430 : :
431 : : /**
432 : : * Returns the renderer range matching the provided \a value, or NULLPTR if no
433 : : * range matches the value.
434 : : *
435 : : * \since QGIS 3.10.1
436 : : */
437 : : const QgsRendererRange *rangeForValue( double value ) const;
438 : :
439 : : protected:
440 : : QString mAttrName;
441 : : QgsRangeList mRanges;
442 : : std::unique_ptr<QgsSymbol> mSourceSymbol;
443 : : std::unique_ptr<QgsColorRamp> mSourceColorRamp;
444 : :
445 : : std::unique_ptr<QgsExpression> mExpression;
446 : : GraduatedMethod mGraduatedMethod = GraduatedColor;
447 : : //! attribute index (derived from attribute name in startRender)
448 : :
449 : : int mAttrNum = -1;
450 : : bool mCounting = false;
451 : :
452 : : std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
453 : :
454 : : /**
455 : : * Gets the symbol which is used to represent \a value.
456 : : */
457 : : QgsSymbol *symbolForValue( double value ) const;
458 : :
459 : : /**
460 : : * Returns the matching legend key for a value.
461 : : */
462 : : QString legendKeyForValue( double value ) const;
463 : :
464 : : //! \note not available in Python bindings
465 : : static QString graduatedMethodStr( GraduatedMethod method ) SIP_SKIP;
466 : :
467 : : std::shared_ptr<QgsClassificationMethod> mClassificationMethod;
468 : :
469 : : private:
470 : :
471 : : /**
472 : : * Returns calculated value used for classifying a feature.
473 : : */
474 : : QVariant valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const;
475 : :
476 : : //! Returns list of legend symbol items from individual ranges
477 : : QgsLegendSymbolList baseLegendSymbolItems() const;
478 : :
479 : : // TODO QGIS 4: remove
480 : : Q_NOWARN_DEPRECATED_PUSH
481 : : static QString methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode );
482 : : static QgsGraduatedSymbolRenderer::Mode modeFromMethodId( const QString &methodId );
483 : : Q_NOWARN_DEPRECATED_POP
484 : :
485 : : #ifdef SIP_RUN
486 : : QgsGraduatedSymbolRenderer( const QgsGraduatedSymbolRenderer & );
487 : : QgsGraduatedSymbolRenderer &operator=( const QgsGraduatedSymbolRenderer & );
488 : : #endif
489 : :
490 : : friend class TestQgsGraduatedSymbolRenderer;
491 : :
492 : : };
493 : :
494 : : #endif // QGSGRADUATEDSYMBOLRENDERER_H
|