14 changes: 6 additions & 8 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8785,11 +8785,9 @@ void QgisApp::legendLayerStretchUsingCurrentExtent()
QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( currentLayer );
if ( layer )
{
QgsContrastEnhancement::ContrastEnhancementAlgorithm contrastEnhancementAlgorithm = QgsContrastEnhancement::StretchToMinimumMaximum;

QgsRectangle myRectangle;
myRectangle = mMapCanvas->mapSettings().outputExtentToLayerExtent( layer, mMapCanvas->extent() );
layer->setContrastEnhancement( contrastEnhancementAlgorithm, QgsRaster::ContrastEnhancementMinMax, myRectangle );
layer->refreshContrastEnhancement( myRectangle );

mLayerTreeView->refreshLayerSymbology( layer->id() );
mMapCanvas->refresh();
Expand Down Expand Up @@ -9116,25 +9114,25 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString& currentPage )

void QgisApp::fullHistogramStretch()
{
histogramStretch( false, QgsRaster::ContrastEnhancementMinMax );
histogramStretch( false, QgsRasterMinMaxOrigin::MinMax );
}

void QgisApp::localHistogramStretch()
{
histogramStretch( true, QgsRaster::ContrastEnhancementMinMax );
histogramStretch( true, QgsRasterMinMaxOrigin::MinMax );
}

void QgisApp::fullCumulativeCutStretch()
{
histogramStretch( false, QgsRaster::ContrastEnhancementCumulativeCut );
histogramStretch( false, QgsRasterMinMaxOrigin::CumulativeCut );
}

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();

Expand Down
3 changes: 2 additions & 1 deletion src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class QgsDiagramProperties;
#include "qgsmimedatautils.h"
#include "qgswelcomepageitemsmodel.h"
#include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"

#include "ui_qgisapp.h"

Expand Down Expand Up @@ -1522,7 +1523,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void createDecorations();

//! 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
void adjustBrightnessContrast( int delta, bool updateBrightness = true );
Expand Down
33 changes: 33 additions & 0 deletions src/app/qgslayerstylingwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "qgsmaplayerconfigwidget.h"
#include "qgsmaplayerstylemanagerwidget.h"
#include "qgsruntimeprofiler.h"
#include "qgsrasterminmaxwidget.h"


QgsLayerStylingWidget::QgsLayerStylingWidget( QgsMapCanvas* canvas, const QList<QgsMapLayerConfigWidgetFactory*>& pages, QWidget *parent )
Expand Down Expand Up @@ -378,15 +379,47 @@ void QgsLayerStylingWidget::updateCurrentWidgetLayer()
else if ( mCurrentLayer->type() == QgsMapLayer::RasterLayer )
{
QgsRasterLayer *rlayer = qobject_cast<QgsRasterLayer*>( mCurrentLayer );
bool hasMinMaxCollapsedState = false;
bool minMaxCollapsed = false;

switch ( row )
{
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 );
if ( hasMinMaxCollapsedState )
{
QgsRasterRendererWidget* currentRenderWidget = mRasterStyleWidget->currentRenderWidget();
if ( currentRenderWidget )
{
QgsRasterMinMaxWidget* mmWidget = currentRenderWidget->minMaxWidget();
if ( mmWidget )
{
mmWidget->setCollapsed( minMaxCollapsed );
}
}
}
mRasterStyleWidget->setDockMode( true );
connect( mRasterStyleWidget, SIGNAL( widgetChanged() ), this, SLOT( autoApply() ) );
mWidgetStack->setMainPanel( mRasterStyleWidget );
break;
}

case 1: // Transparency
{
QgsRasterTransparencyWidget* transwidget = new QgsRasterTransparencyWidget( rlayer, mMapCanvas, mWidgetStack );
Expand Down
78 changes: 55 additions & 23 deletions src/app/qgsoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "qgsproject.h"
#include "qgsdualview.h"
#include "qgsrasterlayer.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"

#include "qgsattributetablefiltermodel.h"
#include "qgsrasterformatsaveoptionswidget.h"
Expand Down Expand Up @@ -653,22 +655,24 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
spnGreen->setValue( mSettings->value( QStringLiteral( "/Raster/defaultGreenBand" ), 2 ).toInt() );
spnBlue->setValue( mSettings->value( QStringLiteral( "/Raster/defaultBlueBand" ), 3 ).toInt() );

initContrastEnhancement( cboxContrastEnhancementAlgorithmSingleBand, QStringLiteral( "singleBand" ), QStringLiteral( "StretchToMinimumMaximum" ) );
initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ), QStringLiteral( "NoEnhancement" ) );
initContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ), QStringLiteral( "StretchToMinimumMaximum" ) );
initContrastEnhancement( cboxContrastEnhancementAlgorithmSingleBand, QStringLiteral( "singleBand" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsRasterLayer::SINGLE_BAND_ENHANCEMENT_ALGORITHM ) );
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" );
cboxContrastEnhancementLimits->addItem( tr( "Minimum / maximum" ), "MinMax" );
cboxContrastEnhancementLimits->addItem( tr( "Mean +/- standard deviation" ), "StdDev" );
initMinMaxLimits( cboxContrastEnhancementLimitsSingleBand, QStringLiteral( "singleBand" ),
QgsRasterMinMaxOrigin::limitsString( QgsRasterLayer::SINGLE_BAND_MIN_MAX_LIMITS ) );
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 ) );

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() );
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() );

