1 /***************************************************************************
2      qgspropertytransformer.h
3      ------------------------
4     Date                 : January 2017
5     Copyright            : (C) 2017 by Nyall Dawson
6     Email                : nyall dot dawson 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 QGSPROPERTYTRANSFORMER_H
16 #define QGSPROPERTYTRANSFORMER_H
17 
18 #include "qgis_core.h"
19 #include "qgsexpression.h"
20 #include "qgsexpressioncontext.h"
21 #include "qgspointxy.h"
22 #include <QVariant>
23 #include <QHash>
24 #include <QString>
25 #include <QStringList>
26 #include <QDomElement>
27 #include <QDomDocument>
28 #include <QColor>
29 #include <memory>
30 #include <algorithm>
31 
32 class QgsColorRamp;
33 
34 
35 /**
36  * \ingroup core
37  * \class QgsCurveTransform
38  * \brief Handles scaling of input values to output values by using a curve created
39  * from smoothly joining a number of set control points.
40  *
41  * QgsCurveTransform assists in creation of curve type transforms, typically seen in
42  * raster image editing software (eg the curves dialog in GIMP or Photoshop).
43  * Transforms are created by passing a number of set control points through which
44  * the transform curve must pass. The curve is guaranteed to exactly pass through
45  * these control points. Between control points the curve is smoothly interpolated
46  * so that no disjoint sections or "corners" are present.
47  *
48  * If the first or last control point are not located at x = 0 and x = 1 respectively,
49  * then values outside this range will be mapped to the y value of either the first
50  * or last control point. In other words, the curve will have a flat segment
51  * for values outside of the control point range.
52  *
53  * \since QGIS 3.0
54  */
55 
56 class CORE_EXPORT QgsCurveTransform
57 {
58   public:
59 
60     /**
61      * Constructs a default QgsCurveTransform which linearly maps values
62      * between 0 and 1 unchanged. I.e. y == x.
63      */
64     QgsCurveTransform();
65 
66     /**
67      * Constructs a QgsCurveTransform using a specified list of \a controlPoints.
68      * Behavior is undefined if duplicate x values exist in the control points
69      * list.
70      */
71     QgsCurveTransform( const QList< QgsPointXY > &controlPoints );
72 
73     ~QgsCurveTransform();
74 
75     /**
76      * Copy constructor
77      */
78     QgsCurveTransform( const QgsCurveTransform &other );
79 
80     QgsCurveTransform &operator=( const QgsCurveTransform &other );
81 
82     /**
83      * Returns a list of the control points for the transform.
84      * \see setControlPoints()
85      */
controlPoints()86     QList< QgsPointXY > controlPoints() const { return mControlPoints; }
87 
88     /**
89      * Sets the list of control points for the transform. Any existing
90      * points are removed.
91      * \see controlPoints()
92      */
93     void setControlPoints( const QList< QgsPointXY > &points );
94 
95     /**
96      * Adds a control point to the transform. Behavior is undefined if duplicate
97      * x values exist in the control points list.
98      * \see removeControlPoint()
99      */
100     void addControlPoint( double x, double y );
101 
102     /**
103      * Removes a control point from the transform. This will have no effect if a
104      * matching control point does not exist.
105      * \see addControlPoint()
106      */
107     void removeControlPoint( double x, double y );
108 
109     /**
110      * Returns the mapped y value corresponding to the specified \a x value.
111      */
112     double y( double x ) const;
113 
114     /**
115      * Returns a list of y values corresponding to a list of \a x values.
116      * Calling this method is faster then calling the double variant multiple
117      * times.
118      */
119     QVector< double > y( const QVector< double > &x ) const;
120 
121     /**
122      * Reads the curve's state from an XML element.
123      * \param elem source DOM element for transform's state
124      * \param doc DOM document
125      * \see writeXml()
126     */
127     bool readXml( const QDomElement &elem, const QDomDocument &doc );
128 
129     /**
130      * Writes the current state of the transform into an XML element
131      * \param transformElem destination element for the transform's state
132      * \param doc DOM document
133      * \see readXml()
134     */
135     bool writeXml( QDomElement &transformElem, QDomDocument &doc ) const;
136 
137     /**
138      * Saves this curve transformer to a QVariantMap, wrapped in a QVariant.
139      * You can use QgsXmlUtils::writeVariant to save it to an XML document.
140      *
141      * \see loadVariant()
142      */
143     QVariant toVariant() const;
144 
145     /**
146      * Load this curve transformer from a QVariantMap, wrapped in a QVariant.
147      * You can use QgsXmlUtils::writeVariant to load it from an XML document.
148      *
149      * \see toVariant()
150      */
151     bool loadVariant( const QVariant &transformer );
152 
153   private:
154 
155     void calcSecondDerivativeArray();
156 
157     QList< QgsPointXY > mControlPoints;
158 
159     double *mSecondDerivativeArray = nullptr;
160 };
161 
162 
163 /**
164  * \ingroup core
165  * \class QgsPropertyTransformer
166  * \brief Abstract base class for objects which transform the calculated value of a property.
167  * Possible uses include transformers which map a value into a scaled size or color from a gradient.
168  * \since QGIS 3.0
169  */
170 class CORE_EXPORT QgsPropertyTransformer
171 {
172 
173 #ifdef SIP_RUN
174     SIP_CONVERT_TO_SUBCLASS_CODE
175     if ( sipCpp->transformerType() == QgsPropertyTransformer::GenericNumericTransformer )
176       sipType = sipType_QgsGenericNumericTransformer;
177     else if ( sipCpp->transformerType() == QgsPropertyTransformer::SizeScaleTransformer )
178       sipType = sipType_QgsSizeScaleTransformer;
179     else if ( sipCpp->transformerType() == QgsPropertyTransformer::ColorRampTransformer )
180       sipType = sipType_QgsColorRampTransformer;
181     else
182       sipType = sipType_QgsPropertyTransformer;
183     SIP_END
184 #endif
185 
186   public:
187 
188     //! Transformer types
189     enum Type
190     {
191       GenericNumericTransformer, //!< Generic transformer for numeric values (QgsGenericNumericTransformer)
192       SizeScaleTransformer, //!< Size scaling transformer (QgsSizeScaleTransformer)
193       ColorRampTransformer, //!< Color ramp transformer (QgsColorRampTransformer)
194     };
195 
196     /**
197      * Factory method for creating a new property transformer of the specified type.
198      * \param type transformer type to create
199      */
200     static QgsPropertyTransformer *create( Type type ) SIP_FACTORY;
201 
202     /**
203      * Constructor for QgsPropertyTransformer
204      * \param minValue minimum expected value from source property
205      * \param maxValue maximum expected value from source property
206      */
207     QgsPropertyTransformer( double minValue = 0.0, double maxValue = 1.0 );
208 
209     /**
210      * Copy constructor.
211      */
212     QgsPropertyTransformer( const QgsPropertyTransformer &other );
213     QgsPropertyTransformer &operator=( const QgsPropertyTransformer &other );
214 
215     virtual ~QgsPropertyTransformer();
216 
217     /**
218      * Returns the transformer type.
219      */
220     virtual Type transformerType() const = 0;
221 
222     /**
223      * Returns a clone of the transformer.
224      */
225     virtual QgsPropertyTransformer *clone() const = 0 SIP_FACTORY;
226 
227     /**
228      * Loads this transformer from a QVariantMap, wrapped in a QVariant.
229      * You can use QgsXmlUtils::readVariant to read it from an XML document.
230      *
231      * \see toVariant()
232      */
233     virtual bool loadVariant( const QVariant &transformer );
234 
235     /**
236      * Saves this transformer to a QVariantMap, wrapped in a QVariant.
237      * You can use QgsXmlUtils::writeVariant to save it to an XML document.
238      *
239      * \see loadVariant()
240      */
241     virtual QVariant toVariant() const;
242 
243     /**
244      * Returns the minimum value expected by the transformer.
245      * \see maxValue()
246      * \see setMinValue()
247      */
minValue()248     double minValue() const { return mMinValue; }
249 
250     /**
251      * Sets the minimum value expected by the transformer.
252      * \param min minimum value
253      * \see setMaxValue()
254      * \see minValue()
255      */
setMinValue(double min)256     void setMinValue( double min ) { mMinValue = min; }
257 
258     /**
259      * Returns the maximum value expected by the transformer.
260      * \see minValue()
261      * \see setMaxValue()
262      */
maxValue()263     double maxValue() const { return mMaxValue; }
264 
265     /**
266      * Sets the maximum value expected by the transformer.
267      * \param max maximum value
268      * \see setMinValue()
269      * \see maxValue()
270      */
setMaxValue(double max)271     void setMaxValue( double max ) { mMaxValue = max; }
272 
273     /**
274      * Returns the curve transform applied to input values before they are transformed
275      * by the individual transform subclasses.
276      * \see setCurveTransform()
277      */
curveTransform()278     QgsCurveTransform *curveTransform() const { return mCurveTransform.get(); }
279 
280     /**
281      * Sets a curve transform to apply to input values before they are transformed
282      * by the individual transform subclasses. Ownership of \a transform is transferred
283      * to the property transformer.
284      * \see curveTransform()
285      */
setCurveTransform(QgsCurveTransform * transform SIP_TRANSFER)286     void setCurveTransform( QgsCurveTransform *transform SIP_TRANSFER ) { mCurveTransform.reset( transform ); }
287 
288     /**
289      * Calculates the transform of a value. Derived classes must implement this to perform their transformations
290      * on input values
291      * \param context expression context
292      * \param value input value to transform
293      */
294     virtual QVariant transform( const QgsExpressionContext &context, const QVariant &value ) const = 0;
295 
296     /**
297      * Converts the transformer to a QGIS expression string. The \a baseExpression string consists
298      * of a sub-expression reflecting the parent property's state.
299      */
300     virtual QString toExpression( const QString &baseExpression ) const = 0;
301 
302     /**
303      * Attempts to parse an expression into a corresponding property transformer.
304      * \param expression expression to parse
305      * \param baseExpression will be set to the component of the source expression which
306      * is used to calculate the input to the property transformer. This will be set to an
307      * empty string if a field reference is the transformer input.
308      * \param fieldName will be set to a field name which is used to calculate the input
309      * to the property transformer. This will be set to an
310      * empty string if an expression is the transformer input.
311      * \returns corresponding property transformer, or NULLPTR if expression could not
312      * be parsed to a transformer.
313      */
314     static QgsPropertyTransformer *fromExpression( const QString &expression, QString &baseExpression SIP_OUT, QString &fieldName SIP_OUT ) SIP_FACTORY;
315 
316   protected:
317 
318     /**
319      * Applies base class numeric transformations. Derived classes should call this
320      * to transform an \a input numeric value before they apply any transform to the result.
321      * This applies any curve transforms which may exist on the transformer.
322      */
323     double transformNumeric( double input ) const;
324 #ifndef SIP_RUN
325     //! Minimum value expected by the transformer
326     double mMinValue;
327 
328     //! Maximum value expected by the transformer
329     double mMaxValue;
330 
331     //! Optional curve transform
332     std::unique_ptr< QgsCurveTransform > mCurveTransform;
333 #endif
334 };
335 
336 /**
337  * \ingroup core
338  * \class QgsGenericNumericTransformer
339  * \brief QgsPropertyTransformer subclass for scaling an input numeric value into an output numeric value.
340  * \since QGIS 3.0
341  */
342 
343 class CORE_EXPORT QgsGenericNumericTransformer : public QgsPropertyTransformer
344 {
345   public:
346 
347     /**
348      * Constructor for QgsGenericNumericTransformer.
349      * \param minValue minimum expected input value
350      * \param maxValue maximum expected input value
351      * \param minOutput minimum value to return
352      * \param maxOutput maximum value to return
353      * \param nullOutput value to return for null inputs
354      * \param exponent optional exponential for non-linear scaling
355      */
356     QgsGenericNumericTransformer( double minValue = 0.0,
357                                   double maxValue = 1.0,
358                                   double minOutput = 0.0,
359                                   double maxOutput = 1.0,
360                                   double nullOutput = 0.0,
361                                   double exponent = 1.0 );
362 
transformerType()363     Type transformerType() const override { return GenericNumericTransformer; }
364     QgsGenericNumericTransformer *clone() const override SIP_FACTORY;
365     QVariant toVariant() const override;
366     bool loadVariant( const QVariant &definition ) override;
367     QVariant transform( const QgsExpressionContext &context, const QVariant &value ) const override;
368     QString toExpression( const QString &baseExpression ) const override;
369 
370     /**
371      * Attempts to parse an expression into a corresponding QgsSizeScaleTransformer.
372      * \param expression expression to parse
373      * \param baseExpression will be set to the component of the source expression which
374      * is used to calculate the input to the property transformer. This will be set to an
375      * empty string if a field reference is the transformer input.
376      * \param fieldName will be set to a field name which is used to calculate the input
377      * to the property transformer. This will be set to an
378      * empty string if an expression is the transformer input.
379      * \returns corresponding QgsSizeScaleTransformer, or NULLPTR if expression could not
380      * be parsed to a size scale transformer.
381      */
382     static QgsGenericNumericTransformer *fromExpression( const QString &expression, QString &baseExpression SIP_OUT, QString &fieldName SIP_OUT ) SIP_FACTORY;
383 
384     /**
385      * Calculates the size corresponding to a specific \a input value.
386      * \returns calculated size using size scale transformer's parameters and type
387      */
388     double value( double input ) const;
389 
390     /**
391      * Returns the minimum calculated size.
392      * \see setMinOutputValue()
393      * \see maxOutputValue()
394      */
minOutputValue()395     double minOutputValue() const { return mMinOutput; }
396 
397     /**
398      * Sets the minimum calculated size.
399      * \param size minimum size
400      * \see minOutputValue()
401      * \see setMaxOutputValue()
402      */
setMinOutputValue(double size)403     void setMinOutputValue( double size ) { mMinOutput = size; }
404 
405     /**
406      * Returns the maximum calculated size.
407      * \see minOutputValue()
408      */
maxOutputValue()409     double maxOutputValue() const { return mMaxOutput; }
410 
411     /**
412      * Sets the maximum calculated size.
413      * \param size maximum size
414      * \see maxOutputValue()
415      * \see setMinOutputValue()
416      */
setMaxOutputValue(double size)417     void setMaxOutputValue( double size ) { mMaxOutput = size; }
418 
419     /**
420      * Returns the size value when an expression evaluates to NULL.
421      * \see setNullOutputValue()
422      */
nullOutputValue()423     double nullOutputValue() const { return mNullOutput; }
424 
425     /**
426      * Sets the size value for when an expression evaluates to NULL.
427      * \param size null size
428      * \see nullOutputValue()
429      */
setNullOutputValue(double size)430     void setNullOutputValue( double size ) { mNullOutput = size; }
431 
432     /**
433      * Returns the exponent for an exponential expression.
434      * \see setExponent()
435      */
exponent()436     double exponent() const { return mExponent; }
437 
438     /**
439      * Sets the exponent for an exponential expression.
440      * \param exponent exponent
441      * \see exponent()
442      */
setExponent(double exponent)443     void setExponent( double exponent ) { mExponent = exponent; }
444 
445   private:
446     double mMinOutput;
447     double mMaxOutput;
448     double mNullOutput;
449     double mExponent;
450 
451 };
452 
453 /**
454  * \ingroup core
455  * \class QgsSizeScaleTransformer
456  * \brief QgsPropertyTransformer subclass for scaling a value into a size according to various
457  * scaling methods.
458  * \since QGIS 3.0
459  */
460 
461 class CORE_EXPORT QgsSizeScaleTransformer : public QgsPropertyTransformer
462 {
463   public:
464 
465     //! Size scaling methods
466     enum ScaleType
467     {
468       Linear, //!< Linear scaling
469       Area, //!< Area based scaling
470       Flannery, //!< Flannery scaling method
471       Exponential, //!< Scale using set exponent
472     };
473 
474     /**
475      * Constructor for QgsSizeScaleTransformer.
476      * \param type scaling type
477      * \param minValue minimum expected value
478      * \param maxValue maximum expected value
479      * \param minSize minimum size to return
480      * \param maxSize maximum size to return
481      * \param nullSize size to return for null values
482      * \param exponent exponent for Exponential scaling method
483      */
484     QgsSizeScaleTransformer( ScaleType type = Linear,
485                              double minValue = 0.0,
486                              double maxValue = 1.0,
487                              double minSize = 0.0,
488                              double maxSize = 1.0,
489                              double nullSize = 0.0,
490                              double exponent = 1.0 );
491 
transformerType()492     Type transformerType() const override { return SizeScaleTransformer; }
493     QgsSizeScaleTransformer *clone() const override SIP_FACTORY;
494     QVariant toVariant() const override;
495     bool loadVariant( const QVariant &definition ) override;
496     QVariant transform( const QgsExpressionContext &context, const QVariant &value ) const override;
497     QString toExpression( const QString &baseExpression ) const override;
498 
499     /**
500      * Attempts to parse an expression into a corresponding QgsSizeScaleTransformer.
501      * \param expression expression to parse
502      * \param baseExpression will be set to the component of the source expression which
503      * is used to calculate the input to the property transformer. This will be set to an
504      * empty string if a field reference is the transformer input.
505      * \param fieldName will be set to a field name which is used to calculate the input
506      * to the property transformer. This will be set to an
507      * empty string if an expression is the transformer input.
508      * \returns corresponding QgsSizeScaleTransformer, or NULLPTR if expression could not
509      * be parsed to a size scale transformer.
510      */
511     static QgsSizeScaleTransformer *fromExpression( const QString &expression, QString &baseExpression SIP_OUT, QString &fieldName SIP_OUT ) SIP_FACTORY;
512 
513     /**
514      * Calculates the size corresponding to a specific value.
515      * \param value value to calculate size for
516      * \returns calculated size using size scale transformer's parameters and type
517      */
518     double size( double value ) const;
519 
520     /**
521      * Returns the minimum calculated size.
522      * \see setMinSize()
523      * \see maxSize()
524      */
minSize()525     double minSize() const { return mMinSize; }
526 
527     /**
528      * Sets the minimum calculated size.
529      * \param size minimum size
530      * \see minSize()
531      * \see setMaxSize()
532      */
setMinSize(double size)533     void setMinSize( double size ) { mMinSize = size; }
534 
535     /**
536      * Returns the maximum calculated size.
537      * \see minSize()
538      */
maxSize()539     double maxSize() const { return mMaxSize; }
540 
541     /**
542      * Sets the maximum calculated size.
543      * \param size maximum size
544      * \see maxSize()
545      * \see setMinSize()
546      */
setMaxSize(double size)547     void setMaxSize( double size ) { mMaxSize = size; }
548 
549     /**
550      * Returns the size value when an expression evaluates to NULL.
551      * \see setNullSize()
552      */
nullSize()553     double nullSize() const { return mNullSize; }
554 
555     /**
556      * Sets the size value for when an expression evaluates to NULL.
557      * \param size null size
558      * \see nullSize()
559      */
setNullSize(double size)560     void setNullSize( double size ) { mNullSize = size; }
561 
562     /**
563      * Returns the exponent for an exponential expression.
564      * \see setExponent()
565      * \see type()
566      */
exponent()567     double exponent() const { return mExponent; }
568 
569     /**
570      * Sets the exponent for an exponential expression.
571      * \param exponent exponent
572      * \see exponent()
573      */
setExponent(double exponent)574     void setExponent( double exponent ) { mExponent = exponent; }
575 
576     /**
577      * Returns the size transformer's scaling type (the method used to calculate
578      * the size from a value).
579      * \see setType()
580      */
type()581     ScaleType type() const { return mType; }
582 
583     /**
584      * Sets the size transformer's scaling type (the method used to calculate
585      * the size from a value).
586      * \param type scale type
587      * \see type()
588      */
589     void setType( ScaleType type );
590 
591   private:
592     ScaleType mType = Linear;
593     double mMinSize;
594     double mMaxSize;
595     double mNullSize;
596     double mExponent;
597 
598 };
599 
600 /**
601  * \ingroup core
602  * \class QgsColorRampTransformer
603  * \brief QgsPropertyTransformer subclass for transforming a numeric value into a color from a
604  * color ramp.
605  * \since QGIS 3.0
606  */
607 
608 class CORE_EXPORT QgsColorRampTransformer : public QgsPropertyTransformer
609 {
610   public:
611 
612     /**
613      * Constructor for QgsColorRampTransformer.
614      * \param minValue minimum expected value
615      * \param maxValue maximum expected value
616      * \param ramp source color ramp. Ownership is transferred to the transformer.
617      * \param nullColor color to return for null values
618      */
619     QgsColorRampTransformer( double minValue = 0.0,
620                              double maxValue = 1.0,
621                              QgsColorRamp *ramp SIP_TRANSFER = nullptr,
622                              const QColor &nullColor = QColor( 0, 0, 0, 0 ) );
623 
624     //! Copy constructor
625     QgsColorRampTransformer( const QgsColorRampTransformer &other );
626 
627     QgsColorRampTransformer &operator=( const QgsColorRampTransformer &other );
628 
transformerType()629     Type transformerType() const override { return ColorRampTransformer; }
630     QgsColorRampTransformer *clone() const override SIP_FACTORY;
631     QVariant toVariant() const override;
632     bool loadVariant( const QVariant &definition ) override;
633     QVariant transform( const QgsExpressionContext &context, const QVariant &value ) const override;
634     QString toExpression( const QString &baseExpression ) const override;
635 
636     /**
637      * Calculates the color corresponding to a specific value.
638      * \param value value to calculate color for
639      * \returns calculated color using transformer's parameters and type
640      */
641     QColor color( double value ) const;
642 
643     /**
644      * Returns the color ramp used for calculating property colors.
645      * \returns color ramp
646      * \see setColorRamp()
647      */
648     QgsColorRamp *colorRamp() const;
649 
650     /**
651      * Sets the color ramp to use for calculating property colors.
652      * \param ramp color ramp, ownership of ramp is transferred to the transformer.
653      * \see colorRamp()
654      */
655     void setColorRamp( QgsColorRamp *ramp SIP_TRANSFER );
656 
657     /**
658      * Returns the color corresponding to a null value.
659      * \see setNullColor()
660      */
nullColor()661     QColor nullColor() const { return mNullColor; }
662 
663     /**
664      * Sets the color corresponding to a null value.
665      * \param color null color
666      * \see nullColor()
667      */
setNullColor(const QColor & color)668     void setNullColor( const QColor &color ) { mNullColor = color; }
669 
670     /**
671      * Returns the color ramp's name.
672      * \see setRampName()
673      */
rampName()674     QString rampName() const { return mRampName; }
675 
676     /**
677      * Sets the color ramp's \a name. The ramp name must be set to match
678      * a color ramp available in the style database for conversion to expression
679      * to work correctly.
680      * \see rampName()
681      */
setRampName(const QString & name)682     void setRampName( const QString &name ) { mRampName = name; }
683 
684   private:
685 
686     std::unique_ptr< QgsColorRamp > mGradientRamp;
687     QColor mNullColor;
688     QString mRampName;
689 
690 };
691 
692 #endif // QGSPROPERTYTRANSFORMER_H
693