Skip to content
Permalink
Browse files
Allow cancelation of raster stats/histogram operations
  • Loading branch information
nyalldawson committed Apr 3, 2017
1 parent b9f1f0e commit e400ab6249f7b84982498fbfecf5d0d9bebf8512
@@ -1671,6 +1671,7 @@ QgsRasterInterface {#qgis_api_break_3_0_QgsRasterInterface}
- srcDataType() has been renamed to sourceDataType()
- srcInput() has been renamed to sourceInput()
- block() has new "feedback" argument.
- The signature of histogram() and bandStatistics() now takes a QgsRasterBlockFeedback pointer argument.


QgsRasterLayer {#qgis_api_break_3_0_QgsRasterLayer}
@@ -198,39 +198,20 @@ class QgsRasterInterface
*/
virtual QgsRasterBandStats bandStatistics( int bandNo,
int stats = QgsRasterBandStats::All,
const QgsRectangle & extent = QgsRectangle(),
int sampleSize = 0 );

/** \brief Returns true if histogram is available (cached, already calculated). * The parameters are the same as in bandStatistics()
* @return true if statistics are available (ready to use)
*/
const QgsRectangle &extent = QgsRectangle(),
int sampleSize = 0, QgsRasterBlockFeedback *feedback = 0 );
virtual bool hasStatistics( int bandNo,
int stats = QgsRasterBandStats::All,
const QgsRectangle & extent = QgsRectangle(),
const QgsRectangle &extent = QgsRectangle(),
int sampleSize = 0 );

/** \brief Get histogram. Histograms are cached in providers.
* @param bandNo The band (number).
* @param binCount Number of bins (intervals,buckets). If 0, the number of bins is decided automatically according to data type, raster size etc.
* @param minimum Minimum value, if NaN, raster minimum value will be used.
* @param maximum Maximum value, if NaN, raster minimum value will be used.
* @param extent Extent used to calc histogram, if empty, whole raster extent is used.
* @param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @param includeOutOfRange include out of range values
* @return Vector of non NULL cell counts for each bin.
* @note binCount, minimum and maximum not optional in python bindings
*/
virtual QgsRasterHistogram histogram( int bandNo,
int binCount,
double minimum,
double maximum,
const QgsRectangle & extent,
int sampleSize,
bool includeOutOfRange );
const QgsRectangle &extent = QgsRectangle(),
int sampleSize = 0,
bool includeOutOfRange = false, QgsRasterBlockFeedback *feedback = 0 );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram()
* @note binCount, minimum and maximum not optional in python bindings
*/
virtual bool hasHistogram( int bandNo,
int binCount,
double minimum,
@@ -118,7 +118,7 @@ bool QgsRasterInterface::hasStatistics( int bandNo,
QgsRasterBandStats QgsRasterInterface::bandStatistics( int bandNo,
int stats,
const QgsRectangle &extent,
int sampleSize )
int sampleSize, QgsRasterBlockFeedback *feedback )
{
QgsDebugMsgLevel( QString( "theBandNo = %1 stats = %2 sampleSize = %3" ).arg( bandNo ).arg( stats ).arg( sampleSize ), 4 );

@@ -169,6 +169,9 @@ QgsRasterBandStats QgsRasterInterface::bandStatistics( int bandNo,
{
for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
{
if ( feedback && feedback->isCanceled() )
return myRasterBandStats;

QgsDebugMsgLevel( QString( "myYBlock = %1 myXBlock = %2" ).arg( myYBlock ).arg( myXBlock ), 4 );
int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize );
int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize );
@@ -180,7 +183,7 @@ QgsRasterBandStats QgsRasterInterface::bandStatistics( int bandNo,

QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );

QgsRasterBlock *blk = block( bandNo, myPartExtent, myBlockWidth, myBlockHeight );
QgsRasterBlock *blk = block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback );

// Collect the histogram counts.
for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
@@ -394,7 +397,7 @@ QgsRasterHistogram QgsRasterInterface::histogram( int bandNo,
double minimum, double maximum,
const QgsRectangle &extent,
int sampleSize,
bool includeOutOfRange )
bool includeOutOfRange, QgsRasterBlockFeedback *feedback )
{
QgsDebugMsgLevel( QString( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ), 4 );

@@ -452,6 +455,9 @@ QgsRasterHistogram QgsRasterInterface::histogram( int bandNo,
{
for ( int myXBlock = 0; myXBlock < myNXBlocks; myXBlock++ )
{
if ( feedback && feedback->isCanceled() )
return myHistogram;

int myBlockWidth = qMin( myXBlockSize, myWidth - myXBlock * myXBlockSize );
int myBlockHeight = qMin( myYBlockSize, myHeight - myYBlock * myYBlockSize );

@@ -462,7 +468,7 @@ QgsRasterHistogram QgsRasterInterface::histogram( int bandNo,

QgsRectangle myPartExtent( xmin, ymin, xmax, ymax );

QgsRasterBlock *blk = block( bandNo, myPartExtent, myBlockWidth, myBlockHeight );
QgsRasterBlock *blk = block( bandNo, myPartExtent, myBlockWidth, myBlockHeight, feedback );

// Collect the histogram counts.
for ( qgssize i = 0; i < ( static_cast< qgssize >( myBlockHeight ) ) * myBlockWidth; i++ )
@@ -192,12 +192,13 @@ class CORE_EXPORT QgsRasterInterface
* @param stats Requested statistics
* @param extent Extent used to calc statistics, if empty, whole raster extent is used.
* @param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @param feedback optional feedback object
* @return Band statistics.
*/
virtual QgsRasterBandStats bandStatistics( int bandNo,
int stats = QgsRasterBandStats::All,
const QgsRectangle &extent = QgsRectangle(),
int sampleSize = 0 );
int sampleSize = 0, QgsRasterBlockFeedback *feedback = nullptr );

/** \brief Returns true if histogram is available (cached, already calculated). * The parameters are the same as in bandStatistics()
* @return true if statistics are available (ready to use)
@@ -215,6 +216,7 @@ class CORE_EXPORT QgsRasterInterface
* @param extent Extent used to calc histogram, if empty, whole raster extent is used.
* @param sampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @param includeOutOfRange include out of range values
* @param feedback optional feedback object
* @return Vector of non NULL cell counts for each bin.
* @note binCount, minimum and maximum not optional in Python bindings
*/
@@ -224,7 +226,7 @@ class CORE_EXPORT QgsRasterInterface
double maximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle &extent = QgsRectangle(),
int sampleSize = 0,
bool includeOutOfRange = false );
bool includeOutOfRange = false, QgsRasterBlockFeedback *feedback = nullptr );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram()
* @note binCount, minimum and maximum not optional in Python bindings
@@ -62,6 +62,7 @@ struct QgsGdalProgress
{
int type;
QgsGdalProvider *provider = nullptr;
QgsRasterBlockFeedback *feedback = nullptr;
};
//
// global callback function
@@ -87,10 +88,12 @@ int CPL_STDCALL progressCallback( double dfComplete,
{
mypProvider->emitProgress( prog->type, dfComplete * 100, QString( pszMessage ) );
mypProvider->emitProgressUpdate( dfComplete * 100 );
if ( prog->feedback )
prog->feedback->setProgress( dfComplete * 100 );
}
sDfLastComplete = dfComplete;

return true;
return prog->feedback ? !prog->feedback->isCanceled() : true;
}

QgsGdalProvider::QgsGdalProvider( const QString &uri, QgsError error )
@@ -1295,7 +1298,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int bandNo,
double minimum, double maximum,
const QgsRectangle &boundingBox,
int sampleSize,
bool includeOutOfRange )
bool includeOutOfRange, QgsRasterBlockFeedback *feedback )
{
QgsDebugMsg( QString( "theBandNo = %1 binCount = %2 minimum = %3 maximum = %4 sampleSize = %5" ).arg( bandNo ).arg( binCount ).arg( minimum ).arg( maximum ).arg( sampleSize ) );

@@ -1316,13 +1319,13 @@ QgsRasterHistogram QgsGdalProvider::histogram( int bandNo,
!userNoDataValues( bandNo ).isEmpty() )
{
QgsDebugMsg( "Custom no data values, using generic histogram." );
return QgsRasterDataProvider::histogram( bandNo, binCount, minimum, maximum, boundingBox, sampleSize, includeOutOfRange );
return QgsRasterDataProvider::histogram( bandNo, binCount, minimum, maximum, boundingBox, sampleSize, includeOutOfRange, feedback );
}

if ( myHistogram.extent != extent() )
{
QgsDebugMsg( "Not full extent, using generic histogram." );
return QgsRasterDataProvider::histogram( bandNo, binCount, minimum, maximum, boundingBox, sampleSize, includeOutOfRange );
return QgsRasterDataProvider::histogram( bandNo, binCount, minimum, maximum, boundingBox, sampleSize, includeOutOfRange, feedback );
}

QgsDebugMsg( "Computing GDAL histogram" );
@@ -1345,6 +1348,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int bandNo,
QgsGdalProgress myProg;
myProg.type = QgsRaster::ProgressHistogram;
myProg.provider = this;
myProg.feedback = feedback;

#if 0 // this is the old method

@@ -1409,7 +1413,7 @@ QgsRasterHistogram QgsGdalProvider::histogram( int bandNo,
includeOutOfRange, bApproxOK, progressCallback,
&myProg ); //this is the arg for our custom gdal progress callback

if ( myError != CE_None )
if ( myError != CE_None || ( feedback && feedback->isCanceled() ) )
{
QgsDebugMsg( "Cannot get histogram" );
delete [] myHistogramArray;
@@ -2264,7 +2268,7 @@ bool QgsGdalProvider::hasStatistics( int bandNo,
return false;
}

QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const QgsRectangle &boundingBox, int sampleSize )
QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const QgsRectangle &boundingBox, int sampleSize, QgsRasterBlockFeedback *feedback )
{
QgsDebugMsg( QString( "theBandNo = %1 sampleSize = %2" ).arg( bandNo ).arg( sampleSize ) );

@@ -2293,7 +2297,7 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const
!userNoDataValues( bandNo ).isEmpty() )
{
QgsDebugMsg( "Custom no data values, using generic statistics." );
return QgsRasterDataProvider::bandStatistics( bandNo, stats, boundingBox, sampleSize );
return QgsRasterDataProvider::bandStatistics( bandNo, stats, boundingBox, sampleSize, feedback );
}

int supportedStats = QgsRasterBandStats::Min | QgsRasterBandStats::Max
@@ -2306,7 +2310,7 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const
( stats & ( ~supportedStats ) ) )
{
QgsDebugMsg( "Statistics not supported by provider, using generic statistics." );
return QgsRasterDataProvider::bandStatistics( bandNo, stats, boundingBox, sampleSize );
return QgsRasterDataProvider::bandStatistics( bandNo, stats, boundingBox, sampleSize, feedback );
}

