QGIS API Documentation 3.29.0-Master (8c80f25a4f)
qgscolorrampshader.cpp
Go to the documentation of this file.
1/* **************************************************************************
2 qgscolorrampshader.cpp - description
3 -------------------
4begin : Fri Dec 28 2007
5copyright : (C) 2007 by Peter J. Ersts
7
8This class is based off of code that was originally written by Marco Hugentobler and
9originally part of the larger QgsRasterLayer class
10****************************************************************************/
11
12/* **************************************************************************
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 ***************************************************************************/
20
21// Threshold for treating values as exact match.
22// Set to 0.0 to support displaying small values (https://github.com/qgis/QGIS/issues/20706)
23#define DOUBLE_DIFF_THRESHOLD 0.0 // 0.0000001
24
25#include "qgslogger.h"
26#include "qgis.h"
27#include "qgscolorrampimpl.h"
28#include "qgscolorrampshader.h"
29#include "qgsrasterinterface.h"
31#include "qgssymbollayerutils.h"
32#include "qgsreadwritecontext.h"
34
35#include <cmath>
36QgsColorRampShader::QgsColorRampShader( double minimumValue, double maximumValue, QgsColorRamp *colorRamp, Type type, ClassificationMode classificationMode )
37 : QgsRasterShaderFunction( minimumValue, maximumValue )
38 , mColorRampType( type )
39 , mClassificationMode( classificationMode )
40 , mLegendSettings( std::make_unique< QgsColorRampLegendNodeSettings >() )
41{
42 QgsDebugMsgLevel( QStringLiteral( "called." ), 4 );
43
44 setSourceColorRamp( colorRamp );
45}
46
48
51 , mColorRampType( other.mColorRampType )
52 , mClassificationMode( other.mClassificationMode )
53 , mLUT( other.mLUT )
54 , mLUTOffset( other.mLUTOffset )
55 , mLUTFactor( other.mLUTFactor )
56 , mLUTInitialized( other.mLUTInitialized )
57 , mClip( other.mClip )
58 , mLegendSettings( other.legendSettings() ? new QgsColorRampLegendNodeSettings( *other.legendSettings() ) : new QgsColorRampLegendNodeSettings() )
59{
60 if ( auto *lSourceColorRamp = other.sourceColorRamp() )
61 mSourceColorRamp.reset( lSourceColorRamp->clone() );
62 mColorRampItemList = other.mColorRampItemList;
63}
64
66{
67 QgsRasterShaderFunction::operator=( other );
68 if ( auto *lSourceColorRamp = other.sourceColorRamp() )
69 mSourceColorRamp.reset( lSourceColorRamp->clone() );
70 else
71 mSourceColorRamp.reset();
72
73 mColorRampType = other.mColorRampType;
74 mClassificationMode = other.mClassificationMode;
75 mLUT = other.mLUT;
76 mLUTOffset = other.mLUTOffset;
77 mLUTFactor = other.mLUTFactor;
78 mLUTInitialized = other.mLUTInitialized;
79 mClip = other.mClip;
80 mColorRampItemList = other.mColorRampItemList;
81 mLegendSettings.reset( other.legendSettings() ? new QgsColorRampLegendNodeSettings( *other.legendSettings() ) : new QgsColorRampLegendNodeSettings() );
82 return *this;
83}
84
86{
87 switch ( mColorRampType )
88 {
89 case Interpolated:
90 return QStringLiteral( "INTERPOLATED" );
91 case Discrete:
92 return QStringLiteral( "DISCRETE" );
93 case Exact:
94 return QStringLiteral( "EXACT" );
95 }
96 return QStringLiteral( "Unknown" );
97}
98
99void QgsColorRampShader::setColorRampItemList( const QList<QgsColorRampShader::ColorRampItem> &list )
100{
101 mColorRampItemList = list.toVector();
102 // Reset the look up table when the color ramp is changed
103 mLUTInitialized = false;
104 mLUT.clear();
105}
106
108{
109 mColorRampType = colorRampType;
110}
111
113{
114 return mColorRampItemList.isEmpty();
115}
116
117void QgsColorRampShader::setColorRampType( const QString &type )
118{
119 if ( type == QLatin1String( "INTERPOLATED" ) )
120 {
121 mColorRampType = Interpolated;
122 }
123 else if ( type == QLatin1String( "DISCRETE" ) )
124 {
125 mColorRampType = Discrete;
126 }
127 else
128 {
129 mColorRampType = Exact;
130 }
131}
132
134{
135 return mSourceColorRamp.get();
136}
137
139{
140 std::unique_ptr<QgsGradientColorRamp> ramp = std::make_unique< QgsGradientColorRamp >();
141 const int count = mColorRampItemList.size();
142 if ( count == 0 )
143 {
144 const QColor none( 0, 0, 0, 0 );
145 ramp->setColor1( none );
146 ramp->setColor2( none );
147 }
148 else if ( count == 1 )
149 {
150 ramp->setColor1( mColorRampItemList[0].color );
151 ramp->setColor2( mColorRampItemList[0].color );
152 }
153 else
154 {
156 // minimum and maximum values can fall outside the range of the item list
157 const double min = minimumValue();
158 const double max = maximumValue();
159 for ( int i = 0; i < count; i++ )
160 {
161 const double offset = ( mColorRampItemList[i].value - min ) / ( max - min );
162 if ( i == 0 )
163 {
164 ramp->setColor1( mColorRampItemList[i].color );
165 if ( offset <= 0.0 )
166 continue;
167 }
168 else if ( i == count - 1 )
169 {
170 ramp->setColor2( mColorRampItemList[i].color );
171 if ( offset >= 1.0 )
172 continue;
173 }
174 stops << QgsGradientStop( offset, mColorRampItemList[i].color );
175 }
176 ramp->setStops( stops );
177 }
178
179 return ramp.release();
180}
181
183{
184 mSourceColorRamp.reset( colorramp );
185}
186
187void QgsColorRampShader::classifyColorRamp( const int classes, const int band, const QgsRectangle &extent, QgsRasterInterface *input )
188{
189 if ( minimumValue() > maximumValue() )
190 return;
191
192 const bool discrete = colorRampType() == Discrete;
193
194 QList<double> entryValues;
195 QVector<QColor> entryColors;
196
197 double min = minimumValue();
198 double max = maximumValue();
199
200 if ( minimumValue() == maximumValue() )
201 {
202 if ( sourceColorRamp() && sourceColorRamp()->count() > 1 )
203 {
204 entryValues.push_back( min );
205 if ( discrete )
206 entryValues.push_back( std::numeric_limits<double>::infinity() );
207 for ( int i = 0; i < entryValues.size(); ++i )
208 entryColors.push_back( sourceColorRamp()->color( sourceColorRamp()->value( i ) ) );
209 }
210 }
211 else if ( classificationMode() == Continuous )
212 {
213 if ( sourceColorRamp() && sourceColorRamp()->count() > 1 )
214 {
215 int numberOfEntries = sourceColorRamp()->count();
216 entryValues.reserve( numberOfEntries );
217 if ( discrete )
218 {
219 double intervalDiff = max - min;
220
221 // remove last class when ColorRamp is gradient and discrete, as they are implemented with an extra stop
222 QgsGradientColorRamp *colorGradientRamp = dynamic_cast<QgsGradientColorRamp *>( sourceColorRamp() );
223 if ( colorGradientRamp && colorGradientRamp->isDiscrete() )
224 {
225 numberOfEntries--;
226 }
227 else
228 {
229 // if color ramp is continuous scale values to get equally distributed classes.
230 // Doesn't work perfectly when stops are non equally distributed.
231 intervalDiff *= ( numberOfEntries - 1 ) / static_cast<double>( numberOfEntries );
232 }
233
234 // skip first value (always 0.0)
235 for ( int i = 1; i < numberOfEntries; ++i )
236 {
237 const double value = sourceColorRamp()->value( i );
238 entryValues.push_back( min + value * intervalDiff );
239 }
240 entryValues.push_back( std::numeric_limits<double>::infinity() );
241 }
242 else
243 {
244 for ( int i = 0; i < numberOfEntries; ++i )
245 {
246 const double value = sourceColorRamp()->value( i );
247 entryValues.push_back( min + value * ( max - min ) );
248 }
249 }
250 // for continuous mode take original color map colors
251 for ( int i = 0; i < numberOfEntries; ++i )
252 {
253 const int idx = i;
254 entryColors.push_back( sourceColorRamp()->color( sourceColorRamp()->value( idx ) ) );
255 }
256 }
257 }
258 else // for other classification modes interpolate colors linearly
259 {
260 if ( classes < 2 )
261 return; // < 2 classes is not useful, shouldn't happen, but if it happens save it from crashing
262
263 if ( classificationMode() == Quantile )
264 {
265 // Quantile
266 if ( band < 0 || !input )
267 return; // quantile classification requires a valid band, minMaxOrigin, and input
268
269 double cut1 = std::numeric_limits<double>::quiet_NaN();
270 double cut2 = std::numeric_limits<double>::quiet_NaN();
271 // Note: the sample size in other parts of QGIS appears to be 25000, it is ten times here.
272 const int sampleSize = 250000 * 10;
273
274 // set min and max from histogram, used later to calculate number of decimals to display
275 input->cumulativeCut( band, 0.0, 1.0, min, max, extent, sampleSize );
276
277 entryValues.reserve( classes );
278 if ( discrete )
279 {
280 const double intervalDiff = 1.0 / ( classes );
281 for ( int i = 1; i < classes; ++i )
282 {
283 input->cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
284 entryValues.push_back( cut2 );
285 }
286 entryValues.push_back( std::numeric_limits<double>::infinity() );
287 }
288 else
289 {
290 const double intervalDiff = 1.0 / ( classes - 1 );
291 for ( int i = 0; i < classes; ++i )
292 {
293 input->cumulativeCut( band, 0.0, i * intervalDiff, cut1, cut2, extent, sampleSize );
294 entryValues.push_back( cut2 );
295 }
296 }
297 }
298 else // EqualInterval
299 {
300 entryValues.reserve( classes );
301 if ( discrete )
302 {
303 // in discrete mode the lowest value is not an entry and the highest
304 // value is inf, there are ( numberOfEntries ) of which the first
305 // and last are not used.
306 const double intervalDiff = ( max - min ) / ( classes );
307
308 for ( int i = 1; i < classes; ++i )
309 {
310 entryValues.push_back( min + i * intervalDiff );
311 }
312 entryValues.push_back( std::numeric_limits<double>::infinity() );
313 }
314 else
315 {
316 //because the highest value is also an entry, there are (numberOfEntries - 1) intervals
317 const double intervalDiff = ( max - min ) / ( classes - 1 );
318
319 for ( int i = 0; i < classes; ++i )
320 {
321 entryValues.push_back( min + i * intervalDiff );
322 }
323 }
324 }
325
326 if ( !sourceColorRamp() || sourceColorRamp()->count() == 1 )
327 {
328 //hard code color range from blue -> red (previous default)
329 int colorDiff = 0;
330 if ( classes != 0 )
331 {
332 colorDiff = ( int )( 255 / classes );
333 }
334
335 entryColors.reserve( classes );
336 for ( int i = 0; i < classes; ++i )
337 {
338 QColor currentColor;
339 const int idx = i;
340 currentColor.setRgb( colorDiff * idx, 0, 255 - colorDiff * idx );
341 entryColors.push_back( currentColor );
342 }
343 }
344 else
345 {
346 entryColors.reserve( classes );
347 for ( int i = 0; i < classes; ++i )
348 {
349 const int idx = i;
350 entryColors.push_back( sourceColorRamp()->color( ( ( double ) idx ) / ( classes - 1 ) ) );
351 }
352 }
353 }
354
355 QList<double>::const_iterator value_it = entryValues.constBegin();
356 QVector<QColor>::const_iterator color_it = entryColors.constBegin();
357
358 // calculate a reasonable number of decimals to display
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 ) );
361
362 QList<QgsColorRampShader::ColorRampItem> colorRampItems;
363 for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
364 {
365 QgsColorRampShader::ColorRampItem newColorRampItem;
366 newColorRampItem.value = *value_it;
367 newColorRampItem.color = *color_it;
368 newColorRampItem.label = QString::number( *value_it, 'g', nDecimals );
369 colorRampItems.append( newColorRampItem );
370 }
371
372 std::sort( colorRampItems.begin(), colorRampItems.end() );
373 setColorRampItemList( colorRampItems );
374}
375
376void QgsColorRampShader::classifyColorRamp( const int band, const QgsRectangle &extent, QgsRasterInterface *input )
377{
378 classifyColorRamp( colorRampItemList().count(), band, extent, input );
379}
380
381bool QgsColorRampShader::shade( double value, int *returnRedValue, int *returnGreenValue, int *returnBlueValue, int *returnAlphaValue ) const
382{
383 if ( mColorRampItemList.isEmpty() )
384 {
385 return false;
386 }
387 if ( std::isnan( value ) || std::isinf( value ) )
388 return false;
389
390 const int colorRampItemListCount = mColorRampItemList.count();
391 const QgsColorRampShader::ColorRampItem *colorRampItems = mColorRampItemList.constData();
392 int idx;
393 if ( !mLUTInitialized )
394 {
395 // calculate LUT for faster index recovery
396 mLUTFactor = 1.0;
397 const double minimumValue = colorRampItems[0].value;
398 mLUTOffset = minimumValue + DOUBLE_DIFF_THRESHOLD;
399 // Only make lut if at least 3 items, with 2 items the low and high cases handle both
400 if ( colorRampItemListCount >= 3 )
401 {
402 const double rangeValue = colorRampItems[colorRampItemListCount - 2].value - minimumValue;
403 if ( rangeValue > 0 )
404 {
405 const int lutSize = 256; // TODO: test if speed can be increased with a different LUT size
406 mLUTFactor = ( lutSize - 0.0000001 ) / rangeValue; // decrease slightly to make sure last LUT category is correct
407 idx = 0;
408 double val;
409 mLUT.reserve( lutSize );
410 for ( int i = 0; i < lutSize; i++ )
411 {
412 val = ( i / mLUTFactor ) + mLUTOffset;
413 while ( idx < colorRampItemListCount
414 && colorRampItems[idx].value - DOUBLE_DIFF_THRESHOLD < val )
415 {
416 idx++;
417 }
418 mLUT.emplace_back( idx );
419 }
420 }
421 }
422 mLUTInitialized = true;
423 }
424
425 // overflow indicates that value > maximum value + DOUBLE_DIFF_THRESHOLD
426 // that way idx can point to the last valid item
427 bool overflow = false;
428
429 // find index of the first ColorRampItem that is equal or higher to theValue
430 const int lutIndex = ( value - mLUTOffset ) * mLUTFactor;
431 if ( value <= mLUTOffset )
432 {
433 idx = 0;
434 }
435 else if ( static_cast< std::size_t>( lutIndex ) >= mLUT.size() )
436 {
437 idx = colorRampItemListCount - 1;
438 if ( colorRampItems[idx].value + DOUBLE_DIFF_THRESHOLD < value )
439 {
440 overflow = true;
441 }
442 }
443 else if ( lutIndex < 0 )
444 {
445 return false;
446 }
447 else
448 {
449 // get initial value from LUT
450 idx = mLUT[ lutIndex ];
451
452 // check if it's correct and if not increase until correct
453 // the LUT is made in such a way the index is always correct or too low, never too high
454 while ( idx < colorRampItemListCount && colorRampItems[idx].value + DOUBLE_DIFF_THRESHOLD < value )
455 {
456 idx++;
457 }
458 if ( idx >= colorRampItemListCount )
459 {
460 idx = colorRampItemListCount - 1;
461 overflow = true;
462 }
463 }
464
465 const QgsColorRampShader::ColorRampItem &currentColorRampItem = colorRampItems[idx];
466
467 switch ( colorRampType() )
468 {
469 case Interpolated:
470 {
471 // Interpolate the color between two class breaks linearly.
472 if ( idx < 1 || overflow || currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD <= value )
473 {
474 if ( mClip && ( overflow
475 || currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD > value ) )
476 {
477 return false;
478 }
479 *returnRedValue = currentColorRampItem.color.red();
480 *returnGreenValue = currentColorRampItem.color.green();
481 *returnBlueValue = currentColorRampItem.color.blue();
482 *returnAlphaValue = currentColorRampItem.color.alpha();
483 return true;
484 }
485
486 const QgsColorRampShader::ColorRampItem &previousColorRampItem = colorRampItems[idx - 1];
487
488 const float currentRampRange = currentColorRampItem.value - previousColorRampItem.value;
489 const float offsetInRange = value - previousColorRampItem.value;
490 const float scale = offsetInRange / currentRampRange;
491
492 const QRgb c1 = previousColorRampItem.color.rgba();
493 const QRgb c2 = currentColorRampItem.color.rgba();
494
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 );
499 return true;
500 };
501 case Discrete:
502 {
503 // Assign the color of the higher class for every pixel between two class breaks.
504 // NOTE: The implementation has always been different than the documentation,
505 // which said lower class before, see https://github.com/qgis/QGIS/issues/22009
506 if ( overflow )
507 {
508 return false;
509 }
510 *returnRedValue = currentColorRampItem.color.red();
511 *returnGreenValue = currentColorRampItem.color.green();
512 *returnBlueValue = currentColorRampItem.color.blue();
513 *returnAlphaValue = currentColorRampItem.color.alpha();
514 return true;
515 };
516 case Exact:
517 {
518 // Assign the color of the exact matching value in the color ramp item list
519 if ( !overflow && currentColorRampItem.value - DOUBLE_DIFF_THRESHOLD <= value )
520 {
521 *returnRedValue = currentColorRampItem.color.red();
522 *returnGreenValue = currentColorRampItem.color.green();
523 *returnBlueValue = currentColorRampItem.color.blue();
524 *returnAlphaValue = currentColorRampItem.color.alpha();
525 return true;
526 }
527 else
528 {
529 return false;
530 }
531 }
532 }
533 return false;
534}
535
536bool QgsColorRampShader::shade( double redValue, double greenValue,
537 double blueValue, double alphaValue,
538 int *returnRedValue, int *returnGreenValue,
539 int *returnBlueValue, int *returnAlphaValue ) const
540{
541 Q_UNUSED( redValue )
542 Q_UNUSED( greenValue )
543 Q_UNUSED( blueValue )
544 Q_UNUSED( alphaValue )
545
546 *returnRedValue = 0;
547 *returnGreenValue = 0;
548 *returnBlueValue = 0;
549 *returnAlphaValue = 0;
550
551 return false;
552}
553
554void QgsColorRampShader::legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems ) const
555{
556 QVector<QgsColorRampShader::ColorRampItem>::const_iterator colorRampIt = mColorRampItemList.constBegin();
557 for ( ; colorRampIt != mColorRampItemList.constEnd(); ++colorRampIt )
558 {
559 symbolItems.push_back( qMakePair( colorRampIt->label, colorRampIt->color ) );
560 }
561}
562
563QDomElement QgsColorRampShader::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
564{
565 QDomElement colorRampShaderElem = doc.createElement( QStringLiteral( "colorrampshader" ) );
566 colorRampShaderElem.setAttribute( QStringLiteral( "colorRampType" ), colorRampTypeAsQString() );
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 );
572
573 // save source color ramp
574 if ( sourceColorRamp() )
575 {
576 const QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), sourceColorRamp(), doc );
577 colorRampShaderElem.appendChild( colorRampElem );
578 }
579
580 //items
581 const QList<QgsColorRampShader::ColorRampItem> itemList = colorRampItemList();
582 QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
583 for ( ; itemIt != itemList.constEnd(); ++itemIt )
584 {
585 QDomElement itemElem = doc.createElement( QStringLiteral( "item" ) );
586 itemElem.setAttribute( QStringLiteral( "label" ), itemIt->label );
587 itemElem.setAttribute( QStringLiteral( "value" ), QgsRasterBlock::printValue( itemIt->value ) );
588 itemElem.setAttribute( QStringLiteral( "color" ), itemIt->color.name() );
589 itemElem.setAttribute( QStringLiteral( "alpha" ), itemIt->color.alpha() );
590 colorRampShaderElem.appendChild( itemElem );
591 }
592
593 if ( mLegendSettings )
594 mLegendSettings->writeXml( doc, colorRampShaderElem, context );
595
596 return colorRampShaderElem;
597}
598
599void QgsColorRampShader::readXml( const QDomElement &colorRampShaderElem, const QgsReadWriteContext &context )
600{
601 // try to load color ramp (optional)
602 QDomElement sourceColorRampElem = colorRampShaderElem.firstChildElement( QStringLiteral( "colorramp" ) );
603 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
604 {
606 }
607
608 setColorRampType( colorRampShaderElem.attribute( QStringLiteral( "colorRampType" ), QStringLiteral( "INTERPOLATED" ) ) );
609 setClassificationMode( static_cast< QgsColorRampShader::ClassificationMode >( colorRampShaderElem.attribute( QStringLiteral( "classificationMode" ), QStringLiteral( "1" ) ).toInt() ) );
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() );
614
615 QList<QgsColorRampShader::ColorRampItem> itemList;
616 QDomElement itemElem;
617 QString itemLabel;
618 double itemValue;
619 QColor itemColor;
620
621 const QDomNodeList itemNodeList = colorRampShaderElem.elementsByTagName( QStringLiteral( "item" ) );
622 itemList.reserve( itemNodeList.size() );
623 for ( int i = 0; i < itemNodeList.size(); ++i )
624 {
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() );
630
631 itemList.push_back( QgsColorRampShader::ColorRampItem( itemValue, itemColor, itemLabel ) );
632 }
633 setColorRampItemList( itemList );
634
635 if ( !mLegendSettings )
636 mLegendSettings = std::make_unique< QgsColorRampLegendNodeSettings >();
637
638 mLegendSettings->readXml( colorRampShaderElem, context );
639}
640
642{
643 return mLegendSettings.get();
644}
645
647{
648 if ( settings == mLegendSettings.get() )
649 return;
650 mLegendSettings.reset( settings );
651}
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.
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.
QList< QgsColorRampShader::ColorRampItem > colorRampItemList() const
Returns the custom colormap.
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.
Definition: qgscolorramp.h:30
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.
Definition: qgsrectangle.h:42
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)
Definition: qgslogger.h:39