31 #include <qwt_global.h>
32 #include <qwt_plot_canvas.h>
33 #include <qwt_legend.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>
55 mRasterLayer( lyr ), mRendererWidget( 0 )
73 mHistoShowMarkers = settings.value(
"/Raster/histogram/showMarkers",
false ).toBool();
75 mHistoZoomToMinMax = settings.value(
"/Raster/histogram/zoomToMinMax",
false ).toBool();
77 mHistoDrawLines = settings.value(
"/Raster/histogram/drawLines",
true ).toBool();
86 for (
int myIteratorInt = 1;
87 myIteratorInt <= myBandCountInt;
99 leHistoMin->setValidator(
new QDoubleValidator(
this ) );
100 leHistoMax->setValidator(
new QDoubleValidator(
this ) );
106 connect( leHistoMin, SIGNAL( editingFinished() ),
this, SLOT(
applyHistoMin() ) );
107 connect( leHistoMax, SIGNAL( editingFinished() ),
this, SLOT(
applyHistoMax() ) );
111 QMenu* menu =
new QMenu(
this );
112 menu->setSeparatorsCollapsible(
false );
113 btnHistoActions->setMenu( menu );
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 );
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 );
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 );
138 menu->addAction( action );
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 );
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 );
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 );
159 menu->addAction( action );
160 action =
new QAction(
tr(
"Show selected band" ), group );
161 action->setData( QVariant(
"Show selected" ) );
162 action->setCheckable(
true );
164 menu->addAction( action );
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 );
174 action =
new QAction(
"", group );
175 action->setData( QVariant(
"Draw lines" ) );
178 action->setText(
tr(
"Draw as lines" ) );
179 action->setCheckable(
true );
184 action->setText(
tr(
"Draw as lines (only int layers)" ) );
185 action->setEnabled(
false );
187 menu->addAction( action );
190 action =
new QAction(
tr(
"Actions" ), group );
191 action->setSeparator(
true );
192 menu->addAction( action );
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 );
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 );
232 action =
new QAction(
tr(
"Recompute Histogram" ), group );
233 action->setData( QVariant(
"Compute histogram" ) );
234 menu->addAction( action );
262 if ( QApplication::overrideCursor() )
263 QApplication::restoreOverrideCursor();
264 btnHistoMin->setChecked(
false );
265 btnHistoMax->setChecked(
false );
288 if ( ! forceComputeFlag )
290 for (
int myIteratorInt = 1;
291 myIteratorInt <= myBandCountInt;
294 int sampleSize = 250000;
297 QgsDebugMsg( QString(
"band %1 does not have cached histo" ).arg( myIteratorInt ) );
304 stackedWidget2->setCurrentIndex( 1 );
305 connect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
306 QApplication::setOverrideCursor( Qt::WaitCursor );
308 for (
int myIteratorInt = 1;
309 myIteratorInt <= myBandCountInt;
312 int sampleSize = 250000;
316 disconnect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
318 stackedWidget2->setCurrentIndex( 0 );
319 QApplication::restoreOverrideCursor();
342 QgsDebugMsg( QString(
"raster does not have cached histogram" ) );
343 stackedWidget2->setCurrentIndex( 2 );
348 mpPlot->detachItems();
351 mpPlot->setAutoDelete(
true );
352 mpPlot->setTitle(
QObject::tr(
"Raster Histogram" ) );
353 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
355 mpPlot->setAxisTitle( QwtPlot::xBottom,
QObject::tr(
"Pixel Value" ) );
356 mpPlot->setAxisTitle( QwtPlot::yLeft,
QObject::tr(
"Frequency" ) );
357 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
361 QwtPlotGrid * myGrid =
new QwtPlotGrid();
362 myGrid->attach( mpPlot );
367 QVector<QColor> myColors;
368 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
369 srand( myBandCountInt * 100 );
370 while ( myColors.size() <= myBandCountInt )
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 ) ) );
383 int myGrayBand = mySelectedBands[0];
384 for (
int i = 1; i <= myBandCountInt; i++ )
386 if ( i == myGrayBand )
389 cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
393 if ( ! myColors.isEmpty() )
396 myColors.pop_front();
402 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
409 int myRedBand = mySelectedBands[0];
410 int myGreenBand = mySelectedBands[1];
411 int myBlueBand = mySelectedBands[2];
414 myColors.remove( 0, 3 );
415 for (
int i = 1; i <= myBandCountInt; i++ )
418 if ( i == myRedBand )
420 else if ( i == myGreenBand )
422 else if ( i == myBlueBand )
426 if ( ! myColors.isEmpty() )
428 myColor = myColors.first();
429 myColors.pop_front();
435 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
437 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
439 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
461 bool myFirstIteration =
true;
464 double myBinXStep = 1;
467 for (
int myIteratorInt = 1;
468 myIteratorInt <= myBandCountInt;
474 if ( ! mySelectedBands.contains( myIteratorInt ) )
478 int sampleSize = 250000;
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 ) );
484 bool myDrawLines =
true;
493 QwtPlotCurve * mypCurve = 0;
496 mypCurve =
new QwtPlotCurve(
tr(
"Band %1" ).arg( myIteratorInt ) );
498 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
499 mypCurve->setPen( QPen(
mHistoColors.at( myIteratorInt ) ) );
502 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
503 QwtPlotHistogram * mypHisto = 0;
506 mypHisto =
new QwtPlotHistogram(
tr(
"Band %1" ).arg( myIteratorInt ) );
507 mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
509 mypHisto->setPen( QPen( Qt::lightGray ) );
511 mypHisto->setBrush( QBrush(
mHistoColors.at( myIteratorInt ) ) );
517 mypHistoItem =
new HistogramItem(
tr(
"Band %1" ).arg( myIteratorInt ) );
518 mypHistoItem->setRenderHint( QwtPlotItem::RenderAntialiased );
523 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
524 QVector<QPointF> data;
525 QVector<QwtIntervalSample> dataHisto;
527 QVector<double> myX2Data;
528 QVector<double> myY2Data;
530 QwtArray<QwtDoubleInterval> intervalsHisto;
531 QwtArray<double> valuesHisto;
539 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
547 for (
int myBin = 0; myBin < myHistogram.
binCount; myBin++ )
550 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
553 data << QPointF( myBinX, myBinValue );
557 dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
562 myX2Data.append(
double( myBinX ) );
563 myY2Data.append(
double( myBinValue ) );
567 intervalsHisto.append( QwtDoubleInterval( myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 ) );
568 valuesHisto.append(
double( myBinValue ) );
571 myBinX += myBinXStep;
574 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
577 mypCurve->setSamples( data );
578 mypCurve->attach( mpPlot );
582 mypHisto->setSamples( dataHisto );
583 mypHisto->attach( mpPlot );
588 mypCurve->setData( myX2Data, myY2Data );
589 mypCurve->attach( mpPlot );
593 mypHistoItem->
setData( QwtIntervalData( intervalsHisto, valuesHisto ) );
594 mypHistoItem->attach( mpPlot );
607 myFirstIteration =
false;
613 mpPlot->setAxisScale( QwtPlot::xBottom,
633 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
635 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
636 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
639 mHistoPicker->setSelectionFlags( QwtPicker::PointSelection | QwtPicker::DragSelection );
648 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
649 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
651 mHistoZoomer->setSelectionFlags( QwtPicker::RectSelection | QwtPicker::DragSelection );
657 disconnect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
658 stackedWidget2->setCurrentIndex( 0 );
662 QApplication::restoreOverrideCursor();
673 QFileInfo myInfo( myFileNameAndFilter.first );
674 if ( QFileInfo( myFileNameAndFilter.first ).baseName() !=
"" )
681 int width,
int height,
int quality )
684 QFileInfo myInfo( theFilename );
685 QDir myDir( myInfo.dir() );
686 if ( ! myDir.exists() )
688 QgsDebugMsg( QString(
"Error, directory %1 non-existent (theFilename = %2)" ).arg( myDir.absolutePath() ).arg( theFilename ) );
693 QPixmap myPixmap( width, height );
694 QRect myQRect( 5, 5, width - 10, height - 10 );
695 myPixmap.fill( Qt::white );
697 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
698 QwtPlotRenderer myRenderer;
699 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground |
700 QwtPlotRenderer::DiscardCanvasBackground );
701 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
704 myPainter.begin( &myPixmap );
705 myRenderer.render( mpPlot, &myPainter, myQRect );
708 QwtPlotPrintFilter myFilter;
709 int myOptions = QwtPlotPrintFilter::PrintAll;
710 myOptions &= ~QwtPlotPrintFilter::PrintBackground;
711 myOptions |= QwtPlotPrintFilter::PrintFrameWithScales;
712 myFilter.setOptions( myOptions );
715 myPainter.begin( &myPixmap );
716 mpPlot->print( &myPainter, myQRect, myFilter );
726 myPixmap.save( theFilename, 0, quality );
734 cboHistoBand->setCurrentIndex( theBandNo - 1 );
743 index = cboHistoBand->currentIndex();
751 btnHistoMin->setEnabled(
true );
752 btnHistoMax->setEnabled(
true );
755 leHistoMin->setText( myMinMax.first );
756 leHistoMax->setText( myMinMax.second );
766 histoAction( action->data().toString(), action->isChecked() );
771 if ( actionName ==
"" )
775 QgsDebugMsg( QString(
"band = %1 action = %2" ).arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ) );
778 if ( actionName ==
"Show markers" )
786 else if ( actionName ==
"Zoom min_max" )
793 else if ( actionName ==
"Update min_max" )
800 else if ( actionName ==
"Show all" )
807 else if ( actionName ==
"Show selected" )
814 else if ( actionName ==
"Show RGB" )
821 else if ( actionName ==
"Draw lines" )
830 else if ( actionName ==
"Load apply all" )
832 mHistoLoadApplyAll = actionFlag;
833 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
841 QVector<int> myBands;
845 double minMaxValues[2];
848 if ( mHistoLoadApplyAll )
851 for (
int i = 1; i <= myBandCountInt; i++ )
853 if ( i != cboHistoBand->currentIndex() + 1 )
860 myBands << cboHistoBand->currentIndex() + 1;
872 leHistoMin->blockSignals(
true );
873 leHistoMax->blockSignals(
true );
876 foreach (
int theBandNo, myBands )
880 if ( actionName ==
"Load actual" )
883 theBandNo, minMaxValues );
885 else if ( actionName ==
"Load estimate" )
888 theBandNo, minMaxValues );
890 else if ( actionName ==
"Load extent" )
893 theBandNo, minMaxValues );
895 else if ( actionName ==
"Load 1 stddev" ||
896 actionName ==
"Load stddev" )
898 ok =
mRendererWidget->bandMinMaxFromStdDev( myStdDev, theBandNo, minMaxValues );
903 cboHistoBand->setCurrentIndex( theBandNo - 1 );
904 if ( !ok || actionName ==
"Load reset" )
918 leHistoMin->setText( QString::number( minMaxValues[0] ) );
919 leHistoMax->setText( QString::number( minMaxValues[1] ) );
926 leHistoMin->blockSignals(
false );
927 leHistoMax->blockSignals(
false );
930 else if ( actionName ==
"Compute histogram" )
946 int theBandNo = cboHistoBand->currentIndex() + 1;
949 for (
int i = 0; i <= mySelectedBands.size(); i++ )
953 min = leHistoMin->text();
964 rect.setLeft( min.toDouble() );
975 int theBandNo = cboHistoBand->currentIndex() + 1;
978 for (
int i = 0; i <= mySelectedBands.size(); i++ )
982 max = leHistoMax->text();
993 rect.setRight( max.toDouble() );
1002 if ( QApplication::overrideCursor() )
1003 QApplication::restoreOverrideCursor();
1004 if ( btnHistoMin->isChecked() )
1006 btnHistoMax->setChecked(
false );
1007 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1010 mHistoZoomer->setEnabled( ! btnHistoMax->isChecked() );
1020 if ( QApplication::overrideCursor() )
1021 QApplication::restoreOverrideCursor();
1022 if ( btnHistoMax->isChecked() )
1024 btnHistoMin->setChecked(
false );
1025 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1028 mHistoZoomer->setEnabled( ! btnHistoMax->isChecked() );
1038 if ( !scale )
return "";
1040 QList< double > minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1041 QList< double > majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1042 double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1043 double min = majorTicks[0] - diff;
1045 min -= ( majorTicks[1] - majorTicks[0] );
1046 #if defined(QWT_VERSION) && QWT_VERSION<0x050200
1047 double max = scale->hBound();
1049 double max = scale->upperBound();
1051 double closest = target;
1052 double current =
min;
1054 while ( current < max )
1057 if ( current > target )
1059 closest = ( abs( target - current + diff ) < abs( target - current ) ) ? current - diff : current;
1065 return QString::number( closest );
1070 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1072 #if defined(QWT_VERSION) && QWT_VERSION>=0x060100
1073 const QwtScaleDiv * scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1075 const QwtScaleDiv * scale = mpPlot->axisScaleDiv( QwtPlot::xBottom );
1078 if ( btnHistoMin->isChecked() )
1082 btnHistoMin->setChecked(
false );
1088 btnHistoMax->setChecked(
false );
1091 if ( QApplication::overrideCursor() )
1092 QApplication::restoreOverrideCursor();
1103 if ( leHistoMin->signalsBlocked() )
1109 int theBandNo = cboHistoBand->currentIndex() + 1;
1112 if (( !
mHistoShowMarkers && ! btnHistoMin->isChecked() && ! btnHistoMax->isChecked() ) ||
1113 ( ! mySelectedBands.isEmpty() && ! mySelectedBands.contains( theBandNo ) ) )
1123 QString minStr = leHistoMin->text();
1124 QString maxStr = leHistoMax->text();
1126 minVal = minStr.toDouble();
1128 maxVal = maxStr.toDouble();
1131 linePen.setStyle( Qt::DashLine );
1147 QList< int > mySelectedBands;
1153 mySelectedBands << cboHistoBand->currentIndex() + 1;
1161 return mySelectedBands;
1166 QList< int > mySelectedBands;
1170 mySelectedBands << -1 << -1 << -1;
1171 return mySelectedBands;
1180 for (
int i = 0; i <= 2; i++ )
1186 return mySelectedBands;
1191 QPair< QString, QString > myMinMax;
1206 for (
int i = 0; i <= 2; i++ )
1227 if ( myMinMax.first.isEmpty() )
1228 myMinMax.first = QString::number(
mHistoMin );
1229 if ( myMinMax.second.isEmpty() )
1230 myMinMax.second = QString::number(
mHistoMax );
1232 QgsDebugMsg( QString(
"bandNo %1 got min/max [%2] [%3]" ).arg( theBandNo ).arg( myMinMax.first ).arg( myMinMax.second ) );
A rectangle specified with double values.
void setColor(const QColor &)
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.
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.
double ANALYSIS_EXPORT max(double x, double y)
returns the maximum of two doubles or the first argument if both are equal
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...
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 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.
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.
double maximum
The maximum histogram value.
DataType
Raster data types.
The QgsRasterHistogram is a container for histogram of a single raster band.
int binCount
Number of bins (intervals,buckets) in histogram.
QgsRasterDataProvider * dataProvider()
Returns the data provider.
double ANALYSIS_EXPORT min(double x, double y)
returns the minimum of two doubles or the first argument if both are equal
HistogramVector histogramVector
Store the histogram for a given layer.
QPair< QString, QString > GUI_EXPORT getSaveAsImageName(QWidget *theParent, QString theMessage, QString defaultFilename)
A helper function to get an image name from the user.