QgsDebugMsg( "Using GDAL statistics." );
@@ -2334,6 +2338,7 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const
QgsGdalProgress myProg;
myProg.type = QgsRaster::ProgressHistogram;
myProg.provider = this;
myProg.feedback = feedback;

// try to fetch the cached stats (bForce=FALSE)
// GDALGetRasterStatistics() do not work correctly with bApproxOK=false and bForce=false/true
@@ -2358,6 +2363,9 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int bandNo, int stats, const
QgsDebugMsg( "Using GDAL cached statistics" );
}

if ( feedback && feedback->isCanceled() )
return myRasterBandStats;

// if stats are found populate the QgsRasterBandStats object
if ( CE_None == myerval )
{
@@ -115,7 +115,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
QgsRasterBandStats bandStatistics( int bandNo,
int stats = QgsRasterBandStats::All,
const QgsRectangle &boundingBox = QgsRectangle(),
int sampleSize = 0 ) override;
int sampleSize = 0, QgsRasterBlockFeedback *feedback = nullptr ) override;

bool hasHistogram( int bandNo,
int binCount = 0,
@@ -131,7 +131,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
double maximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle &boundingBox = QgsRectangle(),
int sampleSize = 0,
bool includeOutOfRange = false ) override;
bool includeOutOfRange = false, QgsRasterBlockFeedback *feedback = nullptr ) override;

