diff --git a/python/core/qgsrasterlayer.sip b/python/core/qgsrasterlayer.sip index d38908785d0..d9615841bcd 100644 --- a/python/core/qgsrasterlayer.sip +++ b/python/core/qgsrasterlayer.sip @@ -162,9 +162,6 @@ public: /** \brief Accessor that returns the height of the (unclipped) raster */ int height(); - /** \brief Accessor to find out whether the histogram should be inverted */ - //bool invertHistogram() const; //removed with raster redesign - /** \brief Is the NoDataValue Valid */ bool isNoDataValueValid() const; @@ -198,9 +195,6 @@ public: /** \brief Mutator for mGrayMinimumMaximumEstimated */ //void setGrayMinimumMaximumEstimated( bool theBool ); //removed with raster redesign - /** \brief Mutator to alter the state of the invert histogram flag */ - //void setInvertHistogram( bool theFlag ); //removed with raster redesign - /** \brief Mutator for mRGBMinimumMaximumEstimated */ //void setRGBMinimumMaximumEstimated( bool theBool ); //removed with raster redesign @@ -249,12 +243,6 @@ public: * If no matching band is found zero will be returned! */ int bandNumber( const QString & theBandName ); - /** \brief Get RasterBandStats for a band given its number (read only) */ - const QgsRasterBandStats bandStatistics( int ); - - /** \brief Get RasterBandStats for a band given its name (read only) */ - const QgsRasterBandStats bandStatistics( const QString & ); - /** \brief Accessor for ths raster layers pyramid list. A pyramid list defines the * POTENTIAL pyramids that can be in a raster. To know which of the pyramid layers * ACTUALLY exists you need to look at the existsFlag member in each struct stored in the @@ -322,9 +310,6 @@ public: /** \brief Checks if symbology is the same as another layers */ bool hasCompatibleSymbology( const QgsMapLayer& theOther ) const; - /** \brief Check whether a given band number has stats associated with it */ - bool hasStatistics( int theBandNoInt ); - /** \brief Identify raster value(s) found on the point position */ bool identify( const QgsPoint & point, QMap& results /Out/ ); @@ -489,12 +474,6 @@ public: const QString & theResamplingMethod = "NEAREST", bool theTryInternalFlag = false ); - /** \brief Populate the histogram vector for a given band */ - void populateHistogram( int theBandNoInt, - int theBinCountInt = 256, - bool theIgnoreOutOfRangeFlag = true, - bool theThoroughBandScanFlag = false ); - void showStatusMessage( const QString & theMessage ); /** \brief Propagate progress updates from GDAL up to the parent app */ diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 294d24b1c78..0521ac99e10 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -5581,7 +5581,7 @@ QgsContrastEnhancement* QgisApp::rasterContrastEnhancement( QgsRasterLayer* rlay } else { - QgsRasterBandStats rasterBandStats = rlayer->bandStatistics( band ); + QgsRasterBandStats rasterBandStats = rlayer->dataProvider()->bandStatistics( band ); minValue = rasterBandStats.minimumValue; maxValue = rasterBandStats.maximumValue; } diff --git a/src/core/qgsprojectfiletransform.cpp b/src/core/qgsprojectfiletransform.cpp index c8be6371664..3e23cacb89f 100644 --- a/src/core/qgsprojectfiletransform.cpp +++ b/src/core/qgsprojectfiletransform.cpp @@ -590,7 +590,7 @@ void QgsProjectFileTransform::convertRasterProperties( QDomDocument& doc, QDomNo newColorRampShaderElem.setAttribute( "colorRampType", "INTERPOLATED" ); //get minmax from rasterlayer - QgsRasterBandStats rasterBandStats = rlayer->bandStatistics( grayBand ); + QgsRasterBandStats rasterBandStats = rlayer->dataProvider()->bandStatistics( grayBand ); double minValue = rasterBandStats.minimumValue; double maxValue = rasterBandStats.maximumValue; double breakSize = ( maxValue - minValue ) / 3; diff --git a/src/core/qgsrasterdataprovider.cpp b/src/core/qgsrasterdataprovider.cpp index bc640a7f481..3cfe1f75488 100644 --- a/src/core/qgsrasterdataprovider.cpp +++ b/src/core/qgsrasterdataprovider.cpp @@ -473,6 +473,26 @@ QgsRasterBandStats QgsRasterDataProvider::statisticsDefaults( int theBandNo, return myRasterBandStats; } +bool QgsRasterDataProvider::hasStatistics( int theBandNo, + const QgsRectangle & theExtent, + int theSampleSize ) +{ + QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) ); + if ( mStatistics.size() == 0 ) return false; + + QgsRasterBandStats myRasterBandStats = statisticsDefaults( theBandNo, theExtent, theSampleSize ); + + foreach( QgsRasterBandStats stats, mStatistics ) + { + if ( stats == myRasterBandStats ) + { + QgsDebugMsg( "Has cached statistics." ); + return true; + } + } + return false; +} + // Find cached QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo, const QgsRectangle & theExtent, diff --git a/src/core/qgsrasterdataprovider.h b/src/core/qgsrasterdataprovider.h index 08ebde5e0eb..c9dc8f4930b 100644 --- a/src/core/qgsrasterdataprovider.h +++ b/src/core/qgsrasterdataprovider.h @@ -295,26 +295,6 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast return QStringList(); } - /** \brief test if the requested histogram is already available */ - - virtual bool hasCachedHistogram( int theBandNoInt, int theBinCountInt = RASTER_HISTOGRAM_BINS ) - { - Q_UNUSED( theBandNoInt ); Q_UNUSED( theBinCountInt ); return false; - } - - /** \brief Populate the histogram vector for a given band */ - - virtual void populateHistogram( int theBandNoInt, - QgsRasterBandStats & theBandStats, - int theBinCountInt = RASTER_HISTOGRAM_BINS, - bool theIgnoreOutOfRangeFlag = true, - bool theThoroughBandScanFlag = false - ) - { - Q_UNUSED( theBandNoInt ); Q_UNUSED( theBandStats ); Q_UNUSED( theBinCountInt ); - Q_UNUSED( theIgnoreOutOfRangeFlag ); Q_UNUSED( theThoroughBandScanFlag ); - } - /** \brief Get histogram. Histograms are cached in providers. * @param theBandNo The band (number). * @param theBinCount Number of bins (intervals,buckets). If 0, the number of bins is decided automaticaly according to data type, raster size etc. @@ -371,6 +351,11 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast const QgsRectangle & theExtent = QgsRectangle(), int theSampleSize = 0 ); + /** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram() */ + virtual bool hasStatistics( int theBandNo, + const QgsRectangle & theExtent = QgsRectangle(), + int theSampleSize = 0 ); + /** \brief helper function to create zero padded band names */ QString generateBandName( int theBandNumber ) const { diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index f36864ffd4e..b32d839d446 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -339,6 +339,7 @@ int QgsRasterLayer::bandNumber( QString const & theBandName ) const * @sa RasterBandStats * @note This is a cpu intensive and slow task! */ +/* const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo ) { QgsDebugMsg( "theBandNo = " + QString::number( theBandNo ) ); @@ -411,7 +412,7 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBand return QgsRasterBandStats(); // return a null one } - +*/ QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList, QString const & theResamplingMethod, bool theTryInternalFlag ) @@ -922,6 +923,7 @@ bool QgsRasterLayer::hasCompatibleSymbology( const QgsMapLayer& theOther ) const * @param theBandNo The number of the band to check * @return true if statistics have already been build for this band otherwise false */ +/* bool QgsRasterLayer::hasStatistics( int theBandNo ) { if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 ) @@ -934,6 +936,7 @@ bool QgsRasterLayer::hasStatistics( int theBandNo ) return false; } } +*/ /** * @param thePoint the QgsPoint for which to obtain pixel values @@ -1289,7 +1292,7 @@ QString QgsRasterLayer::metadata() myMetadata += "