//set the color for selections
int myRed = mSettings->value( QStringLiteral( "/qgis/default_selection_color_red" ), 255 ).toInt();
Expand Down Expand Up @@ -1268,8 +1272,9 @@ void QgsOptions::saveOptions()
saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ) );
saveContrastEnhancement( cboxContrastEnhancementAlgorithmMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ) );

QString contrastEnhancementLimits = cboxContrastEnhancementLimits->currentData().toString();
mSettings->setValue( QStringLiteral( "/Raster/defaultContrastEnhancementLimits" ), contrastEnhancementLimits );
saveMinMaxLimits( cboxContrastEnhancementLimitsSingleBand, QStringLiteral( "singleBand" ) );
saveMinMaxLimits( cboxContrastEnhancementLimitsMultiBandSingleByte, QStringLiteral( "multiBandSingleByte" ) );
saveMinMaxLimits( cboxContrastEnhancementLimitsMultiBandMultiByte, QStringLiteral( "multiBandMultiByte" ) );

mSettings->setValue( QStringLiteral( "/Raster/defaultStandardDeviation" ), spnThreeBandStdDev->value() );

Expand Down Expand Up @@ -2071,14 +2076,18 @@ void QgsOptions::initContrastEnhancement( QComboBox *cbox, const QString& name,
{
QSettings settings;

//add items to the color enhanceContrast combo box
cbox->addItem( tr( "No Stretch" ), "NoEnhancement" );
cbox->addItem( tr( "Stretch To MinMax" ), "StretchToMinimumMaximum" );
cbox->addItem( tr( "Stretch And Clip To MinMax" ), "StretchAndClipToMinimumMaximum" );
cbox->addItem( tr( "Clip To MinMax" ), "ClipToMinimumMaximum" );

QString contrastEnchacement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastEnchacement ) );
//add items to the color enhanceContrast combo boxes
cbox->addItem( tr( "No Stretch" ),
QgsContrastEnhancement::contrastEnhancementAlgorithmString( QgsContrastEnhancement::NoEnhancement ) );
cbox->addItem( tr( "Stretch To MinMax" ),
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 contrastEnhancement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastEnhancement ) );
}

