Merge pull request #3871 from rouault/auto_stretch

[FEATURE] Implement raster auto-stretching when updating canvas
This commit is contained in:
Even Rouault 2016-12-16 13:53:54 +01:00 committed by GitHub
commit 792873af5c
49 changed files with 1948 additions and 911 deletions

View File

@ -1313,6 +1313,14 @@ QgsProject {#qgis_api_break_3_0_QgsProject}
- clearProperties() was removed. Use clear() instead. - clearProperties() was removed. Use clear() instead.
QgsRaster {#qgis_api_break_3_0_QgsRaster}
---------
- QgsRaster::ContrastEnhancementLimits has been removed, use QgsRasterMinMaxOrigin::Limits
- QgsRaster::contrastEnhancementLimitsAsString() has been removed, use QgsRasterMinMaxOrigin::limitsString()
- QgsRaster::contrastEnhancementLimitsFromString() has been removed, use QgsRasterMinMaxOrigin::limitsFromString()
QgsRasterCalcNode {#qgis_api_break_3_0_QgsRasterCalcNode} QgsRasterCalcNode {#qgis_api_break_3_0_QgsRasterCalcNode}
----------------- -----------------
@ -1343,13 +1351,18 @@ QgsRasterLayer {#qgis_api_break_3_0_QgsRasterLayer}
- setDrawingStyle() was removed. Use setRendererForDrawingStyle() or setRenderer() instead. - setDrawingStyle() was removed. Use setRendererForDrawingStyle() or setRenderer() instead.
- previewAsPixmap() was removed. Use previewAsImage() instead. - previewAsPixmap() was removed. Use previewAsImage() instead.
- updateProgress() had no effect and was removed. - updateProgress() had no effect and was removed.
- CUMULATIVE_CUT_LOWER and CUMULATIVE_CUT_UPPER have been moved to QgsRasterMinMaxOrigin
- the second parameter of setContrastEnhancement() has changed type. It is now QgsRasterMinMaxOrigin::Limits
QgsRasterProjector {#qgis_api_break_3_0_QgsRasterProjector} QgsRasterProjector {#qgis_api_break_3_0_QgsRasterProjector}
------------------ ------------------
- extentSize() now takes a QgsCoordinateTransform reference, not a pointer. An invalid QgsCoordinateTransform should be used instead of a null pointer if no transformation is required. - extentSize() now takes a QgsCoordinateTransform reference, not a pointer. An invalid QgsCoordinateTransform should be used instead of a null pointer if no transformation is required.
QgsRasterRenderer
-----------------
- MinMaxOrigin enum, minMaxOriginName(), minMaxOriginLabel(), minMaxOriginFromName() removed. Use minMaxOrigin() instead
QgsRelation {#qgis_api_break_3_0_QgsRelation} QgsRelation {#qgis_api_break_3_0_QgsRelation}
----------- -----------
@ -1430,6 +1443,12 @@ QgsSimpleMarkerSymbolLayerWidget {#qgis_api_break_3_0_QgsSimpleMarkerSymb
- setName() was removed. - setName() was removed.
QgsSingleBandPseudoColorRenderer {#qgis_api_break_3_0_QgsSingleBandPseudoColorRenderer}
--------------------------------
- classificationMinMaxOrigin() and setClassificationMinMaxOrigin() removed. Use minMaxOrigin() and setMinMaxOrigin()
QgsSingleSymbolRendererWidget {#qgis_api_break_3_0_QgsSingleSymbolRendererWidget} QgsSingleSymbolRendererWidget {#qgis_api_break_3_0_QgsSingleSymbolRendererWidget}
----------------------------- -----------------------------

View File

@ -274,6 +274,7 @@
%Include raster/qgsrasterinterface.sip %Include raster/qgsrasterinterface.sip
%Include raster/qgsrasteriterator.sip %Include raster/qgsrasteriterator.sip
%Include raster/qgsrasterlayer.sip %Include raster/qgsrasterlayer.sip
%Include raster/qgsrasterminmaxorigin.sip
%Include raster/qgsrasternuller.sip %Include raster/qgsrasternuller.sip
%Include raster/qgsrasterpipe.sip %Include raster/qgsrasterpipe.sip
%Include raster/qgsrasterprojector.sip %Include raster/qgsrasterprojector.sip

View File

@ -62,14 +62,6 @@ class QgsRaster
PyramidsErdas, PyramidsErdas,
}; };
/** \brief Contrast enhancement limits */
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};
/** \brief This enumerator describes the different kinds of drawing we can do */ /** \brief This enumerator describes the different kinds of drawing we can do */
enum DrawingStyle enum DrawingStyle
@ -87,9 +79,6 @@ class QgsRaster
SingleBandColorDataStyle // ARGB values rendered directly SingleBandColorDataStyle // ARGB values rendered directly
}; };
static QString contrastEnhancementLimitsAsString( QgsRaster::ContrastEnhancementLimits theLimits );
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( const QString& theLimits );
/** Get value representable by given data type. /** Get value representable by given data type.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64. * Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* @param value * @param value

View File

@ -10,11 +10,6 @@ class QgsRasterLayer : QgsMapLayer
%End %End
public: public:
/** \brief Default cumulative cut lower limit */
static const double CUMULATIVE_CUT_LOWER;
/** \brief Default cumulative cut upper limit */
static const double CUMULATIVE_CUT_UPPER;
/** \brief Default sample size (number of pixels) for estimated statistics/histogram calculation */ /** \brief Default sample size (number of pixels) for estimated statistics/histogram calculation */
static const double SAMPLE_SIZE; static const double SAMPLE_SIZE;
@ -165,7 +160,7 @@ class QgsRasterLayer : QgsMapLayer
void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax, QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax,
const QgsRectangle& theExtent = QgsRectangle(), const QgsRectangle& theExtent = QgsRectangle(),
int theSampleSize = QgsRasterLayer::SAMPLE_SIZE, int theSampleSize = QgsRasterLayer::SAMPLE_SIZE,
bool theGenerateLookupTableFlag = true ); bool theGenerateLookupTableFlag = true );

View File

@ -0,0 +1,127 @@
/** \class QgsRasterMinMaxOrigin
* This class describes the origin of min/max values. It does not store by
* itself the min/max values.
*/
class QgsRasterMinMaxOrigin
{
%TypeHeaderCode
#include <qgsrasterminmaxorigin.h>
%End
public:
//! \brief Default cumulative cut lower limit
static const double CUMULATIVE_CUT_LOWER;
//! \brief Default cumulative cut upper limit
static const double CUMULATIVE_CUT_UPPER;
//! \brief Default standard deviation factor
static const double DEFAULT_STDDEV_FACTOR;
//! \brief This enumerator describes the limits used to compute min/max values
enum Limits
{
//! User defined.
None /PyName=None_/,
//! Real min-max values
MinMax,
//! Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ]
StdDev,
//! Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ]
CumulativeCut
};
//! \brief This enumerator describes the extent used to compute min/max values
enum Extent
{
//! Whole raster is used to compute statistics.
WholeRaster,
//! Current extent of the canvas (at the time of computation) is used to compute statistics.
CurrentCanvas,
//! Constantly updated extent of the canvas is used to compute statistics.
UpdatedCanvas
};
//! \brief This enumerator describes the accuracy used to compute statistics.
enum StatAccuracy
{
//! Exact statistics.
Exact,
//! Approximated statistics.
Estimated
};
//! \brief Default constructor.
QgsRasterMinMaxOrigin();
//! \brief Equality operator.
bool operator ==( const QgsRasterMinMaxOrigin& other ) const;
//////// Getter methods /////////////////////
//! \brief Return limits.
QgsRasterMinMaxOrigin::Limits limits() const;
//! \brief Return extent.
QgsRasterMinMaxOrigin::Extent extent() const;
//! \brief Return statistic accuracy.
QgsRasterMinMaxOrigin::StatAccuracy statAccuracy() const;
//! \brief Return lower bound of cumulative cut method (between 0 and 1).
double cumulativeCutLower() const;
//! \brief Return upper bound of cumulative cut method (between 0 and 1).
double cumulativeCutUpper() const;
//! \brief Return factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
double stdDevFactor() const;
//////// Setter methods /////////////////////
//! \brief Set limits.
void setLimits(QgsRasterMinMaxOrigin::Limits theLimits);
//! \brief Set extent.
void setExtent(QgsRasterMinMaxOrigin::Extent theExtent);
//! \brief Set statistics accuracy.
void setStatAccuracy(QgsRasterMinMaxOrigin::StatAccuracy theAccuracy);
//! \brief Set lower bound of cumulative cut method (between 0 and 1).
void setCumulativeCutLower(double val);
//! \brief Set upper bound of cumulative cut method (between 0 and 1).
void setCumulativeCutUpper(double val);
//! \brief Set factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
void setStdDevFactor(double val);
//////// XML serialization /////////////////////
//! \brief Serialize object.
void writeXml( QDomDocument& doc, QDomElement& parentElem ) const;
//! \brief Deserialize object.
void readXml( const QDomElement& elem );
//////// Static methods /////////////////////
//! \brief Return a string to serialize Limits
static QString limitsString( QgsRasterMinMaxOrigin::Limits theLimits );
//! \brief Deserialize Limits
static QgsRasterMinMaxOrigin::Limits limitsFromString( const QString& theLimits );
//! \brief Return a string to serialize Extent
static QString extentString( QgsRasterMinMaxOrigin::Extent theExtent );
//! \brief Deserialize Extent
static QgsRasterMinMaxOrigin::Extent extentFromString( const QString& theExtent );
//! \brief Return a string to serialize StatAccuracy
static QString statAccuracyString( QgsRasterMinMaxOrigin::StatAccuracy theAccuracy );
//! \brief Deserialize StatAccuracy
static QgsRasterMinMaxOrigin::StatAccuracy statAccuracyFromString( const QString& theAccuracy );
};

View File

@ -6,22 +6,6 @@ class QgsRasterRenderer : QgsRasterInterface
%End %End
public: public:
// Origin of min / max values
enum MinMaxOrigin
{
MinMaxUnknown,
MinMaxUser, // entered by user
// method
MinMaxMinMax,
MinMaxCumulativeCut,
MinMaxStdDev,
// Extent
MinMaxFullExtent,
MinMaxSubExtent,
// Precision
MinMaxEstimated,
MinMaxExact
};
static const QRgb NODATA_COLOR; static const QRgb NODATA_COLOR;
@ -60,14 +44,16 @@ class QgsRasterRenderer : QgsRasterInterface
/** Copies common properties like opacity / transparency data from other renderer. /** Copies common properties like opacity / transparency data from other renderer.
* Useful when cloning renderers. * Useful when cloning renderers.
* @note added in 2.16 */ * @note added in 2.16 */
void copyCommonProperties( const QgsRasterRenderer* other ); void copyCommonProperties( const QgsRasterRenderer* other, bool copyMinMaxOrigin = true );
/** Returns a list of band numbers used by the renderer*/ /** Returns a list of band numbers used by the renderer*/
virtual QList<int> usesBands() const; virtual QList<int> usesBands() const;
static QString minMaxOriginName( int theOrigin ); //! Returns const reference to origin of min/max values
static QString minMaxOriginLabel( int theOrigin ); const QgsRasterMinMaxOrigin& minMaxOrigin() const;
static int minMaxOriginFromName( const QString& theName );
//! Sets origin of min/max values
void setMinMaxOrigin( const QgsRasterMinMaxOrigin& theOrigin );
protected: protected:

View File

@ -40,8 +40,6 @@ class QgsSingleBandPseudoColorRenderer: QgsRasterRenderer
double classificationMax() const; double classificationMax() const;
void setClassificationMin( double min ); void setClassificationMin( double min );
void setClassificationMax( double max ); void setClassificationMax( double max );
int classificationMinMaxOrigin() const;
void setClassificationMinMaxOrigin( int origin );
private: private:

View File

@ -19,7 +19,8 @@ class QgsMultiBandColorRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 ); void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 ); void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 ); int selectedBand( int index = 0 );
void doComputations();
public slots: public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); void loadMinMax( int theBandNo, double theMin, double theMax );
}; };

View File

@ -37,9 +37,34 @@ class QgsRasterMinMaxWidget: QWidget
/** Return the selected sample size. */ /** Return the selected sample size. */
int sampleSize(); int sampleSize();
// Load programmaticaly with current values //! \brief Set the "source" of min/max values.
void load(); void setFromMinMaxOrigin( const QgsRasterMinMaxOrigin& );
//! \brief Return a QgsRasterMinMaxOrigin object with the widget values.
QgsRasterMinMaxOrigin minMaxOrigin();
//! Hide updated extent radio button
void hideUpdatedExtent();
//! Load programmaticaly with current values
void doComputations();
//! Uncheck cumulative cut, min/max, std-dev radio buttons
void userHasSetManualMinMaxValues();
//! Return if the widget is collaped.
bool isCollapsed() const;
//! Set collapsed state of widget
void setCollapsed(bool b);
signals: signals:
void load( int theBandNo, double theMin, double theMax, int origin ); /**
* Emitted when something on the widget has changed.
* All widgets will fire this event to notify of an internal change.
*/
void widgetChanged();
//! signal emitted when new min/max values are computed from statistics.
void load( int theBandNo, double theMin, double theMax );
}; };

View File

@ -7,14 +7,6 @@ class QgsRasterRendererWidget: QWidget
QgsRasterRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ); QgsRasterRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent );
virtual ~QgsRasterRendererWidget(); virtual ~QgsRasterRendererWidget();
enum LoadMinMaxAlgo
{
Estimate,
Actual,
CurrentExtent,
CumulativeCut // 2 - 98% cumulative cut
};
virtual QgsRasterRenderer* renderer() = 0 /Factory/; virtual QgsRasterRenderer* renderer() = 0 /Factory/;
void setRasterLayer( QgsRasterLayer* layer ); void setRasterLayer( QgsRasterLayer* layer );
@ -42,6 +34,8 @@ class QgsRasterRendererWidget: QWidget
virtual QString stdDev(); virtual QString stdDev();
virtual void setStdDev( const QString& value ); virtual void setStdDev( const QString& value );
virtual int selectedBand( int index = 0 ); virtual int selectedBand( int index = 0 );
virtual void doComputations();
virtual QgsRasterMinMaxWidget* minMaxWidget();
signals: signals:
/** /**

View File

@ -19,7 +19,8 @@ class QgsSingleBandGrayRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 ); void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 ); void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 ); int selectedBand( int index = 0 );
void doComputations();
public slots: public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); void loadMinMax( int theBandNo, double theMin, double theMax );
}; };

View File

@ -21,12 +21,14 @@ class QgsSingleBandPseudoColorRendererWidget : QgsRasterRendererWidget
void setFromRenderer( const QgsRasterRenderer* r ); void setFromRenderer( const QgsRasterRenderer* r );
void doComputations();
public slots: public slots:
/** Executes the single band pseudo raster classficiation /** Executes the single band pseudo raster classficiation
*/ */
void classify(); void classify();
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); void loadMinMax( int theBandNo, double theMin, double theMax );
}; };

View File

