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.
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}
-----------------
@ -1343,13 +1351,18 @@ QgsRasterLayer {#qgis_api_break_3_0_QgsRasterLayer}
- setDrawingStyle() was removed. Use setRendererForDrawingStyle() or setRenderer() instead.
- previewAsPixmap() was removed. Use previewAsImage() instead.
- 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}
------------------
- 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}
-----------
@ -1430,6 +1443,12 @@ QgsSimpleMarkerSymbolLayerWidget {#qgis_api_break_3_0_QgsSimpleMarkerSymb
- 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}
-----------------------------

View File

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

View File

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

View File

@ -10,11 +10,6 @@ class QgsRasterLayer : QgsMapLayer
%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 sample size (number of pixels) for estimated statistics/histogram calculation */
static const double SAMPLE_SIZE;
@ -165,7 +160,7 @@ class QgsRasterLayer : QgsMapLayer
void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax,
QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax,
const QgsRectangle& theExtent = QgsRectangle(),
int theSampleSize = QgsRasterLayer::SAMPLE_SIZE,
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
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;
@ -60,14 +44,16 @@ class QgsRasterRenderer : 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;
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;
//! Sets origin of min/max values
void setMinMaxOrigin( const QgsRasterMinMaxOrigin& theOrigin );
protected:

View File

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

View File

@ -19,7 +19,8 @@ class QgsMultiBandColorRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 );
void doComputations();
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. */
int sampleSize();
// Load programmaticaly with current values
void load();
//! \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 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:
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 );
virtual ~QgsRasterRendererWidget();
enum LoadMinMaxAlgo
{
Estimate,
Actual,
CurrentExtent,
CumulativeCut // 2 - 98% cumulative cut
};
virtual QgsRasterRenderer* renderer() = 0 /Factory/;
void setRasterLayer( QgsRasterLayer* layer );
@ -42,6 +34,8 @@ class QgsRasterRendererWidget: QWidget
virtual QString stdDev();
virtual void setStdDev( const QString& value );
virtual int selectedBand( int index = 0 );
virtual void doComputations();
virtual QgsRasterMinMaxWidget* minMaxWidget();
signals:
/**

View File

@ -19,7 +19,8 @@ class QgsSingleBandGrayRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 );
void doComputations();
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 doComputations();
public slots:
/** Executes the single band pseudo raster classficiation
*/
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 );
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();
@ -9176,25 +9174,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();

View File

@ -125,6 +125,7 @@ class QgsDiagramProperties;
#include "qgsmimedatautils.h"
#include "qgswelcomepageitemsmodel.h"
#include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"
#include "ui_qgisapp.h"
@ -1526,7 +1527,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 );

View File

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

View File

@ -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"
@ -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();
@ -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() );
@ -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" );
//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 contrastEnchacement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastEnchacement ) );
QString contrastEnhancement = mSettings->value( "/Raster/defaultContrastEnhancementAlgorithm/" + name, defaultVal ).toString();
cbox->setCurrentIndex( cbox->findData( contrastEnhancement ) );
}
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 );
}
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();

View File

@ -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;

View File

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

View File

@ -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
@ -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

View File

@ -32,6 +32,15 @@
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) { \
QGSCOMPARENEAR( point1.x(), point2.x(), 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 "qgis.h"
#include "qgsraster.h"
class QgsContrastEnhancementFunction;
class QDomDocument;
@ -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
@ -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
@ -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();

View File

@ -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 )

View File

@ -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
{
@ -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

View File

@ -78,10 +78,22 @@ typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QStrin
#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 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()
: QgsMapLayer( RasterLayer )
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
@ -835,30 +847,86 @@ void QgsRasterLayer::closeDataProvider()
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 );
if ( !mPipe.renderer() || !mDataProvider )
if ( !rasterRenderer || !mDataProvider )
{
return;
}
QList<int> myBands;
QList<QgsContrastEnhancement*> myEnhancements;
QgsRasterMinMaxOrigin myMinMaxOrigin;
QgsRasterRenderer* myRasterRenderer = nullptr;
QgsSingleBandGrayRenderer* myGrayRenderer = nullptr;
QgsMultiBandColorRenderer* myMultiBandRenderer = nullptr;
QString rendererType = mPipe.renderer()->type();
QString rendererType = rasterRenderer->type();
if ( rendererType == QLatin1String( "singlebandgray" ) )
{
myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() );
myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( rasterRenderer );
if ( !myGrayRenderer ) return;
myBands << myGrayRenderer->grayBand();
myRasterRenderer = myGrayRenderer;
myMinMaxOrigin = myGrayRenderer->minMaxOrigin();
}
else if ( rendererType == QLatin1String( "multibandcolor" ) )
{
myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() );
myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( rasterRenderer );
if ( !myMultiBandRenderer ) return;
myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand();
myRasterRenderer = myMultiBandRenderer;
myMinMaxOrigin = myMultiBandRenderer->minMaxOrigin();
}
Q_FOREACH ( int myBand, myBands )
@ -869,34 +937,12 @@ void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnh
QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement( static_cast< Qgis::DataType >( myType ) );
myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag );
double myMin = std::numeric_limits<double>::quiet_NaN();
double myMax = std::numeric_limits<double>::quiet_NaN();
double min;
double max;
computeMinMax( myBand, myMinMaxOrigin, theLimits, theExtent, theSampleSize, min, max );
if ( theLimits == QgsRaster::ContrastEnhancementMinMax )
{
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 );
myEnhancement->setMinimumValue( min );
myEnhancement->setMaximumValue( max );
myEnhancements.append( myEnhancement );
}
else
@ -919,57 +965,208 @@ void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnh
//delete all remaining unused enhancements
qDeleteAll( myEnhancements );
emit repaintRequested();
emit styleChanged();
myMinMaxOrigin.setLimits( theLimits );
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()
{
QgsDebugMsgLevel( "Entered", 4 );
QSettings mySettings;
QString myKey;
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 );
QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm;
QgsRasterMinMaxOrigin::Limits myLimits;
defaultContrastEnhancementSettings( myAlgorithm, myLimits );
setContrastEnhancement( myAlgorithm, myLimits );
}

