QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsrasterminmaxwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterminmaxwidget.h
3  ---------------------------------
4  begin : July 2012
5  copyright : (C) 2012 by Radim Blazek
6  email : radim dot blazek at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <QSettings>
19 #include <QMessageBox>
20 
21 #include "qgsrasterlayer.h"
22 #include "qgsrasterminmaxwidget.h"
23 #include "qgsmapcanvas.h"
24 #include "qgsrasterrenderer.h"
25 #include "qgsrasterdataprovider.h"
26 #include "qgsrasterminmaxorigin.h"
27 #include "qgsdoublespinbox.h"
28 
29 const int IDX_WHOLE_RASTER = 0;
30 const int IDX_CURRENT_CANVAS = 1;
31 const int IDX_UPDATED_CANVAS = 2;
32 
34  : QWidget( parent )
35  , mLayer( layer )
36  , mLastRectangleValid( false )
37  , mBandsChanged( false )
38 {
39  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
40  setupUi( this );
41 
42  // use maximum value as a clear value for the upper border of the cumulative cut
43  mCumulativeCutUpperDoubleSpinBox->setClearValueMode( QgsDoubleSpinBox::MaximumValue );
44 
45  connect( mUserDefinedRadioButton, &QRadioButton::toggled, this, &QgsRasterMinMaxWidget::mUserDefinedRadioButton_toggled );
46  connect( mMinMaxRadioButton, &QRadioButton::toggled, this, &QgsRasterMinMaxWidget::mMinMaxRadioButton_toggled );
47  connect( mStdDevRadioButton, &QRadioButton::toggled, this, &QgsRasterMinMaxWidget::mStdDevRadioButton_toggled );
48  connect( mCumulativeCutRadioButton, &QRadioButton::toggled, this, &QgsRasterMinMaxWidget::mCumulativeCutRadioButton_toggled );
49  connect( mStatisticsExtentCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterMinMaxWidget::mStatisticsExtentCombo_currentIndexChanged );
50  connect( mCumulativeCutLowerDoubleSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsRasterMinMaxWidget::mCumulativeCutLowerDoubleSpinBox_valueChanged );
51  connect( mCumulativeCutUpperDoubleSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsRasterMinMaxWidget::mCumulativeCutUpperDoubleSpinBox_valueChanged );
52  connect( mStdDevSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsRasterMinMaxWidget::mStdDevSpinBox_valueChanged );
53  connect( cboAccuracy, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterMinMaxWidget::cboAccuracy_currentIndexChanged );
54 
55  const QgsRasterMinMaxOrigin defaultMinMaxOrigin;
56  setFromMinMaxOrigin( defaultMinMaxOrigin );
57 }
58 
60 {
61  mCanvas = canvas;
62 }
63 
65 {
66  return mCanvas;
67 }
68 
69 void QgsRasterMinMaxWidget::setBands( const QList<int> &bands )
70 {
71  mBandsChanged = bands != mBands;
72  mBands = bands;
73 }
74 
76 {
77  const int nExtentIdx = mStatisticsExtentCombo->currentIndex();
78  if ( nExtentIdx != IDX_CURRENT_CANVAS && nExtentIdx != IDX_UPDATED_CANVAS )
79  return QgsRectangle();
80 
81  if ( mLayer && mCanvas )
82  return mCanvas->mapSettings().outputExtentToLayerExtent( mLayer, mCanvas->extent() );
83  else if ( mCanvas )
84  return mCanvas->extent();
85  else
86  return QgsRectangle();
87 }
88 
90 {
91  mUserDefinedRadioButton->setChecked( true );
92  mStatisticsExtentCombo->setCurrentIndex( IDX_WHOLE_RASTER );
93 }
94 
95 void QgsRasterMinMaxWidget::mUserDefinedRadioButton_toggled( bool toggled )
96 {
97  mStatisticsExtentCombo->setEnabled( !toggled );
98  cboAccuracy->setEnabled( !toggled );
99  emit widgetChanged();
100 }
101 
103 {
104  switch ( minMaxOrigin.limits() )
105  {
107  mUserDefinedRadioButton->setChecked( true );
108  break;
109 
111  mMinMaxRadioButton->setChecked( true );
112  break;
113 
115  mStdDevRadioButton->setChecked( true );
116  break;
117 
119  mCumulativeCutRadioButton->setChecked( true );
120  break;
121  }
122 
123  switch ( minMaxOrigin.extent() )
124  {
126  mStatisticsExtentCombo->setCurrentIndex( IDX_WHOLE_RASTER );
127  break;
128 
130  mStatisticsExtentCombo->setCurrentIndex( IDX_CURRENT_CANVAS );
131  break;
132 
134  mStatisticsExtentCombo->setCurrentIndex( IDX_UPDATED_CANVAS );
135  break;
136  }
137 
138  mCumulativeCutLowerDoubleSpinBox->setValue( 100.0 * minMaxOrigin.cumulativeCutLower() );
139  mCumulativeCutUpperDoubleSpinBox->setValue( 100.0 * minMaxOrigin.cumulativeCutUpper() );
140  mStdDevSpinBox->setValue( minMaxOrigin.stdDevFactor() );
141 
142  cboAccuracy->setCurrentIndex( minMaxOrigin.statAccuracy() == QgsRasterMinMaxOrigin::Estimated ? 0 : 1 );
143 }
144 
146 {
148 
149  if ( mMinMaxRadioButton->isChecked() )
151  else if ( mStdDevRadioButton->isChecked() )
153  else if ( mCumulativeCutRadioButton->isChecked() )
155  else
157 
158  switch ( mStatisticsExtentCombo->currentIndex() )
159  {
160  case IDX_WHOLE_RASTER:
161  default:
163  break;
164  case IDX_CURRENT_CANVAS:
166  break;
167  case IDX_UPDATED_CANVAS:
169  break;
170  }
171 
172  if ( cboAccuracy->currentIndex() == 0 )
174  else
176 
178  mCumulativeCutLowerDoubleSpinBox->value() / 100.0 );
180  mCumulativeCutUpperDoubleSpinBox->value() / 100.0 );
181  minMaxOrigin.setStdDevFactor( mStdDevSpinBox->value() );
182 
183  return minMaxOrigin;
184 }
185 
187 {
188  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
189  if ( !mLayer->dataProvider() )
190  return;
191 
192  const QgsRectangle myExtent = extent(); // empty == full
193  const int mySampleSize = sampleSize(); // 0 == exact
194 
195  const QgsRasterMinMaxOrigin newMinMaxOrigin = minMaxOrigin();
196  if ( mLastRectangleValid && mLastRectangle == myExtent &&
197  mLastMinMaxOrigin == newMinMaxOrigin &&
198  !mBandsChanged )
199  {
200  QgsDebugMsg( QStringLiteral( "Does not need to redo statistics computations" ) );
201  return;
202  }
203 
204  mLastRectangleValid = true;
205  mLastRectangle = myExtent;
206  mLastMinMaxOrigin = newMinMaxOrigin;
207  mBandsChanged = false;
208 
209  const auto constMBands = mBands;
210  for ( const int myBand : constMBands )
211  {
212  QgsDebugMsg( QStringLiteral( "myBand = %1" ).arg( myBand ) );
213  if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() )
214  {
215  continue;
216  }
217  double myMin = std::numeric_limits<double>::quiet_NaN();
218  double myMax = std::numeric_limits<double>::quiet_NaN();
219 
220  bool updateMinMax = false;
221  if ( mCumulativeCutRadioButton->isChecked() )
222  {
223  updateMinMax = true;
224  const double myLower = mCumulativeCutLowerDoubleSpinBox->value() / 100.0;
225  const double myUpper = mCumulativeCutUpperDoubleSpinBox->value() / 100.0;
226  mLayer->dataProvider()->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, myExtent, mySampleSize );
227  }
228  else if ( mMinMaxRadioButton->isChecked() )
229  {
230  updateMinMax = true;
231  // TODO: consider provider minimum/maximumValue() (has to be defined well in povider)
232  const QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, myExtent, mySampleSize );
233  myMin = myRasterBandStats.minimumValue;
234  myMax = myRasterBandStats.maximumValue;
235  }
236  else if ( mStdDevRadioButton->isChecked() )
237  {
238  updateMinMax = true;
239  const QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, myExtent, mySampleSize );
240  const double myStdDev = mStdDevSpinBox->value();
241  myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
242  myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
243  }
244 
245  if ( updateMinMax )
246  emit load( myBand, myMin, myMax );
247  }
248 }
249 
251 {
252  mStatisticsExtentCombo->removeItem( IDX_UPDATED_CANVAS );
253 }
@ MaximumValue
Reset value to maximum()
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:88
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
QgsRectangle outputExtentToLayerExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from output CRS to layer's CRS
The RasterBandStats struct is a container for statistics about a single raster band.
double mean
The mean cell value for the band. NO_DATA values are excluded.
double stdDev
The standard deviation of the cell values.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
virtual void cumulativeCut(int bandNo, double lowerCount, double upperCount, double &lowerValue, double &upperValue, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0)
Find values for cumulative pixel count cut.
virtual int bandCount() const =0
Gets number of bands.
virtual QgsRasterBandStats bandStatistics(int bandNo, int stats=QgsRasterBandStats::All, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
This class describes the origin of min/max values.
void setExtent(QgsRasterMinMaxOrigin::Extent extent)
Sets the extent.
QgsRasterMinMaxOrigin::StatAccuracy statAccuracy() const
Returns the raster statistic accuracy.
double cumulativeCutLower() const
Returns the lower bound of cumulative cut method (between 0 and 1).
@ Exact
Exact statistics.
@ Estimated
Approximated statistics.
QgsRasterMinMaxOrigin::Limits limits() const
Returns the raster limits.
double stdDevFactor() const
Returns the factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ].
void setLimits(QgsRasterMinMaxOrigin::Limits limits)
Sets the limits.
void setStatAccuracy(QgsRasterMinMaxOrigin::StatAccuracy accuracy)
Sets the statistics accuracy.
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
@ CurrentCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
@ WholeRaster
Whole raster is used to compute statistics.
void setCumulativeCutUpper(double val)
Sets the upper bound of cumulative cut method (between 0 and 1).
void setStdDevFactor(double val)
Sets the factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ].
double cumulativeCutUpper() const
Returns the upper bound of cumulative cut method (between 0 and 1).
void setCumulativeCutLower(double val)
Sets the lower bound of cumulative cut method (between 0 and 1).
@ StdDev
Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ].
@ MinMax
Real min-max values.
@ CumulativeCut
Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ].
QgsRasterMinMaxOrigin::Extent extent() const
Returns the raster extent.
QgsRectangle extent()
Returns the extent selected by the user.
QgsRasterMinMaxWidget(QgsRasterLayer *layer, QWidget *parent=nullptr)
Constructor for QgsRasterMinMaxWidget.
void doComputations()
Load programmatically with current values.
QgsMapCanvas * mapCanvas()
Returns the map canvas associated with the widget.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void load(int bandNo, double min, double max)
signal emitted when new min/max values are computed from statistics.
void setFromMinMaxOrigin(const QgsRasterMinMaxOrigin &)
Sets the "source" of min/max values.
int sampleSize()
Returns the selected sample size.
void setBands(const QList< int > &bands)
void hideUpdatedExtent()
Hide updated extent choice.
QgsRasterMinMaxOrigin minMaxOrigin()
Returns a QgsRasterMinMaxOrigin object with the widget values.
void widgetChanged()
Emitted when something on the widget has changed.
void userHasSetManualMinMaxValues()
Uncheck cumulative cut, min/max, std-dev radio buttons.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const int IDX_CURRENT_CANVAS
const int IDX_WHOLE_RASTER
const int IDX_UPDATED_CANVAS