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;
425 mLUT.emplace_back( idx );
429 mLUTInitialized =
true;
434 bool overflow =
false;
437 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
438 if ( value <= mLUTOffset )
442 else if (
static_cast< std::size_t
>( lutIndex ) >= mLUT.size() )
444 idx = colorRampItemListCount - 1;
450 else if ( lutIndex < 0 )
457 idx = mLUT[lutIndex];
465 if ( idx >= colorRampItemListCount )
467 idx = colorRampItemListCount - 1;
474 switch ( mColorRampType )
485 *returnRedValue = currentColorRampItem.
color.red();
486 *returnGreenValue = currentColorRampItem.
color.green();
487 *returnBlueValue = currentColorRampItem.
color.blue();
488 *returnAlphaValue = currentColorRampItem.
color.alpha();
494 const float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
495 const float offsetInRange = value - previousColorRampItem.
value;
496 const float scale = offsetInRange / currentRampRange;
498 const int c1Red = previousColorRampItem.
color.red();
499 const int c1Green = previousColorRampItem.
color.green();
500 const int c1Blue = previousColorRampItem.
color.blue();
501 const int c1Alpha = previousColorRampItem.
color.alpha();
503 const int c2Red = currentColorRampItem.
color.red();
504 const int c2Green = currentColorRampItem.
color.green();
505 const int c2Blue = currentColorRampItem.
color.blue();
506 const int c2Alpha = currentColorRampItem.
color.alpha();
508 *returnRedValue = c1Red +
static_cast< int >( ( c2Red - c1Red ) * scale );
509 *returnGreenValue = c1Green +
static_cast< int >( ( c2Green - c1Green ) * scale );
510 *returnBlueValue = c1Blue +
static_cast< int >( ( c2Blue - c1Blue ) * scale );
511 *returnAlphaValue = c1Alpha +
static_cast< int >( ( c2Alpha - c1Alpha ) * scale );
523 *returnRedValue = currentColorRampItem.
color.red();
524 *returnGreenValue = currentColorRampItem.
color.green();
525 *returnBlueValue = currentColorRampItem.
color.blue();
526 *returnAlphaValue = currentColorRampItem.
color.alpha();
534 *returnRedValue = currentColorRampItem.
color.red();
535 *returnGreenValue = currentColorRampItem.
color.green();
536 *returnBlueValue = currentColorRampItem.
color.blue();
537 *returnAlphaValue = currentColorRampItem.
color.alpha();
549bool QgsColorRampShader::shade(
double redValue,
double greenValue,
double blueValue,
double alphaValue,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
552 Q_UNUSED( greenValue )
553 Q_UNUSED( blueValue )
554 Q_UNUSED( alphaValue )
557 *returnGreenValue = 0;
558 *returnBlueValue = 0;
559 *returnAlphaValue = 0;
566 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
567 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
569 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
575 QDomElement colorRampShaderElem = doc.createElement( u
"colorrampshader"_s );
577 colorRampShaderElem.setAttribute( u
"classificationMode"_s,
static_cast< int >(
classificationMode() ) );
578 colorRampShaderElem.setAttribute( u
"clip"_s,
clip() );
579 colorRampShaderElem.setAttribute( u
"minimumValue"_s,
mMinimumValue );
580 colorRampShaderElem.setAttribute( u
"maximumValue"_s,
mMaximumValue );
581 colorRampShaderElem.setAttribute( u
"labelPrecision"_s,
mLabelPrecision );
587 colorRampShaderElem.appendChild( colorRampElem );
592 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
593 for ( ; itemIt != itemList.constEnd(); ++itemIt )
595 QDomElement itemElem = doc.createElement( u
"item"_s );
596 itemElem.setAttribute( u
"label"_s, itemIt->label );
598 itemElem.setAttribute( u
"color"_s, itemIt->color.name() );
599 itemElem.setAttribute( u
"alpha"_s, itemIt->color.alpha() );
600 colorRampShaderElem.appendChild( itemElem );
603 if ( mLegendSettings )
604 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
606 return colorRampShaderElem;
612 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( u
"colorramp"_s );
613 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( u
"name"_s ) ==
"[source]"_L1 )
618 setColorRampType( colorRampShaderElem.attribute( u
"colorRampType"_s, u
"INTERPOLATED"_s ) );
620 setClip( colorRampShaderElem.attribute( u
"clip"_s, u
"0"_s ) ==
"1"_L1 );
621 setMinimumValue( colorRampShaderElem.attribute( u
"minimumValue"_s ).toDouble() );
622 setMaximumValue( colorRampShaderElem.attribute( u
"maximumValue"_s ).toDouble() );
623 setLabelPrecision( colorRampShaderElem.attribute( u
"labelPrecision"_s, u
"6"_s ).toDouble() );
625 QList<QgsColorRampShader::ColorRampItem> itemList;
626 QDomElement itemElem;
631 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( u
"item"_s );
632 itemList.reserve( itemNodeList.size() );
633 for (
int i = 0; i < itemNodeList.size(); ++i )
635 itemElem = itemNodeList.at( i ).toElement();
636 itemValue = itemElem.attribute( u
"value"_s ).toDouble();
637 itemLabel = itemElem.attribute( u
"label"_s );
638 itemColor.setNamedColor( itemElem.attribute( u
"color"_s ) );
639 itemColor.setAlpha( itemElem.attribute( u
"alpha"_s, u
"255"_s ).toInt() );
645 if ( !mLegendSettings )
646 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
648 mLegendSettings->readXml( colorRampShaderElem, context );
653 return mLegendSettings.get();
658 if ( settings == mLegendSettings.get() )
660 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)