31 , mLightAngle( lightAngle )
32 , mLightAzimuth( lightAzimuth )
33 , mMultiDirectional( false )
55 int band = elem.attribute( QStringLiteral(
"band" ), QStringLiteral(
"0" ) ).toInt();
56 double azimuth = elem.attribute( QStringLiteral(
"azimuth" ), QStringLiteral(
"315" ) ).toDouble();
57 double angle = elem.attribute( QStringLiteral(
"angle" ), QStringLiteral(
"45" ) ).toDouble();
58 double zFactor = elem.attribute( QStringLiteral(
"zfactor" ), QStringLiteral(
"1" ) ).toDouble();
59 bool multiDirectional = elem.attribute( QStringLiteral(
"multidirection" ), QStringLiteral(
"0" ) ).toInt();
70 if ( parentElem.isNull() )
75 QDomElement rasterRendererElem = doc.createElement( QStringLiteral(
"rasterrenderer" ) );
78 rasterRendererElem.setAttribute( QStringLiteral(
"band" ), mBand );
79 rasterRendererElem.setAttribute( QStringLiteral(
"azimuth" ), QString::number( mLightAzimuth ) );
80 rasterRendererElem.setAttribute( QStringLiteral(
"angle" ), QString::number( mLightAngle ) );
81 rasterRendererElem.setAttribute( QStringLiteral(
"zfactor" ), QString::number( mZFactor ) );
82 rasterRendererElem.setAttribute( QStringLiteral(
"multidirection" ), QString::number( mMultiDirectional ) );
83 parentElem.appendChild( rasterRendererElem );
89 std::unique_ptr< QgsRasterBlock > outputBlock(
new QgsRasterBlock() );
93 return outputBlock.release();
96 std::shared_ptr< QgsRasterBlock > inputBlock(
mInput->
block( mBand, extent, width, height, feedback ) );
98 if ( !inputBlock || inputBlock->isEmpty() )
101 return outputBlock.release();
104 std::shared_ptr< QgsRasterBlock > alphaBlock;
109 if ( !alphaBlock || alphaBlock->isEmpty() )
112 return outputBlock.release();
117 alphaBlock = inputBlock;
122 return outputBlock.release();
125 double cellXSize = extent.
width() / double( width );
126 double cellYSize = extent.
height() / double( height );
127 double zenithRad = std::max( 0.0, 90 - mLightAngle ) * M_PI / 180.0;
128 double azimuthRad = -1 * mLightAzimuth * M_PI / 180.0;
129 double cosZenithRad = std::cos( zenithRad );
130 double sinZenithRad = std::sin( zenithRad );
133 double angle0Rad = ( -1 * mLightAzimuth - 45 - 45 * 0.5 ) * M_PI / 180.0;
134 double angle1Rad = ( -1 * mLightAzimuth - 45 * 0.5 ) * M_PI / 180.0;
135 double angle2Rad = ( -1 * mLightAzimuth + 45 * 0.5 ) * M_PI / 180.0;
136 double angle3Rad = ( -1 * mLightAzimuth + 45 + 45 * 0.5 ) * M_PI / 180.0;
146 if ( inputBlock->isNoData( i, j ) )
148 outputBlock->setColor( i, j, myDefaultColor );
152 qgssize iUp, iDown, jLeft, jRight;
158 else if ( i < (
qgssize )height - 1 )
174 else if ( j < (
qgssize )width - 1 )
196 x22 = inputBlock->value( i, j );
198 x11 = inputBlock->isNoData( iUp, jLeft ) ? x22 : inputBlock->value( iUp, jLeft );
199 x21 = inputBlock->isNoData( i, jLeft ) ? x22 : inputBlock->value( i, jLeft );
200 x31 = inputBlock->isNoData( iDown, jLeft ) ? x22 : inputBlock->value( iDown, jLeft );
202 x12 = inputBlock->isNoData( iUp, j ) ? x22 : inputBlock->value( iUp, j );
204 x32 = inputBlock->isNoData( iDown, j ) ? x22 : inputBlock->value( iDown, j );
206 x13 = inputBlock->isNoData( iUp, jRight ) ? x22 : inputBlock->value( iUp, jRight );
207 x23 = inputBlock->isNoData( i, jRight ) ? x22 : inputBlock->value( i, jRight );
208 x33 = inputBlock->isNoData( iDown, jRight ) ? x22 : inputBlock->value( iDown, jRight );
210 double derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellXSize );
211 double derY = calcFirstDerY( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellYSize );
213 double slopeRad = std::atan( mZFactor * std::sqrt( derX * derX + derY * derY ) );
214 double aspectRad = std::atan2( derX, -derY );
218 if ( !mMultiDirectional )
221 grayValue = qBound( 0.0, 255.0 * ( cosZenithRad * std::cos( slopeRad )
222 + sinZenithRad * std::sin( slopeRad )
223 * std::cos( azimuthRad - aspectRad ) ), 255.0 );
228 double weight0 = std::sin( aspectRad - angle0Rad );
229 double weight1 = std::sin( aspectRad - angle1Rad );
230 double weight2 = std::sin( aspectRad - angle2Rad );
231 double weight3 = std::sin( aspectRad - angle3Rad );
232 weight0 = weight0 * weight0;
233 weight1 = weight1 * weight1;
234 weight2 = weight2 * weight2;
235 weight3 = weight3 * weight3;
237 double cosSlope = cosZenithRad * std::cos( slopeRad );
238 double sinSlope = sinZenithRad * std::sin( slopeRad );
239 double color0 = cosSlope + sinSlope * std::cos( angle0Rad - aspectRad );
240 double color1 = cosSlope + sinSlope * std::cos( angle1Rad - aspectRad );
241 double color2 = cosSlope + sinSlope * std::cos( angle2Rad - aspectRad );
242 double color3 = cosSlope + sinSlope * std::cos( angle3Rad - aspectRad );
243 grayValue = qBound( 0.0, 255 * ( weight0 * color0 + weight1 * color1 + weight2 * color2 + weight3 * color3 ) * 0.5, 255.0 );
253 currentAlpha *= alphaBlock->value( i ) / 255.0;
258 outputBlock->setColor( i, j, qRgba( grayValue, grayValue, grayValue, 255 ) );
262 outputBlock->setColor( i, j, qRgba( currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * 255 ) );
267 return outputBlock.release();
290 double QgsHillshadeRenderer::calcFirstDerX(
double x11,
double x21,
double x31,
double x12,
double x22,
double x32,
double x13,
double x23,
double x33,
double cellsize )
295 return ( ( x13 + x23 + x23 + x33 ) - ( x11 + x21 + x21 + x31 ) ) / ( 8 * cellsize );
298 double QgsHillshadeRenderer::calcFirstDerY(
double x11,
double x21,
double x31,
double x12,
double x22,
double x32,
double x13,
double x23,
double x33,
double cellsize )
303 return ( ( x31 + x32 + x32 + x33 ) - ( x11 + x12 + x12 + x13 ) ) / ( 8 * -cellsize );
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.
void setMultiDirectional(bool isMultiDirectional)
Sets whether to render using a multi-directional hillshade algorithm.
virtual QgsRectangle extent() const
Get the extent of the interface.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
virtual QgsRasterInterface * input() const
Current input.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void setBand(int bandNo)
Sets the band used by the renderer.
QgsRasterTransparency * mRasterTransparency
Raster transparency per color or value. Overwrites global alpha value.
void setZFactor(double zfactor)
Set the Z scaling factor of the result image.
int band() const
Returns the band used by the renderer.
static const QRgb NODATA_COLOR
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
QList< int > usesBands() const override
Returns a list of band numbers used by the renderer.
bool multiDirectional() const
Returns true if the renderer is using multi-directional hillshading.
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.
double width() const
Returns the width of the rectangle.
void _writeXml(QDomDocument &doc, QDomElement &rasterRendererElem) const
Write upper class info into rasterrenderer element (called by writeXml method of subclasses) ...
void copyCommonProperties(const QgsRasterRenderer *other, bool copyMinMaxOrigin=true)
Copies common properties like opacity / transparency data from other renderer.
A renderer for generating live hillshade models.
QgsHillshadeRenderer(QgsRasterInterface *input, int band, double lightAzimuth, double lightAltitude)
A renderer for generating live hillshade models.
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.
Base class for processing filters like renderers, reprojector, resampler etc.
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...
QgsHillshadeRenderer * clone() const override
Clone itself, create deep copy.
void writeXml(QDomDocument &doc, QDomElement &parentElem) const override
Write base class members to xml.
double mOpacity
Global alpha value (0-1)
double zFactor() const
Returns the Z scaling factor.
double azimuth() const
Returns the direction of the light over the raster between 0-360.
static QgsRasterRenderer * create(const QDomElement &elem, QgsRasterInterface *input)
Factory method to create a new renderer.
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
Raster renderer pipe that applies colors to a raster.
double height() const
Returns the height of the rectangle.