@ -8845,11 +8845,9 @@ void QgisApp::legendLayerStretchUsingCurrentExtent()
QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( currentLayer ); QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( currentLayer );
if ( layer ) if ( layer )
{ {
QgsContrastEnhancement::ContrastEnhancementAlgorithm contrastEnhancementAlgorithm = QgsContrastEnhancement::StretchToMinimumMaximum;
QgsRectangle myRectangle; QgsRectangle myRectangle;
myRectangle = mMapCanvas->mapSettings().outputExtentToLayerExtent( layer, mMapCanvas->extent() ); myRectangle = mMapCanvas->mapSettings().outputExtentToLayerExtent( layer, mMapCanvas->extent() );
layer->setContrastEnhancement( contrastEnhancementAlgorithm, QgsRaster::ContrastEnhancementMinMax, myRectangle ); layer->refreshContrastEnhancement( myRectangle );
mLayerTreeView->refreshLayerSymbology( layer->id() ); mLayerTreeView->refreshLayerSymbology( layer->id() );
mMapCanvas->refresh(); mMapCanvas->refresh();
@ -9176,25 +9174,25 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString& currentPage )
void QgisApp::fullHistogramStretch() void QgisApp::fullHistogramStretch()
{ {
histogramStretch( false, QgsRaster::ContrastEnhancementMinMax ); histogramStretch( false, QgsRasterMinMaxOrigin::MinMax );
} }
void QgisApp::localHistogramStretch() void QgisApp::localHistogramStretch()
{ {
histogramStretch( true, QgsRaster::ContrastEnhancementMinMax ); histogramStretch( true, QgsRasterMinMaxOrigin::MinMax );
} }
void QgisApp::fullCumulativeCutStretch() void QgisApp::fullCumulativeCutStretch()
{ {
histogramStretch( false, QgsRaster::ContrastEnhancementCumulativeCut ); histogramStretch( false, QgsRasterMinMaxOrigin::CumulativeCut );
} }
void QgisApp::localCumulativeCutStretch() void QgisApp::localCumulativeCutStretch()
{ {
histogramStretch( true, QgsRaster::ContrastEnhancementCumulativeCut ); histogramStretch( true, QgsRasterMinMaxOrigin::CumulativeCut );
} }
void QgisApp::histogramStretch( bool visibleAreaOnly, QgsRaster::ContrastEnhancementLimits theLimits ) void QgisApp::histogramStretch( bool visibleAreaOnly, QgsRasterMinMaxOrigin::Limits theLimits )
{ {
QgsMapLayer * myLayer = mLayerTreeView->currentLayer(); QgsMapLayer * myLayer = mLayerTreeView->currentLayer();

View File

@ -125,6 +125,7 @@ class QgsDiagramProperties;
#include "qgsmimedatautils.h" #include "qgsmimedatautils.h"
#include "qgswelcomepageitemsmodel.h" #include "qgswelcomepageitemsmodel.h"
#include "qgsraster.h" #include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"
#include "ui_qgisapp.h" #include "ui_qgisapp.h"
@ -1526,7 +1527,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void createDecorations(); void createDecorations();
//! Do histogram stretch for singleband gray / multiband color rasters //! Do histogram stretch for singleband gray / multiband color rasters
void histogramStretch( bool visibleAreaOnly = false, QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax ); void histogramStretch( bool visibleAreaOnly = false, QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax );
//! Apply raster brightness //! Apply raster brightness
void adjustBrightnessContrast( int delta, bool updateBrightness = true ); void adjustBrightnessContrast( int delta, bool updateBrightness = true );

View File

@ -42,6 +42,7 @@
#include "qgsmaplayerconfigwidget.h" #include "qgsmaplayerconfigwidget.h"
#include "qgsmaplayerstylemanagerwidget.h" #include "qgsmaplayerstylemanagerwidget.h"
#include "qgsruntimeprofiler.h" #include "qgsruntimeprofiler.h"
#include "qgsrasterminmaxwidget.h"
QgsLayerStylingWidget::QgsLayerStylingWidget( QgsMapCanvas* canvas, const QList<QgsMapLayerConfigWidgetFactory*>& pages, QWidget *parent ) QgsLayerStylingWidget::QgsLayerStylingWidget( QgsMapCanvas* canvas, const QList<QgsMapLayerConfigWidgetFactory*>& pages, QWidget *parent )
@ -378,15 +379,47 @@ void QgsLayerStylingWidget::updateCurrentWidgetLayer()
else if ( mCurrentLayer->type() == QgsMapLayer::RasterLayer ) else if ( mCurrentLayer->type() == QgsMapLayer::RasterLayer )
{ {
QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer*>( mCurrentLayer ); QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer*>( mCurrentLayer );
bool hasMinMaxCollapsedState = false;
bool minMaxCollapsed = false;
switch ( row ) switch ( row )
{ {
case 0: // Style case 0: // Style
{
// Backup collapsed state of min/max group so as to restore it
// on the new widget.
if ( mRasterStyleWidget )
{
QgsRasterRendererWidget* currentRenderWidget = mRasterStyleWidget->currentRenderWidget();
if ( currentRenderWidget )
{
QgsRasterMinMaxWidget* mmWidget = currentRenderWidget->minMaxWidget();
if ( mmWidget )
{
hasMinMaxCollapsedState = true;
minMaxCollapsed = mmWidget->isCollapsed();
}
}
}
mRasterStyleWidget = new QgsRendererRasterPropertiesWidget( rlayer, mMapCanvas, mWidgetStack ); mRasterStyleWidget = new QgsRendererRasterPropertiesWidget( rlayer, mMapCanvas, mWidgetStack );
if ( hasMinMaxCollapsedState )
{
QgsRasterRendererWidget* currentRenderWidget = mRasterStyleWidget->currentRenderWidget();
if ( currentRenderWidget )
{
QgsRasterMinMaxWidget* mmWidget = currentRenderWidget->minMaxWidget();
if ( mmWidget )
{
mmWidget->setCollapsed( minMaxCollapsed );
}
}
}
mRasterStyleWidget->setDockMode( true ); mRasterStyleWidget->setDockMode( true );
connect( mRasterStyleWidget, SIGNAL( widgetChanged() ), this, SLOT( autoApply() ) ); connect( mRasterStyleWidget, SIGNAL( widgetChanged() ), this, SLOT( autoApply() ) );
mWidgetStack->setMainPanel( mRasterStyleWidget ); mWidgetStack->setMainPanel( mRasterStyleWidget );
break; break;
}
case 1: // Transparency case 1: // Transparency
{ {
QgsRasterTransparencyWidget* transwidget = new QgsRasterTransparencyWidget( rlayer, mMapCanvas, mWidgetStack ); QgsRasterTransparencyWidget* transwidget = new QgsRasterTransparencyWidget( rlayer, mMapCanvas, mWidgetStack );

View File

@ -31,6 +31,8 @@
#include "qgsproject.h" #include "qgsproject.h"
#include "qgsdualview.h" #include "qgsdualview.h"
#include "qgsrasterlayer.h" #include "qgsrasterlayer.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"
#include "qgsattributetablefiltermodel.h" #include "qgsattributetablefiltermodel.h"
#include "qgsrasterformatsaveoptionswidget.h" #include "qgsrasterformatsaveoptionswidget.h"
@ -653,22 +655,24 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
spnGreen->setValue( mSettings->value( QStringLiteral( "/Raster/defaultGreenBand" ), 2 ).toInt() ); spnGreen->setValue( mSettings->value( QStringLiteral( "/Raster/defaultGreenBand" ), 2 ).toInt() );
spnBlue->setValue( mSettings->value( QStringLiteral( "/Raster/defaultBlueBand" ), 3 ).toInt() ); spnBlue->setValue( mSettings->value( QStringLiteral( "/Raster/defaultBlueBand" ), 3 ).toInt() );
initContrastEnhancement( cboxContrastEnhancementAlgorithmSingleBand, QStringLiteral( "singleBand" ), QStringLiteral( "StretchToMinimumMaximum" ) ); initContrastEnhancement( cboxContrastEnhancementAlgorithmSingleBand, QStringLiteral( "singleBand" ),
initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ), QStringLiteral( "NoEnhancement" ) ); QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsRasterLayer::SINGLE_BAND_ENHANCEMENT_ALGORITHM ) );
initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ), QStringLiteral( "StretchToMinimumMaximum" ) ); initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM ) );
initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM ) );
cboxContrastEnhancementLimits->addItem( tr( "Cumulative pixel count cut" ), "CumulativeCut" ); initMinMaxLimits( cboxContrastEnhancementLimitsSingleBand, QStringLiteral( "singleBand" ),
cboxContrastEnhancementLimits->addItem( tr( "Minimum / maximum" ), "MinMax" ); QgsRasterMinMaxOrigin::limitsString( QgsRasterLayer::SINGLE_BAND_MIN_MAX_LIMITS ) );
cboxContrastEnhancementLimits->addItem( tr( "Mean +/- standard deviation" ), "StdDev" ); initMinMaxLimits( cboxContrastEnhancementLimitsMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS ) );
initMinMaxLimits( cboxContrastEnhancementLimitsMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS ) );
QString contrastEnchacementLimits = mSettings->value( QStringLiteral( "/Raster/defaultContrastEnhancementLimits" ), "CumulativeCut" ).toString(); spnThreeBandStdDev->setValue( mSettings->value( QStringLiteral( "/Raster/defaultStandardDeviation" ), QgsRasterMinMaxOrigin::DEFAULT_STDDEV_FACTOR ).toDouble() );
cboxContrastEnhancementLimits->setCurrentIndex( cboxContrastEnhancementLimits->findData( contrastEnchacementLimits ) ); mRasterCumulativeCutLowerDoubleSpinBox->setValue( 100.0 * mSettings->value( QStringLiteral( "/Raster/cumulativeCutLower" ), QString::number( QgsRasterMinMaxOrigin::CUMULATIVE_CUT_LOWER ) ).toDouble() );
mRasterCumulativeCutUpperDoubleSpinBox->setValue( 100.0 * mSettings->value( QStringLiteral( "/Raster/cumulativeCutUpper" ), QString::number( QgsRasterMinMaxOrigin::CUMULATIVE_CUT_UPPER ) ).toDouble() );
spnThreeBandStdDev->setValue( mSettings->value( QStringLiteral( "/Raster/defaultStandardDeviation" ), 2.0 ).toDouble() );
mRasterCumulativeCutLowerDoubleSpinBox->setValue( 100.0 * mSettings->value( QStringLiteral( "/Raster/cumulativeCutLower" ), QString::number( QgsRasterLayer::CUMULATIVE_CUT_LOWER ) ).toDouble() );
mRasterCumulativeCutUpperDoubleSpinBox->setValue( 100.0 * mSettings->value( QStringLiteral( "/Raster/cumulativeCutUpper" ), QString::number( QgsRasterLayer::CUMULATIVE_CUT_UPPER ) ).toDouble() );
//set the color for selections //set the color for selections
int myRed = mSettings->value( QStringLiteral( "/qgis/default_selection_color_red" ), 255 ).toInt(); int myRed = mSettings->value( QStringLiteral( "/qgis/default_selection_color_red" ), 255 ).toInt();
@ -1268,8 +1272,9 @@ void QgsOptions::saveOptions()
saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ) ); saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ) );
saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ) ); saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ) );
QString contrastEnhancementLimits = cboxContrastEnhancementLimits->currentData().toString(); saveMinMaxLimits( cboxContrastEnhancementLimitsSingleBand, QStringLiteral( "singleBand" ) );
mSettings->setValue( QStringLiteral( "/Raster/defaultContrastEnhancementLimits" ), contrastEnhancementLimits ); saveMinMaxLimits( cboxContrastEnhancementLimitsMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ) );
saveMinMaxLimits( cboxContrastEnhancementLimitsMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ) );
mSettings->setValue( QStringLiteral( "/Raster/defaultStandardDeviation" ), spnThreeBandStdDev->value() ); mSettings->setValue( QStringLiteral( "/Raster/defaultStandardDeviation" ), spnThreeBandStdDev->value() );
@ -2071,14 +2076,18 @@ void QgsOptions::initContrastEnhancement( QComboBox *cbox, const QString& name,
{ {
QSettings settings; QSettings settings;
//add items to the color enhanceContrast combo box //add items to the color enhanceContrast combo boxes
cbox->addItem( tr( "No Stretch" ), "NoEnhancement" ); cbox->addItem( tr( "No Stretch" ),
cbox->addItem( tr( "Stretch To MinMax" ), "StretchToMinimumMaximum" ); QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsContrastEnhancement::NoEnhancement ) );
cbox->addItem( tr( "Stretch And Clip To MinMax" ), "StretchAndClipToMinimumMaximum" ); cbox->addItem( tr( "Stretch To MinMax" ),
cbox->addItem( tr( "Clip To MinMax" ), "ClipToMinimumMaximum" ); QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsContrastEnhancement::StretchToMinimumMaximum ) );
cbox->addItem( tr( "Stretch And Clip To MinMax" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsContrastEnhancement::StretchAndClipToMinimumMaximum ) );
cbox->addItem( tr( "Clip To MinMax" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsContrastEnhancement::ClipToMinimumMaximum ) );
QString contrastEnchacement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString(); QString contrastEnhancement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastEnchacement ) ); cbox->setCurrentIndex( cbox->findData( contrastEnhancement ) );
} }
void QgsOptions::saveContrastEnhancement( QComboBox *cbox, const QString& name ) void QgsOptions::saveContrastEnhancement( QComboBox *cbox, const QString& name )
@ -2088,6 +2097,29 @@ void QgsOptions::saveContrastEnhancement( QComboBox *cbox, const QString& name )
mSettings->setValue( "/Raster/defaultContrastEnhancementAlgorithm/" + name, value ); mSettings->setValue( "/Raster/defaultContrastEnhancementAlgorithm/" + name, value );
} }
void QgsOptions::initMinMaxLimits( QComboBox *cbox, const QString& name, const QString& defaultVal )
{
QSettings settings;
//add items to the color limitsContrast combo boxes
cbox->addItem( tr( "Cumulative pixel count cut" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterMinMaxOrigin::CumulativeCut ) );
cbox->addItem( tr( "Minimum / maximum" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterMinMaxOrigin::MinMax ) );
cbox->addItem( tr( "Mean +/- standard deviation" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterMinMaxOrigin::StdDev ) );
QString contrastLimits = mSettings->value( "/Raster/defaultContrastEnhancementLimits/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastLimits ) );
}
void QgsOptions::saveMinMaxLimits( QComboBox *cbox, const QString& name )
{
QSettings settings;
QString value = cbox->currentData().toString();
mSettings->setValue( "/Raster/defaultContrastEnhancementLimits/" + name, value );
}
void QgsOptions::on_mRemoveDefaultTransformButton_clicked() void QgsOptions::on_mRemoveDefaultTransformButton_clicked()
{ {
QList<QTreeWidgetItem*> items = mDefaultDatumTransformTreeWidget->selectedItems(); QList<QTreeWidgetItem*> items = mDefaultDatumTransformTreeWidget->selectedItems();

View File

@ -206,6 +206,8 @@ class APP_EXPORT QgsOptions : public QgsOptionsDialogBase, private Ui::QgsOption
QStringList i18nList(); QStringList i18nList();
void initContrastEnhancement( QComboBox *cbox, const QString& name, const QString& defaultVal ); void initContrastEnhancement( QComboBox *cbox, const QString& name, const QString& defaultVal );
void saveContrastEnhancement( QComboBox *cbox, const QString& name ); void saveContrastEnhancement( QComboBox *cbox, const QString& name );
void initMinMaxLimits( QComboBox *cbox, const QString& name, const QString& defaultVal );
void saveMinMaxLimits( QComboBox *cbox, const QString& name );
QgsCoordinateReferenceSystem mDefaultCrs; QgsCoordinateReferenceSystem mDefaultCrs;
QgsCoordinateReferenceSystem mLayerDefaultCrs; QgsCoordinateReferenceSystem mLayerDefaultCrs;
bool mLoadedGdalDriverList; bool mLoadedGdalDriverList;

View File

@ -855,6 +855,8 @@ void QgsRasterLayerProperties::apply()
QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( mRendererStackedWidget->currentWidget() ); QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( mRendererStackedWidget->currentWidget() );
if ( rendererWidget ) if ( rendererWidget )
{ {
rendererWidget->doComputations();
mRasterLayer->setRenderer( rendererWidget->renderer() ); mRasterLayer->setRenderer( rendererWidget->renderer() );
} }

View File

@ -318,6 +318,7 @@ SET(QGIS_CORE_SRCS
raster/qgsrasteriterator.cpp raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp raster/qgsrasterlayer.cpp
raster/qgsrasterlayerrenderer.cpp raster/qgsrasterlayerrenderer.cpp
raster/qgsrasterminmaxorigin.cpp
raster/qgsrasternuller.cpp raster/qgsrasternuller.cpp
raster/qgsrasterpipe.cpp raster/qgsrasterpipe.cpp
raster/qgsrasterprojector.cpp raster/qgsrasterprojector.cpp
@ -800,6 +801,7 @@ SET(QGIS_CORE_HDRS
raster/qgsrasteridentifyresult.h raster/qgsrasteridentifyresult.h
raster/qgsrasterinterface.h raster/qgsrasterinterface.h
raster/qgsrasteriterator.h raster/qgsrasteriterator.h
raster/qgsrasterminmaxorigin.h
raster/qgsrasternuller.h raster/qgsrasternuller.h
raster/qgsrasterpipe.h raster/qgsrasterpipe.h
raster/qgsrasterprojector.h raster/qgsrasterprojector.h

View File

@ -32,6 +32,15 @@
QVERIFY( qgsDoubleNear( value, expected, epsilon ) ); \ QVERIFY( qgsDoubleNear( value, expected, epsilon ) ); \
} }
#define QGSCOMPARENOTNEAR(value,not_expected,epsilon) { \
bool _xxxresult = qgsDoubleNear( value, not_expected, epsilon ); \
if ( _xxxresult ) \
{ \
qDebug( "Expecting %f to be differerent from %f (diff %f > %f)", static_cast< double >( value ), static_cast< double >( not_expected ), qAbs( static_cast< double >( not_expected ) - value ), static_cast< double >( epsilon ) ); \
} \
QVERIFY( !qgsDoubleNear( value, not_expected, epsilon ) ); \
}
#define QGSCOMPARENEARPOINT(point1,point2,epsilon) { \ #define QGSCOMPARENEARPOINT(point1,point2,epsilon) { \
QGSCOMPARENEAR( point1.x(), point2.x(), epsilon ); \ QGSCOMPARENEAR( point1.x(), point2.x(), epsilon ); \
QGSCOMPARENEAR( point1.y(), point2.y(), epsilon ); \ QGSCOMPARENEAR( point1.y(), point2.y(), epsilon ); \

View File

@ -24,6 +24,7 @@ class originally created circa 2004 by T.Sutton, Gary E.Sherman, Steve Halasz
#include <limits> #include <limits>
#include "qgis.h" #include "qgis.h"
#include "qgsraster.h"
class QgsContrastEnhancementFunction; class QgsContrastEnhancementFunction;
class QDomDocument; class QDomDocument;
@ -65,6 +66,12 @@ class CORE_EXPORT QgsContrastEnhancement
//! \brief Helper function that returns the minimum possible value for a GDAL data type //! \brief Helper function that returns the minimum possible value for a GDAL data type
static double minimumValuePossible( Qgis::DataType ); static double minimumValuePossible( Qgis::DataType );
//! \brief Return a string to serialize ContrastEnhancementAlgorithm
static QString contrastEnhancementAlgorithmString( ContrastEnhancementAlgorithm algorithm );
//! \brief Deserialize ContrastEnhancementAlgorithm
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString( const QString& contrastEnhancementString );
/* /*
* *
* Non-Static Inline methods * Non-Static Inline methods
@ -78,10 +85,6 @@ class CORE_EXPORT QgsContrastEnhancement
ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const { return mContrastEnhancementAlgorithm; } ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const { return mContrastEnhancementAlgorithm; }
static QString contrastEnhancementAlgorithmString( ContrastEnhancementAlgorithm algorithm );
static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString( const QString& contrastEnhancementString );
/* /*
* *
* Non-Static methods * Non-Static methods
@ -137,8 +140,6 @@ class CORE_EXPORT QgsContrastEnhancement
//! \brief Maximum range of values for a given data type //! \brief Maximum range of values for a given data type
double mRasterDataTypeRange; double mRasterDataTypeRange;
//! \brief Method to generate a new lookup table //! \brief Method to generate a new lookup table
bool generateLookupTable(); bool generateLookupTable();

View File

@ -19,39 +19,6 @@
#include "qgsraster.h" #include "qgsraster.h"
QString QgsRaster::contrastEnhancementLimitsAsString( ContrastEnhancementLimits theLimits )
{
switch ( theLimits )
{
case QgsRaster::ContrastEnhancementMinMax:
return QStringLiteral( "MinMax" );
case QgsRaster::ContrastEnhancementStdDev:
return QStringLiteral( "StdDev" );
case QgsRaster::ContrastEnhancementCumulativeCut:
return QStringLiteral( "CumulativeCut" );
default:
break;
}
return QStringLiteral( "None" );
}
QgsRaster::ContrastEnhancementLimits QgsRaster::contrastEnhancementLimitsFromString( const QString& theLimits )
{
if ( theLimits == QLatin1String( "MinMax" ) )
{
return ContrastEnhancementMinMax;
}
else if ( theLimits == QLatin1String( "StdDev" ) )
{
return ContrastEnhancementStdDev;
}
else if ( theLimits == QLatin1String( "CumulativeCut" ) )
{
return ContrastEnhancementCumulativeCut;
}
return ContrastEnhancementNone;
}
bool QgsRaster::isRepresentableValue( double value, Qgis::DataType dataType ) bool QgsRaster::isRepresentableValue( double value, Qgis::DataType dataType )
{ {
switch ( dataType ) switch ( dataType )

View File

@ -99,15 +99,6 @@ class CORE_EXPORT QgsRaster
PyramidsErdas = 2 PyramidsErdas = 2
}; };
//! \brief Contrast enhancement limits
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};
//! \brief This enumerator describes the different kinds of drawing we can do //! \brief This enumerator describes the different kinds of drawing we can do
enum DrawingStyle enum DrawingStyle
{ {
@ -124,9 +115,6 @@ class CORE_EXPORT QgsRaster
SingleBandColorDataStyle // ARGB values rendered directly SingleBandColorDataStyle // ARGB values rendered directly
}; };
static QString contrastEnhancementLimitsAsString( QgsRaster::ContrastEnhancementLimits theLimits );
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( const QString& theLimits );
/** Check if the specified value is representable in the given data type. /** Check if the specified value is representable in the given data type.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64. * Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* @param value * @param value

View File

@ -78,10 +78,22 @@ typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QStrin
#define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer") #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer")
const double QgsRasterLayer::CUMULATIVE_CUT_LOWER = 0.02;
const double QgsRasterLayer::CUMULATIVE_CUT_UPPER = 0.98;
const double QgsRasterLayer::SAMPLE_SIZE = 250000; const double QgsRasterLayer::SAMPLE_SIZE = 250000;
const QgsContrastEnhancement::ContrastEnhancementAlgorithm
QgsRasterLayer::SINGLE_BAND_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::StretchToMinimumMaximum;
const QgsContrastEnhancement::ContrastEnhancementAlgorithm
QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::NoEnhancement;
const QgsContrastEnhancement::ContrastEnhancementAlgorithm
QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM = QgsContrastEnhancement::StretchToMinimumMaximum;
const QgsRasterMinMaxOrigin::Limits
QgsRasterLayer::SINGLE_BAND_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::MinMax;
const QgsRasterMinMaxOrigin::Limits
QgsRasterLayer::MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::MinMax;
const QgsRasterMinMaxOrigin::Limits
QgsRasterLayer::MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS = QgsRasterMinMaxOrigin::CumulativeCut;
QgsRasterLayer::QgsRasterLayer() QgsRasterLayer::QgsRasterLayer()
: QgsMapLayer( RasterLayer ) : QgsMapLayer( RasterLayer )
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) ) , QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
@ -835,30 +847,86 @@ void QgsRasterLayer::closeDataProvider()
mDataProvider = nullptr; mDataProvider = nullptr;
} }
void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRaster::ContrastEnhancementLimits theLimits, const QgsRectangle& theExtent, int theSampleSize, bool theGenerateLookupTableFlag ) void QgsRasterLayer::computeMinMax( int band,
const QgsRasterMinMaxOrigin& mmo,
QgsRasterMinMaxOrigin::Limits limits,
const QgsRectangle& extent,
int sampleSize,
double& min, double& max )
{
min = std::numeric_limits<double>::quiet_NaN();
max = std::numeric_limits<double>::quiet_NaN();
if ( limits == QgsRasterMinMaxOrigin::MinMax )
{
QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Min | QgsRasterBandStats::Max, extent, sampleSize );
min = myRasterBandStats.minimumValue;
max = myRasterBandStats.maximumValue;
}
else if ( limits == QgsRasterMinMaxOrigin::StdDev )
{
QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( band, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, extent, sampleSize );
min = myRasterBandStats.mean - ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
max = myRasterBandStats.mean + ( mmo.stdDevFactor() * myRasterBandStats.stdDev );
}
else if ( limits == QgsRasterMinMaxOrigin::CumulativeCut )
{
const double myLower = mmo.cumulativeCutLower();
const double myUpper = mmo.cumulativeCutUpper();
QgsDebugMsgLevel( QString( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
mDataProvider->cumulativeCut( band, myLower, myUpper, min, max, extent, sampleSize );
}
QgsDebugMsgLevel( QString( "band = %1 min = %2 max = %3" ).arg( band ).arg( min ).arg( max ), 4 );
}
void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRasterMinMaxOrigin::Limits theLimits, const QgsRectangle& theExtent, int theSampleSize, bool theGenerateLookupTableFlag )
{
setContrastEnhancement( theAlgorithm,
theLimits,
theExtent,
theSampleSize,
theGenerateLookupTableFlag,
mPipe.renderer() );
}
void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRasterMinMaxOrigin::Limits theLimits,
const QgsRectangle& theExtent,
int theSampleSize,
bool theGenerateLookupTableFlag,
QgsRasterRenderer* rasterRenderer )
{ {
QgsDebugMsgLevel( QString( "theAlgorithm = %1 theLimits = %2 theExtent.isEmpty() = %3" ).arg( theAlgorithm ).arg( theLimits ).arg( theExtent.isEmpty() ), 4 ); QgsDebugMsgLevel( QString( "theAlgorithm = %1 theLimits = %2 theExtent.isEmpty() = %3" ).arg( theAlgorithm ).arg( theLimits ).arg( theExtent.isEmpty() ), 4 );
if ( !mPipe.renderer() || !mDataProvider ) if ( !rasterRenderer || !mDataProvider )
{ {
return; return;
} }
QList<int> myBands; QList<int> myBands;
QList<QgsContrastEnhancement*> myEnhancements; QList<QgsContrastEnhancement*> myEnhancements;
QgsRasterMinMaxOrigin myMinMaxOrigin;
QgsRasterRenderer* myRasterRenderer = nullptr;
QgsSingleBandGrayRenderer* myGrayRenderer = nullptr; QgsSingleBandGrayRenderer* myGrayRenderer = nullptr;
QgsMultiBandColorRenderer* myMultiBandRenderer = nullptr; QgsMultiBandColorRenderer* myMultiBandRenderer = nullptr;
QString rendererType = mPipe.renderer()->type(); QString rendererType = rasterRenderer->type();
if ( rendererType == QLatin1String( "singlebandgray" ) ) if ( rendererType == QLatin1String( "singlebandgray" ) )
{ {
myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() ); myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( rasterRenderer );
if ( !myGrayRenderer ) return; if ( !myGrayRenderer ) return;
myBands << myGrayRenderer->grayBand(); myBands << myGrayRenderer->grayBand();
myRasterRenderer = myGrayRenderer;
myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
} }
else if ( rendererType == QLatin1String( "multibandcolor" ) ) else if ( rendererType == QLatin1String( "multibandcolor" ) )
{ {
myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() ); myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( rasterRenderer );
if ( !myMultiBandRenderer ) return; if ( !myMultiBandRenderer ) return;
myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand(); myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
myRasterRenderer = myMultiBandRenderer;
myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
} }
Q_FOREACH ( int myBand, myBands ) Q_FOREACH ( int myBand, myBands )
@ -869,34 +937,12 @@ void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnh
QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) ); QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) );
myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag ); myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
double myMin = std::numeric_limits<double>::quiet_NaN(); double min;
double myMax = std::numeric_limits<double>::quiet_NaN(); double max;
computeMinMax( myBand, myMinMaxOrigin, theLimits, theExtent, theSampleSize, min, max );
if ( theLimits == QgsRaster::ContrastEnhancementMinMax ) myEnhancement->setMinimumValue( min );
{ myEnhancement->setMaximumValue( max );
QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, theExtent, theSampleSize );
myMin = myRasterBandStats.minimumValue;
myMax = myRasterBandStats.maximumValue;
}
else if ( theLimits == QgsRaster::ContrastEnhancementStdDev )
{
double myStdDev = 1; // make optional?
QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, theExtent, theSampleSize );
myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
}
else if ( theLimits == QgsRaster::ContrastEnhancementCumulativeCut )
{
QSettings mySettings;
double myLower = mySettings.value( QStringLiteral( "/Raster/cumulativeCutLower" ), QString::number( CUMULATIVE_CUT_LOWER ) ).toDouble();
double myUpper = mySettings.value( QStringLiteral( "/Raster/cumulativeCutUpper" ), QString::number( CUMULATIVE_CUT_UPPER ) ).toDouble();
QgsDebugMsgLevel( QString( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ), 4 );
mDataProvider->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, theExtent, theSampleSize );
}
QgsDebugMsgLevel( QString( "myBand = %1 myMin = %2 myMax = %3" ).arg( myBand ).arg( myMin ).arg( myMax ), 4 );
myEnhancement->setMinimumValue( myMin );
myEnhancement->setMaximumValue( myMax );
myEnhancements.append( myEnhancement ); myEnhancements.append( myEnhancement );
} }
else else
@ -919,57 +965,208 @@ void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnh
//delete all remaining unused enhancements //delete all remaining unused enhancements
qDeleteAll( myEnhancements ); qDeleteAll( myEnhancements );
emit repaintRequested(); myMinMaxOrigin.setLimits( theLimits );
emit styleChanged(); if ( theExtent != QgsRectangle() &&
myMinMaxOrigin.extent() == QgsRasterMinMaxOrigin::WholeRaster )
{
myMinMaxOrigin.setExtent( QgsRasterMinMaxOrigin::CurrentCanvas );
}
if ( myRasterRenderer )
{
myRasterRenderer->setMinMaxOrigin( myMinMaxOrigin );
}
if ( rasterRenderer == renderer() )
{
emit repaintRequested();
emit styleChanged();
emit rendererChanged();
}
}
void QgsRasterLayer::refreshContrastEnhancement( const QgsRectangle& theExtent )
{
QgsSingleBandGrayRenderer* singleBandRenderer = nullptr;
QgsMultiBandColorRenderer* multiBandRenderer = nullptr;
const QgsContrastEnhancement* ce = nullptr;
if (( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) ) )
{
ce = singleBandRenderer->contrastEnhancement();
}
else if (( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) ) )
{
ce = multiBandRenderer->redContrastEnhancement();
}
if ( ce )
{
setContrastEnhancement( ce->contrastEnhancementAlgorithm() == QgsContrastEnhancement::NoEnhancement ?
QgsContrastEnhancement::StretchToMinimumMaximum : ce->contrastEnhancementAlgorithm(),
renderer()->minMaxOrigin().limits() == QgsRasterMinMaxOrigin::None ?
QgsRasterMinMaxOrigin::MinMax : renderer()->minMaxOrigin().limits(),
theExtent,
SAMPLE_SIZE,
true,
renderer() );
}
else
{
QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm;
QgsRasterMinMaxOrigin::Limits myLimits;
if ( defaultContrastEnhancementSettings( myAlgorithm, myLimits ) )
{
setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum,
myLimits,
theExtent,
SAMPLE_SIZE,
true,
renderer() );
}
}
}
void QgsRasterLayer::refreshRendererIfNeeded( QgsRasterRenderer* rasterRenderer,
const QgsRectangle& theExtent )
{
if ( !( mDataProvider &&
mLastRectangleUsedByRefreshContrastEnhancementIfNeeded != theExtent &&
rasterRenderer->minMaxOrigin().limits() != QgsRasterMinMaxOrigin::None &&
rasterRenderer->minMaxOrigin().extent() == QgsRasterMinMaxOrigin::UpdatedCanvas ) )
return;
QgsSingleBandGrayRenderer* singleBandRenderer = nullptr;
QgsMultiBandColorRenderer* multiBandRenderer = nullptr;
QgsSingleBandPseudoColorRenderer* sbpcr = nullptr;
const QgsContrastEnhancement* ce = nullptr;
if (( singleBandRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( rasterRenderer ) ) )
{
ce = singleBandRenderer->contrastEnhancement();
}
else if (( multiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( rasterRenderer ) ) )
{
ce = multiBandRenderer->redContrastEnhancement();
}
else if (( sbpcr = dynamic_cast<QgsSingleBandPseudoColorRenderer*>( rasterRenderer ) ) )
{
mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = theExtent;
double min;
double max;
computeMinMax( sbpcr->band(),
rasterRenderer->minMaxOrigin(),
rasterRenderer->minMaxOrigin().limits(), theExtent,
SAMPLE_SIZE, min, max );
sbpcr->setClassificationMin( min );
sbpcr->setClassificationMax( max );
dynamic_cast<QgsSingleBandPseudoColorRenderer*>( renderer() )->setClassificationMin( min );
dynamic_cast<QgsSingleBandPseudoColorRenderer*>( renderer() )->setClassificationMax( max );
emit styleChanged();
emit rendererChanged();
return;
}
if ( ce &&
ce->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement )
{
mLastRectangleUsedByRefreshContrastEnhancementIfNeeded = theExtent;
setContrastEnhancement( ce->contrastEnhancementAlgorithm(),
rasterRenderer->minMaxOrigin().limits(),
theExtent,
SAMPLE_SIZE,
true,
rasterRenderer );
// Update main renderer so that the legends get updated
if ( singleBandRenderer )
dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() )->setContrastEnhancement( new QgsContrastEnhancement( * singleBandRenderer->contrastEnhancement() ) );
else if ( multiBandRenderer )
{
if ( multiBandRenderer->redContrastEnhancement() )
{
dynamic_cast<QgsMultiBandColorRenderer*>( renderer() )->setRedContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->redContrastEnhancement() ) );
}
if ( multiBandRenderer->greenContrastEnhancement() )
{
dynamic_cast<QgsMultiBandColorRenderer*>( renderer() )->setGreenContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->greenContrastEnhancement() ) );
}
if ( multiBandRenderer->blueContrastEnhancement() )
{
dynamic_cast<QgsMultiBandColorRenderer*>( renderer() )->setBlueContrastEnhancement( new QgsContrastEnhancement( *multiBandRenderer->blueContrastEnhancement() ) );
}
}
emit styleChanged();
emit rendererChanged();
}
}
bool QgsRasterLayer::defaultContrastEnhancementSettings(
QgsContrastEnhancement::ContrastEnhancementAlgorithm& myAlgorithm,
QgsRasterMinMaxOrigin::Limits& myLimits ) const
{
QSettings mySettings;
QString key;
QString defaultAlg;
QString defaultLimits;
// TODO: we should not test renderer class here, move it somehow to renderers
if ( dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) )
{
key = QStringLiteral( "singleBand" );
defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
SINGLE_BAND_ENHANCEMENT_ALGORITHM );
defaultLimits = QgsRasterMinMaxOrigin::limitsString(
SINGLE_BAND_MIN_MAX_LIMITS );
}
else if ( dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) )
{
if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
{
key = QStringLiteral( "multiBandSingleByte" );
defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM );
defaultLimits = QgsRasterMinMaxOrigin::limitsString(
MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS );
}
else
{
key = QStringLiteral( "multiBandMultiByte" );
defaultAlg = QgsContrastEnhancement::contrastEnhancementAlgorithmString(
MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM );
defaultLimits = QgsRasterMinMaxOrigin::limitsString(
MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS );
}
}
if ( key.isEmpty() )
{
QgsDebugMsg( "No default contrast enhancement for this drawing style" );
myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( QString() );
myLimits = QgsRasterMinMaxOrigin::limitsFromString( QString() );
return false;
}
QgsDebugMsgLevel( "key = " + key, 4 );
QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + key, defaultAlg ).toString();
QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits/" + key, defaultLimits ).toString();
QgsDebugMsgLevel( "myLimitsString = " + myLimitsString, 4 );
myLimits = QgsRasterMinMaxOrigin::limitsFromString( myLimitsString );
return true;
} }
void QgsRasterLayer::setDefaultContrastEnhancement() void QgsRasterLayer::setDefaultContrastEnhancement()
{ {
QgsDebugMsgLevel( "Entered", 4 ); QgsDebugMsgLevel( "Entered", 4 );
QSettings mySettings; QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm;
QgsRasterMinMaxOrigin::Limits myLimits;
QString myKey; defaultContrastEnhancementSettings( myAlgorithm, myLimits );
QString myDefault;
// TODO: we should not test renderer class here, move it somehow to renderers
if ( dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) )
{
myKey = QStringLiteral( "singleBand" );
myDefault = QStringLiteral( "StretchToMinimumMaximum" );
}
else if ( dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) )
{
if ( QgsRasterBlock::typeSize( dataProvider()->sourceDataType( 1 ) ) == 1 )
{
myKey = QStringLiteral( "multiBandSingleByte" );
myDefault = QStringLiteral( "NoEnhancement" );
}
else
{
myKey = QStringLiteral( "multiBandMultiByte" );
myDefault = QStringLiteral( "StretchToMinimumMaximum" );
}
}
if ( myKey.isEmpty() )
{
QgsDebugMsg( "No default contrast enhancement for this drawing style" );
}
QgsDebugMsgLevel( "myKey = " + myKey, 4 );
QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + myKey, myDefault ).toString();
QgsDebugMsgLevel( "myAlgorithmString = " + myAlgorithmString, 4 );
QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString );
if ( myAlgorithm == QgsContrastEnhancement::NoEnhancement )
{
return;
}
QString myLimitsString = mySettings.value( QStringLiteral( "/Raster/defaultContrastEnhancementLimits" ), "CumulativeCut" ).toString();
QgsRaster::ContrastEnhancementLimits myLimits = QgsRaster::contrastEnhancementLimitsFromString( myLimitsString );
setContrastEnhancement( myAlgorithm, myLimits ); setContrastEnhancement( myAlgorithm, myLimits );
} }

View File

@ -33,6 +33,7 @@
#include "qgsraster.h" #include "qgsraster.h"
#include "qgsrasterpipe.h" #include "qgsrasterpipe.h"
#include "qgsrasterviewport.h" #include "qgsrasterviewport.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h" #include "qgscontrastenhancement.h"
class QgsMapToPixel; class QgsMapToPixel;
@ -136,15 +137,28 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
{ {
Q_OBJECT Q_OBJECT
public: public:
//! \brief Default cumulative cut lower limit
static const double CUMULATIVE_CUT_LOWER;
//! \brief Default cumulative cut upper limit
static const double CUMULATIVE_CUT_UPPER;
//! \brief Default sample size (number of pixels) for estimated statistics/histogram calculation //! \brief Default sample size (number of pixels) for estimated statistics/histogram calculation
static const double SAMPLE_SIZE; static const double SAMPLE_SIZE;
//! \brief Default enhancement algorithm for single band raster
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm SINGLE_BAND_ENHANCEMENT_ALGORITHM;
//! \brief Default enhancement algorithm for multiple band raster of type Byte
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_SINGLE_BYTE_ENHANCEMENT_ALGORITHM;
//! \brief Default enhancement algorithm for multiple band raster of type different from Byte
static const QgsContrastEnhancement::ContrastEnhancementAlgorithm MULTIPLE_BAND_MULTI_BYTE_ENHANCEMENT_ALGORITHM;
//! \brief Default enhancement limits for single band raster
static const QgsRasterMinMaxOrigin::Limits SINGLE_BAND_MIN_MAX_LIMITS;
//! \brief Default enhancement limits for multiple band raster of type Byte
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_SINGLE_BYTE_MIN_MAX_LIMITS;
//! \brief Default enhancement limits for multiple band raster of type different from Byte
static const QgsRasterMinMaxOrigin::Limits MULTIPLE_BAND_MULTI_BYTE_MIN_MAX_LIMITS;
//! \brief Constructor. Provider is not set. //! \brief Constructor. Provider is not set.
QgsRasterLayer(); QgsRasterLayer();
@ -291,11 +305,30 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax, QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax,
const QgsRectangle& theExtent = QgsRectangle(), const QgsRectangle& theExtent = QgsRectangle(),
int theSampleSize = SAMPLE_SIZE, int theSampleSize = SAMPLE_SIZE,
bool theGenerateLookupTableFlag = true ); bool theGenerateLookupTableFlag = true );
/** \brief Refresh contrast enhancement with new extent.
* @note not available in python bindings
*/
// Used by QgisApp::legendLayerStretchUsingCurrentExtent()
void refreshContrastEnhancement( const QgsRectangle& theExtent );
/** \brief Refresh renderer with new extent, if needed
* @note not available in python bindings
*/
// Used by QgsRasterLayerRenderer
void refreshRendererIfNeeded( QgsRasterRenderer* rasterRenderer, const QgsRectangle& theExtent );
/** \brief Return default contrast enhancemnt settings for that type of raster.
* @note not available in python bindings
*/
bool defaultContrastEnhancementSettings(
QgsContrastEnhancement::ContrastEnhancementAlgorithm& myAlgorithm,
QgsRasterMinMaxOrigin::Limits& myLimits ) const;
//! \brief Set default contrast enhancement //! \brief Set default contrast enhancement
void setDefaultContrastEnhancement(); void setDefaultContrastEnhancement();
@ -368,6 +401,20 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
//! Sets corresponding renderer for style //! Sets corresponding renderer for style
void setRendererForDrawingStyle( QgsRaster::DrawingStyle theDrawingStyle ); void setRendererForDrawingStyle( QgsRaster::DrawingStyle theDrawingStyle );
void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRasterMinMaxOrigin::Limits theLimits,
const QgsRectangle& theExtent,
int theSampleSize,
bool theGenerateLookupTableFlag,
QgsRasterRenderer* rasterRenderer );
void computeMinMax( int band,
const QgsRasterMinMaxOrigin& mmo,
QgsRasterMinMaxOrigin::Limits limits,
const QgsRectangle& extent,
int sampleSize,
double& min, double& max );
//! \brief Constant defining flag for XML and a constant that signals property not used //! \brief Constant defining flag for XML and a constant that signals property not used
const QString QSTRING_NOT_SET; const QString QSTRING_NOT_SET;
const QString TRSTRING_NOT_SET; const QString TRSTRING_NOT_SET;
@ -386,6 +433,9 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
LayerType mRasterType; LayerType mRasterType;
QgsRasterPipe mPipe; QgsRasterPipe mPipe;
//! To save computations and possible infinite cycle of notifications
QgsRectangle mLastRectangleUsedByRefreshContrastEnhancementIfNeeded;
}; };
#endif #endif

