int QgsRasterCalculator::processCalculation( QProgressDialog* p ) { //prepare search string / tree QString errorString; QgsRasterCalcNode* calcNode = QgsRasterCalcNode::parseRasterCalcString( mFormulaString, errorString ); if ( !calcNode ) { //error } double targetGeoTransform[6]; outputGeoTransform( targetGeoTransform ); //open all input rasters for reading QMap< QString, GDALRasterBandH > mInputRasterBands; //raster references and corresponding scanline data QMap< QString, QgsRasterMatrix* > inputScanLineData; //stores raster references and corresponding scanline data QVector< GDALDatasetH > mInputDatasets; //raster references and corresponding dataset QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin(); for ( ; it != mRasterEntries.constEnd(); ++it ) { if ( !it->raster ) // no raster layer in entry { return 2; } GDALDatasetH inputDataset = GDALOpen( it->raster->source().toLocal8Bit().data(), GA_ReadOnly ); if ( inputDataset == NULL ) { return 2; } //check if the input dataset is south up or rotated. If yes, use GDALAutoCreateWarpedVRT to create a north up raster double inputGeoTransform[6]; if ( GDALGetGeoTransform( inputDataset, inputGeoTransform ) == CE_None && ( inputGeoTransform[1] < 0.0 || inputGeoTransform[2] != 0.0 || inputGeoTransform[4] != 0.0 || inputGeoTransform[5] > 0.0 ) ) { GDALDatasetH vDataset = GDALAutoCreateWarpedVRT( inputDataset, NULL, NULL, GRA_NearestNeighbour, 0.2, NULL ); mInputDatasets.push_back( vDataset ); mInputDatasets.push_back( inputDataset ); inputDataset = vDataset; } else { mInputDatasets.push_back( inputDataset ); } GDALRasterBandH inputRasterBand = GDALGetRasterBand( inputDataset, it->bandNumber ); if ( inputRasterBand == NULL ) { return 2; } int nodataSuccess; double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess ); mInputRasterBands.insert( it->ref, inputRasterBand ); inputScanLineData.insert( it->ref, new QgsRasterMatrix( mNumOutputColumns, 1, new float[mNumOutputColumns], nodataValue ) ); } //open output dataset for writing GDALDriverH outputDriver = openOutputDriver(); if ( outputDriver == NULL ) { return 1; } GDALDatasetH outputDataset = openOutputFile( outputDriver ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 ); float outputNodataValue = -FLT_MAX; GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue ); float* resultScanLine = ( float * ) CPLMalloc( sizeof( float ) * mNumOutputColumns ); if ( p ) { p->setMaximum( mNumOutputRows ); } QgsRasterMatrix resultMatrix; //read / write line by line for ( int i = 0; i < mNumOutputRows; ++i ) { if ( p ) { p->setValue( i ); } if ( p && p->wasCanceled() ) { break; } //fill buffers QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin(); for ( ; bufferIt != inputScanLineData.end(); ++bufferIt ) { double sourceTransformation[6]; GDALRasterBandH sourceRasterBand = mInputRasterBands[bufferIt.key()]; GDALGetGeoTransform( GDALGetBandDataset( sourceRasterBand ), sourceTransformation ); //the function readRasterPart calls GDALRasterIO (and ev. does some conversion if raster transformations are not the same) readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, bufferIt.value()->data() ); } if ( calcNode->calculate( inputScanLineData, resultMatrix ) ) { bool resultIsNumber = resultMatrix.isNumber(); float* calcData; if ( resultIsNumber ) //scalar result. Insert number for every pixel { calcData = new float[mNumOutputColumns]; for ( int j = 0; j < mNumOutputColumns; ++j ) { calcData[j] = resultMatrix.number(); } } else //result is real matrix { calcData = resultMatrix.data(); } //replace all matrix nodata values with output nodatas for ( int j = 0; j < mNumOutputColumns; ++j ) { if ( calcData[j] == resultMatrix.nodataValue() ) { calcData[j] = outputNodataValue; } } //write scanline to the dataset if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { qWarning( "RasterIO error!" ); } if ( resultIsNumber ) { delete[] calcData; } } } if ( p ) { p->setValue( mNumOutputRows ); } //close datasets and release memory delete calcNode; QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin(); for ( ; bufferIt != inputScanLineData.end(); ++bufferIt ) { delete bufferIt.value(); } inputScanLineData.clear(); QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets.begin(); for ( ; datasetIt != mInputDatasets.end(); ++ datasetIt ) { GDALClose( *datasetIt ); } if ( p && p->wasCanceled() ) { //delete the dataset without closing (because it is faster) GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() ); return 3; } GDALClose( outputDataset ); CPLFree( resultScanLine ); return 0; }
int QgsRasterCalculator::processCalculation( QProgressDialog* p ) { //prepare search string / tree QString errorString; QgsRasterCalcNode* calcNode = QgsRasterCalcNode::parseRasterCalcString( mFormulaString, errorString ); if ( !calcNode ) { //error return static_cast<int>( ParserError ); } QMap< QString, QgsRasterBlock* > inputBlocks; QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin(); for ( ; it != mRasterEntries.constEnd(); ++it ) { if ( !it->raster ) // no raster layer in entry { delete calcNode; qDeleteAll( inputBlocks ); return static_cast< int >( InputLayerError ); } QgsRasterBlock* block = nullptr; // if crs transform needed if ( it->raster->crs() != mOutputCrs ) { QgsRasterProjector proj; proj.setCRS( it->raster->crs(), mOutputCrs ); proj.setInput( it->raster->dataProvider() ); proj.setPrecision( QgsRasterProjector::Exact ); block = proj.block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows ); } else { block = it->raster->dataProvider()->block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows ); } if ( block->isEmpty() ) { delete block; delete calcNode; qDeleteAll( inputBlocks ); return static_cast<int>( MemoryError ); } inputBlocks.insert( it->ref, block ); } //open output dataset for writing GDALDriverH outputDriver = openOutputDriver(); if ( !outputDriver ) { return static_cast< int >( CreateOutputError ); } GDALDatasetH outputDataset = openOutputFile( outputDriver ); GDALSetProjection( outputDataset, mOutputCrs.toWkt().toLocal8Bit().data() ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 ); float outputNodataValue = -FLT_MAX; GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue ); if ( p ) { p->setMaximum( mNumOutputRows ); } QgsRasterMatrix resultMatrix; resultMatrix.setNodataValue( outputNodataValue ); //read / write line by line for ( int i = 0; i < mNumOutputRows; ++i ) { if ( p ) { p->setValue( i ); } if ( p && p->wasCanceled() ) { break; } if ( calcNode->calculate( inputBlocks, resultMatrix, i ) ) { bool resultIsNumber = resultMatrix.isNumber(); float* calcData = new float[mNumOutputColumns]; for ( int j = 0; j < mNumOutputColumns; ++j ) { calcData[j] = ( float )( resultIsNumber ? resultMatrix.number() : resultMatrix.data()[j] ); } //write scanline to the dataset if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { qWarning( "RasterIO error!" ); } delete[] calcData; } } if ( p ) { p->setValue( mNumOutputRows ); } //close datasets and release memory delete calcNode; qDeleteAll( inputBlocks ); inputBlocks.clear(); if ( p && p->wasCanceled() ) { //delete the dataset without closing (because it is faster) GDALDeleteDataset( outputDriver, TO8F( mOutputFile ) ); return static_cast< int >( Cancelled ); } GDALClose( outputDataset ); return static_cast< int >( Success ); }
QgsRasterCalculator::Result QgsRasterCalculator::processCalculation( QgsFeedback *feedback ) { mLastError.clear(); //prepare search string / tree std::unique_ptr< QgsRasterCalcNode > calcNode( QgsRasterCalcNode::parseRasterCalcString( mFormulaString, mLastError ) ); if ( !calcNode ) { //error return ParserError; } // Check input layers and bands for ( const auto &entry : qgis::as_const( mRasterEntries ) ) { if ( !entry.raster ) // no raster layer in entry { mLastError = QObject::tr( "No raster layer for entry %1" ).arg( entry.ref ); return InputLayerError; } if ( entry.bandNumber <= 0 || entry.bandNumber > entry.raster->bandCount() ) { mLastError = QObject::tr( "Band number %1 is not valid for entry %2" ).arg( entry.bandNumber ).arg( entry.ref ); return BandError; } } #ifdef HAVE_OPENCL // Check for matrix nodes, GPU implementation does not support them QList<const QgsRasterCalcNode *> nodeList; if ( QgsOpenClUtils::enabled() && QgsOpenClUtils::available() && calcNode->findNodes( QgsRasterCalcNode::Type::tMatrix ).isEmpty() ) return processCalculationGPU( std::move( calcNode ), feedback ); #endif //open output dataset for writing GDALDriverH outputDriver = openOutputDriver(); if ( !outputDriver ) { mLastError = QObject::tr( "Could not obtain driver for %1" ).arg( mOutputFormat ); return CreateOutputError; } gdal::dataset_unique_ptr outputDataset( openOutputFile( outputDriver ) ); if ( !outputDataset ) { mLastError = QObject::tr( "Could not create output %1" ).arg( mOutputFile ); return CreateOutputError; } GDALSetProjection( outputDataset.get(), mOutputCrs.toWkt().toLocal8Bit().data() ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 ); float outputNodataValue = -FLT_MAX; GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue ); // Check if we need to read the raster as a whole (which is memory inefficient // and not interruptable by the user) by checking if any raster matrix nodes are // in the expression bool requiresMatrix = ! calcNode->findNodes( QgsRasterCalcNode::Type::tMatrix ).isEmpty(); // Take the fast route (process one line at a time) if we can if ( ! requiresMatrix ) { // Map of raster names -> blocks std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks; std::map<QString, QgsRasterCalculatorEntry> uniqueRasterEntries; for ( const auto &r : calcNode->findNodes( QgsRasterCalcNode::Type::tRasterRef ) ) { QString layerRef( r->toString().remove( 0, 1 ) ); layerRef.chop( 1 ); if ( ! inputBlocks.count( layerRef ) ) { for ( const auto &ref : mRasterEntries ) { if ( ref.ref == layerRef ) { uniqueRasterEntries[layerRef] = ref; inputBlocks[layerRef ] = qgis::make_unique<QgsRasterBlock>(); } } } } //read / write line by line QMap<QString, QgsRasterBlock * > _rasterData; // Cast to float std::vector<float> castedResult; castedResult.reserve( static_cast<size_t>( mNumOutputColumns ) ); auto rowHeight = mOutputRectangle.height() / mNumOutputRows; for ( size_t row = 0; row < static_cast<size_t>( mNumOutputRows ); ++row ) { if ( feedback ) { feedback->setProgress( 100.0 * static_cast< double >( row ) / mNumOutputRows ); } if ( feedback && feedback->isCanceled() ) { break; } // Calculates the rect for a single row read QgsRectangle rect( mOutputRectangle ); rect.setYMaximum( rect.yMaximum() - rowHeight * row ); rect.setYMinimum( rect.yMaximum() - rowHeight ); // Read rows into input blocks for ( auto &layerRef : inputBlocks ) { QgsRasterCalculatorEntry ref = uniqueRasterEntries[layerRef.first]; if ( uniqueRasterEntries[layerRef.first].raster->crs() != mOutputCrs ) { QgsRasterProjector proj; proj.setCrs( ref.raster->crs(), mOutputCrs ); proj.setInput( ref.raster->dataProvider() ); proj.setPrecision( QgsRasterProjector::Exact ); layerRef.second.reset( proj.block( ref.bandNumber, rect, mNumOutputColumns, 1 ) ); } else { inputBlocks[layerRef.first].reset( ref.raster->dataProvider()->block( ref.bandNumber, rect, mNumOutputColumns, 1 ) ); } } QgsRasterMatrix resultMatrix; resultMatrix.setNodataValue( outputNodataValue ); _rasterData.clear(); for ( const auto &layerRef : inputBlocks ) { _rasterData.insert( layerRef.first, inputBlocks[layerRef.first].get() ); } if ( calcNode->calculate( _rasterData, resultMatrix, 0 ) ) { // write scanline to the dataset for ( size_t i = 0; i < static_cast<size_t>( mNumOutputColumns ); i++ ) { castedResult[i] = static_cast<float>( resultMatrix.data()[i] ); } if ( GDALRasterIO( outputRasterBand, GF_Write, 0, row, mNumOutputColumns, 1, castedResult.data(), mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( QStringLiteral( "RasterIO error!" ) ); } } } if ( feedback ) { feedback->setProgress( 100.0 ); } } else // Original code (memory inefficient route) { QMap< QString, QgsRasterBlock * > inputBlocks; QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin(); for ( ; it != mRasterEntries.constEnd(); ++it ) { std::unique_ptr< QgsRasterBlock > block; // if crs transform needed if ( it->raster->crs() != mOutputCrs ) { QgsRasterProjector proj; proj.setCrs( it->raster->crs(), mOutputCrs ); proj.setInput( it->raster->dataProvider() ); proj.setPrecision( QgsRasterProjector::Exact ); QgsRasterBlockFeedback *rasterBlockFeedback = new QgsRasterBlockFeedback(); QObject::connect( feedback, &QgsFeedback::canceled, rasterBlockFeedback, &QgsRasterBlockFeedback::cancel ); block.reset( proj.block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows, rasterBlockFeedback ) ); if ( rasterBlockFeedback->isCanceled() ) { qDeleteAll( inputBlocks ); return Canceled; } } else { block.reset( it->raster->dataProvider()->block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows ) ); } if ( block->isEmpty() ) { mLastError = QObject::tr( "Could not allocate required memory for %1" ).arg( it->ref ); qDeleteAll( inputBlocks ); return MemoryError; } inputBlocks.insert( it->ref, block.release() ); } QgsRasterMatrix resultMatrix; resultMatrix.setNodataValue( outputNodataValue ); //read / write line by line for ( int i = 0; i < mNumOutputRows; ++i ) { if ( feedback ) { feedback->setProgress( 100.0 * static_cast< double >( i ) / mNumOutputRows ); } if ( feedback && feedback->isCanceled() ) { break; } if ( calcNode->calculate( inputBlocks, resultMatrix, i ) ) { bool resultIsNumber = resultMatrix.isNumber(); float *calcData = new float[mNumOutputColumns]; for ( int j = 0; j < mNumOutputColumns; ++j ) { calcData[j] = ( float )( resultIsNumber ? resultMatrix.number() : resultMatrix.data()[j] ); } //write scanline to the dataset if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( QStringLiteral( "RasterIO error!" ) ); } delete[] calcData; } } if ( feedback ) { feedback->setProgress( 100.0 ); } //close datasets and release memory calcNode.reset(); qDeleteAll( inputBlocks ); inputBlocks.clear(); } if ( feedback && feedback->isCanceled() ) { //delete the dataset without closing (because it is faster) gdal::fast_delete_and_close( outputDataset, outputDriver, mOutputFile ); return Canceled; } return Success; }
QgsRasterCalculator::Result QgsRasterCalculator::processCalculationGPU( std::unique_ptr< QgsRasterCalcNode > calcNode, QgsFeedback *feedback ) { QString cExpression( calcNode->toString( true ) ); QList<const QgsRasterCalcNode *> nodeList( calcNode->findNodes( QgsRasterCalcNode::Type::tRasterRef ) ); QSet<QString> capturedTexts; for ( const auto &r : qgis::as_const( nodeList ) ) { QString s( r->toString().remove( 0, 1 ) ); s.chop( 1 ); capturedTexts.insert( s ); } // Extract all references struct LayerRef { QString name; int band; QgsRasterLayer *layer = nullptr; QString varName; QString typeName; size_t index; size_t bufferSize; size_t dataSize; }; // Collects all layers, band, name, varName and size information std::vector<LayerRef> inputRefs; size_t refCounter = 0; for ( const auto &r : capturedTexts ) { if ( r.startsWith( '"' ) ) continue; QStringList parts( r.split( '@' ) ); if ( parts.count() != 2 ) continue; bool ok = false; LayerRef entry; entry.name = r; entry.band = parts[1].toInt( &ok ); for ( const auto &ref : mRasterEntries ) { if ( ref.ref == entry.name ) entry.layer = ref.raster; } if ( !( entry.layer && entry.layer->dataProvider() && ok ) ) continue; entry.dataSize = entry.layer->dataProvider()->dataTypeSize( entry.band ); switch ( entry.layer->dataProvider()->dataType( entry.band ) ) { case Qgis::DataType::Byte: entry.typeName = QStringLiteral( "unsigned char" ); break; case Qgis::DataType::UInt16: entry.typeName = QStringLiteral( "unsigned int" ); break; case Qgis::DataType::Int16: entry.typeName = QStringLiteral( "short" ); break; case Qgis::DataType::UInt32: entry.typeName = QStringLiteral( "unsigned int" ); break; case Qgis::DataType::Int32: entry.typeName = QStringLiteral( "int" ); break; case Qgis::DataType::Float32: entry.typeName = QStringLiteral( "float" ); break; // FIXME: not sure all OpenCL implementations support double // maybe safer to fall back to the CPU implementation // after a compatibility check case Qgis::DataType::Float64: entry.typeName = QStringLiteral( "double" ); break; default: return BandError; } entry.bufferSize = entry.dataSize * mNumOutputColumns; entry.index = refCounter; entry.varName = QStringLiteral( "input_raster_%1_band_%2" ) .arg( refCounter++ ) .arg( entry.band ); inputRefs.push_back( entry ); } // Prepare context and queue cl::Context ctx( QgsOpenClUtils::context() ); cl::CommandQueue queue( QgsOpenClUtils::commandQueue() ); // Create the C expression std::vector<cl::Buffer> inputBuffers; inputBuffers.reserve( inputRefs.size() ); QStringList inputArgs; for ( const auto &ref : inputRefs ) { cExpression.replace( QStringLiteral( "\"%1\"" ).arg( ref.name ), QStringLiteral( "%1[i]" ).arg( ref.varName ) ); inputArgs.append( QStringLiteral( "__global %1 *%2" ) .arg( ref.typeName ) .arg( ref.varName ) ); inputBuffers.push_back( cl::Buffer( ctx, CL_MEM_READ_ONLY, ref.bufferSize, nullptr, nullptr ) ); } //qDebug() << cExpression; // Create the program QString programTemplate( R"CL( // Inputs: ##INPUT_DESC## // Expression: ##EXPRESSION_ORIGINAL## __kernel void rasterCalculator( ##INPUT## __global float *resultLine ) { // Get the index of the current element const int i = get_global_id(0); // Expression resultLine[i] = ##EXPRESSION##; } )CL" ); QStringList inputDesc; for ( const auto &ref : inputRefs ) { inputDesc.append( QStringLiteral( " // %1 = %2" ).arg( ref.varName ).arg( ref.name ) ); } programTemplate = programTemplate.replace( QStringLiteral( "##INPUT_DESC##" ), inputDesc.join( '\n' ) ); programTemplate = programTemplate.replace( QStringLiteral( "##INPUT##" ), inputArgs.length() ? ( inputArgs.join( ',' ).append( ',' ) ) : QChar( ' ' ) ); programTemplate = programTemplate.replace( QStringLiteral( "##EXPRESSION##" ), cExpression ); programTemplate = programTemplate.replace( QStringLiteral( "##EXPRESSION_ORIGINAL##" ), calcNode->toString( ) ); // qDebug() << programTemplate; // Create a program from the kernel source cl::Program program( QgsOpenClUtils::buildProgram( programTemplate, QgsOpenClUtils::ExceptionBehavior::Throw ) ); // Create the buffers, output is float32 (4 bytes) // We assume size of float = 4 because that's the size used by OpenCL and IEEE 754 Q_ASSERT( sizeof( float ) == 4 ); std::size_t resultBufferSize( 4 * static_cast<size_t>( mNumOutputColumns ) ); cl::Buffer resultLineBuffer( ctx, CL_MEM_WRITE_ONLY, resultBufferSize, nullptr, nullptr ); auto kernel = cl::Kernel( program, "rasterCalculator" ); for ( unsigned int i = 0; i < inputBuffers.size() ; i++ ) { kernel.setArg( i, inputBuffers.at( i ) ); } kernel.setArg( static_cast<unsigned int>( inputBuffers.size() ), resultLineBuffer ); QgsOpenClUtils::CPLAllocator<float> resultLine( static_cast<size_t>( mNumOutputColumns ) ); //open output dataset for writing GDALDriverH outputDriver = openOutputDriver(); if ( !outputDriver ) { mLastError = QObject::tr( "Could not obtain driver for %1" ).arg( mOutputFormat ); return CreateOutputError; } gdal::dataset_unique_ptr outputDataset( openOutputFile( outputDriver ) ); if ( !outputDataset ) { mLastError = QObject::tr( "Could not create output %1" ).arg( mOutputFile ); return CreateOutputError; } GDALSetProjection( outputDataset.get(), mOutputCrs.toWkt().toLocal8Bit().data() ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 ); if ( !outputRasterBand ) return BandError; // Input block (buffer) std::unique_ptr<QgsRasterBlock> block; // Run kernel on all scanlines auto rowHeight = mOutputRectangle.height() / mNumOutputRows; for ( int line = 0; line < mNumOutputRows; line++ ) { if ( feedback && feedback->isCanceled() ) { break; } if ( feedback ) { feedback->setProgress( 100.0 * static_cast< double >( line ) / mNumOutputRows ); } // Read lines from rasters into the buffers for ( const auto &ref : inputRefs ) { // Read one row QgsRectangle rect( mOutputRectangle ); rect.setYMaximum( rect.yMaximum() - rowHeight * line ); rect.setYMinimum( rect.yMaximum() - rowHeight ); // TODO: check if this is too slow // if crs transform needed if ( ref.layer->crs() != mOutputCrs ) { QgsRasterProjector proj; proj.setCrs( ref.layer->crs(), mOutputCrs ); proj.setInput( ref.layer->dataProvider() ); proj.setPrecision( QgsRasterProjector::Exact ); block.reset( proj.block( ref.band, rect, mNumOutputColumns, 1 ) ); } else { block.reset( ref.layer->dataProvider()->block( ref.band, rect, mNumOutputColumns, 1 ) ); } //for ( int i = 0; i < mNumOutputColumns; i++ ) // qDebug() << "Input: " << line << i << ref.varName << " = " << block->value( 0, i ); //qDebug() << "Writing buffer " << ref.index; Q_ASSERT( ref.bufferSize == static_cast<size_t>( block->data().size( ) ) ); queue.enqueueWriteBuffer( inputBuffers[ref.index], CL_TRUE, 0, ref.bufferSize, block->bits() ); } // Run the kernel queue.enqueueNDRangeKernel( kernel, 0, cl::NDRange( mNumOutputColumns ) ); // Write the result queue.enqueueReadBuffer( resultLineBuffer, CL_TRUE, 0, resultBufferSize, resultLine.get() ); //for ( int i = 0; i < mNumOutputColumns; i++ ) // qDebug() << "Output: " << line << i << " = " << resultLine[i]; if ( GDALRasterIO( outputRasterBand, GF_Write, 0, line, mNumOutputColumns, 1, resultLine.get(), mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { return CreateOutputError; } } if ( feedback && feedback->isCanceled() ) { //delete the dataset without closing (because it is faster) gdal::fast_delete_and_close( outputDataset, outputDriver, mOutputFile ); return Canceled; } inputBuffers.clear(); return Success; }
int QgsRelief::processRaster( QgsFeedback *feedback ) { //open input file int xSize, ySize; GDALDatasetH inputDataset = openInputFile( xSize, ySize ); if ( !inputDataset ) { return 1; //opening of input file failed } //output driver GDALDriverH outputDriver = openOutputDriver(); if ( !outputDriver ) { return 2; } GDALDatasetH outputDataset = openOutputFile( inputDataset, outputDriver ); if ( !outputDataset ) { return 3; //create operation on output file failed } //initialize dependency filters with cell sizes mHillshadeFilter285->setCellSizeX( mCellSizeX ); mHillshadeFilter285->setCellSizeY( mCellSizeY ); mHillshadeFilter285->setZFactor( mZFactor ); mHillshadeFilter300->setCellSizeX( mCellSizeX ); mHillshadeFilter300->setCellSizeY( mCellSizeY ); mHillshadeFilter300->setZFactor( mZFactor ); mHillshadeFilter315->setCellSizeX( mCellSizeX ); mHillshadeFilter315->setCellSizeY( mCellSizeY ); mHillshadeFilter315->setZFactor( mZFactor ); mSlopeFilter->setCellSizeX( mCellSizeX ); mSlopeFilter->setCellSizeY( mCellSizeY ); mSlopeFilter->setZFactor( mZFactor ); mAspectFilter->setCellSizeX( mCellSizeX ); mAspectFilter->setCellSizeY( mCellSizeY ); mAspectFilter->setZFactor( mZFactor ); //open first raster band for reading (operation is only for single band raster) GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, 1 ); if ( !rasterBand ) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 4; } mInputNodataValue = GDALGetRasterNoDataValue( rasterBand, nullptr ); mSlopeFilter->setInputNodataValue( mInputNodataValue ); mAspectFilter->setInputNodataValue( mInputNodataValue ); mHillshadeFilter285->setInputNodataValue( mInputNodataValue ); mHillshadeFilter300->setInputNodataValue( mInputNodataValue ); mHillshadeFilter315->setInputNodataValue( mInputNodataValue ); GDALRasterBandH outputRedBand = GDALGetRasterBand( outputDataset, 1 ); GDALRasterBandH outputGreenBand = GDALGetRasterBand( outputDataset, 2 ); GDALRasterBandH outputBlueBand = GDALGetRasterBand( outputDataset, 3 ); if ( !outputRedBand || !outputGreenBand || !outputBlueBand ) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 5; } //try to set -9999 as nodata value GDALSetRasterNoDataValue( outputRedBand, -9999 ); GDALSetRasterNoDataValue( outputGreenBand, -9999 ); GDALSetRasterNoDataValue( outputBlueBand, -9999 ); mOutputNodataValue = GDALGetRasterNoDataValue( outputRedBand, nullptr ); mSlopeFilter->setOutputNodataValue( mOutputNodataValue ); mAspectFilter->setOutputNodataValue( mOutputNodataValue ); mHillshadeFilter285->setOutputNodataValue( mOutputNodataValue ); mHillshadeFilter300->setOutputNodataValue( mOutputNodataValue ); mHillshadeFilter315->setOutputNodataValue( mOutputNodataValue ); if ( ySize < 3 ) //we require at least three rows (should be true for most datasets) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 6; } //keep only three scanlines in memory at a time float *scanLine1 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); float *scanLine2 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); float *scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); unsigned char *resultRedLine = ( unsigned char * ) CPLMalloc( sizeof( unsigned char ) * xSize ); unsigned char *resultGreenLine = ( unsigned char * ) CPLMalloc( sizeof( unsigned char ) * xSize ); unsigned char *resultBlueLine = ( unsigned char * ) CPLMalloc( sizeof( unsigned char ) * xSize ); bool resultOk; //values outside the layer extent (if the 3x3 window is on the border) are sent to the processing method as (input) nodata values for ( int i = 0; i < ySize; ++i ) { if ( feedback ) { feedback->setProgress( 100.0 * i / static_cast< double >( ySize ) ); } if ( feedback && feedback->isCanceled() ) { break; } if ( i == 0 ) { //fill scanline 1 with (input) nodata for the values above the first row and feed scanline2 with the first row for ( int a = 0; a < xSize; ++a ) { scanLine1[a] = mInputNodataValue; } if ( GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, scanLine2, xSize, 1, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } } else { //normally fetch only scanLine3 and release scanline 1 if we move forward one row CPLFree( scanLine1 ); scanLine1 = scanLine2; scanLine2 = scanLine3; scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); } if ( i == ySize - 1 ) //fill the row below the bottom with nodata values { for ( int a = 0; a < xSize; ++a ) { scanLine3[a] = mInputNodataValue; } } else { if ( GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, scanLine3, xSize, 1, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } } for ( int j = 0; j < xSize; ++j ) { if ( j == 0 ) { resultOk = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j + 1], &mInputNodataValue, &scanLine2[j], \ &scanLine2[j + 1], &mInputNodataValue, &scanLine3[j], &scanLine3[j + 1], \ &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] ); } else if ( j == xSize - 1 ) { resultOk = processNineCellWindow( &scanLine1[j - 1], &scanLine1[j], &mInputNodataValue, &scanLine2[j - 1], &scanLine2[j], \ &mInputNodataValue, &scanLine3[j - 1], &scanLine3[j], &mInputNodataValue, \ &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] ); } else { resultOk = processNineCellWindow( &scanLine1[j - 1], &scanLine1[j], &scanLine1[j + 1], &scanLine2[j - 1], &scanLine2[j], \ &scanLine2[j + 1], &scanLine3[j - 1], &scanLine3[j], &scanLine3[j + 1], \ &resultRedLine[j], &resultGreenLine[j], &resultBlueLine[j] ); } if ( !resultOk ) { resultRedLine[j] = mOutputNodataValue; resultGreenLine[j] = mOutputNodataValue; resultBlueLine[j] = mOutputNodataValue; } } if ( GDALRasterIO( outputRedBand, GF_Write, 0, i, xSize, 1, resultRedLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } if ( GDALRasterIO( outputGreenBand, GF_Write, 0, i, xSize, 1, resultGreenLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } if ( GDALRasterIO( outputBlueBand, GF_Write, 0, i, xSize, 1, resultBlueLine, xSize, 1, GDT_Byte, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } } if ( feedback ) { feedback->setProgress( 100 ); } CPLFree( resultRedLine ); CPLFree( resultBlueLine ); CPLFree( resultGreenLine ); CPLFree( scanLine1 ); CPLFree( scanLine2 ); CPLFree( scanLine3 ); GDALClose( inputDataset ); if ( feedback && feedback->isCanceled() ) { //delete the dataset without closing (because it is faster) GDALDeleteDataset( outputDriver, mOutputFile.toUtf8().constData() ); return 7; } GDALClose( outputDataset ); return 0; }
int QgsNineCellFilter::processRaster( QProgressDialog* p ) { GDALAllRegister(); //open input file int xSize, ySize; GDALDatasetH inputDataset = openInputFile( xSize, ySize ); if ( inputDataset == NULL ) { return 1; //opening of input file failed } //output driver GDALDriverH outputDriver = openOutputDriver(); if ( outputDriver == 0 ) { return 2; } GDALDatasetH outputDataset = openOutputFile( inputDataset, outputDriver ); if ( outputDataset == NULL ) { return 3; //create operation on output file failed } //open first raster band for reading (operation is only for single band raster) GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, 1 ); if ( rasterBand == NULL ) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 4; } mInputNodataValue = GDALGetRasterNoDataValue( rasterBand, NULL ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 ); if ( outputRasterBand == NULL ) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 5; } //try to set -9999 as nodata value GDALSetRasterNoDataValue( outputRasterBand, -9999 ); mOutputNodataValue = GDALGetRasterNoDataValue( outputRasterBand, NULL ); if ( ySize < 3 ) //we require at least three rows (should be true for most datasets) { GDALClose( inputDataset ); GDALClose( outputDataset ); return 6; } //keep only three scanlines in memory at a time float* scanLine1 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); float* scanLine2 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); float* scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); float* resultLine = ( float * ) CPLMalloc( sizeof( float ) * xSize ); if ( p ) { p->setMaximum( ySize ); } //values outside the layer extent (if the 3x3 window is on the border) are sent to the processing method as (input) nodata values for ( int i = 0; i < ySize; ++i ) { if ( p ) { p->setValue( i ); } if ( p && p->wasCanceled() ) { break; } if ( i == 0 ) { //fill scanline 1 with (input) nodata for the values above the first row and feed scanline2 with the first row for ( int a = 0; a < xSize; ++a ) { scanLine1[a] = mInputNodataValue; } GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, scanLine2, xSize, 1, GDT_Float32, 0, 0 ); } else { //normally fetch only scanLine3 and release scanline 1 if we move forward one row CPLFree( scanLine1 ); scanLine1 = scanLine2; scanLine2 = scanLine3; scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize ); } if ( i == ySize - 1 ) //fill the row below the bottom with nodata values { for ( int a = 0; a < xSize; ++a ) { scanLine3[a] = mInputNodataValue; } } else { GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, scanLine3, xSize, 1, GDT_Float32, 0, 0 ); } for ( int j = 0; j < xSize; ++j ) { if ( j == 0 ) { resultLine[j] = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j], \ &scanLine2[j+1], &mInputNodataValue, &scanLine3[j], &scanLine3[j+1] ); } else if ( j == xSize - 1 ) { resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j], \ &mInputNodataValue, &scanLine3[j-1], &scanLine3[j], &mInputNodataValue ); } else { resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j], \ &scanLine2[j+1], &scanLine3[j-1], &scanLine3[j], &scanLine3[j+1] ); } } GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine, xSize, 1, GDT_Float32, 0, 0 ); } if ( p ) { p->setValue( ySize ); } CPLFree( resultLine ); CPLFree( scanLine1 ); CPLFree( scanLine2 ); CPLFree( scanLine3 ); GDALClose( inputDataset ); if ( p && p->wasCanceled() ) { //delete the dataset without closing (because it is faster) GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() ); return 7; } GDALClose( outputDataset ); return 0; }