View File

@ -33,6 +33,7 @@
#include "qgsraster.h"
#include "qgsrasterpipe.h"
#include "qgsrasterviewport.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"
class QgsMapToPixel;
@ -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();
@ -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();
@ -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;
@ -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

View File

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

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 );
}
QDomElement minMaxOriginElem = doc.createElement( QStringLiteral( "minMaxOrigin" ) );
mMinMaxOrigin.writeXml( doc, minMaxOriginElem );
rasterRendererElem.appendChild( minMaxOriginElem );
}
void QgsRasterRenderer::readXml( const QDomElement& rendererElem )
@ -132,9 +136,15 @@ 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;
@ -142,150 +152,6 @@ void QgsRasterRenderer::copyCommonProperties( const QgsRasterRenderer* other )
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() );
}

View File

@ -21,6 +21,7 @@
#include <QPair>
#include "qgsrasterinterface.h"
#include "qgsrasterminmaxorigin.h"
class QDomElement;
@ -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;
@ -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:
@ -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& );

View File

@ -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 )
{
}
@ -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;
}
@ -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 );
}

View File

@ -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;
@ -77,8 +75,6 @@ class CORE_EXPORT QgsSingleBandPseudoColorRenderer: public QgsRasterRenderer
double mClassificationMin;
double mClassificationMax;
int mClassificationMinMaxOrigin;
QgsSingleBandPseudoColorRenderer( const QgsSingleBandPseudoColorRenderer& );
const QgsSingleBandPseudoColorRenderer& operator=( const QgsSingleBandPseudoColorRenderer& );
};

View File

@ -24,6 +24,7 @@
QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{
setupUi( this );
createValidators();
@ -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 ) ) );
@ -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 );
@ -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;
@ -242,6 +296,7 @@ void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin,
return;
}
mDisableMinMaxWidgetRefresh = true;
if ( qIsNaN( theMin ) )
{
myMinLineEdit->clear();
@ -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 )
@ -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
{
@ -356,6 +409,7 @@ QString QgsMultiBandColorRendererWidget::max( int index )
void QgsMultiBandColorRendererWidget::setMin( const QString& value, int index )
{
mDisableMinMaxWidgetRefresh = true;
switch ( index )
{
case 0:
@ -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:
@ -388,6 +444,7 @@ void QgsMultiBandColorRendererWidget::setMax( const QString& value, int index )
default:
break;
}
mDisableMinMaxWidgetRefresh = false;
}
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 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();
@ -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

View File

@ -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()
@ -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 )
@ -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() )
{
@ -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 );
}

View File

@ -21,6 +21,10 @@
#include "ui_qgsrasterminmaxwidgetbase.h"
#include "qgsrectangle.h"
#include "qgsraster.h"
#include "qgsrasterminmaxorigin.h"
#include "qgscontrastenhancement.h"
class QgsMapCanvas;
class QgsRasterLayer;
@ -67,14 +71,49 @@ 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;
@ -82,6 +121,10 @@ class GUI_EXPORT QgsRasterMinMaxWidget: public QWidget, private Ui::QgsRasterMin
QgsRectangle mExtent;
QgsMapCanvas* mCanvas;
bool mLastRectangleValid;
QgsRectangle mLastRectangle;
QgsRasterMinMaxOrigin mLastMinMaxOrigin;
};
#endif // QGSRASTERMINMAXWIDGET_H

View File