View File

@ -177,6 +177,9 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRender
// copy the whole raster pipe! // copy the whole raster pipe!
mPipe = new QgsRasterPipe( *layer->pipe() ); mPipe = new QgsRasterPipe( *layer->pipe() );
QgsRasterRenderer* rasterRenderer = mPipe->renderer();
if ( rasterRenderer )
layer->refreshRendererIfNeeded( rasterRenderer, myRasterExtent );
} }
QgsRasterLayerRenderer::~QgsRasterLayerRenderer() QgsRasterLayerRenderer::~QgsRasterLayerRenderer()

View File

@ -0,0 +1,205 @@
/***************************************************************************
qgsrasterminmaxorigin.h - Origin of min/max values
--------------------------------------
Date : Dec 2016
Copyright : (C) 2016 by Even Rouault
email : even.rouault at spatialys.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsrasterminmaxorigin.h"
#include <QDomDocument>
#include <QDomElement>
#include <QSettings>
QgsRasterMinMaxOrigin::QgsRasterMinMaxOrigin()
: mLimits( None )
, mExtent( WholeRaster )
, mAccuracy( Estimated )
, mCumulativeCutLower( CUMULATIVE_CUT_LOWER )
, mCumulativeCutUpper( CUMULATIVE_CUT_UPPER )
, mStdDevFactor( DEFAULT_STDDEV_FACTOR )
{
QSettings mySettings;
mCumulativeCutLower = mySettings.value( QStringLiteral( "/Raster/cumulativeCutLower" ), CUMULATIVE_CUT_LOWER ).toDouble();
mCumulativeCutUpper = mySettings.value( QStringLiteral( "/Raster/cumulativeCutUpper" ), CUMULATIVE_CUT_UPPER ).toDouble();
mStdDevFactor = mySettings.value( QStringLiteral( "/Raster/defaultStandardDeviation" ), DEFAULT_STDDEV_FACTOR ).toDouble();
}
bool QgsRasterMinMaxOrigin::operator ==( const QgsRasterMinMaxOrigin& other ) const
{
return mLimits == other.mLimits &&
mExtent == other.mExtent &&
mAccuracy == other.mAccuracy &&
qAbs( mCumulativeCutLower - other.mCumulativeCutLower ) < 1e-5 &&
qAbs( mCumulativeCutUpper - other.mCumulativeCutUpper ) < 1e-5 &&
qAbs( mStdDevFactor - other.mStdDevFactor ) < 1e-5;
}
QString QgsRasterMinMaxOrigin::limitsString( Limits theLimits )
{
switch ( theLimits )
{
case MinMax:
return QStringLiteral( "MinMax" );
case StdDev:
return QStringLiteral( "StdDev" );
case CumulativeCut:
return QStringLiteral( "CumulativeCut" );
default:
break;
}
return QStringLiteral( "None" );
}
QgsRasterMinMaxOrigin::Limits QgsRasterMinMaxOrigin::limitsFromString( const QString& theLimits )
{
if ( theLimits == QLatin1String( "MinMax" ) )
{
return MinMax;
}
else if ( theLimits == QLatin1String( "StdDev" ) )
{
return StdDev;
}
else if ( theLimits == QLatin1String( "CumulativeCut" ) )
{
return CumulativeCut;
}
return None;
}
QString QgsRasterMinMaxOrigin::extentString( Extent minMaxExtent )
{
switch ( minMaxExtent )
{
case WholeRaster:
return QStringLiteral( "WholeRaster" );
case CurrentCanvas:
return QStringLiteral( "CurrentCanvas" );
case UpdatedCanvas:
return QStringLiteral( "UpdatedCanvas" );
}
return QStringLiteral( "WholeRaster" );
}
QgsRasterMinMaxOrigin::Extent QgsRasterMinMaxOrigin::extentFromString( const QString& theExtent )
{
if ( theExtent == QLatin1String( "WholeRaster" ) )
{
return WholeRaster;
}
else if ( theExtent == QLatin1String( "CurrentCanvas" ) )
{
return CurrentCanvas;
}
else if ( theExtent == QLatin1String( "UpdatedCanvas" ) )
{
return UpdatedCanvas;
}
else
{
return WholeRaster;
}
}
QString QgsRasterMinMaxOrigin::statAccuracyString( StatAccuracy theAccuracy )
{
if ( theAccuracy == Exact )
return QStringLiteral( "Exact" );
return QStringLiteral( "Estimated" );
}
QgsRasterMinMaxOrigin::StatAccuracy QgsRasterMinMaxOrigin::statAccuracyFromString( const QString& theAccuracy )
{
if ( theAccuracy == QLatin1String( "Exact" ) )
return Exact;
return Estimated;
}
void QgsRasterMinMaxOrigin::writeXml( QDomDocument& doc, QDomElement& parentElem ) const
{
// limits
QDomElement limitsElem = doc.createElement( QStringLiteral( "limits" ) );
QDomText limitsText = doc.createTextNode( limitsString( mLimits ) );
limitsElem.appendChild( limitsText );
parentElem.appendChild( limitsElem );
// extent
QDomElement extentElem = doc.createElement( QStringLiteral( "extent" ) );
QDomText extentText = doc.createTextNode( extentString( mExtent ) );
extentElem.appendChild( extentText );
parentElem.appendChild( extentElem );
// statAccuracy
QDomElement statAccuracyElem = doc.createElement( QStringLiteral( "statAccuracy" ) );
QDomText statAccuracyText = doc.createTextNode( statAccuracyString( mAccuracy ) );
statAccuracyElem.appendChild( statAccuracyText );
parentElem.appendChild( statAccuracyElem );
// mCumulativeCutLower
QDomElement cumulativeCutLowerElem = doc.createElement( QStringLiteral( "cumulativeCutLower" ) );
QDomText cumulativeCutLowerText = doc.createTextNode( QString::number( mCumulativeCutLower ) );
cumulativeCutLowerElem.appendChild( cumulativeCutLowerText );
parentElem.appendChild( cumulativeCutLowerElem );
// mCumulativeCutUpper
QDomElement cumulativeCutUpperElem = doc.createElement( QStringLiteral( "cumulativeCutUpper" ) );
QDomText cumulativeCutUpperText = doc.createTextNode( QString::number( mCumulativeCutUpper ) );
cumulativeCutUpperElem.appendChild( cumulativeCutUpperText );
parentElem.appendChild( cumulativeCutUpperElem );
// mCumulativeCutUpper
QDomElement stdDevFactorElem = doc.createElement( QStringLiteral( "stdDevFactor" ) );
QDomText stdDevFactorText = doc.createTextNode( QString::number( mStdDevFactor ) );
stdDevFactorElem.appendChild( stdDevFactorText );
parentElem.appendChild( stdDevFactorElem );
}
void QgsRasterMinMaxOrigin::readXml( const QDomElement& elem )
{
QDomElement limitsElem = elem.firstChildElement( QStringLiteral( "limits" ) );
if ( !limitsElem.isNull() )
{
mLimits = limitsFromString( limitsElem.text() );
}
QDomElement extentElem = elem.firstChildElement( QStringLiteral( "extent" ) );
if ( !extentElem.isNull() )
{
mExtent = extentFromString( extentElem.text() );
}
QDomElement statAccuracyElem = elem.firstChildElement( QStringLiteral( "statAccuracy" ) );
if ( !statAccuracyElem.isNull() )
{
mAccuracy = statAccuracyFromString( statAccuracyElem.text() );
}
QDomElement cumulativeCutLowerElem = elem.firstChildElement( QStringLiteral( "cumulativeCutLower" ) );
if ( !cumulativeCutLowerElem.isNull() )
{
mCumulativeCutLower = cumulativeCutLowerElem.text().toDouble();
}
QDomElement cumulativeCutUpperElem = elem.firstChildElement( QStringLiteral( "cumulativeCutUpper" ) );
if ( !cumulativeCutUpperElem.isNull() )
{
mCumulativeCutUpper = cumulativeCutUpperElem.text().toDouble();
}
QDomElement stdDevFactorElem = elem.firstChildElement( QStringLiteral( "stdDevFactor" ) );
if ( !stdDevFactorElem.isNull() )
{
mStdDevFactor = stdDevFactorElem.text().toDouble();
}
}

View File

@ -0,0 +1,159 @@
/***************************************************************************
qgsrasterminmaxorigin.h - Origin of min/max values
--------------------------------------
Date : Dec 2016
Copyright : (C) 2016 by Even Rouault
email : even.rouault at spatialys.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSRASTERMINMAXORIGIN_H
#define QGSRASTERMINMAXORIGIN_H
#include <QDomDocument>
#include <QDomElement>
/** \ingroup core
* This class describes the origin of min/max values. It does not store by
* itself the min/max values.
* @note added in QGIS 3.0
*/
class CORE_EXPORT QgsRasterMinMaxOrigin
{
public:
//! \brief Default cumulative cut lower limit
static constexpr double CUMULATIVE_CUT_LOWER = 0.02;
//! \brief Default cumulative cut upper limit
static constexpr double CUMULATIVE_CUT_UPPER = 0.98;
//! \brief Default standard deviation factor
static constexpr double DEFAULT_STDDEV_FACTOR = 2.0;
//! \brief This enumerator describes the limits used to compute min/max values
enum Limits
{
//! User defined.
None,
//! Real min-max values
MinMax,
//! Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ]
StdDev,
//! Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ]
CumulativeCut
};
//! \brief This enumerator describes the extent used to compute min/max values
enum Extent
{
//! Whole raster is used to compute statistics.
WholeRaster,
//! Current extent of the canvas (at the time of computation) is used to compute statistics.
CurrentCanvas,
//! Constantly updated extent of the canvas is used to compute statistics.
UpdatedCanvas
};
//! \brief This enumerator describes the accuracy used to compute statistics.
enum StatAccuracy
{
//! Exact statistics.
Exact,
//! Approximated statistics.
Estimated
};
//! \brief Default constructor.
QgsRasterMinMaxOrigin();
//! \brief Equality operator.
bool operator ==( const QgsRasterMinMaxOrigin& other ) const;
//////// Getter methods /////////////////////
//! \brief Return limits.
Limits limits() const { return mLimits; }
//! \brief Return extent.
Extent extent() const { return mExtent; }
//! \brief Return statistic accuracy.
StatAccuracy statAccuracy() const { return mAccuracy; }
//! \brief Return lower bound of cumulative cut method (between 0 and 1).
double cumulativeCutLower() const { return mCumulativeCutLower; }
//! \brief Return upper bound of cumulative cut method (between 0 and 1).
double cumulativeCutUpper() const { return mCumulativeCutUpper; }
//! \brief Return factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
double stdDevFactor() const { return mStdDevFactor; }
//////// Setter methods /////////////////////
//! \brief Set limits.
void setLimits( Limits theLimits ) { mLimits = theLimits; }
//! \brief Set extent.
void setExtent( Extent theExtent ) { mExtent = theExtent; }
//! \brief Set statistics accuracy.
void setStatAccuracy( StatAccuracy theAccuracy ) { mAccuracy = theAccuracy; }
//! \brief Set lower bound of cumulative cut method (between 0 and 1).
void setCumulativeCutLower( double val ) { mCumulativeCutLower = val; }
//! \brief Set upper bound of cumulative cut method (between 0 and 1).
void setCumulativeCutUpper( double val ) { mCumulativeCutUpper = val; }
//! \brief Set factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
void setStdDevFactor( double val ) { mStdDevFactor = val; }
//////// XML serialization /////////////////////
//! \brief Serialize object.
void writeXml( QDomDocument& doc, QDomElement& parentElem ) const;
//! \brief Deserialize object.
void readXml( const QDomElement& elem );
//////// Static methods /////////////////////
//! \brief Return a string to serialize Limits
static QString limitsString( Limits theLimits );
//! \brief Deserialize Limits
static Limits limitsFromString( const QString& theLimits );
//! \brief Return a string to serialize Extent
static QString extentString( Extent theExtent );
//! \brief Deserialize Extent
static Extent extentFromString( const QString& theExtent );
//! \brief Return a string to serialize StatAccuracy
static QString statAccuracyString( StatAccuracy theAccuracy );
//! \brief Deserialize StatAccuracy
static StatAccuracy statAccuracyFromString( const QString& theAccuracy );
private:
Limits mLimits;
Extent mExtent;
StatAccuracy mAccuracy;
double mCumulativeCutLower;
double mCumulativeCutUpper;
double mStdDevFactor;
};
#endif // QGSRASTERMINMAXORIGIN_H

