23#define DOUBLE_DIFF_THRESHOLD 0.0
37 , mColorRampType( type )
38 , mClassificationMode( classificationMode )
50 , mColorRampType( other.mColorRampType )
51 , mClassificationMode( other.mClassificationMode )
53 , mLUTOffset( other.mLUTOffset )
54 , mLUTFactor( other.mLUTFactor )
55 , mLUTInitialized( other.mLUTInitialized )
56 , mClip( other.mClip )
61 mColorRampItemList = other.mColorRampItemList;
66 QgsRasterShaderFunction::operator=( other );
72 mColorRampType = other.mColorRampType;
73 mClassificationMode = other.mClassificationMode;
75 mLUTOffset = other.mLUTOffset;
76 mLUTFactor = other.mLUTFactor;
77 mLUTInitialized = other.mLUTInitialized;
79 mColorRampItemList = other.mColorRampItemList;
86 switch ( mColorRampType )
89 return QStringLiteral(
"INTERPOLATED" );
91 return QStringLiteral(
"DISCRETE" );
93 return QStringLiteral(
"EXACT" );
95 return QStringLiteral(
"Unknown" );
100 mColorRampItemList = list.toVector();
102 mLUTInitialized =
false;
113 return mColorRampItemList.isEmpty();
118 if ( type == QLatin1String(
"INTERPOLATED" ) )
122 else if ( type == QLatin1String(
"DISCRETE" ) )
139 std::unique_ptr<QgsGradientColorRamp> ramp = std::make_unique< QgsGradientColorRamp >();
140 const int count = mColorRampItemList.size();
143 const QColor none( 0, 0, 0, 0 );
144 ramp->setColor1( none );
145 ramp->setColor2( none );
147 else if ( count == 1 )
149 ramp->setColor1( mColorRampItemList[0].color );
150 ramp->setColor2( mColorRampItemList[0].color );
158 for (
int i = 0; i < count; i++ )
160 const double offset = ( mColorRampItemList[i].value - min ) / ( max - min );
163 ramp->setColor1( mColorRampItemList[i].color );
167 else if ( i == count - 1 )
169 ramp->setColor2( mColorRampItemList[i].color );
175 ramp->setStops( stops );
178 return ramp.release();
193 QList<double> entryValues;
194 QVector<QColor> entryColors;
203 entryValues.push_back( min );
205 entryValues.push_back( std::numeric_limits<double>::infinity() );
206 for (
int i = 0; i < entryValues.size(); ++i )
215 entryValues.reserve( numberOfEntries );
218 double intervalDiff = max - min;
222 if ( colorGradientRamp && colorGradientRamp->
isDiscrete() )
230 intervalDiff *= ( numberOfEntries - 1 ) /
static_cast<double>( numberOfEntries );
234 for (
int i = 1; i < numberOfEntries; ++i )
237 entryValues.push_back( min + value * intervalDiff );
239 entryValues.push_back( std::numeric_limits<double>::infinity() );
243 for (
int i = 0; i < numberOfEntries; ++i )
246 entryValues.push_back( min + value * ( max - min ) );
250 for (
int i = 0; i < numberOfEntries; ++i )
265 if ( band < 0 || !input )
268 double cut1 = std::numeric_limits<double>::quiet_NaN();
269 double cut2 = std::numeric_limits<double>::quiet_NaN();
271 const int sampleSize = 250000 * 10;
274 input->
cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
276 entryValues.reserve( classes );
279 const double intervalDiff = 1.0 / ( classes );
280 for (
int i = 1; i < classes; ++i )
282 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
283 entryValues.push_back( cut2 );
285 entryValues.push_back( std::numeric_limits<double>::infinity() );
289 const double intervalDiff = 1.0 / ( classes - 1 );
290 for (
int i = 0; i < classes; ++i )
292 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
293 entryValues.push_back( cut2 );
299 entryValues.reserve( classes );
305 const double intervalDiff = ( max - min ) / ( classes );
307 for (
int i = 1; i < classes; ++i )
309 entryValues.push_back( min + i * intervalDiff );
311 entryValues.push_back( std::numeric_limits<double>::infinity() );
316 const double intervalDiff = ( max - min ) / ( classes - 1 );
318 for (
int i = 0; i < classes; ++i )
320 entryValues.push_back( min + i * intervalDiff );
331 colorDiff = ( int )( 255 / classes );
334 entryColors.reserve( classes );
335 for (
int i = 0; i < classes; ++i )
339 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
340 entryColors.push_back( currentColor );
345 entryColors.reserve( classes );
346 for (
int i = 0; i < classes; ++i )
354 QList<double>::const_iterator value_it = entryValues.constBegin();
355 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
358 const double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
359 const int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
361 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
362 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
365 newColorRampItem.
value = *value_it;
366 newColorRampItem.
color = *color_it;
367 newColorRampItem.
label = QString::number( *value_it,
'g', nDecimals );
368 colorRampItems.append( newColorRampItem );
371 std::sort( colorRampItems.begin(), colorRampItems.end() );
380bool QgsColorRampShader::shade(
double value,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
382 const int colorRampItemListCount = mColorRampItemList.count();
383 if ( colorRampItemListCount == 0 )
387 if ( std::isnan( value ) || std::isinf( value ) )
392 if ( !mLUTInitialized )
399 if ( colorRampItemListCount >= 3 )
401 const double rangeValue = colorRampItems[colorRampItemListCount - 2].
value -
minimumValue;
402 if ( rangeValue > 0 )
404 const int lutSize = 256;
405 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue;
408 mLUT.reserve( lutSize );
409 for (
int i = 0; i < lutSize; i++ )
411 val = ( i / mLUTFactor ) + mLUTOffset;
412 while ( idx < colorRampItemListCount
417 mLUT.emplace_back( idx );
421 mLUTInitialized =
true;
426 bool overflow =
false;
429 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
430 if ( value <= mLUTOffset )
434 else if (
static_cast< std::size_t
>( lutIndex ) >= mLUT.size() )
436 idx = colorRampItemListCount - 1;
442 else if ( lutIndex < 0 )
449 idx = mLUT[ lutIndex ];
457 if ( idx >= colorRampItemListCount )
459 idx = colorRampItemListCount - 1;
466 switch ( mColorRampType )
473 if ( mClip && ( overflow
478 *returnRedValue = currentColorRampItem.
color.red();
479 *returnGreenValue = currentColorRampItem.
color.green();
480 *returnBlueValue = currentColorRampItem.
color.blue();
481 *returnAlphaValue = currentColorRampItem.
color.alpha();
487 const float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
488 const float offsetInRange = value - previousColorRampItem.
value;
489 const float scale = offsetInRange / currentRampRange;
491 const int c1Red = previousColorRampItem.
color.red();
492 const int c1Green = previousColorRampItem.
color.green();
493 const int c1Blue = previousColorRampItem.
color.blue();
494 const int c1Alpha = previousColorRampItem.
color.alpha();
496 const int c2Red = currentColorRampItem.
color.red();
497 const int c2Green = currentColorRampItem.
color.green();
498 const int c2Blue = currentColorRampItem.
color.blue();
499 const int c2Alpha = currentColorRampItem.
color.alpha();
501 *returnRedValue = c1Red +
static_cast< int >( ( c2Red - c1Red ) * scale );
502 *returnGreenValue = c1Green +
static_cast< int >( ( c2Green - c1Green ) * scale );
503 *returnBlueValue = c1Blue +
static_cast< int >( ( c2Blue - c1Blue ) * scale );
504 *returnAlphaValue = c1Alpha +
static_cast< int >( ( c2Alpha - c1Alpha ) * scale );
516 *returnRedValue = currentColorRampItem.
color.red();
517 *returnGreenValue = currentColorRampItem.
color.green();
518 *returnBlueValue = currentColorRampItem.
color.blue();
519 *returnAlphaValue = currentColorRampItem.
color.alpha();
527 *returnRedValue = currentColorRampItem.
color.red();
528 *returnGreenValue = currentColorRampItem.
color.green();
529 *returnBlueValue = currentColorRampItem.
color.blue();
530 *returnAlphaValue = currentColorRampItem.
color.alpha();
543 double blueValue,
double alphaValue,
544 int *returnRedValue,
int *returnGreenValue,
545 int *returnBlueValue,
int *returnAlphaValue )
const
548 Q_UNUSED( greenValue )
549 Q_UNUSED( blueValue )
550 Q_UNUSED( alphaValue )
553 *returnGreenValue = 0;
554 *returnBlueValue = 0;
555 *returnAlphaValue = 0;
562 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
563 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
565 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
571 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral(
"colorrampshader" ) );
573 colorRampShaderElem.setAttribute( QStringLiteral(
"classificationMode" ),
static_cast< int >(
classificationMode() ) );
574 colorRampShaderElem.setAttribute( QStringLiteral(
"clip" ),
clip() );
575 colorRampShaderElem.setAttribute( QStringLiteral(
"minimumValue" ),
mMinimumValue );
576 colorRampShaderElem.setAttribute( QStringLiteral(
"maximumValue" ),
mMaximumValue );
577 colorRampShaderElem.setAttribute( QStringLiteral(
"labelPrecision" ),
mLabelPrecision );
583 colorRampShaderElem.appendChild( colorRampElem );
588 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
589 for ( ; itemIt != itemList.constEnd(); ++itemIt )
591 QDomElement itemElem = doc.createElement( QStringLiteral(
"item" ) );
592 itemElem.setAttribute( QStringLiteral(
"label" ), itemIt->label );
594 itemElem.setAttribute( QStringLiteral(
"color" ), itemIt->color.name() );
595 itemElem.setAttribute( QStringLiteral(
"alpha" ), itemIt->color.alpha() );
596 colorRampShaderElem.appendChild( itemElem );
599 if ( mLegendSettings )
600 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
602 return colorRampShaderElem;
608 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral(
"colorramp" ) );
609 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
614 setColorRampType( colorRampShaderElem.attribute( QStringLiteral(
"colorRampType" ), QStringLiteral(
"INTERPOLATED" ) ) );
616 setClip( colorRampShaderElem.attribute( QStringLiteral(
"clip" ), QStringLiteral(
"0" ) ) == QLatin1String(
"1" ) );
617 setMinimumValue( colorRampShaderElem.attribute( QStringLiteral(
"minimumValue" ) ).toDouble() );
618 setMaximumValue( colorRampShaderElem.attribute( QStringLiteral(
"maximumValue" ) ).toDouble() );
619 setLabelPrecision( colorRampShaderElem.attribute( QStringLiteral(
"labelPrecision" ), QStringLiteral(
"6" ) ).toDouble() );
621 QList<QgsColorRampShader::ColorRampItem> itemList;
622 QDomElement itemElem;
627 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral(
"item" ) );
628 itemList.reserve( itemNodeList.size() );
629 for (
int i = 0; i < itemNodeList.size(); ++i )
631 itemElem = itemNodeList.at( i ).toElement();
632 itemValue = itemElem.attribute( QStringLiteral(
"value" ) ).toDouble();
633 itemLabel = itemElem.attribute( QStringLiteral(
"label" ) );
634 itemColor.setNamedColor( itemElem.attribute( QStringLiteral(
"color" ) ) );
635 itemColor.setAlpha( itemElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt() );
641 if ( !mLegendSettings )
642 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
644 mLegendSettings->readXml( colorRampShaderElem, context );
649 return mLegendSettings.get();
654 if ( settings == mLegendSettings.get() )
656 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.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
~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 QColor color(double value) const =0
Returns the color corresponding to a specified value.
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.
The raster shade function applies a shader to a pixel at render time - typically used to render grays...
double mMinimumValue
User defineable minimum value for the shading function.
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.
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QDomElement saveColorRamp(const QString &name, 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)