void QgsOptions::saveContrastEnhancement( QComboBox *cbox, const QString& name )
Expand All @@ -2088,6 +2097,29 @@ void QgsOptions::saveContrastEnhancement( QComboBox *cbox, const QString& name )
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()
{
QList<QTreeWidgetItem*> items = mDefaultDatumTransformTreeWidget->selectedItems();
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ class APP_EXPORT QgsOptions : public QgsOptionsDialogBase, private Ui::QgsOption
QStringList i18nList();
void initContrastEnhancement( QComboBox *cbox, const QString& name, const QString& defaultVal );
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 mLayerDefaultCrs;
bool mLoadedGdalDriverList;
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsrasterlayerproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,8 @@ void QgsRasterLayerProperties::apply()
QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( mRendererStackedWidget->currentWidget() );
if ( rendererWidget )
{
rendererWidget->doComputations();

mRasterLayer->setRenderer( rendererWidget->renderer() );
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ SET(QGIS_CORE_SRCS
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
raster/qgsrasterlayerrenderer.cpp
raster/qgsrasterminmaxorigin.cpp
raster/qgsrasternuller.cpp
raster/qgsrasterpipe.cpp
raster/qgsrasterprojector.cpp
Expand Down Expand Up @@ -800,6 +801,7 @@ SET(QGIS_CORE_HDRS
raster/qgsrasteridentifyresult.h
raster/qgsrasterinterface.h
raster/qgsrasteriterator.h
raster/qgsrasterminmaxorigin.h
raster/qgsrasternuller.h
raster/qgsrasterpipe.h
raster/qgsrasterprojector.h
Expand Down
13 changes: 7 additions & 6 deletions src/core/raster/qgscontrastenhancement.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class originally created circa 2004 by T.Sutton, Gary E.Sherman, Steve Halasz
#include <limits>

#include "qgis.h"
#include "qgsraster.h"

class QgsContrastEnhancementFunction;
class QDomDocument;
Expand Down Expand Up @@ -65,6 +66,12 @@ class CORE_EXPORT QgsContrastEnhancement
//! \brief Helper function that returns the minimum possible value for a GDAL data type
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
Expand All @@ -78,10 +85,6 @@ class CORE_EXPORT QgsContrastEnhancement

ContrastEnhancementAlgorithm contrastEnhancementAlgorithm() const { return mContrastEnhancementAlgorithm; }

static QString contrastEnhancementAlgorithmString( ContrastEnhancementAlgorithm algorithm );

static ContrastEnhancementAlgorithm contrastEnhancementAlgorithmFromString( const QString& contrastEnhancementString );

/*
*
* Non-Static methods
Expand Down Expand Up @@ -137,8 +140,6 @@ class CORE_EXPORT QgsContrastEnhancement
//! \brief Maximum range of values for a given data type
double mRasterDataTypeRange;



//! \brief Method to generate a new lookup table
bool generateLookupTable();

Expand Down
33 changes: 0 additions & 33 deletions src/core/raster/qgsraster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,6 @@

#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 )
{
switch ( dataType )
Expand Down
12 changes: 0 additions & 12 deletions src/core/raster/qgsraster.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,6 @@ class CORE_EXPORT QgsRaster
PyramidsErdas = 2
};

//! \brief Contrast enhancement limits
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};

//! \brief This enumerator describes the different kinds of drawing we can do
enum DrawingStyle
{
Expand All @@ -124,9 +115,6 @@ class CORE_EXPORT QgsRaster
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.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* @param value
Expand Down
309 changes: 253 additions & 56 deletions src/core/raster/qgsrasterlayer.cpp

Large diffs are not rendered by default.

62 changes: 56 additions & 6 deletions src/core/raster/qgsrasterlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "qgsraster.h"
#include "qgsrasterpipe.h"
#include "qgsrasterviewport.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"

class QgsMapToPixel;
Expand Down Expand Up @@ -136,15 +137,28 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
{
Q_OBJECT
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
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.
QgsRasterLayer();

Expand Down Expand Up @@ -291,11 +305,30 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer


void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax,
QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax,
const QgsRectangle& theExtent = QgsRectangle(),
int theSampleSize = SAMPLE_SIZE,
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
void setDefaultContrastEnhancement();

Expand Down Expand Up @@ -368,6 +401,20 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
//! Sets corresponding renderer for style
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
const QString QSTRING_NOT_SET;
const QString TRSTRING_NOT_SET;
Expand All @@ -386,6 +433,9 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
LayerType mRasterType;

QgsRasterPipe mPipe;

//! To save computations and possible infinite cycle of notifications
QgsRectangle mLastRectangleUsedByRefreshContrastEnhancementIfNeeded;
};

#endif
3 changes: 3 additions & 0 deletions src/core/raster/qgsrasterlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRender

// copy the whole raster pipe!
mPipe = new QgsRasterPipe( *layer->pipe() );
QgsRasterRenderer* rasterRenderer = mPipe->renderer();
if ( rasterRenderer )
layer->refreshRendererIfNeeded( rasterRenderer, myRasterExtent );
}

QgsRasterLayerRenderer::~QgsRasterLayerRenderer()
Expand Down
205 changes: 205 additions & 0 deletions src/core/raster/qgsrasterminmaxorigin.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
}
159 changes: 159 additions & 0 deletions src/core/raster/qgsrasterminmaxorigin.h
Original file line number Diff line number Diff line change
@@ -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
160 changes: 13 additions & 147 deletions src/core/raster/qgsrasterrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ void QgsRasterRenderer::_writeXml( QDomDocument& doc, QDomElement& rasterRendere
{
mRasterTransparency->writeXml( doc, rasterRendererElem );
}

QDomElement minMaxOriginElem = doc.createElement( QStringLiteral( "minMaxOrigin" ) );
mMinMaxOrigin.writeXml( doc, minMaxOriginElem );
rasterRendererElem.appendChild( minMaxOriginElem );
}

void QgsRasterRenderer::readXml( const QDomElement& rendererElem )
Expand All @@ -132,160 +136,22 @@ void QgsRasterRenderer::readXml( const QDomElement& rendererElem )
mRasterTransparency = new QgsRasterTransparency();
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 )
return;

setOpacity( other->opacity() );
setAlphaBand( other->alphaBand() );
setRasterTransparency( other->rasterTransparency() ? new QgsRasterTransparency( *other->rasterTransparency() ) : nullptr );
}

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;
if ( copyMinMaxOrigin )
setMinMaxOrigin( other->minMaxOrigin() );
}
30 changes: 10 additions & 20 deletions src/core/raster/qgsrasterrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <QPair>

#include "qgsrasterinterface.h"
#include "qgsrasterminmaxorigin.h"

class QDomElement;

Expand All @@ -36,22 +37,6 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
Q_DECLARE_TR_FUNCTIONS( QgsRasterRenderer );

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;

Expand Down Expand Up @@ -90,14 +75,16 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
/** Copies common properties like opacity / transparency data from other renderer.
* Useful when cloning renderers.
* @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
virtual QList<int> usesBands() const { return QList<int>(); }

static QString minMaxOriginName( int theOrigin );
static QString minMaxOriginLabel( int theOrigin );
static int minMaxOriginFromName( const QString& theName );
//! Returns const reference to origin of min/max values
const QgsRasterMinMaxOrigin& minMaxOrigin() const { return mMinMaxOrigin; }

//! Sets origin of min/max values
void setMinMaxOrigin( const QgsRasterMinMaxOrigin& theOrigin ) { mMinMaxOrigin = theOrigin; }

protected:

Expand All @@ -115,6 +102,9 @@ class CORE_EXPORT QgsRasterRenderer : public QgsRasterInterface
Default: -1 (not set)*/
int mAlphaBand;

//! Origin of min/max values
QgsRasterMinMaxOrigin mMinMaxOrigin;

private:

QgsRasterRenderer( const QgsRasterRenderer& );
Expand Down
47 changes: 44 additions & 3 deletions src/core/raster/qgssinglebandpseudocolorrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ QgsSingleBandPseudoColorRenderer::QgsSingleBandPseudoColorRenderer( QgsRasterInt
, mBand( band )
, mClassificationMin( std::numeric_limits<double>::quiet_NaN() )
, mClassificationMax( std::numeric_limits<double>::quiet_NaN() )
, mClassificationMinMaxOrigin( QgsRasterRenderer::MinMaxUnknown )
{
}

Expand Down Expand Up @@ -107,7 +106,50 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRenderer::create( const QDomElement&
// TODO: add _readXML in superclass?
r->setClassificationMin( elem.attribute( QStringLiteral( "classificationMin" ), 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;
}
Expand Down Expand Up @@ -228,7 +270,6 @@ void QgsSingleBandPseudoColorRenderer::writeXml( QDomDocument& doc, QDomElement&
}
rasterRendererElem.setAttribute( QStringLiteral( "classificationMin" ), QgsRasterBlock::printValue( mClassificationMin ) );
rasterRendererElem.setAttribute( QStringLiteral( "classificationMax" ), QgsRasterBlock::printValue( mClassificationMax ) );
rasterRendererElem.setAttribute( QStringLiteral( "classificationMinMaxOrigin" ), QgsRasterRenderer::minMaxOriginName( mClassificationMinMaxOrigin ) );

parentElem.appendChild( rasterRendererElem );
}
Expand Down
4 changes: 0 additions & 4 deletions src/core/raster/qgssinglebandpseudocolorrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer
double classificationMax() const { return mClassificationMax; }
void setClassificationMin( double min ) { mClassificationMin = min; }
void setClassificationMax( double max ) { mClassificationMax = max; }
int classificationMinMaxOrigin() const { return mClassificationMinMaxOrigin; }
void setClassificationMinMaxOrigin( int origin ) { mClassificationMinMaxOrigin = origin; }

private:
QgsRasterShader* mShader;
Expand All @@ -77,8 +75,6 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer
double mClassificationMin;
double mClassificationMax;

int mClassificationMinMaxOrigin;

QgsSingleBandPseudoColorRenderer( const QgsSingleBandPseudoColorRenderer& );
const QgsSingleBandPseudoColorRenderer& operator=( const QgsSingleBandPseudoColorRenderer& );
};
Expand Down
79 changes: 68 additions & 11 deletions src/gui/raster/qgsmultibandcolorrendererwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{
setupUi( this );
createValidators();
Expand All @@ -43,8 +44,11 @@ QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer
layout->setContentsMargins( 0, 0, 0, 0 );
mMinMaxContainerWidget->setLayout( layout );
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 ) ),
this, SLOT( onBandChanged( int ) ) );
Expand Down Expand Up @@ -108,9 +112,17 @@ QgsRasterRenderer* QgsMultiBandColorRendererWidget::renderer()

QgsMultiBandColorRenderer* r = new QgsMultiBandColorRenderer( provider, redBand, greenBand, blueBand );
setCustomMinMaxValues( r, provider, redBand, greenBand, blueBand );

r->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );

return r;
}

void QgsMultiBandColorRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
}

void QgsMultiBandColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{
QgsRasterRendererWidget::setMapCanvas( canvas );
Expand Down Expand Up @@ -214,9 +226,51 @@ void QgsMultiBandColorRendererWidget::onBandChanged( int index )
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 ) );

QLineEdit *myMinLineEdit, *myMaxLineEdit;
Expand All @@ -242,6 +296,7 @@ void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin,
return;
}

mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) )
{
myMinLineEdit->clear();
Expand All @@ -259,13 +314,7 @@ void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin,
{
myMaxLineEdit->setText( QString::number( theMax ) );
}

//automaticlly activate contrast enhancement algorithm if set to none
if ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementAlgorithmComboBox->setCurrentIndex(
mContrastEnhancementAlgorithmComboBox->findData( QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
mDisableMinMaxWidgetRefresh = false;
}

void QgsMultiBandColorRendererWidget::setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit )
Expand Down Expand Up @@ -300,9 +349,13 @@ void QgsMultiBandColorRendererWidget::setFromRenderer( const QgsRasterRenderer*
mGreenBandComboBox->setCurrentIndex( mGreenBandComboBox->findData( mbcr->greenBand() ) );
mBlueBandComboBox->setCurrentIndex( mBlueBandComboBox->findData( mbcr->blueBand() ) );

mDisableMinMaxWidgetRefresh = true;
setMinMaxValue( mbcr->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit );
setMinMaxValue( mbcr->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit );
setMinMaxValue( mbcr->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit );
mDisableMinMaxWidgetRefresh = false;

mMinMaxWidget->setFromMinMaxOrigin( mbcr->minMaxOrigin() );
}
else
{
Expand Down Expand Up @@ -356,6 +409,7 @@ QString QgsMultiBandColorRendererWidget::max( int index )

void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index )
{
mDisableMinMaxWidgetRefresh = true;
switch ( index )
{
case 0:
Expand All @@ -370,10 +424,12 @@ void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index )
default:
break;
}
mDisableMinMaxWidgetRefresh = false;
}

