23#define DOUBLE_DIFF_THRESHOLD 0.0
39using namespace Qt::StringLiterals;
43 , mColorRampType( type )
56 , mColorRampType( other.mColorRampType )
57 , mClassificationMode( other.mClassificationMode )
59 , mLUTOffset( other.mLUTOffset )
60 , mLUTFactor( other.mLUTFactor )
61 , mLUTInitialized( other.mLUTInitialized )
62 , mClip( other.mClip )
67 mColorRampItemList = other.mColorRampItemList;
75 QgsRasterShaderFunction::operator=( other );
81 mColorRampType = other.mColorRampType;
82 mClassificationMode = other.mClassificationMode;
84 mLUTOffset = other.mLUTOffset;
85 mLUTFactor = other.mLUTFactor;
86 mLUTInitialized = other.mLUTInitialized;
88 mColorRampItemList = other.mColorRampItemList;
95 switch ( mColorRampType )
98 return u
"INTERPOLATED"_s;
100 return u
"DISCRETE"_s;
109 mColorRampItemList = list.toVector();
111 mLUTInitialized =
false;
122 return mColorRampItemList.isEmpty();
127 if ( type ==
"INTERPOLATED"_L1 )
131 else if ( type ==
"DISCRETE"_L1 )
148 auto ramp = std::make_unique< QgsGradientColorRamp >();
149 const int count = mColorRampItemList.size();
152 const QColor none( 0, 0, 0, 0 );
153 ramp->setColor1( none );
154 ramp->setColor2( none );
156 else if ( count == 1 )
158 ramp->setColor1( mColorRampItemList[0].color );
159 ramp->setColor2( mColorRampItemList[0].color );
167 for (
int i = 0; i < count; i++ )
169 const double offset = ( mColorRampItemList[i].value - min ) / ( max - min );
172 ramp->setColor1( mColorRampItemList[i].color );
176 else if ( i == count - 1 )
178 ramp->setColor2( mColorRampItemList[i].color );
184 ramp->setStops( stops );
187 return ramp.release();
202 QList<double> entryValues;
203 QVector<QColor> entryColors;
212 entryValues.push_back( min );
214 entryValues.push_back( std::numeric_limits<double>::infinity() );
215 for (
int i = 0; i < entryValues.size(); ++i )
224 entryValues.reserve( numberOfEntries );
227 double intervalDiff = max - min;
231 if ( colorGradientRamp && colorGradientRamp->
isDiscrete() )
239 intervalDiff *= ( numberOfEntries - 1 ) /
static_cast<double>( numberOfEntries );
243 for (
int i = 1; i < numberOfEntries; ++i )
246 entryValues.push_back( min + value * intervalDiff );
248 entryValues.push_back( std::numeric_limits<double>::infinity() );
252 for (
int i = 0; i < numberOfEntries; ++i )
255 entryValues.push_back( min + value * ( max - min ) );
259 for (
int i = 0; i < numberOfEntries; ++i )
274 if ( band < 0 || !input )
277 double cut1 = std::numeric_limits<double>::quiet_NaN();
278 double cut2 = std::numeric_limits<double>::quiet_NaN();
280 const int sampleSize = 250000 * 10;
283 input->
cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
285 entryValues.reserve( classes );
288 const double intervalDiff = 1.0 / ( classes );
289 for (
int i = 1; i < classes; ++i )
291 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
292 entryValues.push_back( cut2 );
294 entryValues.push_back( std::numeric_limits<double>::infinity() );
298 const double intervalDiff = 1.0 / ( classes - 1 );
299 for (
int i = 0; i < classes; ++i )
301 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
302 entryValues.push_back( cut2 );
308 entryValues.reserve( classes );
314 const double intervalDiff = ( max - min ) / ( classes );
316 for (
int i = 1; i < classes; ++i )
318 entryValues.push_back( min + i * intervalDiff );
320 entryValues.push_back( std::numeric_limits<double>::infinity() );
325 const double intervalDiff = ( max - min ) / ( classes - 1 );
327 for (
int i = 0; i < classes; ++i )
329 entryValues.push_back( min + i * intervalDiff );
340 colorDiff = ( int )( 255 / classes );
343 entryColors.reserve( classes );
344 for (
int i = 0; i < classes; ++i )
348 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
349 entryColors.push_back( currentColor );
354 entryColors.reserve( classes );
355 for (
int i = 0; i < classes; ++i )
358 entryColors.push_back(
sourceColorRamp()->color( ( (
double ) idx ) / ( classes - 1 ) ) );
363 QList<double>::const_iterator value_it = entryValues.constBegin();
364 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
367 const double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
368 const int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
370 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
371 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
374 newColorRampItem.
value = *value_it;
375 newColorRampItem.
color = *color_it;
376 newColorRampItem.
label = QString::number( *value_it,
'g', nDecimals );
377 colorRampItems.append( newColorRampItem );
380 std::sort( colorRampItems.begin(), colorRampItems.end() );
389bool QgsColorRampShader::shade(
double value,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
391 const int colorRampItemListCount = mColorRampItemList.count();
392 if ( colorRampItemListCount == 0 )
396 if ( std::isnan( value ) || std::isinf( value ) )
401 if ( !mLUTInitialized )
408 if ( colorRampItemListCount >= 3 )
410 const double rangeValue = colorRampItems[colorRampItemListCount - 2].
value -
minimumValue;
411 if ( rangeValue > 0 )
413 const int lutSize = 256;
414 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue;
417 mLUT.reserve( lutSize );
418 for (
int i = 0; i < lutSize; i++ )
420 val = ( i / mLUTFactor ) + mLUTOffset;
421 while ( idx < colorRampItemListCount
426 mLUT.emplace_back( idx );
430 mLUTInitialized =
true;
435 bool overflow =
false;
438 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
439 if ( value <= mLUTOffset )
443 else if (
static_cast< std::size_t
>( lutIndex ) >= mLUT.size() )
445 idx = colorRampItemListCount - 1;
451 else if ( lutIndex < 0 )
458 idx = mLUT[ lutIndex ];
466 if ( idx >= colorRampItemListCount )
468 idx = colorRampItemListCount - 1;
475 switch ( mColorRampType )
482 if ( mClip && ( overflow
487 *returnRedValue = currentColorRampItem.
color.red();
488 *returnGreenValue = currentColorRampItem.
color.green();
489 *returnBlueValue = currentColorRampItem.
color.blue();
490 *returnAlphaValue = currentColorRampItem.
color.alpha();
496 const float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
497 const float offsetInRange = value - previousColorRampItem.
value;
498 const float scale = offsetInRange / currentRampRange;
500 const int c1Red = previousColorRampItem.
color.red();
501 const int c1Green = previousColorRampItem.
color.green();
502 const int c1Blue = previousColorRampItem.
color.blue();
503 const int c1Alpha = previousColorRampItem.
color.alpha();
505 const int c2Red = currentColorRampItem.
color.red();
506 const int c2Green = currentColorRampItem.
color.green();
507 const int c2Blue = currentColorRampItem.
color.blue();
508 const int c2Alpha = currentColorRampItem.
color.alpha();
510 *returnRedValue = c1Red +
static_cast< int >( ( c2Red - c1Red ) * scale );
511 *returnGreenValue = c1Green +
static_cast< int >( ( c2Green - c1Green ) * scale );
512 *returnBlueValue = c1Blue +
static_cast< int >( ( c2Blue - c1Blue ) * scale );
513 *returnAlphaValue = c1Alpha +
static_cast< int >( ( c2Alpha - c1Alpha ) * scale );
525 *returnRedValue = currentColorRampItem.
color.red();
526 *returnGreenValue = currentColorRampItem.
color.green();
527 *returnBlueValue = currentColorRampItem.
color.blue();
528 *returnAlphaValue = currentColorRampItem.
color.alpha();
536 *returnRedValue = currentColorRampItem.
color.red();
537 *returnGreenValue = currentColorRampItem.
color.green();
538 *returnBlueValue = currentColorRampItem.
color.blue();
539 *returnAlphaValue = currentColorRampItem.
color.alpha();
552 double blueValue,
double alphaValue,
553 int *returnRedValue,
int *returnGreenValue,
554 int *returnBlueValue,
int *returnAlphaValue )
const
557 Q_UNUSED( greenValue )
558 Q_UNUSED( blueValue )
559 Q_UNUSED( alphaValue )
562 *returnGreenValue = 0;
563 *returnBlueValue = 0;
564 *returnAlphaValue = 0;
571 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
572 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
574 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
580 QDomElement colorRampShaderElem = doc.createElement( u
"colorrampshader"_s );
582 colorRampShaderElem.setAttribute( u
"classificationMode"_s,
static_cast< int >(
classificationMode() ) );
583 colorRampShaderElem.setAttribute( u
"clip"_s,
clip() );
584 colorRampShaderElem.setAttribute( u
"minimumValue"_s,
mMinimumValue );
585 colorRampShaderElem.setAttribute( u
"maximumValue"_s,
mMaximumValue );
586 colorRampShaderElem.setAttribute( u
"labelPrecision"_s,
mLabelPrecision );
592 colorRampShaderElem.appendChild( colorRampElem );
597 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
598 for ( ; itemIt != itemList.constEnd(); ++itemIt )
600 QDomElement itemElem = doc.createElement( u
"item"_s );
601 itemElem.setAttribute( u
"label"_s, itemIt->label );
603 itemElem.setAttribute( u
"color"_s, itemIt->color.name() );
604 itemElem.setAttribute( u
"alpha"_s, itemIt->color.alpha() );
605 colorRampShaderElem.appendChild( itemElem );
608 if ( mLegendSettings )
609 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
611 return colorRampShaderElem;
617 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( u
"colorramp"_s );
618 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( u
"name"_s ) ==
"[source]"_L1 )
623 setColorRampType( colorRampShaderElem.attribute( u
"colorRampType"_s, u
"INTERPOLATED"_s ) );
625 setClip( colorRampShaderElem.attribute( u
"clip"_s, u
"0"_s ) ==
"1"_L1 );
626 setMinimumValue( colorRampShaderElem.attribute( u
"minimumValue"_s ).toDouble() );
627 setMaximumValue( colorRampShaderElem.attribute( u
"maximumValue"_s ).toDouble() );
628 setLabelPrecision( colorRampShaderElem.attribute( u
"labelPrecision"_s, u
"6"_s ).toDouble() );
630 QList<QgsColorRampShader::ColorRampItem> itemList;
631 QDomElement itemElem;
636 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( u
"item"_s );
637 itemList.reserve( itemNodeList.size() );
638 for (
int i = 0; i < itemNodeList.size(); ++i )
640 itemElem = itemNodeList.at( i ).toElement();
641 itemValue = itemElem.attribute( u
"value"_s ).toDouble();
642 itemLabel = itemElem.attribute( u
"label"_s );
643 itemColor.setNamedColor( itemElem.attribute( u
"color"_s ) );
644 itemColor.setAlpha( itemElem.attribute( u
"alpha"_s, u
"255"_s ).toInt() );
650 if ( !mLegendSettings )
651 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
653 mLegendSettings->readXml( colorRampShaderElem, context );
658 return mLegendSettings.get();
663 if ( settings == mLegendSettings.get() )
665 mLegendSettings.reset( settings );
ShaderInterpolationMethod
Color ramp shader interpolation methods.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
@ Linear
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
ShaderClassificationMethod
Color ramp shader classification methods.
@ Continuous
Uses breaks from color palette.
@ Quantile
Uses quantile (i.e. equal pixel) count.
Settings for a color ramp legend node.
~QgsColorRampShader() override
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Returns legend symbology items if provided by renderer.
Qgis::ShaderClassificationMethod classificationMode() const
Returns the classification mode.
Qgis::ShaderInterpolationMethod colorRampType() const
Returns the color ramp interpolation method.
const QgsColorRampLegendNodeSettings * legendSettings() const
Returns the color ramp shader legend settings.
bool isEmpty() const
Whether the color ramp contains any items.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
void setClassificationMode(Qgis::ShaderClassificationMethod classificationMode)
Sets the classification mode.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom color map.
QgsColorRampShader & operator=(const QgsColorRampShader &other)
void setClip(bool clip)
Sets whether the shader should not render values out of range.
bool clip() const
Returns whether the shader will clip values which are out of range.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes configuration to a new DOM element.
bool shade(double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue) const override
Generates an new RGBA value based on one input value.
QgsColorRamp * sourceColorRamp() const
Returns the source color ramp.
QgsColorRamp * createColorRamp() const
Creates a gradient color ramp from shader settings.
void classifyColorRamp(int classes=0, int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
void setColorRampType(Qgis::ShaderInterpolationMethod colorRampType)
Sets the color ramp interpolation method.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom color map.
QString colorRampTypeAsQString() const
Returns the color ramp type as a string.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads configuration from the given DOM element.
QgsColorRampShader(double minimumValue=0.0, double maximumValue=255.0, QgsColorRamp *colorRamp=nullptr, Qgis::ShaderInterpolationMethod type=Qgis::ShaderInterpolationMethod::Linear, Qgis::ShaderClassificationMethod classificationMode=Qgis::ShaderClassificationMethod::Continuous)
Creates a new color ramp shader.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
Source color ramp.
void setLegendSettings(QgsColorRampLegendNodeSettings *settings)
Sets the color ramp shader legend settings.
Abstract base class for color ramps.
virtual int count() const =0
Returns number of defined colors, or -1 if undefined.
virtual double value(int index) const =0
Returns relative value between [0,1] of color at specified index.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
Represents a color stop within a QgsGradientColorRamp color ramp.
static QString printValue(double value, bool localized=false)
Print double value with all necessary significant digits.
Base class for processing filters like renderers, reprojector, resampler etc.
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.
double mMinimumValue
User defineable minimum value for the shading function.
QgsRasterShaderFunction(double minimumValue=0.0, double maximumValue=255.0)
double maximumValue() const
Returns the minimum value for the raster shader.
double mMaximumValue
User defineable maximum value for the shading function.
void setLabelPrecision(int labelPrecision)
Sets label precision to labelPrecision.
virtual void setMaximumValue(double value)
Sets the maximum value for the raster shader.
virtual void setMinimumValue(double value)
Sets the minimum value for the raster shader.
int mLabelPrecision
Label precision.
double minimumValue() const
Returns the maximum value for the raster shader.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
QList< QgsGradientStop > QgsGradientStopsList
List of gradient stops.
#define DOUBLE_DIFF_THRESHOLD
#define QgsDebugMsgLevel(str, level)