@ -25,6 +25,7 @@
class QgsRasterLayer;
class QgsRasterRenderer;
class QgsMapCanvas;
class QgsRasterMinMaxWidget;
/** \ingroup gui
* \class QgsRasterRendererWidget
@ -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; }
@ -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:
/**

View File

@ -29,6 +29,8 @@
#include "qgsrasterresamplefilter.h"
#include "qgsbilinearrasterresampler.h"
#include "qgscubicrasterresampler.h"
#include "qgsmultibandcolorrenderer.h"
#include "qgssinglebandgrayrenderer.h"
static void _initRendererWidgetFunctions()
@ -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()
@ -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 );
}
@ -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
void toggleColorizeControls( bool colorizeEnabled );
void refreshAfterSyleChanged();
private:
void setRendererWidget( const QString& rendererName );

View File

@ -24,6 +24,7 @@
QgsSingleBandGrayRendererWidget::QgsSingleBandGrayRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
{
setupUi( this );
@ -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();
@ -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();
@ -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 )
@ -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;
}

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 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

View File

@ -42,6 +42,7 @@
QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent )
: QgsRasterRendererWidget( layer, extent )
, mMinMaxWidget( nullptr )
, mDisableMinMaxWidgetRefresh( false )
, mMinMaxOrigin( 0 )
{
QSettings settings;
@ -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();
@ -111,7 +115,13 @@ 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 );
@ -119,8 +129,6 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
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() ) );
@ -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 );
@ -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() );
}
}
@ -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();
@ -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 )
@ -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();
}
}

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 ); }
QgsRasterRenderer* renderer() override;
void setMapCanvas( QgsMapCanvas* canvas ) override;
void doComputations() override;
QgsRasterMinMaxWidget* minMaxWidget() override { return mMinMaxWidget; }
void setFromRenderer( const QgsRasterRenderer* r );
@ -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:
@ -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();
@ -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();
};

View File

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

View File

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

View File

@ -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">
@ -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 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>
<widget class="QLabel" name="label">
<property name="text">
<string>-</string>
</property>
</widget>
<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>
<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_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>
<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 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_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>
</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>

View File

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

View File

@ -45,6 +45,7 @@
//qgis unit test includes
#include <qgsrenderchecker.h>
#include "qgstestutils.h"
/** \ingroup UnitTests
* This is a unit test for the QgsRasterLayer class.
@ -90,6 +91,7 @@ class TestQgsRasterLayer : public QObject
void multiBandColorRenderer();
void setRenderer();
void regression992(); //test for issue #992 - GeoJP2 images improperly displayed as all black
void testRefreshRendererIfNeeded();
private:
@ -206,7 +208,7 @@ void TestQgsRasterLayer::cleanupTestCase()
void TestQgsRasterLayer::isValid()
{
QVERIFY( mpRasterLayer->isValid() );
mpRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax );
mpRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setExtent( mpRasterLayer->extent() );
QVERIFY( render( "raster" ) );
}
@ -355,7 +357,7 @@ void TestQgsRasterLayer::colorRamp4()
void TestQgsRasterLayer::landsatBasic()
{
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->setExtent( mpLandsatRasterLayer->extent() );
QVERIFY( render( "landsat_basic" ) );
@ -632,7 +634,7 @@ void TestQgsRasterLayer::transparency()
QVERIFY( mpFloat32RasterLayer->isValid() );
QgsSingleBandGrayRenderer* renderer = new QgsSingleBandGrayRenderer( mpRasterLayer->dataProvider(), 1 );
mpFloat32RasterLayer->setRenderer( renderer );
mpFloat32RasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRaster::ContrastEnhancementMinMax );
mpFloat32RasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
qDebug( "contrastEnhancement.minimumValue = %.17g", renderer->contrastEnhancement()->minimumValue() );
qDebug( "contrastEnhancement.maximumValue = %.17g", renderer->contrastEnhancement()->maximumValue() );
@ -695,5 +697,31 @@ void TestQgsRasterLayer::regression992()
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 )
#include "testqgsrasterlayer.moc"

View File

@ -19,6 +19,7 @@ import os
from qgis.PyQt.QtCore import QFileInfo
from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import (QgsRaster,
QgsRasterLayer,
@ -27,6 +28,7 @@ from qgis.core import (QgsRaster,
QgsProject,
QgsMapSettings,
QgsPoint,
QgsRasterMinMaxOrigin,
QgsRasterShader,
QgsRasterTransparency,
QgsRenderChecker,
@ -89,7 +91,7 @@ class TestQgsRasterLayer(unittest.TestCase):
myRasterLayer.setRenderer(renderer)
myRasterLayer.setContrastEnhancement(
QgsContrastEnhancement.StretchToMinimumMaximum,
QgsRaster.ContrastEnhancementMinMax)
QgsRasterMinMaxOrigin.MinMax)
myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement()
# print ("myContrastEnhancement.minimumValue = %.17g" %
@ -229,5 +231,62 @@ class TestQgsRasterLayer(unittest.TestCase):
assert self.rendererChanged
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__':
unittest.main()