void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index )
{
mDisableMinMaxWidgetRefresh = true;
switch ( index )
{
case 0:
Expand All @@ -388,6 +444,7 @@ void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index )
default:
break;
}
mDisableMinMaxWidgetRefresh = false;
}

int QgsMultiBandColorRendererWidget::selectedBand( int index )
Expand Down
14 changes: 13 additions & 1 deletion src/gui/raster/qgsmultibandcolorrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,22 @@ class GUI_EXPORT QgsMultiBandColorRendererWidget: public QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 ) override;
void setMax( const QString& value, int index = 0 ) override;
int selectedBand( int index = 0 ) override;
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }

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:
//void on_mLoadPushButton_clicked();
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:
void createValidators();
Expand All @@ -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
void setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit );
QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;

void minMaxModified();
};

#endif // QGSMULTIBANDCOLORRENDERERWIDGET_H
185 changes: 136 additions & 49 deletions src/gui/raster/qgsrasterminmaxwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,23 @@
#include "qgsmapcanvas.h"
#include "qgsrasterrenderer.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 )
: QWidget( parent )
, mLayer( theLayer )
, mCanvas( nullptr )
, mLastRectangleValid( false )
{
QgsDebugMsg( "Entered." );
setupUi( this );

QSettings mySettings;

// 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() );
QgsRasterMinMaxOrigin defaultMinMaxOrigin;
setFromMinMaxOrigin( defaultMinMaxOrigin );
}

QgsRasterMinMaxWidget::~QgsRasterMinMaxWidget()
Expand All @@ -66,7 +58,8 @@ QgsMapCanvas* QgsRasterMinMaxWidget::mapCanvas()

QgsRectangle QgsRasterMinMaxWidget::extent()
{
if ( !cbxClipExtent->isChecked() )
const int nExtentIdx = mStatisticsExtentCombo->currentIndex();
if ( nExtentIdx != IDX_CURRENT_CANVAS && nExtentIdx != IDX_UPDATED_CANVAS )
return QgsRectangle();

if ( mLayer && mCanvas )
Expand All @@ -77,13 +70,126 @@ QgsRectangle QgsRasterMinMaxWidget::extent()
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." );

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 )
{
int origin = QgsRasterRenderer::MinMaxUnknown;
QgsDebugMsg( QString( "myBand = %1" ).arg( myBand ) );
if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() )
{
Expand All @@ -92,56 +198,37 @@ void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked()
double myMin = std::numeric_limits<double>::quiet_NaN();
double myMax = std::numeric_limits<double>::quiet_NaN();

QgsRectangle myExtent = extent(); // empty == full
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;
}

bool updateMinMax = false;
if ( mCumulativeCutRadioButton->isChecked() )
{
updateMinMax = true;
double myLower = mCumulativeCutLowerDoubleSpinBox->value() / 100.0;
double myUpper = mCumulativeCutUpperDoubleSpinBox->value() / 100.0;
mLayer->dataProvider()->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, myExtent, mySampleSize );
origin |= QgsRasterRenderer::MinMaxCumulativeCut;
}
else if ( mMinMaxRadioButton->isChecked() )
{
updateMinMax = true;
// TODO: consider provider minimum/maximumValue() (has to be defined well in povider)
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, myExtent, mySampleSize );
myMin = myRasterBandStats.minimumValue;
myMax = myRasterBandStats.maximumValue;
origin |= QgsRasterRenderer::MinMaxMinMax;
}
else if ( mStdDevRadioButton->isChecked() )
{
updateMinMax = true;
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, myExtent, mySampleSize );
double myStdDev = mStdDevSpinBox->value();
myMin = 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 );
}
51 changes: 47 additions & 4 deletions src/gui/raster/qgsrasterminmaxwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include "ui_qgsrasterminmaxwidgetbase.h"
#include "qgsrectangle.h"

