22
22
#include " cpl_string.h"
23
23
#include < QProgressDialog>
24
24
25
+ #include " gdalwarper.h"
26
+
25
27
QgsRasterCalculator::QgsRasterCalculator ( const QString& formulaString, const QString& outputFile, const QString& outputFormat,
26
28
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 )
28
30
{
29
31
}
30
32
@@ -37,7 +39,7 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
37
39
// prepare search string / tree
38
40
QString errorString;
39
41
QgsRasterCalcNode* calcNode = QgsRasterCalcNode::parseRasterCalcString ( mFormulaString , errorString );
40
- if ( !calcNode )
42
+ if ( !calcNode )
41
43
{
42
44
// error
43
45
}
@@ -51,34 +53,53 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
51
53
QVector< GDALDatasetH > mInputDatasets ; // raster references and corresponding dataset
52
54
53
55
QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries .constBegin ();
54
- for ( ; it != mRasterEntries .constEnd (); ++it )
56
+ for ( ; it != mRasterEntries .constEnd (); ++it )
55
57
{
56
- if ( !it->raster ) // no raster layer in entry
58
+ if ( !it->raster ) // no raster layer in entry
57
59
{
58
60
return 2 ;
59
61
}
60
62
GDALDatasetH inputDataset = GDALOpen ( it->raster ->source ().toLocal8Bit ().data (), GA_ReadOnly );
61
- if ( inputDataset == NULL )
63
+ if ( inputDataset == NULL )
62
64
{
63
65
return 2 ;
64
66
}
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
+
65
87
GDALRasterBandH inputRasterBand = GDALGetRasterBand ( inputDataset, it->bandNumber );
66
- if ( inputRasterBand == NULL )
88
+ if ( inputRasterBand == NULL )
67
89
{
68
90
return 2 ;
69
91
}
70
92
71
93
int nodataSuccess;
72
94
double nodataValue = GDALGetRasterNoDataValue ( inputRasterBand, &nodataSuccess );
73
95
74
- mInputDatasets .push_back ( inputDataset );
75
96
mInputRasterBands .insert ( it->ref , inputRasterBand );
76
97
inputScanLineData.insert ( it->ref , new QgsRasterMatrix ( mNumOutputColumns , 1 , new float [mNumOutputColumns ], nodataValue ) );
77
98
}
78
99
79
100
// open output dataset for writing
80
101
GDALDriverH outputDriver = openOutputDriver ();
81
- if ( outputDriver == NULL )
102
+ if ( outputDriver == NULL )
82
103
{
83
104
return 1 ;
84
105
}
@@ -90,29 +111,29 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
90
111
91
112
float * resultScanLine = ( float * ) CPLMalloc ( sizeof ( float ) * mNumOutputColumns );
92
113
93
- if ( p )
114
+ if ( p )
94
115
{
95
116
p->setMaximum ( mNumOutputRows );
96
117
}
97
118
98
119
QgsRasterMatrix resultMatrix;
99
120
100
121
// read / write line by line
101
- for ( int i = 0 ; i < mNumOutputRows ; ++i )
122
+ for ( int i = 0 ; i < mNumOutputRows ; ++i )
102
123
{
103
- if ( p )
124
+ if ( p )
104
125
{
105
126
p->setValue ( i );
106
127
}
107
128
108
- if ( p && p->wasCanceled () )
129
+ if ( p && p->wasCanceled () )
109
130
{
110
131
break ;
111
132
}
112
133
113
134
// fill buffers
114
135
QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin ();
115
- for ( ; bufferIt != inputScanLineData.end (); ++bufferIt )
136
+ for ( ; bufferIt != inputScanLineData.end (); ++bufferIt )
116
137
{
117
138
double sourceTransformation[6 ];
118
139
GDALRasterBandH sourceRasterBand = mInputRasterBands [bufferIt.key ()];
@@ -121,15 +142,15 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
121
142
readRasterPart ( targetGeoTransform, 0 , i, mNumOutputColumns , 1 , sourceTransformation, sourceRasterBand, bufferIt.value ()->data () );
122
143
}
123
144
124
- if ( calcNode->calculate ( inputScanLineData, resultMatrix ) )
145
+ if ( calcNode->calculate ( inputScanLineData, resultMatrix ) )
125
146
{
126
147
bool resultIsNumber = resultMatrix.isNumber ();
127
148
float * calcData;
128
149
129
- if ( resultIsNumber ) // scalar result. Insert number for every pixel
150
+ if ( resultIsNumber ) // scalar result. Insert number for every pixel
130
151
{
131
152
calcData = new float [mNumOutputColumns ];
132
- for ( int j = 0 ; j < mNumOutputColumns ; ++j )
153
+ for ( int j = 0 ; j < mNumOutputColumns ; ++j )
133
154
{
134
155
calcData[j] = resultMatrix.number ();
135
156
}
@@ -140,49 +161,49 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
140
161
}
141
162
142
163
// replace all matrix nodata values with output nodatas
143
- for ( int j = 0 ; j < mNumOutputColumns ; ++j )
164
+ for ( int j = 0 ; j < mNumOutputColumns ; ++j )
144
165
{
145
- if ( calcData[j] == resultMatrix.nodataValue () )
166
+ if ( calcData[j] == resultMatrix.nodataValue () )
146
167
{
147
168
calcData[j] = outputNodataValue;
148
169
}
149
170
}
150
171
151
172
// 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 )
153
174
{
154
175
qWarning ( " RasterIO error!" );
155
176
}
156
177
157
- if ( resultIsNumber )
178
+ if ( resultIsNumber )
158
179
{
159
180
delete[] calcData;
160
181
}
161
182
}
162
183
163
184
}
164
185
165
- if ( p )
186
+ if ( p )
166
187
{
167
188
p->setValue ( mNumOutputRows );
168
189
}
169
190
170
191
// close datasets and release memory
171
192
delete calcNode;
172
193
QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin ();
173
- for ( ; bufferIt != inputScanLineData.end (); ++bufferIt )
194
+ for ( ; bufferIt != inputScanLineData.end (); ++bufferIt )
174
195
{
175
196
delete bufferIt.value ();
176
197
}
177
198
inputScanLineData.clear ();
178
199
179
200
QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets .begin ();
180
- for ( ; datasetIt != mInputDatasets .end (); ++ datasetIt )
201
+ for ( ; datasetIt != mInputDatasets .end (); ++ datasetIt )
181
202
{
182
203
GDALClose ( *datasetIt );
183
204
}
184
205
185
- if ( p && p->wasCanceled () )
206
+ if ( p && p->wasCanceled () )
186
207
{
187
208
// delete the dataset without closing (because it is faster)
188
209
GDALDeleteDataset ( outputDriver, mOutputFile .toLocal8Bit ().data () );
@@ -204,13 +225,13 @@ GDALDriverH QgsRasterCalculator::openOutputDriver()
204
225
// open driver
205
226
GDALDriverH outputDriver = GDALGetDriverByName ( mOutputFormat .toLocal8Bit ().data () );
206
227
207
- if ( outputDriver == NULL )
228
+ if ( outputDriver == NULL )
208
229
{
209
230
return outputDriver; // return NULL, driver does not exist
210
231
}
211
232
212
233
driverMetadata = GDALGetMetadata ( outputDriver, NULL );
213
- if ( !CSLFetchBoolean ( driverMetadata, GDAL_DCAP_CREATE, false ) )
234
+ if ( !CSLFetchBoolean ( driverMetadata, GDAL_DCAP_CREATE, false ) )
214
235
{
215
236
return NULL ; // driver exist, but it does not support the create operation
216
237
}
@@ -223,7 +244,7 @@ GDALDatasetH QgsRasterCalculator::openOutputFile( GDALDriverH outputDriver )
223
244
// open output file
224
245
char **papszOptions = NULL ;
225
246
GDALDatasetH outputDataset = GDALCreate ( outputDriver, mOutputFile .toLocal8Bit ().data (), mNumOutputColumns , mNumOutputRows , 1 , GDT_Float32, papszOptions );
226
- if ( outputDataset == NULL )
247
+ if ( outputDataset == NULL )
227
248
{
228
249
return outputDataset;
229
250
}
@@ -239,7 +260,7 @@ GDALDatasetH QgsRasterCalculator::openOutputFile( GDALDriverH outputDriver )
239
260
void QgsRasterCalculator::readRasterPart ( double * targetGeotransform, int xOffset, int yOffset, int nCols, int nRows, double * sourceTransform, GDALRasterBandH sourceBand, float * rasterBuffer )
240
261
{
241
262
// 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 ) )
243
264
{
244
265
GDALRasterIO ( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0 , 0 );
245
266
return ;
@@ -255,10 +276,10 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
255
276
QgsRectangle intersection = targetRect.intersect ( &sourceRect );
256
277
257
278
// no intersection, fill all the pixels with nodata values
258
- if ( intersection.isEmpty () )
279
+ if ( intersection.isEmpty () )
259
280
{
260
281
int nPixels = nCols * nRows;
261
- for ( int i = 0 ; i < nPixels; ++i )
282
+ for ( int i = 0 ; i < nPixels; ++i )
262
283
{
263
284
rasterBuffer[i] = nodataValue;
264
285
}
@@ -284,17 +305,17 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
284
305
double targetPixelY = targetGeotransform[3 ] + targetGeotransform[5 ] * yOffset + targetGeotransform[5 ] / 2.0 ; // coordinates of current target pixel
285
306
int sourceIndexX, sourceIndexY; // current raster index in source pixels
286
307
double sx, sy;
287
- for ( int i = 0 ; i < nRows; ++i )
308
+ for ( int i = 0 ; i < nRows; ++i )
288
309
{
289
310
targetPixelX = targetPixelXMin;
290
- for ( int j = 0 ; j < nCols; ++j )
311
+ for ( int j = 0 ; j < nCols; ++j )
291
312
{
292
313
sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1 ];
293
314
sourceIndexX = sx > 0 ? sx : floor ( sx );
294
315
sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5 ];
295
316
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 )
298
319
{
299
320
rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ];
300
321
}
@@ -313,9 +334,9 @@ void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffse
313
334
314
335
bool QgsRasterCalculator::transformationsEqual ( double * t1, double * t2 ) const
315
336
{
316
- for ( int i = 0 ; i < 6 ; ++i )
337
+ for ( int i = 0 ; i < 6 ; ++i )
317
338
{
318
- if ( !doubleNear ( t1[i], t2[i], 0.00001 ) )
339
+ if ( !doubleNear ( t1[i], t2[i], 0.00001 ) )
319
340
{
320
341
return false ;
321
342
}
0 commit comments