QGIS API Documentation  2.99.0-Master (7fe5405)
qgssinglebandpseudocolorrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglebandpseudocolorrenderer.cpp
3  ------------------------------------
4  begin : January 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgscolorramp.h"
20 #include "qgscolorrampshader.h"
21 #include "qgsrastershader.h"
22 #include "qgsrastertransparency.h"
23 #include "qgsrasterviewport.h"
24 
25 #include <QDomDocument>
26 #include <QDomElement>
27 #include <QImage>
28 
30  QgsRasterRenderer( input, QStringLiteral( "singlebandpseudocolor" ) )
31  , mShader( shader )
32  , mBand( band )
33  , mClassificationMin( std::numeric_limits<double>::quiet_NaN() )
34  , mClassificationMax( std::numeric_limits<double>::quiet_NaN() )
35 {
36 }
37 
39 {
40  delete mShader;
41 }
42 
44 {
45  if ( bandNo > mInput->bandCount() || bandNo <= 0 )
46  {
47  return;
48  }
49  mBand = bandNo;
50 }
51 
53 {
54  mClassificationMin = min;
55  if ( shader() )
56  {
57  QgsColorRampShader* colorRampShader = dynamic_cast<QgsColorRampShader*>( shader()->rasterShaderFunction() );
58  if ( colorRampShader )
59  {
60  colorRampShader->setMinimumValue( min );
61  }
62  }
63 }
64 
66 {
67  mClassificationMax = max;
68  if ( shader() )
69  {
70  QgsColorRampShader* colorRampShader = dynamic_cast<QgsColorRampShader*>( shader()->rasterShaderFunction() );
71  if ( colorRampShader )
72  {
73  colorRampShader->setMaximumValue( max );
74  }
75  }
76 }
77 
79 {
80  QgsRasterShader *shader = nullptr;
81 
82  if ( mShader )
83  {
84  shader = new QgsRasterShader( mShader->minimumValue(), mShader->maximumValue() );
85 
86  // Shader function
87  const QgsColorRampShader* origColorRampShader = dynamic_cast<const QgsColorRampShader*>( mShader->rasterShaderFunction() );
88 
89  if ( origColorRampShader )
90  {
91  QgsColorRampShader * colorRampShader = new QgsColorRampShader( mShader->minimumValue(), mShader->maximumValue() );
92 
93  if ( origColorRampShader->sourceColorRamp() )
94  {
95  colorRampShader->setSourceColorRamp( origColorRampShader->sourceColorRamp()->clone() );
96  }
97  colorRampShader->setColorRampType( origColorRampShader->colorRampType() );
98  colorRampShader->setClassificationMode( origColorRampShader->classificationMode() );
99  colorRampShader->setClip( origColorRampShader->clip() );
100  colorRampShader->setColorRampItemList( origColorRampShader->colorRampItemList() );
101  shader->setRasterShaderFunction( colorRampShader );
102  }
103  }
104  QgsSingleBandPseudoColorRenderer * renderer = new QgsSingleBandPseudoColorRenderer( nullptr, mBand, shader );
105  renderer->copyCommonProperties( this );
106 
107  return renderer;
108 }
109 
111 {
112  delete mShader;
113  mShader = shader;
114 }
115 
117 {
118  if ( band() == -1 || classificationMin() >= classificationMax() )
119  {
120  return;
121  }
122 
123  QgsColorRampShader* colorRampShader = new QgsColorRampShader( classificationMin(), classificationMax(), colorRamp, colorRampType, classificationMode );
124  colorRampShader->classifyColorRamp( classes, band(), extent, input() );
125  colorRampShader->setClip( clip );
126 
127  QgsRasterShader* rasterShader = new QgsRasterShader();
128  rasterShader->setRasterShaderFunction( colorRampShader );
129  setShader( rasterShader );
130 }
131 
133 {
134  if ( elem.isNull() )
135  {
136  return nullptr;
137  }
138 
139  int band = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
140  QgsRasterShader* shader = nullptr;
141  QDomElement rasterShaderElem = elem.firstChildElement( QStringLiteral( "rastershader" ) );
142  if ( !rasterShaderElem.isNull() )
143  {
144  shader = new QgsRasterShader();
145  shader->readXml( rasterShaderElem );
146  }
147 
149  r->readXml( elem );
150 
151  // TODO: add _readXML in superclass?
152  r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), QStringLiteral( "NaN" ) ).toDouble() );
153  r->setClassificationMax( elem.attribute( QStringLiteral( "classificationMax" ), QStringLiteral( "NaN" ) ).toDouble() );
154 
155  // Backward compatibility with serialization of QGIS 2.X era
156  QString minMaxOrigin = elem.attribute( QStringLiteral( "classificationMinMaxOrigin" ) );
157  if ( !minMaxOrigin.isEmpty() )
158  {
159  if ( minMaxOrigin.contains( QLatin1String( "MinMax" ) ) )
160  {
162  }
163  else if ( minMaxOrigin.contains( QLatin1String( "CumulativeCut" ) ) )
164  {
166  }
167  else if ( minMaxOrigin.contains( QLatin1String( "StdDev" ) ) )
168  {
170  }
171  else
172  {
174  }
175 
176  if ( minMaxOrigin.contains( QLatin1String( "FullExtent" ) ) )
177  {
179  }
180  else if ( minMaxOrigin.contains( QLatin1String( "SubExtent" ) ) )
181  {
183  }
184  else
185  {
187  }
188 
189  if ( minMaxOrigin.contains( QLatin1String( "Estimated" ) ) )
190  {
192  }
193  else // if ( minMaxOrigin.contains( QLatin1String( "Exact" ) ) )
194  {
196  }
197  }
198 
199  return r;
200 }
201 
203 {
204  Q_UNUSED( bandNo );
205 
206  QgsRasterBlock *outputBlock = new QgsRasterBlock();
207  if ( !mInput || !mShader )
208  {
209  return outputBlock;
210  }
211 
212 
213  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height, feedback );
214  if ( !inputBlock || inputBlock->isEmpty() )
215  {
216  QgsDebugMsg( "No raster data!" );
217  delete inputBlock;
218  return outputBlock;
219  }
220 
221  //rendering is faster without considering user-defined transparency
222  bool hasTransparency = usesTransparency();
223 
224  QgsRasterBlock *alphaBlock = nullptr;
225  if ( mAlphaBand > 0 && mAlphaBand != mBand )
226  {
227  alphaBlock = mInput->block( mAlphaBand, extent, width, height, feedback );
228  if ( !alphaBlock || alphaBlock->isEmpty() )
229  {
230  delete inputBlock;
231  delete alphaBlock;
232  return outputBlock;
233  }
234  }
235  else if ( mAlphaBand == mBand )
236  {
237  alphaBlock = inputBlock;
238  }
239 
240  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
241  {
242  delete inputBlock;
243  delete alphaBlock;
244  return outputBlock;
245  }
246 
247  QRgb myDefaultColor = NODATA_COLOR;
248 
249  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
250  {
251  if ( inputBlock->isNoData( i ) )
252  {
253  outputBlock->setColor( i, myDefaultColor );
254  continue;
255  }
256  double val = inputBlock->value( i );
257  int red, green, blue, alpha;
258  if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
259  {
260  outputBlock->setColor( i, myDefaultColor );
261  continue;
262  }
263 
264  if ( alpha < 255 )
265  {
266  // Working with premultiplied colors, so multiply values by alpha
267  red *= ( alpha / 255.0 );
268  blue *= ( alpha / 255.0 );
269  green *= ( alpha / 255.0 );
270  }
271 
272  if ( !hasTransparency )
273  {
274  outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
275  }
276  else
277  {
278  //opacity
279  double currentOpacity = mOpacity;
280  if ( mRasterTransparency )
281  {
282  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
283  }
284  if ( mAlphaBand > 0 )
285  {
286  currentOpacity *= alphaBlock->value( i ) / 255.0;
287  }
288 
289  outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
290  }
291  }
292 
293  delete inputBlock;
294  if ( mAlphaBand > 0 && mBand != mAlphaBand )
295  {
296  delete alphaBlock;
297  }
298 
299  return outputBlock;
300 }
301 
302 void QgsSingleBandPseudoColorRenderer::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
303 {
304  if ( parentElem.isNull() )
305  {
306  return;
307  }
308 
309  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
310  _writeXml( doc, rasterRendererElem );
311  rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
312  if ( mShader )
313  {
314  mShader->writeXml( doc, rasterRendererElem ); //todo: include color ramp items directly in this renderer
315  }
316  rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) );
317  rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) );
318 
319  parentElem.appendChild( rasterRendererElem );
320 }
321 
322 void QgsSingleBandPseudoColorRenderer::legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const
323 {
324  if ( mShader )
325  {
326  QgsRasterShaderFunction* shaderFunction = mShader->rasterShaderFunction();
327  if ( shaderFunction )
328  {
329  shaderFunction->legendSymbologyItems( symbolItems );
330  }
331  }
332 }
333 
335 {
336  QList<int> bandList;
337  if ( mBand != -1 )
338  {
339  bandList << mBand;
340  }
341  return bandList;
342 }
virtual int bandCount() const =0
Get number of bands.
void setStatAccuracy(StatAccuracy theAccuracy)
Set statistics accuracy.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Interface for all raster shaders.
static QString printValue(double value)
Print double value with all necessary significant digits.
void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const override
Get symbology items if provided by renderer.
QgsSingleBandPseudoColorRenderer * clone() const override
Clone itself, create deep copy.
virtual QgsRectangle extent() const
Get the extent of the interface.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
virtual QgsRasterInterface * input() const
Current input.
QgsRasterMinMaxOrigin mMinMaxOrigin
Origin of min/max values.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &theList)
Set custom colormap.
const QgsRasterMinMaxOrigin & minMaxOrigin() const
Returns const reference to origin of min/max values.
void setClip(bool clip)
Sets whether the shader should not render values out of range.
void setExtent(Extent theExtent)
Set extent.
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
QgsRasterShader * shader()
Returns the raster shader.
bool isNoData(int row, int column)
Check if value at position is no data.
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
Type
Supported methods for color interpolation.
Current extent of the canvas (at the time of computation) is used to compute statistics.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
bool setColor(int row, int column, QRgb color)
Set color on position.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:76
Raster data container.
void setLimits(Limits theLimits)
Set limits.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
QgsRasterShaderFunction * rasterShaderFunction()
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
The raster shade function applies a shader to a pixel at render time - typically used to render grays...
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
double maximumValue()
Return the maximum value for the raster shader.
Raster renderer pipe for single band pseudocolor.
Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ].
bool usesTransparency() const
bool shade(double, int *, int *, int *, int *)
generates and new RGBA value based on one input value
bool isEmpty() const
Returns true if block is empty, i.e.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:452
int mAlphaBand
Read alpha value from band.
void readXml(const QDomElement &rendererElem) override
Sets base class members from xml. Usually called from create() methods of subclasses.
void setSourceColorRamp(QgsColorRamp *colorramp)
Set the source color ramp.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ]...
void setRasterShaderFunction(QgsRasterShaderFunction *)
A public method that allows the user to set their own shader function.
Base class for processing filters like renderers, reprojector, resampler etc.
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:437
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...
Definition: qgis.h:333
bool reset(Qgis::DataType theDataType, int theWidth, int theHeight)
Reset block.
void writeXml(QDomDocument &doc, QDomElement &parent) const
Writes shader state to an XML element.
void classifyColorRamp(const int classes=0, const int band=-1, const QgsRectangle &extent=QgsRectangle(), QgsRasterInterface *input=nullptr)
Classify color ramp shader.
Whole raster is used to compute statistics.
void setColorRampType(QgsColorRampShader::Type theColorRampType)
Set the color ramp type.
void setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
virtual void setMinimumValue(double)
Return the minimum value.
double minimumValue()
Return the minimum value for the raster shader.
double value(int row, int column) const
Read a single value if type of block is numeric.
void setBand(int bandNo)
Sets the band used by the renderer.
double mOpacity
Global alpha value (0-1)
void createShader(QgsColorRamp *colorRamp=nullptr, QgsColorRampShader::Type colorRampType=QgsColorRampShader::Interpolated, QgsColorRampShader::ClassificationMode classificationMode=QgsColorRampShader::Continuous, int classes=0, bool clip=false, const QgsRectangle &extent=QgsRectangle())
Creates a color ramp shader.
ClassificationMode
Classification modes used to create the color ramp shader.
QgsRasterInterface * mInput
QgsSingleBandPseudoColorRenderer(QgsRasterInterface *input, int band=-1, QgsRasterShader *shader=nullptr)
Note: takes ownership of QgsRasterShader.
Feedback object tailored for raster block reading.
virtual void setMaximumValue(double)
Set the maximum value.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Raster renderer pipe that applies colors to a raster.
int band() const
Returns the band used by the renderer.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
void readXml(const QDomElement &elem)
Reads shader state from an XML element.