31 #include <cpl_string.h> 
   32 #include <gdalwarper.h> 
   44                                       const char *pszMessage,
 
   47   Q_UNUSED( pszMessage )
 
   49   static double sDfLastComplete = -1.0;
 
   53   if ( sDfLastComplete > dfComplete )
 
   55     if ( sDfLastComplete >= 1.0 )
 
   56       sDfLastComplete = -1.0;
 
   58       sDfLastComplete = dfComplete;
 
   61   if ( std::floor( sDfLastComplete * 10 ) != std::floor( dfComplete * 10 ) )
 
   66   sDfLastComplete = dfComplete;
 
   75   : mFormulaString( formulaString )
 
   76   , mOutputFile( outputFile )
 
   77   , mOutputFormat( outputFormat )
 
   78   , mOutputRectangle( outputExtent )
 
   79   , mNumOutputColumns( nOutputColumns )
 
   80   , mNumOutputRows( nOutputRows )
 
   81   , mRasterEntries( rasterEntries )
 
   82   , mTransformContext( transformContext )
 
   90   : mFormulaString( formulaString )
 
   91   , mOutputFile( outputFile )
 
   92   , mOutputFormat( outputFormat )
 
   93   , mOutputRectangle( outputExtent )
 
   95   , mNumOutputColumns( nOutputColumns )
 
   96   , mNumOutputRows( nOutputRows )
 
   97   , mRasterEntries( rasterEntries )
 
   98   , mTransformContext( transformContext )
 
  105     const QgsRectangle &outputExtent, 
int nOutputColumns, 
int nOutputRows, 
const QVector<QgsRasterCalculatorEntry> &rasterEntries )
 
  106   : mFormulaString( formulaString )
 
  107   , mOutputFile( outputFile )
 
  108   , mOutputFormat( outputFormat )
 
  109   , mOutputRectangle( outputExtent )
 
  110   , mNumOutputColumns( nOutputColumns )
 
  111   , mNumOutputRows( nOutputRows )
 
  112   , mRasterEntries( rasterEntries )
 
  115   mOutputCrs = mRasterEntries.at( 0 ).raster->crs();
 
  123   : mFormulaString( formulaString )
 
  124   , mOutputFile( outputFile )
 
  125   , mOutputFormat( outputFormat )
 
  126   , mOutputRectangle( outputExtent )
 
  128   , mNumOutputColumns( nOutputColumns )
 
  129   , mNumOutputRows( nOutputRows )
 
  130   , mRasterEntries( rasterEntries )
 
  131   , mTransformContext( 
QgsProject::instance()->transformContext() )
 
  148   for ( 
const auto &entry : std::as_const( mRasterEntries ) )
 
  152       mLastError = QObject::tr( 
"No raster layer for entry %1" ).arg( entry.ref );
 
  155     if ( entry.bandNumber <= 0 || entry.bandNumber > entry.raster->bandCount() )
 
  157       mLastError = QObject::tr( 
"Band number %1 is not valid for entry %2" ).arg( entry.bandNumber ).arg( entry.ref );
 
  165   bool requiresMatrix = ! calcNode->findNodes( QgsRasterCalcNode::Type::tMatrix ).isEmpty();
 
  171     return processCalculationGPU( std::move( calcNode ), feedback );
 
  176   GDALDriverH outputDriver = openOutputDriver();
 
  179     mLastError = QObject::tr( 
"Could not obtain driver for %1" ).arg( mOutputFormat );
 
  184   if ( !outputDataset )
 
  186     mLastError = QObject::tr( 
"Could not create output %1" ).arg( mOutputFile );
 
  191   GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
 
  193   float outputNodataValue = -FLT_MAX;
 
  194   GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue );
 
  198   if ( ! requiresMatrix )
 
  201     std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks;
 
  202     std::map<QString, QgsRasterCalculatorEntry> uniqueRasterEntries;
 
  203     const QList<const QgsRasterCalcNode *> rasterRefNodes = calcNode->findNodes( QgsRasterCalcNode::Type::tRasterRef );
 
  206       QString layerRef( r->toString().remove( 0, 1 ) );
 
  208       if ( ! inputBlocks.count( layerRef ) )
 
  212           if ( ref.ref == layerRef )
 
  214             uniqueRasterEntries[layerRef] = ref;
 
  215             inputBlocks[layerRef ] = std::make_unique<QgsRasterBlock>();
 
  222     QMap<QString, QgsRasterBlock * > _rasterData;
 
  224     std::vector<float> castedResult( 
static_cast<size_t>( mNumOutputColumns ), 0 );
 
  225     auto rowHeight = mOutputRectangle.