QString buildPyramids( const QList<QgsRasterPyramid> &rasterPyramidList,
const QString &resamplingMethod = "NEAREST",
@@ -284,7 +284,7 @@ void QgsGrassRasterProvider::readBlock( int bandNo, QgsRectangle const &viewExt
memcpy( block, data.data(), size );
}

QgsRasterBandStats QgsGrassRasterProvider::bandStatistics( int bandNo, int stats, const QgsRectangle &boundingBox, int sampleSize )
QgsRasterBandStats QgsGrassRasterProvider::bandStatistics( int bandNo, int stats, const QgsRectangle &boundingBox, int sampleSize, QgsRasterBlockFeedback * )
{
QgsDebugMsg( QString( "theBandNo = %1 sampleSize = %2" ).arg( bandNo ).arg( sampleSize ) );
QgsRasterBandStats myRasterBandStats;
@@ -193,7 +193,7 @@ class GRASS_LIB_EXPORT QgsGrassRasterProvider : public QgsRasterDataProvider
QgsRasterBandStats bandStatistics( int bandNo,
int stats = QgsRasterBandStats::All,
const QgsRectangle &boundingBox = QgsRectangle(),
int sampleSize = 0 ) override;
int sampleSize = 0, QgsRasterBlockFeedback *feedback = nullptr ) override;

QList<QgsColorRampShader::ColorRampItem> colorTable( int bandNo )const override;

0 comments on commit e400ab6

Please sign in to comment.