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