height() / mNumOutputRows;
 
  226     for ( 
size_t row = 0; row < static_cast<size_t>( mNumOutputRows ); ++row )
 
  230         feedback->
setProgress( 100.0 * 
static_cast< double >( row ) / mNumOutputRows );
 
  244       for ( 
auto &layerRef : inputBlocks )
 
  253           layerRef.second.reset( proj.
block( ref.
bandNumber, rect, mNumOutputColumns, 1 ) );
 
  262       QgsRasterMatrix resultMatrix( mNumOutputColumns, 1, 
nullptr, outputNodataValue );
 
  265       for ( 
const auto &layerRef : inputBlocks )
 
  267         _rasterData.insert( layerRef.first, layerRef.second.get() );
 
  270       if ( calcNode->calculate( _rasterData, resultMatrix, 0 ) )
 
  272         std::copy( resultMatrix.
data(), resultMatrix.
data() + mNumOutputColumns, castedResult.begin() );
 
  273         if ( GDALRasterIO( outputRasterBand, GF_Write, 0, row, mNumOutputColumns, 1, castedResult.data(), mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
 
  275           QgsDebugMsg( QStringLiteral( 
"RasterIO error!" ) );
 
  293     QMap< QString, QgsRasterBlock * > inputBlocks;
 
  294     QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin();
 
  295     for ( ; it != mRasterEntries.constEnd(); ++it )
 
  298       std::unique_ptr< QgsRasterBlock > block;
 
  300       if ( it->raster->crs() != mOutputCrs )
 
  303         proj.
setCrs( it->raster->crs(), mOutputCrs, it->raster->transformContext() );
 
  304         proj.
setInput( it->raster->dataProvider() );
 
  309         block.reset( proj.
block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows, rasterBlockFeedback ) );
 
  312           qDeleteAll( inputBlocks );
 
  318         block.reset( it->raster->dataProvider()->block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows ) );
 
  320       if ( block->isEmpty() )
 
  322         mLastError = QObject::tr( 
"Could not allocate required memory for %1" ).arg( it->ref );
 
  323         qDeleteAll( inputBlocks );
 
  326       inputBlocks.insert( it->ref, block.release() );
 
  333     for ( 
int i = 0; i < mNumOutputRows; ++i )
 
  337         feedback->
setProgress( 100.0 * 
static_cast< double >( i ) / mNumOutputRows );
 
  345       if ( calcNode->calculate( inputBlocks, resultMatrix, i ) )
 
  347         bool resultIsNumber = resultMatrix.
isNumber();
 
  348         float *calcData = 
