31 #include <cpl_string.h> 32 #include <gdalwarper.h> 35 const QgsRectangle &outputExtent,
int nOutputColumns,
int nOutputRows,
const QVector<QgsRasterCalculatorEntry> &rasterEntries )
36 : mFormulaString( formulaString )
37 , mOutputFile( outputFile )
38 , mOutputFormat( outputFormat )
39 , mOutputRectangle( outputExtent )
40 , mNumOutputColumns( nOutputColumns )
41 , mNumOutputRows( nOutputRows )
42 , mRasterEntries( rasterEntries )
45 mOutputCrs = mRasterEntries.at( 0 ).raster->crs();
50 : mFormulaString( formulaString )
51 , mOutputFile( outputFile )
52 , mOutputFormat( outputFormat )
53 , mOutputRectangle( outputExtent )
54 , mOutputCrs( outputCrs )
55 , mNumOutputColumns( nOutputColumns )
56 , mNumOutputRows( nOutputRows )
57 , mRasterEntries( rasterEntries )
74 for (
const auto &entry : qgis::as_const( mRasterEntries ) )
78 mLastError = QObject::tr(
"No raster layer for entry %1" ).arg( entry.ref );
81 if ( entry.bandNumber <= 0 || entry.bandNumber > entry.raster->bandCount() )
83 mLastError = QObject::tr(
"Band number %1 is not valid for entry %2" ).arg( entry.bandNumber ).arg( entry.ref );
89 GDALDriverH outputDriver = openOutputDriver();
92 mLastError = QObject::tr(
"Could not obtain driver for %1" ).arg( mOutputFormat );
99 mLastError = QObject::tr(
"Could not create output %1" ).arg( mOutputFile );
103 GDALSetProjection( outputDataset.get(), mOutputCrs.
toWkt().toLocal8Bit().data() );
104 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset.get(), 1 );
106 float outputNodataValue = -FLT_MAX;
107 GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue );
112 bool requiresMatrix = ! calcNode->findNodes( QgsRasterCalcNode::Type::tMatrix ).isEmpty();
115 if ( ! requiresMatrix )
118 std::map<QString, std::unique_ptr<QgsRasterBlock>> inputBlocks;
119 std::map<QString, QgsRasterCalculatorEntry> uniqueRasterEntries;
120 for (
const auto &r : calcNode->findNodes( QgsRasterCalcNode::Type::tRasterRef ) )
122 QString layerRef( r->toString().remove( 0, 1 ) );
124 if ( ! inputBlocks.count( layerRef ) )
126 for (
const auto &ref : mRasterEntries )
128 if ( ref.ref == layerRef )
130 uniqueRasterEntries[layerRef] = ref;
131 inputBlocks[layerRef ] = qgis::make_unique<QgsRasterBlock>();
138 QMap<QString, QgsRasterBlock * > _rasterData;
140 std::vector<float> castedResult( static_cast<size_t>( mNumOutputColumns ), 0 );
141 auto rowHeight = mOutputRectangle.
height() / mNumOutputRows;
142 for (
size_t row = 0; row < static_cast<size_t>( mNumOutputRows ); ++row )
146 feedback->
setProgress( 100.0 * static_cast< double >( row ) / mNumOutputRows );
160 for (
auto &layerRef : inputBlocks )
163 if ( uniqueRasterEntries[layerRef.first].raster->crs() != mOutputCrs )
169 layerRef.second.reset( proj.
block( ref.
bandNumber, rect, mNumOutputColumns, 1 ) );
181 for (
const auto &layerRef : inputBlocks )
183 _rasterData.insert( layerRef.first, inputBlocks[layerRef.first].get() );
186 if ( calcNode->calculate( _rasterData, resultMatrix, 0 ) )
188 std::copy( resultMatrix.
data(), resultMatrix.
data() + mNumOutputColumns, castedResult.begin() );
189 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, row, mNumOutputColumns, 1, castedResult.data(), mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
191 QgsDebugMsg( QStringLiteral(
"RasterIO error!" ) );
203 QMap< QString, QgsRasterBlock * > inputBlocks;
204 QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin();
205 for ( ; it != mRasterEntries.constEnd(); ++it )
208 std::unique_ptr< QgsRasterBlock > block;
210 if ( it->raster->crs() != mOutputCrs )
213 proj.
setCrs( it->raster->crs(), mOutputCrs );
214 proj.
setInput( it->raster->dataProvider() );
219 block.reset( proj.
block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows, rasterBlockFeedback ) );
222 qDeleteAll( inputBlocks );
228 block.reset( it->raster->dataProvider()->block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows ) );
230 if ( block->isEmpty() )
232 mLastError = QObject::tr(
"Could not allocate required memory for %1" ).arg( it->ref );
233 qDeleteAll( inputBlocks );
236 inputBlocks.insert( it->ref, block.release() );
243 for (
int i = 0; i < mNumOutputRows; ++i )
247 feedback->
setProgress( 100.0 * static_cast< double >( i ) / mNumOutputRows );
255 if ( calcNode->calculate( inputBlocks, resultMatrix, i ) )
257 bool resultIsNumber = resultMatrix.
isNumber();
258 float *calcData =
new float[mNumOutputColumns];
260 for (
int j = 0; j < mNumOutputColumns; ++j )
262 calcData[j] = ( float )( resultIsNumber ? resultMatrix.
number() : resultMatrix.
data()[j] );
266 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
268 QgsDebugMsg( QStringLiteral(
"RasterIO error!" ) );
283 qDeleteAll( inputBlocks );
297 GDALDriverH QgsRasterCalculator::openOutputDriver()
300 GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() );
318 char **papszOptions =
nullptr;
319 gdal::dataset_unique_ptr outputDataset( GDALCreate( outputDriver, mOutputFile.toUtf8().constData(), mNumOutputColumns, mNumOutputRows, 1, GDT_Float32, papszOptions ) );
320 if ( !outputDataset )
326 double geotransform[6];
327 outputGeoTransform( geotransform );
328 GDALSetGeoTransform( outputDataset.get(), geotransform );
330 return outputDataset;
333 void QgsRasterCalculator::outputGeoTransform(
double *transform )
const 335 transform[0] = mOutputRectangle.
xMinimum();
336 transform[1] = mOutputRectangle.
width() / mNumOutputColumns;
338 transform[3] = mOutputRectangle.
yMaximum();
340 transform[5] = -mOutputRectangle.
height() / mNumOutputRows;
bool isCanceled() const
Tells whether the operation has been canceled already.
A rectangle specified with double values.
Result processCalculation(QgsFeedback *feedback=nullptr)
Starts the calculation and writes a new raster.
QgsRasterLayer * raster
Raster layer associated with entry.
void cancel()
Tells the internal routines that the current operation should be canceled. This should be run by the ...
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Error allocating memory for result.
void setNodataValue(double d)
void setProgress(double progress)
Sets the current progress for the feedback object.
QString toWkt() const
Returns a WKT representation of this CRS.
void canceled()
Internal routines can connect to this signal if they use event loop.
QgsRasterCalculator(const QString &formulaString, const QString &outputFile, const QString &outputFormat, const QgsRectangle &outputExtent, int nOutputColumns, int nOutputRows, const QVector< QgsRasterCalculatorEntry > &rasterEntries)
QgsRasterCalculator constructor.
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
int bandNumber
Band number for entry.
User canceled calculation.
void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
Base class for feedback objects to be used for cancellation of something running in a worker thread...
QgsRasterDataProvider * dataProvider() override
Returns the layer's data provider.
void CORE_EXPORT fast_delete_and_close(dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path)
Performs a fast close of an unwanted GDAL dataset handle by deleting the underlying data store...
Error reading input layer.
void setYMinimum(double y)
Set the minimum y value.
Error creating output data file.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Represents an individual raster layer/band number entry within a raster calculation.
Result
Result of the calculation.
bool isNumber() const
Returns true if matrix is 1x1 (=scalar number)
void setPrecision(Precision precision)
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
virtual bool setInput(QgsRasterInterface *input)
Set input.
QgsRasterBlock * block(int bandNo, const QgsRectangle &boundingBox, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
void setYMaximum(double y)
Set the maximum y value.
This class represents a coordinate reference system (CRS).
double * data()
Returns data array (but not ownership)
const QgsCoordinateReferenceSystem & outputCrs
static QgsRasterCalcNode * parseRasterCalcString(const QString &str, QString &parserErrorMsg)
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
QString lastError() const
Returns a description of the last error encountered.
Invalid band number for input.
double width() const
Returns the width of the rectangle.
Feedback object tailored for raster block reading.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
QgsCoordinateReferenceSystem crs
double height() const
Returns the height of the rectangle.