#include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"

class QgsMapCanvas;
class QgsRasterLayer;

Expand Down Expand Up @@ -67,21 +71,60 @@ class GUI_EXPORT QgsRasterMinMaxWidget: public QWidget, private Ui::QgsRasterMin
//! Return the selected sample size.
int sampleSize() { return cboAccuracy->currentIndex() == 0 ? 250000 : 0; }

// Load programmaticaly with current values
void load() { on_mLoadPushButton_clicked(); }
//! \brief Set the "source" of min/max values.
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:
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:
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:
QgsRasterLayer* mLayer;
QList<int> mBands;
QgsRectangle mExtent;

QgsMapCanvas* mCanvas;

bool mLastRectangleValid;
QgsRectangle mLastRectangle;
QgsRasterMinMaxOrigin mLastMinMaxOrigin;
};

#endif // QGSRASTERMINMAXWIDGET_H
15 changes: 7 additions & 8 deletions src/gui/raster/qgsrasterrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
class QgsRasterLayer;
class QgsRasterRenderer;
class QgsMapCanvas;
class QgsRasterMinMaxWidget;

/** \ingroup gui
* \class QgsRasterRendererWidget
Expand All @@ -44,14 +45,6 @@ class GUI_EXPORT QgsRasterRendererWidget: public QWidget

virtual ~QgsRasterRendererWidget() {}

enum LoadMinMaxAlgo
{
Estimate,
Actual,
CurrentExtent,
CumulativeCut // 2 - 98% cumulative cut
};

virtual QgsRasterRenderer* renderer() = 0;

void setRasterLayer( QgsRasterLayer* layer ) { mRasterLayer = layer; }
Expand Down Expand Up @@ -80,6 +73,12 @@ class GUI_EXPORT QgsRasterRendererWidget: public QWidget
virtual void setStdDev( const QString& value ) { Q_UNUSED( value ); }
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:

/**
Expand Down
47 changes: 45 additions & 2 deletions src/gui/raster/qgsrendererrasterpropertieswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "qgsrasterresamplefilter.h"
#include "qgsbilinearrasterresampler.h"
#include "qgscubicrasterresampler.h"
#include "qgsmultibandcolorrenderer.h"
#include "qgssinglebandgrayrenderer.h"


static void _initRendererWidgetFunctions()
Expand Down Expand Up @@ -103,6 +105,8 @@ QgsRendererRasterPropertiesWidget::QgsRendererRasterPropertiesWidget( QgsMapLaye
// 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
syncToLayer( mRasterLayer );

connect( mRasterLayer, SIGNAL( styleChanged() ), this, SLOT( refreshAfterSyleChanged() ) );
}

QgsRendererRasterPropertiesWidget::~QgsRendererRasterPropertiesWidget()
Expand Down Expand Up @@ -130,14 +134,15 @@ void QgsRendererRasterPropertiesWidget::apply()
QgsRasterRendererWidget* rendererWidget = dynamic_cast<QgsRasterRendererWidget*>( stackedWidget->currentWidget() );
if ( rendererWidget )
{
rendererWidget->doComputations();

QgsRasterRenderer* newRenderer = rendererWidget->renderer();

// 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
QgsRasterRenderer* oldRenderer = mRasterLayer->renderer();
if ( oldRenderer )
newRenderer->copyCommonProperties( oldRenderer );

newRenderer->copyCommonProperties( oldRenderer, false );
mRasterLayer->setRenderer( newRenderer );
}

Expand Down Expand Up @@ -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() ) );
}
}
}
}
3 changes: 3 additions & 0 deletions src/gui/raster/qgsrendererrasterpropertieswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class GUI_EXPORT QgsRendererRasterPropertiesWidget : public QgsMapLayerConfigWid

//! Enable or disable colorize controls depending on checkbox
void toggleColorizeControls( bool colorizeEnabled );

void refreshAfterSyleChanged();

private:
void setRendererWidget( const QString& rendererName );

Expand Down
69 changes: 58 additions & 11 deletions src/gui/raster/qgssinglebandgrayrendererwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{
setupUi( this );

Expand All @@ -50,8 +51,11 @@ QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer
mMinMaxContainerWidget->setLayout( layout );
layout->addWidget( mMinMaxWidget );

connect( mMinMaxWidget, SIGNAL( load( int, double, double, int ) ),
this, SLOT( loadMinMax( int, double, double, int ) ) );
connect( mMinMaxWidget, &QgsRasterMinMaxWidget::widgetChanged,
this, &QgsSingleBandGrayRendererWidget::widgetChanged );

connect( mMinMaxWidget, &QgsRasterMinMaxWidget::load,
this, &QgsSingleBandGrayRendererWidget::loadMinMax );

//fill available bands into combo box
int nBands = provider->bandCount();
Expand Down Expand Up @@ -98,27 +102,57 @@ QgsRasterRenderer* QgsSingleBandGrayRendererWidget::renderer()
e->setMaximumValue( mMaxLineEdit->text().toDouble() );
e->setContrastEnhancementAlgorithm(( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementComboBox->currentData().toInt() ) );


QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( provider, band );
renderer->setContrastEnhancement( e );

renderer->setGradient(( QgsSingleBandGrayRenderer::Gradient ) mGradientComboBox->currentData().toInt() );
renderer->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );

return renderer;
}

void QgsSingleBandGrayRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
}

void QgsSingleBandGrayRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{
QgsRasterRendererWidget::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( theOrigin );

QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );

mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) )
{
mMinLineEdit->clear();
Expand All @@ -136,12 +170,7 @@ void QgsSingleBandGrayRendererWidget::loadMinMax( int theBandNo, double theMin,
{
mMaxLineEdit->setText( QString::number( theMax ) );
}

//automaticlly activate contrast enhancement algorithm if set to none
if ( mContrastEnhancementComboBox->currentData().toInt() == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementComboBox->setCurrentIndex( mContrastEnhancementComboBox->findData( QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
mDisableMinMaxWidgetRefresh = false;
}

void QgsSingleBandGrayRendererWidget::on_mGrayBandComboBox_currentIndexChanged( int index )
Expand All @@ -163,10 +192,28 @@ void QgsSingleBandGrayRendererWidget::setFromRenderer( const QgsRasterRenderer*

mGradientComboBox->setCurrentIndex( mGradientComboBox->findData( gr->gradient() ) );
//minmax
mDisableMinMaxWidgetRefresh = true;
mMinLineEdit->setText( QString::number( ce->minimumValue() ) );
mMaxLineEdit->setText( QString::number( ce->maximumValue() ) );
mDisableMinMaxWidgetRefresh = false;
//contrast enhancement algorithm
mContrastEnhancementComboBox->setCurrentIndex(
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;
}
14 changes: 11 additions & 3 deletions src/gui/raster/qgssinglebandgrayrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,26 @@ class GUI_EXPORT QgsSingleBandGrayRendererWidget: public QgsRasterRendererWidget

QString min( int index = 0 ) override { Q_UNUSED( index ); return mMinLineEdit->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 setMax( const QString& value, int index = 0 ) override { Q_UNUSED( index ); mMaxLineEdit->setText( value ); }
void setMin( const QString& value, int index = 0 ) override;
void setMax( const QString& value, int index = 0 ) override;
int selectedBand( int index = 0 ) override { Q_UNUSED( index ); return mGrayBandComboBox->currentIndex() + 1; }
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }

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:
void on_mGrayBandComboBox_currentIndexChanged( int index );
void on_mMinLineEdit_textChanged( const QString & );
void on_mMaxLineEdit_textChanged( const QString & );

private:
QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;

void minMaxModified();
};

#endif // QGSSINGLEBANDGRAYRENDERERWIDGET_H
63 changes: 46 additions & 17 deletions src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
, mMinMaxOrigin( 0 )
{
QSettings settings;
Expand Down Expand Up @@ -84,9 +85,12 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
layout->setContentsMargins( 0, 0, 0, 0 );
mMinMaxContainerWidget->setLayout( layout );
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
int nBands = provider->bandCount();
Expand All @@ -111,16 +115,20 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
// If there is currently no min/max, load default with user current default options
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 );

resetClassifyButton();

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( btnColorRamp, &QgsColorRampButton::colorRampChanged, this, &QgsSingleBandPseudoColorRendererWidget::applyColorRamp );
connect( mNumberOfEntriesSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( classify() ) );
Expand Down Expand Up @@ -175,10 +183,17 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRendererWidget::renderer()

renderer->setClassificationMin( lineEditValue( mMinLineEdit ) );
renderer->setClassificationMax( lineEditValue( mMaxLineEdit ) );
renderer->setClassificationMinMaxOrigin( mMinMaxOrigin );
renderer->setMinMaxOrigin( mMinMaxWidget->minMaxOrigin() );
return renderer;
}

void QgsSingleBandPseudoColorRendererWidget::doComputations()
{
mMinMaxWidget->doComputations();
if ( mColormapTreeWidget->topLevelItemCount() == 0 )
applyColorRamp();
}

void QgsSingleBandPseudoColorRendererWidget::setMapCanvas( QgsMapCanvas* canvas )
{
QgsRasterRendererWidget::setMapCanvas( canvas );
Expand Down Expand Up @@ -841,8 +856,8 @@ void QgsSingleBandPseudoColorRendererWidget::setFromRenderer( const QgsRasterRen
}
setLineEditValue( mMinLineEdit, pr->classificationMin() );
setLineEditValue( mMaxLineEdit, pr->classificationMax() );
mMinMaxOrigin = pr->classificationMinMaxOrigin();
showMinMaxOrigin();

mMinMaxWidget->setFromMinMaxOrigin( pr->minMaxOrigin() );
}
}

Expand Down Expand Up @@ -885,11 +900,12 @@ void QgsSingleBandPseudoColorRendererWidget::on_mColorInterpolationComboBox_curr
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 );
QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );

mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) )
{
mMinLineEdit->clear();
Expand All @@ -907,14 +923,7 @@ void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int theBandNo, double t
{
mMaxLineEdit->setText( QString::number( theMax ) );
}

mMinMaxOrigin = theOrigin;
showMinMaxOrigin();
}

void QgsSingleBandPseudoColorRendererWidget::showMinMaxOrigin()
{
mMinMaxOriginLabel->setText( QgsRasterRenderer::minMaxOriginLabel( mMinMaxOrigin ) );
mDisableMinMaxWidgetRefresh = false;
}

void QgsSingleBandPseudoColorRendererWidget::setLineEditValue( QLineEdit * theLineEdit, double theValue )
Expand Down Expand Up @@ -995,3 +1004,23 @@ void QgsSingleBandPseudoColorRendererWidget::changeTransparency()
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();
}
}
16 changes: 10 additions & 6 deletions src/gui/raster/qgssinglebandpseudocolorrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
static QgsRasterRendererWidget* create( QgsRasterLayer* layer, const QgsRectangle &theExtent ) { return new QgsSingleBandPseudoColorRendererWidget( layer, theExtent ); }
QgsRasterRenderer* renderer() override;
void setMapCanvas( QgsMapCanvas* canvas ) override;
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }

void setFromRenderer( const QgsRasterRenderer* r );

Expand All @@ -57,7 +59,8 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
/** Executes the single band pseudo raster classficiation
*/
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:

