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>
46 #define RASTER_HISTOGRAM_BINS 256
50 mRasterLayer( lyr ), mRendererWidget( 0 )
68 mHistoShowMarkers = settings.value(
"/Raster/histogram/showMarkers",
false ).toBool();
70 mHistoZoomToMinMax = settings.value(
"/Raster/histogram/zoomToMinMax",
false ).toBool();
79 for (
int myIteratorInt = 1;
80 myIteratorInt <= myBandCountInt;
87 leHistoMin->setValidator(
new QDoubleValidator(
this ) );
88 leHistoMax->setValidator(
new QDoubleValidator(
this ) );
94 connect( leHistoMin, SIGNAL( editingFinished() ),
this, SLOT(
applyHistoMin() ) );
95 connect( leHistoMax, SIGNAL( editingFinished() ),
this, SLOT(
applyHistoMax() ) );
98 QMenu* menu =
new QMenu(
this );
99 menu->setSeparatorsCollapsible(
false );
100 btnHistoActions->setMenu( menu );
105 group =
new QActionGroup(
this );
106 group->setExclusive(
false );
107 connect( group, SIGNAL( triggered( QAction* ) ),
this, SLOT(
histoActionTriggered( QAction* ) ) );
108 action =
new QAction(
tr(
"Min/Max options" ), group );
109 action->setSeparator(
true );
110 menu->addAction( action );
111 action =
new QAction(
tr(
"Always show min/max markers" ), group );
112 action->setData( QVariant(
"Show markers" ) );
113 action->setCheckable(
true );
115 menu->addAction( action );
116 action =
new QAction(
tr(
"Zoom to min/max" ), group );
117 action->setData( QVariant(
"Zoom min_max" ) );
118 action->setCheckable(
true );
120 menu->addAction( action );
121 action =
new QAction(
tr(
"Update style to min/max" ), group );
122 action->setData( QVariant(
"Update min_max" ) );
123 action->setCheckable(
true );
125 menu->addAction( action );
128 group =
new QActionGroup(
this );
129 group->setExclusive(
false );
130 connect( group, SIGNAL( triggered( QAction* ) ),
this, SLOT(
histoActionTriggered( QAction* ) ) );
131 action =
new QAction(
tr(
"Visibility" ), group );
132 action->setSeparator(
true );
133 menu->addAction( action );
134 group =
new QActionGroup(
this );
135 group->setExclusive(
true );
136 connect( group, SIGNAL( triggered( QAction* ) ),
this, SLOT(
histoActionTriggered( QAction* ) ) );
137 action =
new QAction(
tr(
"Show all bands" ), group );
138 action->setData( QVariant(
"Show all" ) );
139 action->setCheckable(
true );
141 menu->addAction( action );
142 action =
new QAction(
tr(
"Show RGB/Gray band(s)" ), group );
143 action->setData( QVariant(
"Show RGB" ) );
144 action->setCheckable(
true );
146 menu->addAction( action );
147 action =
new QAction(
tr(
"Show selected band" ), group );
148 action->setData( QVariant(
"Show selected" ) );
149 action->setCheckable(
true );
151 menu->addAction( action );
154 action =
new QAction(
tr(
"Actions" ), group );
155 action->setSeparator(
true );
156 menu->addAction( action );
159 group =
new QActionGroup(
this );
160 group->setExclusive(
false );
161 connect( group, SIGNAL( triggered( QAction* ) ),
this, SLOT(
histoActionTriggered( QAction* ) ) );
162 action =
new QAction(
tr(
"Reset" ), group );
163 action->setData( QVariant(
"Load reset" ) );
164 menu->addAction( action );
169 action =
new QAction(
tr(
"Load min/max" ), group );
170 action->setSeparator(
true );
171 menu->addAction( action );
172 action =
new QAction(
tr(
"Estimate (faster)" ), group );
173 action->setData( QVariant(
"Load estimate" ) );
174 menu->addAction( action );
175 action =
new QAction(
tr(
"Actual (slower)" ), group );
176 action->setData( QVariant(
"Load actual" ) );
177 menu->addAction( action );
178 action =
new QAction(
tr(
"Current extent" ), group );
179 action->setData( QVariant(
"Load extent" ) );
180 menu->addAction( action );
181 action =
new QAction(
tr(
"Use stddev (1.0)" ), group );
182 action->setData( QVariant(
"Load 1 stddev" ) );
183 menu->addAction( action );
184 action =
new QAction(
tr(
"Use stddev (custom)" ), group );
185 action->setData( QVariant(
"Load stddev" ) );
186 menu->addAction( action );
187 action =
new QAction(
tr(
"Load for each band" ), group );
188 action->setData( QVariant(
"Load apply all" ) );
189 action->setCheckable(
true );
190 action->setChecked( mHistoLoadApplyAll );
191 menu->addAction( action );
195 action =
new QAction(
tr(
"Recompute Histogram" ), group );
196 action->setData( QVariant(
"Compute histogram" ) );
197 menu->addAction( action );
225 if ( QApplication::overrideCursor() )
226 QApplication::restoreOverrideCursor();
227 btnHistoMin->setChecked(
false );
228 btnHistoMax->setChecked(
false );
250 if ( ! forceComputeFlag )
252 for (
int myIteratorInt = 1;
253 myIteratorInt <= myBandCountInt;
257 int sampleSize = 250000;
260 QgsDebugMsg( QString(
"band %1 does not have cached histo" ).arg( myIteratorInt ) );
267 stackedWidget2->setCurrentIndex( 1 );
268 connect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
269 QApplication::setOverrideCursor( Qt::WaitCursor );
271 for (
int myIteratorInt = 1;
272 myIteratorInt <= myBandCountInt;
276 int sampleSize = 250000;
280 disconnect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
282 stackedWidget2->setCurrentIndex( 0 );
283 QApplication::restoreOverrideCursor();
307 QgsDebugMsg( QString(
"raster does not have cached histogram" ) );
308 stackedWidget2->setCurrentIndex( 2 );
312 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
313 mpPlot->detachItems();
318 mpPlot->setAutoDelete(
true );
319 mpPlot->setTitle(
QObject::tr(
"Raster Histogram" ) );
320 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
322 mpPlot->setAxisTitle( QwtPlot::xBottom,
QObject::tr(
"Pixel Value" ) );
323 mpPlot->setAxisTitle( QwtPlot::yLeft,
QObject::tr(
"Frequency" ) );
324 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
328 QwtPlotGrid * myGrid =
new QwtPlotGrid();
329 myGrid->attach( mpPlot );
334 QVector<QColor> myColors;
335 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
336 srand( myBandCountInt * 100 );
337 while ( myColors.size() <= myBandCountInt )
340 QColor( 1 + (
int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) ),
341 1 + (
int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) ),
342 1 + (
int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) ) );
350 int myGrayBand = mySelectedBands[0];
351 for (
int i = 1; i <= myBandCountInt; i++ )
353 if ( i == myGrayBand )
356 cboHistoBand->setItemData( i - 1, Qt::darkGray, Qt::ForegroundRole );
360 if ( ! myColors.isEmpty() )
363 myColors.pop_front();
369 cboHistoBand->setItemData( i - 1, Qt::black, Qt::ForegroundRole );
376 int myRedBand = mySelectedBands[0];
377 int myGreenBand = mySelectedBands[1];
378 int myBlueBand = mySelectedBands[2];
381 myColors.remove( 0, 3 );
382 for (
int i = 1; i <= myBandCountInt; i++ )
385 if ( i == myRedBand )
387 else if ( i == myGreenBand )
389 else if ( i == myBlueBand )
393 if ( ! myColors.isEmpty() )
395 myColor = myColors.first();
396 myColors.pop_front();
402 cboHistoBand->setItemData( i - 1, Qt::black, Qt::ForegroundRole );
404 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
406 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
428 bool myFirstIteration =
true;
431 double myBinXStep = 1;
434 for (
int myIteratorInt = 1;
435 myIteratorInt <= myBandCountInt;
441 if ( ! mySelectedBands.contains( myIteratorInt ) )
444 int sampleSize = 250000;
449 QwtPlotCurve * mypCurve =
new QwtPlotCurve(
tr(
"Band %1" ).arg( myIteratorInt ) );
451 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
452 mypCurve->setPen( QPen(
mHistoColors.at( myIteratorInt ) ) );
453 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
454 QVector<QPointF> data;
456 QVector<double> myX2Data;
457 QVector<double> myY2Data;
464 myBinXStep = ( myHistogram.
maximum - myHistogram.
minimum ) / BINCOUNT;
465 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
473 for (
int myBin = 0; myBin < BINCOUNT; myBin++ )
477 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
478 data << QPointF( myBinX, myBinValue );
480 myX2Data.append(
double( myBinX ) );
481 myY2Data.append(
double( myBinValue ) );
483 myBinX += myBinXStep;
485 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
486 mypCurve->setSamples( data );
488 mypCurve->setData( myX2Data, myY2Data );
490 mypCurve->attach( mpPlot );
500 myFirstIteration =
false;
506 mpPlot->setAxisScale( QwtPlot::xBottom,
526 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
528 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
529 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
532 mHistoPicker->setSelectionFlags( QwtPicker::PointSelection | QwtPicker::DragSelection );
541 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
542 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
544 mHistoZoomer->setSelectionFlags( QwtPicker::RectSelection | QwtPicker::DragSelection );
550 disconnect(
mRasterLayer, SIGNAL( progressUpdate(
int ) ), mHistogramProgress, SLOT( setValue(
int ) ) );
551 stackedWidget2->setCurrentIndex( 0 );
555 QApplication::restoreOverrideCursor();
566 QFileInfo myInfo( myFileNameAndFilter.first );
567 if ( QFileInfo( myFileNameAndFilter.first ).baseName() !=
"" )
574 int width,
int height,
int quality )
577 QFileInfo myInfo( theFilename );
578 QDir myDir( myInfo.dir() );
579 if ( ! myDir.exists() )
581 QgsDebugMsg( QString(
"Error, directory %1 non-existent (theFilename = %2)" ).arg( myDir.absolutePath() ).arg( theFilename ) );
586 QPixmap myPixmap( width, height );
587 QRect myQRect( 5, 5, width - 10, height - 10 );
588 myPixmap.fill( Qt::white );
590 #if defined(QWT_VERSION) && QWT_VERSION>=0x060000
591 QwtPlotRenderer myRenderer;
592 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground |
593 QwtPlotRenderer::DiscardCanvasBackground );
594 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
597 myPainter.begin( &myPixmap );
598 myRenderer.render( mpPlot, &myPainter, myQRect );
601 QwtPlotPrintFilter myFilter;
602 int myOptions = QwtPlotPrintFilter::PrintAll;
603 myOptions &= ~QwtPlotPrintFilter::PrintBackground;
604 myOptions |= QwtPlotPrintFilter::PrintFrameWithScales;
605 myFilter.setOptions( myOptions );
608 myPainter.begin( &myPixmap );
609 mpPlot->print( &myPainter, myQRect, myFilter );
619 myPixmap.save( theFilename, 0, quality );
627 cboHistoBand->setCurrentIndex( theBandNo - 1 );
636 index = cboHistoBand->currentIndex();
644 btnHistoMin->setEnabled(
true );
645 btnHistoMax->setEnabled(
true );
648 leHistoMin->setText( myMinMax.first );
649 leHistoMax->setText( myMinMax.second );
659 histoAction( action->data().toString(), action->isChecked() );
664 if ( actionName ==
"" )
668 QgsDebugMsg( QString(
"band = %1 action = %2" ).arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ) );
671 if ( actionName ==
"Show markers" )
679 else if ( actionName ==
"Zoom min_max" )
686 else if ( actionName ==
"Update min_max" )
693 else if ( actionName ==
"Show all" )
700 else if ( actionName ==
"Show selected" )
707 else if ( actionName ==
"Show RGB" )
715 else if ( actionName ==
"Load apply all" )
717 mHistoLoadApplyAll = actionFlag;
718 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
726 QVector<int> myBands;
730 double minMaxValues[2];
733 if ( mHistoLoadApplyAll )
736 for (
int i = 1; i <= myBandCountInt; i++ )
738 if ( i != cboHistoBand->currentIndex() + 1 )
745 myBands << cboHistoBand->currentIndex() + 1;
757 leHistoMin->blockSignals(
true );
758 leHistoMax->blockSignals(
true );
761 foreach (
int theBandNo, myBands )
765 if ( actionName ==
"Load actual" )
768 theBandNo, minMaxValues );
770 else if ( actionName ==
"Load estimate" )
773 theBandNo, minMaxValues );
775 else if ( actionName ==
"Load extent" )
778 theBandNo, minMaxValues );
780 else if ( actionName ==
"Load 1 stddev" ||
781 actionName ==
"Load stddev" )
783 ok =
mRendererWidget->bandMinMaxFromStdDev( myStdDev, theBandNo, minMaxValues );
788 cboHistoBand->setCurrentIndex( theBandNo - 1 );
789 if ( !ok || actionName ==
"Load reset" )
803 leHistoMin->setText( QString::number( minMaxValues[0] ) );
804 leHistoMax->setText( QString::number( minMaxValues[1] ) );
811 leHistoMin->blockSignals(
false );
812 leHistoMax->blockSignals(
false );
815 else if ( actionName ==
"Compute histogram" )
831 int theBandNo = cboHistoBand->currentIndex() + 1;
834 for (
int i = 0; i <= mySelectedBands.size(); i++ )
838 min = leHistoMin->text();
849 rect.setLeft( min.toDouble() );
860 int theBandNo = cboHistoBand->currentIndex() + 1;
863 for (
int i = 0; i <= mySelectedBands.size(); i++ )
867 max = leHistoMax->text();
878 rect.setRight( max.toDouble() );
887 if ( QApplication::overrideCursor() )
888 QApplication::restoreOverrideCursor();
889 if ( btnHistoMin->isChecked() )
891 btnHistoMax->setChecked(
false );
892 QApplication::setOverrideCursor( Qt::PointingHandCursor );
905 if ( QApplication::overrideCursor() )
906 QApplication::restoreOverrideCursor();
907 if ( btnHistoMax->isChecked() )
909 btnHistoMin->setChecked(
false );
910 QApplication::setOverrideCursor( Qt::PointingHandCursor );
923 if ( !scale )
return "";
925 QList< double > minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
926 QList< double > majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
927 double diff = ( minorTicks[1] - minorTicks[0] ) / div;
928 double min = majorTicks[0] - diff;
930 min -= ( majorTicks[1] - majorTicks[0] );
931 #if defined(QWT_VERSION) && QWT_VERSION<0x050200
932 double max = scale->hBound();
934 double max = scale->upperBound();
936 double closest = target;
937 double current =
min;
939 while ( current < max )
942 if ( current > target )
944 closest = ( abs( target - current + diff ) < abs( target - current ) ) ? current - diff : current;
950 return QString::number( closest );
955 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
957 #if defined(QWT_VERSION) && QWT_VERSION>=0x060100
958 const QwtScaleDiv * scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
960 const QwtScaleDiv * scale = mpPlot->axisScaleDiv( QwtPlot::xBottom );
963 if ( btnHistoMin->isChecked() )
967 btnHistoMin->setChecked(
false );
973 btnHistoMax->setChecked(
false );
976 if ( QApplication::overrideCursor() )
977 QApplication::restoreOverrideCursor();
988 if ( leHistoMin->signalsBlocked() )
994 int theBandNo = cboHistoBand->currentIndex() + 1;
997 if (( !
mHistoShowMarkers && ! btnHistoMin->isChecked() && ! btnHistoMax->isChecked() ) ||
998 ( ! mySelectedBands.isEmpty() && ! mySelectedBands.contains( theBandNo ) ) )
1008 QString minStr = leHistoMin->text();
1009 QString maxStr = leHistoMax->text();
1011 minVal = minStr.toDouble();
1013 maxVal = maxStr.toDouble();
1016 linePen.setStyle( Qt::DashLine );
1032 QList< int > mySelectedBands;
1038 mySelectedBands << cboHistoBand->currentIndex() + 1;
1046 return mySelectedBands;
1051 QList< int > mySelectedBands;
1055 mySelectedBands << -1 << -1 << -1;
1056 return mySelectedBands;
1065 for (
int i = 0; i <= 2; i++ )
1071 return mySelectedBands;
1076 QPair< QString, QString > myMinMax;
1091 for (
int i = 0; i <= 2; i++ )
1112 if ( myMinMax.first.isEmpty() )
1113 myMinMax.first = QString::number(
mHistoMin );
1114 if ( myMinMax.second.isEmpty() )
1115 myMinMax.second = QString::number(
mHistoMax );
1117 QgsDebugMsg( QString(
"bandNo %1 got min/max [%2] [%3]" ).arg( theBandNo ).arg( myMinMax.first ).arg( myMinMax.second ) );