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 );
262 QgsRasterCalculator::QgsRasterCalculator()
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;