Skip to content

Commit a665b7d

Browse files
committedJan 26, 2016
Don't crash when using raster calculator with huge raster (refs #13336)
Now we abort and advise the user if insufficient memory is available to perform the calculation. At some future stage it would be nice to perform the calculations in blocks to allow this scenario, but for now it's better not to crash.
1 parent 5600078 commit a665b7d

File tree

4 files changed

+75
-10
lines changed

4 files changed

+75
-10
lines changed
 

‎python/analysis/raster/qgsrastercalculator.sip

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ class QgsRasterCalculator
1818

1919
public:
2020

21+
//! Result of the calculation
22+
enum Result
23+
{
24+
Success, /*!< Calculation sucessful */
25+
CreateOutputError, /*!< Error creating output data file */
26+
InputLayerError, /*!< Error reading input layer */
27+
Cancelled, /*!< User cancelled calculation */
28+
ParserError, /*!< Error parsing formula */
29+
MemoryError, /*!< Error allocating memory for result */
30+
};
31+
2132
/** QgsRasterCalculator constructor.
2233
* @param formulaString formula for raster calculation
2334
* @param outputFile output file path

‎src/analysis/raster/qgsrastercalculator.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
6969
if ( !calcNode )
7070
{
7171
//error
72-
return 4;
72+
return static_cast<int>( ParserError );
7373
}
7474

7575
QMap< QString, QgsRasterBlock* > inputBlocks;
@@ -78,7 +78,9 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
7878
{
7979
if ( !it->raster ) // no raster layer in entry
8080
{
81-
return 2;
81+
delete calcNode;
82+
qDeleteAll( inputBlocks );
83+
return static_cast< int >( InputLayerError );
8284
}
8385

8486
QgsRasterBlock* block = nullptr;
@@ -96,14 +98,20 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
9698
{
9799
block = it->raster->dataProvider()->block( it->bandNumber, mOutputRectangle, mNumOutputColumns, mNumOutputRows );
98100
}
101+
if ( block->isEmpty() )
102+
{
103+
delete calcNode;
104+
qDeleteAll( inputBlocks );
105+
return static_cast<int>( MemoryError );
106+
}
99107
inputBlocks.insert( it->ref, block );
100108
}
101109

102110
//open output dataset for writing
103111
GDALDriverH outputDriver = openOutputDriver();
104112
if ( !outputDriver )
105113
{
106-
return 1;
114+
return static_cast< int >( CreateOutputError );
107115
}
108116

109117
GDALDatasetH outputDataset = openOutputFile( outputDriver );
@@ -169,11 +177,11 @@ int QgsRasterCalculator::processCalculation( QProgressDialog* p )
169177
{
170178
//delete the dataset without closing (because it is faster)
171179
GDALDeleteDataset( outputDriver, TO8F( mOutputFile ) );
172-
return 3;
180+
return static_cast< int >( Cancelled );
173181
}
174182
GDALClose( outputDataset );
175183

176-
return 0;
184+
return static_cast< int >( Success );
177185
}
178186

179187
QgsRasterCalculator::QgsRasterCalculator()

‎src/analysis/raster/qgsrastercalculator.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ class ANALYSIS_EXPORT QgsRasterCalculator
4141
{
4242
public:
4343

44+
//! Result of the calculation
45+
enum Result
46+
{
47+
Success = 0, /*!< Calculation sucessful */
48+
CreateOutputError = 1, /*!< Error creating output data file */
49+
InputLayerError = 2, /*!< Error reading input layer */
50+
Cancelled = 3, /*!< User cancelled calculation */
51+
ParserError = 4, /*!< Error parsing formula */
52+
MemoryError = 5, /*!< Error allocating memory for result */
53+
};
54+
4455
/** QgsRasterCalculator constructor.
4556
* @param formulaString formula for raster calculation
4657
* @param outputFile output file path
@@ -70,6 +81,7 @@ class ANALYSIS_EXPORT QgsRasterCalculator
7081
/** Starts the calculation and writes new raster
7182
@param p progress bar (or 0 if called from non-gui code)
7283
@return 0 in case of success*/
84+
//TODO QGIS 3.0 - return QgsRasterCalculator::Result
7385
int processCalculation( QProgressDialog* p = nullptr );
7486

7587
private:

‎src/app/qgisapp.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4305,12 +4305,46 @@ void QgisApp::showRasterCalculator()
43054305

43064306
QProgressDialog p( tr( "Calculating..." ), tr( "Abort..." ), 0, 0 );
43074307
p.setWindowModality( Qt::WindowModal );
4308-
if ( rc.processCalculation( &p ) == 0 )
4308+
QgsRasterCalculator::Result res = static_cast< QgsRasterCalculator::Result >( rc.processCalculation( &p ) );
4309+
switch ( res )
43094310
{
4310-
if ( d.addLayerToProject() )
4311-
{
4312-
addRasterLayer( d.outputFile(), QFileInfo( d.outputFile() ).baseName() );
4313-
}
4311+
case QgsRasterCalculator::Success:
4312+
if ( d.addLayerToProject() )
4313+
{
4314+
addRasterLayer( d.outputFile(), QFileInfo( d.outputFile() ).baseName() );
4315+
}
4316+
messageBar()->pushMessage( tr( "Raster calculator" ),
4317+
tr( "Calculation complete." ),
4318+
QgsMessageBar::INFO, messageTimeout() );
4319+
break;
4320+
4321+
case QgsRasterCalculator::CreateOutputError:
4322+
messageBar()->pushMessage( tr( "Raster calculator" ),
4323+
tr( "Could not create destination file." ),
4324+
QgsMessageBar::CRITICAL );
4325+
break;
4326+
4327+
case QgsRasterCalculator::InputLayerError:
4328+
messageBar()->pushMessage( tr( "Raster calculator" ),
4329+
tr( "Could not read input layer." ),
4330+
QgsMessageBar::CRITICAL );
4331+
break;
4332+
4333+
case QgsRasterCalculator::Cancelled:
4334+
break;
4335+
4336+
case QgsRasterCalculator::ParserError:
4337+
messageBar()->pushMessage( tr( "Raster calculator" ),
4338+
tr( "Could not parse raster formula." ),
4339+
QgsMessageBar::CRITICAL );
4340+
break;
4341+
4342+
case QgsRasterCalculator::MemoryError:
4343+
messageBar()->pushMessage( tr( "Raster calculator" ),
4344+
tr( "Insufficient memory available for operation." ),
4345+
QgsMessageBar::CRITICAL );
4346+
break;
4347+
43144348
}
43154349
}
43164350
}

0 commit comments

Comments
 (0)