View File

@ -112,6 +112,10 @@ void QgsRasterRenderer::_writeXml( QDomDocument& doc, QDomElement& rasterRendere
{ {
mRasterTransparency->writeXml( doc, rasterRendererElem ); mRasterTransparency->writeXml( doc, rasterRendererElem );
} }
QDomElement minMaxOriginElem = doc.createElement( QStringLiteral( "minMaxOrigin" ) );
mMinMaxOrigin.writeXml( doc, minMaxOriginElem );
rasterRendererElem.appendChild( minMaxOriginElem );
} }
void QgsRasterRenderer::readXml( const QDomElement& rendererElem ) void QgsRasterRenderer::readXml( const QDomElement& rendererElem )
@ -132,9 +136,15 @@ void QgsRasterRenderer::readXml( const QDomElement& rendererElem )
mRasterTransparency = new QgsRasterTransparency(); mRasterTransparency = new QgsRasterTransparency();
mRasterTransparency->readXml( rasterTransparencyElem ); mRasterTransparency->readXml( rasterTransparencyElem );
} }
QDomElement minMaxOriginElem = rendererElem.firstChildElement( QStringLiteral( "minMaxOrigin" ) );
if ( !minMaxOriginElem.isNull() )
{
mMinMaxOrigin.readXml( minMaxOriginElem );
}
} }
void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer* other ) void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer* other, bool copyMinMaxOrigin )
{ {
if ( !other ) if ( !other )
return; return;
@ -142,150 +152,6 @@ void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer* other )
setOpacity( other->opacity() ); setOpacity( other->opacity() );
setAlphaBand( other->alphaBand() ); setAlphaBand( other->alphaBand() );
setRasterTransparency( other->rasterTransparency() ? new QgsRasterTransparency( *other->rasterTransparency() ) : nullptr ); setRasterTransparency( other->rasterTransparency() ? new QgsRasterTransparency( *other->rasterTransparency() ) : nullptr );
} if ( copyMinMaxOrigin )
setMinMaxOrigin( other->minMaxOrigin() );
QString QgsRasterRenderer::minMaxOriginName( int theOrigin )
{
if ( theOrigin == MinMaxUnknown )
{
return QStringLiteral( "Unknown" );
}
else if ( theOrigin == MinMaxUser )
{
return QStringLiteral( "User" );
}
QString name;
if ( theOrigin & MinMaxMinMax )
{
name += QLatin1String( "MinMax" );
}
else if ( theOrigin & MinMaxCumulativeCut )
{
name += QLatin1String( "CumulativeCut" );
}
else if ( theOrigin & MinMaxStdDev )
{
name += QLatin1String( "StdDev" );
}
if ( theOrigin & MinMaxFullExtent )
{
name += QLatin1String( "FullExtent" );
}
else if ( theOrigin & MinMaxSubExtent )
{
name += QLatin1String( "SubExtent" );
}
if ( theOrigin & MinMaxEstimated )
{
name += QLatin1String( "Estimated" );
}
else if ( theOrigin & MinMaxExact )
{
name += QLatin1String( "Exact" );
}
return name;
}
QString QgsRasterRenderer::minMaxOriginLabel( int theOrigin )
{
if ( theOrigin == MinMaxUnknown )
{
return tr( "Unknown" );
}
else if ( theOrigin == MinMaxUser )
{
return tr( "User defined" );
}
QString label;
QString est_exact;
QString values;
QString extent;
if ( theOrigin & MinMaxEstimated )
{
est_exact = tr( "Estimated" );
}
else if ( theOrigin & MinMaxExact )
{
est_exact = tr( "Exact" );
}
if ( theOrigin & MinMaxMinMax )
{
values = tr( "min / max" );
}
else if ( theOrigin & MinMaxCumulativeCut )
{
values = tr( "cumulative cut" );
}
else if ( theOrigin & MinMaxStdDev )
{
values = tr( "standard deviation" );
}
if ( theOrigin & MinMaxFullExtent )
{
extent = tr( "full extent" );
}
else if ( theOrigin & MinMaxSubExtent )
{
extent = tr( "sub extent" );
}
label = QCoreApplication::translate( "QgsRasterRenderer", "%1 %2 of %3.",
"min/max origin label in raster properties, where %1 - estimated/exact, %2 - values (min/max, stddev, etc.), %3 - extent" )
.arg( est_exact,
values,
extent );
return label;
}
int QgsRasterRenderer::minMaxOriginFromName( const QString& theName )
{
if ( theName.contains( QLatin1String( "Unknown" ) ) )
{
return MinMaxUnknown;
}
else if ( theName.contains( QLatin1String( "User" ) ) )
{
return MinMaxUser;
}
int origin = 0;
if ( theName.contains( QLatin1String( "MinMax" ) ) )
{
origin |= MinMaxMinMax;
}
else if ( theName.contains( QLatin1String( "CumulativeCut" ) ) )
{
origin |= MinMaxCumulativeCut;
}
else if ( theName.contains( QLatin1String( "StdDev" ) ) )
{
origin |= MinMaxStdDev;
}
if ( theName.contains( QLatin1String( "FullExtent" ) ) )
{
origin |= MinMaxFullExtent;
}
else if ( theName.contains( QLatin1String( "SubExtent" ) ) )
{
origin |= MinMaxSubExtent;
}
if ( theName.contains( QLatin1String( "Estimated" ) ) )
{
origin |= MinMaxEstimated;
}
else if ( theName.contains( QLatin1String( "Exact" ) ) )
{
origin |= MinMaxExact;
}
return origin;
} }

View File

