102  std::unique_ptr< QgsRasterBlock > outputBlock( 
new QgsRasterBlock() );
 
  106    return outputBlock.release();
 
  109  std::shared_ptr< QgsRasterBlock > inputBlock( 
mInput->
block( mBand, 
extent, width, height, feedback ) );
 
  111  if ( !inputBlock || inputBlock->isEmpty() )
 
  114    return outputBlock.release();
 
  117  std::shared_ptr< QgsRasterBlock > alphaBlock;
 
  122    if ( !alphaBlock || alphaBlock->isEmpty() )
 
  125      return outputBlock.release();
 
  130    alphaBlock = inputBlock;
 
  135    return outputBlock.release();
 
  138  if ( width == 0 || height == 0 )
 
  139    return outputBlock.release();
 
  144  float cellXSize = 
static_cast<float>( 
extent.
width() ) / width;
 
  145  float cellYSize = 
static_cast<float>( 
extent.
height() ) / height;
 
  146  float zenithRad = 
static_cast<float>( std::max( 0.0, 90 - mLightAngle ) * M_PI / 180.0 );
 
  147  float azimuthRad = 
static_cast<float>( -1 * mLightAzimuth * M_PI / 180.0 );
 
  148  float cosZenithRad = std::cos( zenithRad );
 
  149  float sinZenithRad = std::sin( zenithRad );
 
  152  float cos_alt_mul_z = cosZenithRad * 
static_cast<float>( mZFactor );
 
  153  float cos_az_mul_cos_alt_mul_z = std::cos( azimuthRad ) * cos_alt_mul_z;
 
  154  float sin_az_mul_cos_alt_mul_z = std::sin( azimuthRad ) * cos_alt_mul_z;
 
  155  float cos_az_mul_cos_alt_mul_z_mul_254 = 254.0f * cos_az_mul_cos_alt_mul_z;
 
  156  float sin_az_mul_cos_alt_mul_z_mul_254 = 254.0f * sin_az_mul_cos_alt_mul_z;
 
  157  float square_z = 
