QGIS API Documentation  2.99.0-Master (40f86b2)
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  if ( bandNo > mInput->bandCount() || bandNo <= 0 )
41  {
42  return;
43  }
44  mBand = bandNo;
45 }
46 
48 {
49  mClassificationMin = min;
50  if ( shader() )
51  {
52  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( shader()->rasterShaderFunction() );
53  if ( colorRampShader )
54  {
55  colorRampShader->setMinimumValue( min );
56  }
57  }
58 }
59 
61 {
62  mClassificationMax = max;
63  if ( shader() )
64  {
65  QgsColorRampShader *colorRampShader = dynamic_cast<QgsColorRampShader *>( shader()->rasterShaderFunction() );
66  if ( colorRampShader )
67  {
68  colorRampShader->setMaximumValue( max );
69  }
70  }
71 }
72 
74 {
75  QgsRasterShader *shader = nullptr;
76 
77  if ( mShader )
78  {
79  shader = new QgsRasterShader( mShader->minimumValue(), mShader->maximumValue() );
80 
81  // Shader function
82  const QgsColorRampShader *origColorRampShader = dynamic_cast<const QgsColorRampShader *>( mShader->rasterShaderFunction() );
83 
84  if ( origColorRampShader )
85  {
86  QgsColorRampShader *colorRampShader = new QgsColorRampShader( mShader->minimumValue(), mShader->maximumValue() );
87 
88  if ( origColorRampShader->sourceColorRamp() )
89  {
90  colorRampShader->setSourceColorRamp( origColorRampShader->sourceColorRamp()->clone() );
91  }
92  colorRampShader->setColorRampType( origColorRampShader->colorRampType() );
93  colorRampShader->setClassificationMode( origColorRampShader->classificationMode() );
94  colorRampShader->setClip( origColorRampShader->clip() );
95  colorRampShader->setColorRampItemList( origColorRampShader->colorRampItemList() );
96  shader->setRasterShaderFunction( colorRampShader );
97  }
98  }
99  QgsSingleBandPseudoColorRenderer *renderer = new QgsSingleBandPseudoColorRenderer( nullptr, mBand, shader );
100  renderer->copyCommonProperties( this );
101 
102  return renderer;
103 }
104 
106 {
107  mShader.reset( shader );
108 }
109 
111 {
112  if ( band() == -1 || classificationMin() >= classificationMax() )
113  {
114  return;
115  }
116 
117  QgsColorRampShader *colorRampShader = new QgsColorRampShader( classificationMin(), classificationMax(), colorRamp, colorRampType, classificationMode );
118  colorRampShader->classifyColorRamp( classes, band(), extent, input() );
119  colorRampShader->setClip( clip );
120 
121  QgsRasterShader *rasterShader = new QgsRasterShader();
122  rasterShader->setRasterShaderFunction( colorRampShader );
123  setShader( rasterShader );
124 }
125 
127 {
128  if ( elem.isNull() )
129  {
130  return nullptr;
131  }
132 
133  int band = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
134  QgsRasterShader *shader = nullptr;
135  QDomElement rasterShaderElem = elem.firstChildElement( QStringLiteral( "rastershader" ) );
136  if ( !rasterShaderElem.isNull() )
137  {
138  shader = new QgsRasterShader();
139  shader->readXml( rasterShaderElem );
140  }
141 
143  r->readXml( elem );
144 
145  // TODO: add _readXML in superclass?
146  r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), QStringLiteral( "NaN" ) ).toDouble() );
147  r->setClassificationMax( elem.attribute( QStringLiteral( "classificationMax" ), QStringLiteral( "NaN" ) ).toDouble() );
148 
149  // Backward compatibility with serialization of QGIS 2.X era
150  QString minMaxOrigin = elem.attribute( QStringLiteral( "classificationMinMaxOrigin" ) );
151  if ( !minMaxOrigin.isEmpty() )
152  {
153  if ( minMaxOrigin.contains( QLatin1String( "MinMax" ) ) )
154  {
156  }
157  else if ( minMaxOrigin.contains( QLatin1String( "CumulativeCut" ) ) )
158  {
160  }
161  else if ( minMaxOrigin.contains( QLatin1String( "StdDev" ) ) )
162  {
164  }
165  else
166  {
168  }
169 
170  if ( minMaxOrigin.contains( QLatin1String( "FullExtent" ) ) )
171  {
173  }
174  else if ( minMaxOrigin.contains( QLatin1String( "SubExtent" ) ) )
175  {
177  }
178  else
179  {
181  }
182 
183  if ( minMaxOrigin.contains( QLatin1String( "Estimated" ) ) )
184  {
186  }
187  else // if ( minMaxOrigin.contains( QLatin1String( "Exact" ) ) )
188  {
190  }
191  }
192 
193  return r;
194 }
195 
197 {
198  Q_UNUSED( bandNo );
199 
200  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
201  if ( !mInput || !mShader )
202  {
203  return outputBlock.release();
204  }
205 
206 
207  std::shared_ptr< QgsRasterBlock > inputBlock( mInput->block( mBand, extent, width, height, feedback ) );
208  if ( !inputBlock || inputBlock->isEmpty() )
209  {
210  QgsDebugMsg( "No raster data!" );
211  return outputBlock.release();
212  }
213 
214  //rendering is faster without considering user-defined transparency
215  bool hasTransparency = usesTransparency();
216 
217  std::shared_ptr< QgsRasterBlock > alphaBlock;
218  if ( mAlphaBand > 0 && mAlphaBand != mBand )
219  {
220  alphaBlock.reset( mInput->block( mAlphaBand, extent, width, height, feedback ) );
221  if ( !alphaBlock || alphaBlock->isEmpty() )
222  {
223  return outputBlock.release();
224  }
225  }
226  else if ( mAlphaBand == mBand )
227  {
228  alphaBlock = inputBlock;
229  }
230 
231  if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) )
232  {
233  return outputBlock.release();
234  }
235 
236  QRgb myDefaultColor = NODATA_COLOR;
237 
238  for ( qgssize i = 0; i < ( qgssize )width * height; i++ )
239  {
240  if ( inputBlock->isNoData( i ) )
241  {
242  outputBlock->setColor( i, myDefaultColor );
243  continue;
244  }
245  double val = inputBlock->value( i );
246  int red, green, blue, alpha;
247  if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
248  {
249  outputBlock->setColor( i, myDefaultColor );
250  continue;
251  }
252 
253  if ( alpha < 255 )
254  {
255  // Working with premultiplied colors, so multiply values by alpha
256  red *= ( alpha / 255.0 );
257  blue *= ( alpha / 255.0 );
258  green *= ( alpha / 255.0 );
259  }
260 
261  if ( !hasTransparency )
262  {
263  outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
264  }
265  else
266  {
267  //opacity
268  double currentOpacity = mOpacity;
269  if ( mRasterTransparency )
270  {
271  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
272  }
273  if ( mAlphaBand > 0 )
274  {
275  currentOpacity *= alphaBlock->value( i ) / 255.0;
276  }
277 
278  outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
279  }
280  }
281 
282  return outputBlock.release();
283 }
284 
285 void QgsSingleBandPseudoColorRenderer::writeXml( QDomDocument &doc, QDomElement &parentElem ) const
286 {
287  if ( parentElem.isNull() )
288  {
289  return;
290  }
291 
292  QDomElement rasterRendererElem = doc.createElement( QStringLiteral( "rasterrenderer" ) );
293  _writeXml( doc, rasterRendererElem );
294  rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
295  if ( mShader )
296  {
297  mShader->writeXml( doc, rasterRendererElem ); //todo: include color ramp items directly in this renderer
298  }
299  rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) );
300  rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) );
301 
302  parentElem.appendChild( rasterRendererElem );
303 }
304 
305 void QgsSingleBandPseudoColorRenderer::legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems ) const
306 {
307  if ( mShader )
308  {
309  QgsRasterShaderFunction *shaderFunction = mShader->rasterShaderFunction();
310  if ( shaderFunction )
311  {
312  shaderFunction->legendSymbologyItems( symbolItems );
313  }
314  }
315 }
316 
318 {
319  QList<int> bandList;
320  if ( mBand != -1 )
321  {
322  bandList << mBand;
323  }
324  return bandList;
325 }
virtual int bandCount() const =0
Get number of bands.
int alphaValue(double, int globalTransparency=255) const
Returns the transparency value for a single value Pixel.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Interface for all raster shaders.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &list)
Set custom colormap.
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
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
virtual QgsRasterInterface * input() const
Current input.
QgsRasterMinMaxOrigin mMinMaxOrigin
Origin of min/max values.
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.
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
QgsRasterShader * shader()
Returns the raster shader.
void setLimits(Limits limits)
Set limits.
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.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:76
void setColorRampType(QgsColorRampShader::Type colorRampType)
Set the color ramp type.
Raster data container.
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.
Raster renderer pipe for single band pseudocolor.
Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ].
bool usesTransparency() const
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:349
void setExtent(Extent extent)
Set extent.
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 setClassificationMode(ClassificationMode classificationMode)
Sets classification mode.
virtual void setMinimumValue(double)
Return the minimum value.
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
void setStatAccuracy(StatAccuracy accuracy)
Set statistics accuracy.
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.