23#define DOUBLE_DIFF_THRESHOLD 0.0
39 , mColorRampType( type )
52 , mColorRampType( other.mColorRampType )
53 , mClassificationMode( other.mClassificationMode )
55 , mLUTOffset( other.mLUTOffset )
56 , mLUTFactor( other.mLUTFactor )
57 , mLUTInitialized( other.mLUTInitialized )
58 , mClip( other.mClip )
63 mColorRampItemList = other.mColorRampItemList;
71 QgsRasterShaderFunction::operator=( other );
77 mColorRampType = other.mColorRampType;
78 mClassificationMode = other.mClassificationMode;
80 mLUTOffset = other.mLUTOffset;
81 mLUTFactor = other.mLUTFactor;
82 mLUTInitialized = other.mLUTInitialized;
84 mColorRampItemList = other.mColorRampItemList;
91 switch ( mColorRampType )
94 return QStringLiteral(
"INTERPOLATED" );
96 return QStringLiteral(
"DISCRETE" );
98 return QStringLiteral(
"EXACT" );
100 return QStringLiteral(
"Unknown" );
105 mColorRampItemList = list.toVector();
107 mLUTInitialized =
false;
118 return mColorRampItemList.isEmpty();
123 if ( type == QLatin1String(
"INTERPOLATED" ) )
127 else if ( type == QLatin1String(
"DISCRETE" ) )
144 auto ramp = std::make_unique< QgsGradientColorRamp >();
145 const int count = mColorRampItemList.size();
148 const QColor none( 0, 0, 0, 0 );
149 ramp->setColor1( none );
150 ramp->setColor2( none );
152 else if ( count == 1 )
154 ramp->setColor1( mColorRampItemList[0].color );
155 ramp->setColor2( mColorRampItemList[0].color );
163 for (
int i = 0; i < count; i++ )
165 const double offset = ( mColorRampItemList[i].value - min ) / ( max - min );
168 ramp->setColor1( mColorRampItemList[i].color );
172 else if ( i == count - 1 )
174 ramp->setColor2( mColorRampItemList[i].color );
180 ramp->setStops( stops );
183 return ramp.release();
198 QList<double> entryValues;
199 QVector<QColor> entryColors;
208 entryValues.push_back( min );
210 entryValues.push_back( std::numeric_limits<double>::infinity() );
211 for (
int i = 0; i < entryValues.size(); ++i )
220 entryValues.reserve( numberOfEntries );
223 double intervalDiff = max - min;
227 if ( colorGradientRamp && colorGradientRamp->
isDiscrete() )
235 intervalDiff *= ( numberOfEntries - 1 ) /
static_cast<double>( numberOfEntries );
239 for (
int i = 1; i < numberOfEntries; ++i )
242 entryValues.push_back( min + value * intervalDiff );
244 entryValues.push_back( std::numeric_limits<double>::infinity() );
248 for (
int i = 0; i < numberOfEntries; ++i )
251 entryValues.push_back( min + value * ( max - min ) );
255 for (
int i = 0; i < numberOfEntries; ++i )
270 if ( band < 0 || !input )
273 double cut1 = std::numeric_limits<double>::quiet_NaN();
274 double cut2 = std::numeric_limits<double>::quiet_NaN();
276 const int sampleSize = 250000 * 10;
279 input->
cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
281 entryValues.reserve( classes );
284 const double intervalDiff = 1.0 / ( classes );
285 for (
int i = 1; i < classes; ++i )
287 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
288 entryValues.push_back( cut2 );
290 entryValues.push_back( std::numeric_limits<double>::infinity() );
294 const double intervalDiff = 1.0 / ( classes - 1 );
295 for (
int i = 0; i < classes; ++i )
297 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
298 entryValues.push_back( cut2 );
304 entryValues.reserve( classes );
310 const double intervalDiff = ( max - min ) / ( classes );
312 for (
int i = 1; i < classes; ++i )
314 entryValues.push_back( min + i * intervalDiff );
316 entryValues.push_back( std::numeric_limits<double>::infinity() );
321 const double intervalDiff = ( max - min ) / ( classes - 1 );
323 for (
int i = 0; i < classes; ++i )
325 entryValues.push_back( min + i * intervalDiff );
336 colorDiff = ( int )( 255 / classes );
339 entryColors.reserve( classes );
340 for (
int i = 0; i < classes; ++i )
344 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
345 entryColors.push_back( currentColor );
350 entryColors.reserve( classes );
351 for (
int i = 0; i < classes; ++i )
354 entryColors.push_back(
sourceColorRamp()->color( ( (
double ) idx ) / ( classes - 1 ) ) );
359 QList<double>::const_iterator value_it = entryValues.constBegin();
360 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
363 const double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
364 const int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
366 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
367 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
370 newColorRampItem.
value = *value_it;
371 newColorRampItem.
color = *color_it;
372 newColorRampItem.
label = QString::number( *value_it,
'g', nDecimals );
373 colorRampItems.append( newColorRampItem );
376 std::sort( colorRampItems.begin(), colorRampItems.end() );
385bool QgsColorRampShader::shade(
double value,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
387 const int colorRampItemListCount = mColorRampItemList.count();
388 if ( colorRampItemListCount == 0 )
392 if ( std::isnan( value ) || std::isinf( value ) )
397 if ( !mLUTInitialized )
404 if ( colorRampItemListCount >= 3 )
406 const double rangeValue = colorRampItems[colorRampItemListCount - 2].
value -
minimumValue;
407 if ( rangeValue > 0 )
409 const int lutSize = 256;
410 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue;
413 mLUT.reserve( lutSize );
414 for (
int i = 0; i < lutSize; i++ )
416 val = ( i / mLUTFactor ) + mLUTOffset;
417 while ( idx < colorRampItemListCount
422 mLUT.emplace_back( idx );
426 mLUTInitialized =
true;
431 bool overflow =
false;
434 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
435 if ( value <= mLUTOffset )
439 else if (
static_cast< std::size_t
>( lutIndex ) >= mLUT.size() )
441 idx = colorRampItemListCount - 1;
447 else if ( lutIndex < 0 )
454 idx = mLUT[ lutIndex ];
462 if ( idx >= colorRampItemListCount )
464 idx = colorRampItemListCount - 1;
471 switch ( mColorRampType )
478 if ( mClip && ( overflow
483 *returnRedValue = currentColorRampItem.
color.red();
484 *returnGreenValue = currentColorRampItem.
color.green();
485 *returnBlueValue = currentColorRampItem.
color.blue();
486 *returnAlphaValue = currentColorRampItem.
color.alpha();
492 const float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
493 const float offsetInRange = value - previousColorRampItem.
value;
494 const float scale = offsetInRange / currentRampRange;
496 const int c1Red = previousColorRampItem.
color.red();
497 const int c1Green = previousColorRampItem.
color.green();
498 const int c1Blue = previousColorRampItem.
color.blue();
499 const int c1Alpha = previousColorRampItem.
color.alpha();
501 const int c2Red = currentColorRampItem.
color.red();
502 const int c2Green = currentColorRampItem.
color.green();
503 const int c2Blue = currentColorRampItem.
color.blue();
504 const int c2Alpha = currentColorRampItem.
color.alpha();
506 *returnRedValue = c1Red +
static_cast< int >( ( c2Red - c1Red ) * scale );
507 *returnGreenValue = c1Green +
static_cast< int >( ( c2Green - c1Green ) * scale );
508 *returnBlueValue = c1Blue +
static_cast< int >( ( c2Blue - c1Blue ) * scale );
509 *returnAlphaValue = c1Alpha +
static_cast< int >( ( c2Alpha - c1Alpha ) * scale );
521 *returnRedValue = currentColorRampItem.
color.red();
522 *returnGreenValue = currentColorRampItem.
color.green();
523 *returnBlueValue = currentColorRampItem.
color.blue();
524 *returnAlphaValue = currentColorRampItem.
color.alpha();
532 *returnRedValue = currentColorRampItem.
color.red();
533 *returnGreenValue = currentColorRampItem.
color.green();
534 *returnBlueValue = currentColorRampItem.
color.blue();
535 *returnAlphaValue = currentColorRampItem.
color.alpha();
548 double blueValue,
double alphaValue,
549 int *returnRedValue,
int *returnGreenValue,
550 int *returnBlueValue,
int *returnAlphaValue )
const
553 Q_UNUSED( greenValue )
554 Q_UNUSED( blueValue )
555 Q_UNUSED( alphaValue )
558 *returnGreenValue = 0;
559 *returnBlueValue = 0;
560 *returnAlphaValue = 0;
567 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
568 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
570 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
576 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral(
"colorrampshader" ) );
578 colorRampShaderElem.setAttribute( QStringLiteral(
"classificationMode" ),
static_cast< int >(
classificationMode() ) );
579 colorRampShaderElem.setAttribute( QStringLiteral(
"clip" ),
clip() );
580 colorRampShaderElem.setAttribute( QStringLiteral(
"minimumValue" ),
mMinimumValue );
581 colorRampShaderElem.setAttribute( QStringLiteral(
"maximumValue" ),
mMaximumValue );
582 colorRampShaderElem.setAttribute( QStringLiteral(
"labelPrecision" ),
mLabelPrecision );
588 colorRampShaderElem.appendChild( colorRampElem );
593 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
594 for ( ; itemIt != itemList.constEnd(); ++itemIt )
596 QDomElement itemElem = doc.createElement( QStringLiteral(
"item" ) );
597 itemElem.setAttribute( QStringLiteral(
"label" ), itemIt->label );
599 itemElem.setAttribute( QStringLiteral(
"color" ), itemIt->color.name() );
600 itemElem.setAttribute( QStringLiteral(
"alpha" ), itemIt->color.alpha() );
601 colorRampShaderElem.appendChild( itemElem );
604 if ( mLegendSettings )
605 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
607 return colorRampShaderElem;
613 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral(
"colorramp" ) );
614 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
619 setColorRampType( colorRampShaderElem.attribute( QStringLiteral(
"colorRampType" ), QStringLiteral(
"INTERPOLATED" ) ) );
621 setClip( colorRampShaderElem.attribute( QStringLiteral(
"clip" ), QStringLiteral(
"0" ) ) == QLatin1String(
"1" ) );
622 setMinimumValue( colorRampShaderElem.attribute( QStringLiteral(
"minimumValue" ) ).toDouble() );
623 setMaximumValue( colorRampShaderElem.attribute( QStringLiteral(
"maximumValue" ) ).toDouble() );
624 setLabelPrecision( colorRampShaderElem.attribute( QStringLiteral(
"labelPrecision" ), QStringLiteral(
"6" ) ).toDouble() );
626 QList<QgsColorRampShader::ColorRampItem> itemList;
627 QDomElement itemElem;
632 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral(
"item" ) );
633 itemList.reserve( itemNodeList.size() );
634 for (
int i = 0; i < itemNodeList.size(); ++i )
636 itemElem = itemNodeList.at( i ).toElement();
637 itemValue = itemElem.attribute( QStringLiteral(
"value" ) ).toDouble();
638 itemLabel = itemElem.attribute( QStringLiteral(
"label" ) );
639 itemColor.setNamedColor( itemElem.attribute( QStringLiteral(
"color" ) ) );
640 itemColor.setAlpha( itemElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt() );
646 if ( !mLegendSettings )
647 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
649 mLegendSettings->readXml( colorRampShaderElem, context );
654 return mLegendSettings.get();
659 if ( settings == mLegendSettings.get() )
661 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)