static_cast<float>( mZFactor * mZFactor );
 
  158  float sin_altRadians_mul_254 = 254.0f * sinZenithRad;
 
  161  float sin_altRadians_mul_127 = 127.0f * sinZenithRad;
 
  163  float cos225_az_mul_cos_alt_mul_z_mul_127 = -32.87001872802012f * cos_alt_mul_z;
 
  164  float cos_alt_mul_z_mul_127 = 127.0f * cos_alt_mul_z;
 
  175                  && inputBlock->dataTypeSize() <= 4 );
 
  181    if ( source.isEmpty() )
 
  189  std::chrono::time_point<std::chrono::system_clock> startTime( std::chrono::system_clock::now() );
 
  197      std::size_t inputDataTypeSize = inputBlock->dataTypeSize();
 
  198      std::size_t outputDataTypeSize = outputBlock->dataTypeSize();
 
  201      switch ( inputBlock->dataType() )
 
  204          typeName = QStringLiteral( 
"unsigned char" );
 
  207          typeName = QStringLiteral( 
"unsigned int" );
 
  210          typeName = QStringLiteral( 
"short" );
 
  213          typeName = QStringLiteral( 
"unsigned int" );
 
  219          typeName = QStringLiteral( 
"float" );
 
  222          throw QgsException( QStringLiteral( 
"Unsupported data type for OpenCL processing." ) );
 
  227        source.replace( QLatin1String( 
"__global float *scanLine" ), QStringLiteral( 
"__global %1 *scanLine" ).arg( 
typeName ) );
 
  231      std::size_t scanLineWidth( inputBlock->width() + 2 );
 
  232      std::size_t inputSize( inputDataTypeSize * inputBlock->width() );
 
  235      std::size_t bufferWidth( width + 2 );
 
  236      std::size_t bufferSize( inputDataTypeSize * bufferWidth );
 
  241      std::unique_ptr<QgsRasterBlock> scanLine = std::make_unique<QgsRasterBlock>( inputBlock->dataType(), scanLineWidth, 1 );
 
  248      std::vector<float> rasterParams;
 
  249      rasterParams.push_back( inputBlock->noDataValue() );
 
  250      rasterParams.push_back( outputBlock->noDataValue() );
 
  251      rasterParams.push_back( mZFactor );
 
  252      rasterParams.push_back( cellXSize );
 
  253      rasterParams.push_back( cellYSize );
 
  254      rasterParams.push_back( 
static_cast<float>( 
mOpacity ) ); 
 
  257      rasterParams.push_back( cos_az_mul_cos_alt_mul_z_mul_254 ); 
 
  258      rasterParams.push_back( sin_az_mul_cos_alt_mul_z_mul_254 ); 
 
  259      rasterParams.push_back( square_z ); 
 
  260      rasterParams.push_back( sin_altRadians_mul_254 ); 
 
  263      rasterParams.push_back( sin_altRadians_mul_127 ); 
 
  264      rasterParams.push_back( cos225_az_mul_cos_alt_mul_z_mul_127 ); 
 
  265      rasterParams.push_back( cos_alt_mul_z_mul_127 ); 
 
  268      rasterParams.push_back( 
static_cast<float>( qBlue( defaultNodataColor ) ) ); 
 
  269      rasterParams.push_back( 
static_cast<float>( qGreen( defaultNodataColor ) ) ); 
 
  270      rasterParams.push_back( 
static_cast<float>( qRed( defaultNodataColor ) ) ); 
 
  271      rasterParams.push_back( 
static_cast<float>( qAlpha( defaultNodataColor ) ) / 255.0f ); 
 
  274      rasterParams.push_back( 
static_cast<float>( mMultiDirectional ) ); 
 
  276      cl::Buffer rasterParamsBuffer( queue, rasterParams.begin(), rasterParams.end(), 
true, 
false, 
nullptr );
 
  277      cl::Buffer scanLine1Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, 
nullptr, 
nullptr );
 
  278      cl::Buffer scanLine2Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, 
nullptr, 
nullptr );
 
  279      cl::Buffer scanLine3Buffer( ctx, CL_MEM_READ_ONLY, bufferSize, 
nullptr, 
nullptr );
 
  280      cl::Buffer *scanLineBuffer[3] = {&scanLine1Buffer, &scanLine2Buffer, &scanLine3Buffer};
 
  282      cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, outputDataTypeSize * width, 
nullptr, 
nullptr );
 
  284      static std::map<Qgis::DataType, cl::Program> programCache;
 
  285      cl::Program program = programCache[inputBlock->dataType()];
 
  286      if ( ! program.get() )
 
  290        program = programCache[inputBlock->dataType()];
 
  297      auto kernel =  cl::KernelFunctor <
 
  303                     > ( program, 
"processNineCellWindow" );
 
  307      std::vector<int> rowIndex = {0, 1, 2};
 
  309      for ( 
int i = 0; i < height; i++ )
 
  318          feedback->