Expand Down Expand Up @@ -87,10 +90,10 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
void mColormapTreeWidget_itemEdited( QTreeWidgetItem* item, int column );
void on_mBandComboBox_currentIndexChanged( int index );
void on_mColorInterpolationComboBox_currentIndexChanged( int index );
void on_mMinLineEdit_textChanged( const QString & text ) { Q_UNUSED( text ); resetClassifyButton(); }
void on_mMaxLineEdit_textChanged( const QString & text ) { Q_UNUSED( text ); resetClassifyButton(); }
void on_mMinLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); }
void on_mMaxLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); }
void on_mMinLineEdit_textChanged( const QString & ) { resetClassifyButton(); }
void on_mMaxLineEdit_textChanged( const QString & ) { resetClassifyButton(); }
void on_mMinLineEdit_textEdited( const QString & text ) ;
void on_mMaxLineEdit_textEdited( const QString & text ) ;
void on_mClassificationModeComboBox_currentIndexChanged( int index );
void changeColor();
void changeTransparency();
Expand All @@ -100,10 +103,11 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
void setLineEditValue( QLineEdit *theLineEdit, double theValue );
double lineEditValue( const QLineEdit *theLineEdit ) const;
void resetClassifyButton();
void showMinMaxOrigin();
QgsRasterMinMaxWidget * mMinMaxWidget;
bool mDisableMinMaxWidgetRefresh;
int mMinMaxOrigin;