new float[mNumOutputColumns];
 
  350         for ( 
int j = 0; j < mNumOutputColumns; ++j )
 
  352           calcData[j] = ( float )( resultIsNumber ? resultMatrix.
number() : resultMatrix.
data()[j] );
 
  356         if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
 
  358           QgsDebugMsg( QStringLiteral( 
"RasterIO error!" ) );
 
  365         qDeleteAll( inputBlocks );
 
  380     qDeleteAll( inputBlocks );
 
  392   GDALComputeRasterStatistics( outputRasterBand, 
true, 
nullptr, 
nullptr, 
nullptr, 
nullptr, 
GdalProgressCallback, feedback );
 
  401   QString cExpression( calcNode->toString( 
true ) );
 
  403   QList<const QgsRasterCalcNode *> nodeList( calcNode->findNodes( QgsRasterCalcNode::Type::tRasterRef ) );
 
  404   QSet<QString> capturedTexts;
 
  405   for ( 
const auto &r : std::as_const( nodeList ) )
 
  407     QString s( r->toString().remove( 0, 1 ) );
 
  409     capturedTexts.insert( s );
 
  426   std::vector<LayerRef> inputRefs;
 
  427   size_t refCounter = 0;
 
  428   for ( 
const auto &r : capturedTexts )
 
  430     if ( r.startsWith( 
'"' ) )
 
  432     QStringList parts( r.split( 
'@' ) );
 
  433     if ( parts.count() != 2 )
 
  438     entry.band = parts[1].toInt( &ok );
 
  439     for ( 
const auto &ref : std::as_const( mRasterEntries ) )
 
  441       if ( ref.ref == entry.name )
 
  442         entry.layer = ref.raster;
 
  444     if ( !( entry.layer && entry.layer->dataProvider() && ok ) )
 
  446     entry.dataSize = entry.layer->dataProvider()->dataTypeSize( entry.band );
 
  447     switch ( entry.layer->dataProvider()->dataType( entry.band ) )
 
  450         entry.typeName = QStringLiteral( 
"unsigned char" );
 
  453         entry.typeName = QStringLiteral( 
"unsigned int" );
 
  456         entry.typeName = QStringLiteral( 
"short" );
 
  459         entry.typeName = QStringLiteral( 
"unsigned int" );
 
  462         entry.typeName = QStringLiteral( 
"int" );
 
  465         entry.typeName = QStringLiteral( 
"float" );
 
  471         entry.typeName = QStringLiteral( 
"double" );
 
  476     entry.bufferSize = entry.dataSize * mNumOutputColumns;
 
  477     entry.index = refCounter;
 
  478     entry.varName = QStringLiteral( 
"input_raster_%1_band_%2" )
 
  481     inputRefs.push_back( entry );
 
  492     std::vector<cl::Buffer> inputBuffers;
 
  493     inputBuffers.reserve( inputRefs.size() );
 
  494     QStringList inputArgs;
 
  495     for ( 
const auto &ref : inputRefs )
 
  497       cExpression.replace( QStringLiteral( 
"\"%1\"" ).arg( ref.name ), QStringLiteral( 
"%1[i]" ).arg( ref.varName ) );
 
  498       inputArgs.append( QStringLiteral( 
"__global %1 *%2" )
 
  499                         .arg( ref.typeName, ref.varName ) );
 
  500       inputBuffers.push_back( cl::Buffer( ctx, CL_MEM_READ_ONLY, ref.bufferSize, 
nullptr, 
nullptr ) );
 
  506     QString programTemplate( R
"CL( 
  509     // Expression: ##EXPRESSION_ORIGINAL## 
  510     __kernel void rasterCalculator( ##INPUT## 
  511                               __global float *resultLine 
  514       // Get the index of the current element 
  515       const int i = get_global_id(0); 
  516       // Check for nodata in input 
  517       if ( ##INPUT_NODATA_CHECK## ) 
  518         resultLine[i] = -FLT_MAX; 
  521         resultLine[i] = ##EXPRESSION##; 
  525     QStringList inputDesc; 
  526     QStringList inputNoDataCheck; 
  527     for ( 
const auto &ref : inputRefs )
 
  529       inputDesc.append( QStringLiteral( 
"  // %1 = %2" ).arg( ref.varName, ref.name ) );
 
  530       if ( ref.layer->dataProvider()->sourceHasNoDataValue( ref.band ) )
 
  532         inputNoDataCheck.append( QStringLiteral( 
"(float) %1[i] == (float) %2" ).arg( ref.varName, QString::number( ref.layer->dataProvider()->sourceNoDataValue( ref.band ), 
'g', 10 ) ) );
 
  536     programTemplate = programTemplate.replace( QLatin1String( 
"##INPUT_NODATA_CHECK##" ), inputNoDataCheck.isEmpty() ? QStringLiteral( 
"false" ) : inputNoDataCheck.join( QLatin1String( 
" || " ) ) );
 
  537     programTemplate = programTemplate.replace( QLatin1String( 
"##INPUT_DESC##" ), inputDesc.join( 
'\n' ) );
 
  538     programTemplate = programTemplate.replace( QLatin1String( 
"##INPUT##" ), !inputArgs.isEmpty() ? ( inputArgs.join( 
',' ).append( 
',' ) ) : QChar( 
' ' ) );
 
  539     programTemplate = programTemplate.replace( QLatin1String( 
"##EXPRESSION##" ), cExpression );
 
  540     programTemplate = programTemplate.replace( QLatin1String( 
"##EXPRESSION_ORIGINAL##" ), calcNode->toString( ) );
 
  549     Q_ASSERT( 
sizeof( 
float ) == 4 );
 
  550     std::size_t resultBufferSize( 4 * 
static_cast<size_t>( mNumOutputColumns ) );
 
  551     cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY,
 
  552                                  resultBufferSize, 
nullptr, 
nullptr );
 
  554     auto kernel = cl::Kernel( program, 
"rasterCalculator" );
 
  556     for ( 
unsigned int i = 0; i < inputBuffers.size() ; i++ )
 
  558       kernel.setArg( i, inputBuffers.at( i ) );
 
  560     kernel.setArg( 
static_cast<unsigned int>( inputBuffers.size() ), resultLineBuffer );
 
  565     GDALDriverH outputDriver = openOutputDriver();
 
  568       mLastError = QObject::tr( 
"Could not obtain driver for %1" ).arg( mOutputFormat );
 
  573     if ( !outputDataset )
 
  575       mLastError = QObject::tr( 
"Could not create output %1" ).arg( mOutputFile );
 
  582     GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
 
  583     if ( !outputRasterBand )
 
  586     const float outputNodataValue = -FLT_MAX;
 
  587     GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue );
 
  590     std::unique_ptr<QgsRasterBlock> block;
 
  593     auto rowHeight = mOutputRectangle.
height() / mNumOutputRows;
 
  594     for ( 
int line = 0; line < mNumOutputRows; line++ )
 
  603         feedback->
setProgress( 100.0 * 
static_cast< double >( line ) / mNumOutputRows );
 
  607       for ( 
const auto &ref : inputRefs )
 
  611         rect.setYMaximum( rect.yMaximum() - rowHeight * line );
 
  612         rect.setYMinimum( rect.yMaximum() - rowHeight );
 
  616         if ( ref.layer->crs() != mOutputCrs )
 
  619           proj.
setCrs( ref.layer->crs(), mOutputCrs, ref.layer->transformContext() );
 
  620           proj.
setInput( ref.layer->dataProvider() );
 
  622           block.reset( proj.
block( ref.band, rect, mNumOutputColumns, 1 ) );
 
  626           block.reset( ref.layer->dataProvider()->block( ref.band, rect, mNumOutputColumns, 1 ) );
 
  633         Q_ASSERT( ref.bufferSize == 
static_cast<size_t>( block->data().size( ) ) );
 
  634         queue.enqueueWriteBuffer( inputBuffers[ref.index], CL_TRUE, 0,
 
  635                                   ref.bufferSize, block->bits() );
 
  639       queue.enqueueNDRangeKernel(
 
  642         cl::NDRange( mNumOutputColumns )
 
  646       queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0,
 
  647                                resultBufferSize, resultLine.get() );
 
  652       if ( GDALRasterIO( outputRasterBand, GF_Write, 0, line, mNumOutputColumns, 1, resultLine.get(), mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
 
  665     inputBuffers.clear();
 
  667     GDALComputeRasterStatistics( outputRasterBand, 
true, 
nullptr, 
nullptr, 
nullptr, 
nullptr, 
GdalProgressCallback, feedback );
 
  670   catch ( cl::Error &e )
 
  672     mLastError = e.what();
 
  680 GDALDriverH QgsRasterCalculator::openOutputDriver()
 
  683   GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() );
 
  701   char **papszOptions = 
nullptr;
 
  702   gdal::dataset_unique_ptr outputDataset( GDALCreate( outputDriver, mOutputFile.toUtf8().constData(), mNumOutputColumns, mNumOutputRows, 1, GDT_Float32, papszOptions ) );
 
  703   if ( !outputDataset )
 
  709   double geotransform[6];
 
  710   outputGeoTransform( geotransform );
 
  711   GDALSetGeoTransform( outputDataset.get(), geotransform );
 
  713   return outputDataset;
 
  716 void QgsRasterCalculator::outputGeoTransform( 
double *transform )
 const 
  718   transform[0] = mOutputRectangle.
xMinimum();
 
  719   transform[1] = mOutputRectangle.
width() / mNumOutputColumns;
 
  721   transform[3] = mOutputRectangle.
yMaximum();
 
  723   transform[5] = -mOutputRectangle.
height() / mNumOutputRows;
 
  733   QVector<QgsRasterCalculatorEntry> availableEntries;
 
  739     entry.ref = QStringLiteral( 
"%1@%2" ).arg( entry.raster->name() ).arg( entry.bandNumber );
 
  743       for ( 
const auto &
ref : std::as_const( availableEntries ) )
 
  746         if ( !( entry.raster && 
ref.raster ) )
 
  749         if ( 
ref.raster->publicSource() == entry.raster->publicSource() )
 
  751           if ( 
ref.bandNumber != entry.bandNumber )
 
  761         if ( 
ref.ref == entry.ref )
 
  764           entry.ref = QStringLiteral( 
"%1_%2@%3" ).arg( entry.raster->name() ).arg( i++ ).arg( entry.bandNumber );
 
  772   QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();
 
  773   for ( ; layerIt != layers.constEnd(); ++layerIt )
 
  775     QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer *>( layerIt.value() );
 
  779       for ( 
int i = 0; i < rlayer->
bandCount(); ++i )
 
  784         if ( ! uniqueRasterBandIdentifier( entry ) )
 
  786         availableEntries.push_back( entry );
 
  790   return availableEntries;