23 #define DOUBLE_DIFF_THRESHOLD 0.0 // 0.0000001
36 , mColorRampType( type )
37 , mClassificationMode( classificationMode )
46 , mColorRampType( other.mColorRampType )
47 , mClassificationMode( other.mClassificationMode )
49 , mLUTOffset( other.mLUTOffset )
50 , mLUTFactor( other.mLUTFactor )
51 , mLUTInitialized( other.mLUTInitialized )
52 , mClip( other.mClip )
56 mColorRampItemList = other.mColorRampItemList;
61 QgsRasterShaderFunction::operator=( other );
67 mColorRampType = other.mColorRampType;
68 mClassificationMode = other.mClassificationMode;
70 mLUTOffset = other.mLUTOffset;
71 mLUTFactor = other.mLUTFactor;
72 mLUTInitialized = other.mLUTInitialized;
74 mColorRampItemList = other.mColorRampItemList;
80 switch ( mColorRampType )
83 return QStringLiteral(
"INTERPOLATED" );
85 return QStringLiteral(
"DISCRETE" );
87 return QStringLiteral(
"EXACT" );
89 return QStringLiteral(
"Unknown" );
94 mColorRampItemList = list.toVector();
96 mLUTInitialized =
false;
107 return mColorRampItemList.isEmpty();
112 if ( type == QLatin1String(
"INTERPOLATED" ) )
116 else if ( type == QLatin1String(
"DISCRETE" ) )
122 mColorRampType =
Exact;
145 QList<double> entryValues;
146 QVector<QColor> entryColors;
156 entryValues.reserve( numberOfEntries );
159 double intervalDiff = max - min;
163 if ( colorGradientRamp && colorGradientRamp->
isDiscrete() )
171 intervalDiff *= ( numberOfEntries - 1 ) /
static_cast<double>( numberOfEntries );
175 for (
int i = 1; i < numberOfEntries; ++i )
178 entryValues.push_back( min + value * intervalDiff );
180 entryValues.push_back( std::numeric_limits<double>::infinity() );
184 for (
int i = 0; i < numberOfEntries; ++i )
187 entryValues.push_back( min + value * ( max - min ) );
191 for (
int i = 0; i < numberOfEntries; ++i )
206 if ( band < 0 || !input )
209 double cut1 = std::numeric_limits<double>::quiet_NaN();
210 double cut2 = std::numeric_limits<double>::quiet_NaN();
212 const int sampleSize = 250000 * 10;
215 input->
cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
217 entryValues.reserve( classes );
220 double intervalDiff = 1.0 / ( classes );
221 for (
int i = 1; i < classes; ++i )
223 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
224 entryValues.push_back( cut2 );
226 entryValues.push_back( std::numeric_limits<double>::infinity() );
230 double intervalDiff = 1.0 / ( classes - 1 );
231 for (
int i = 0; i < classes; ++i )
233 input->
cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
234 entryValues.push_back( cut2 );
240 entryValues.reserve( classes );
246 double intervalDiff = ( max - min ) / ( classes );
248 for (
int i = 1; i < classes; ++i )
250 entryValues.push_back( min + i * intervalDiff );
252 entryValues.push_back( std::numeric_limits<double>::infinity() );
257 double intervalDiff = ( max - min ) / ( classes - 1 );
259 for (
int i = 0; i < classes; ++i )
261 entryValues.push_back( min + i * intervalDiff );
272 colorDiff = ( int )( 255 / classes );
275 entryColors.reserve( classes );
276 for (
int i = 0; i < classes; ++i )
280 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
281 entryColors.push_back( currentColor );
286 entryColors.reserve( classes );
287 for (
int i = 0; i < classes; ++i )
295 QList<double>::const_iterator value_it = entryValues.constBegin();
296 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
299 double maxabs = std::log10( std::max( std::fabs( max ), std::fabs( min ) ) );
300 int nDecimals = std::round( std::max( 3.0 + maxabs - std::log10( max - min ), maxabs <= 15.0 ? maxabs + 0.49 : 0.0 ) );
302 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
303 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
306 newColorRampItem.
value = *value_it;
307 newColorRampItem.
color = *color_it;
308 newColorRampItem.
label = QString::number( *value_it,
'g', nDecimals );
309 colorRampItems.append( newColorRampItem );
312 std::sort( colorRampItems.begin(), colorRampItems.end() );
321 bool QgsColorRampShader::shade(
double value,
int *returnRedValue,
int *returnGreenValue,
int *returnBlueValue,
int *returnAlphaValue )
const
323 if ( mColorRampItemList.isEmpty() )
327 if ( std::isnan( value ) || std::isinf( value ) )
330 int colorRampItemListCount = mColorRampItemList.count();
333 if ( !mLUTInitialized )
340 if ( colorRampItemListCount >= 3 )
342 double rangeValue = colorRampItems[colorRampItemListCount - 2].
value -
minimumValue;
343 if ( rangeValue > 0 )
346 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue;
349 mLUT.reserve( lutSize );
350 for (
int i = 0; i < lutSize; i++ )
352 val = ( i / mLUTFactor ) + mLUTOffset;
353 while ( idx < colorRampItemListCount
358 mLUT.push_back( idx );
362 mLUTInitialized =
true;
367 bool overflow =
false;
370 int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
371 if ( value < mLUTOffset )
375 else if ( lutIndex >= mLUT.count() )
377 idx = colorRampItemListCount - 1;
383 else if ( lutIndex < 0 )
390 idx = mLUT.at( lutIndex );
398 if ( idx >= colorRampItemListCount )
400 idx = colorRampItemListCount - 1;
414 if ( mClip && ( overflow
419 *returnRedValue = currentColorRampItem.
color.red();
420 *returnGreenValue = currentColorRampItem.
color.green();
421 *returnBlueValue = currentColorRampItem.
color.blue();
422 *returnAlphaValue = currentColorRampItem.
color.alpha();
428 float currentRampRange = currentColorRampItem.
value - previousColorRampItem.
value;
429 float offsetInRange = value - previousColorRampItem.
value;
430 float scale = offsetInRange / currentRampRange;
431 const QRgb c1 = previousColorRampItem.
color.rgba();
432 const QRgb c2 = currentColorRampItem.
color.rgba();
434 *returnRedValue = qRed( c1 ) +
static_cast< int >( ( qRed( c2 ) - qRed( c1 ) ) * scale );
435 *returnGreenValue = qGreen( c1 ) +
static_cast< int >( ( qGreen( c2 ) - qGreen( c1 ) ) * scale );
436 *returnBlueValue = qBlue( c1 ) +
static_cast< int >( ( qBlue( c2 ) - qBlue( c1 ) ) * scale );
437 *returnAlphaValue = qAlpha( c1 ) +
static_cast< int >( ( qAlpha( c2 ) - qAlpha( c1 ) ) * scale );
449 *returnRedValue = currentColorRampItem.
color.red();
450 *returnGreenValue = currentColorRampItem.
color.green();
451 *returnBlueValue = currentColorRampItem.
color.blue();
452 *returnAlphaValue = currentColorRampItem.
color.alpha();
460 *returnRedValue = currentColorRampItem.
color.red();
461 *returnGreenValue = currentColorRampItem.
color.green();
462 *returnBlueValue = currentColorRampItem.
color.blue();
463 *returnAlphaValue = currentColorRampItem.
color.alpha();
476 double blueValue,
double alphaValue,
477 int *returnRedValue,
int *returnGreenValue,
478 int *returnBlueValue,
int *returnAlphaValue )
const
481 Q_UNUSED( greenValue )
482 Q_UNUSED( blueValue )
483 Q_UNUSED( alphaValue )
486 *returnGreenValue = 0;
487 *returnBlueValue = 0;
488 *returnAlphaValue = 0;
495 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
496 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
498 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
504 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral(
"colorrampshader" ) );
506 colorRampShaderElem.setAttribute( QStringLiteral(
"classificationMode" ),
classificationMode() );
507 colorRampShaderElem.setAttribute( QStringLiteral(
"clip" ),
clip() );
508 colorRampShaderElem.setAttribute( QStringLiteral(
"minimumValue" ),
mMinimumValue );
509 colorRampShaderElem.setAttribute( QStringLiteral(
"maximumValue" ),
mMaximumValue );
515 colorRampShaderElem.appendChild( colorRampElem );
520 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
521 for ( ; itemIt != itemList.constEnd(); ++itemIt )
523 QDomElement itemElem = doc.createElement( QStringLiteral(
"item" ) );
524 itemElem.setAttribute( QStringLiteral(
"label" ), itemIt->label );
526 itemElem.setAttribute( QStringLiteral(
"color" ), itemIt->color.name() );
527 itemElem.setAttribute( QStringLiteral(
"alpha" ), itemIt->color.alpha() );
528 colorRampShaderElem.appendChild( itemElem );
530 return colorRampShaderElem;
536 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral(
"colorramp" ) );
537 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
542 setColorRampType( colorRampShaderElem.attribute( QStringLiteral(
"colorRampType" ), QStringLiteral(
"INTERPOLATED" ) ) );
544 setClip( colorRampShaderElem.attribute( QStringLiteral(
"clip" ), QStringLiteral(
"0" ) ) == QLatin1String(
"1" ) );
545 setMinimumValue( colorRampShaderElem.attribute( QStringLiteral(
"minimumValue" ) ).toDouble() );
546 setMaximumValue( colorRampShaderElem.attribute( QStringLiteral(
"maximumValue" ) ).toDouble() );
548 QList<QgsColorRampShader::ColorRampItem> itemList;
549 QDomElement itemElem;
554 QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral(
"item" ) );
555 itemList.reserve( itemNodeList.size() );
556 for (
int i = 0; i < itemNodeList.size(); ++i )
558 itemElem = itemNodeList.at( i ).toElement();
559 itemValue = itemElem.attribute( QStringLiteral(
"value" ) ).toDouble();
560 itemLabel = itemElem.attribute( QStringLiteral(
"label" ) );
561 itemColor.setNamedColor( itemElem.attribute( QStringLiteral(
"color" ) ) );
562 itemColor.setAlpha( itemElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt() );