34#include <QDomDocument>
37#include <QRegularExpression>
42using namespace Qt::StringLiterals;
44const int QgsPalettedRasterRenderer::MAX_FLOAT_CLASSES = 65536;
50 QHash<QString, QHash<QColor, QVector<QVariant>>> classData;
52 classData.reserve(
classes.size() );
54 QVector<QString> labels;
55 labels.reserve(
classes.size() );
59 if ( !classData.contains( klass.label ) )
61 labels.push_back( klass.label );
63 classData[klass.label][klass.color].push_back( klass.value );
66 mMultiValueClassData.reserve( classData.size() );
68 for (
auto labelIt = labels.constBegin(); labelIt != labels.constEnd(); ++labelIt )
70 for ( auto colorIt = classData[*labelIt].constBegin(); colorIt != classData[*labelIt].constEnd(); ++colorIt )
72 mMultiValueClassData.push_back( MultiValueClass { colorIt.value(), colorIt.key(), *labelIt } );
82 , mMultiValueClassData( classes )
89 auto renderer = std::make_unique< QgsPalettedRasterRenderer >(
nullptr, mBand, mMultiValueClassData );
91 if ( mSourceColorRamp )
92 renderer->setSourceColorRamp( mSourceColorRamp->clone() );
94 renderer->copyCommonProperties(
this );
96 return renderer.release();
111 const int bandNumber = elem.attribute( u
"band"_s, u
"-1"_s ).toInt();
114 const QDomElement paletteElem = elem.firstChildElement( u
"colorPalette"_s );
115 if ( !paletteElem.isNull() )
117 const QDomNodeList paletteEntries = paletteElem.elementsByTagName( u
"paletteEntry"_s );
119 QDomElement entryElem;
122 for (
int i = 0; i < paletteEntries.size(); ++i )
126 entryElem = paletteEntries.at( i ).toElement();
127 value = entryElem.attribute( u
"value"_s, u
"0"_s ).toDouble();
128 color = QColor( entryElem.attribute( u
"color"_s, u
"#000000"_s ) );
129 color.setAlpha( entryElem.attribute( u
"alpha"_s, u
"255"_s ).toInt() );
130 label = entryElem.attribute( u
"label"_s );
131 QgsDebugMsgLevel( u
"Value: %1, label: %2, color: %3"_s.arg( value ).arg(
label, entryElem.attribute( u
"color"_s ) ), 4 );
140 QDomElement sourceColorRampElem = elem.firstChildElement( u
"colorramp"_s );
141 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( u
"name"_s ) ==
"[source]"_L1 )
156 return mMultiValueClassData;
161 mMultiValueClassData =
classes;
167 if ( !mMultiValueClassData.isEmpty() )
169 const auto constMClassData = mMultiValueClassData;
172 if (
c.values.contains( idx ) )
182 MultiValueClassData::iterator cMvIt = mMultiValueClassData.begin();
183 for ( ; cMvIt != mMultiValueClassData.end(); ++cMvIt )
185 if ( cMvIt->values.contains( idx ) )
187 cMvIt->label =
label;
215 auto outputBlock = std::make_unique<QgsRasterBlock>();
216 if ( !
mInput || mMultiValueClassData.isEmpty() )
218 return outputBlock.release();
221 const std::shared_ptr< QgsRasterBlock > inputBlock(
mInput->block( mBand,
extent, width, height, feedback ) );
223 if ( !inputBlock || inputBlock->isEmpty() )
226 return outputBlock.release();
232 std::shared_ptr< QgsRasterBlock > alphaBlock;
237 if ( !alphaBlock || alphaBlock->isEmpty() )
239 return outputBlock.release();
244 alphaBlock = inputBlock;
249 return outputBlock.release();
256 Q_ASSERT( outputBlock );
257 unsigned int *outputData = (
unsigned int * ) ( outputBlock->bits() );
260 bool isNoData =
false;
261 for (
qgssize i = 0; i < rasterSize; ++i )
263 const double value = inputBlock->valueAndNoData( i, isNoData );
266 outputData[i] = myDefaultColor;
269 if ( !mColors.contains( value ) )
271 outputData[i] = myDefaultColor;
275 if ( !hasTransparency )
277 outputData[i] = mColors.value( value );
288 const double alpha = alphaBlock->value( i );
291 outputBlock->setColor( i, myDefaultColor );
296 currentOpacity *= alpha / 255.0;
300 const QRgb
c = mColors.value( value );
301 outputData[i] = qRgba( currentOpacity * qRed(
c ), currentOpacity * qGreen(
c ), currentOpacity * qBlue(
c ), currentOpacity * qAlpha(
c ) );
305 return outputBlock.release();
310 return mMultiValueClassData.size();
315 if ( parentElem.isNull() )
320 QDomElement rasterRendererElem = doc.createElement( u
"rasterrenderer"_s );
323 rasterRendererElem.setAttribute( u
"band"_s, mBand );
324 QDomElement colorPaletteElem = doc.createElement( u
"colorPalette"_s );
325 const ClassData klassData { classData() };
326 ClassData::const_iterator it = klassData.constBegin();
327 for ( ; it != klassData.constEnd(); ++it )
329 const QColor color = it->color;
330 QDomElement colorElem = doc.createElement( u
"paletteEntry"_s );
331 colorElem.setAttribute( u
"value"_s, it->value );
332 colorElem.setAttribute( u
"color"_s, color.name() );
333 colorElem.setAttribute( u
"alpha"_s, color.alpha() );
334 if ( !it->label.isEmpty() )
336 colorElem.setAttribute( u
"label"_s, it->label );
338 colorPaletteElem.appendChild( colorElem );
340 rasterRendererElem.appendChild( colorPaletteElem );
343 if ( mSourceColorRamp )
346 rasterRendererElem.appendChild( colorRampElem );
349 parentElem.appendChild( rasterRendererElem );
356 toSld( doc, element, context );
365 const QDomNodeList elements = element.elementsByTagName( u
"sld:RasterSymbolizer"_s );
366 if ( elements.size() == 0 )
370 QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
373 QDomElement channelSelectionElem = doc.createElement( u
"sld:ChannelSelection"_s );
374 rasterSymbolizerElem.appendChild( channelSelectionElem );
377 QDomElement channelElem = doc.createElement( u
"sld:GrayChannel"_s );
378 channelSelectionElem.appendChild( channelElem );
381 QDomElement sourceChannelNameElem = doc.createElement( u
"sld:SourceChannelName"_s );
382 sourceChannelNameElem.appendChild( doc.createTextNode( QString::number( mBand ) ) );
383 channelElem.appendChild( sourceChannelNameElem );
386 QDomElement colorMapElem = doc.createElement( u
"sld:ColorMap"_s );
387 colorMapElem.setAttribute( u
"type"_s, u
"values"_s );
388 if ( this->
classes().size() >= 255 )
389 colorMapElem.setAttribute( u
"extended"_s, u
"true"_s );
390 rasterSymbolizerElem.appendChild( colorMapElem );
394 const QList<QgsPalettedRasterRenderer::Class>
classes = this->
classes();
395 QList<QgsPalettedRasterRenderer::Class>::const_iterator classDataIt =
classes.constBegin();
396 for ( ; classDataIt !=
classes.constEnd(); ++classDataIt )
398 QDomElement colorMapEntryElem = doc.createElement( u
"sld:ColorMapEntry"_s );
399 colorMapElem.appendChild( colorMapEntryElem );
402 colorMapEntryElem.setAttribute( u
"color"_s, classDataIt->color.name() );
403 colorMapEntryElem.setAttribute( u
"quantity"_s, QString::number( classDataIt->value ) );
404 colorMapEntryElem.setAttribute( u
"label"_s, classDataIt->label );
405 if ( classDataIt->color.alphaF() != 1.0 )
407 colorMapEntryElem.setAttribute( u
"opacity"_s, QString::number( classDataIt->color.alphaF() ) );
415 if ( mSourceColorRamp )
427 QList< QPair< QString, QColor > > symbolItems;
430 QString lab { classData.label };
434 for (
const QVariant &val : std::as_const( classData.values ) )
438 const double numericValue { val.toDouble( &ok ) };
441 values.push_back( QLocale().toString( numericValue ) );
445 values.push_back( val.toString() );
448 lab = values.join( QChar(
' ' ) );
450 symbolItems << qMakePair( lab, classData.color );
458 QList<QgsLayerTreeModelLegendNode *> res;
461 if ( !name.isEmpty() )
467 res.reserve( res.size() + items.size() );
468 for (
const QPair< QString, QColor > &item : items )
489 mSourceColorRamp.reset( ramp );
494 return mSourceColorRamp.get();
499 QList<QgsColorRampShader::ColorRampItem>::const_iterator colorIt = table.constBegin();
501 for ( ; colorIt != table.constEnd(); ++colorIt )
510 if ( !attributeTable || !attributeTable->
isValid() )
517 const QList<QgsRasterAttributeTable::MinMaxClass> minMaxClasses { attributeTable->
minMaxClasses( classificationColumn ) };
518 if ( minMaxClasses.empty() )
523 QVector<QVariant> values;
524 for (
const double val : std::as_const( minMaxClass.minMaxValues ) )
526 values.push_back( QVariant( val ) );
528 classData.push_back( { values, minMaxClass.color, minMaxClass.name } );
531 int numClasses {
static_cast<int>( classData.count() ) };
534 if ( ramp && numClasses > 0 )
542 randomRamp->setTotalColorCount( numClasses );
545 if ( numClasses > 1 )
548 QgsPalettedRasterRenderer::MultiValueClassData::iterator cIt = classData.begin();
549 for ( ; cIt != classData.end(); ++cIt )
551 cIt->color = ramp->
color( i /
static_cast<double>( numClasses ) );
563 const thread_local QRegularExpression linePartRx( u
"[\\s,:]+"_s );
565 const QStringList parts =
string.split(
'\n', Qt::SkipEmptyParts );
566 for (
const QString &part : parts )
568 const QStringList lineParts = part.split( linePartRx, Qt::SkipEmptyParts );
570 switch ( lineParts.count() )
574 const int value = lineParts.at( 0 ).toInt( &ok );
584 const int value = lineParts.at( 0 ).toInt( &ok );
588 const QColor
c( lineParts.at( 1 ) );
596 if ( lineParts.count() < 4 )
599 const int value = lineParts.at( 0 ).toInt( &ok );
604 const double r = lineParts.at( 1 ).toDouble( &rOk );
606 const double g = lineParts.at( 2 ).toDouble( &gOk );
608 const double b = lineParts.at( 3 ).toDouble( &bOk );
611 if ( rOk && gOk && bOk )
613 c = QColor( r, g, b );
616 if ( lineParts.count() >= 5 )
618 const double alpha = lineParts.at( 4 ).toDouble( &ok );
624 if ( lineParts.count() > 5 )
626 label = lineParts.mid( 5 ).join(
' ' );
639 QFile inputFile( path );
641 if ( inputFile.open( QIODevice::ReadOnly ) )
643 QTextStream in( &inputFile );
644 input = in.readAll();
655 std::sort( cd.begin(), cd.end(), [](
const Class &a,
const Class &b ) ->
bool { return a.value < b.value; } );
657 const auto constCd = cd;
658 for (
const Class &
c : constCd )
660 out << u
"%1 %2 %3 %4 %5 %6"_s.arg(
c.value ).arg(
c.color.red() ).arg(
c.color.green() ).arg(
c.color.blue() ).arg(
c.color.alpha() ).arg(
c.label );
662 return out.join(
'\n' );
672 if ( bandNumber > 0 && bandNumber <= raster->
bandCount() )
674 qlonglong numClasses = 0;
687 std::set<double> values;
695 const int nbBlocksWidth =
static_cast< int >( std::ceil( 1.0 * raster->
xSize() / maxWidth ) );
696 const int nbBlocksHeight =
static_cast< int >( std::ceil( 1.0 * raster->
ySize() / maxHeight ) );
697 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
703 std::unique_ptr< QgsRasterBlock > rasterBlock;
705 bool isNoData =
false;
706 while ( iter.
readNextRasterPart( bandNumber, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
709 feedback->
setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
714 for (
int row = 0; row < iterRows; row++ )
719 for (
int column = 0; column < iterCols; column++ )
724 const double currentValue = rasterBlock->valueAndNoData( row, column, isNoData );
725 if ( numClasses >= MAX_FLOAT_CLASSES )
730 if ( !isNoData && values.find( currentValue ) == values.end() )
732 values.insert( currentValue );
733 data.push_back(
Class( currentValue, QColor(), QLocale().toString( currentValue ) ) );
740 std::sort( data.begin(), data.end(), [](
const Class &a,
const Class &b ) ->
bool { return a.value < b.value; } );
752 const int bins = std::ceil( max - min ) + 1;
765 for (
int idx = 0; idx <
histogram.binCount; ++idx )
767 const int count =
histogram.histogramVector.at( idx );
770 data <<
Class( currentValue, QColor(), QLocale().toString( currentValue ) );
773 currentValue += interval;
783 if ( ramp && numClasses > 0 )
791 randomRamp->setTotalColorCount( data.count() );
794 if ( numClasses > 1 )
797 QgsPalettedRasterRenderer::ClassData::iterator cIt = data.begin();
798 for ( ; cIt != data.end(); ++cIt )
803 feedback->
setProgress( std::max<int>( 1, 100 * ( i + 1 ) / numClasses ) );
805 cIt->color = ramp->
color( i /
static_cast<double>( numClasses ) );
816 for (
const MultiValueClass &klass : std::as_const( mMultiValueClassData ) )
818 for (
const QVariant &entry : std::as_const( klass.values ) )
821 const double value { entry.toDouble( &ok ) };
824 data.push_back( { value, klass.color, klass.label } );
828 QgsDebugMsgLevel( u
"Could not convert class value '%1' to double when creating classes."_s.arg( entry.toString() ), 2 );
835void QgsPalettedRasterRenderer::updateArrays()
839 MultiValueClassData::const_iterator it = mMultiValueClassData.constBegin();
840 for ( ; it != mMultiValueClassData.constEnd(); ++it )
842 for (
const QVariant &entry : std::as_const( it->values ) )
845 const double value { entry.toDouble( &ok ) };
848 mColors[value] = qPremultiply( it->color.rgba() );
852 QgsDebugMsgLevel( u
"Could not convert class value '%1' to double for color lookup."_s.arg( entry.toString() ), 2 );
QFlags< RasterRendererFlag > RasterRendererFlags
Flags which control behavior of raster renderers.
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
@ Float32
Thirty two bit floating point (float).
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Float64
Sixty four bit floating point (double).
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Layer tree node points to a map layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
Properties of a multi value class: a class that contains multiple values.
QColor color
Color to render values.
MultiValueClass(const QVector< QVariant > &values, const QColor &color=QColor(), const QString &label=QString())
Constructor for MultiValueClass from a list of values.
QVector< QVariant > values
Values.
QString label
Label for values.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
QList< QgsLayerTreeModelLegendNode * > createLegendNodes(QgsLayerTreeLayer *nodeLayer) override
Creates a set of legend nodes representing the renderer.
static QgsPalettedRasterRenderer::MultiValueClassData rasterAttributeTableToClassData(const QgsRasterAttributeTable *attributeTable, int classificationColumn=-1, QgsColorRamp *ramp=nullptr)
Reads and returns classes from the Raster Attribute Table attributeTable, optionally classifying the ...
QgsColorRamp * sourceColorRamp() const
Gets the source color ramp.
static QgsPalettedRasterRenderer::ClassData classDataFromString(const QString &string)
Converts a string containing a color table or class data to to paletted renderer class data.
QString label(double idx) const
Returns optional category label.
void setSourceColorRamp(QgsColorRamp *ramp)
Set the source color ramp.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
bool canCreateRasterAttributeTable() const override
Returns true if the renderer is suitable for attribute table creation.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
Q_DECL_DEPRECATED int band() const
Returns the raster band used for rendering the raster.
QList< QgsPalettedRasterRenderer::Class > ClassData
Map of value to class properties.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
Qgis::RasterRendererFlags flags() const override
Returns flags which dictate renderer behavior.
int nColors() const
Returns number of colors.
QList< QgsPalettedRasterRenderer::MultiValueClass > MultiValueClassData
Map of multi value to class properties.
static QgsPalettedRasterRenderer::ClassData classDataFromFile(const QString &path)
Opens a color table file and returns corresponding paletted renderer class data.
bool setInputBand(int band) override
Attempts to set the input band for the renderer.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
void setMultiValueClasses(const MultiValueClassData &classes)
Sets the multi value classes to setMultiValueClasses.
static QgsPalettedRasterRenderer::ClassData colorTableToClassData(const QList< QgsColorRampShader::ColorRampItem > &table)
Converts a raster color table to paletted renderer class data.
ClassData classes() const
Returns a map of value to classes (colors) used by the renderer.
QList< QPair< QString, QColor > > legendSymbologyItems() const override
Returns symbology items if provided by renderer.
QgsPalettedRasterRenderer * clone() const override
Clone itself, create deep copy.
void setLabel(double idx, const QString &label)
Set category label.
static QgsPalettedRasterRenderer::ClassData classDataFromRaster(QgsRasterInterface *raster, int bandNumber, QgsColorRamp *ramp=nullptr, QgsRasterBlockFeedback *feedback=nullptr)
Generates class data from a raster, for the specified bandNumber.
int inputBand() const override
Returns the input band for the renderer, or -1 if no input band is available.
static QString classDataToString(const QgsPalettedRasterRenderer::ClassData &classes)
Converts classes to a string representation, using the .clr/gdal color table file format.
MultiValueClassData multiValueClasses() const
Returns a map of multi value to classes (colors) used by the renderer.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
QgsPalettedRasterRenderer(QgsRasterInterface *input, int bandNumber, const ClassData &classes)
Constructor for QgsPalettedRasterRenderer.
A color ramp consisting of random colors, constrained within component ranges.
The Field class represents a Raster Attribute Table classification entry for a thematic Raster Attrib...
Represents a Raster Attribute Table (RAT).
QList< QgsRasterAttributeTable::MinMaxClass > minMaxClasses(const int classificationColumn=-1) const
Returns the classes for a thematic Raster Attribute Table, classified by classificationColumn,...
bool isValid(QString *errorMessage=nullptr) const
Returns true if the Raster Attribute Table is valid, optionally reporting validity checks results in ...
The RasterBandStats struct is a container for statistics about a single raster band.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
Feedback object tailored for raster block reading.
A container for a histogram of a single raster band.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
virtual int xSize() const
Gets raster size.
QgsRasterInterface(QgsRasterInterface *input=nullptr)
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
QString displayBandName(int bandNumber) const
Generates a friendly, descriptive name for the specified bandNumber.
QgsRasterInterface * mInput
virtual int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
virtual QgsRasterInterface * input() const
Current input.
virtual QgsRasterHistogram histogram(int bandNo, int binCount=0, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false, QgsRasterBlockFeedback *feedback=nullptr)
Returns a band histogram.
Iterator for sequentially processing raster cells.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
void startRasterRead(int bandNumber, qgssize nCols, qgssize nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
Raster renderer pipe that applies colors to a raster.
QgsRasterRenderer(QgsRasterInterface *input=nullptr, const QString &type=QString())
Constructor for QgsRasterRenderer.
double mOpacity
Global alpha value (0-1).
int mAlphaBand
Read alpha value from band.
QRgb renderColorForNodataPixel() const
Returns the color for the renderer to use to represent nodata pixels.
std::unique_ptr< QgsRasterTransparency > mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses).
int bandCount() const override
Gets number of bands.
bool usesTransparency() const
virtual Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const
Used from subclasses to create SLD Rule elements following SLD v1.0 specs.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
Implementation of legend node interface for displaying raster legend entries.
A rectangle specified with double values.
Implementation of legend node interface for displaying arbitrary labels with icons.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
A color ramp entity for QgsStyle databases.
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
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.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
Properties of a single value class.
Contains information relating to the style entity currently being visited.