22#include "moc_qgsrasterhistogramwidget.cpp"
32#include <QActionGroup>
33#include <QRandomGenerator>
36#include <qwt_global.h>
37#include <qwt_plot_canvas.h>
38#include <qwt_legend.h>
40#include <qwt_plot_curve.h>
41#include <qwt_plot_grid.h>
42#include <qwt_plot_marker.h>
43#include <qwt_plot_picker.h>
44#include <qwt_picker_machine.h>
45#include <qwt_plot_zoomer.h>
46#include <qwt_plot_layout.h>
47#include <qwt_plot_renderer.h>
48#include <qwt_plot_histogram.h>
49#include <qwt_scale_div.h>
63 connect( mSaveAsImageButton, &QToolButton::clicked,
this, &QgsRasterHistogramWidget::mSaveAsImageButton_clicked );
64 connect( cboHistoBand,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged );
65 connect( btnHistoMin, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMin_toggled );
66 connect( btnHistoMax, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMax_toggled );
67 connect( btnHistoCompute, &QPushButton::clicked,
this, &QgsRasterHistogramWidget::btnHistoCompute_clicked );
71 mRendererWidget =
nullptr;
72 mRendererName = QStringLiteral(
"singlebandgray" );
77 mHistoPicker =
nullptr;
78 mHistoZoomer =
nullptr;
79 mHistoMarkerMin =
nullptr;
80 mHistoMarkerMax =
nullptr;
83 mHistoShowMarkers = settings.
value( QStringLiteral(
"Raster/histogram/showMarkers" ),
false ).toBool();
85 mHistoZoomToMinMax = settings.
value( QStringLiteral(
"Raster/histogram/zoomToMinMax" ),
false ).toBool();
86 mHistoUpdateStyleToMinMax = settings.
value( QStringLiteral(
"Raster/histogram/updateStyleToMinMax" ),
true ).toBool();
87 mHistoDrawLines = settings.
value( QStringLiteral(
"Raster/histogram/drawLines" ),
true ).toBool();
89 mHistoShowBands = ShowAll;
95 const int myBandCountInt = mRasterLayer->
bandCount();
96 for (
int myIteratorInt = 1;
97 myIteratorInt <= myBandCountInt;
100 cboHistoBand->addItem( mRasterLayer->
bandName( myIteratorInt ) );
117 connect( leHistoMin, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMin );
118 connect( leHistoMax, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMax );
122 QMenu *menu =
new QMenu(
this );
123 menu->setSeparatorsCollapsible(
false );
124 btnHistoActions->setMenu( menu );
125 QActionGroup *group =
nullptr;
126 QAction *action =
nullptr;
129 group =
new QActionGroup(
this );
130 group->setExclusive(
false );
131 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
132 action =
new QAction( tr(
"Min/Max options" ), group );
133 action->setSeparator(
true );
134 menu->addAction( action );
135 action =
new QAction( tr(
"Always show min/max markers" ), group );
136 action->setData( QVariant(
"Show markers" ) );
137 action->setCheckable(
true );
138 action->setChecked( mHistoShowMarkers );
139 menu->addAction( action );
140 action =
new QAction( tr(
"Zoom to min/max" ), group );
141 action->setData( QVariant(
"Zoom min_max" ) );
142 action->setCheckable(
true );
143 action->setChecked( mHistoZoomToMinMax );
144 menu->addAction( action );
145 action =
new QAction( tr(
"Update style to min/max" ), group );
146 action->setData( QVariant(
"Update min_max" ) );
147 action->setCheckable(
true );
148 action->setChecked( mHistoUpdateStyleToMinMax );
149 menu->addAction( action );
152 group =
new QActionGroup(
this );
153 group->setExclusive(
false );
154 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
155 action =
new QAction( tr(
"Visibility" ), group );
156 action->setSeparator(
true );
157 menu->addAction( action );
158 group =
new QActionGroup(
this );
159 group->setExclusive(
true );
160 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
161 action =
new QAction( tr(
"Show all bands" ), group );
162 action->setData( QVariant(
"Show all" ) );
163 action->setCheckable(
true );
164 action->setChecked( mHistoShowBands == ShowAll );
165 menu->addAction( action );
166 action =
new QAction( tr(
"Show RGB/Gray band(s)" ), group );
167 action->setData( QVariant(
"Show RGB" ) );
168 action->setCheckable(
true );
169 action->setChecked( mHistoShowBands == ShowRGB );
170 menu->addAction( action );
171 action =
new QAction( tr(
"Show selected band" ), group );
172 action->setData( QVariant(
"Show selected" ) );
173 action->setCheckable(
true );
174 action->setChecked( mHistoShowBands == ShowSelected );
175 menu->addAction( action );
178 group =
new QActionGroup(
this );
179 group->setExclusive(
false );
180 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
181 action =
new QAction( tr(
"Display" ), group );
182 action->setSeparator(
true );
183 menu->addAction( action );
185 action =
new QAction( QString(), group );
186 action->setData( QVariant(
"Draw lines" ) );
189 action->setText( tr(
"Draw as lines" ) );
190 action->setCheckable(
true );
191 action->setChecked( mHistoDrawLines );
195 action->setText( tr(
"Draw as lines (only int layers)" ) );
196 action->setEnabled(
false );
198 menu->addAction( action );
201 action =
new QAction( tr(
"Actions" ), group );
202 action->setSeparator(
true );
203 menu->addAction( action );
206 group =
new QActionGroup(
this );
207 group->setExclusive(
false );
208 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
209 action =
new QAction( tr(
"Reset" ), group );
210 action->setData( QVariant(
"Load reset" ) );
211 menu->addAction( action );
217 action =
new QAction( tr(
"Load min/max" ), group );
218 action->setSeparator(
true );
219 menu->addAction( action );
220 action =
new QAction( tr(
"Estimate (faster)" ), group );
221 action->setData( QVariant(
"Load estimate" ) );
222 menu->addAction( action );
223 action =
new QAction( tr(
"Actual (slower)" ), group );
224 action->setData( QVariant(
"Load actual" ) );
225 menu->addAction( action );
226 action =
new QAction( tr(
"Current extent" ), group );
227 action->setData( QVariant(
"Load extent" ) );
228 menu->addAction( action );
229 action =
new QAction( tr(
"Use stddev (1.0)" ), group );
230 action->setData( QVariant(
"Load 1 stddev" ) );
231 menu->addAction( action );
232 action =
new QAction( tr(
"Use stddev (custom)" ), group );
233 action->setData( QVariant(
"Load stddev" ) );
234 menu->addAction( action );
235 action =
new QAction( tr(
"Load for each band" ), group );
236 action->setData( QVariant(
"Load apply all" ) );
237 action->setCheckable(
true );
238 action->setChecked( mHistoLoadApplyAll );
239 menu->addAction( action );
243 action =
new QAction( tr(
"Recompute Histogram" ), group );
244 action->setData( QVariant(
"Compute histogram" ) );
245 menu->addAction( action );
253 mRendererName = name;
254 mRendererWidget = rendererWidget;
256 cboHistoBand_currentIndexChanged( -1 );
264 cboHistoBand_currentIndexChanged( -1 );
268 if ( QApplication::overrideCursor() )
269 QApplication::restoreOverrideCursor();
270 btnHistoMin->setChecked(
false );
271 btnHistoMax->setChecked(
false );
275void QgsRasterHistogramWidget::btnHistoCompute_clicked()
304 xRes = yRes = std::sqrt( (
static_cast<double>( extent.width( ) ) * extent.height() ) / sampleSize );
309 const double srcXRes = extent.width() / rasterInterface->
xSize();
310 const double srcYRes = extent.height() / rasterInterface->
ySize();
311 if ( xRes < srcXRes ) xRes = srcXRes;
312 if ( yRes < srcYRes ) yRes = srcYRes;
315 const int histogramWidth =
static_cast <int>( extent.width() / xRes );
316 const int histogramHeight =
static_cast <int>( extent.height() / yRes );
318 int binCount =
static_cast<int>( std::min(
static_cast<qint64
>( 1000 ),
319 static_cast<qint64
>( histogramWidth ) * histogramHeight ) );
324 binCount =
static_cast<int>( std::min(
static_cast<qint64
>( binCount ),
325 static_cast<qint64
>( std::ceil( statsMax - statsMin + 1 ) ) ) );
336 const int myBandCountInt = mRasterLayer->
bandCount();
339 if ( ! forceComputeFlag )
341 for (
int myIteratorInt = 1;
342 myIteratorInt <= myBandCountInt;
346 const int binCount = getBinCount( mRasterLayer->
dataProvider(), myIteratorInt, sampleSize );
347 if ( !mRasterLayer->
dataProvider()->
hasHistogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize ) )
349 QgsDebugMsgLevel( QStringLiteral(
"band %1 does not have cached histo" ).arg( myIteratorInt ), 2 );
356 stackedWidget2->setCurrentIndex( 1 );
360 QApplication::setOverrideCursor( Qt::WaitCursor );
362 for (
int myIteratorInt = 1;
363 myIteratorInt <= myBandCountInt;
367 const int binCount = getBinCount( mRasterLayer->
dataProvider(), myIteratorInt, sampleSize );
368 mRasterLayer->
dataProvider()->
histogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
372 stackedWidget2->setCurrentIndex( 0 );
373 QApplication::restoreOverrideCursor();
390 const int myBandCountInt = mRasterLayer->
bandCount();
395 QgsDebugMsgLevel( QStringLiteral(
"raster does not have cached histogram" ), 2 );
396 stackedWidget2->setCurrentIndex( 2 );
401 mpPlot->detachItems();
404 mpPlot->setAutoDelete(
true );
405 mpPlot->setTitle( QObject::tr(
"Raster Histogram" ) );
406 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
408 mpPlot->setAxisTitle( QwtPlot::xBottom, QObject::tr(
"Pixel Value" ) );
409 mpPlot->setAxisTitle( QwtPlot::yLeft, QObject::tr(
"Frequency" ) );
410 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
414 QwtPlotGrid *myGrid =
new QwtPlotGrid();
415 myGrid->attach( mpPlot );
418 mHistoColors.clear();
419 mHistoColors << Qt::black;
420 QVector<QColor> myColors;
421 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
424 QRandomGenerator colorGenerator( myBandCountInt * 100 );
425 while ( myColors.size() <= myBandCountInt )
428 QColor( colorGenerator.bounded( 1, 256 ),
429 colorGenerator.bounded( 1, 256 ),
430 colorGenerator.bounded( 1, 256 ) );
435 QList< int > mySelectedBands = rendererSelectedBands();
436 if ( mRendererName == QLatin1String(
"singlebandgray" ) )
438 const int myGrayBand = mySelectedBands[0];
439 for (
int i = 1; i <= myBandCountInt; i++ )
441 if ( i == myGrayBand )
443 mHistoColors << Qt::darkGray;
444 cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
448 if ( ! myColors.isEmpty() )
450 mHistoColors << myColors.first();
451 myColors.pop_front();
455 mHistoColors << Qt::black;
457 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
462 else if ( mRendererName == QLatin1String(
"multibandcolor" ) )
464 const int myRedBand = mySelectedBands[0];
465 const int myGreenBand = mySelectedBands[1];
466 const int myBlueBand = mySelectedBands[2];
469 myColors.remove( 0, 3 );
470 for (
int i = 1; i <= myBandCountInt; i++ )
473 if ( i == myRedBand )
475 else if ( i == myGreenBand )
477 else if ( i == myBlueBand )
481 if ( ! myColors.isEmpty() )
483 myColor = myColors.first();
484 myColors.pop_front();
490 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
492 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
494 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
496 mHistoColors << myColor;
501 mHistoColors << myColors;
516 bool myFirstIteration =
true;
518 mySelectedBands = histoSelectedBands();
519 double myBinXStep = 1;
522 for (
int bandNumber = 1;
523 bandNumber <= myBandCountInt;
527 if ( mHistoShowBands != ShowAll )
529 if ( ! mySelectedBands.contains( bandNumber ) )
538 const int binCount = getBinCount( mRasterLayer->
dataProvider(), bandNumber, sampleSize );
541 QgsDebugMsgLevel( QStringLiteral(
"got raster histo for band %1 : min=%2 max=%3 count=%4" ).arg( bandNumber ).arg( myHistogram.
minimum ).arg( myHistogram.
maximum ).arg( myHistogram.
binCount ), 2 );
544 bool myDrawLines =
true;
545 if ( ! mHistoDrawLines &&
553 QwtPlotCurve *mypCurve =
nullptr;
556 mypCurve =
new QwtPlotCurve( tr(
"Band %1" ).arg( bandNumber ) );
558 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
559 mypCurve->setPen( QPen( mHistoColors.at( bandNumber ) ) );
562 QwtPlotHistogram *mypHisto =
nullptr;
565 mypHisto =
new QwtPlotHistogram( tr(
"Band %1" ).arg( bandNumber ) );
566 mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
568 mypHisto->setPen( QPen( Qt::lightGray ) );
570 mypHisto->setBrush( QBrush( mHistoColors.at( bandNumber ) ) );
573 QVector<QPointF> data;
574 QVector<QwtIntervalSample> dataHisto;
578 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
580 for (
int myBin = 0; myBin < myHistogram.
binCount; myBin++ )
585 data << QPointF( myBinX, myBinValue );
589 dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
591 myBinX += myBinXStep;
596 mypCurve->setSamples( data );
597 mypCurve->attach( mpPlot );
601 mypHisto->setSamples( dataHisto );
602 mypHisto->attach( mpPlot );
605 if ( myFirstIteration || mHistoMin > myHistogram.
minimum )
607 mHistoMin = myHistogram.
minimum;
609 if ( myFirstIteration || mHistoMax < myHistogram.
maximum )
611 mHistoMax = myHistogram.
maximum;
613 QgsDebugMsgLevel( QStringLiteral(
"computed histo min = %1 max = %2" ).arg( mHistoMin ).arg( mHistoMax ), 2 );
614 myFirstIteration =
false;
617 if ( mHistoMin < mHistoMax )
623 mpPlot->setAxisScale( QwtPlot::xBottom,
624 mHistoMin - myBinXStep / 2,
625 mHistoMax + myBinXStep / 2 );
626 mpPlot->setEnabled(
true );
631 mHistoMarkerMin =
new QwtPlotMarker();
632 mHistoMarkerMin->attach( mpPlot );
633 mHistoMarkerMax =
new QwtPlotMarker();
634 mHistoMarkerMax->attach( mpPlot );
635 updateHistoMarkers();
640 mHistoPicker =
new QwtPlotPicker( mpPlot->canvas() );
642 mHistoPicker->setTrackerMode( QwtPicker::AlwaysOff );
643 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
644 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
645 connect( mHistoPicker,
static_cast < void ( QwtPlotPicker::* )(
const QPointF & )
> ( &QwtPlotPicker::selected ),
this, &QgsRasterHistogramWidget::histoPickerSelected );
647 mHistoPicker->setEnabled(
false );
652 mHistoZoomer =
new QwtPlotZoomer( mpPlot->canvas() );
653 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
654 mHistoZoomer->setTrackerMode( QwtPicker::AlwaysOff );
656 mHistoZoomer->setEnabled(
true );
660 mpPlot->setDisabled(
true );
662 mHistoPicker->setEnabled(
false );
664 mHistoZoomer->setEnabled(
false );
667 stackedWidget2->setCurrentIndex( 0 );
671 QApplication::restoreOverrideCursor();
674void QgsRasterHistogramWidget::mSaveAsImageButton_clicked()
680 const QFileInfo myInfo( myFileNameAndFilter.first );
681 if ( !myInfo.baseName().isEmpty() )
688 int width,
int height,
int quality )
691 const QFileInfo myInfo( filename );
692 const QDir myDir( myInfo.dir() );
693 if ( ! myDir.exists() )
695 QgsDebugError( QStringLiteral(
"Error, directory %1 non-existent (theFilename = %2)" ).arg( myDir.absolutePath(), filename ) );
700 QPixmap myPixmap( width, height );
701 const QRect myQRect( 5, 5, width - 10, height - 10 );
702 myPixmap.fill( Qt::white );
704 QwtPlotRenderer myRenderer;
705 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground |
706 QwtPlotRenderer::DiscardCanvasBackground );
707 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
710 myPainter.begin( &myPixmap );
711 myRenderer.render( mpPlot, &myPainter, myQRect );
715 myPixmap.save( filename,
nullptr, quality );
723 cboHistoBand->setCurrentIndex( bandNo - 1 );
726void QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged(
int index )
728 if ( mHistoShowBands == ShowSelected )
732 index = cboHistoBand->currentIndex();
735 mHistoPicker->setEnabled(
false );
736 mHistoPicker->setRubberBandPen( QPen( mHistoColors.at( index + 1 ) ) );
739 mHistoZoomer->setEnabled(
true );
740 btnHistoMin->setEnabled(
true );
741 btnHistoMax->setEnabled(
true );
743 const QPair< QString, QString > myMinMax = rendererMinMax( index + 1 );
744 leHistoMin->setText( myMinMax.first );
745 leHistoMax->setText( myMinMax.second );
751void QgsRasterHistogramWidget::histoActionTriggered( QAction *action )
755 histoAction( action->data().toString(), action->isChecked() );
760 if ( actionName.isEmpty() )
764 QgsDebugMsgLevel( QStringLiteral(
"band = %1 action = %2" ).arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ), 2 );
767 if ( actionName == QLatin1String(
"Show markers" ) )
769 mHistoShowMarkers = actionFlag;
771 settings.
setValue( QStringLiteral(
"Raster/histogram/showMarkers" ), mHistoShowMarkers );
772 updateHistoMarkers();
775 else if ( actionName == QLatin1String(
"Zoom min_max" ) )
777 mHistoZoomToMinMax = actionFlag;
779 settings.
setValue( QStringLiteral(
"Raster/histogram/zoomToMinMax" ), mHistoZoomToMinMax );
782 else if ( actionName == QLatin1String(
"Update min_max" ) )
784 mHistoUpdateStyleToMinMax = actionFlag;
786 settings.
setValue( QStringLiteral(
"Raster/histogram/updateStyleToMinMax" ), mHistoUpdateStyleToMinMax );
789 else if ( actionName == QLatin1String(
"Show all" ) )
791 mHistoShowBands = ShowAll;
796 else if ( actionName == QLatin1String(
"Show selected" ) )
798 mHistoShowBands = ShowSelected;
803 else if ( actionName == QLatin1String(
"Show RGB" ) )
805 mHistoShowBands = ShowRGB;
810 else if ( actionName == QLatin1String(
"Draw lines" ) )
812 mHistoDrawLines = actionFlag;
814 settings.
setValue( QStringLiteral(
"Raster/histogram/drawLines" ), mHistoDrawLines );
815 btnHistoCompute_clicked();
819 else if ( actionName ==
"Load apply all" )
821 mHistoLoadApplyAll = actionFlag;
822 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
828 else if ( actionName.left( 5 ) == QLatin1String(
"Load " ) && mRendererWidget )
830 QVector<int> myBands;
834 double minMaxValues[2];
837 if ( mHistoLoadApplyAll )
839 int myBandCountInt = mRasterLayer->
bandCount();
840 for (
int i = 1; i <= myBandCountInt; i++ )
842 if ( i != cboHistoBand->currentIndex() + 1 )
849 myBands << cboHistoBand->currentIndex() + 1;
853 double myStdDev = 1.0;
854 if ( actionName ==
"Load stddev" )
856 myStdDev = mRendererWidget->
stdDev().toDouble();
861 leHistoMin->blockSignals(
true );
862 leHistoMax->blockSignals(
true );
865 const auto constMyBands = myBands;
866 for (
const int bandNo : constMyBands )
870 if ( actionName ==
"Load actual" )
872 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Actual,
873 bandNo, minMaxValues );
875 else if ( actionName ==
"Load estimate" )
877 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Estimate,
878 bandNo, minMaxValues );
880 else if ( actionName ==
"Load extent" )
882 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::CurrentExtent,
883 bandNo, minMaxValues );
885 else if ( actionName ==
"Load 1 stddev" ||
886 actionName ==
"Load stddev" )
888 ok = mRendererWidget->bandMinMaxFromStdDev( myStdDev, bandNo, minMaxValues );
893 cboHistoBand->setCurrentIndex( bandNo - 1 );
894 if ( !ok || actionName == QLatin1String(
"Load reset" ) )
908 leHistoMin->setText( QString::number( minMaxValues[0] ) );
909 leHistoMax->setText( QString::number( minMaxValues[1] ) );
916 leHistoMin->blockSignals(
false );
917 leHistoMax->blockSignals(
false );
918 updateHistoMarkers();
920 else if ( actionName == QLatin1String(
"Compute histogram" ) )
922 btnHistoCompute_clicked();
931void QgsRasterHistogramWidget::applyHistoMin()
933 if ( ! mRendererWidget )
936 const int bandNo = cboHistoBand->currentIndex() + 1;
937 const QList< int > selectedBands = rendererSelectedBands();
939 for (
int i = 0; i <= selectedBands.size(); i++ )
943 min = leHistoMin->text();
944 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
min( i ) != min )
946 mRendererWidget->
setMin( min, i );
959 updateHistoMarkers();
961 if ( ! min.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
963 QRectF rect = mHistoZoomer->zoomRect();
964 rect.setLeft( min.toDouble() );
965 mHistoZoomer->zoom( rect );
970void QgsRasterHistogramWidget::applyHistoMax()
972 if ( ! mRendererWidget )
975 const int bandNo = cboHistoBand->currentIndex() + 1;
976 const QList< int > mySelectedBands = rendererSelectedBands();
978 for (
int i = 0; i <= mySelectedBands.size(); i++ )
982 max = leHistoMax->text();
983 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
max( i ) != max )
985 mRendererWidget->
setMax( max, i );
998 updateHistoMarkers();
1000 if ( ! max.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
1002 QRectF rect = mHistoZoomer->zoomRect();
1003 rect.setRight( max.toDouble() );
1004 mHistoZoomer->zoom( rect );
1009void QgsRasterHistogramWidget::btnHistoMin_toggled()
1011 if ( mpPlot && mHistoPicker )
1013 if ( QApplication::overrideCursor() )
1014 QApplication::restoreOverrideCursor();
1015 if ( btnHistoMin->isChecked() )
1017 btnHistoMax->setChecked(
false );
1018 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1021 mHistoZoomer->setEnabled( ! btnHistoMin->isChecked() );
1022 mHistoPicker->setEnabled( btnHistoMin->isChecked() );
1024 updateHistoMarkers();
1027void QgsRasterHistogramWidget::btnHistoMax_toggled()
1029 if ( mpPlot && mHistoPicker )
1031 if ( QApplication::overrideCursor() )
1032 QApplication::restoreOverrideCursor();
1033 if ( btnHistoMax->isChecked() )
1035 btnHistoMin->setChecked(
false );
1036 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1039 mHistoZoomer->setEnabled( ! btnHistoMax->isChecked() );
1040 mHistoPicker->setEnabled( btnHistoMax->isChecked() );
1042 updateHistoMarkers();
1049 if ( !scale )
return QString();
1051 QList< double > minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1052 QList< double > majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1053 const double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1054 double min = majorTicks[0] - diff;
1056 min -= ( majorTicks[1] - majorTicks[0] );
1057 const double max = scale->upperBound();
1058 double closest = target;
1059 double current = min;
1061 while ( current < max )
1064 if ( current > target )
1066 closest = ( std::fabs( target - current + diff ) < std::fabs( target - current ) ) ? current - diff : current;
1072 return QLocale().toString( closest );
1075void QgsRasterHistogramWidget::histoPickerSelected( QPointF pos )
1077 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1079 const QwtScaleDiv *scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1081 if ( btnHistoMin->isChecked() )
1085 btnHistoMin->setChecked(
false );
1091 btnHistoMax->setChecked(
false );
1094 if ( QApplication::overrideCursor() )
1095 QApplication::restoreOverrideCursor();
1098void QgsRasterHistogramWidget::histoPickerSelectedQwt5(
QwtDoublePoint pos )
1100 histoPickerSelected( QPointF( pos.x(), pos.y() ) );
1103void QgsRasterHistogramWidget::updateHistoMarkers()
1106 if ( leHistoMin->signalsBlocked() )
1109 if ( !mpPlot || !mHistoMarkerMin || !mHistoMarkerMax )
1112 const int bandNo = cboHistoBand->currentIndex() + 1;
1113 const QList< int > mySelectedBands = histoSelectedBands();
1115 if ( ( ! mHistoShowMarkers && ! btnHistoMin->isChecked() && ! btnHistoMax->isChecked() ) ||
1116 ( ! mySelectedBands.isEmpty() && ! mySelectedBands.contains( bandNo ) ) )
1118 mHistoMarkerMin->hide();
1119 mHistoMarkerMax->hide();
1124 double minVal = mHistoMin;
1125 double maxVal = mHistoMax;
1126 const QString minStr = leHistoMin->text();
1127 const QString maxStr = leHistoMax->text();
1128 if ( !minStr.isEmpty() )
1129 minVal = minStr.toDouble();
1130 if ( !maxStr.isEmpty() )
1131 maxVal = maxStr.toDouble();
1133 QPen linePen = QPen( mHistoColors.at( bandNo ) );
1134 linePen.setStyle( Qt::DashLine );
1135 mHistoMarkerMin->setLineStyle( QwtPlotMarker::VLine );
1136 mHistoMarkerMin->setLinePen( linePen );
1137 mHistoMarkerMin->setXValue( minVal );
1138 mHistoMarkerMin->show();
1139 mHistoMarkerMax->setLineStyle( QwtPlotMarker::VLine );
1140 mHistoMarkerMax->setLinePen( linePen );
1141 mHistoMarkerMax->setXValue( maxVal );
1142 mHistoMarkerMax->show();
1148QList< int > QgsRasterHistogramWidget::histoSelectedBands()
1150 QList< int > mySelectedBands;
1152 if ( mHistoShowBands != ShowAll )
1154 if ( mHistoShowBands == ShowSelected )
1156 mySelectedBands << cboHistoBand->currentIndex() + 1;
1158 else if ( mHistoShowBands == ShowRGB )
1160 mySelectedBands = rendererSelectedBands();
1164 return mySelectedBands;
1167QList< int > QgsRasterHistogramWidget::rendererSelectedBands()
1169 QList< int > mySelectedBands;
1171 if ( ! mRendererWidget )
1173 mySelectedBands << -1 << -1 << -1;
1174 return mySelectedBands;
1177 if ( mRendererName == QLatin1String(
"singlebandgray" ) ||
1178 mRendererName == QLatin1String(
"singlebandpseudocolor" ) )
1182 else if ( mRendererName == QLatin1String(
"multibandcolor" ) )
1184 for (
int i = 0; i <= 2; i++ )
1190 return mySelectedBands;
1193QPair< QString, QString > QgsRasterHistogramWidget::rendererMinMax(
int bandNo )
1195 QPair< QString, QString > myMinMax;
1197 if ( ! mRendererWidget )
1200 if ( mRendererName == QLatin1String(
"singlebandgray" ) ||
1201 mRendererName == QLatin1String(
"singlebandpseudocolor" ) )
1205 myMinMax.first = mRendererWidget->
min();
1206 myMinMax.second = mRendererWidget->
max();
1209 else if ( mRendererName == QLatin1String(
"multibandcolor" ) )
1211 for (
int i = 0; i <= 2; i++ )
1215 myMinMax.first = mRendererWidget->
min( i );
1216 myMinMax.second = mRendererWidget->
max( i );
1232 if ( myMinMax.first.isEmpty() )
1233 myMinMax.first = QLocale().toString( mHistoMin );
1234 if ( myMinMax.second.isEmpty() )
1235 myMinMax.second = QLocale().toString( mHistoMax );
1237 QgsDebugMsgLevel( QStringLiteral(
"bandNo %1 got min/max [%2] [%3]" ).arg( bandNo ).arg( myMinMax.first, myMinMax.second ), 2 );
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
DataType
Raster data types.
@ Int16
Sixteen bit signed integer (qint16)
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
@ UInt16
Sixteen bit unsigned integer (quint16)
@ Byte
Eight bit unsigned integer (quint8)
@ Int32
Thirty two bit signed integer (qint32)
@ UInt32
Thirty two bit unsigned integer (quint32)
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
@ StretchToMinimumMaximum
Linear histogram.
@ NoEnhancement
Default color scaling algorithm, no scaling is applied.
static double maximumValuePossible(Qgis::DataType dataType)
Helper function that returns the maximum possible value for a data type.
static double minimumValuePossible(Qgis::DataType dataType)
Helper function that returns the minimum possible value for a data type.
QgsDoubleValidator is a QLineEdit Validator that combines QDoubleValidator and QRegularExpressionVali...
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
double minimumValue
The minimum cell value in the raster band.
double maximumValue
The maximum cell value in the raster band.
Feedback object tailored for raster block reading.
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...
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
The QgsRasterHistogram is a container for histogram of a single raster band.
double minimum
The minimum histogram value.
double maximum
The maximum histogram value.
QgsRasterHistogram::HistogramVector histogramVector
Stores the histogram for a given layer.
int binCount
Number of bins (intervals,buckets) in histogram.
Base class for processing filters like renderers, reprojector, resampler etc.
virtual Qgis::RasterInterfaceCapabilities capabilities() const
Returns the capabilities supported by the interface.
virtual int xSize() const
Gets raster size.
Q_DECL_DEPRECATED QgsRasterBandStats bandStatistics(int bandNo, int stats, const QgsRectangle &extent=QgsRectangle(), int sampleSize=0, QgsRasterBlockFeedback *feedback=nullptr)
Returns the band statistics.
virtual Qgis::DataType sourceDataType(int bandNo) const
Returns source data type for the band specified by number, source data type may be shorter than dataT...
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)
virtual int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
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.
Represents a raster layer.
int bandCount() const
Returns the number of bands in this layer.
QString bandName(int bandNoInt) const
Returns the name of a band given its number.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A rectangle specified with double values.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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.
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)