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
Gets number of bands.
A rectangle specified with double values.
void setMultiDirectional(bool isMultiDirectional)
Sets whether to render using a multi-directional hillshade algorithm.
virtual QgsRectangle extent() const
Gets 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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
virtual QgsRasterInterface * input() const
Current input.
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.
int alphaValue(double value, int globalTransparency=255) const
Returns the transparency value for a single value pixel.
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.