23 #include <QProgressDialog> 26 #include <cpl_string.h> 27 #include <gdalwarper.h> 28 #include <ogr_srs_api.h> 30 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 31 #define TO8(x) (x).toUtf8().constData() 32 #define TO8F(x) (x).toUtf8().constData() 34 #define TO8(x) (x).toLocal8Bit().constData() 35 #define TO8F(x) QFile::encodeName( x ).constData() 39 const QgsRectangle& outputExtent,
int nOutputColumns,
int nOutputRows,
const QVector<QgsRasterCalculatorEntry>& rasterEntries )
40 : mFormulaString( formulaString )
41 , mOutputFile( outputFile )
42 , mOutputFormat( outputFormat )
43 , mOutputRectangle( outputExtent )
44 , mNumOutputColumns( nOutputColumns )
45 , mNumOutputRows( nOutputRows )
46 , mRasterEntries( rasterEntries )
65 double targetGeoTransform[6];
66 outputGeoTransform( targetGeoTransform );
69 QMap< QString, GDALRasterBandH > mInputRasterBands;
70 QMap< QString, QgsRasterMatrix* > inputScanLineData;
71 QVector< GDALDatasetH > mInputDatasets;
73 QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin();
74 for ( ; it != mRasterEntries.constEnd(); ++it )
80 GDALDatasetH inputDataset = GDALOpen(
TO8F( it->raster->source() ), GA_ReadOnly );
87 double inputGeoTransform[6];
88 if ( GDALGetGeoTransform( inputDataset, inputGeoTransform ) == CE_None
89 && ( inputGeoTransform[1] < 0.0
90 || inputGeoTransform[2] != 0.0
91 || inputGeoTransform[4] != 0.0
92 || inputGeoTransform[5] > 0.0 ) )
94 GDALDatasetH vDataset = GDALAutoCreateWarpedVRT( inputDataset, NULL, NULL, GRA_NearestNeighbour, 0.2, NULL );
95 mInputDatasets.push_back( vDataset );
96 mInputDatasets.push_back( inputDataset );
97 inputDataset = vDataset;
101 mInputDatasets.push_back( inputDataset );
104 GDALRasterBandH inputRasterBand = GDALGetRasterBand( inputDataset, it->bandNumber );
105 if ( inputRasterBand == NULL )
111 double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess );
113 mInputRasterBands.insert( it->ref, inputRasterBand );
114 inputScanLineData.insert( it->ref,
new QgsRasterMatrix( mNumOutputColumns, 1,
new float[mNumOutputColumns], nodataValue ) );
118 GDALDriverH outputDriver = openOutputDriver();
119 if ( outputDriver == NULL )
123 GDALDatasetH outputDataset = openOutputFile( outputDriver );
126 if ( mRasterEntries.size() > 0 )
133 if ( OSRSetFromUserInput( ogrSRS, rl->
crs().
authid().toUtf8().constData() ) == OGRERR_NONE )
135 OSRExportToWkt( ogrSRS, &crsWKT );
136 GDALSetProjection( outputDataset, crsWKT );
140 GDALSetProjection( outputDataset,
TO8( rl->
crs().
toWkt() ) );
142 OSRDestroySpatialReference( ogrSRS );
148 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 );
150 float outputNodataValue = -FLT_MAX;
151 GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue );
153 float* resultScanLine = (
float * ) CPLMalloc(
sizeof(
float ) * mNumOutputColumns );
157 p->setMaximum( mNumOutputRows );
163 for (
int i = 0; i < mNumOutputRows; ++i )
170 if ( p && p->wasCanceled() )
176 QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
177 for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
179 double sourceTransformation[6];
180 GDALRasterBandH sourceRasterBand = mInputRasterBands[bufferIt.key()];
181 if ( GDALGetGeoTransform( GDALGetBandDataset( sourceRasterBand ), sourceTransformation ) != CE_None )
183 qWarning(
"GDALGetGeoTransform failed!" );
187 readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, bufferIt.value()->data() );
190 if ( calcNode->
calculate( inputScanLineData, resultMatrix ) )
192 bool resultIsNumber = resultMatrix.
isNumber();
195 if ( resultIsNumber )
197 calcData =
new float[mNumOutputColumns];
198 for (
int j = 0; j < mNumOutputColumns; ++j )
200 calcData[j] = resultMatrix.
number();
205 calcData = resultMatrix.
data();
209 for (
int j = 0; j < mNumOutputColumns; ++j )
213 calcData[j] = outputNodataValue;
218 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
220 qWarning(
"RasterIO error!" );
223 if ( resultIsNumber )
233 p->setValue( mNumOutputRows );
238 QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
239 for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
241 delete bufferIt.value();
243 inputScanLineData.clear();
245 QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets.begin();
246 for ( ; datasetIt != mInputDatasets.end(); ++ datasetIt )
248 GDALClose( *datasetIt );
251 if ( p && p->wasCanceled() )
254 GDALDeleteDataset( outputDriver,
TO8F( mOutputFile ) );
257 GDALClose( outputDataset );
258 CPLFree( resultScanLine );
263 : mNumOutputColumns( 0 )
264 , mNumOutputRows( 0 )
268 GDALDriverH QgsRasterCalculator::openOutputDriver()
270 char **driverMetadata;
273 GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() );
275 if ( outputDriver == NULL )
280 driverMetadata = GDALGetMetadata( outputDriver, NULL );
281 if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE,
false ) )
289 GDALDatasetH QgsRasterCalculator::openOutputFile( GDALDriverH outputDriver )
292 char **papszOptions = NULL;
293 GDALDatasetH outputDataset = GDALCreate( outputDriver,
TO8F( mOutputFile ), mNumOutputColumns, mNumOutputRows, 1, GDT_Float32, papszOptions );
294 if ( outputDataset == NULL )
296 return outputDataset;
300 double geotransform[6];
301 outputGeoTransform( geotransform );
302 GDALSetGeoTransform( outputDataset, geotransform );
304 return outputDataset;
307 void QgsRasterCalculator::readRasterPart(
double* targetGeotransform,
int xOffset,
int yOffset,
int nCols,
int nRows,
double* sourceTransform, GDALRasterBandH sourceBand,
float* rasterBuffer )
310 if ( transformationsEqual( targetGeotransform, sourceTransform ) )
312 GDALRasterIO( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0, 0 );
316 int sourceBandXSize = GDALGetRasterBandXSize( sourceBand );
317 int sourceBandYSize = GDALGetRasterBandYSize( sourceBand );
321 double nodataValue = GDALGetRasterNoDataValue( sourceBand, &nodataSuccess );
322 QgsRectangle targetRect( targetGeotransform[0] + targetGeotransform[1] * xOffset, targetGeotransform[3] + yOffset * targetGeotransform[5] + nRows * targetGeotransform[5]
323 , targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] * nCols, targetGeotransform[3] + yOffset * targetGeotransform[5] );
324 QgsRectangle sourceRect( sourceTransform[0], sourceTransform[3] + GDALGetRasterBandYSize( sourceBand ) * sourceTransform[5],
325 sourceTransform[0] + GDALGetRasterBandXSize( sourceBand )* sourceTransform[1], sourceTransform[3] );
331 int nPixels = nCols * nRows;
332 for (
int i = 0; i < nPixels; ++i )
334 rasterBuffer[i] = nodataValue;
340 int sourcePixelOffsetXMin = floor(( intersection.
xMinimum() - sourceTransform[0] ) / sourceTransform[1] );
341 int sourcePixelOffsetXMax = ceil(( intersection.
xMaximum() - sourceTransform[0] ) / sourceTransform[1] );
342 if ( sourcePixelOffsetXMax > sourceBandXSize )
344 sourcePixelOffsetXMax = sourceBandXSize;
346 int nSourcePixelsX = sourcePixelOffsetXMax - sourcePixelOffsetXMin;
348 int sourcePixelOffsetYMax = floor(( intersection.
yMaximum() - sourceTransform[3] ) / sourceTransform[5] );
349 int sourcePixelOffsetYMin = ceil(( intersection.
yMinimum() - sourceTransform[3] ) / sourceTransform[5] );
350 if ( sourcePixelOffsetYMin > sourceBandYSize )
352 sourcePixelOffsetYMin = sourceBandYSize;
354 int nSourcePixelsY = sourcePixelOffsetYMin - sourcePixelOffsetYMax;
355 float* sourceRaster = (
float * ) CPLMalloc(
sizeof(
float ) * nSourcePixelsX * nSourcePixelsY );
356 double sourceRasterXMin = sourceRect.
xMinimum() + sourcePixelOffsetXMin * sourceTransform[1];
357 double sourceRasterYMax = sourceRect.
yMaximum() + sourcePixelOffsetYMax * sourceTransform[5];
358 if ( GDALRasterIO( sourceBand, GF_Read, sourcePixelOffsetXMin, sourcePixelOffsetYMax, nSourcePixelsX, nSourcePixelsY,
359 sourceRaster, nSourcePixelsX, nSourcePixelsY, GDT_Float32, 0, 0 ) != CE_None )
362 CPLFree( sourceRaster );
363 int npixels = nRows * nCols;
364 for (
int i = 0; i < npixels; ++i )
366 rasterBuffer[i] = nodataValue;
373 double targetPixelXMin = targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] / 2.0;
374 double targetPixelY = targetGeotransform[3] + targetGeotransform[5] * yOffset + targetGeotransform[5] / 2.0;
375 int sourceIndexX, sourceIndexY;
377 for (
int i = 0; i < nRows; ++i )
379 targetPixelX = targetPixelXMin;
380 for (
int j = 0; j < nCols; ++j )
382 sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1];
383 sourceIndexX = sx > 0 ? sx : floor( sx );
384 sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5];
385 sourceIndexY = sy > 0 ? sy : floor( sy );
386 if ( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX
387 && sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY )
389 rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ];
393 rasterBuffer[j + i*j] = nodataValue;
395 targetPixelX += targetGeotransform[1];
397 targetPixelY += targetGeotransform[5];
400 CPLFree( sourceRaster );
404 bool QgsRasterCalculator::transformationsEqual(
double* t1,
double* t2 )
const 406 for (
int i = 0; i < 6; ++i )
416 void QgsRasterCalculator::outputGeoTransform(
double* transform )
const 418 transform[0] = mOutputRectangle.
xMinimum();
419 transform[1] = mOutputRectangle.
width() / mNumOutputColumns;
421 transform[3] = mOutputRectangle.
yMaximum();
423 transform[5] = -mOutputRectangle.
height() / mNumOutputRows;
A rectangle specified with double values.
bool isEmpty() const
test if rectangle is empty.
double yMaximum() const
Get the y maximum value (top side of rectangle)
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
int processCalculation(QProgressDialog *p=0)
Starts the calculation and writes new raster.
QgsRasterCalculator(const QString &formulaString, const QString &outputFile, const QString &outputFormat, const QgsRectangle &outputExtent, int nOutputColumns, int nOutputRows, const QVector< QgsRasterCalculatorEntry > &rasterEntries)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
double xMaximum() const
Get the x maximum value (right side of rectangle)
bool calculate(QMap< QString, QgsRasterMatrix * > &rasterData, QgsRasterMatrix &result) const
Calculates result (might be real matrix or single number)
bool isNumber() const
Returns true if matrix is 1x1 (=scalar number)
double nodataValue() const
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
static QgsRasterCalcNode * parseRasterCalcString(const QString &str, QString &parserErrorMsg)
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
float * data()
Returns data array (but not ownership)
double width() const
Width of the rectangle.
double xMinimum() const
Get the x minimum value (left side of rectangle)
double height() const
Height of the rectangle.
void * OGRSpatialReferenceH