41 , mLightAngle( lightAngle )
42 , mLightAzimuth( lightAzimuth )
43 , mMultiDirectional( false )
65 int band = elem.attribute( QStringLiteral(
"band" ), QStringLiteral(
"0" ) ).toInt();
66 double azimuth = elem.attribute( QStringLiteral(
"azimuth" ), QStringLiteral(
"315" ) ).toDouble();
67 double angle = elem.attribute( QStringLiteral(
"angle" ), QStringLiteral(
"45" ) ).toDouble();
68 double zFactor = elem.attribute( QStringLiteral(
"zfactor" ), QStringLiteral(
"1" ) ).toDouble();
69 bool multiDirectional = elem.attribute( QStringLiteral(
"multidirection" ), QStringLiteral(
"0" ) ).toInt();
80 if ( parentElem.isNull() )
85 QDomElement rasterRendererElem = doc.createElement( QStringLiteral(
"rasterrenderer" ) );
88 rasterRendererElem.setAttribute( QStringLiteral(
"band" ), mBand );
89 rasterRendererElem.setAttribute( QStringLiteral(
"azimuth" ), QString::number( mLightAzimuth ) );
90 rasterRendererElem.setAttribute( QStringLiteral(
"angle" ), QString::number( mLightAngle ) );
91 rasterRendererElem.setAttribute( QStringLiteral(
"zfactor" ), QString::number( mZFactor ) );
92 rasterRendererElem.setAttribute( QStringLiteral(
"multidirection" ), QString::number( mMultiDirectional ) );
93 parentElem.appendChild( rasterRendererElem );
99 std::unique_ptr< QgsRasterBlock > outputBlock(
new QgsRasterBlock() );
102 QgsDebugMsg( QStringLiteral(
"No input raster!" ) );
103 return outputBlock.release();
106 std::shared_ptr< QgsRasterBlock > inputBlock(
mInput->
block( mBand,
extent, width, height, feedback ) );
108 if ( !inputBlock || inputBlock->isEmpty() )
110 QgsDebugMsg( QStringLiteral(
"No raster data!" ) );
111 return outputBlock.release();
114 std::shared_ptr< QgsRasterBlock > alphaBlock;
119 if ( !alphaBlock || alphaBlock->isEmpty() )
122 return outputBlock.release();
127 alphaBlock = inputBlock;
132 return outputBlock.release();
138 float cellXSize =
static_cast<float>(
extent.
width() ) / width;
139 float cellYSize =
static_cast<float>(
extent.
height() ) / height;
140 float zenithRad =
static_cast<float>( std::max( 0.0, 90 - mLightAngle ) * M_PI / 180.0 );
141 float azimuthRad =
static_cast<float>( -1 * mLightAzimuth * M_PI / 180.0 );
142 float cosZenithRad = std::cos( zenithRad );
143 float sinZenithRad = std::sin( zenithRad );
146 float cos_alt_mul_z = cosZenithRad *
static_cast<float>( mZFactor );
147 float cos_az_mul_cos_alt_mul_z = std::cos( azimuthRad ) * cos_alt_mul_z;
148 float sin_az_mul_cos_alt_mul_z = std::sin( azimuthRad ) * cos_alt_mul_z;
149 float cos_az_mul_cos_alt_mul_z_mul_254 = 254.0f * cos_az_mul_cos_alt_mul_z;
150 float sin_az_mul_cos_alt_mul_z_mul_254 = 254.0f * sin_az_mul_cos_alt_mul_z;
151 float square_z =
static_cast<float>( mZFactor * mZFactor );
152 float sin_altRadians_mul_254 = 254.0f * sinZenithRad;
155 float sin_altRadians_mul_127 = 127.0f * sinZenithRad;
157 float cos225_az_mul_cos_alt_mul_z_mul_127 = -32.87001872802012f * cos_alt_mul_z;
158 float cos_alt_mul_z_mul_127 = 127.0f * cos_alt_mul_z;
169 && inputBlock->dataTypeSize() <= 4 );
175 if ( source.isEmpty() )
183 std::chrono::time_point<std::chrono::system_clock> startTime( std::chrono::system_clock::now() );
191 std::size_t inputDataTypeSize = inputBlock->dataTypeSize();
192 std::size_t outputDataTypeSize = outputBlock->dataTypeSize();
195 switch ( inputBlock->dataType() )
197 case Qgis::DataType::Byte:
198 typeName = QStringLiteral(
"unsigned char" );
200 case Qgis::DataType::UInt16:
201 typeName = QStringLiteral(
"unsigned int" );
203 case Qgis::DataType::Int16:
204 typeName = QStringLiteral(
"short" );
206 case Qgis::DataType::UInt32:
207 typeName = QStringLiteral(
"unsigned int" );
209 case Qgis::DataType::Int32:
212 case Qgis::DataType::Float32:
213 typeName = QStringLiteral(
"float" );
216 throw QgsException( QStringLiteral(
"Unsupported data type for OpenCL processing." ) );
219 if ( inputBlock->dataType() != Qgis::DataType::Float32 )
221 source.replace( QStringLiteral(
"__global float *scanLine" ), QStringLiteral(
"__global %1 *scanLine" ).arg(
typeName ) );
225 std::size_t scanLineWidth( inputBlock->width() + 2 );
226 std::size_t inputSize( inputDataTypeSize * inputBlock->width() );
229 std::size_t bufferWidth( width + 2 );
230 std::size_t bufferSize( inputDataTypeSize * bufferWidth );
235 std::unique_ptr<QgsRasterBlock> scanLine = qgis::make_unique<QgsRasterBlock>( inputBlock->dataType(), scanLineWidth, 1 );
242 std::vector<float> rasterParams;
243 rasterParams.push_back( inputBlock->noDataValue() );
244 rasterParams.push_back( outputBlock->noDataValue() );
245 rasterParams.push_back( mZFactor );
246 rasterParams.push_back( cellXSize );
247 rasterParams.push_back( cellYSize );
248 rasterParams.push_back(
static_cast<float>(
mOpacity ) );
251 rasterParams.push_back( cos_az_mul_cos_alt_mul_z_mul_254 );
252 rasterParams.push_back( sin_az_mul_cos_alt_mul_z_mul_254 );
253 rasterParams.push_back( square_z );
254 rasterParams.push_back( sin_altRadians_mul_254 );
257 rasterParams.push_back( sin_altRadians_mul_127 );
258 rasterParams.push_back( cos225_az_mul_cos_alt_mul_z_mul_127 );
259 rasterParams.push_back( cos_alt_mul_z_mul_127 );
262 rasterParams.push_back(
static_cast<float>( qBlue( defaultNodataColor ) ) );
263 rasterParams.push_back(
static_cast<float>( qGreen( defaultNodataColor ) ) );
264 rasterParams.push_back(
static_cast<float>( qRed( defaultNodataColor ) ) );
265 rasterParams.push_back(
static_cast<float>( qAlpha( defaultNodataColor ) ) / 255.0f );
268 rasterParams.push_back(
static_cast<float>( mMultiDirectional ) );
270 cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(),
true,
false,
nullptr );
271 cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
272 cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
273 cl::Buffer scanLine3Buffer( ctx, CL_MEM_READ_ONLY, bufferSize,
nullptr,
nullptr );
274 cl::Buffer *scanLineBuffer[3] = {&scanLine1Buffer, &scanLine2Buffer, &scanLine3Buffer};
276 cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, outputDataTypeSize * width,
nullptr,
nullptr );
278 static std::map<Qgis::DataType, cl::Program> programCache;
279 cl::Program program = programCache[inputBlock->dataType()];
280 if ( ! program.get() )
284 program = programCache[inputBlock->dataType()];
291 auto kernel = cl::KernelFunctor <
297 > ( program,
"processNineCellWindow" );
301 std::vector<int> rowIndex = {0, 1, 2};
303 for (
int i = 0; i < height; i++ )
312 feedback->
setProgress( 100.0 *
static_cast< double >( i ) / height );
318 scanLine->resetNoDataValue();
319 queue.enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) );
321 memcpy( scanLine->bits( 0, 1 ), inputBlock->bits( i, 0 ), inputSize );
322 queue.enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) );
324 memcpy( scanLine->bits( 0, 1 ), inputBlock->bits( i + 1, 0 ), inputSize );
325 queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) );
331 if ( i == inputBlock->height() - 1 )
333 scanLine->resetNoDataValue();
334 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine->bits( ) );
338 queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, inputDataTypeSize * 1 , inputSize, inputBlock->bits( i + 1, 0 ) );
342 kernel( cl::EnqueueArgs(
346 *scanLineBuffer[rowIndex[0]],
347 *scanLineBuffer[rowIndex[1]],
348 *scanLineBuffer[rowIndex[2]],
353 queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, outputDataTypeSize * outputBlock->width( ), outputBlock->bits( i, 0 ) );
354 std::rotate( rowIndex.begin(), rowIndex.begin() + 1, rowIndex.end() );
357 catch ( cl::Error &e )
372 for (
qgssize i = 0; i < static_cast<qgssize>( height ); i++ )
375 for (
qgssize j = 0; j < static_cast<qgssize>( width ); j++ )
378 if ( inputBlock->isNoData( i, j ) )
380 outputBlock->setColor(
static_cast<int>( i ),
static_cast<int>( j ), defaultNodataColor );
384 qgssize iUp, iDown, jLeft, jRight;
390 else if ( i <
static_cast<qgssize>( height ) - 1 )
406 else if ( j <
static_cast<qgssize>( width ) - 1 )
428 x22 = inputBlock->value( i, j );
430 x11 = inputBlock->isNoData( iUp, jLeft ) ? x22 : inputBlock->value( iUp, jLeft );
431 x21 = inputBlock->isNoData( i, jLeft ) ? x22 : inputBlock->value( i, jLeft );
432 x31 = inputBlock->isNoData( iDown, jLeft ) ? x22 : inputBlock->value( iDown, jLeft );
434 x12 = inputBlock->isNoData( iUp, j ) ? x22 : inputBlock->value( iUp, j );
436 x32 = inputBlock->isNoData( iDown, j ) ? x22 : inputBlock->value( iDown, j );
438 x13 = inputBlock->isNoData( iUp, jRight ) ? x22 : inputBlock->value( iUp, jRight );
439 x23 = inputBlock->isNoData( i, jRight ) ? x22 : inputBlock->value( i, jRight );
440 x33 = inputBlock->isNoData( iDown, jRight ) ? x22 : inputBlock->value( iDown, jRight );
442 double derX = calcFirstDerX( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellXSize );
443 double derY = calcFirstDerY( x11, x21, x31, x12, x22, x32, x13, x23, x33, cellYSize );
448 if ( !mMultiDirectional )
451 grayValue = qBound( 0.0, ( sin_altRadians_mul_254 -
452 ( derY * cos_az_mul_cos_alt_mul_z_mul_254 -
453 derX * sin_az_mul_cos_alt_mul_z_mul_254 ) ) /
454 std::sqrt( 1 + square_z * ( derX * derX + derY * derY ) )
461 const float xx = derX * derX;
462 const float yy = derY * derY;
463 const float xx_plus_yy = xx + yy;
465 if ( xx_plus_yy == 0.0 )
467 grayValue = qBound( 0.0f,
static_cast<float>( 1.0 + sin_altRadians_mul_254 ), 255.0f );
472 float val225_mul_127 = sin_altRadians_mul_127 +
473 ( derX - derY ) * cos225_az_mul_cos_alt_mul_z_mul_127;
474 val225_mul_127 = ( val225_mul_127 <= 0.0 ) ? 0.0 : val225_mul_127;
475 float val270_mul_127 = sin_altRadians_mul_127 -
476 derX * cos_alt_mul_z_mul_127;
477 val270_mul_127 = ( val270_mul_127 <= 0.0 ) ? 0.0 : val270_mul_127;
478 float val315_mul_127 = sin_altRadians_mul_127 +
479 ( derX + derY ) * cos225_az_mul_cos_alt_mul_z_mul_127;
480 val315_mul_127 = ( val315_mul_127 <= 0.0 ) ? 0.0 : val315_mul_127;
481 float val360_mul_127 = sin_altRadians_mul_127 -
482 derY * cos_alt_mul_z_mul_127;
483 val360_mul_127 = ( val360_mul_127 <= 0.0 ) ? 0.0 : val360_mul_127;
486 const float weight_225 = 0.5 * xx_plus_yy - derX * derY;
487 const float weight_270 = xx;
488 const float weight_315 = xx_plus_yy - weight_225;
489 const float weight_360 = yy;
490 const float cang_mul_127 = (
491 ( weight_225 * val225_mul_127 +
492 weight_270 * val270_mul_127 +
493 weight_315 * val315_mul_127 +
494 weight_360 * val360_mul_127 ) / xx_plus_yy ) /
495 ( 1 + square_z * xx_plus_yy );
497 grayValue = qBound( 0.0f, 1.0f + cang_mul_127, 255.0f );
508 currentAlpha *= alphaBlock->value( i ) / 255.0;
513 outputBlock->setColor( i, j, qRgba( grayValue, grayValue, grayValue, 255 ) );
517 outputBlock->setColor( i, j, qRgba( currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * 255 ) );
526 if (
QgsSettings().value( QStringLiteral(
"Map/logCanvasRefreshEvent" ),
false ).toBool() )
529 .arg( useOpenCL ? QStringLiteral(
"OpenCL" ) : QStringLiteral(
"CPU" ) )
532 .arg( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now() - startTime ).count() ),
538 return outputBlock.release();
561 double QgsHillshadeRenderer::calcFirstDerX(
double x11,
double x21,
double x31,
double x12,
double x22,
double x32,
double x13,
double x23,
double x33,
double cellsize )
566 return ( ( x13 + x23 + x23 + x33 ) - ( x11 + x21 + x21 + x31 ) ) / ( 8 * cellsize );
569 double QgsHillshadeRenderer::calcFirstDerY(
double x11,
double x21,
double x31,
double x12,
double x22,
double x32,
double x13,
double x23,
double x33,
double cellsize )
574 return ( ( x31 + x32 + x32 + x33 ) - ( x11 + x12 + x12 + x13 ) ) / ( 8 * -cellsize );
583 QDomNodeList elements = element.elementsByTagName( QStringLiteral(
"sld:RasterSymbolizer" ) );
584 if ( elements.size() == 0 )
588 QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
595 QDomElement channelSelectionElem = doc.createElement( QStringLiteral(
"sld:ChannelSelection" ) );
596 elements = rasterSymbolizerElem.elementsByTagName( QStringLiteral(
"sld:Opacity" ) );
597 if ( elements.size() != 0 )
599 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
603 elements = rasterSymbolizerElem.elementsByTagName( QStringLiteral(
"sld:Geometry" ) );
604 if ( elements.size() != 0 )
606 rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
610 rasterSymbolizerElem.insertBefore( channelSelectionElem, rasterSymbolizerElem.firstChild() );
615 QDomElement channelElem = doc.createElement( QStringLiteral(
"sld:GrayChannel" ) );
616 channelSelectionElem.appendChild( channelElem );
619 QDomElement sourceChannelNameElem = doc.createElement( QStringLiteral(
"sld:SourceChannelName" ) );
620 sourceChannelNameElem.appendChild( doc.createTextNode( QString::number(
band() ) ) );
621 channelElem.appendChild( sourceChannelNameElem );
625 QDomElement shadedReliefElem = doc.createElement( QStringLiteral(
"sld:ShadedRelief" ) );
626 rasterSymbolizerElem.appendChild( shadedReliefElem );
629 QDomElement brightnessOnlyElem = doc.createElement( QStringLiteral(
"sld:BrightnessOnly" ) );
630 brightnessOnlyElem.appendChild( doc.createTextNode( QStringLiteral(
"true" ) ) );
631 shadedReliefElem.appendChild( brightnessOnlyElem );
634 QDomElement reliefFactorElem = doc.createElement( QStringLiteral(
"sld:ReliefFactor" ) );
635 reliefFactorElem.appendChild( doc.createTextNode( QString::number(
zFactor() ) ) );
636 shadedReliefElem.appendChild( reliefFactorElem );
639 QDomElement altitudeVendorOptionElem = doc.createElement( QStringLiteral(
"sld:VendorOption" ) );
640 altitudeVendorOptionElem.setAttribute( QStringLiteral(
"name" ), QStringLiteral(
"altitude" ) );
641 altitudeVendorOptionElem.appendChild( doc.createTextNode( QString::number(
altitude() ) ) );
642 shadedReliefElem.appendChild( altitudeVendorOptionElem );
645 QDomElement azimutVendorOptionElem = doc.createElement( QStringLiteral(
"sld:VendorOption" ) );
646 azimutVendorOptionElem.setAttribute( QStringLiteral(
"name" ), QStringLiteral(
"azimuth" ) );
647 azimutVendorOptionElem.appendChild( doc.createTextNode( QString::number(
azimuth() ) ) );
648 shadedReliefElem.appendChild( azimutVendorOptionElem );
651 QDomElement multidirectionalVendorOptionElem = doc.createElement( QStringLiteral(
"sld:VendorOption" ) );
652 multidirectionalVendorOptionElem.setAttribute( QStringLiteral(
"name" ), QStringLiteral(
"multidirectional" ) );
653 multidirectionalVendorOptionElem.appendChild( doc.createTextNode( QString::number(
multiDirectional() ) ) );
654 shadedReliefElem.appendChild( multidirectionalVendorOptionElem );