Skip to content

Commit 028b5db

Browse files
author
mhugent
committed
Use GDALAutoCreateWarpedVRT to handle south-up (or rotated) rasters also for calculator. Fixes bug #3281
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@14842 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 6c5a3dd commit 028b5db

File tree

1 file changed

+57
-36
lines changed

1 file changed

+57
-36
lines changed

src/analysis/raster/qgsrastercalculator.cpp

+57-36
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
#include "cpl_string.h"
2323
#include <QProgressDialog>
2424

25+
#include "gdalwarper.h"
26+
2527
QgsRasterCalculator::QgsRasterCalculator( const QString& formulaString, const QString& outputFile, const QString& outputFormat,
2628
const QgsRectangle& outputExtent, int nOutputColumns, int nOutputRows, const QVector<QgsRasterCalculatorEntry>& rasterEntries ): mFormulaString( formulaString ), mOutputFile( outputFile ), mOutputFormat( outputFormat ),
27-
mOutputRectangle( outputExtent ), mNumOutputColumns( nOutputColumns ), mNumOutputRows( nOutputRows ), mRasterEntries( rasterEntries )
29+
mOutputRectangle( outputExtent ), mNumOutputColumns( nOutputColumns ), mNumOutputRows( nOutputRows ), mRasterEntries( rasterEntries )
2830
{
2931
}
3032

@@ -37,7 +39,7 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
3739
//prepare search string / tree
3840
QString errorString;
3941
QgsRasterCalcNode* calcNode = QgsRasterCalcNode::parseRasterCalcString( mFormulaString, errorString );
40-
if( !calcNode )
42+
if ( !calcNode )
4143
{
4244
//error
4345
}
@@ -51,34 +53,53 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
5153
QVector< GDALDatasetH > mInputDatasets; //raster references and corresponding dataset
5254

5355
QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin();
54-
for( ; it != mRasterEntries.constEnd(); ++it )
56+
for ( ; it != mRasterEntries.constEnd(); ++it )
5557
{
56-
if( !it->raster ) // no raster layer in entry
58+
if ( !it->raster ) // no raster layer in entry
5759
{
5860
return 2;
5961
}
6062
GDALDatasetH inputDataset = GDALOpen( it->raster->source().toLocal8Bit().data(), GA_ReadOnly );
61-
if( inputDataset == NULL )
63+
if ( inputDataset == NULL )
6264
{
6365
return 2;
6466
}
67+
68+
//check if the input dataset is south up or rotated. If yes, use GDALAutoCreateWarpedVRT to create a north up raster
69+
double inputGeoTransform[6];
70+
if ( GDALGetGeoTransform( inputDataset, inputGeoTransform ) == CE_None
71+
&& ( inputGeoTransform[1] < 0.0
72+
|| inputGeoTransform[2] != 0.0
73+
|| inputGeoTransform[4] != 0.0
74+
|| inputGeoTransform[5] > 0.0 ) )
75+
{
76+
GDALDatasetH vDataset = GDALAutoCreateWarpedVRT( inputDataset, NULL, NULL, GRA_NearestNeighbour, 0.2, NULL );
77+
mInputDatasets.push_back( vDataset );
78+
mInputDatasets.push_back( inputDataset );
79+
inputDataset = vDataset;
80+
}
81+
else
82+
{
83+
mInputDatasets.push_back( inputDataset );
84+
}
85+
86+
6587
GDALRasterBandH inputRasterBand = GDALGetRasterBand( inputDataset, it->bandNumber );
66-
if( inputRasterBand == NULL )
88+
if ( inputRasterBand == NULL )
6789
{
6890
return 2;
6991
}
7092

7193
int nodataSuccess;
7294
double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess );
7395

74-
mInputDatasets.push_back( inputDataset );
7596
mInputRasterBands.insert( it->ref, inputRasterBand );
7697
inputScanLineData.insert( it->ref, new QgsRasterMatrix( mNumOutputColumns, 1, new float[mNumOutputColumns], nodataValue ) );
7798
}
7899

79100
//open output dataset for writing
80101
GDALDriverH outputDriver = openOutputDriver();
81-
if( outputDriver == NULL )
102+
if ( outputDriver == NULL )
82103
{
83104
return 1;
84105
}
@@ -90,29 +111,29 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
90111

91112
float* resultScanLine = ( float * ) CPLMalloc( sizeof( float ) * mNumOutputColumns );
92113

93-
if( p )
114+
if ( p )
94115
{
95116
p->setMaximum( mNumOutputRows );
96117
}
97118

98119
QgsRasterMatrix resultMatrix;
99120

100121
//read / write line by line
101-
for( int i = 0; i < mNumOutputRows; ++i )
122+
for ( int i = 0; i < mNumOutputRows; ++i )
102123
{
103-
if( p )
124+
if ( p )
104125
{
105126
p->setValue( i );
106127
}
107128

108-
if( p && p->wasCanceled() )
129+
if ( p && p->wasCanceled() )
109130
{
110131
break;
111132
}
112133

113134
//fill buffers
114135
QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
115-
for( ; bufferIt != inputScanLineData.end(); ++bufferIt )
136+
for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
116137
{
117138
double sourceTransformation[6];
118139
GDALRasterBandH sourceRasterBand = mInputRasterBands[bufferIt.key()];
@@ -121,15 +142,15 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
121142
readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, bufferIt.value()->data() );
122143
}
123144

