23 #define DOUBLE_DIFF_THRESHOLD 0.0 // 0.0000001
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 );