@ -21,6 +21,7 @@
#include <QPair> #include <QPair>
#include "qgsrasterinterface.h" #include "qgsrasterinterface.h"
#include "qgsrasterminmaxorigin.h"
class QDomElement; class QDomElement;
@ -36,22 +37,6 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
Q_DECLARE_TR_FUNCTIONS( QgsRasterRenderer ); Q_DECLARE_TR_FUNCTIONS( QgsRasterRenderer );
public: public:
// Origin of min / max values
enum MinMaxOrigin
{
MinMaxUnknown = 0,
MinMaxUser = 1, // entered by user
// method
MinMaxMinMax = 1 << 1,
MinMaxCumulativeCut = 1 << 2,
MinMaxStdDev = 1 << 3,
// Extent
MinMaxFullExtent = 1 << 4,
MinMaxSubExtent = 1 << 5,
// Precision
MinMaxEstimated = 1 << 6,
MinMaxExact = 1 << 7
};
static const QRgb NODATA_COLOR; static const QRgb NODATA_COLOR;
@ -90,14 +75,16 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
/** Copies common properties like opacity / transparency data from other renderer. /** Copies common properties like opacity / transparency data from other renderer.
* Useful when cloning renderers. * Useful when cloning renderers.
* @note added in 2.16 */ * @note added in 2.16 */
void copyCommonProperties( const QgsRasterRenderer* other ); void copyCommonProperties( const QgsRasterRenderer* other, bool copyMinMaxOrigin = true );
//! Returns a list of band numbers used by the renderer //! Returns a list of band numbers used by the renderer
virtual QList<int> usesBands() const { return QList<int>(); } virtual QList<int> usesBands() const { return QList<int>(); }
static QString minMaxOriginName( int theOrigin ); //! Returns const reference to origin of min/max values
static QString minMaxOriginLabel( int theOrigin ); const QgsRasterMinMaxOrigin& minMaxOrigin() const { return mMinMaxOrigin; }
static int minMaxOriginFromName( const QString& theName );
//! Sets origin of min/max values
void setMinMaxOrigin( const QgsRasterMinMaxOrigin& theOrigin ) { mMinMaxOrigin = theOrigin; }
protected: protected:
@ -115,6 +102,9 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
Default: -1 (not set)*/ Default: -1 (not set)*/
int mAlphaBand; int mAlphaBand;
//! Origin of min/max values
QgsRasterMinMaxOrigin mMinMaxOrigin;
private: private:
QgsRasterRenderer( const QgsRasterRenderer& ); QgsRasterRenderer( const QgsRasterRenderer& );

View File

@ -30,7 +30,6 @@ QgsSingleBandPseudoColorRenderer::QgsSingleBandPseudoColorRenderer( QgsRasterInt
, mBand( band ) , mBand( band )
, mClassificationMin( std::numeric_limits<double>::quiet_NaN() ) , mClassificationMin( std::numeric_limits<double>::quiet_NaN() )
, mClassificationMax( std::numeric_limits<double>::quiet_NaN() ) , mClassificationMax( std::numeric_limits<double>::quiet_NaN() )
, mClassificationMinMaxOrigin( QgsRasterRenderer::MinMaxUnknown )
{ {
} }
@ -107,7 +106,50 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRenderer::create( const QDomElement&
// TODO: add _readXML in superclass? // TODO: add _readXML in superclass?
r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), QStringLiteral( "NaN" ) ).toDouble() ); r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), QStringLiteral( "NaN" ) ).toDouble() );
r->setClassificationMax( elem.attribute( QStringLiteral( "classificationMax" ), QStringLiteral( "NaN" ) ).toDouble() ); r->setClassificationMax( elem.attribute( QStringLiteral( "classificationMax" ), QStringLiteral( "NaN" ) ).toDouble() );
r->setClassificationMinMaxOrigin( QgsRasterRenderer::minMaxOriginFromName( elem.attribute( QStringLiteral( "classificationMinMaxOrigin" ), QStringLiteral( "Unknown" ) ) ) );
// Backward compatibility with serialization of QGIS 2.X era
QString minMaxOrigin = elem.attribute( QStringLiteral( "classificationMinMaxOrigin" ) );
if ( !minMaxOrigin.isEmpty() )
{
if ( minMaxOrigin.contains( QLatin1String( "MinMax" ) ) )
{
r->mMinMaxOrigin.setLimits( QgsRasterMinMaxOrigin::MinMax );
}
else if ( minMaxOrigin.contains( QLatin1String( "CumulativeCut" ) ) )
{
r->mMinMaxOrigin.setLimits( QgsRasterMinMaxOrigin::CumulativeCut );
}
else if ( minMaxOrigin.contains( QLatin1String( "StdDev" ) ) )
{
r->mMinMaxOrigin.setLimits( QgsRasterMinMaxOrigin::StdDev );
}
else
{
r->mMinMaxOrigin.setLimits( QgsRasterMinMaxOrigin::None );
}
if ( minMaxOrigin.contains( QLatin1String( "FullExtent" ) ) )
{
r->mMinMaxOrigin.setExtent( QgsRasterMinMaxOrigin::WholeRaster );
}
else if ( minMaxOrigin.contains( QLatin1String( "SubExtent" ) ) )
{
r->mMinMaxOrigin.setExtent( QgsRasterMinMaxOrigin::CurrentCanvas );
}
else
{
r->mMinMaxOrigin.setExtent( QgsRasterMinMaxOrigin::WholeRaster );
}
if ( minMaxOrigin.contains( QLatin1String( "Estimated" ) ) )
{
r->mMinMaxOrigin.setStatAccuracy( QgsRasterMinMaxOrigin::Estimated );
}
else // if ( minMaxOrigin.contains( QLatin1String( "Exact" ) ) )
{
r->mMinMaxOrigin.setStatAccuracy( QgsRasterMinMaxOrigin::Exact );
}
}
return r; return r;
} }
@ -228,7 +270,6 @@ void QgsSingleBandPseudoColorRenderer::writeXml( QDomDocument& doc, QDomElement&
} }
rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) ); rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) );
rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) ); rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) );
rasterRendererElem.setAttribute( QStringLiteral( "classificationMinMaxOrigin" ), QgsRasterRenderer::minMaxOriginName( mClassificationMinMaxOrigin ) );
parentElem.appendChild( rasterRendererElem ); parentElem.appendChild( rasterRendererElem );
} }

View File

@ -65,8 +65,6 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer
double classificationMax() const { return mClassificationMax; } double classificationMax() const { return mClassificationMax; }
void setClassificationMin( double min ) { mClassificationMin = min; } void setClassificationMin( double min ) { mClassificationMin = min; }
void setClassificationMax( double max ) { mClassificationMax = max; } void setClassificationMax( double max ) { mClassificationMax = max; }
int classificationMinMaxOrigin() const { return mClassificationMinMaxOrigin; }
void setClassificationMinMaxOrigin( int origin ) { mClassificationMinMaxOrigin = origin; }
private: private:
QgsRasterShader* mShader; QgsRasterShader* mShader;
@ -77,8 +75,6 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer
double mClassificationMin; double mClassificationMin;
double mClassificationMax; double mClassificationMax;
int mClassificationMinMaxOrigin;
QgsSingleBandPseudoColorRenderer( const QgsSingleBandPseudoColorRenderer& ); QgsSingleBandPseudoColorRenderer( const QgsSingleBandPseudoColorRenderer& );
const QgsSingleBandPseudoColorRenderer& operator=( const QgsSingleBandPseudoColorRenderer& ); const QgsSingleBandPseudoColorRenderer& operator=( const QgsSingleBandPseudoColorRenderer& );
}; };

View File

@ -24,6 +24,7 @@
QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ) QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent ) : QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr ) , mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{ {
setupUi( this ); setupUi( this );
createValidators(); createValidators();
@ -43,8 +44,11 @@ QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer
layout->setContentsMargins( 0, 0, 0, 0 ); layout->setContentsMargins( 0, 0, 0, 0 );
mMinMaxContainerWidget->setLayout( layout ); mMinMaxContainerWidget->setLayout( layout );
layout->addWidget( mMinMaxWidget ); layout->addWidget( mMinMaxWidget );
connect( mMinMaxWidget, SIGNAL( load( int, double, double, int ) ),
this, SLOT( loadMinMax( int, double, double, int ) ) ); connect( mMinMaxWidget, &QgsRasterMinMaxWidget::widgetChanged,
this, &QgsMultiBandColorRendererWidget::widgetChanged );
connect( mMinMaxWidget, &QgsRasterMinMaxWidget::load,
this, &QgsMultiBandColorRendererWidget::loadMinMax );
connect( mRedBandComboBox, SIGNAL( currentIndexChanged( int ) ), connect( mRedBandComboBox, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( onBandChanged( int ) ) ); this, SLOT( onBandChanged( int ) ) );
@ -108,9 +112,17 @@ QgsRasterRenderer* QgsMultiBandColorRendererWidget::renderer()
QgsMultiBandColorRenderer* r = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand ); QgsMultiBandColorRenderer* r = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand );
setCustomMinMaxValues( r, provider, redBand, greenBand, blueBand ); setCustomMinMaxValues( r, provider, redBand, greenBand, blueBand );
r->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );
return r; return r;
} }
void QgsMultiBandColorRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
}
void QgsMultiBandColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas ) void QgsMultiBandColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{ {
QgsRasterRendererWidget::setMapCanvas( canvas ); QgsRasterRendererWidget::setMapCanvas( canvas );
@ -214,9 +226,51 @@ void QgsMultiBandColorRendererWidget::onBandChanged( int index )
emit widgetChanged(); emit widgetChanged();
} }
void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ) void QgsMultiBandColorRendererWidget::on_mRedMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::on_mRedMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::on_mGreenMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::on_mGreenMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::on_mBlueMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::on_mBlueMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsMultiBandColorRendererWidget::minMaxModified()
{
if ( !mDisableMinMaxWidgetRefresh )
{
if (( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementAlgorithmComboBox->setCurrentIndex(
mContrastEnhancementAlgorithmComboBox->findData(( int ) QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
mMinMaxWidget->userHasSetManualMinMaxValues();
}
}
void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax )
{ {
Q_UNUSED( theOrigin );
QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) ); QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );
QLineEdit *myMinLineEdit, *myMaxLineEdit; QLineEdit *myMinLineEdit, *myMaxLineEdit;
@ -242,6 +296,7 @@ void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin,
return; return;
} }
mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) ) if ( qIsNaN( theMin ) )
{ {
myMinLineEdit->clear(); myMinLineEdit->clear();
@ -259,13 +314,7 @@ void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin,
{ {
myMaxLineEdit->setText( QString::number( theMax ) ); myMaxLineEdit->setText( QString::number( theMax ) );
} }
mDisableMinMaxWidgetRefresh = false;
//automaticlly activate contrast enhancement algorithm if set to none
if ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementAlgorithmComboBox->setCurrentIndex(
mContrastEnhancementAlgorithmComboBox->findData( QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
} }
void QgsMultiBandColorRendererWidget::setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit ) void QgsMultiBandColorRendererWidget::setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit )
@ -300,9 +349,13 @@ void QgsMultiBandColorRendererWidget::setFromRenderer( const QgsRasterRenderer*
mGreenBandComboBox->setCurrentIndex( mGreenBandComboBox->findData( mbcr->greenBand() ) ); mGreenBandComboBox->setCurrentIndex( mGreenBandComboBox->findData( mbcr->greenBand() ) );
mBlueBandComboBox->setCurrentIndex( mBlueBandComboBox->findData( mbcr->blueBand() ) ); mBlueBandComboBox->setCurrentIndex( mBlueBandComboBox->findData( mbcr->blueBand() ) );
mDisableMinMaxWidgetRefresh = true;
setMinMaxValue( mbcr->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit ); setMinMaxValue( mbcr->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit );
setMinMaxValue( mbcr->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit ); setMinMaxValue( mbcr->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit );
setMinMaxValue( mbcr->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit ); setMinMaxValue( mbcr->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit );
mDisableMinMaxWidgetRefresh = false;
mMinMaxWidget->setFromMinMaxOrigin( mbcr->minMaxOrigin() );
} }
else else
{ {
@ -356,6 +409,7 @@ QString QgsMultiBandColorRendererWidget::max( int index )
void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index ) void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index )
{ {
mDisableMinMaxWidgetRefresh = true;
switch ( index ) switch ( index )
{ {
case 0: case 0:
@ -370,10 +424,12 @@ void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index )
default: default:
break; break;
} }
mDisableMinMaxWidgetRefresh = false;
} }
void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index ) void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index )
{ {
mDisableMinMaxWidgetRefresh = true;
switch ( index ) switch ( index )
{ {
case 0: case 0:
@ -388,6 +444,7 @@ void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index )
default: default:
break; break;
} }
mDisableMinMaxWidgetRefresh = false;
} }
int QgsMultiBandColorRendererWidget::selectedBand( int index ) int QgsMultiBandColorRendererWidget::selectedBand( int index )

View File

@ -50,13 +50,22 @@ class GUI_EXPORT QgsMultiBandColorRendererWidget: public QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 ) override; void setMin( const QString& value, int index = 0 ) override;
void setMax( const QString& value, int index = 0 ) override; void setMax( const QString& value, int index = 0 ) override;
int selectedBand( int index = 0 ) override; int selectedBand( int index = 0 ) override;
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }
public slots: public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); //! called when new min/max values are loaded
void loadMinMax( int theBandNo, double theMin, double theMax );
private slots: private slots:
//void on_mLoadPushButton_clicked(); //void on_mLoadPushButton_clicked();
void onBandChanged( int ); void onBandChanged( int );
void on_mRedMinLineEdit_textChanged( const QString & );
void on_mRedMaxLineEdit_textChanged( const QString & );
void on_mGreenMinLineEdit_textChanged( const QString & );
void on_mGreenMaxLineEdit_textChanged( const QString & );
void on_mBlueMinLineEdit_textChanged( const QString & );
void on_mBlueMaxLineEdit_textChanged( const QString & );
private: private:
void createValidators(); void createValidators();
@ -65,6 +74,9 @@ class GUI_EXPORT QgsMultiBandColorRendererWidget: public QgsRasterRendererWidget
//! Reads min/max values from contrast enhancement and fills values into the min/max line edits //! Reads min/max values from contrast enhancement and fills values into the min/max line edits
void setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit ); void setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit );
QgsRasterMinMaxWidget * mMinMaxWidget; QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;
void minMaxModified();
}; };
#endif // QGSMULTIBANDCOLORRENDERERWIDGET_H #endif // QGSMULTIBANDCOLORRENDERERWIDGET_H

View File

