QGIS API Documentation  2.17.0-Master (bf77d09)
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 "qgsrastershader.h"
20 #include "qgsrastertransparency.h"
21 #include "qgsrasterviewport.h"
22 #include <QDomDocument>
23 #include <QDomElement>
24 #include <QImage>
25 
27  QgsRasterRenderer( input, "singlebandpseudocolor" )
28  , mShader( shader )
29  , mBand( band )
30  , mClassificationMin( std::numeric_limits<double>::quiet_NaN() )
31  , mClassificationMax( std::numeric_limits<double>::quiet_NaN() )
32  , mClassificationMinMaxOrigin( QgsRasterRenderer::MinMaxUnknown )
33 {
34 }
35 
37 {
38  delete mShader;
39 }
40 
42 {
43  if ( bandNo > mInput->bandCount() || bandNo <= 0 )
44  {
45  return;
46  }
47  mBand = bandNo;
48 }
49 
51 {
52  QgsRasterShader *shader = nullptr;
53 
54  if ( mShader )
55  {
56  shader = new QgsRasterShader( mShader->minimumValue(), mShader->maximumValue() );
57 
58  // Shader function
59  const QgsColorRampShader* origColorRampShader = dynamic_cast<const QgsColorRampShader*>( mShader->rasterShaderFunction() );
60 
61  if ( origColorRampShader )
62  {
63  QgsColorRampShader * colorRampShader = new QgsColorRampShader( mShader->minimumValue(), mShader->maximumValue() );
64 
65  colorRampShader->setColorRampType( origColorRampShader->colorRampType() );
66  colorRampShader->setClip( origColorRampShader->clip() );
67  colorRampShader->setColorRampItemList( origColorRampShader->colorRampItemList() );
68  shader->setRasterShaderFunction( colorRampShader );
69  }
70  }
71  QgsSingleBandPseudoColorRenderer * renderer = new QgsSingleBandPseudoColorRenderer( nullptr, mBand, shader );
72  renderer->copyCommonProperties( this );
73 
74  return renderer;
75 }
76 
78 {
79  delete mShader;
80  mShader = shader;
81 }
82 
84 {
85  if ( elem.isNull() )
86  {
87  return nullptr;
88  }
89 
90  int band = elem.attribute( "band", "-1" ).toInt();
91  QgsRasterShader* shader = nullptr;
92  QDomElement rasterShaderElem = elem.firstChildElement( "rastershader" );
93  if ( !rasterShaderElem.isNull() )
94  {
95  shader = new QgsRasterShader();
96  shader->readXML( rasterShaderElem );
97  }
98 
100  r->readXML( elem );
101 
102  // TODO: add _readXML in superclass?
103  r->setClassificationMin( elem.attribute( "classificationMin", "NaN" ).toDouble() );
104  r->setClassificationMax( elem.attribute( "classificationMax", "NaN" ).toDouble() );
105  r->setClassificationMinMaxOrigin( QgsRasterRenderer::minMaxOriginFromName( elem.attribute( "classificationMinMaxOrigin", "Unknown" ) ) );
106 
107  return r;
108 }
109 
110 QgsRasterBlock* QgsSingleBandPseudoColorRenderer::block( int bandNo, QgsRectangle const & extent, int width, int height )
111 {
112  Q_UNUSED( bandNo );
113 
114  QgsRasterBlock *outputBlock = new QgsRasterBlock();
115  if ( !mInput || !mShader )
116  {
117  return outputBlock;
118  }
119 
120 
121  QgsRasterBlock *inputBlock = mInput->block( mBand, extent, width, height );
122  if ( !inputBlock || inputBlock->isEmpty() )
123  {
124  QgsDebugMsg( "No raster data!" );
125  delete inputBlock;
126  return outputBlock;
127  }
128 
129  //rendering is faster without considering user-defined transparency
130  bool hasTransparency = usesTransparency();
131 
132  QgsRasterBlock *alphaBlock = nullptr;
133  if ( mAlphaBand > 0 && mAlphaBand != mBand )
134  {
135  alphaBlock = mInput->block( mAlphaBand, extent, width, height );
136  if ( !alphaBlock || alphaBlock->isEmpty() )
137  {
138  delete inputBlock;
139  delete alphaBlock;
140  return outputBlock;
141  }
142  }
143  else if ( mAlphaBand == mBand )
144  {
145  alphaBlock = inputBlock;
146  }
147 
148  if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
149  {
150  delete inputBlock;
151  delete alphaBlock;
152  return outputBlock;
153  }
154 
155  QRgb myDefaultColor = NODATA_COLOR;
156 
157  for ( qgssize i = 0; i < ( qgssize )width*height; i++ )
158  {
159  if ( inputBlock->isNoData( i ) )
160  {
161  outputBlock->setColor( i, myDefaultColor );
162  continue;
163  }
164  double val = inputBlock->value( i );
165  int red, green, blue, alpha;
166  if ( !mShader->shade( val, &red, &green, &blue, &alpha ) )
167  {
168  outputBlock->setColor( i, myDefaultColor );
169  continue;
170  }
171 
172  if ( alpha < 255 )
173  {
174  // Working with premultiplied colors, so multiply values by alpha
175  red *= ( alpha / 255.0 );
176  blue *= ( alpha / 255.0 );
177  green *= ( alpha / 255.0 );
178  }
179 
180  if ( !hasTransparency )
181  {
182  outputBlock->setColor( i, qRgba( red, green, blue, alpha ) );
183  }
184  else
185  {
186  //opacity
187  double currentOpacity = mOpacity;
188  if ( mRasterTransparency )
189  {
190  currentOpacity = mRasterTransparency->alphaValue( val, mOpacity * 255 ) / 255.0;
191  }
192  if ( mAlphaBand > 0 )
193  {
194  currentOpacity *= alphaBlock->value( i ) / 255.0;
195  }
196 
197  outputBlock->setColor( i, qRgba( currentOpacity * red, currentOpacity * green, currentOpacity * blue, currentOpacity * alpha ) );
198  }
199  }
200 
201  delete inputBlock;
202  if ( mAlphaBand > 0 && mBand != mAlphaBand )
203  {
204  delete alphaBlock;
205  }
206 
207  return outputBlock;
208 }
209 
211 {
212  if ( parentElem.isNull() )
213  {
214  return;
215  }
216 
217  QDomElement rasterRendererElem = doc.createElement( "rasterrenderer" );
218  _writeXML( doc, rasterRendererElem );
219  rasterRendererElem.setAttribute( "band", mBand );
220  if ( mShader )
221  {
222  mShader->writeXML( doc, rasterRendererElem ); //todo: include color ramp items directly in this renderer
223  }
224  rasterRendererElem.setAttribute( "classificationMin", QgsRasterBlock::printValue( mClassificationMin ) );
225  rasterRendererElem.setAttribute( "classificationMax", QgsRasterBlock::printValue( mClassificationMax ) );
226  rasterRendererElem.setAttribute( "classificationMinMaxOrigin", QgsRasterRenderer::minMaxOriginName( mClassificationMinMaxOrigin ) );
227 
228  parentElem.appendChild( rasterRendererElem );
229 }
230 
232 {
233  if ( mShader )
234  {
235  QgsRasterShaderFunction* shaderFunction = mShader->rasterShaderFunction();
236  if ( shaderFunction )
237  {
238  shaderFunction->legendSymbologyItems( symbolItems );
239  }
240  }
241 }
242 
244 {
245  QList<int> bandList;
246  if ( mBand != -1 )
247  {
248  bandList << mBand;
249  }
250  return bandList;
251 }
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
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.
QDomNode appendChild(const QDomNode &newChild)
QgsSingleBandPseudoColorRenderer * clone() const override
Clone itself, create deep copy.
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.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void copyCommonProperties(const QgsRasterRenderer *other)
Copies common properties like opacity / transparency data from other renderer.
static int minMaxOriginFromName(const QString &theName)
virtual QgsRasterInterface * input() const
Current input.
void setColorRampItemList(const QList< QgsColorRampShader::ColorRampItem > &theList)
Set custom colormap.
void setClip(bool clip)
Sets whether the shader should not render values out of range.
double toDouble(bool *ok) const
bool isNoData(int row, int column)
Check if value at position is no data.
void setShader(QgsRasterShader *shader)
Takes ownership of the shader.
void readXML(const QDomElement &rendererElem) override
Sets base class members from xml.
void writeXML(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
bool usesTransparency() const
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value.
void writeXML(QDomDocument &doc, QDomElement &parent) const
bool setColor(int row, int column, QRgb color)
Set color on position.
static const QRgb NODATA_COLOR
int alphaValue(double, int theGlobalTransparency=255) const
Returns the transparency value for a single value Pixel.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition: qgis.h:150
Raster data container.
QgsSingleBandPseudoColorRenderer(QgsRasterInterface *input, int band, QgsRasterShader *shader)
Note: takes ownership of QgsRasterShader.
double value(int row, int column) const
Read a single value if type of block is numeric.
void setAttribute(const QString &name, const QString &value)
int band() const
Returns the band used by the renderer.
int toInt(bool *ok, int base) const
QgsRasterShaderFunction * rasterShaderFunction()
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height) override
Read block of data using given extent and size.
The raster shade function applies a shader to a pixel at render time - typically used to render grays...
double maximumValue()
Return the maximum value for the raster shader.
Raster renderer pipe for single band pseudocolor.
bool shade(double, int *, int *, int *, int *)
generates and new RGBA value based on one input value
int mAlphaBand
Read alpha value from band.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
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.
void setColorRampType(QgsColorRampShader::ColorRamp_TYPE theColorRampType)
Set the color ramp type.
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:500
bool reset(QGis::DataType theDataType, int theWidth, int theHeight)
Reset block.
bool isNull() const
virtual void legendSymbologyItems(QList< QPair< QString, QColor > > &symbolItems) const
virtual QgsRectangle extent()
Get the extent of the interface.
QDomElement firstChildElement(const QString &tagName) const
static QString minMaxOriginName(int theOrigin)
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height)=0
Read block of data using given extent and size.
double minimumValue()
Return the minimum value for the raster shader.
void setBand(int bandNo)
Sets the band used by the renderer.
double mOpacity
Global alpha value (0-1)
void readXML(const QDomElement &elem)
QDomElement createElement(const QString &tagName)
void _writeXML(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXML method of subclasses) ...
QgsRasterInterface * mInput
Raster renderer pipe that applies colors to a raster.
bool isEmpty() const
Returns true if block is empty, i.e.