Skip to content

Commit f42f640

Browse files
committed
[rastercalc] Switch all internal calculations to doubles
...for more accurate calculations (fix #9081) Also: - Add test suite for raster calculator - Fix errors with log/log10 calculation and inputs <= 0 - Fix loss of nodata values in certain circumstances
1 parent facfe6e commit f42f640

File tree

7 files changed

+311
-122
lines changed

7 files changed

+311
-122
lines changed

python/analysis/raster/qgsrastermatrix.sip

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ class QgsRasterMatrix
4848

4949
/**Returns data array (but not ownership)*/
5050
//! @note not available in python bindings
51-
// float* data();
51+
// double* data();
5252
/**Returns data and ownership. Sets data and nrows, ncols of this matrix to 0*/
5353
//! @note not available in python bindings
54-
// float* takeData();
54+
// double* takeData();
5555

56-
void setData( int cols, int rows, float* data, double nodataValue );
56+
void setData( int cols, int rows, double* data, double nodataValue );
5757

5858
int nColumns() const;
5959
int nRows() const;

src/analysis/raster/qgsrastercalcnode.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,17 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterMatrix*>& rasterData,
8080
}
8181

8282
int nEntries = ( *it )->nColumns() * ( *it )->nRows();
83-
float* data = new float[nEntries];
84-
memcpy( data, ( *it )->data(), nEntries * sizeof( float ) );
83+
double* data = new double[nEntries];
84+
memcpy( data, ( *it )->data(), nEntries * sizeof( double ) );
8585
result.setData(( *it )->nColumns(), ( *it )->nRows(), data, ( *it )->nodataValue() );
8686
return true;
8787
}
8888
else if ( mType == tOperator )
8989
{
9090
QgsRasterMatrix leftMatrix, rightMatrix;
91-
QgsRasterMatrix resultMatrix;
91+
leftMatrix.setNodataValue( result.nodataValue() );
92+
rightMatrix.setNodataValue( result.nodataValue() );
93+
9294
if ( !mLeft || !mLeft->calculate( rasterData, leftMatrix ) )
9395
{
9496
return false;
@@ -179,9 +181,9 @@ bool QgsRasterCalcNode::calculate( QMap<QString, QgsRasterMatrix*>& rasterData,
179181
}
180182
else if ( mType == tNumber )
181183
{
182-
float* data = new float[1];
184+
double* data = new double[1];
183185
data[0] = mNumber;
184-
result.setData( 1, 1, data, -FLT_MAX );
186+
result.setData( 1, 1, data, result.nodataValue() );
185187
return true;
186188
}
187189
return false;

src/analysis/raster/qgsrastercalculator.cpp

+11-21
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
111111
double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess );
112112

113113
mInputRasterBands.insert( it->ref, inputRasterBand );
114-
inputScanLineData.insert( it->ref, new QgsRasterMatrix( mNumOutputColumns, 1, new float[mNumOutputColumns], nodataValue ) );
114+
inputScanLineData.insert( it->ref, new QgsRasterMatrix( mNumOutputColumns, 1, new double[mNumOutputColumns], nodataValue ) );
115115
}
116116

117117
//open output dataset for writing
@@ -183,35 +183,25 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
183183
qWarning( "GDALGetGeoTransform failed!" );
184184
}
185185

186+
float* inputScanLine = ( float * ) CPLMalloc( sizeof( float ) * mNumOutputColumns );
187+
186188
//the function readRasterPart calls GDALRasterIO (and ev. does some conversion if raster transformations are not the same)
187-
readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, bufferIt.value()->data() );
189+
readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, inputScanLine );
190+
for ( int col = 0; col < mNumOutputColumns; ++col )
191+
{
192+
bufferIt.value()->data()[col] = ( double )inputScanLine[col];
193+
}
188194
}
189195

190196
if ( calcNode->calculate( inputScanLineData, resultMatrix ) )
191197
{
192198
bool resultIsNumber = resultMatrix.isNumber();
193-
float* calcData;
194-
195-
if ( resultIsNumber ) //scalar result. Insert number for every pixel
196-
{
197-
calcData = new float[mNumOutputColumns];
198-
for ( int j = 0; j < mNumOutputColumns; ++j )
199-
{
200-
calcData[j] = resultMatrix.number();
201-
}
202-
}
203-
else //result is real matrix
204-
{
205-
calcData = resultMatrix.data();
206-
}
199+
float* calcData = new float[mNumOutputColumns];
207200

208-
//replace all matrix nodata values with output nodatas
209201
for ( int j = 0; j < mNumOutputColumns; ++j )
210202
{
211-
if ( calcData[j] == resultMatrix.nodataValue() )
212-
{
213-
calcData[j] = outputNodataValue;
214-
}
203+
double result = resultIsNumber ? resultMatrix.number() : resultMatrix.data()[j];
204+
calcData[j] = ( calcData[j] == resultMatrix.nodataValue() ? outputNodataValue : ( float ) result );
215205
}
216206

217207
//write scanline to the dataset

0 commit comments

Comments
 (0)