\n"; //check if full stats for this layer have already been collected - if ( !hasStatistics( myIteratorInt ) ) //not collected + if ( !dataProvider()->hasStatistics( myIteratorInt ) ) //not collected { QgsDebugMsg( ".....no" ); @@ -1304,7 +1307,7 @@ QString QgsRasterLayer::metadata() { QgsDebugMsg( ".....yes" ); - QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt ); + QgsRasterBandStats myRasterBandStats = dataProvider()->bandStatistics( myIteratorInt ); //Min Val myMetadata += "

"; myMetadata += tr( "Min Val" ); @@ -1460,27 +1463,6 @@ QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber ) } } -/* - * @param theBandNoInt - which band to find out if has a cached histogram - * @param theBinCountInt - how many 'bins' to categorise the data into - */ -bool QgsRasterLayer::hasCachedHistogram( int theBandNo, int theBinCount ) -{ - return mDataProvider->hasCachedHistogram( theBandNo, theBinCount ); -} - -/* - * @param theBandNoInt - which band to compute the histogram for - * @param theBinCountInt - how many 'bins' to categorise the data into - * @param theIgnoreOutOfRangeFlag - whether to ignore values that are out of range (default=true) - * @param theThoroughBandScanFlag - whether to visit each cell when computing the histogram (default=false) - */ -void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag ) -{ - QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); - mDataProvider->populateHistogram( theBandNo, myRasterBandStats, theBinCount, theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag ); -} - QString QgsRasterLayer::providerType() const { if ( mProviderKey.isEmpty() ) diff --git a/src/core/raster/qgsrasterlayer.h b/src/core/raster/qgsrasterlayer.h index 23c4e4d04fb..7bf440f642b 100644 --- a/src/core/raster/qgsrasterlayer.h +++ b/src/core/raster/qgsrasterlayer.h @@ -386,10 +386,10 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer int bandNumber( const QString & theBandName ) const; /** \brief Get RasterBandStats for a band given its number (read only) */ - const QgsRasterBandStats bandStatistics( int ); + //const QgsRasterBandStats bandStatistics( int ); /** \brief Get RasterBandStats for a band given its name (read only) */ - const QgsRasterBandStats bandStatistics( const QString & ); + //const QgsRasterBandStats bandStatistics( const QString & ); /** \brief Accessor for ths raster layers pyramid list. A pyramid list defines the * POTENTIAL pyramids that can be in a raster. To know which of the pyramid layers @@ -461,7 +461,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer bool hasCompatibleSymbology( const QgsMapLayer& theOther ) const; /** \brief Check whether a given band number has stats associated with it */ - bool hasStatistics( int theBandNoInt ); + //bool hasStatistics( int theBandNoInt ); /** \brief Identify raster value(s) found on the point position */ bool identify( const QgsPoint & point, QMap& results ); @@ -642,18 +642,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer const QString & theResamplingMethod = "NEAREST", bool theTryInternalFlag = false ); - /** \brief test if the requested histogram is already available */ - - bool hasCachedHistogram( int theBandNoInt, - int theBinCountInt = RASTER_HISTOGRAM_BINS ); - - /** \brief Populate the histogram vector for a given band */ - - void populateHistogram( int theBandNoInt, - int theBinCountInt = RASTER_HISTOGRAM_BINS, - bool theIgnoreOutOfRangeFlag = true, - bool theThoroughBandScanFlag = false ); - void showStatusMessage( const QString & theMessage ); /** \brief Propagate progress updates from GDAL up to the parent app */ diff --git a/src/gui/raster/qgsmultibandcolorrendererwidget.cpp b/src/gui/raster/qgsmultibandcolorrendererwidget.cpp index 2ee4961a267..afa92f9e465 100644 --- a/src/gui/raster/qgsmultibandcolorrendererwidget.cpp +++ b/src/gui/raster/qgsmultibandcolorrendererwidget.cpp @@ -221,7 +221,7 @@ void QgsMultiBandColorRendererWidget::loadMinMaxValueForBand( int band, QLineEdi } else if ( mUseStdDevRadioButton->isChecked() ) { - QgsRasterBandStats rasterBandStats = mRasterLayer->bandStatistics( band ); + QgsRasterBandStats rasterBandStats = mRasterLayer->dataProvider()->bandStatistics( band ); double diff = mStdDevSpinBox->value() * rasterBandStats.stdDev; minMaxValues[0] = rasterBandStats.mean - diff; minMaxValues[1] = rasterBandStats.mean + diff; diff --git a/src/gui/raster/qgsrasterhistogramwidget.cpp b/src/gui/raster/qgsrasterhistogramwidget.cpp index 4a919c7e21e..fd59104d9cc 100644 --- a/src/gui/raster/qgsrasterhistogramwidget.cpp +++ b/src/gui/raster/qgsrasterhistogramwidget.cpp @@ -403,7 +403,7 @@ void QgsRasterHistogramWidget::refreshHistogram() if ( ! mySelectedBands.contains( myIteratorInt ) ) continue; } - QgsRasterBandStats myRasterBandStats = mRasterLayer->bandStatistics( myIteratorInt ); + QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( myIteratorInt ); // mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag ); int sampleSize = 250000; // number of sample cells QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( myIteratorInt, BINCOUNT, std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), QgsRectangle(), sampleSize ); diff --git a/src/gui/raster/qgsrasterrendererwidget.cpp b/src/gui/raster/qgsrasterrendererwidget.cpp index 387fe5e5441..a23b9a20bc1 100644 --- a/src/gui/raster/qgsrasterrendererwidget.cpp +++ b/src/gui/raster/qgsrasterrendererwidget.cpp @@ -67,7 +67,7 @@ bool QgsRasterRendererWidget::bandMinMax( LoadMinMaxAlgo loadAlgo, int band, dou } else if ( loadAlgo == Actual ) { - QgsRasterBandStats rasterBandStats = mRasterLayer->bandStatistics( band ); + QgsRasterBandStats rasterBandStats = mRasterLayer->dataProvider()->bandStatistics( band ); minMaxValues[0] = rasterBandStats.minimumValue; minMaxValues[1] = rasterBandStats.maximumValue; } @@ -129,7 +129,7 @@ bool QgsRasterRendererWidget::bandMinMaxFromStdDev( double stdDev, int band, dou return false; } - QgsRasterBandStats myRasterBandStats = mRasterLayer->bandStatistics( band ); + QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( band ); minMaxValues[0] = myRasterBandStats.mean - ( stdDev * myRasterBandStats.stdDev ); minMaxValues[1] = myRasterBandStats.mean + ( stdDev * myRasterBandStats.stdDev ); diff --git a/src/gui/raster/qgssinglebandgrayrendererwidget.cpp b/src/gui/raster/qgssinglebandgrayrendererwidget.cpp index 6f6e60ec596..b8dfe40c8d0 100644 --- a/src/gui/raster/qgssinglebandgrayrendererwidget.cpp +++ b/src/gui/raster/qgssinglebandgrayrendererwidget.cpp @@ -104,7 +104,7 @@ void QgsSingleBandGrayRendererWidget::on_mLoadPushButton_clicked() } else if ( mUseStdDevRadioButton->isChecked() ) { - QgsRasterBandStats rasterBandStats = mRasterLayer->bandStatistics( band ); + QgsRasterBandStats rasterBandStats = mRasterLayer->dataProvider()->bandStatistics( band ); double diff = mStdDevSpinBox->value() * rasterBandStats.stdDev; minMaxValues[0] = rasterBandStats.mean - diff; minMaxValues[1] = rasterBandStats.mean + diff; diff --git a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp index 5643ce936b3..acd21860d7c 100644 --- a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp +++ b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp @@ -184,7 +184,7 @@ void QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked() } int bandNr = mBandComboBox->itemData( bandComboIndex ).toInt(); - QgsRasterBandStats myRasterBandStats = mRasterLayer->bandStatistics( bandNr ); + QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( bandNr ); int numberOfEntries = mNumberOfEntriesSpinBox->value(); QList entryValues; diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp index a9e660af58b..92f6a2deeeb 100644 --- a/src/providers/gdal/qgsgdalprovider.cpp +++ b/src/providers/gdal/qgsgdalprovider.cpp @@ -1267,7 +1267,7 @@ bool QgsGdalProvider::hasHistogram( int theBandNo, return false; } - QgsDebugMsg( "Looking for GDAL histogram xxxx" ); + QgsDebugMsg( "Looking for GDAL histogram" ); GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo ); if ( ! myGdalBand ) @@ -2001,6 +2001,63 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri } } +bool QgsGdalProvider::hasStatistics( int theBandNo, + const QgsRectangle & theExtent, + int theSampleSize ) +{ + QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) ); + + // First check if cached in mStatistics + if ( QgsRasterDataProvider::hasStatistics( theBandNo, theExtent, theSampleSize ) ) + { + return true; + } + + QgsRasterBandStats myRasterBandStats = statisticsDefaults( theBandNo, theExtent, theSampleSize ); + + // If not cached, check if supported by GDAL + if ( myRasterBandStats.extent != extent() ) + { + QgsDebugMsg( "Not supported by GDAL." ); + return false; + } + + QgsDebugMsg( "Looking for GDAL statistics" ); + + GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo ); + if ( ! myGdalBand ) + { + return false; + } + + int bApproxOK = false; + if ( theSampleSize > 0 ) + { + if (( xSize() * ySize() / theSampleSize ) > 2 ) // not perfect + { + bApproxOK = true; + } + } + + // Params in GDALGetRasterStatistics must not be NULL otherwise GDAL returns + // without error even if stats are not cached + double pdfMin; + double pdfMax; + double pdfMean; + double pdfStdDev; + + // try to fetch the cached stats (bForce=FALSE) + CPLErr myerval = GDALGetRasterStatistics( myGdalBand, bApproxOK, FALSE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev ); + + if ( CE_None == myerval ) // CE_Warning if cached not found + { + QgsDebugMsg( "GDAL has cached statistics" ); + return true; + } + + return false; +} + QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, const QgsRectangle & theExtent, int theSampleSize ) { QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) ); diff --git a/src/providers/gdal/qgsgdalprovider.h b/src/providers/gdal/qgsgdalprovider.h index 45de2d4ba0f..4e92edcea71 100644 --- a/src/providers/gdal/qgsgdalprovider.h +++ b/src/providers/gdal/qgsgdalprovider.h @@ -238,12 +238,10 @@ class QgsGdalProvider : public QgsRasterDataProvider QStringList subLayers() const; static QStringList subLayers( GDALDatasetH dataset ); - /** \brief If the provider supports it, return band stats for the - given band. - @note added in QGIS 1.7 - @note overloads virtual method from QgsRasterProvider::bandStatistics + bool hasStatistics( int theBandNo, + const QgsRectangle & theExtent = QgsRectangle(), + int theSampleSize = 0 ); - */ QgsRasterBandStats bandStatistics( int theBandNo, const QgsRectangle & theExtent = QgsRectangle(), int theSampleSize = 0 ); diff --git a/tests/src/core/testqgsrasterlayer.cpp b/tests/src/core/testqgsrasterlayer.cpp index fcb57131716..02e85779684 100644 --- a/tests/src/core/testqgsrasterlayer.cpp +++ b/tests/src/core/testqgsrasterlayer.cpp @@ -187,19 +187,20 @@ void TestQgsRasterLayer::checkDimensions() QVERIFY( mpRasterLayer->height() == 10 ); // regression check for ticket #832 // note bandStatistics call is base 1 - QVERIFY( mpRasterLayer->bandStatistics( 1 ).elementCount == 100 ); + QVERIFY( mpRasterLayer->dataProvider()->bandStatistics( 1 ).elementCount == 100 ); mReport += "

Check Dimensions

\n"; mReport += "

Passed

"; } void TestQgsRasterLayer::checkStats() { + QgsRasterBandStats myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1 ); QVERIFY( mpRasterLayer->width() == 10 ); QVERIFY( mpRasterLayer->height() == 10 ); - QVERIFY( mpRasterLayer->bandStatistics( 1 ).elementCount == 100 ); - QVERIFY( mpRasterLayer->bandStatistics( 1 ).minimumValue == 0 ); - QVERIFY( mpRasterLayer->bandStatistics( 1 ).maximumValue == 9 ); - QVERIFY( mpRasterLayer->bandStatistics( 1 ).mean == 4.5 ); - QVERIFY( fabs( mpRasterLayer->bandStatistics( 1 ).stdDev - 2.87228132326901431 ) + QVERIFY( myStatistics.elementCount == 100 ); + QVERIFY( myStatistics.minimumValue == 0 ); + QVERIFY( myStatistics.maximumValue == 9 ); + QVERIFY( myStatistics.mean == 4.5 ); + QVERIFY( fabs( myStatistics.stdDev - 2.87228132326901431 ) < 0.0000000000000001 ); mReport += "

Check Stats

\n"; mReport += "

Passed

";