QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgscolorrampshader.cpp
Go to the documentation of this file.
1 /* **************************************************************************
2  qgscolorrampshader.cpp - description
3  -------------------
4 begin : Fri Dec 28 2007
5 copyright : (C) 2007 by Peter J. Ersts
6 email : [email protected]
7 
8 This class is based off of code that was originally written by Marco Hugentobler and
9 originally part of the larger QgsRasterLayer class
10 ****************************************************************************/
11 
12 /* **************************************************************************
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * *
19  ***************************************************************************/
20 
21 // Threshold for treating values as exact match.
22 // Set to 0.0 to support displaying small values (https://github.com/qgis/QGIS/issues/20706)
23 #define DOUBLE_DIFF_THRESHOLD 0.0 // 0.0000001
24 
25 #include "qgslogger.h"
26 #include "qgis.h"
27 #include "qgscolorramp.h"
28 #include "qgscolorrampshader.h"
29 #include "qgsrasterinterface.h"
30 #include "qgsrasterminmaxorigin.h"
31 #include "qgssymbollayerutils.h"
32 
33 #include <cmath>
34 QgsColorRampShader::QgsColorRampShader( double minimumValue, double maximumValue, QgsColorRamp *colorRamp, Type type, ClassificationMode classificationMode )
35  : QgsRasterShaderFunction( minimumValue, maximumValue )
36  , mColorRampType( type )
37  , mClassificationMode( classificationMode )
38 {
39  QgsDebugMsgLevel( QStringLiteral( "called." ), 4 );
40 
41  setSourceColorRamp( colorRamp );
42 }
43 
45  : QgsRasterShaderFunction( other )
46  , mColorRampType( other.mColorRampType )
47  , mClassificationMode( other.mClassificationMode )
48  , mLUT( other.mLUT )
49  , mLUTOffset( other.mLUTOffset )
50  , mLUTFactor( other.mLUTFactor )
51  , mLUTInitialized( other.mLUTInitialized )
52  , mClip( other.mClip )
53 {
54  if ( other.sourceColorRamp() )
55  mSourceColorRamp.reset( other.sourceColorRamp()->clone() );
56  mColorRampItemList = other.mColorRampItemList;
57 }
58 
60 {
61  if ( other.sourceColorRamp() )
62  mSourceColorRamp.reset( other.sourceColorRamp()->clone() );
63  else
64  mSourceColorRamp.reset();
65 
66  mColorRampType = other.mColorRampType;
67  mClassificationMode = other.mClassificationMode;
68  mLUT = other.mLUT;
69  mLUTOffset = other.mLUTOffset;
70  mLUTFactor = other.mLUTFactor;
71  mLUTInitialized = other.mLUTInitialized;
72  mClip = other.mClip;
73  mColorRampItemList = other.mColorRampItemList;
74  return *this;
75 }
76 
78 {
79  switch ( mColorRampType )
80  {
81  case Interpolated:
82  return QStringLiteral( "INTERPOLATED" );
83  case Discrete:
84  return QStringLiteral( "DISCRETE" );
85  case Exact:
86  return QStringLiteral( "EXACT" );
87  }
88  return QStringLiteral( "Unknown" );
89 }
90 
91 void QgsColorRampShader::setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem> &list )
92 {
93  mColorRampItemList = list.toVector();
94  // Reset the look up table when the color ramp is changed
95  mLUTInitialized = false;
96  mLUT.clear();
97 }
98 
100 {
101  mColorRampType = colorRampType;
102 }
103 
105 {
106  return mColorRampItemList.isEmpty();
107 }
108 
109 void QgsColorRampShader::setColorRampType( const QString &type )
110 {
111  if ( type == QLatin1String( "INTERPOLATED" ) )
112  {
113  mColorRampType = Interpolated;
114  }
115  else if ( type == QLatin1String( "DISCRETE" ) )
116  {
117  mColorRampType = Discrete;
118  }
119  else
120  {
121  mColorRampType = Exact;
122  }
123 }
124 
126 {
127  return mSourceColorRamp.get();
128 }
129 
131 {
132  mSourceColorRamp.reset( colorramp );
133 }
134 
135 void QgsColorRampShader::classifyColorRamp( const int classes, const int band, const QgsRectangle &extent, QgsRasterInterface *input )
136 {
137  if ( minimumValue() >= maximumValue() )
138  {
139  return;
140  }
141 
142  bool discrete = colorRampType() == Discrete;
143 
144  QList<double> entryValues;
145  QVector<QColor> entryColors;
146 
147  double min = minimumValue();
148  double max = maximumValue();
149 
150  if ( classificationMode() == Continuous )
151  {
152  if ( sourceColorRamp() && sourceColorRamp()->count() > 1 )
153  {
154  int numberOfEntries = sourceColorRamp()->count();
155  entryValues.reserve( numberOfEntries );
156  if ( discrete )
157  {
158  double intervalDiff = max - min;
159 
160  // remove last class when ColorRamp is gradient and discrete, as they are implemented with an extra stop
161  QgsGradientColorRamp *colorGradientRamp = dynamic_cast<QgsGradientColorRamp *>( sourceColorRamp() );
162  if ( colorGradientRamp && colorGradientRamp->isDiscrete() )
163  {
164  numberOfEntries--;
165  }
166  else
167  {
168  // if color ramp is continuous scale values to get equally distributed classes.
169  // Doesn't work perfectly when stops are non equally distributed.
170  intervalDiff *= ( numberOfEntries - 1 ) / static_cast<double>( numberOfEntries );
171  }
172 
173  // skip first value (always 0.0)
174  for ( int i = 1; i < numberOfEntries; ++i )
175  {
176  double value = sourceColorRamp()->value( i );
177  entryValues.push_back( min + value * intervalDiff );
178  }
179  entryValues.push_back( std::numeric_limits<double>::infinity() );
180  }
181  else
182  {
183  for ( int i = 0; i < numberOfEntries; ++i )
184  {
185  double value = sourceColorRamp()->value( i );
186  entryValues.push_back( min + value * ( max - min ) );
187  }
188  }
189  // for continuous mode take original color map colors
190  for ( int i = 0; i < numberOfEntries; ++i )
191  {
192  int idx = i;
193  entryColors.push_back( sourceColorRamp()->color( sourceColorRamp()->value( idx ) ) );
194  }
195  }
196  }
197  else // for other classification modes interpolate colors linearly
198  {
199  if ( classes < 2 )
200  return; // < 2 classes is not useful, shouldn't happen, but if it happens save it from crashing
201 
202  if ( classificationMode() == Quantile )
203  {
204  // Quantile
205  if ( band < 0 || !input )
206  return; // quantile classificationr requires a valid band, minMaxOrigin, and input
207 
208  double cut1 = std::numeric_limits<double>::quiet_NaN();
209  double cut2 = std::numeric_limits<double>::quiet_NaN();
210  int sampleSize = 250000;
211 
212  // set min and max from histogram, used later to calculate number of decimals to display
213  input->cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
214 
215  entryValues.reserve( classes );
216  if ( discrete )
217  {
218  double intervalDiff = 1.0 / ( classes );
219  for ( int i = 1; i < classes; ++i )
220  {
221  input->cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
222  entryValues.push_back( cut2 );
223  }
224  entryValues.push_back( std::numeric_limits<double>::infinity() );
225  }
226  else
227  {
228  double intervalDiff = 1.0 / ( classes - 1 );
229  for ( int i = 0; i < classes; ++i )
230  {
231  input->cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
232  entryValues.push_back( cut2 );
233  }
234  }
235  }
236  else // EqualInterval
237  {
238  entryValues.reserve( classes );
239  if ( discrete )
240  {
241  // in discrete mode the lowest value is not an entry and the highest
242  // value is inf, there are ( numberOfEntries ) of which the first
243  // and last are not used.
244  double intervalDiff = ( max - min ) / ( classes );
245 
246  for ( int i = 1; i < classes; ++i )
247  {
248  entryValues.push_back( min + i * intervalDiff );
249  }
250  entryValues.push_back( std::numeric_limits<double>::infinity() );
251  }
252  else
253  {
254  //because the highest value is also an entry, there are (numberOfEntries - 1) intervals
255  double intervalDiff = ( max - min ) / ( classes - 1 );
256 
257  for ( int i = 0; i < classes; ++i )
258  {
259  entryValues.push_back( min + i * intervalDiff );
260  }
261  }
262  }
263 
264  if ( !sourceColorRamp() || sourceColorRamp()->count() == 1 )
265  {
266  //hard code color range from blue -> red (previous default)
267  int colorDiff = 0;
268  if ( classes != 0 )
269  {
270  colorDiff = ( int )( 255 / classes );
271  }
272 
273  entryColors.reserve( classes );
274  for ( int i = 0; i < classes; ++i )
275  {
276  QColor currentColor;
277  int idx = i;
278  currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
279  entryColors.push_back( currentColor );
280  }
281  }
282  else
283  {
284  entryColors.reserve( classes );
285  for ( int i = 0; i < classes; ++i )
286  {
287  int idx = i;
288  entryColors.push_back( sourceColorRamp()->color( ( ( double ) idx ) / ( classes - 1 ) ) );
289  }
290  }
291  }
292 
293  QList<double>::const_iterator value_it = entryValues.constBegin();
294  QVector<QColor>::const_iterator color_it = entryColors.constBegin();
295 
296  // calculate a reasonable number of decimals to display
297  double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
298  int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
299 
300  QList<QgsColorRampShader::ColorRampItem> colorRampItems;
301  for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
302  {
303  QgsColorRampShader::ColorRampItem newColorRampItem;
304  newColorRampItem.value = *value_it;
305  newColorRampItem.color = *color_it;
306  newColorRampItem.label = QString::number( *value_it, 'g', nDecimals );
307  colorRampItems.append( newColorRampItem );
308  }
309 
310  std::sort( colorRampItems.begin(), colorRampItems.end() );
311  setColorRampItemList( colorRampItems );
312 }
313 
314 void QgsColorRampShader::classifyColorRamp( const int band, const QgsRectangle &extent, QgsRasterInterface *input )
315 {
316  classifyColorRamp( colorRampItemList().count(), band, extent, input );
317 }
318 
319 bool QgsColorRampShader::shade( double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue ) const
320 {
321  if ( mColorRampItemList.isEmpty() )
322  {
323  return false;
324  }
325  if ( std::isnan( value ) || std::isinf( value ) )
326  return false;
327 
328  int colorRampItemListCount = mColorRampItemList.count();
329  const QgsColorRampShader::ColorRampItem *colorRampItems = mColorRampItemList.constData();
330  int idx;
331  if ( !mLUTInitialized )
332  {
333  // calculate LUT for faster index recovery
334  mLUTFactor = 1.0;
335  double minimumValue = colorRampItems[0].value;
336  mLUTOffset = minimumValue + DOUBLE_DIFF_THRESHOLD;
337  // Only make lut if at least 3 items, with 2 items the low and high cases handle both
338  if ( colorRampItemListCount >= 3 )
339  {
340  double rangeValue = colorRampItems[colorRampItemListCount - 2].value - minimumValue;
341  if ( rangeValue > 0 )
342  {
343  int lutSize = 256; // TODO: test if speed can be increased with a different LUT size
344  mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue; // decrease slightly to make sure last LUT category is correct
345  idx = 0;
346  double val;
347  mLUT.reserve( lutSize );
348  for ( int i = 0; i < lutSize; i++ )
349  {
350  val = ( i / mLUTFactor ) + mLUTOffset;
351  while ( idx < colorRampItemListCount
352  && colorRampItems[idx].value - DOUBLE_DIFF_THRESHOLD < val )
353  {
354  idx++;
355  }
356  mLUT.push_back( idx );
357  }
358  }
359  }
360  mLUTInitialized = true;
361  }
362 
363  // overflow indicates that value > maximum value + DOUBLE_DIFF_THRESHOLD
364  // that way idx can point to the last valid item
365  bool overflow = false;
366 
367  // find index of the first ColorRampItem that is equal or higher to theValue
368  int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
369  if ( value < mLUTOffset )
370  {
371  idx = 0;
372  }
373  else if ( lutIndex >= mLUT.count() )
374  {
375  idx = colorRampItemListCount - 1;
376  if ( colorRampItems[idx].value + DOUBLE_DIFF_THRESHOLD < value )
377  {
378  overflow = true;
379  }
380  }
381  else if ( lutIndex < 0 )
382  {
383  return false;
384  }
385  else
386  {
387  // get initial value from LUT
388  idx = mLUT.at( lutIndex );
389 
390  // check if it's correct and if not increase until correct
391  // the LUT is made in such a way the index is always correct or too low, never too high
392  while ( idx < colorRampItemListCount && colorRampItems[idx].value + DOUBLE_DIFF_THRESHOLD < value )
393  {
394  idx++;
395  }
396  if ( idx >= colorRampItemListCount )
397  {
398  idx = colorRampItemListCount - 1;
399  overflow = true;
400  }
401  }
402 
403  const QgsColorRampShader::ColorRampItem &currentColorRampItem = colorRampItems[idx];
404 
405  if ( colorRampType() == Interpolated )
406  {
407  // Interpolate the color between two class breaks linearly.
408  if ( idx < 1 || overflow || currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD <= value )
409  {
410  if ( mClip && ( overflow
411  || currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD > value ) )
412  {
413  return false;
414  }
415  *returnRedValue = currentColorRampItem.color.red();
416  *returnGreenValue = currentColorRampItem.color.green();
417  *returnBlueValue = currentColorRampItem.color.blue();
418  *returnAlphaValue = currentColorRampItem.color.alpha();
419  return true;
420  }
421 
422  const QgsColorRampShader::ColorRampItem &previousColorRampItem = colorRampItems[idx - 1];
423 
424  float currentRampRange = currentColorRampItem.value - previousColorRampItem.value;
425  float offsetInRange = value - previousColorRampItem.value;
426  float scale = offsetInRange / currentRampRange;
427  const QRgb c1 = previousColorRampItem.color.rgba();
428  const QRgb c2 = currentColorRampItem.color.rgba();
429 
430  *returnRedValue = qRed( c1 ) + static_cast< int >( ( qRed( c2 ) - qRed( c1 ) ) * scale );
431  *returnGreenValue = qGreen( c1 ) + static_cast< int >( ( qGreen( c2 ) - qGreen( c1 ) ) * scale );
432  *returnBlueValue = qBlue( c1 ) + static_cast< int >( ( qBlue( c2 ) - qBlue( c1 ) ) * scale );
433  *returnAlphaValue = qAlpha( c1 ) + static_cast< int >( ( qAlpha( c2 ) - qAlpha( c1 ) ) * scale );
434  return true;
435  }
436  else if ( colorRampType() == Discrete )
437  {
438  // Assign the color of the higher class for every pixel between two class breaks.
439  // NOTE: The implementation has always been different than the documentation,
440  // which said lower class before, see https://github.com/qgis/QGIS/issues/22009
441  if ( overflow )
442  {
443  return false;
444  }
445  *returnRedValue = currentColorRampItem.color.red();
446  *returnGreenValue = currentColorRampItem.color.green();
447  *returnBlueValue = currentColorRampItem.color.blue();
448  *returnAlphaValue = currentColorRampItem.color.alpha();
449  return true;
450  }
451  else // EXACT
452  {
453  // Assign the color of the exact matching value in the color ramp item list
454  if ( !overflow && currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD <= value )
455  {
456  *returnRedValue = currentColorRampItem.color.red();
457  *returnGreenValue = currentColorRampItem.color.green();
458  *returnBlueValue = currentColorRampItem.color.blue();
459  *returnAlphaValue = currentColorRampItem.color.alpha();
460  return true;
461  }
462  else
463  {
464  return false;
465  }
466  }
467 }
468 
469 bool QgsColorRampShader::shade( double redValue, double greenValue,
470  double blueValue, double alphaValue,
471  int *returnRedValue, int *returnGreenValue,
472  int *returnBlueValue, int *returnAlphaValue ) const
473 {
474  Q_UNUSED( redValue )
475  Q_UNUSED( greenValue )
476  Q_UNUSED( blueValue )
477  Q_UNUSED( alphaValue )
478 
479  *returnRedValue = 0;
480  *returnGreenValue = 0;
481  *returnBlueValue = 0;
482  *returnAlphaValue = 0;
483 
484  return false;
485 }
486 
487 void QgsColorRampShader::legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems ) const
488 {
489  QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
490  for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
491  {
492  symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
493  }
494 }
495 
496 QDomElement QgsColorRampShader::writeXml( QDomDocument &doc ) const
497 {
498  QDomElement colorRampShaderElem = doc.createElement( QStringLiteral( "colorrampshader" ) );
499  colorRampShaderElem.setAttribute( QStringLiteral( "colorRampType" ), colorRampTypeAsQString() );
500  colorRampShaderElem.setAttribute( QStringLiteral( "classificationMode" ), classificationMode() );
501  colorRampShaderElem.setAttribute( QStringLiteral( "clip" ), clip() );
502 
503  // save source color ramp
504  if ( sourceColorRamp() )
505  {
506  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), sourceColorRamp(), doc );
507  colorRampShaderElem.appendChild( colorRampElem );
508  }
509 
510  //items
511  QList<QgsColorRampShader::ColorRampItem> itemList = colorRampItemList();
512  QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
513  for ( ; itemIt != itemList.constEnd(); ++itemIt )
514  {
515  QDomElement itemElem = doc.createElement( QStringLiteral( "item" ) );
516  itemElem.setAttribute( QStringLiteral( "label" ), itemIt->label );
517  itemElem.setAttribute( QStringLiteral( "value" ), QgsRasterBlock::printValue( itemIt->value ) );
518  itemElem.setAttribute( QStringLiteral( "color" ), itemIt->color.name() );
519  itemElem.setAttribute( QStringLiteral( "alpha" ), itemIt->color.alpha() );
520  colorRampShaderElem.appendChild( itemElem );
521  }
522  return colorRampShaderElem;
523 }
524 
525 void QgsColorRampShader::readXml( const QDomElement &colorRampShaderElem )
526 {
527  // try to load color ramp (optional)
528  QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral( "colorramp" ) );
529  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
530  {
531  setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
532  }
533 
534  setColorRampType( colorRampShaderElem.attribute( QStringLiteral( "colorRampType" ), QStringLiteral( "INTERPOLATED" ) ) );
535  setClassificationMode( static_cast< QgsColorRampShader::ClassificationMode >( colorRampShaderElem.attribute( QStringLiteral( "classificationMode" ), QStringLiteral( "1" ) ).toInt() ) );
536  setClip( colorRampShaderElem.attribute( QStringLiteral( "clip" ), QStringLiteral( "0" ) ) == QLatin1String( "1" ) );
537 
538  QList<QgsColorRampShader::ColorRampItem> itemList;
539  QDomElement itemElem;
540  QString itemLabel;
541  double itemValue;
542  QColor itemColor;
543 
544  QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral( "item" ) );
545  itemList.reserve( itemNodeList.size() );
546  for ( int i = 0; i < itemNodeList.size(); ++i )
547  {
548  itemElem = itemNodeList.at( i ).toElement();
549  itemValue = itemElem.attribute( QStringLiteral( "value" ) ).toDouble();
550  itemLabel = itemElem.attribute( QStringLiteral( "label" ) );
551  itemColor.setNamedColor( itemElem.attribute( QStringLiteral( "color" ) ) );
552  itemColor.setAlpha( itemElem.attribute( QStringLiteral( "alpha" ), QStringLiteral( "255" ) ).toInt() );
553 
554  itemList.push_back( QgsColorRampShader::ColorRampItem( itemValue, itemColor, itemLabel ) );
555  }
556  setColorRampItemList( itemList );
557 }
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates and new RGB value based on one input value.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
static QString printValue(double value)
Print double value with all necessary significant digits.
Uses quantile (i.e. equal pixel) count.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
QDomElement writeXml(QDomDocument &doc) const
Writes configuration to a new DOM element.
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp&#39;s settings to an XML element.
QString colorRampTypeAsQString() const
Returns the color ramp type as a string.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
QgsColorRampShader & operator=(const QgsColorRampShader &other)
Assignment operator.
double maximumValue() const
Returns the minimum value for the raster shader.
void setClip(bool clip)
Sets whether the shader should not render values out of range.
virtual void cumulativeCut(int bandNo, double lowerCount, double upperCount, double &lowerValue, double &upperValue, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Find values for cumulative pixel count cut.
Type
Supported methods for color interpolation.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
The raster shade function applies a shader to a pixel at render time - typically used to render grays...
virtual double value(int index) const =0
Returns relative value between [0,1] of color at specified index.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Returns legend symbology items if provided by renderer.
void readXml(const QDomElement &elem)
Reads configuration from the given DOM element.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
Definition: qgscolorramp.h:202
virtual int count() const =0
Returns number of defined colors, or -1 if undefined.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
double minimumValue() const
Returns the maximum value for the raster shader.
Base class for processing filters like renderers, reprojector, resampler etc.
void classifyColorRamp(int classes=0, int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
Type colorRampType() const
Returns the color ramp type.
Assigns the color of the exact matching value in the color ramp item list.
Uses breaks from color palette.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
Source color ramp.
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
bool clip() const
Returns whether the shader will clip values which are out of range.
#define DOUBLE_DIFF_THRESHOLD
Interpolates the color between two class breaks linearly.
ClassificationMode
Classification modes used to create the color ramp shader.
bool isEmpty() const
Whether the color ramp contains any items.
Assigns the color of the higher class for every pixel between two class breaks.
ClassificationMode classificationMode() const
Returns the classification mode.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
QgsColorRampShader(double minimumValue=0.0, double maximumValue=255.0, QgsColorRamp *colorRamp=nullptr, Type type=Interpolated, ClassificationMode classificationMode=Continuous)
Creates a new color ramp shader.