QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsrasterhistogramwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterhistogramwidget.cpp
3  ---------------------------
4  begin : July 2012
5  copyright : (C) 2012 by Etienne Tourigny
6  email : etourigny dot dev 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 "qgsapplication.h"
19 #include "qgsguiutils.h"
23 #include "qgsrasterminmaxwidget.h"
24 #include "qgsrasterdataprovider.h"
25 #include "qgssettings.h"
26 
27 #include <QMenu>
28 #include <QFileInfo>
29 #include <QDir>
30 #include <QPainter>
31 
32 // QWT Charting widget
33 #include <qwt_global.h>
34 #include <qwt_plot_canvas.h>
35 #include <qwt_legend.h>
36 #include <qwt_plot.h>
37 #include <qwt_plot_curve.h>
38 #include <qwt_plot_grid.h>
39 #include <qwt_plot_marker.h>
40 #include <qwt_plot_picker.h>
41 #include <qwt_picker_machine.h>
42 #include <qwt_plot_zoomer.h>
43 #include <qwt_plot_layout.h>
44 #include <qwt_plot_renderer.h>
45 #include <qwt_plot_histogram.h>
46 
47 #ifdef Q_OS_WIN
48 #include <time.h>
49 #endif
50 
51 // this has been removed, now we let the provider/raster interface decide
52 // how many bins are suitable depending on data type and range
53 //#define RASTER_HISTOGRAM_BINS 256
54 
56  : QgsMapLayerConfigWidget( lyr, nullptr, parent )
57  , mRasterLayer( lyr )
58 
59 {
60  setupUi( this );
61  connect( mSaveAsImageButton, &QToolButton::clicked, this, &QgsRasterHistogramWidget::mSaveAsImageButton_clicked );
62  connect( cboHistoBand, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged );
63  connect( btnHistoMin, &QToolButton::toggled, this, &QgsRasterHistogramWidget::btnHistoMin_toggled );
64  connect( btnHistoMax, &QToolButton::toggled, this, &QgsRasterHistogramWidget::btnHistoMax_toggled );
65  connect( btnHistoCompute, &QPushButton::clicked, this, &QgsRasterHistogramWidget::btnHistoCompute_clicked );
66 
67  mSaveAsImageButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileSave.svg" ) ) );
68 
69  mRendererWidget = nullptr;
70  mRendererName = QStringLiteral( "singlebandgray" );
71 
72  mHistoMin = 0;
73  mHistoMax = 0;
74 
75  mHistoPicker = nullptr;
76  mHistoZoomer = nullptr;
77  mHistoMarkerMin = nullptr;
78  mHistoMarkerMax = nullptr;
79 
80  QgsSettings settings;
81  mHistoShowMarkers = settings.value( QStringLiteral( "Raster/histogram/showMarkers" ), false ).toBool();
82  // mHistoLoadApplyAll = settings.value( "/Raster/histogram/loadApplyAll", false ).toBool();
83  mHistoZoomToMinMax = settings.value( QStringLiteral( "Raster/histogram/zoomToMinMax" ), false ).toBool();
84  mHistoUpdateStyleToMinMax = settings.value( QStringLiteral( "Raster/histogram/updateStyleToMinMax" ), true ).toBool();
85  mHistoDrawLines = settings.value( QStringLiteral( "Raster/histogram/drawLines" ), true ).toBool();
86  // mHistoShowBands = (HistoShowBands) settings.value( "/Raster/histogram/showBands", (int) ShowAll ).toInt();
87  mHistoShowBands = ShowAll;
88 
89  bool isInt = true;
90  if ( true )
91  {
92  //band selector
93  int myBandCountInt = mRasterLayer->bandCount();
94  for ( int myIteratorInt = 1;
95  myIteratorInt <= myBandCountInt;
96  ++myIteratorInt )
97  {
98  cboHistoBand->addItem( mRasterLayer->bandName( myIteratorInt ) );
99  Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( myIteratorInt );
100  if ( !( mySrcDataType == Qgis::Byte ||
101  mySrcDataType == Qgis::Int16 || mySrcDataType == Qgis::Int32 ||
102  mySrcDataType == Qgis::UInt16 || mySrcDataType == Qgis::UInt32 ) )
103  isInt = false;
104  }
105 
106  // histo min/max selectors
107  leHistoMin->setValidator( new QDoubleValidator( this ) );
108  leHistoMax->setValidator( new QDoubleValidator( this ) );
109  // this might generate many refresh events! test..
110  // connect( leHistoMin, SIGNAL( textChanged( const QString & ) ), this, SLOT( updateHistoMarkers() ) );
111  // connect( leHistoMax, SIGNAL( textChanged( const QString & ) ), this, SLOT( updateHistoMarkers() ) );
112  // connect( leHistoMin, SIGNAL( textChanged( const QString & ) ), this, SLOT( applyHistoMin() ) );
113  // connect( leHistoMax, SIGNAL( textChanged( const QString & ) ), this, SLOT( applyHistoMax() ) );
114  connect( leHistoMin, &QLineEdit::editingFinished, this, &QgsRasterHistogramWidget::applyHistoMin );
115  connect( leHistoMax, &QLineEdit::editingFinished, this, &QgsRasterHistogramWidget::applyHistoMax );
116 
117  // histo actions
118  // TODO move/add options to qgis options dialog
119  QMenu *menu = new QMenu( this );
120  menu->setSeparatorsCollapsible( false );
121  btnHistoActions->setMenu( menu );
122  QActionGroup *group = nullptr;
123  QAction *action = nullptr;
124 
125  // min/max options
126  group = new QActionGroup( this );
127  group->setExclusive( false );
128  connect( group, &QActionGroup::triggered, this, &QgsRasterHistogramWidget::histoActionTriggered );
129  action = new QAction( tr( "Min/Max options" ), group );
130  action->setSeparator( true );
131  menu->addAction( action );
132  action = new QAction( tr( "Always show min/max markers" ), group );
133  action->setData( QVariant( "Show markers" ) );
134  action->setCheckable( true );
135  action->setChecked( mHistoShowMarkers );
136  menu->addAction( action );
137  action = new QAction( tr( "Zoom to min/max" ), group );
138  action->setData( QVariant( "Zoom min_max" ) );
139  action->setCheckable( true );
140  action->setChecked( mHistoZoomToMinMax );
141  menu->addAction( action );
142  action = new QAction( tr( "Update style to min/max" ), group );
143  action->setData( QVariant( "Update min_max" ) );
144  action->setCheckable( true );
145  action->setChecked( mHistoUpdateStyleToMinMax );
146  menu->addAction( action );
147 
148  // visibility options
149  group = new QActionGroup( this );
150  group->setExclusive( false );
151  connect( group, &QActionGroup::triggered, this, &QgsRasterHistogramWidget::histoActionTriggered );
152  action = new QAction( tr( "Visibility" ), group );
153  action->setSeparator( true );
154  menu->addAction( action );
155  group = new QActionGroup( this );
156  group->setExclusive( true ); // these options are exclusive
157  connect( group, &QActionGroup::triggered, this, &QgsRasterHistogramWidget::histoActionTriggered );
158  action = new QAction( tr( "Show all bands" ), group );
159  action->setData( QVariant( "Show all" ) );
160  action->setCheckable( true );
161  action->setChecked( mHistoShowBands == ShowAll );
162  menu->addAction( action );
163  action = new QAction( tr( "Show RGB/Gray band(s)" ), group );
164  action->setData( QVariant( "Show RGB" ) );
165  action->setCheckable( true );
166  action->setChecked( mHistoShowBands == ShowRGB );
167  menu->addAction( action );
168  action = new QAction( tr( "Show selected band" ), group );
169  action->setData( QVariant( "Show selected" ) );
170  action->setCheckable( true );
171  action->setChecked( mHistoShowBands == ShowSelected );
172  menu->addAction( action );
173 
174  // display options
175  group = new QActionGroup( this );
176  group->setExclusive( false );
177  connect( group, &QActionGroup::triggered, this, &QgsRasterHistogramWidget::histoActionTriggered );
178  action = new QAction( tr( "Display" ), group );
179  action->setSeparator( true );
180  menu->addAction( action );
181  // should we plot as histogram instead of line plot? (int data only)
182  action = new QAction( QString(), group );
183  action->setData( QVariant( "Draw lines" ) );
184  if ( isInt )
185  {
186  action->setText( tr( "Draw as lines" ) );
187  action->setCheckable( true );
188  action->setChecked( mHistoDrawLines );
189  }
190  else
191  {
192  action->setText( tr( "Draw as lines (only int layers)" ) );
193  action->setEnabled( false );
194  }
195  menu->addAction( action );
196 
197  // actions
198  action = new QAction( tr( "Actions" ), group );
199  action->setSeparator( true );
200  menu->addAction( action );
201 
202  // load actions
203  group = new QActionGroup( this );
204  group->setExclusive( false );
205  connect( group, &QActionGroup::triggered, this, &QgsRasterHistogramWidget::histoActionTriggered );
206  action = new QAction( tr( "Reset" ), group );
207  action->setData( QVariant( "Load reset" ) );
208  menu->addAction( action );
209 
210  // these actions have been disabled for api cleanup, restore them eventually
211  // TODO restore these in qgis 2.4
212 #if 0
213  // Load min/max needs 3 params (method, extent, accuracy), cannot put it in single item
214  action = new QAction( tr( "Load min/max" ), group );
215  action->setSeparator( true );
216  menu->addAction( action );
217  action = new QAction( tr( "Estimate (faster)" ), group );
218  action->setData( QVariant( "Load estimate" ) );
219  menu->addAction( action );
220  action = new QAction( tr( "Actual (slower)" ), group );
221  action->setData( QVariant( "Load actual" ) );
222  menu->addAction( action );
223  action = new QAction( tr( "Current extent" ), group );
224  action->setData( QVariant( "Load extent" ) );
225  menu->addAction( action );
226  action = new QAction( tr( "Use stddev (1.0)" ), group );
227  action->setData( QVariant( "Load 1 stddev" ) );
228  menu->addAction( action );
229  action = new QAction( tr( "Use stddev (custom)" ), group );
230  action->setData( QVariant( "Load stddev" ) );
231  menu->addAction( action );
232  action = new QAction( tr( "Load for each band" ), group );
233  action->setData( QVariant( "Load apply all" ) );
234  action->setCheckable( true );
235  action->setChecked( mHistoLoadApplyAll );
236  menu->addAction( action );
237 #endif
238 
239  //others
240  action = new QAction( tr( "Recompute Histogram" ), group );
241  action->setData( QVariant( "Compute histogram" ) );
242  menu->addAction( action );
243 
244  }
245 
246 } // QgsRasterHistogramWidget ctor
247 
248 void QgsRasterHistogramWidget::setRendererWidget( const QString &name, QgsRasterRendererWidget *rendererWidget )
249 {
250  mRendererName = name;
251  mRendererWidget = rendererWidget;
253  cboHistoBand_currentIndexChanged( -1 );
254 }
255 
256 void QgsRasterHistogramWidget::setActive( bool activeFlag )
257 {
258  if ( activeFlag )
259  {
261  cboHistoBand_currentIndexChanged( -1 );
262  }
263  else
264  {
265  if ( QApplication::overrideCursor() )
266  QApplication::restoreOverrideCursor();
267  btnHistoMin->setChecked( false );
268  btnHistoMax->setChecked( false );
269  }
270 }
271 
272 void QgsRasterHistogramWidget::btnHistoCompute_clicked()
273 {
274 // Histogram computation can be called either by clicking the "Compute Histogram" button
275 // which is only visible if there is no cached histogram or by calling the
276 // "Compute Histogram" action. Due to limitations in the gdal api, it is not possible
277 // to re-calculate the histogram if it has already been calculated
278  computeHistogram( true );
280 }
281 
282 bool QgsRasterHistogramWidget::computeHistogram( bool forceComputeFlag )
283 {
284 
285  //bool myIgnoreOutOfRangeFlag = true;
286  //bool myThoroughBandScanFlag = false;
287  int myBandCountInt = mRasterLayer->bandCount();
288 
289  // if forceComputeFlag = false make sure raster has cached histogram, else return false
290  if ( ! forceComputeFlag )
291  {
292  for ( int myIteratorInt = 1;
293  myIteratorInt <= myBandCountInt;
294  ++myIteratorInt )
295  {
296  int sampleSize = 250000; // number of sample cells
297  if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize ) )
298  {
299  QgsDebugMsg( QStringLiteral( "band %1 does not have cached histo" ).arg( myIteratorInt ) );
300  return false;
301  }
302  }
303  }
304 
305  // compute histogram
306  stackedWidget2->setCurrentIndex( 1 );
307 
308  std::unique_ptr< QgsRasterBlockFeedback > feedback( new QgsRasterBlockFeedback() );
309  connect( feedback.get(), &QgsRasterBlockFeedback::progressChanged, mHistogramProgress, &QProgressBar::setValue );
310  QApplication::setOverrideCursor( Qt::WaitCursor );
311 
312  for ( int myIteratorInt = 1;
313  myIteratorInt <= myBandCountInt;
314  ++myIteratorInt )
315  {
316  int sampleSize = 250000; // number of sample cells
317  mRasterLayer->dataProvider()->histogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize, false, feedback.get() );
318  }
319 
320  // mHistogramProgress->hide();
321  stackedWidget2->setCurrentIndex( 0 );
322  QApplication::restoreOverrideCursor();
323 
324  return true;
325 }
326 
327 
329 {
330  // Explanation:
331  // We use the gdal histogram creation routine is called for each selected
332  // layer. Currently the hist is hardcoded to create 256 bins. Each bin stores
333  // the total number of cells that fit into the range defined by that bin.
334  //
335  // The graph routine below determines the greatest number of pixels in any given
336  // bin in all selected layers, and the min. It then draws a scaled line between min
337  // and max - scaled to image height. 1 line drawn per selected band
338  //
339  int myBandCountInt = mRasterLayer->bandCount();
340 
341 
342  if ( ! computeHistogram( false ) )
343  {
344  QgsDebugMsg( QStringLiteral( "raster does not have cached histogram" ) );
345  stackedWidget2->setCurrentIndex( 2 );
346  return;
347  }
348 
349  // clear plot
350  mpPlot->detachItems();
351 
352  //ensure all children get removed
353  mpPlot->setAutoDelete( true );
354  mpPlot->setTitle( QObject::tr( "Raster Histogram" ) );
355  mpPlot->insertLegend( new QwtLegend(), QwtPlot::BottomLegend );
356  // Set axis titles
357  mpPlot->setAxisTitle( QwtPlot::xBottom, QObject::tr( "Pixel Value" ) );
358  mpPlot->setAxisTitle( QwtPlot::yLeft, QObject::tr( "Frequency" ) );
359  mpPlot->setAxisAutoScale( QwtPlot::yLeft );
360 
361  // x axis scale only set after computing global min/max across bands (see below)
362  // add a grid
363  QwtPlotGrid *myGrid = new QwtPlotGrid();
364  myGrid->attach( mpPlot );
365 
366  // make colors list
367  mHistoColors.clear();
368  mHistoColors << Qt::black; // first element, not used
369  QVector<QColor> myColors;
370  myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
371  qsrand( myBandCountInt * 100 ); // make sure colors are always the same for a given band count
372  while ( myColors.size() <= myBandCountInt )
373  {
374  myColors <<
375  QColor( 1 + ( int )( 255.0 * qrand() / ( RAND_MAX + 1.0 ) ),
376  1 + ( int )( 255.0 * qrand() / ( RAND_MAX + 1.0 ) ),
377  1 + ( int )( 255.0 * qrand() / ( RAND_MAX + 1.0 ) ) );
378  }
379  //randomise seed again
380  qsrand( time( nullptr ) );
381 
382  // assign colors to each band, depending on the current RGB/gray band selection
383  // grayscale
384  QList< int > mySelectedBands = rendererSelectedBands();
385  if ( mRendererName == QLatin1String( "singlebandgray" ) )
386  {
387  int myGrayBand = mySelectedBands[0];
388  for ( int i = 1; i <= myBandCountInt; i++ )
389  {
390  if ( i == myGrayBand )
391  {
392  mHistoColors << Qt::darkGray;
393  cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
394  }
395  else
396  {
397  if ( ! myColors.isEmpty() )
398  {
399  mHistoColors << myColors.first();
400  myColors.pop_front();
401  }
402  else
403  {
404  mHistoColors << Qt::black;
405  }
406  cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
407  }
408  }
409  }
410  // RGB
411  else if ( mRendererName == QLatin1String( "multibandcolor" ) )
412  {
413  int myRedBand = mySelectedBands[0];
414  int myGreenBand = mySelectedBands[1];
415  int myBlueBand = mySelectedBands[2];
416  // remove RGB, which are reserved for the actual RGB bands
417  // show name of RGB bands in appropriate color in bold
418  myColors.remove( 0, 3 );
419  for ( int i = 1; i <= myBandCountInt; i++ )
420  {
421  QColor myColor;
422  if ( i == myRedBand )
423  myColor = Qt::red;
424  else if ( i == myGreenBand )
425  myColor = Qt::green;
426  else if ( i == myBlueBand )
427  myColor = Qt::blue;
428  else
429  {
430  if ( ! myColors.isEmpty() )
431  {
432  myColor = myColors.first();
433  myColors.pop_front();
434  }
435  else
436  {
437  myColor = Qt::black;
438  }
439  cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
440  }
441  if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
442  {
443  cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
444  }
445  mHistoColors << myColor;
446  }
447  }
448  else
449  {
450  mHistoColors << myColors;
451  }
452 
453  //
454  //now draw actual graphs
455  //
456 
457  //sometimes there are more bins than needed
458  //we find out the last one that actually has data in it
459  //so we can discard the rest and set the x-axis scales correctly
460  //
461  // scan through to get counts from layers' histograms
462  //
463  mHistoMin = 0;
464  mHistoMax = 0;
465  bool myFirstIteration = true;
466  /* Gets selected band list, if mHistoShowBands != ShowAll */
467  mySelectedBands = histoSelectedBands();
468  double myBinXStep = 1;
469  double myBinX = 0;
470 
471  for ( int myIteratorInt = 1;
472  myIteratorInt <= myBandCountInt;
473  ++myIteratorInt )
474  {
475  /* skip this band if mHistoShowBands != ShowAll and this band is not selected */
476  if ( mHistoShowBands != ShowAll )
477  {
478  if ( ! mySelectedBands.contains( myIteratorInt ) )
479  continue;
480  }
481 
482  int sampleSize = 250000; // number of sample cells
483 
484  std::unique_ptr< QgsRasterBlockFeedback > feedback( new QgsRasterBlockFeedback() );
485  connect( feedback.get(), &QgsRasterBlockFeedback::progressChanged, mHistogramProgress, &QProgressBar::setValue );
486 
487  QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize, false, feedback.get() );
488 
489  QgsDebugMsg( QStringLiteral( "got raster histo for band %1 : min=%2 max=%3 count=%4" ).arg( myIteratorInt ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myHistogram.binCount ) );
490 
491  Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( myIteratorInt );
492  bool myDrawLines = true;
493  if ( ! mHistoDrawLines &&
494  ( mySrcDataType == Qgis::Byte ||
495  mySrcDataType == Qgis::Int16 || mySrcDataType == Qgis::Int32 ||
496  mySrcDataType == Qgis::UInt16 || mySrcDataType == Qgis::UInt32 ) )
497  {
498  myDrawLines = false;
499  }
500 
501  QwtPlotCurve *mypCurve = nullptr;
502  if ( myDrawLines )
503  {
504  mypCurve = new QwtPlotCurve( tr( "Band %1" ).arg( myIteratorInt ) );
505  //mypCurve->setCurveAttribute( QwtPlotCurve::Fitted );
506  mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
507  mypCurve->setPen( QPen( mHistoColors.at( myIteratorInt ) ) );
508  }
509 
510  QwtPlotHistogram *mypHisto = nullptr;
511  if ( ! myDrawLines )
512  {
513  mypHisto = new QwtPlotHistogram( tr( "Band %1" ).arg( myIteratorInt ) );
514  mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
515  //mypHisto->setPen( QPen( mHistoColors.at( myIteratorInt ) ) );
516  mypHisto->setPen( QPen( Qt::lightGray ) );
517  // this is needed in order to see the colors in the legend
518  mypHisto->setBrush( QBrush( mHistoColors.at( myIteratorInt ) ) );
519  }
520 
521  QVector<QPointF> data;
522  QVector<QwtIntervalSample> dataHisto;
523 
524  // calculate first bin x value and bin step size if not Byte data
525  if ( mySrcDataType != Qgis::Byte )
526  {
527  myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
528  myBinX = myHistogram.minimum + myBinXStep / 2.0;
529  }
530  else
531  {
532  myBinXStep = 1;
533  myBinX = 0;
534  }
535 
536  for ( int myBin = 0; myBin < myHistogram.binCount; myBin++ )
537  {
538  int myBinValue = myHistogram.histogramVector.at( myBin );
539  if ( myDrawLines )
540  {
541  data << QPointF( myBinX, myBinValue );
542  }
543  else
544  {
545  dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
546  }
547  myBinX += myBinXStep;
548  }
549 
550  if ( myDrawLines )
551  {
552  mypCurve->setSamples( data );
553  mypCurve->attach( mpPlot );
554  }
555  else
556  {
557  mypHisto->setSamples( dataHisto );
558  mypHisto->attach( mpPlot );
559  }
560 
561  if ( myFirstIteration || mHistoMin > myHistogram.minimum )
562  {
563  mHistoMin = myHistogram.minimum;
564  }
565  if ( myFirstIteration || mHistoMax < myHistogram.maximum )
566  {
567  mHistoMax = myHistogram.maximum;
568  }
569  QgsDebugMsg( QStringLiteral( "computed histo min = %1 max = %2" ).arg( mHistoMin ).arg( mHistoMax ) );
570  myFirstIteration = false;
571  }
572 
573  if ( mHistoMin < mHistoMax )
574  {
575  // for x axis use band pixel values rather than gdal hist. bin values
576  // subtract -0.5 to prevent rounding errors
577  // see http://www.gdal.org/classGDALRasterBand.html#3f8889607d3b2294f7e0f11181c201c8
578  // fix x range for non-Byte data
579  mpPlot->setAxisScale( QwtPlot::xBottom,
580  mHistoMin - myBinXStep / 2,
581  mHistoMax + myBinXStep / 2 );
582  mpPlot->setEnabled( true );
583  mpPlot->replot();
584 
585  // histo plot markers
586  // memory leak?
587  mHistoMarkerMin = new QwtPlotMarker();
588  mHistoMarkerMin->attach( mpPlot );
589  mHistoMarkerMax = new QwtPlotMarker();
590  mHistoMarkerMax->attach( mpPlot );
591  updateHistoMarkers();
592 
593  // histo picker
594  if ( !mHistoPicker )
595  {
596  mHistoPicker = new QwtPlotPicker( mpPlot->canvas() );
597  // mHistoPicker->setTrackerMode( QwtPicker::ActiveOnly );
598  mHistoPicker->setTrackerMode( QwtPicker::AlwaysOff );
599  mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
600  mHistoPicker->setStateMachine( new QwtPickerDragPointMachine );
601  connect( mHistoPicker, static_cast < void ( QwtPlotPicker::* )( const QPointF & ) > ( &QwtPlotPicker::selected ), this, &QgsRasterHistogramWidget::histoPickerSelected );
602  }
603  mHistoPicker->setEnabled( false );
604 
605  // plot zoomer
606  if ( !mHistoZoomer )
607  {
608  mHistoZoomer = new QwtPlotZoomer( mpPlot->canvas() );
609  mHistoZoomer->setStateMachine( new QwtPickerDragRectMachine );
610  mHistoZoomer->setTrackerMode( QwtPicker::AlwaysOff );
611  }
612  mHistoZoomer->setEnabled( true );
613  }
614  else
615  {
616  mpPlot->setDisabled( true );
617  if ( mHistoPicker )
618  mHistoPicker->setEnabled( false );
619  if ( mHistoZoomer )
620  mHistoZoomer->setEnabled( false );
621  }
622 
623  stackedWidget2->setCurrentIndex( 0 );
624  // icon from http://findicons.com/icon/169577/14_zoom?id=171427
625  mpPlot->canvas()->setCursor( QCursor( QgsApplication::getThemePixmap( QStringLiteral( "/mIconZoom.svg" ) ) ) );
626  // cboHistoBand_currentIndexChanged( -1 );
627  QApplication::restoreOverrideCursor();
628 }
629 
630 void QgsRasterHistogramWidget::mSaveAsImageButton_clicked()
631 {
632  if ( !mpPlot )
633  return;
634 
635  QPair< QString, QString> myFileNameAndFilter = QgsGuiUtils::getSaveAsImageName( this, tr( "Choose a file name to save the map image as" ) );
636  QFileInfo myInfo( myFileNameAndFilter.first );
637  if ( !myInfo.baseName().isEmpty() )
638  {
639  histoSaveAsImage( myFileNameAndFilter.first );
640  }
641 }
642 
643 bool QgsRasterHistogramWidget::histoSaveAsImage( const QString &filename,
644  int width, int height, int quality )
645 {
646  // make sure dir. exists
647  QFileInfo myInfo( filename );
648  QDir myDir( myInfo.dir() );
649  if ( ! myDir.exists() )
650  {
651  QgsDebugMsg( QStringLiteral( "Error, directory %1 non-existent (theFilename = %2)" ).arg( myDir.absolutePath(), filename ) );
652  return false;
653  }
654 
655  // prepare the pixmap
656  QPixmap myPixmap( width, height );
657  QRect myQRect( 5, 5, width - 10, height - 10 ); // leave a 5px border on all sides
658  myPixmap.fill( Qt::white ); // Qt::transparent ?
659 
660  QwtPlotRenderer myRenderer;
661  myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground |
662  QwtPlotRenderer::DiscardCanvasBackground );
663  myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
664 
665  QPainter myPainter;
666  myPainter.begin( &myPixmap );
667  myRenderer.render( mpPlot, &myPainter, myQRect );
668  myPainter.end();
669 
670  // save pixmap to file
671  myPixmap.save( filename, nullptr, quality );
672 
673  // should do more error checking
674  return true;
675 }
676 
678 {
679  cboHistoBand->setCurrentIndex( bandNo - 1 );
680 }
681 
682 void QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged( int index )
683 {
684  if ( mHistoShowBands == ShowSelected )
686 
687  // get the current index value, index can be -1
688  index = cboHistoBand->currentIndex();
689  if ( mHistoPicker )
690  {
691  mHistoPicker->setEnabled( false );
692  mHistoPicker->setRubberBandPen( QPen( mHistoColors.at( index + 1 ) ) );
693  }
694  if ( mHistoZoomer )
695  mHistoZoomer->setEnabled( true );
696  btnHistoMin->setEnabled( true );
697  btnHistoMax->setEnabled( true );
698 
699  QPair< QString, QString > myMinMax = rendererMinMax( index + 1 );
700  leHistoMin->setText( myMinMax.first );
701  leHistoMax->setText( myMinMax.second );
702 
703  applyHistoMin();
704  applyHistoMax();
705 }
706 
707 void QgsRasterHistogramWidget::histoActionTriggered( QAction *action )
708 {
709  if ( ! action )
710  return;
711  histoAction( action->data().toString(), action->isChecked() );
712 }
713 
714 void QgsRasterHistogramWidget::histoAction( const QString &actionName, bool actionFlag )
715 {
716  if ( actionName.isEmpty() )
717  return;
718 
719  // this approach is a bit of a hack, but this way we don't have to define slots for each action
720  QgsDebugMsg( QStringLiteral( "band = %1 action = %2" ).arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ) );
721 
722  // checkeable actions
723  if ( actionName == QLatin1String( "Show markers" ) )
724  {
725  mHistoShowMarkers = actionFlag;
726  QgsSettings settings;
727  settings.setValue( QStringLiteral( "Raster/histogram/showMarkers" ), mHistoShowMarkers );
728  updateHistoMarkers();
729  return;
730  }
731  else if ( actionName == QLatin1String( "Zoom min_max" ) )
732  {
733  mHistoZoomToMinMax = actionFlag;
734  QgsSettings settings;
735  settings.setValue( QStringLiteral( "Raster/histogram/zoomToMinMax" ), mHistoZoomToMinMax );
736  return;
737  }
738  else if ( actionName == QLatin1String( "Update min_max" ) )
739  {
740  mHistoUpdateStyleToMinMax = actionFlag;
741  QgsSettings settings;
742  settings.setValue( QStringLiteral( "Raster/histogram/updateStyleToMinMax" ), mHistoUpdateStyleToMinMax );
743  return;
744  }
745  else if ( actionName == QLatin1String( "Show all" ) )
746  {
747  mHistoShowBands = ShowAll;
748  // settings.setValue( "/Raster/histogram/showBands", static_cast<int>(mHistoShowBands) );
750  return;
751  }
752  else if ( actionName == QLatin1String( "Show selected" ) )
753  {
754  mHistoShowBands = ShowSelected;
755  // settings.setValue( "/Raster/histogram/showBands", static_cast<int>(mHistoShowBands) );
757  return;
758  }
759  else if ( actionName == QLatin1String( "Show RGB" ) )
760  {
761  mHistoShowBands = ShowRGB;
762  // settings.setValue( "/Raster/histogram/showBands", static_cast<int>(mHistoShowBands) );
764  return;
765  }
766  else if ( actionName == QLatin1String( "Draw lines" ) )
767  {
768  mHistoDrawLines = actionFlag;
769  QgsSettings settings;
770  settings.setValue( QStringLiteral( "Raster/histogram/drawLines" ), mHistoDrawLines );
771  btnHistoCompute_clicked(); // refresh
772  return;
773  }
774 #if 0
775  else if ( actionName == "Load apply all" )
776  {
777  mHistoLoadApplyAll = actionFlag;
778  settings.setValue( "/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
779  return;
780  }
781 #endif
782  // Load actions
783  // TODO - separate calculations from rendererwidget so we can do them without
784  else if ( actionName.left( 5 ) == QLatin1String( "Load " ) && mRendererWidget )
785  {
786  QVector<int> myBands;
787  bool ok = false;
788 
789 #if 0
790  double minMaxValues[2];
791 
792  // find which band(s) need updating (all or current)
793  if ( mHistoLoadApplyAll )
794  {
795  int myBandCountInt = mRasterLayer->bandCount();
796  for ( int i = 1; i <= myBandCountInt; i++ )
797  {
798  if ( i != cboHistoBand->currentIndex() + 1 )
799  myBands << i;
800  }
801  }
802 #endif
803 
804  // add current band to the end
805  myBands << cboHistoBand->currentIndex() + 1;
806 
807  // get stddev value once if needed
808 #if 0
809  double myStdDev = 1.0;
810  if ( actionName == "Load stddev" )
811  {
812  myStdDev = mRendererWidget->stdDev().toDouble();
813  }
814 #endif
815 
816  // don't update markers every time
817  leHistoMin->blockSignals( true );
818  leHistoMax->blockSignals( true );
819 
820  // process each band
821  const auto constMyBands = myBands;
822  for ( int bandNo : constMyBands )
823  {
824  ok = false;
825 #if 0
826  if ( actionName == "Load actual" )
827  {
828  ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Actual,
829  bandNo, minMaxValues );
830  }
831  else if ( actionName == "Load estimate" )
832  {
833  ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Estimate,
834  bandNo, minMaxValues );
835  }
836  else if ( actionName == "Load extent" )
837  {
838  ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::CurrentExtent,
839  bandNo, minMaxValues );
840  }
841  else if ( actionName == "Load 1 stddev" ||
842  actionName == "Load stddev" )
843  {
844  ok = mRendererWidget->bandMinMaxFromStdDev( myStdDev, bandNo, minMaxValues );
845  }
846 #endif
847 
848  // apply current item
849  cboHistoBand->setCurrentIndex( bandNo - 1 );
850  if ( !ok || actionName == QLatin1String( "Load reset" ) )
851  {
852  leHistoMin->clear();
853  leHistoMax->clear();
854 #if 0
855  // TODO - fix gdal provider: changes data type when nodata value is not found
856  // this prevents us from getting proper min and max values here
858  ( Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
860  ( Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
861  }
862  else
863  {
864  leHistoMin->setText( QString::number( minMaxValues[0] ) );
865  leHistoMax->setText( QString::number( minMaxValues[1] ) );
866 #endif
867  }
868  applyHistoMin();
869  applyHistoMax();
870  }
871  // update markers
872  leHistoMin->blockSignals( false );
873  leHistoMax->blockSignals( false );
874  updateHistoMarkers();
875  }
876  else if ( actionName == QLatin1String( "Compute histogram" ) )
877  {
878  btnHistoCompute_clicked();
879  }
880  else
881  {
882  QgsDebugMsg( "Invalid action " + actionName );
883  return;
884  }
885 }
886 
887 void QgsRasterHistogramWidget::applyHistoMin()
888 {
889  if ( ! mRendererWidget )
890  return;
891 
892  int bandNo = cboHistoBand->currentIndex() + 1;
893  QList< int > mySelectedBands = rendererSelectedBands();
894  QString min;
895  for ( int i = 0; i <= mySelectedBands.size(); i++ )
896  {
897  if ( bandNo == mRendererWidget->selectedBand( i ) )
898  {
899  min = leHistoMin->text();
900  if ( mHistoUpdateStyleToMinMax && mRendererWidget->min( i ) != min )
901  {
902  mRendererWidget->setMin( min, i );
903  if ( mRendererWidget->minMaxWidget() )
904  {
905  mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
906  }
907  }
908  }
909  }
910 
911  updateHistoMarkers();
912 
913  if ( ! min.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
914  {
915  QRectF rect = mHistoZoomer->zoomRect();
916  rect.setLeft( min.toDouble() );
917  mHistoZoomer->zoom( rect );
918  }
919  emit widgetChanged();
920 }
921 
922 void QgsRasterHistogramWidget::applyHistoMax()
923 {
924  if ( ! mRendererWidget )
925  return;
926 
927  int bandNo = cboHistoBand->currentIndex() + 1;
928  QList< int > mySelectedBands = rendererSelectedBands();
929  QString max;
930  for ( int i = 0; i <= mySelectedBands.size(); i++ )
931  {
932  if ( bandNo == mRendererWidget->selectedBand( i ) )
933  {
934  max = leHistoMax->text();
935  if ( mHistoUpdateStyleToMinMax && mRendererWidget->max( i ) != max )
936  {
937  mRendererWidget->setMax( max, i );
938  if ( mRendererWidget->minMaxWidget() )
939  {
940  mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
941  }
942  }
943  }
944  }
945 
946  updateHistoMarkers();
947 
948  if ( ! max.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
949  {
950  QRectF rect = mHistoZoomer->zoomRect();
951  rect.setRight( max.toDouble() );
952  mHistoZoomer->zoom( rect );
953  }
954  emit widgetChanged();
955 }
956 
957 void QgsRasterHistogramWidget::btnHistoMin_toggled()
958 {
959  if ( mpPlot && mHistoPicker )
960  {
961  if ( QApplication::overrideCursor() )
962  QApplication::restoreOverrideCursor();
963  if ( btnHistoMin->isChecked() )
964  {
965  btnHistoMax->setChecked( false );
966  QApplication::setOverrideCursor( Qt::PointingHandCursor );
967  }
968  if ( mHistoZoomer )
969  mHistoZoomer->setEnabled( ! btnHistoMin->isChecked() );
970  mHistoPicker->setEnabled( btnHistoMin->isChecked() );
971  }
972  updateHistoMarkers();
973 }
974 
975 void QgsRasterHistogramWidget::btnHistoMax_toggled()
976 {
977  if ( mpPlot && mHistoPicker )
978  {
979  if ( QApplication::overrideCursor() )
980  QApplication::restoreOverrideCursor();
981  if ( btnHistoMax->isChecked() )
982  {
983  btnHistoMin->setChecked( false );
984  QApplication::setOverrideCursor( Qt::PointingHandCursor );
985  }
986  if ( mHistoZoomer )
987  mHistoZoomer->setEnabled( ! btnHistoMax->isChecked() );
988  mHistoPicker->setEnabled( btnHistoMax->isChecked() );
989  }
990  updateHistoMarkers();
991 }
992 
993 // local function used by histoPickerSelected(), to get a rounded picked value
994 // this is sensitive and may not always be correct, needs more testing
995 QString findClosestTickVal( double target, const QwtScaleDiv *scale, int div = 100 )
996 {
997  if ( !scale ) return QString();
998 
999  QList< double > minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1000  QList< double > majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1001  double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1002  double min = majorTicks[0] - diff;
1003  if ( min > target )
1004  min -= ( majorTicks[1] - majorTicks[0] );
1005  double max = scale->upperBound();
1006  double closest = target;
1007  double current = min;
1008 
1009  while ( current < max )
1010  {
1011  current += diff;
1012  if ( current > target )
1013  {
1014  closest = ( std::fabs( target - current + diff ) < std::fabs( target - current ) ) ? current - diff : current;
1015  break;
1016  }
1017  }
1018 
1019  // QgsDebugMsg( QStringLiteral( "target=%1 div=%2 closest=%3" ).arg( target ).arg( div ).arg( closest ) );
1020  return QString::number( closest );
1021 }
1022 
1023 void QgsRasterHistogramWidget::histoPickerSelected( QPointF pos )
1024 {
1025  if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1026  {
1027  const QwtScaleDiv *scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1028 
1029  if ( btnHistoMin->isChecked() )
1030  {
1031  leHistoMin->setText( findClosestTickVal( pos.x(), scale ) );
1032  applyHistoMin();
1033  btnHistoMin->setChecked( false );
1034  }
1035  else // if ( btnHistoMax->isChecked() )
1036  {
1037  leHistoMax->setText( findClosestTickVal( pos.x(), scale ) );
1038  applyHistoMax();
1039  btnHistoMax->setChecked( false );
1040  }
1041  }
1042  if ( QApplication::overrideCursor() )
1043  QApplication::restoreOverrideCursor();
1044 }
1045 
1046 void QgsRasterHistogramWidget::histoPickerSelectedQwt5( QwtDoublePoint pos )
1047 {
1048  histoPickerSelected( QPointF( pos.x(), pos.y() ) );
1049 }
1050 
1051 void QgsRasterHistogramWidget::updateHistoMarkers()
1052 {
1053  // hack to not update markers
1054  if ( leHistoMin->signalsBlocked() )
1055  return;
1056  // todo error checking
1057  if ( !mpPlot || !mHistoMarkerMin || !mHistoMarkerMax )
1058  return;
1059 
1060  int bandNo = cboHistoBand->currentIndex() + 1;
1061  QList< int > mySelectedBands = histoSelectedBands();
1062 
1063  if ( ( ! mHistoShowMarkers && ! btnHistoMin->isChecked() && ! btnHistoMax->isChecked() ) ||
1064  ( ! mySelectedBands.isEmpty() && ! mySelectedBands.contains( bandNo ) ) )
1065  {
1066  mHistoMarkerMin->hide();
1067  mHistoMarkerMax->hide();
1068  mpPlot->replot();
1069  return;
1070  }
1071 
1072  double minVal = mHistoMin;
1073  double maxVal = mHistoMax;
1074  QString minStr = leHistoMin->text();
1075  QString maxStr = leHistoMax->text();
1076  if ( !minStr.isEmpty() )
1077  minVal = minStr.toDouble();
1078  if ( !maxStr.isEmpty() )
1079  maxVal = maxStr.toDouble();
1080 
1081  QPen linePen = QPen( mHistoColors.at( bandNo ) );
1082  linePen.setStyle( Qt::DashLine );
1083  mHistoMarkerMin->setLineStyle( QwtPlotMarker::VLine );
1084  mHistoMarkerMin->setLinePen( linePen );
1085  mHistoMarkerMin->setXValue( minVal );
1086  mHistoMarkerMin->show();
1087  mHistoMarkerMax->setLineStyle( QwtPlotMarker::VLine );
1088  mHistoMarkerMax->setLinePen( linePen );
1089  mHistoMarkerMax->setXValue( maxVal );
1090  mHistoMarkerMax->show();
1091 
1092  mpPlot->replot();
1093 }
1094 
1095 
1096 QList< int > QgsRasterHistogramWidget::histoSelectedBands()
1097 {
1098  QList< int > mySelectedBands;
1099 
1100  if ( mHistoShowBands != ShowAll )
1101  {
1102  if ( mHistoShowBands == ShowSelected )
1103  {
1104  mySelectedBands << cboHistoBand->currentIndex() + 1;
1105  }
1106  else if ( mHistoShowBands == ShowRGB )
1107  {
1108  mySelectedBands = rendererSelectedBands();
1109  }
1110  }
1111 
1112  return mySelectedBands;
1113 }
1114 
1115 QList< int > QgsRasterHistogramWidget::rendererSelectedBands()
1116 {
1117  QList< int > mySelectedBands;
1118 
1119  if ( ! mRendererWidget )
1120  {
1121  mySelectedBands << -1 << -1 << -1; // make sure we return 3 elements
1122  return mySelectedBands;
1123  }
1124 
1125  if ( mRendererName == QLatin1String( "singlebandgray" ) )
1126  {
1127  mySelectedBands << mRendererWidget->selectedBand();
1128  }
1129  else if ( mRendererName == QLatin1String( "multibandcolor" ) )
1130  {
1131  for ( int i = 0; i <= 2; i++ )
1132  {
1133  mySelectedBands << mRendererWidget->selectedBand( i );
1134  }
1135  }
1136 
1137  return mySelectedBands;
1138 }
1139 
1140 QPair< QString, QString > QgsRasterHistogramWidget::rendererMinMax( int bandNo )
1141 {
1142  QPair< QString, QString > myMinMax;
1143 
1144  if ( ! mRendererWidget )
1145  return myMinMax;
1146 
1147  if ( mRendererName == QLatin1String( "singlebandgray" ) )
1148  {
1149  if ( bandNo == mRendererWidget->selectedBand() )
1150  {
1151  myMinMax.first = mRendererWidget->min();
1152  myMinMax.second = mRendererWidget->max();
1153  }
1154  }
1155  else if ( mRendererName == QLatin1String( "multibandcolor" ) )
1156  {
1157  for ( int i = 0; i <= 2; i++ )
1158  {
1159  if ( bandNo == mRendererWidget->selectedBand( i ) )
1160  {
1161  myMinMax.first = mRendererWidget->min( i );
1162  myMinMax.second = mRendererWidget->max( i );
1163  break;
1164  }
1165  }
1166  }
1167 
1168  // TODO - there are 2 definitions of raster data type that should be unified
1169  // QgsRasterDataProvider::DataType and Qgis::DataType
1170  // TODO - fix gdal provider: changes data type when nodata value is not found
1171  // this prevents us from getting proper min and max values here
1172  // minStr = QString::number( QgsContrastEnhancement::minimumValuePossible( ( Qgis::DataType )
1173  // mRasterLayer->dataProvider()->dataType( bandNo ) ) );
1174  // maxStr = QString::number( QgsContrastEnhancement::maximumValuePossible( ( Qgis::DataType )
1175  // mRasterLayer->dataProvider()->dataType( bandNo ) ) );
1176 
1177  // if we get an empty result, fill with default value (histo min/max)
1178  if ( myMinMax.first.isEmpty() )
1179  myMinMax.first = QString::number( mHistoMin );
1180  if ( myMinMax.second.isEmpty() )
1181  myMinMax.second = QString::number( mHistoMax );
1182 
1183  QgsDebugMsg( QStringLiteral( "bandNo %1 got min/max [%2] [%3]" ).arg( bandNo ).arg( myMinMax.first, myMinMax.second ) );
1184 
1185  return myMinMax;
1186 }
1187 
1189 {
1190 
1191 }
QgsRasterMinMaxWidget::userHasSetManualMinMaxValues
void userHasSetManualMinMaxValues()
Uncheck cumulative cut, min/max, std-dev radio buttons.
Definition: qgsrasterminmaxwidget.cpp:84
QgsRasterRendererWidget::stdDev
virtual QString stdDev()
Definition: qgsrasterrendererwidget.h:73
QgsRasterHistogramWidget::histoAction
void histoAction(const QString &actionName, bool actionFlag=true)
Apply a histoActionTriggered() event.
Definition: qgsrasterhistogramwidget.cpp:714
QgsRasterLayer::bandCount
int bandCount() const
Returns the number of bands in this layer.
Definition: qgsrasterlayer.cpp:216
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:114
QgsRasterHistogram::histogramVector
QgsRasterHistogram::HistogramVector histogramVector
Stores the histogram for a given layer.
Definition: qgsrasterhistogram.h:84
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
Qgis::UInt32
@ UInt32
Thirty two bit unsigned integer (quint32)
Definition: qgis.h:120
QgsRasterDataProvider::dataType
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsRasterHistogramWidget::apply
void apply() override
Definition: qgsrasterhistogramwidget.cpp:1188
QgsRasterRendererWidget::minMaxWidget
virtual QgsRasterMinMaxWidget * minMaxWidget()
Returns min/max widget when it exists.
Definition: qgsrasterrendererwidget.h:81
QgsContrastEnhancement::maximumValuePossible
static double maximumValuePossible(Qgis::DataType dataType)
Helper function that returns the maximum possible value for a GDAL data type.
Definition: qgscontrastenhancement.h:66
QgsRasterHistogramWidget::setRendererWidget
void setRendererWidget(const QString &name, QgsRasterRendererWidget *rendererWidget=nullptr)
Sets the renderer widget (or just its name if there is no widget)
Definition: qgsrasterhistogramwidget.cpp:248
QwtDoublePoint
QPointF QwtDoublePoint
Definition: qgscurveeditorwidget.h:36
QgsRasterHistogramWidget::setActive
void setActive(bool activeFlag)
Activate the histogram widget.
Definition: qgsrasterhistogramwidget.cpp:256
QgsRasterInterface::hasHistogram
virtual bool hasHistogram(int bandNo, int binCount, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false)
Returns true if histogram is available (cached, already calculated)
Definition: qgsrasterinterface.cpp:376
QgsRasterRendererWidget::setMax
virtual void setMax(const QString &value, int index=0)
Definition: qgsrasterrendererwidget.h:72
QgsSettings
Definition: qgssettings.h:61
qgsrasterrendererregistry.h
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsrasterrendererwidget.h
QgsRectangle
Definition: qgsrectangle.h:41
QgsRasterLayer::bandName
QString bandName(int bandNoInt) const
Returns the name of a band given its number.
Definition: qgsrasterlayer.cpp:222
QgsMapLayerConfigWidget
A panel widget that can be shown in the map style dock.
Definition: qgsmaplayerconfigwidget.h:33
qgsapplication.h
QgsRasterHistogramWidget::computeHistogram
bool computeHistogram(bool forceComputeFlag)
Compute the histogram on demand.
Definition: qgsrasterhistogramwidget.cpp:282
QgsRasterHistogramWidget::QgsRasterHistogramWidget
QgsRasterHistogramWidget(QgsRasterLayer *layer, QWidget *parent=nullptr)
Constructor for QgsRasterHistogramWidget, for the specified raster layer.
Definition: qgsrasterhistogramwidget.cpp:55
QgsRasterHistogram::minimum
double minimum
The minimum histogram value.
Definition: qgsrasterhistogram.h:90
findClosestTickVal
QString findClosestTickVal(double target, const QwtScaleDiv *scale, int div=100)
Definition: qgsrasterhistogramwidget.cpp:995
QgsPanelWidget::widgetChanged
void widgetChanged()
Emitted when the widget state changes.
QgsRasterHistogramWidget::setSelectedBand
void setSelectedBand(int index)
Apply a histoActionTriggered() event.
Definition: qgsrasterhistogramwidget.cpp:677
QgsRasterRendererWidget::min
virtual QString min(int index=0)
Definition: qgsrasterrendererwidget.h:69
QgsContrastEnhancement::minimumValuePossible
static double minimumValuePossible(Qgis::DataType dataType)
Helper function that returns the minimum possible value for a GDAL data type.
Definition: qgscontrastenhancement.h:105
QgsFeedback::progressChanged
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
QgsRasterHistogram::binCount
int binCount
Number of bins (intervals,buckets) in histogram.
Definition: qgsrasterhistogram.h:73
qgsrasterhistogramwidget.h
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsRasterLayer
Definition: qgsrasterlayer.h:72
QgsGuiUtils::getSaveAsImageName
QPair< QString, QString > GUI_EXPORT getSaveAsImageName(QWidget *parent, const QString &message, const QString &defaultFilename)
A helper function to get an image name from the user.
Definition: qgsguiutils.cpp:102
Qgis::UInt16
@ UInt16
Sixteen bit unsigned integer (quint16)
Definition: qgis.h:118
QgsRasterRendererWidget::selectedBand
virtual int selectedBand(int index=0)
Definition: qgsrasterrendererwidget.h:75
QgsRasterHistogramWidget::histoSaveAsImage
bool histoSaveAsImage(const QString &filename, int width=600, int height=600, int quality=-1)
Save the histogram as an image to disk.
Definition: qgsrasterhistogramwidget.cpp:643
QgsRasterDataProvider::sourceDataType
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
QgsRasterInterface::histogram
virtual QgsRasterHistogram histogram(int bandNo, int binCount=0, double minimum=std::numeric_limits< double >::quiet_NaN(), double maximum=std::numeric_limits< double >::quiet_NaN(), const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, bool includeOutOfRange=false, QgsRasterBlockFeedback *feedback=nullptr)
Returns a band histogram.
Definition: qgsrasterinterface.cpp:403
QgsRasterHistogram
Definition: qgsrasterhistogram.h:33
qgsrasterminmaxwidget.h
QgsRasterBlockFeedback
Definition: qgsrasterinterface.h:40
qgssettings.h
Qgis::Int16
@ Int16
Sixteen bit signed integer (qint16)
Definition: qgis.h:119
QgsApplication::getThemePixmap
static QPixmap getThemePixmap(const QString &name)
Helper to get a theme icon as a pixmap.
Definition: qgsapplication.cpp:700
Qgis::Int32
@ Int32
Thirty two bit signed integer (qint32)
Definition: qgis.h:121
QgsRasterRendererWidget::setMin
virtual void setMin(const QString &value, int index=0)
Definition: qgsrasterrendererwidget.h:71
QgsRasterRendererWidget
Definition: qgsrasterrendererwidget.h:36
qgsguiutils.h
QgsRasterHistogram::maximum
double maximum
The maximum histogram value.
Definition: qgsrasterhistogram.h:87
QgsRasterRendererWidget::max
virtual QString max(int index=0)
Definition: qgsrasterrendererwidget.h:70
Qgis::Byte
@ Byte
Eight bit unsigned integer (quint8)
Definition: qgis.h:117
QgsRasterLayer::dataProvider
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Definition: qgsrasterlayer.cpp:233
QgsRasterHistogramWidget::refreshHistogram
void refreshHistogram()
slot executed when user wishes to refresh raster histogramwidget
Definition: qgsrasterhistogramwidget.cpp:328
qgsrasterdataprovider.h