22 #include "cpl_string.h"
23 #include <QProgressDialog>
26 #include "gdalwarper.h"
27 #include <ogr_srs_api.h>
29 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
30 #define TO8(x) (x).toUtf8().constData()
31 #define TO8F(x) (x).toUtf8().constData()
33 #define TO8(x) (x).toLocal8Bit().constData()
34 #define TO8F(x) QFile::encodeName( x ).constData()
38 const QgsRectangle& outputExtent,
int nOutputColumns,
int nOutputRows,
const QVector<QgsRasterCalculatorEntry>& rasterEntries ): mFormulaString( formulaString ), mOutputFile( outputFile ), mOutputFormat( outputFormat ),
39 mOutputRectangle( outputExtent ), mNumOutputColumns( nOutputColumns ), mNumOutputRows( nOutputRows ), mRasterEntries( rasterEntries )
57 double targetGeoTransform[6];
61 QMap< QString, GDALRasterBandH > mInputRasterBands;
62 QMap< QString, QgsRasterMatrix* > inputScanLineData;
63 QVector< GDALDatasetH > mInputDatasets;
65 QVector<QgsRasterCalculatorEntry>::const_iterator it =
mRasterEntries.constBegin();
72 GDALDatasetH inputDataset = GDALOpen(
TO8F( it->raster->source() ), GA_ReadOnly );
73 if ( inputDataset == NULL )
79 double inputGeoTransform[6];
80 if ( GDALGetGeoTransform( inputDataset, inputGeoTransform ) == CE_None
81 && ( inputGeoTransform[1] < 0.0
82 || inputGeoTransform[2] != 0.0
83 || inputGeoTransform[4] != 0.0
84 || inputGeoTransform[5] > 0.0 ) )
86 GDALDatasetH vDataset = GDALAutoCreateWarpedVRT( inputDataset, NULL, NULL, GRA_NearestNeighbour, 0.2, NULL );
87 mInputDatasets.push_back( vDataset );
88 mInputDatasets.push_back( inputDataset );
89 inputDataset = vDataset;
93 mInputDatasets.push_back( inputDataset );
97 GDALRasterBandH inputRasterBand = GDALGetRasterBand( inputDataset, it->bandNumber );
98 if ( inputRasterBand == NULL )
104 double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess );
106 mInputRasterBands.insert( it->ref, inputRasterBand );
112 if ( outputDriver == NULL )
126 if ( OSRSetFromUserInput( ogrSRS, rl->
crs().
authid().toUtf8().constData() ) == OGRERR_NONE )
128 OSRExportToWkt( ogrSRS, &crsWKT );
129 GDALSetProjection( outputDataset, crsWKT );
133 GDALSetProjection( outputDataset,
TO8( rl->
crs().
toWkt() ) );
135 OSRDestroySpatialReference( ogrSRS );
141 GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 );
143 float outputNodataValue = -FLT_MAX;
144 GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue );
146 float* resultScanLine = (
float * ) CPLMalloc(
sizeof(
float ) *
mNumOutputColumns );
163 if ( p && p->wasCanceled() )
169 QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
170 for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
172 double sourceTransformation[6];
173 GDALRasterBandH sourceRasterBand = mInputRasterBands[bufferIt.key()];
174 GDALGetGeoTransform( GDALGetBandDataset( sourceRasterBand ), sourceTransformation );
179 if ( calcNode->
calculate( inputScanLineData, resultMatrix ) )
181 bool resultIsNumber = resultMatrix.
isNumber();
184 if ( resultIsNumber )
189 calcData[j] = resultMatrix.
number();
194 calcData = resultMatrix.
data();
202 calcData[j] = outputNodataValue;
207 if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
209 qWarning(
"RasterIO error!" );
212 if ( resultIsNumber )
222 p->setValue( mNumOutputRows );
227 QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
228 for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
230 delete bufferIt.value();
232 inputScanLineData.clear();
234 QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets.begin();
235 for ( ; datasetIt != mInputDatasets.end(); ++ datasetIt )
237 GDALClose( *datasetIt );
240 if ( p && p->wasCanceled() )
246 GDALClose( outputDataset );
247 CPLFree( resultScanLine );
257 char **driverMetadata;
260 GDALDriverH outputDriver = GDALGetDriverByName(
mOutputFormat.toLocal8Bit().data() );
262 if ( outputDriver == NULL )
267 driverMetadata = GDALGetMetadata( outputDriver, NULL );
268 if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE,
false ) )
279 char **papszOptions = NULL;
281 if ( outputDataset == NULL )
283 return outputDataset;
287 double geotransform[6];
289 GDALSetGeoTransform( outputDataset, geotransform );
291 return outputDataset;
294 void QgsRasterCalculator::readRasterPart(
double* targetGeotransform,
int xOffset,
int yOffset,
int nCols,
int nRows,
double* sourceTransform, GDALRasterBandH sourceBand,
float* rasterBuffer )
299 GDALRasterIO( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0, 0 );
303 int sourceBandXSize = GDALGetRasterBandXSize( sourceBand );
304 int sourceBandYSize = GDALGetRasterBandYSize( sourceBand );
308 double nodataValue = GDALGetRasterNoDataValue( sourceBand, &nodataSuccess );
309 QgsRectangle targetRect( targetGeotransform[0] + targetGeotransform[1] * xOffset, targetGeotransform[3] + yOffset * targetGeotransform[5] + nRows * targetGeotransform[5]
310 , targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] * nCols, targetGeotransform[3] + yOffset * targetGeotransform[5] );
311 QgsRectangle sourceRect( sourceTransform[0], sourceTransform[3] + GDALGetRasterBandYSize( sourceBand ) * sourceTransform[5],
312 sourceTransform[0] + GDALGetRasterBandXSize( sourceBand )* sourceTransform[1], sourceTransform[3] );
318 int nPixels = nCols * nRows;
319 for (
int i = 0; i < nPixels; ++i )
321 rasterBuffer[i] = nodataValue;
327 int sourcePixelOffsetXMin = floor(( intersection.
xMinimum() - sourceTransform[0] ) / sourceTransform[1] );
328 int sourcePixelOffsetXMax = ceil(( intersection.
xMaximum() - sourceTransform[0] ) / sourceTransform[1] );
329 if ( sourcePixelOffsetXMax > sourceBandXSize )
331 sourcePixelOffsetXMax = sourceBandXSize;
333 int nSourcePixelsX = sourcePixelOffsetXMax - sourcePixelOffsetXMin;
335 int sourcePixelOffsetYMax = floor(( intersection.
yMaximum() - sourceTransform[3] ) / sourceTransform[5] );
336 int sourcePixelOffsetYMin = ceil(( intersection.
yMinimum() - sourceTransform[3] ) / sourceTransform[5] );
337 if ( sourcePixelOffsetYMin > sourceBandYSize )
339 sourcePixelOffsetYMin = sourceBandYSize;
341 int nSourcePixelsY = sourcePixelOffsetYMin - sourcePixelOffsetYMax;
342 float* sourceRaster = (
float * ) CPLMalloc(
sizeof(
float ) * nSourcePixelsX * nSourcePixelsY );
343 double sourceRasterXMin = sourceRect.
xMinimum() + sourcePixelOffsetXMin * sourceTransform[1];
344 double sourceRasterYMax = sourceRect.
yMaximum() + sourcePixelOffsetYMax * sourceTransform[5];
345 if ( GDALRasterIO( sourceBand, GF_Read, sourcePixelOffsetXMin, sourcePixelOffsetYMax, nSourcePixelsX, nSourcePixelsY,
346 sourceRaster, nSourcePixelsX, nSourcePixelsY, GDT_Float32, 0, 0 ) != CE_None )
349 CPLFree( sourceRaster );
350 int npixels = nRows * nCols;
351 for (
int i = 0; i < npixels; ++i )
353 rasterBuffer[i] = nodataValue;
360 double targetPixelXMin = targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] / 2.0;
361 double targetPixelY = targetGeotransform[3] + targetGeotransform[5] * yOffset + targetGeotransform[5] / 2.0;
362 int sourceIndexX, sourceIndexY;
364 for (
int i = 0; i < nRows; ++i )
366 targetPixelX = targetPixelXMin;
367 for (
int j = 0; j < nCols; ++j )
369 sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1];
370 sourceIndexX = sx > 0 ? sx : floor( sx );
371 sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5];
372 sourceIndexY = sy > 0 ? sy : floor( sy );
373 if ( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX
374 && sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY )
376 rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ];
380 rasterBuffer[j + i*j] = nodataValue;
382 targetPixelX += targetGeotransform[1];
384 targetPixelY += targetGeotransform[5];
387 CPLFree( sourceRaster );
393 for (
int i = 0; i < 6; ++i )
QgsRectangle mOutputRectangle
Output raster extent.
A rectangle specified with double values.
bool isEmpty() const
test if rectangle is empty
int mNumOutputColumns
Number of output columns.
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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
int mNumOutputRows
Number of output rows.
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)
void readRasterPart(double *targetGeotransform, int xOffset, int yOffset, int nCols, int nRows, double *sourceTransform, GDALRasterBandH sourceBand, float *rasterBuffer)
Reads raster pixels from a dataset/band.
QVector< QgsRasterCalculatorEntry > mRasterEntries
bool transformationsEqual(double *t1, double *t2) const
Compares two geotransformations (six parameter double arrays.
void outputGeoTransform(double *transform) const
Sets gdal 6 parameters array from mOutputRectangle, mNumOutputColumns, mNumOutputRows.
bool isNumber() const
Returns true if matrix is 1x1 (=scalar number)
GDALDriverH openOutputDriver()
Opens the output driver and tests if it supports the creation of a new dataset.
double nodataValue() const
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
GDALDatasetH openOutputFile(GDALDriverH outputDriver)
Opens the output file and sets the same geotransform and CRS as the input data.
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