void minMaxModified();
};


Expand Down
2 changes: 1 addition & 1 deletion src/plugins/georeferencer/qgsgeorefplugingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ void QgsGeorefPluginGui::localHistogramStretch()
{
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();
}

Expand Down
234 changes: 92 additions & 142 deletions src/ui/qgsoptionsbase.ui

Large diffs are not rendered by default.

349 changes: 179 additions & 170 deletions src/ui/qgsrasterminmaxwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>316</width>
<height>300</height>
<width>324</width>
<height>250</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -45,202 +45,211 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="mCumulativeCutRadioButton">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QRadioButton" name="mUserDefinedRadioButton">
<property name="text">
<string>Cumulative
count cut</string>
<string>Use&amp;r defined</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
<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 row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QRadioButton" name="mCumulativeCutRadioButton">
<property name="text">
<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>
<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 row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QRadioButton" name="mStdDevRadioButton">
<property name="text">
<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>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<item row="2" column="0">
<widget class="QRadioButton" name="mMinMaxRadioButton">
<property name="text">
<string>Min / max</string>
<string>&amp;Min / max</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
<string notr="true">mMinMaxMethodRadioButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<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_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 row="6" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QComboBox" name="mStatisticsExtentCombo">
<item>
<property name="text">
<string>Whole raster</string>
</property>
</item>
<item>
<property name="text">
<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>
</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>
</widget>
</item>
</layout>
</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/>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup"/>
<buttongroup name="mMinMaxMethodRadioButtonGroup"/>
</buttongroups>
</ui>
Loading