124-
if( calcNode->calculate( inputScanLineData, resultMatrix ) )
145+
if ( calcNode->calculate( inputScanLineData, resultMatrix ) )
125146
{
126147
bool resultIsNumber = resultMatrix.isNumber();
127148
float* calcData;
128149

129-
if( resultIsNumber ) //scalar result. Insert number for every pixel
150+
if ( resultIsNumber ) //scalar result. Insert number for every pixel
130151
{
131152
calcData = new float[mNumOutputColumns];
132-
for( int j = 0; j < mNumOutputColumns; ++j )
153+
for ( int j = 0; j < mNumOutputColumns; ++j )
133154
{
134155
calcData[j] = resultMatrix.number();
135156
}
@@ -140,49 +161,49 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
140161
}
141162

142163
//replace all matrix nodata values with output nodatas
143-
for( int j = 0; j < mNumOutputColumns; ++j )
164+
for ( int j = 0; j < mNumOutputColumns; ++j )
144165
{
145-
if( calcData[j] == resultMatrix.nodataValue() )
166+
if ( calcData[j] == resultMatrix.nodataValue() )
146167
{
147168
calcData[j] = outputNodataValue;
148169
}
149170
}
150171

151172
//write scanline to the dataset
152-
if( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
173+
if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None )
153174
{
154175
qWarning( "RasterIO error!" );
155176
}
156177

157-
if( resultIsNumber )
178+
if ( resultIsNumber )
158179
{
159180
delete[] calcData;
160181
}
161182
}
162183

163184
}
164185

165-
if( p )
186+
if ( p )
166187
{
167188
p->setValue( mNumOutputRows );
168189
}
169190

170191
//close datasets and release memory
171192
delete calcNode;
172193
QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin();
173-
for( ; bufferIt != inputScanLineData.end(); ++bufferIt )
194+
for ( ; bufferIt != inputScanLineData.end(); ++bufferIt )
174195
{
175196
delete bufferIt.value();
176197
}
177198
inputScanLineData.clear();
178199

179200
QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets.begin();
180-
for( ; datasetIt != mInputDatasets.end(); ++ datasetIt )
201+
for ( ; datasetIt != mInputDatasets.end(); ++ datasetIt )
181202
{
182203
GDALClose( *datasetIt );
183204
}
184205

185-
if( p && p->wasCanceled() )
206+
if ( p && p->wasCanceled() )
186207
{
187208
//delete the dataset without closing (because it is faster)
188209
GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() );
@@ -204,13 +225,13 @@ GDALDriverH QgsRasterCalculator::openOutputDriver()
204225
//open driver
205226
GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() );
206227

207-
if( outputDriver == NULL )
228+
if ( outputDriver == NULL )
208229
{
209230
return outputDriver; //return NULL, driver does not exist
210231
}
211232

212233
driverMetadata = GDALGetMetadata( outputDriver, NULL );
213-
if( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) )
234+
if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) )
214235
{
215236
return NULL; //driver exist, but it does not support the create operation
216237
}
@@ -223,7 +244,7 @@ GDALDatasetH QgsRasterCalculator::openOutputFile( GDALDriverH outputDriver )
223244
//open output file
224245
char **papszOptions = NULL;
225246
GDALDatasetH outputDataset = GDALCreate( outputDriver, mOutputFile.toLocal8Bit().data(), mNumOutputColumns, mNumOutputRows, 1, GDT_Float32, papszOptions );
226-
if( outputDataset == NULL )
247+
if ( outputDataset == NULL )
227248
{
228249
return outputDataset;
229250
}
@@ -239,7 +260,7 @@ GDALDatasetH QgsRasterCalculator::openOutputFile( GDALDriverH outputDriver )
239260
void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffset, int yOffset, int nCols, int nRows, double* sourceTransform, GDALRasterBandH sourceBand, float* rasterBuffer )
240261
{
241262
//If dataset transform is the same as the requested transform, do a normal GDAL raster io
242-
if( transformationsEqual( targetGeotransform, sourceTransform ) )
263+
if ( transformationsEqual( targetGeotransform, sourceTransform ) )
243264
{
244265
GDALRasterIO( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0, 0 );
245266
return;
@@ -255,10 +276,10 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
255276
QgsRectangle intersection = targetRect.intersect( &sourceRect );
256277

257278
//no intersection, fill all the pixels with nodata values
258-
if( intersection.isEmpty() )
279+
if ( intersection.isEmpty() )
259280
{
260281
int nPixels = nCols * nRows;
261-
for( int i = 0; i < nPixels; ++i )
282+
for ( int i = 0; i < nPixels; ++i )
262283
{
263284
rasterBuffer[i] = nodataValue;
264285
}
@@ -284,17 +305,17 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
284305
double targetPixelY = targetGeotransform[3] + targetGeotransform[5] * yOffset + targetGeotransform[5] / 2.0; //coordinates of current target pixel
285306
int sourceIndexX, sourceIndexY; //current raster index in source pixels
286307
double sx, sy;
287-
for( int i = 0; i < nRows; ++i )
308+
for ( int i = 0; i < nRows; ++i )
288309
{
289310
targetPixelX = targetPixelXMin;
290-
for( int j = 0; j < nCols; ++j )
311+
for ( int j = 0; j < nCols; ++j )
291312
{
292313
sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1];
293314
sourceIndexX = sx > 0 ? sx : floor( sx );
294315
sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5];
295316
sourceIndexY = sy > 0 ? sy : floor( sy );
296-
if( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX
297-
&& sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY )
317+
if ( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX
318+
&& sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY )
298319
{
299320
rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ];
300321
}
@@ -313,9 +334,9 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
313334

314335
bool QgsRasterCalculator::transformationsEqual( double* t1, double* t2 ) const
315336
{
316-
for( int i = 0; i < 6; ++i )
337+
for ( int i = 0; i < 6; ++i )
317338
{
318-
if( !doubleNear( t1[i], t2[i], 0.00001 ) )
339+
if ( !doubleNear( t1[i], t2[i], 0.00001 ) )
319340
{
320341
return false;
321342
}

0 commit comments

Comments
 (0)