setProgress( 100.0 * 
static_cast< double >( i ) / height );
 
  324          scanLine->resetNoDataValue();
 
  325          queue.enqueueWriteBuffer( scanLine1Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) );
 
  327          memcpy( scanLine->bits( 0, 1 ), inputBlock->bits( i, 0 ), inputSize );
 
  328          queue.enqueueWriteBuffer( scanLine2Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) ); 
 
  330          memcpy( scanLine->bits( 0, 1 ), inputBlock->bits( i + 1, 0 ), inputSize );
 
  331          queue.enqueueWriteBuffer( scanLine3Buffer, CL_TRUE, 0, bufferSize, scanLine->bits( ) ); 
 
  337          if ( i == inputBlock->height() - 1 )
 
  339            scanLine->resetNoDataValue();
 
  340            queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, 0, bufferSize, scanLine->bits( ) );
 
  344            queue.enqueueWriteBuffer( *scanLineBuffer[rowIndex[2]], CL_TRUE, inputDataTypeSize * 1 , inputSize, inputBlock->bits( i + 1, 0 ) );
 
  348        kernel( cl::EnqueueArgs(
 
  352                *scanLineBuffer[rowIndex[0]],
 
  353                *scanLineBuffer[rowIndex[1]],
 
  354                *scanLineBuffer[rowIndex[2]],
 
  359        queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, outputDataTypeSize * outputBlock->width( ), outputBlock->bits( i, 0 ) );
 
  360        std::rotate( rowIndex.begin(), rowIndex.begin() + 1, rowIndex.end() );
 
  363    catch ( cl::Error &e )
 
  378    double pixelValues[9] {0, 0, 0, 0, 0, 0, 0, 0, 0};
 
  379    bool isNoData[9] {
false, 
false, 
false, 
false, 
false, 
false, 
false, 
false, 
false};
 
  381    for ( 
int row = 0; row < height; row++ )
 
  383      for ( 
int col = 0; col < width; col++ )
 
  391        else if ( row == height - 1 )
 
  399          pixelValues[ 0 ] = inputBlock->valueAndNoData( iUp, 0, isNoData[0] );
 
  400          pixelValues[ 1 ] = pixelValues[0];
 
  401          isNoData[1] = isNoData[0];
 
  402          pixelValues[ 2 ] = pixelValues[0];
 
  403          isNoData[2] = isNoData[0];
 
  405          pixelValues[ 3 ] = inputBlock->valueAndNoData( row, 0, isNoData[3] );
 
  406          pixelValues[ 4 ] = pixelValues[3];
 
  407          isNoData[4] = isNoData[3];
 
  408          pixelValues[ 5 ] = pixelValues[3];
 
  409          isNoData[5] = isNoData[3];
 
  411          pixelValues[ 6 ] = inputBlock->valueAndNoData( iDown, 0, isNoData[6] );
 
  412          pixelValues[ 7 ] = pixelValues[6];
 
  413          isNoData[7] = isNoData[6];
 
  414          pixelValues[ 8 ] = pixelValues[6];
 
  415          isNoData[8] = isNoData[6];
 
  420          pixelValues[ 0 ] = pixelValues[1];
 
  421          pixelValues[ 1 ] = pixelValues[2];
 
  422          pixelValues[ 3 ] = pixelValues[4];
 
  423          pixelValues[ 4 ] = pixelValues[5];
 
  424          pixelValues[ 6 ] = pixelValues[7];
 
  425          pixelValues[ 7 ] = pixelValues[8];
 
  426          isNoData[ 0 ] = isNoData[1];
 
  427          isNoData[ 1 ] = isNoData[2];
 
  428          isNoData[ 3 ] = isNoData[4];
 
  429          isNoData[ 4 ] = isNoData[5];
 
  430          isNoData[ 6 ] = isNoData[7];
 
  431          isNoData[ 7 ] = isNoData[8];
 
  435        if ( col < width - 1 )
 
  437          pixelValues[2] = inputBlock->valueAndNoData( iUp, col + 1, isNoData[2] );
 
  438          pixelValues[5] = inputBlock->valueAndNoData( row, col + 1, isNoData[5] );
 
  439          pixelValues[8] = inputBlock->valueAndNoData( iDown, col + 1, isNoData[8] );
 
  444          outputBlock->setColor( row, col, defaultNodataColor );
 
  449        const double x22 = pixelValues[4];
 
  451        const double x11 = isNoData[0] ? x22 : pixelValues[0];
 
  452        const double x21 = isNoData[3] ? x22 : pixelValues[3];
 
  453        const double x31 = isNoData[6] ? x22 : pixelValues[6];
 
  454        const double x12 = isNoData[1] ? x22 : pixelValues[1];
 
  456        const double x32 = isNoData[7] ? x22 : pixelValues[7];
 
  457        const double x13 = isNoData[2] ? x22 : pixelValues[2];
 
  458        const double x23 = isNoData[5] ? x22 : pixelValues[5];
 
  459        const double x33 = isNoData[8] ? x22 : pixelValues[8];
 
  462        const double derX = ( ( x13 + x23 + x23 + x33 ) - ( x11 + x21 + x21 + x31 ) ) / ( 8 * cellXSize );
 
  463        const double derY = ( ( x31 + x32 + x32 + x33 ) - ( x11 + x12 + x12 + x13 ) ) / ( 8 * -cellYSize );
 
  468        if ( !mMultiDirectional )
 
  471          grayValue = std::clamp( ( sin_altRadians_mul_254 -
 
  472                                    ( derY * cos_az_mul_cos_alt_mul_z_mul_254 -
 
  473                                      derX * sin_az_mul_cos_alt_mul_z_mul_254 ) ) /
 
  474                                  std::sqrt( 1 + square_z * ( derX * derX + derY * derY ) ),
 
  481          const float xx = derX * derX;
 
  482          const float yy = derY * derY;
 
  483          const float xx_plus_yy = xx + yy;
 
  485          if ( xx_plus_yy == 0.0 )
 
  487            grayValue = std::clamp( 
static_cast<float>( 1.0 + sin_altRadians_mul_254 ), 0.0f, 255.0f );
 
  492            float val225_mul_127 = sin_altRadians_mul_127 +
 
  493                                   ( derX - derY ) * cos225_az_mul_cos_alt_mul_z_mul_127;
 
  494            val225_mul_127 = ( val225_mul_127 <= 0.0 ) ? 0.0 : val225_mul_127;
 
  495            float val270_mul_127 = sin_altRadians_mul_127 -
 
  496                                   derX * cos_alt_mul_z_mul_127;
 
  497            val270_mul_127 = ( val270_mul_127 <= 0.0 ) ? 0.0 : val270_mul_127;
 
  498            float val315_mul_127 = sin_altRadians_mul_127 +
 
  499                                   ( derX + derY ) * cos225_az_mul_cos_alt_mul_z_mul_127;
 
  500            val315_mul_127 = ( val315_mul_127 <= 0.0 ) ? 0.0 : val315_mul_127;
 
  501            float val360_mul_127 = sin_altRadians_mul_127 -
 
  502                                   derY * cos_alt_mul_z_mul_127;
 
  503            val360_mul_127 = ( val360_mul_127 <= 0.0 ) ? 0.0 : val360_mul_127;
 
  506            const float weight_225 = 0.5 * xx_plus_yy - derX * derY;
 
  507            const float weight_270 = xx;
 
  508            const float weight_315 = xx_plus_yy - weight_225;
 
  509            const float weight_360 = yy;
 
  510            const float cang_mul_127 = (
 
  511                                         ( weight_225 * val225_mul_127 +
 
  512                                           weight_270 * val270_mul_127 +
 
  513                                           weight_315 * val315_mul_127 +
 
  514                                           weight_360 * val360_mul_127 ) / xx_plus_yy ) /
 
  515                                       ( 1 + square_z * xx_plus_yy );
 
  517            grayValue = std::clamp( 1.0f + cang_mul_127, 0.0f, 255.0f );
 
  528          currentAlpha *= alphaBlock->value( row ) / 255.0;
 
  533          outputBlock->setColor( row, col, qRgba( grayValue, grayValue, grayValue, 255 ) );
 
  537          outputBlock->setColor( row, col, qRgba( currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * grayValue, currentAlpha * 255 ) );
 
  546  if ( 
QgsSettings().value( QStringLiteral( 
"Map/logCanvasRefreshEvent" ), 
false ).toBool() )
 
  549                               .arg( useOpenCL ? QStringLiteral( 
"OpenCL" ) : QStringLiteral( 
"CPU" ) )
 
  552                               .arg( std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now() - startTime ).count() ),
 
  558  return outputBlock.release();
 
 
  603  QDomNodeList elements = element.elementsByTagName( QStringLiteral( 
"sld:RasterSymbolizer" ) );
 
  604  if ( elements.size() == 0 )
 
  608  QDomElement rasterSymbolizerElem = elements.at( 0 ).toElement();
 
  615    QDomElement channelSelectionElem = doc.createElement( QStringLiteral( 
"sld:ChannelSelection" ) );
 
  616    elements = rasterSymbolizerElem.elementsByTagName( QStringLiteral( 
"sld:Opacity" ) );
 
  617    if ( elements.size() != 0 )
 
  619      rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
 
  623      elements = rasterSymbolizerElem.elementsByTagName( QStringLiteral( 
"sld:Geometry" ) );
 
  624      if ( elements.size() != 0 )
 
  626        rasterSymbolizerElem.insertAfter( channelSelectionElem, elements.at( 0 ) );
 
  630        rasterSymbolizerElem.insertBefore( channelSelectionElem, rasterSymbolizerElem.firstChild() );
 
  635    QDomElement channelElem = doc.createElement( QStringLiteral( 
"sld:GrayChannel" ) );
 
  636    channelSelectionElem.appendChild( channelElem );
 
  639    QDomElement sourceChannelNameElem = doc.createElement( QStringLiteral( 
"sld:SourceChannelName" ) );
 
  640    sourceChannelNameElem.appendChild( doc.createTextNode( QString::number( mBand ) ) );
 
  641    channelElem.appendChild( sourceChannelNameElem );
 
  645  QDomElement shadedReliefElem = doc.createElement( QStringLiteral( 
"sld:ShadedRelief" ) );
 
  646  rasterSymbolizerElem.appendChild( shadedReliefElem );
 
  649  QDomElement brightnessOnlyElem = doc.createElement( QStringLiteral( 
"sld:BrightnessOnly" ) );
 
  650  brightnessOnlyElem.appendChild( doc.createTextNode( QStringLiteral( 
"true" ) ) );
 
  651  shadedReliefElem.appendChild( brightnessOnlyElem );
 
  654  QDomElement reliefFactorElem = doc.createElement( QStringLiteral( 
"sld:ReliefFactor" ) );
 
  655  reliefFactorElem.appendChild( doc.createTextNode( QString::number( 
zFactor() ) ) );
 
  656  shadedReliefElem.appendChild( reliefFactorElem );
 
  659  QDomElement altitudeVendorOptionElem = doc.createElement( QStringLiteral( 
"sld:VendorOption" ) );
 
  660  altitudeVendorOptionElem.setAttribute( QStringLiteral( 
"name" ), QStringLiteral( 
"altitude" ) );
 
  661  altitudeVendorOptionElem.appendChild( doc.createTextNode( QString::number( 
altitude() ) ) );
 
  662  shadedReliefElem.appendChild( altitudeVendorOptionElem );
 
  665  QDomElement azimutVendorOptionElem = doc.createElement( QStringLiteral( 
"sld:VendorOption" ) );
 
  666  azimutVendorOptionElem.setAttribute( QStringLiteral( 
"name" ), QStringLiteral( 
"azimuth" ) );
 
  667  azimutVendorOptionElem.appendChild( doc.createTextNode( QString::number( 
azimuth() ) ) );
 
  668  shadedReliefElem.appendChild( azimutVendorOptionElem );
 
  671  QDomElement multidirectionalVendorOptionElem = doc.createElement( QStringLiteral( 
"sld:VendorOption" ) );
 
  672  multidirectionalVendorOptionElem.setAttribute( QStringLiteral( 
"name" ), QStringLiteral( 
"multidirectional" ) );
 
  673  multidirectionalVendorOptionElem.appendChild( doc.createTextNode( QString::number( 
multiDirectional() ) ) );
 
  674  shadedReliefElem.appendChild( multidirectionalVendorOptionElem );