@ -23,31 +23,23 @@
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
#include "qgsrasterrenderer.h" #include "qgsrasterrenderer.h"
#include "qgsrasterdataprovider.h" #include "qgsrasterdataprovider.h"
#include "qgsrasterminmaxorigin.h"
const int IDX_WHOLE_RASTER = 0;
const int IDX_CURRENT_CANVAS = 1;
const int IDX_UPDATED_CANVAS = 2;
QgsRasterMinMaxWidget::QgsRasterMinMaxWidget( QgsRasterLayer* theLayer, QWidget *parent ) QgsRasterMinMaxWidget::QgsRasterMinMaxWidget( QgsRasterLayer* theLayer, QWidget *parent )
: QWidget( parent ) : QWidget( parent )
, mLayer( theLayer ) , mLayer( theLayer )
, mCanvas( nullptr ) , mCanvas( nullptr )
, mLastRectangleValid( false )
{ {
QgsDebugMsg( "Entered." ); QgsDebugMsg( "Entered." );
setupUi( this ); setupUi( this );
QSettings mySettings; QgsRasterMinMaxOrigin defaultMinMaxOrigin;
setFromMinMaxOrigin( defaultMinMaxOrigin );
// set contrast enhancement setting to default
// ideally we should set it actual method last used to get min/max, but there is no way to know currently
QString contrastEnchacementLimits = mySettings.value( QStringLiteral( "/Raster/defaultContrastEnhancementLimits" ), "CumulativeCut" ).toString();
if ( contrastEnchacementLimits == QLatin1String( "MinMax" ) )
mMinMaxRadioButton->setChecked( true );
else if ( contrastEnchacementLimits == QLatin1String( "StdDev" ) )
mStdDevRadioButton->setChecked( true );
double myLower = 100.0 * mySettings.value( QStringLiteral( "/Raster/cumulativeCutLower" ), QString::number( QgsRasterLayer::CUMULATIVE_CUT_LOWER ) ).toDouble();
double myUpper = 100.0 * mySettings.value( QStringLiteral( "/Raster/cumulativeCutUpper" ), QString::number( QgsRasterLayer::CUMULATIVE_CUT_UPPER ) ).toDouble();
mCumulativeCutLowerDoubleSpinBox->setValue( myLower );
mCumulativeCutUpperDoubleSpinBox->setValue( myUpper );
mStdDevSpinBox->setValue( mySettings.value( QStringLiteral( "/Raster/defaultStandardDeviation" ), 2.0 ).toDouble() );
} }
QgsRasterMinMaxWidget::~QgsRasterMinMaxWidget() QgsRasterMinMaxWidget::~QgsRasterMinMaxWidget()
@ -66,7 +58,8 @@ QgsMapCanvas* QgsRasterMinMaxWidget::mapCanvas()
QgsRectangle QgsRasterMinMaxWidget::extent() QgsRectangle QgsRasterMinMaxWidget::extent()
{ {
if ( !cbxClipExtent->isChecked() ) const int nExtentIdx = mStatisticsExtentCombo->currentIndex();
if ( nExtentIdx != IDX_CURRENT_CANVAS && nExtentIdx != IDX_UPDATED_CANVAS )
return QgsRectangle(); return QgsRectangle();
if ( mLayer && mCanvas ) if ( mLayer && mCanvas )
@ -77,13 +70,126 @@ QgsRectangle QgsRasterMinMaxWidget::extent()
return QgsRectangle(); return QgsRectangle();
} }
void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked() void QgsRasterMinMaxWidget::userHasSetManualMinMaxValues()
{
mUserDefinedRadioButton->setChecked( true );
mStatisticsExtentCombo->setCurrentIndex( IDX_WHOLE_RASTER );
}
void QgsRasterMinMaxWidget::on_mUserDefinedRadioButton_toggled( bool toggled )
{
mStatisticsExtentCombo->setEnabled( !toggled );
cboAccuracy->setEnabled( !toggled );
emit widgetChanged();
}
void QgsRasterMinMaxWidget::setFromMinMaxOrigin( const QgsRasterMinMaxOrigin& minMaxOrigin )
{
switch ( minMaxOrigin.limits() )
{
case QgsRasterMinMaxOrigin::None:
default:
mUserDefinedRadioButton->setChecked( true );
break;
case QgsRasterMinMaxOrigin::MinMax:
mMinMaxRadioButton->setChecked( true );
break;
case QgsRasterMinMaxOrigin::StdDev:
mStdDevRadioButton->setChecked( true );
break;
case QgsRasterMinMaxOrigin::CumulativeCut:
mCumulativeCutRadioButton->setChecked( true );
break;
}
switch ( minMaxOrigin.extent() )
{
default:
case QgsRasterMinMaxOrigin::WholeRaster:
mStatisticsExtentCombo->setCurrentIndex( IDX_WHOLE_RASTER );
break;
case QgsRasterMinMaxOrigin::CurrentCanvas:
mStatisticsExtentCombo->setCurrentIndex( IDX_CURRENT_CANVAS );
break;
case QgsRasterMinMaxOrigin::UpdatedCanvas:
mStatisticsExtentCombo->setCurrentIndex( IDX_UPDATED_CANVAS );
break;
}
mCumulativeCutLowerDoubleSpinBox->setValue( 100.0 * minMaxOrigin.cumulativeCutLower() );
mCumulativeCutUpperDoubleSpinBox->setValue( 100.0 * minMaxOrigin.cumulativeCutUpper() );
mStdDevSpinBox->setValue( minMaxOrigin.stdDevFactor() );
cboAccuracy->setCurrentIndex( minMaxOrigin.statAccuracy() == QgsRasterMinMaxOrigin::Estimated ? 0 : 1 );
}
QgsRasterMinMaxOrigin QgsRasterMinMaxWidget::minMaxOrigin()
{
QgsRasterMinMaxOrigin minMaxOrigin;
if ( mMinMaxRadioButton->isChecked() )
minMaxOrigin.setLimits( QgsRasterMinMaxOrigin::MinMax );
else if ( mStdDevRadioButton->isChecked() )
minMaxOrigin.setLimits( QgsRasterMinMaxOrigin::StdDev );
else if ( mCumulativeCutRadioButton->isChecked() )
minMaxOrigin.setLimits( QgsRasterMinMaxOrigin::CumulativeCut );
else
minMaxOrigin.setLimits( QgsRasterMinMaxOrigin::None );
switch ( mStatisticsExtentCombo->currentIndex() )
{
case IDX_WHOLE_RASTER:
default:
minMaxOrigin.setExtent( QgsRasterMinMaxOrigin::WholeRaster );
break;
case IDX_CURRENT_CANVAS:
minMaxOrigin.setExtent( QgsRasterMinMaxOrigin::CurrentCanvas );
break;
case IDX_UPDATED_CANVAS:
minMaxOrigin.setExtent( QgsRasterMinMaxOrigin::UpdatedCanvas );
break;
}
if ( cboAccuracy->currentIndex() == 0 )
minMaxOrigin.setStatAccuracy( QgsRasterMinMaxOrigin::Estimated );
else
minMaxOrigin.setStatAccuracy( QgsRasterMinMaxOrigin::Exact );
minMaxOrigin.setCumulativeCutLower(
mCumulativeCutLowerDoubleSpinBox->value() / 100.0 );
minMaxOrigin.setCumulativeCutUpper(
mCumulativeCutUpperDoubleSpinBox->value() / 100.0 );
minMaxOrigin.setStdDevFactor( mStdDevSpinBox->value() );
return minMaxOrigin;
}
void QgsRasterMinMaxWidget::doComputations()
{ {
QgsDebugMsg( "Entered." ); QgsDebugMsg( "Entered." );
QgsRectangle myExtent = extent(); // empty == full
int mySampleSize = sampleSize(); // 0 == exact
QgsRasterMinMaxOrigin newMinMaxOrigin = minMaxOrigin();
if ( mLastRectangleValid && mLastRectangle == myExtent &&
mLastMinMaxOrigin == newMinMaxOrigin )
{
QgsDebugMsg( "Does not need to redo statistics computations" );
return;
}
mLastRectangleValid = true;
mLastRectangle = myExtent;
mLastMinMaxOrigin = newMinMaxOrigin;
Q_FOREACH ( int myBand, mBands ) Q_FOREACH ( int myBand, mBands )
{ {
int origin = QgsRasterRenderer::MinMaxUnknown;
QgsDebugMsg( QString( "myBand = %1" ).arg( myBand ) ); QgsDebugMsg( QString( "myBand = %1" ).arg( myBand ) );
if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() ) if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() )
{ {
@ -92,56 +198,37 @@ void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked()
double myMin = std::numeric_limits<double>::quiet_NaN(); double myMin = std::numeric_limits<double>::quiet_NaN();
double myMax = std::numeric_limits<double>::quiet_NaN(); double myMax = std::numeric_limits<double>::quiet_NaN();
QgsRectangle myExtent = extent(); // empty == full bool updateMinMax = false;
if ( cbxClipExtent->isChecked() )
{
origin |= QgsRasterRenderer::MinMaxSubExtent;
}
else
{
origin |= QgsRasterRenderer::MinMaxFullExtent;
}
QgsDebugMsg( QString( "myExtent.isEmpty() = %1" ).arg( myExtent.isEmpty() ) );
int mySampleSize = sampleSize(); // 0 == exact
if ( cboAccuracy->currentIndex() == 0 )
{
origin |= QgsRasterRenderer::MinMaxEstimated;
}
else
{
origin |= QgsRasterRenderer::MinMaxExact;
}
if ( mCumulativeCutRadioButton->isChecked() ) if ( mCumulativeCutRadioButton->isChecked() )
{ {
updateMinMax = true;
double myLower = mCumulativeCutLowerDoubleSpinBox->value() / 100.0; double myLower = mCumulativeCutLowerDoubleSpinBox->value() / 100.0;
double myUpper = mCumulativeCutUpperDoubleSpinBox->value() / 100.0; double myUpper = mCumulativeCutUpperDoubleSpinBox->value() / 100.0;
mLayer->dataProvider()->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, myExtent, mySampleSize ); mLayer->dataProvider()->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, myExtent, mySampleSize );
origin |= QgsRasterRenderer::MinMaxCumulativeCut;
} }
else if ( mMinMaxRadioButton->isChecked() ) else if ( mMinMaxRadioButton->isChecked() )
{ {
updateMinMax = true;
// TODO: consider provider minimum/maximumValue() (has to be defined well in povider) // TODO: consider provider minimum/maximumValue() (has to be defined well in povider)
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, myExtent, mySampleSize ); QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, myExtent, mySampleSize );
myMin = myRasterBandStats.minimumValue; myMin = myRasterBandStats.minimumValue;
myMax = myRasterBandStats.maximumValue; myMax = myRasterBandStats.maximumValue;
origin |= QgsRasterRenderer::MinMaxMinMax;
} }
else if ( mStdDevRadioButton->isChecked() ) else if ( mStdDevRadioButton->isChecked() )
{ {
updateMinMax = true;
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, myExtent, mySampleSize ); QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, myExtent, mySampleSize );
double myStdDev = mStdDevSpinBox->value(); double myStdDev = mStdDevSpinBox->value();
myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev ); myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev ); myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
origin |= QgsRasterRenderer::MinMaxStdDev;
}
else
{
QMessageBox::warning( this, tr( "No option selected" ), tr( "Please select an option to load min/max values." ) );
return;
} }
emit load( myBand, myMin, myMax, origin ); if ( updateMinMax )
emit load( myBand, myMin, myMax );
} }
} }
void QgsRasterMinMaxWidget::hideUpdatedExtent()
{
mStatisticsExtentCombo->removeItem( IDX_UPDATED_CANVAS );
}

View File

@ -21,6 +21,10 @@
#include "ui_qgsrasterminmaxwidgetbase.h" #include "ui_qgsrasterminmaxwidgetbase.h"
#include "qgsrectangle.h" #include "qgsrectangle.h"
#include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"
class QgsMapCanvas; class QgsMapCanvas;
class QgsRasterLayer; class QgsRasterLayer;
@ -67,14 +71,49 @@ class GUI_EXPORT QgsRasterMinMaxWidget: public QWidget, private Ui::QgsRasterMin
//! Return the selected sample size. //! Return the selected sample size.
int sampleSize() { return cboAccuracy->currentIndex() == 0 ? 250000 : 0; } int sampleSize() { return cboAccuracy->currentIndex() == 0 ? 250000 : 0; }
// Load programmaticaly with current values //! \brief Set the "source" of min/max values.
void load() { on_mLoadPushButton_clicked(); } void setFromMinMaxOrigin( const QgsRasterMinMaxOrigin& );
//! \brief Return a QgsRasterMinMaxOrigin object with the widget values.
QgsRasterMinMaxOrigin minMaxOrigin();
//! Hide updated extent choice
void hideUpdatedExtent();
//! Load programmaticaly with current values
void doComputations();
//! Uncheck cumulative cut, min/max, std-dev radio buttons
void userHasSetManualMinMaxValues();
//! Return if the widget is collaped.
bool isCollapsed() const { return mLoadMinMaxValuesGroupBox->isCollapsed(); }
//! Set collapsed state of widget
void setCollapsed( bool b ) { mLoadMinMaxValuesGroupBox->setCollapsed( b ); }
signals: signals:
void load( int theBandNo, double theMin, double theMax, int origin );
/**
* Emitted when something on the widget has changed.
* All widgets will fire this event to notify of an internal change.
*/
void widgetChanged();
//! signal emitted when new min/max values are computed from statistics.
void load( int theBandNo, double theMin, double theMax );
private slots: private slots:
void on_mLoadPushButton_clicked();
void on_mUserDefinedRadioButton_toggled( bool );
void on_mMinMaxRadioButton_toggled( bool b ) { if ( b ) emit widgetChanged(); }
void on_mStdDevRadioButton_toggled( bool b ) { if ( b ) emit widgetChanged(); }
void on_mCumulativeCutRadioButton_toggled( bool b ) { if ( b ) emit widgetChanged(); }
void on_mStatisticsExtentCombo_currentIndexChanged( int ) { emit widgetChanged(); }
void on_mCumulativeCutLowerDoubleSpinBox_valueChanged( double ) { emit widgetChanged(); }
void on_mCumulativeCutUpperDoubleSpinBox_valueChanged( double ) { emit widgetChanged(); }
void on_mStdDevSpinBox_valueChanged( double ) { emit widgetChanged(); }
void on_cboAccuracy_currentIndexChanged( int ) { emit widgetChanged(); }
private: private:
QgsRasterLayer* mLayer; QgsRasterLayer* mLayer;
@ -82,6 +121,10 @@ class GUI_EXPORT QgsRasterMinMaxWidget: public QWidget, private Ui::QgsRasterMin
QgsRectangle mExtent; QgsRectangle mExtent;
QgsMapCanvas* mCanvas; QgsMapCanvas* mCanvas;
bool mLastRectangleValid;
QgsRectangle mLastRectangle;
QgsRasterMinMaxOrigin mLastMinMaxOrigin;
}; };
#endif // QGSRASTERMINMAXWIDGET_H #endif // QGSRASTERMINMAXWIDGET_H

View File

