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 ); }