23 #define DOUBLE_DIFF_THRESHOLD 0.0
38 , mColorRampType( type )
39 , mClassificationMode( classificationMode )
51 , mColorRampType( other.mColorRampType )
52 , mClassificationMode( other.mClassificationMode )
54 , mLUTOffset( other.mLUTOffset )
55 , mLUTFactor( other.mLUTFactor )
56 , mLUTInitialized( other.mLUTInitialized )
57 , mClip( other.mClip )
62 mColorRampItemList = other.mColorRampItemList;
67 QgsRasterShaderFunction::operator=( other );
73 mColorRampType = other.mColorRampType;
74 mClassificationMode = other.mClassificationMode;
76 mLUTOffset = other.mLUTOffset;
77 mLUTFactor = other.mLUTFactor;
78 mLUTInitialized = other.mLUTInitialized;
80 mColorRampItemList = other.mColorRampItemList;
87 switch ( mColorRampType )
90 return QStringLiteral(
"INTERPOLATED" );
92 return QStringLiteral(
"DISCRETE" );
94 return QStringLiteral(
"EXACT" );
96 return QStringLiteral(
"Unknown" );
101 mColorRampItemList = list.toVector();
103 mLUTInitialized =
false;
114 return mColorRampItemList.isEmpty();
119 if ( type == QLatin1String(
"INTERPOLATED" ) )
123 else if ( type == QLatin1String(
"DISCRETE" ) )
129 mColorRampType =
Exact;
140 std::unique_ptr<QgsGradientColorRamp> ramp = std::make_unique< QgsGradientColorRamp >();
141 const int count = mColorRampItemList.size();
144 const QColor none( 0, 0, 0, 0 );
145 ramp->setColor1( none );
146 ramp->setColor2( none );
148 else if ( count == 1 )
150 ramp->setColor1( mColorRampItemList[0].color );
151 ramp->setColor2( mColorRampItemList[0].color );
159 for (
int i = 0; i < count; i++ )
161 const double offset = ( mColorRampItemList[i].value - min ) / ( max - min );
164 ramp->setColor1( mColorRampItemList[i].color );
168 else if ( i == count - 1 )
170 ramp->setColor2( mColorRampItemList[i].color );
176 ramp->setStops( stops );
179 return ramp.release();
194 QList<double> entryValues;
195 QVector<QColor> entryColors;
204 entryValues.push_back( min );
206 entryValues.push_back( std::numeric_limits<double>::infinity() );
207 for (
int i = 0; i < entryValues.size(); ++i )
216 entryValues.reserve( numberOfEntries );
219 double intervalDiff = max - min;
223 if ( colorGradientRamp && colorGradientRamp->
isDiscrete() )
231 intervalDiff *= ( numberOfEntries - 1 ) /
static_cast<double>( numberOfEntries );
235 for (
int i = 1; i < numberOfEntries; ++i )
238 entryValues.push_back( min + value * intervalDiff );
240 entryValues.push_back( std::numeric_limits<double>::infinity() );
244 for (
int i = 0; i < numberOfEntries; ++i )
247 entryValues.push_back( min + value * ( max - min ) );
251 for (
int i = 0; i < numberOfEntries; ++i )
266 if ( band < 0 || !input )
269 double cut1 = std::numeric_limits<double>::quiet_NaN();
270 double cut2 = std::numeric_limits<double>::quiet_NaN();
272 const int sampleSize = 250000 * 10;
275 input->
cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
277 entryValues.reserve( classes );
280 const double intervalDiff = 1.0 / ( classes );
281 for (
int i = 1; i < classes; ++i )
283 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
284 entryValues.push_back( cut2 );
286 entryValues.push_back( std::numeric_limits<double>::infinity() );
290 const double intervalDiff = 1.0 / ( classes - 1 );
291 for (
int i = 0; i < classes; ++i )
293 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
294 entryValues.push_back( cut2 );
300 entryValues.reserve( classes );
306 const double intervalDiff = ( max - min ) / ( classes );
308 for (
int i = 1; i < classes; ++i )
310 entryValues.push_back( min + i * intervalDiff );
312 entryValues.push_back( std::numeric_limits<double>::infinity() );
317 const double intervalDiff = ( max - min ) / ( classes - 1 );
319 for (
int i = 0; i < classes; ++i )
321 entryValues.push_back( min + i * intervalDiff );
332 colorDiff = ( int )( 255 / classes );
335 entryColors.reserve( classes );
336 for (
int i = 0; i < classes; ++i )
340 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
341 entryColors.push_back( currentColor );
346 entryColors.reserve( classes );
347 for (
int i = 0; i < classes; ++i )
355 QList<double>::const_iterator value_it = entryValues.constBegin();
356 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
359 const double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
360 const int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
362 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
363 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
366 newColorRampItem.
value = *value_it;
367 newColorRampItem.
color = *color_it;
368 newColorRampItem.
label = QString::number( *value_it,
'g', nDecimals );
369 colorRampItems.append( newColorRampItem );
372 std::sort( colorRampItems.begin(), colorRampItems.end() );
381 bool QgsColorRampShader::shade(
double value,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
383 if ( mColorRampItemList.isEmpty() )
387 if ( std::isnan( value ) || std::isinf( value ) )
390 const int colorRampItemListCount = mColorRampItemList.count();
393 if ( !mLUTInitialized )
400 if ( colorRampItemListCount >= 3 )
402 const double rangeValue = colorRampItems[colorRampItemListCount - 2].
value -
minimumValue;
403 if ( rangeValue > 0 )
405 const int lutSize = 256;
406 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue;
409 mLUT.reserve( lutSize );
410 for (
int i = 0; i < lutSize; i++ )
412 val = ( i / mLUTFactor ) + mLUTOffset;
413 while ( idx < colorRampItemListCount
418 mLUT.emplace_back( idx );
422 mLUTInitialized =
true;
427 bool overflow =
false;
430 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
431 if ( value < mLUTOffset )
435 else if (
static_cast< std::size_t
>( lutIndex ) >= mLUT.size() )
437 idx = colorRampItemListCount - 1;
443 else if ( lutIndex < 0 )
450 idx = mLUT[ lutIndex ];
458 if ( idx >= colorRampItemListCount )
460 idx = colorRampItemListCount - 1;
474 if ( mClip && ( overflow
479 *returnRedValue = currentColorRampItem.
color.red();
480 *returnGreenValue = currentColorRampItem.
color.green();
481 *returnBlueValue = currentColorRampItem.
color.blue();
482 *returnAlphaValue = currentColorRampItem.
color.alpha();
488 const float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
489 const float offsetInRange = value - previousColorRampItem.
value;
490 const float scale = offsetInRange / currentRampRange;
492 const QRgb c1 = previousColorRampItem.
color.rgba();
493 const QRgb c2 = currentColorRampItem.
color.rgba();
495 *returnRedValue = qRed( c1 ) +
static_cast< int >( ( qRed( c2 ) - qRed( c1 ) ) * scale );
496 *returnGreenValue = qGreen( c1 ) +
static_cast< int >( ( qGreen( c2 ) - qGreen( c1 ) ) * scale );
497 *returnBlueValue = qBlue( c1 ) +
static_cast< int >( ( qBlue( c2 ) - qBlue( c1 ) ) * scale );
498 *returnAlphaValue = qAlpha( c1 ) +
static_cast< int >( ( qAlpha( c2 ) - qAlpha( c1 ) ) * scale );
510 *returnRedValue = currentColorRampItem.
color.red();
511 *returnGreenValue = currentColorRampItem.
color.green();
512 *returnBlueValue = currentColorRampItem.
color.blue();
513 *returnAlphaValue = currentColorRampItem.
color.alpha();
521 *returnRedValue = currentColorRampItem.
color.red();
522 *returnGreenValue = currentColorRampItem.
color.green();
523 *returnBlueValue = currentColorRampItem.
color.blue();
524 *returnAlphaValue = currentColorRampItem.
color.alpha();
537 double blueValue,
double alphaValue,
538 int *returnRedValue,
int *returnGreenValue,
539 int *returnBlueValue,
int *returnAlphaValue )
const
542 Q_UNUSED( greenValue )
543 Q_UNUSED( blueValue )
544 Q_UNUSED( alphaValue )
547 *returnGreenValue = 0;
548 *returnBlueValue = 0;
549 *returnAlphaValue = 0;
556 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
557 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
559 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
565 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral(
"colorrampshader" ) );
567 colorRampShaderElem.setAttribute( QStringLiteral(
"classificationMode" ),
classificationMode() );
568 colorRampShaderElem.setAttribute( QStringLiteral(
"clip" ),
clip() );
569 colorRampShaderElem.setAttribute( QStringLiteral(
"minimumValue" ),
mMinimumValue );
570 colorRampShaderElem.setAttribute( QStringLiteral(
"maximumValue" ),
mMaximumValue );
571 colorRampShaderElem.setAttribute( QStringLiteral(
"labelPrecision" ),
mLabelPrecision );
577 colorRampShaderElem.appendChild( colorRampElem );
582 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
583 for ( ; itemIt != itemList.constEnd(); ++itemIt )
585 QDomElement itemElem = doc.createElement( QStringLiteral(
"item" ) );
586 itemElem.setAttribute( QStringLiteral(
"label" ), itemIt->label );
588 itemElem.setAttribute( QStringLiteral(
"color" ), itemIt->color.name() );
589 itemElem.setAttribute( QStringLiteral(
"alpha" ), itemIt->color.alpha() );
590 colorRampShaderElem.appendChild( itemElem );
593 if ( mLegendSettings )
594 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
596 return colorRampShaderElem;
602 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral(
"colorramp" ) );
603 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
608 setColorRampType( colorRampShaderElem.attribute( QStringLiteral(
"colorRampType" ), QStringLiteral(
"INTERPOLATED" ) ) );
610 setClip( colorRampShaderElem.attribute( QStringLiteral(
"clip" ), QStringLiteral(
"0" ) ) == QLatin1String(
"1" ) );
611 setMinimumValue( colorRampShaderElem.attribute( QStringLiteral(
"minimumValue" ) ).toDouble() );
612 setMaximumValue( colorRampShaderElem.attribute( QStringLiteral(
"maximumValue" ) ).toDouble() );
613 setLabelPrecision( colorRampShaderElem.attribute( QStringLiteral(
"labelPrecision" ), QStringLiteral(
"6" ) ).toDouble() );
615 QList<QgsColorRampShader::ColorRampItem> itemList;
616 QDomElement itemElem;
621 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral(
"item" ) );
622 itemList.reserve( itemNodeList.size() );
623 for (
int i = 0; i < itemNodeList.size(); ++i )
625 itemElem = itemNodeList.at( i ).toElement();
626 itemValue = itemElem.attribute( QStringLiteral(
"value" ) ).toDouble();
627 itemLabel = itemElem.attribute( QStringLiteral(
"label" ) );
628 itemColor.setNamedColor( itemElem.attribute( QStringLiteral(
"color" ) ) );
629 itemColor.setAlpha( itemElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt() );
635 if ( !mLegendSettings )
636 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
638 mLegendSettings->readXml( colorRampShaderElem, context );
643 return mLegendSettings.get();
648 if ( settings == mLegendSettings.get() )
650 mLegendSettings.reset( settings );
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
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Returns legend symbology items if provided by renderer.
ClassificationMode classificationMode() const
Returns the classification mode.
const QgsColorRampLegendNodeSettings * legendSettings() const
Returns the color ramp shader legend settings.
bool isEmpty() const
Whether the color ramp contains any items.
Type colorRampType() const
Returns the color ramp type.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
QgsColorRampShader & operator=(const QgsColorRampShader &other)
Assignment operator.
ClassificationMode
Classification modes used to create the color ramp shader.
@ Quantile
Uses quantile (i.e. equal pixel) count.
@ Continuous
Uses breaks from color palette.
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 and new RGB 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.
Type
Supported methods for color interpolation.
@ Interpolated
Interpolates the color between two class breaks linearly.
@ Discrete
Assigns the color of the higher class for every pixel between two class breaks.
@ Exact
Assigns the color of the exact matching value in the color ramp item list.
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
void classifyColorRamp(int classes=0, int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Sets a custom colormap.
void setColorRampType(QgsColorRampShader::Type colorRampType)
Sets the color ramp type.
QgsColorRampShader(double minimumValue=0.0, double maximumValue=255.0, QgsColorRamp *colorRamp=nullptr, Type type=Interpolated, ClassificationMode classificationMode=Continuous)
Creates a new color ramp shader.
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.
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)
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)