@ -25,6 +25,7 @@
class QgsRasterLayer; class QgsRasterLayer;
class QgsRasterRenderer; class QgsRasterRenderer;
class QgsMapCanvas; class QgsMapCanvas;
class QgsRasterMinMaxWidget;
/** \ingroup gui /** \ingroup gui
* \class QgsRasterRendererWidget * \class QgsRasterRendererWidget
@ -44,14 +45,6 @@ class GUI_EXPORT QgsRasterRendererWidget: public QWidget
virtual ~QgsRasterRendererWidget() {} virtual ~QgsRasterRendererWidget() {}
enum LoadMinMaxAlgo
{
Estimate,
Actual,
CurrentExtent,
CumulativeCut // 2 - 98% cumulative cut
};
virtual QgsRasterRenderer* renderer() = 0; virtual QgsRasterRenderer* renderer() = 0;
void setRasterLayer( QgsRasterLayer* layer ) { mRasterLayer = layer; } void setRasterLayer( QgsRasterLayer* layer ) { mRasterLayer = layer; }
@ -80,6 +73,12 @@ class GUI_EXPORT QgsRasterRendererWidget: public QWidget
virtual void setStdDev( const QString& value ) { Q_UNUSED( value ); } virtual void setStdDev( const QString& value ) { Q_UNUSED( value ); }
virtual int selectedBand( int index = 0 ) { Q_UNUSED( index ); return -1; } virtual int selectedBand( int index = 0 ) { Q_UNUSED( index ); return -1; }
//! Load programmaticaly with current values
virtual void doComputations() { }
//! Return min/max widget when it exists.
virtual QgsRasterMinMaxWidget* minMaxWidget() { return nullptr; }
signals: signals:
/** /**

View File

@ -29,6 +29,8 @@
#include "qgsrasterresamplefilter.h" #include "qgsrasterresamplefilter.h"
#include "qgsbilinearrasterresampler.h" #include "qgsbilinearrasterresampler.h"
#include "qgscubicrasterresampler.h" #include "qgscubicrasterresampler.h"
#include "qgsmultibandcolorrenderer.h"
#include "qgssinglebandgrayrenderer.h"
static void _initRendererWidgetFunctions() static void _initRendererWidgetFunctions()
@ -103,6 +105,8 @@ QgsRendererRasterPropertiesWidget::QgsRendererRasterPropertiesWidget( QgsMapLaye
// finally sync to the layer - even though some actions may emit widgetChanged signal, // finally sync to the layer - even though some actions may emit widgetChanged signal,
// this is not a problem - nobody is listening to our signals yet // this is not a problem - nobody is listening to our signals yet
syncToLayer( mRasterLayer ); syncToLayer( mRasterLayer );
connect( mRasterLayer, SIGNAL( styleChanged() ), this, SLOT( refreshAfterSyleChanged() ) );
} }
QgsRendererRasterPropertiesWidget::~QgsRendererRasterPropertiesWidget() QgsRendererRasterPropertiesWidget::~QgsRendererRasterPropertiesWidget()
@ -130,14 +134,15 @@ void QgsRendererRasterPropertiesWidget::apply()
QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( stackedWidget->currentWidget() ); QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( stackedWidget->currentWidget() );
if ( rendererWidget ) if ( rendererWidget )
{ {
rendererWidget->doComputations();
QgsRasterRenderer* newRenderer = rendererWidget->renderer(); QgsRasterRenderer* newRenderer = rendererWidget->renderer();
// there are transparency related data stored in renderer instances, but they // there are transparency related data stored in renderer instances, but they
// are not configured in the widget, so we need to copy them over from existing renderer // are not configured in the widget, so we need to copy them over from existing renderer
QgsRasterRenderer* oldRenderer = mRasterLayer->renderer(); QgsRasterRenderer* oldRenderer = mRasterLayer->renderer();
if ( oldRenderer ) if ( oldRenderer )
newRenderer->copyCommonProperties( oldRenderer ); newRenderer->copyCommonProperties( oldRenderer, false );
mRasterLayer->setRenderer( newRenderer ); mRasterLayer->setRenderer( newRenderer );
} }
@ -360,3 +365,41 @@ void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &render
} }
} }
void QgsRendererRasterPropertiesWidget::refreshAfterSyleChanged()
{
if ( mRendererWidget )
{
QgsRasterRenderer* renderer = mRasterLayer->renderer();
if ( QgsMultiBandColorRenderer* mbcr = dynamic_cast<QgsMultiBandColorRenderer*>( renderer ) )
{
const QgsContrastEnhancement* redCe = mbcr->redContrastEnhancement();
if ( redCe )
{
mRendererWidget->setMin( QString::number( redCe->minimumValue() ), 0 );
mRendererWidget->setMax( QString::number( redCe->maximumValue() ), 0 );
}
const QgsContrastEnhancement* greenCe = mbcr->greenContrastEnhancement();
if ( greenCe )
{
mRendererWidget->setMin( QString::number( greenCe->minimumValue() ), 1 );
mRendererWidget->setMax( QString::number( greenCe->maximumValue() ), 1 );
}
const QgsContrastEnhancement* blueCe = mbcr->blueContrastEnhancement();
if ( blueCe )
{
mRendererWidget->setMin( QString::number( blueCe->minimumValue() ), 2 );
mRendererWidget->setMax( QString::number( blueCe->maximumValue() ), 2 );
}
}
else if ( QgsSingleBandGrayRenderer* sbgr = dynamic_cast<QgsSingleBandGrayRenderer*>( renderer ) )
{
const QgsContrastEnhancement* ce = sbgr->contrastEnhancement();
if ( ce )
{
mRendererWidget->setMin( QString::number( ce->minimumValue() ) );
mRendererWidget->setMax( QString::number( ce->maximumValue() ) );
}
}
}
}

View File

@ -79,6 +79,9 @@ class GUI_EXPORT QgsRendererRasterPropertiesWidget : public QgsMapLayerConfigWid
//! Enable or disable colorize controls depending on checkbox //! Enable or disable colorize controls depending on checkbox
void toggleColorizeControls( bool colorizeEnabled ); void toggleColorizeControls( bool colorizeEnabled );
void refreshAfterSyleChanged();
private: private:
void setRendererWidget( const QString& rendererName ); void setRendererWidget( const QString& rendererName );

View File

@ -24,6 +24,7 @@
QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ) QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent ) : QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr ) , mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{ {
setupUi( this ); setupUi( this );
@ -50,8 +51,11 @@ QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer
mMinMaxContainerWidget->setLayout( layout ); mMinMaxContainerWidget->setLayout( layout );
layout->addWidget( mMinMaxWidget ); layout->addWidget( mMinMaxWidget );
connect( mMinMaxWidget, SIGNAL( load( int, double, double, int ) ), connect( mMinMaxWidget, &QgsRasterMinMaxWidget::widgetChanged,
this, SLOT( loadMinMax( int, double, double, int ) ) ); this, &QgsSingleBandGrayRendererWidget::widgetChanged );
connect( mMinMaxWidget, &QgsRasterMinMaxWidget::load,
this, &QgsSingleBandGrayRendererWidget::loadMinMax );
//fill available bands into combo box //fill available bands into combo box
int nBands = provider->bandCount(); int nBands = provider->bandCount();
@ -98,27 +102,57 @@ QgsRasterRenderer* QgsSingleBandGrayRendererWidget::renderer()
e->setMaximumValue( mMaxLineEdit->text().toDouble() ); e->setMaximumValue( mMaxLineEdit->text().toDouble() );
e->setContrastEnhancementAlgorithm(( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementComboBox->currentData().toInt() ) ); e->setContrastEnhancementAlgorithm(( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementComboBox->currentData().toInt() ) );
QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( provider, band ); QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( provider, band );
renderer->setContrastEnhancement( e ); renderer->setContrastEnhancement( e );
renderer->setGradient(( QgsSingleBandGrayRenderer::Gradient ) mGradientComboBox->currentData().toInt() ); renderer->setGradient(( QgsSingleBandGrayRenderer::Gradient ) mGradientComboBox->currentData().toInt() );
renderer->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );
return renderer; return renderer;
} }
void QgsSingleBandGrayRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
}
void QgsSingleBandGrayRendererWidget::setMapCanvas( QgsMapCanvas* canvas ) void QgsSingleBandGrayRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{ {
QgsRasterRendererWidget::setMapCanvas( canvas ); QgsRasterRendererWidget::setMapCanvas( canvas );
mMinMaxWidget->setMapCanvas( canvas ); mMinMaxWidget->setMapCanvas( canvas );
} }
void QgsSingleBandGrayRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ) void QgsSingleBandGrayRendererWidget::on_mMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsSingleBandGrayRendererWidget::on_mMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsSingleBandGrayRendererWidget::minMaxModified()
{
if ( !mDisableMinMaxWidgetRefresh )
{
if (( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementComboBox->currentData().toInt() ) == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementComboBox->setCurrentIndex(
mContrastEnhancementComboBox->findData(( int ) QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
mMinMaxWidget->userHasSetManualMinMaxValues();
}
}
void QgsSingleBandGrayRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax )
{ {
Q_UNUSED( theBandNo ); Q_UNUSED( theBandNo );
Q_UNUSED( theOrigin );
QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) ); QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );
mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) ) if ( qIsNaN( theMin ) )
{ {
mMinLineEdit->clear(); mMinLineEdit->clear();
@ -136,12 +170,7 @@ void QgsSingleBandGrayRendererWidget::loadMinMax( int theBandNo, double theMin,
{ {
mMaxLineEdit->setText( QString::number( theMax ) ); mMaxLineEdit->setText( QString::number( theMax ) );
} }
mDisableMinMaxWidgetRefresh = false;
//automaticlly activate contrast enhancement algorithm if set to none
if ( mContrastEnhancementComboBox->currentData().toInt() == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementComboBox->setCurrentIndex( mContrastEnhancementComboBox->findData( QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
} }
void QgsSingleBandGrayRendererWidget::on_mGrayBandComboBox_currentIndexChanged( int index ) void QgsSingleBandGrayRendererWidget::on_mGrayBandComboBox_currentIndexChanged( int index )
@ -163,10 +192,28 @@ void QgsSingleBandGrayRendererWidget::setFromRenderer( const QgsRasterRenderer*
mGradientComboBox->setCurrentIndex( mGradientComboBox->findData( gr->gradient() ) ); mGradientComboBox->setCurrentIndex( mGradientComboBox->findData( gr->gradient() ) );
//minmax //minmax
mDisableMinMaxWidgetRefresh = true;
mMinLineEdit->setText( QString::number( ce->minimumValue() ) ); mMinLineEdit->setText( QString::number( ce->minimumValue() ) );
mMaxLineEdit->setText( QString::number( ce->maximumValue() ) ); mMaxLineEdit->setText( QString::number( ce->maximumValue() ) );
mDisableMinMaxWidgetRefresh = false;
//contrast enhancement algorithm //contrast enhancement algorithm
mContrastEnhancementComboBox->setCurrentIndex( mContrastEnhancementComboBox->setCurrentIndex(
mContrastEnhancementComboBox->findData(( int )( ce->contrastEnhancementAlgorithm() ) ) ); mContrastEnhancementComboBox->findData(( int )( ce->contrastEnhancementAlgorithm() ) ) );
mMinMaxWidget->setFromMinMaxOrigin( gr->minMaxOrigin() );
} }
} }
void QgsSingleBandGrayRendererWidget::setMin( const QString& value, int )
{
mDisableMinMaxWidgetRefresh = true;
mMinLineEdit->setText( value );
mDisableMinMaxWidgetRefresh = false;
}
void QgsSingleBandGrayRendererWidget::setMax( const QString& value, int )
{
mDisableMinMaxWidgetRefresh = true;
mMaxLineEdit->setText( value );
mDisableMinMaxWidgetRefresh = false;
}

View File

@ -42,18 +42,26 @@ class GUI_EXPORT QgsSingleBandGrayRendererWidget: public QgsRasterRendererWidget
QString min( int index = 0 ) override { Q_UNUSED( index ); return mMinLineEdit->text(); } QString min( int index = 0 ) override { Q_UNUSED( index ); return mMinLineEdit->text(); }
QString max( int index = 0 ) override { Q_UNUSED( index ); return mMaxLineEdit->text(); } QString max( int index = 0 ) override { Q_UNUSED( index ); return mMaxLineEdit->text(); }
void setMin( const QString& value, int index = 0 ) override { Q_UNUSED( index ); mMinLineEdit->setText( value ); } void setMin( const QString& value, int index = 0 ) override;
void setMax( const QString& value, int index = 0 ) override { Q_UNUSED( index ); mMaxLineEdit->setText( value ); } void setMax( const QString& value, int index = 0 ) override;
int selectedBand( int index = 0 ) override { Q_UNUSED( index ); return mGrayBandComboBox->currentIndex() + 1; } int selectedBand( int index = 0 ) override { Q_UNUSED( index ); return mGrayBandComboBox->currentIndex() + 1; }
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }
public slots: public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); //! called when new min/max values are loaded
void loadMinMax( int theBandNo, double theMin, double theMax );
private slots: private slots:
void on_mGrayBandComboBox_currentIndexChanged( int index ); void on_mGrayBandComboBox_currentIndexChanged( int index );
void on_mMinLineEdit_textChanged( const QString & );
void on_mMaxLineEdit_textChanged( const QString & );
private: private:
QgsRasterMinMaxWidget * mMinMaxWidget; QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;
void minMaxModified();
}; };
#endif // QGSSINGLEBANDGRAYRENDERERWIDGET_H #endif // QGSSINGLEBANDGRAYRENDERERWIDGET_H

View File

@ -42,6 +42,7 @@
QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ) QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent ) : QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr ) , mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
, mMinMaxOrigin( 0 ) , mMinMaxOrigin( 0 )
{ {
QSettings settings; QSettings settings;
@ -84,9 +85,12 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
layout->setContentsMargins( 0, 0, 0, 0 ); layout->setContentsMargins( 0, 0, 0, 0 );
mMinMaxContainerWidget->setLayout( layout ); mMinMaxContainerWidget->setLayout( layout );
layout->addWidget( mMinMaxWidget ); layout->addWidget( mMinMaxWidget );
connect( mMinMaxWidget, SIGNAL( load( int, double, double, int ) ),
this, SLOT( loadMinMax( int, double, double, int ) ) );
connect( mMinMaxWidget, &QgsRasterMinMaxWidget::widgetChanged,
this, &QgsSingleBandPseudoColorRendererWidget::widgetChanged );
connect( mMinMaxWidget, &QgsRasterMinMaxWidget::load,
this, &QgsSingleBandPseudoColorRendererWidget::loadMinMax );
//fill available bands into combo box //fill available bands into combo box
int nBands = provider->bandCount(); int nBands = provider->bandCount();
@ -111,7 +115,13 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
// If there is currently no min/max, load default with user current default options // If there is currently no min/max, load default with user current default options
if ( mMinLineEdit->text().isEmpty() || mMaxLineEdit->text().isEmpty() ) if ( mMinLineEdit->text().isEmpty() || mMaxLineEdit->text().isEmpty() )
{ {
mMinMaxWidget->load(); QgsRasterMinMaxOrigin minMaxOrigin = mMinMaxWidget->minMaxOrigin();
if ( minMaxOrigin.limits() == QgsRasterMinMaxOrigin::None )
{
minMaxOrigin.setLimits( QgsRasterMinMaxOrigin::MinMax );
mMinMaxWidget->setFromMinMaxOrigin( minMaxOrigin );
}
mMinMaxWidget->doComputations();
} }
on_mClassificationModeComboBox_currentIndexChanged( 0 ); on_mClassificationModeComboBox_currentIndexChanged( 0 );
@ -119,8 +129,6 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
resetClassifyButton(); resetClassifyButton();
connect( mClassificationModeComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( classify() ) ); connect( mClassificationModeComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( classify() ) );
connect( mMinLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( classify() ) );
connect( mMaxLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( classify() ) );
connect( mClassifyButton, &QPushButton::clicked, this, &QgsSingleBandPseudoColorRendererWidget::applyColorRamp ); connect( mClassifyButton, &QPushButton::clicked, this, &QgsSingleBandPseudoColorRendererWidget::applyColorRamp );
connect( btnColorRamp, &QgsColorRampButton::colorRampChanged, this, &QgsSingleBandPseudoColorRendererWidget::applyColorRamp ); connect( btnColorRamp, &QgsColorRampButton::colorRampChanged, this, &QgsSingleBandPseudoColorRendererWidget::applyColorRamp );
connect( mNumberOfEntriesSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( classify() ) ); connect( mNumberOfEntriesSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( classify() ) );
@ -175,10 +183,17 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRendererWidget::renderer()
renderer->setClassificationMin( lineEditValue( mMinLineEdit ) ); renderer->setClassificationMin( lineEditValue( mMinLineEdit ) );
renderer->setClassificationMax( lineEditValue( mMaxLineEdit ) ); renderer->setClassificationMax( lineEditValue( mMaxLineEdit ) );
renderer->setClassificationMinMaxOrigin( mMinMaxOrigin ); renderer->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );
return renderer; return renderer;
} }
void QgsSingleBandPseudoColorRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
if ( mColormapTreeWidget->topLevelItemCount() == 0 )
applyColorRamp();
}
void QgsSingleBandPseudoColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas ) void QgsSingleBandPseudoColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{ {
QgsRasterRendererWidget::setMapCanvas( canvas ); QgsRasterRendererWidget::setMapCanvas( canvas );
@ -841,8 +856,8 @@ void QgsSingleBandPseudoColorRendererWidget::setFromRenderer( const QgsRasterRen
} }
setLineEditValue( mMinLineEdit, pr->classificationMin() ); setLineEditValue( mMinLineEdit, pr->classificationMin() );
setLineEditValue( mMaxLineEdit, pr->classificationMax() ); setLineEditValue( mMaxLineEdit, pr->classificationMax() );
mMinMaxOrigin = pr->classificationMinMaxOrigin();
showMinMaxOrigin(); mMinMaxWidget->setFromMinMaxOrigin( pr->minMaxOrigin() );
} }
} }
@ -885,11 +900,12 @@ void QgsSingleBandPseudoColorRendererWidget::on_mColorInterpolationComboBox_curr
emit widgetChanged(); emit widgetChanged();
} }
void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ) void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax )
{ {
Q_UNUSED( theBandNo ); Q_UNUSED( theBandNo );
QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) ); QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );
mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) ) if ( qIsNaN( theMin ) )
{ {
mMinLineEdit->clear(); mMinLineEdit->clear();
@ -907,14 +923,7 @@ void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int theBandNo, double t
{ {
mMaxLineEdit->setText( QString::number( theMax ) ); mMaxLineEdit->setText( QString::number( theMax ) );
} }
mDisableMinMaxWidgetRefresh = false;
mMinMaxOrigin = theOrigin;
showMinMaxOrigin();
}
void QgsSingleBandPseudoColorRendererWidget::showMinMaxOrigin()
{
mMinMaxOriginLabel->setText( QgsRasterRenderer::minMaxOriginLabel( mMinMaxOrigin ) );
} }
void QgsSingleBandPseudoColorRendererWidget::setLineEditValue( QLineEdit * theLineEdit, double theValue ) void QgsSingleBandPseudoColorRendererWidget::setLineEditValue( QLineEdit * theLineEdit, double theValue )
@ -995,3 +1004,23 @@ void QgsSingleBandPseudoColorRendererWidget::changeTransparency()
emit widgetChanged(); emit widgetChanged();
} }
} }
void QgsSingleBandPseudoColorRendererWidget::on_mMinLineEdit_textEdited( const QString & )
{
minMaxModified();
classify();
}
void QgsSingleBandPseudoColorRendererWidget::on_mMaxLineEdit_textEdited( const QString & )
{
minMaxModified();
classify();
}
void QgsSingleBandPseudoColorRendererWidget::minMaxModified()
{
if ( !mDisableMinMaxWidgetRefresh )
{
mMinMaxWidget->userHasSetManualMinMaxValues();
}
}

View File

@ -49,6 +49,8 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
static QgsRasterRendererWidget* create( QgsRasterLayer* layer, const QgsRectangle &theExtent ) { return new QgsSingleBandPseudoColorRendererWidget( layer, theExtent ); } static QgsRasterRendererWidget* create( QgsRasterLayer* layer, const QgsRectangle &theExtent ) { return new QgsSingleBandPseudoColorRendererWidget( layer, theExtent ); }
QgsRasterRenderer* renderer() override; QgsRasterRenderer* renderer() override;
void setMapCanvas( QgsMapCanvas* canvas ) override; void setMapCanvas( QgsMapCanvas* canvas ) override;
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }
void setFromRenderer( const QgsRasterRenderer* r ); void setFromRenderer( const QgsRasterRenderer* r );
@ -57,7 +59,8 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
/** Executes the single band pseudo raster classficiation /** Executes the single band pseudo raster classficiation
*/ */
void classify(); void classify();
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin ); //! called when new min/max values are loaded
void loadMinMax( int theBandNo, double theMin, double theMax );
private: private:
@ -87,10 +90,10 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
void mColormapTreeWidget_itemEdited( QTreeWidgetItem* item, int column ); void mColormapTreeWidget_itemEdited( QTreeWidgetItem* item, int column );
void on_mBandComboBox_currentIndexChanged( int index ); void on_mBandComboBox_currentIndexChanged( int index );
void on_mColorInterpolationComboBox_currentIndexChanged( int index ); void on_mColorInterpolationComboBox_currentIndexChanged( int index );
void on_mMinLineEdit_textChanged( const QString & text ) { Q_UNUSED( text ); resetClassifyButton(); } void on_mMinLineEdit_textChanged( const QString & ) { resetClassifyButton(); }
void on_mMaxLineEdit_textChanged( const QString & text ) { Q_UNUSED( text ); resetClassifyButton(); } void on_mMaxLineEdit_textChanged( const QString & ) { resetClassifyButton(); }
void on_mMinLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); } void on_mMinLineEdit_textEdited( const QString & text ) ;
void on_mMaxLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); } void on_mMaxLineEdit_textEdited( const QString & text ) ;
void on_mClassificationModeComboBox_currentIndexChanged( int index ); void on_mClassificationModeComboBox_currentIndexChanged( int index );
void changeColor(); void changeColor();
void changeTransparency(); void changeTransparency();
@ -100,10 +103,11 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
void setLineEditValue( QLineEdit *theLineEdit, double theValue ); void setLineEditValue( QLineEdit *theLineEdit, double theValue );
double lineEditValue( const QLineEdit *theLineEdit ) const; double lineEditValue( const QLineEdit *theLineEdit ) const;
void resetClassifyButton(); void resetClassifyButton();
void showMinMaxOrigin();
QgsRasterMinMaxWidget * mMinMaxWidget; QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;
int mMinMaxOrigin; int mMinMaxOrigin;
void minMaxModified();
}; };

View File

