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 if ( mColorRampItemList.isEmpty() )
386 if ( std::isnan( value ) || std::isinf( value ) )
389 const int colorRampItemListCount = mColorRampItemList.count();
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;
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 QRgb c1 = previousColorRampItem.
color.rgba();
492 const QRgb c2 = currentColorRampItem.
color.rgba();
494 *returnRedValue = qRed( c1 ) +
static_cast< int >( ( qRed( c2 ) - qRed( c1 ) ) * scale );
495 *returnGreenValue = qGreen( c1 ) +
static_cast< int >( ( qGreen( c2 ) - qGreen( c1 ) ) * scale );
496 *returnBlueValue = qBlue( c1 ) +
static_cast< int >( ( qBlue( c2 ) - qBlue( c1 ) ) * scale );
497 *returnAlphaValue = qAlpha( c1 ) +
static_cast< int >( ( qAlpha( c2 ) - qAlpha( c1 ) ) * scale );
509 *returnRedValue = currentColorRampItem.
color.red();
510 *returnGreenValue = currentColorRampItem.
color.green();
511 *returnBlueValue = currentColorRampItem.
color.blue();
512 *returnAlphaValue = currentColorRampItem.
color.alpha();
520 *returnRedValue = currentColorRampItem.
color.red();
521 *returnGreenValue = currentColorRampItem.
color.green();
522 *returnBlueValue = currentColorRampItem.
color.blue();
523 *returnAlphaValue = currentColorRampItem.
color.alpha();
536 double blueValue,
double alphaValue,
537 int *returnRedValue,
int *returnGreenValue,
538 int *returnBlueValue,
int *returnAlphaValue )
const
541 Q_UNUSED( greenValue )
542 Q_UNUSED( blueValue )
543 Q_UNUSED( alphaValue )
546 *returnGreenValue = 0;
547 *returnBlueValue = 0;
548 *returnAlphaValue = 0;
555 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
556 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
558 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
564 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral(
"colorrampshader" ) );
566 colorRampShaderElem.setAttribute( QStringLiteral(
"classificationMode" ),
static_cast< int >(
classificationMode() ) );
567 colorRampShaderElem.setAttribute( QStringLiteral(
"clip" ),
clip() );
568 colorRampShaderElem.setAttribute( QStringLiteral(
"minimumValue" ),
mMinimumValue );
569 colorRampShaderElem.setAttribute( QStringLiteral(
"maximumValue" ),
mMaximumValue );
570 colorRampShaderElem.setAttribute( QStringLiteral(
"labelPrecision" ),
mLabelPrecision );
576 colorRampShaderElem.appendChild( colorRampElem );
581 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
582 for ( ; itemIt != itemList.constEnd(); ++itemIt )
584 QDomElement itemElem = doc.createElement( QStringLiteral(
"item" ) );
585 itemElem.setAttribute( QStringLiteral(
"label" ), itemIt->label );
587 itemElem.setAttribute( QStringLiteral(
"color" ), itemIt->color.name() );
588 itemElem.setAttribute( QStringLiteral(
"alpha" ), itemIt->color.alpha() );
589 colorRampShaderElem.appendChild( itemElem );
592 if ( mLegendSettings )
593 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
595 return colorRampShaderElem;
601 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral(
"colorramp" ) );
602 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
607 setColorRampType( colorRampShaderElem.attribute( QStringLiteral(
"colorRampType" ), QStringLiteral(
"INTERPOLATED" ) ) );
609 setClip( colorRampShaderElem.attribute( QStringLiteral(
"clip" ), QStringLiteral(
"0" ) ) == QLatin1String(
"1" ) );
610 setMinimumValue( colorRampShaderElem.attribute( QStringLiteral(
"minimumValue" ) ).toDouble() );
611 setMaximumValue( colorRampShaderElem.attribute( QStringLiteral(
"maximumValue" ) ).toDouble() );
612 setLabelPrecision( colorRampShaderElem.attribute( QStringLiteral(
"labelPrecision" ), QStringLiteral(
"6" ) ).toDouble() );
614 QList<QgsColorRampShader::ColorRampItem> itemList;
615 QDomElement itemElem;
620 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral(
"item" ) );
621 itemList.reserve( itemNodeList.size() );
622 for (
int i = 0; i < itemNodeList.size(); ++i )
624 itemElem = itemNodeList.at( i ).toElement();
625 itemValue = itemElem.attribute( QStringLiteral(
"value" ) ).toDouble();
626 itemLabel = itemElem.attribute( QStringLiteral(
"label" ) );
627 itemColor.setNamedColor( itemElem.attribute( QStringLiteral(
"color" ) ) );
628 itemColor.setAlpha( itemElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt() );
634 if ( !mLegendSettings )
635 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
637 mLegendSettings->readXml( colorRampShaderElem, context );
642 return mLegendSettings.get();
647 if ( settings == mLegendSettings.get() )
649 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)
Assignment operator.
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)