@ -686,7 +686,7 @@ void QgsGeorefPluginGui::localHistogramStretch()
{ {
QgsRectangle rectangle = mIface->mapCanvas()->mapSettings().outputExtentToLayerExtent( mLayer, mIface->mapCanvas()->extent() ); QgsRectangle rectangle = mIface->mapCanvas()->mapSettings().outputExtentToLayerExtent( mLayer, mIface->mapCanvas()->extent() );
mLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax, rectangle ); mLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax, rectangle );
mCanvas->refresh(); mCanvas->refresh();
} }

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>857</width> <width>1029</width>
<height>658</height> <height>726</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -308,7 +308,7 @@
<item> <item>
<widget class="QStackedWidget" name="mOptionsStackedWidget"> <widget class="QStackedWidget" name="mOptionsStackedWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>8</number> <number>3</number>
</property> </property>
<widget class="QWidget" name="mOptionsPageGeneral"> <widget class="QWidget" name="mOptionsPageGeneral">
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
@ -337,8 +337,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>712</width> <width>723</width>
<height>693</height> <height>640</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_28"> <layout class="QVBoxLayout" name="verticalLayout_28">
@ -1023,8 +1023,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>601</width> <width>607</width>
<height>877</height> <height>850</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_22"> <layout class="QVBoxLayout" name="verticalLayout_22">
@ -1456,8 +1456,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>540</width> <width>545</width>
<height>741</height> <height>694</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_27"> <layout class="QVBoxLayout" name="verticalLayout_27">
@ -1813,9 +1813,9 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>-299</y>
<width>735</width> <width>839</width>
<height>1038</height> <height>982</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_22"> <layout class="QGridLayout" name="gridLayout_22">
@ -2233,45 +2233,67 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_11">
<item> <item>
<widget class="QWidget" name="widget_3" native="true"> <layout class="QGridLayout" name="gridLayout_33">
<layout class="QHBoxLayout" name="horizontalLayout_22"> <item row="4" column="2">
<property name="leftMargin"> <widget class="QComboBox" name="cboxContrastEnhancementLimitsMultiBandSingleByte"/>
<number>0</number> </item>
</property> <item row="1" column="1">
<property name="topMargin"> <widget class="QLabel" name="label_50">
<number>0</number> <property name="text">
</property> <string>Algorithm</string>
<property name="rightMargin"> </property>
<number>0</number> <property name="alignment">
</property> <set>Qt::AlignCenter</set>
<property name="bottomMargin"> </property>
<number>0</number> </widget>
</property> </item>
<item> <item row="3" column="1">
<widget class="QLabel" name="label_37"> <widget class="QComboBox" name="cboxContrastEnhancementAlgorithmSingleBand"/>
<property name="text"> </item>
<string>Single band gray</string> <item row="3" column="0">
</property> <widget class="QLabel" name="label_37">
</widget> <property name="text">
</item> <string>Single band gray</string>
<item> </property>
<widget class="QComboBox" name="cboxContrastEnhancementAlgorithmSingleBand"/> </widget>
</item> </item>
<item> <item row="1" column="2">
<spacer name="horizontalSpacer_23"> <widget class="QLabel" name="label_51">
<property name="orientation"> <property name="text">
<enum>Qt::Horizontal</enum> <string>Limits (minimum/maximum)</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="alignment">
<size> <set>Qt::AlignCenter</set>
<width>208</width> </property>
<height>20</height> </widget>
</size> </item>
</property> <item row="3" column="2">
</spacer> <widget class="QComboBox" name="cboxContrastEnhancementLimitsSingleBand"/>
</item> </item>
</layout> <item row="4" column="1">
</widget> <widget class="QComboBox" name="cboxContrastEnhancementAlgorithmMultiBandSingleByte"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Multi band color (byte / band) </string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Multi band color (&gt; byte / band) </string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cboxContrastEnhancementAlgorithmMultiBandMultiByte"/>
</item>
<item row="5" column="2">
<widget class="QComboBox" name="cboxContrastEnhancementLimitsMultiBandMultiByte"/>
</item>
</layout>
</item> </item>
<item> <item>
<widget class="QWidget" name="widget_4" native="true"> <widget class="QWidget" name="widget_4" native="true">
@ -2288,29 +2310,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QLabel" name="label_38">
<property name="text">
<string>Multi band color (byte / band) </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxContrastEnhancementAlgorithmMultiBandSingleByte"/>
</item>
<item>
<spacer name="horizontalSpacer_24">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>208</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -2329,29 +2328,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QLabel" name="label_39">
<property name="text">
<string>Multi band color (&gt; byte / band) </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxContrastEnhancementAlgorithmMultiBandMultiByte"/>
</item>
<item>
<spacer name="horizontalSpacer_25">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>208</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -2377,29 +2353,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QLabel" name="label_40">
<property name="text">
<string>Limits (minimum/maximum)</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboxContrastEnhancementLimits"/>
</item>
<item>
<spacer name="horizontalSpacer_26">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>208</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -2612,8 +2565,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>148</width> <width>147</width>
<height>276</height> <height>240</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_46"> <layout class="QHBoxLayout" name="horizontalLayout_46">
@ -2759,8 +2712,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>526</width> <width>528</width>
<height>354</height> <height>327</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_25"> <layout class="QVBoxLayout" name="verticalLayout_25">
@ -3102,8 +3055,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>639</width> <width>650</width>
<height>668</height> <height>612</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_30"> <layout class="QVBoxLayout" name="verticalLayout_30">
@ -3533,8 +3486,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>522</width> <width>514</width>
<height>591</height> <height>571</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_39"> <layout class="QVBoxLayout" name="verticalLayout_39">
@ -3802,8 +3755,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>670</width> <width>586</width>
<height>718</height> <height>701</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_31"> <layout class="QVBoxLayout" name="verticalLayout_31">
@ -4357,8 +4310,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>457</width> <width>474</width>
<height>382</height> <height>372</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6"> <layout class="QVBoxLayout" name="verticalLayout_6">
@ -4496,8 +4449,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>557</width> <width>574</width>
<height>677</height> <height>644</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_15"> <layout class="QGridLayout" name="gridLayout_15">
@ -4579,7 +4532,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QRadioButton" name="radOtfNone"> <widget class="QRadioButton" name="radOtfNone">
<property name="text"> <property name="text">
<string>Don't enable 'on the fly' reprojection</string> <string>Don't enable 'on the fl&amp;y' reprojection</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -4609,7 +4562,7 @@
<item row="2" column="0"> <item row="2" column="0">
<widget class="QRadioButton" name="radOtfTransform"> <widget class="QRadioButton" name="radOtfTransform">
<property name="text"> <property name="text">
<string>Enable 'on the &amp;fly' reprojection by default</string> <string>Enable 'on t&amp;he fly' reprojection by default</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -4743,7 +4696,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>302</width> <width>302</width>
<height>238</height> <height>226</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_32"> <layout class="QVBoxLayout" name="verticalLayout_32">
@ -4851,8 +4804,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>670</width> <width>542</width>
<height>793</height> <height>737</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_33"> <layout class="QVBoxLayout" name="verticalLayout_33">
@ -5489,9 +5442,6 @@
<tabstop>spnGreen</tabstop> <tabstop>spnGreen</tabstop>
<tabstop>spnBlue</tabstop> <tabstop>spnBlue</tabstop>
<tabstop>cboxContrastEnhancementAlgorithmSingleBand</tabstop> <tabstop>cboxContrastEnhancementAlgorithmSingleBand</tabstop>
<tabstop>cboxContrastEnhancementAlgorithmMultiBandSingleByte</tabstop>
<tabstop>cboxContrastEnhancementAlgorithmMultiBandMultiByte</tabstop>
<tabstop>cboxContrastEnhancementLimits</tabstop>
<tabstop>mRasterCumulativeCutLowerDoubleSpinBox</tabstop> <tabstop>mRasterCumulativeCutLowerDoubleSpinBox</tabstop>
<tabstop>mRasterCumulativeCutUpperDoubleSpinBox</tabstop> <tabstop>mRasterCumulativeCutUpperDoubleSpinBox</tabstop>
<tabstop>spnThreeBandStdDev</tabstop> <tabstop>spnThreeBandStdDev</tabstop>

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>316</width> <width>324</width>
<height>300</height> <height>250</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -45,202 +45,211 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QGridLayout" name="gridLayout">
<item> <item row="0" column="0">
<widget class="QRadioButton" name="mCumulativeCutRadioButton"> <widget class="QRadioButton" name="mUserDefinedRadioButton">
<property name="text"> <property name="text">
<string>Cumulative <string>Use&amp;r defined</string>
count cut</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="buttonGroup"> <attribute name="buttonGroup">
<string notr="true">buttonGroup</string> <string notr="true">mMinMaxMethodRadioButtonGroup</string>
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item> <item row="1" column="0">
<widget class="QDoubleSpinBox" name="mCumulativeCutLowerDoubleSpinBox"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="decimals"> <item>
<number>1</number> <widget class="QRadioButton" name="mCumulativeCutRadioButton">
</property> <property name="text">
</widget> <string>Cumula&amp;tive
count cut</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mMinMaxMethodRadioButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mCumulativeCutLowerDoubleSpinBox">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mCumulativeCutUpperDoubleSpinBox">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>%</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>123</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
<item> <item row="4" column="0">
<widget class="QLabel" name="label"> <layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="text"> <item>
<string>-</string> <widget class="QRadioButton" name="mStdDevRadioButton">
</property> <property name="text">
</widget> <string>Mean +/-
standard de&amp;viation ×</string>
</property>
<attribute name="buttonGroup">
<string notr="true">mMinMaxMethodRadioButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mStdDevSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>123</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
<item> <item row="2" column="0">
<widget class="QDoubleSpinBox" name="mCumulativeCutUpperDoubleSpinBox">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>%</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>123</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="mMinMaxRadioButton"> <widget class="QRadioButton" name="mMinMaxRadioButton">
<property name="text"> <property name="text">
<string>Min / max</string> <string>&amp;Min / max</string>
</property> </property>
<attribute name="buttonGroup"> <attribute name="buttonGroup">
<string notr="true">buttonGroup</string> <string notr="true">mMinMaxMethodRadioButtonGroup</string>
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item> <item row="6" column="0">
<spacer name="horizontalSpacer"> <layout class="QGridLayout" name="gridLayout_2">
<property name="orientation"> <item row="0" column="1">
<enum>Qt::Horizontal</enum> <widget class="QComboBox" name="mStatisticsExtentCombo">
</property> <item>
<property name="sizeHint" stdset="0"> <property name="text">
<size> <string>Whole raster</string>
<width>0</width> </property>
<height>20</height> </item>
</size> <item>
</property> <property name="text">
</spacer> <string>Current canvas</string>
</property>
</item>
<item>
<property name="text">
<string>Updated canvas</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mStatisticsExtentLabel">
<property name="text">
<string>Statistics extent</string>
</property>
<property name="margin">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mAccuracyLabel">
<property name="text">
<string>Accuracy</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cboAccuracy">
<item>
<property name="text">
<string>Estimate (faster)</string>
</property>
</item>
<item>
<property name="text">
<string>Actual (slower)</string>
</property>
</item>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QRadioButton" name="mStdDevRadioButton">
<property name="text">
<string>Mean +/-
standard deviation ×</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mStdDevSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QPushButton" name="mLoadPushButton">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="mColorInterpolationLabel_2">
<property name="text">
<string>Accuracy</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cboAccuracy">
<item>
<property name="text">
<string>Estimate (faster)</string>
</property>
</item>
<item>
<property name="text">
<string>Actual (slower)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="cbxClipExtent">
<property name="text">
<string>Clip extent to canvas</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mUserDefinedRadioButton</tabstop>
<tabstop>mCumulativeCutRadioButton</tabstop>
<tabstop>mCumulativeCutLowerDoubleSpinBox</tabstop>
<tabstop>mCumulativeCutUpperDoubleSpinBox</tabstop>
<tabstop>mMinMaxRadioButton</tabstop>
<tabstop>mStdDevRadioButton</tabstop>
<tabstop>mStdDevSpinBox</tabstop>
</tabstops>
<resources/> <resources/>
<connections/> <connections/>
<buttongroups> <buttongroups>
<buttongroup name="buttonGroup"/> <buttongroup name="mMinMaxMethodRadioButtonGroup"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -26,6 +26,46 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>3</number> <number>3</number>
</property> </property>
<item row="6" column="0" colspan="5">
<widget class="QTreeWidget" name="mColormapTreeWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<attribute name="headerDefaultSectionSize">
<number>70</number>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>10</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
<column>
<property name="text">
<string>Label</string>
</property>
</column>
</widget>
</item>
<item row="4" column="1" colspan="4"> <item row="4" column="1" colspan="4">
<widget class="QgsColorRampButton" name="btnColorRamp"> <widget class="QgsColorRampButton" name="btnColorRamp">
<property name="sizePolicy"> <property name="sizePolicy">
@ -60,12 +100,12 @@
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLabel" name="mMinLabel"> <widget class="QLabel" name="mMinLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Min</string> <string>Min</string>
</property> </property>
@ -74,6 +114,9 @@
<item row="3" column="1" colspan="4"> <item row="3" column="1" colspan="4">
<widget class="QComboBox" name="mColorInterpolationComboBox"/> <widget class="QComboBox" name="mColorInterpolationComboBox"/>
</item> </item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="mBandComboBox"/>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="mBandLabel"> <widget class="QLabel" name="mBandLabel">
<property name="text"> <property name="text">
@ -81,17 +124,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="mBandComboBox"/>
</item>
<item row="1" column="3"> <item row="1" column="3">
<widget class="QLabel" name="mMaxLabel"> <widget class="QLabel" name="mMaxLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Max</string> <string>Max</string>
</property> </property>
@ -104,7 +144,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0" colspan="5"> <item row="8" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<widget class="QPushButton" name="mClassifyButton"> <widget class="QPushButton" name="mClassifyButton">
@ -183,28 +223,10 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="6" column="0"> <item row="1" column="2">
<widget class="QLabel" name="label_2"> <widget class="QLineEdit" name="mMinLineEdit"/>
<property name="text">
<string>Min / max
origin:</string>
</property>
</widget>
</item> </item>
<item row="6" column="1" colspan="4"> <item row="9" column="0" colspan="5">
<widget class="QLabel" name="mMinMaxOriginLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Min / Max origin</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="5">
<widget class="QCheckBox" name="mClipCheckBox"> <widget class="QCheckBox" name="mClipCheckBox">
<property name="toolTip"> <property name="toolTip">
<string>If checked, any pixels with a value out of range will not be rendered</string> <string>If checked, any pixels with a value out of range will not be rendered</string>
@ -214,10 +236,7 @@ origin:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="7" column="0" colspan="5">
<widget class="QLineEdit" name="mMinLineEdit"/>
</item>
<item row="8" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<widget class="QLabel" name="mClassificationModeLabel"> <widget class="QLabel" name="mClassificationModeLabel">
@ -257,12 +276,12 @@ origin:</string>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximum">
<number>255</number>
</property>
<property name="minimum"> <property name="minimum">
<number>2</number> <number>2</number>
</property> </property>
<property name="maximum">
<number>255</number>
</property>
<property name="value"> <property name="value">
<number>5</number> <number>5</number>
</property> </property>
@ -270,49 +289,6 @@ origin:</string>
</item> </item>
</layout> </layout>
</item> </item>
<item row="2" column="0" colspan="5">
<widget class="QWidget" name="mMinMaxContainerWidget" native="true"/>
</item>
<item row="7" column="0" colspan="5">
<widget class="QTreeWidget" name="mColormapTreeWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<attribute name="headerDefaultSectionSize">
<number>70</number>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>10</number>
</attribute>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Value</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
<column>
<property name="text">
<string>Label</string>
</property>
</column>
</widget>
</item>
<item row="5" column="1" colspan="4"> <item row="5" column="1" colspan="4">
<widget class="QLineEdit" name="mUnitLineEdit"> <widget class="QLineEdit" name="mUnitLineEdit">
<property name="toolTip"> <property name="toolTip">
@ -320,6 +296,9 @@ origin:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="5">
<widget class="QWidget" name="mMinMaxContainerWidget" native="true"/>
</item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="mUnitLabel"> <widget class="QLabel" name="mUnitLabel">
<property name="text"> <property name="text">

View File

@ -45,6 +45,7 @@
//qgis unit test includes //qgis unit test includes
#include <qgsrenderchecker.h> #include <qgsrenderchecker.h>
#include "qgstestutils.h"
/** \ingroup UnitTests /** \ingroup UnitTests
* This is a unit test for the QgsRasterLayer class. * This is a unit test for the QgsRasterLayer class.
@ -90,6 +91,7 @@ class TestQgsRasterLayer : public QObject
void multiBandColorRenderer(); void multiBandColorRenderer();
void setRenderer(); void setRenderer();
void regression992(); //test for issue #992 - GeoJP2 images improperly displayed as all black void regression992(); //test for issue #992 - GeoJP2 images improperly displayed as all black
void testRefreshRendererIfNeeded();
private: private:
@ -206,7 +208,7 @@ void TestQgsRasterLayer::cleanupTestCase()
void TestQgsRasterLayer::isValid() void TestQgsRasterLayer::isValid()
{ {
QVERIFY( mpRasterLayer->isValid() ); QVERIFY( mpRasterLayer->isValid() );
mpRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax ); mpRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setExtent( mpRasterLayer->extent() ); mMapSettings->setExtent( mpRasterLayer->extent() );
QVERIFY( render( "raster" ) ); QVERIFY( render( "raster" ) );
} }
@ -355,7 +357,7 @@ void TestQgsRasterLayer::colorRamp4()
void TestQgsRasterLayer::landsatBasic() void TestQgsRasterLayer::landsatBasic()
{ {
QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" ); QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" );
mpLandsatRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax ); mpLandsatRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setLayers( QList<QgsMapLayer*>() << mpLandsatRasterLayer ); mMapSettings->setLayers( QList<QgsMapLayer*>() << mpLandsatRasterLayer );
mMapSettings->setExtent( mpLandsatRasterLayer->extent() ); mMapSettings->setExtent( mpLandsatRasterLayer->extent() );
QVERIFY( render( "landsat_basic" ) ); QVERIFY( render( "landsat_basic" ) );
@ -632,7 +634,7 @@ void TestQgsRasterLayer::transparency()
QVERIFY( mpFloat32RasterLayer->isValid() ); QVERIFY( mpFloat32RasterLayer->isValid() );
QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( mpRasterLayer->dataProvider(), 1 ); QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( mpRasterLayer->dataProvider(), 1 );
mpFloat32RasterLayer->setRenderer( renderer ); mpFloat32RasterLayer->setRenderer( renderer );
mpFloat32RasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax ); mpFloat32RasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
qDebug( "contrastEnhancement.minimumValue = %.17g", renderer->contrastEnhancement()->minimumValue() ); qDebug( "contrastEnhancement.minimumValue = %.17g", renderer->contrastEnhancement()->minimumValue() );
qDebug( "contrastEnhancement.maximumValue = %.17g", renderer->contrastEnhancement()->maximumValue() ); qDebug( "contrastEnhancement.maximumValue = %.17g", renderer->contrastEnhancement()->maximumValue() );
@ -695,5 +697,31 @@ void TestQgsRasterLayer::regression992()
QVERIFY( render( "raster_geojp2", 400 ) ); QVERIFY( render( "raster_geojp2", 400 ) );
} }
void TestQgsRasterLayer::testRefreshRendererIfNeeded()
{
QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" );
mpLandsatRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setLayers( QList<QgsMapLayer*>() << mpLandsatRasterLayer );
mMapSettings->setExtent( mpLandsatRasterLayer->extent() );
double initMinVal = dynamic_cast<QgsMultiBandColorRenderer*>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
// Should do nothing
QgsRectangle newExtent = QgsRectangle( 785000, 3340000, 785100, 3340100 );
mpLandsatRasterLayer->refreshRendererIfNeeded( mpLandsatRasterLayer->renderer(), newExtent );
QCOMPARE( mpLandsatRasterLayer->renderer()->minMaxOrigin().limits(), QgsRasterMinMaxOrigin::MinMax );
double minVal = dynamic_cast<QgsMultiBandColorRenderer*>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
QGSCOMPARENEAR( initMinVal, minVal, 1e-5 );
// Change to UpdatedCanvas
QgsRasterMinMaxOrigin mmo = mpLandsatRasterLayer->renderer()->minMaxOrigin();
mmo.setExtent( QgsRasterMinMaxOrigin::UpdatedCanvas );
mmo.setStatAccuracy( QgsRasterMinMaxOrigin::Exact );
mpLandsatRasterLayer->renderer()->setMinMaxOrigin( mmo );
QCOMPARE( mpLandsatRasterLayer->renderer()->minMaxOrigin().extent(), QgsRasterMinMaxOrigin::UpdatedCanvas );
mpLandsatRasterLayer->refreshRendererIfNeeded( mpLandsatRasterLayer->renderer(), newExtent );
double newMinVal = dynamic_cast<QgsMultiBandColorRenderer*>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
QGSCOMPARENOTNEAR( initMinVal, newMinVal, 1e-5 );
}
QTEST_MAIN( TestQgsRasterLayer ) QTEST_MAIN( TestQgsRasterLayer )
#include "testqgsrasterlayer.moc" #include "testqgsrasterlayer.moc"

View File

@ -19,6 +19,7 @@ import os
from qgis.PyQt.QtCore import QFileInfo from qgis.PyQt.QtCore import QFileInfo
from qgis.PyQt.QtGui import QColor from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import (QgsRaster, from qgis.core import (QgsRaster,
QgsRasterLayer, QgsRasterLayer,
@ -27,6 +28,7 @@ from qgis.core import (QgsRaster,
QgsProject, QgsProject,
QgsMapSettings, QgsMapSettings,
QgsPoint, QgsPoint,
QgsRasterMinMaxOrigin,
QgsRasterShader, QgsRasterShader,
QgsRasterTransparency, QgsRasterTransparency,
QgsRenderChecker, QgsRenderChecker,
@ -89,7 +91,7 @@ class TestQgsRasterLayer(unittest.TestCase):
myRasterLayer.setRenderer(renderer) myRasterLayer.setRenderer(renderer)
myRasterLayer.setContrastEnhancement( myRasterLayer.setContrastEnhancement(
QgsContrastEnhancement.StretchToMinimumMaximum, QgsContrastEnhancement.StretchToMinimumMaximum,
QgsRaster.ContrastEnhancementMinMax) QgsRasterMinMaxOrigin.MinMax)
myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement() myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement()
# print ("myContrastEnhancement.minimumValue = %.17g" % # print ("myContrastEnhancement.minimumValue = %.17g" %
@ -229,5 +231,62 @@ class TestQgsRasterLayer(unittest.TestCase):
assert self.rendererChanged assert self.rendererChanged
assert layer.renderer() == r assert layer.renderer() == r
def testQgsRasterMinMaxOrigin(self):
mmo = QgsRasterMinMaxOrigin()
mmo_default = QgsRasterMinMaxOrigin()
self.assertEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertEqual(mmo.limits(), QgsRasterMinMaxOrigin.None_)
mmo.setLimits(QgsRasterMinMaxOrigin.CumulativeCut)
self.assertEqual(mmo.limits(), QgsRasterMinMaxOrigin.CumulativeCut)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertEqual(mmo.extent(), QgsRasterMinMaxOrigin.WholeRaster)
mmo.setExtent(QgsRasterMinMaxOrigin.UpdatedCanvas)
self.assertEqual(mmo.extent(), QgsRasterMinMaxOrigin.UpdatedCanvas)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertEqual(mmo.statAccuracy(), QgsRasterMinMaxOrigin.Estimated)
mmo.setStatAccuracy(QgsRasterMinMaxOrigin.Exact)
self.assertEqual(mmo.statAccuracy(), QgsRasterMinMaxOrigin.Exact)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertAlmostEqual(mmo.cumulativeCutLower(), 0.02)
mmo.setCumulativeCutLower(0.1)
self.assertAlmostEqual(mmo.cumulativeCutLower(), 0.1)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertAlmostEqual(mmo.cumulativeCutUpper(), 0.98)
mmo.setCumulativeCutUpper(0.9)
self.assertAlmostEqual(mmo.cumulativeCutUpper(), 0.9)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
self.assertAlmostEqual(mmo.stdDevFactor(), 2.0)
mmo.setStdDevFactor(2.5)
self.assertAlmostEqual(mmo.stdDevFactor(), 2.5)
self.assertNotEqual(mmo, mmo_default)
mmo = QgsRasterMinMaxOrigin()
mmo.setLimits(QgsRasterMinMaxOrigin.CumulativeCut)
mmo.setExtent(QgsRasterMinMaxOrigin.UpdatedCanvas)
mmo.setStatAccuracy(QgsRasterMinMaxOrigin.Exact)
mmo.setCumulativeCutLower(0.1)
mmo.setCumulativeCutUpper(0.9)
mmo.setStdDevFactor(2.5)
doc = QDomDocument()
parentElem = doc.createElement("test")
mmo.writeXml(doc, parentElem)
mmoUnserialized = QgsRasterMinMaxOrigin()
mmoUnserialized.readXml(parentElem)
self.assertEqual(mmo, mmoUnserialized)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()