28#include <QActionGroup>
33#include <QRandomGenerator>
36#include "moc_qgsrasterhistogramwidget.cpp"
38using namespace Qt::StringLiterals;
41#include <qwt_global.h>
42#include <qwt_plot_canvas.h>
43#include <qwt_legend.h>
45#include <qwt_plot_curve.h>
46#include <qwt_plot_grid.h>
47#include <qwt_plot_marker.h>
48#include <qwt_plot_picker.h>
49#include <qwt_picker_machine.h>
50#include <qwt_plot_zoomer.h>
51#include <qwt_plot_layout.h>
52#include <qwt_plot_renderer.h>
53#include <qwt_plot_histogram.h>
54#include <qwt_scale_div.h>
68 connect( mSaveAsImageButton, &QToolButton::clicked,
this, &QgsRasterHistogramWidget::mSaveAsImageButton_clicked );
69 connect( cboHistoBand,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged );
70 connect( btnHistoMin, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMin_toggled );
71 connect( btnHistoMax, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMax_toggled );
72 connect( btnHistoCompute, &QPushButton::clicked,
this, &QgsRasterHistogramWidget::btnHistoCompute_clicked );
76 mRendererWidget =
nullptr;
77 mRendererName = u
"singlebandgray"_s;
82 mHistoPicker =
nullptr;
83 mHistoZoomer =
nullptr;
84 mHistoMarkerMin =
nullptr;
85 mHistoMarkerMax =
nullptr;
88 mHistoShowMarkers = settings.
value( u
"Raster/histogram/showMarkers"_s,
false ).toBool();
90 mHistoZoomToMinMax = settings.
value( u
"Raster/histogram/zoomToMinMax"_s,
false ).toBool();
91 mHistoUpdateStyleToMinMax = settings.
value( u
"Raster/histogram/updateStyleToMinMax"_s,
true ).toBool();
92 mHistoDrawLines = settings.
value( u
"Raster/histogram/drawLines"_s,
true ).toBool();
94 mHistoShowBands = ShowAll;
100 const int myBandCountInt = mRasterLayer->bandCount();
101 for (
int myIteratorInt = 1;
102 myIteratorInt <= myBandCountInt;
105 cboHistoBand->addItem( mRasterLayer->bandName( myIteratorInt ) );
106 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( myIteratorInt );
115 connect( leHistoMin, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMin );
116 connect( leHistoMax, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMax );
120 QMenu *menu =
new QMenu(
this );
121 menu->setSeparatorsCollapsible(
false );
122 btnHistoActions->setMenu( menu );
123 QActionGroup *group =
nullptr;
124 QAction *action =
nullptr;
127 group =
new QActionGroup(
this );
128 group->setExclusive(
false );
129 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
130 action =
new QAction( tr(
"Min/Max options" ), group );
131 action->setSeparator(
true );
132 menu->addAction( action );
133 action =
new QAction( tr(
"Always show min/max markers" ), group );
134 action->setData( QVariant(
"Show markers" ) );
135 action->setCheckable(
true );
136 action->setChecked( mHistoShowMarkers );
137 menu->addAction( action );
138 action =
new QAction( tr(
"Zoom to min/max" ), group );
139 action->setData( QVariant(
"Zoom min_max" ) );
140 action->setCheckable(
true );
141 action->setChecked( mHistoZoomToMinMax );
142 menu->addAction( action );
143 action =
new QAction( tr(
"Update style to min/max" ), group );
144 action->setData( QVariant(
"Update min_max" ) );
145 action->setCheckable(
true );
146 action->setChecked( mHistoUpdateStyleToMinMax );
147 menu->addAction( action );
150 group =
new QActionGroup(
this );
151 group->setExclusive(
false );
152 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
153 action =
new QAction( tr(
"Visibility" ), group );
154 action->setSeparator(
true );
155 menu->addAction( action );
156 group =
new QActionGroup(
this );
157 group->setExclusive(
true );
158 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
159 action =
new QAction( tr(
"Show all bands" ), group );
160 action->setData( QVariant(
"Show all" ) );
161 action->setCheckable(
true );
162 action->setChecked( mHistoShowBands == ShowAll );
163 menu->addAction( action );
164 action =
new QAction( tr(
"Show RGB/Gray band(s)" ), group );
165 action->setData( QVariant(
"Show RGB" ) );
166 action->setCheckable(
true );
167 action->setChecked( mHistoShowBands == ShowRGB );
168 menu->addAction( action );
169 action =
new QAction( tr(
"Show selected band" ), group );
170 action->setData( QVariant(
"Show selected" ) );
171 action->setCheckable(
true );
172 action->setChecked( mHistoShowBands == ShowSelected );
173 menu->addAction( action );
176 group =
new QActionGroup(
this );
177 group->setExclusive(
false );
178 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
179 action =
new QAction( tr(
"Display" ), group );
180 action->setSeparator(
true );
181 menu->addAction( action );
183 action =
new QAction( QString(), group );
184 action->setData( QVariant(
"Draw lines" ) );
187 action->setText( tr(
"Draw as lines" ) );
188 action->setCheckable(
true );
189 action->setChecked( mHistoDrawLines );
193 action->setText( tr(
"Draw as lines (only int layers)" ) );
194 action->setEnabled(
false );
196 menu->addAction( action );
199 action =
new QAction( tr(
"Actions" ), group );
200 action->setSeparator(
true );
201 menu->addAction( action );
204 group =
new QActionGroup(
this );
205 group->setExclusive(
false );
206 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
207 action =
new QAction( tr(
"Reset" ), group );
208 action->setData( QVariant(
"Load reset" ) );
209 menu->addAction( action );
215 action =
new QAction( tr(
"Load min/max" ), group );
216 action->setSeparator(
true );
217 menu->addAction( action );
218 action =
new QAction( tr(
"Estimate (faster)" ), group );
219 action->setData( QVariant(
"Load estimate" ) );
220 menu->addAction( action );
221 action =
new QAction( tr(
"Actual (slower)" ), group );
222 action->setData( QVariant(
"Load actual" ) );
223 menu->addAction( action );
224 action =
new QAction( tr(
"Current extent" ), group );
225 action->setData( QVariant(
"Load extent" ) );
226 menu->addAction( action );
227 action =
new QAction( tr(
"Use stddev (1.0)" ), group );
228 action->setData( QVariant(
"Load 1 stddev" ) );
229 menu->addAction( action );
230 action =
new QAction( tr(
"Use stddev (custom)" ), group );
231 action->setData( QVariant(
"Load stddev" ) );
232 menu->addAction( action );
233 action =
new QAction( tr(
"Load for each band" ), group );
234 action->setData( QVariant(
"Load apply all" ) );
235 action->setCheckable(
true );
236 action->setChecked( mHistoLoadApplyAll );
237 menu->addAction( action );
241 action =
new QAction( tr(
"Recompute Histogram" ), group );
242 action->setData( QVariant(
"Compute histogram" ) );
243 menu->addAction( action );
250 mRendererName = name;
251 mRendererWidget = rendererWidget;
253 cboHistoBand_currentIndexChanged( -1 );
261 cboHistoBand_currentIndexChanged( -1 );
265 if ( QApplication::overrideCursor() )
266 QApplication::restoreOverrideCursor();
267 btnHistoMin->setChecked(
false );
268 btnHistoMax->setChecked(
false );
272void QgsRasterHistogramWidget::btnHistoCompute_clicked()
288static int getBinCount(
QgsRasterInterface *rasterInterface,
int bandNo,
int sampleSize )
297 xRes = yRes = std::sqrt( (
static_cast<double>( extent.width() ) * extent.height() ) / sampleSize );
302 const double srcXRes = extent.width() / rasterInterface->
xSize();
303 const double srcYRes = extent.height() / rasterInterface->
ySize();
304 if ( xRes < srcXRes )
306 if ( yRes < srcYRes )
310 const int histogramWidth =
static_cast<int>( extent.width() / xRes );
311 const int histogramHeight =
static_cast<int>( extent.height() / yRes );
313 int binCount =
static_cast<int>( std::min(
static_cast<qint64
>( 1000 ),
static_cast<qint64
>( histogramWidth ) * histogramHeight ) );
317 binCount =
static_cast<int>( std::min(
static_cast<qint64
>( binCount ),
static_cast<qint64
>( std::ceil( statsMax - statsMin + 1 ) ) ) );
327 const int myBandCountInt = mRasterLayer->bandCount();
330 if ( !forceComputeFlag )
332 for (
int myIteratorInt = 1;
333 myIteratorInt <= myBandCountInt;
337 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
338 if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize ) )
340 QgsDebugMsgLevel( u
"band %1 does not have cached histo"_s.arg( myIteratorInt ), 2 );
347 stackedWidget2->setCurrentIndex( 1 );
351 QApplication::setOverrideCursor( Qt::WaitCursor );
353 for (
int myIteratorInt = 1;
354 myIteratorInt <= myBandCountInt;
358 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
359 mRasterLayer->dataProvider()->histogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
363 stackedWidget2->setCurrentIndex( 0 );
364 QApplication::restoreOverrideCursor();
381 const int myBandCountInt = mRasterLayer->bandCount();
387 stackedWidget2->setCurrentIndex( 2 );
392 mpPlot->detachItems();
395 mpPlot->setAutoDelete(
true );
396 mpPlot->setTitle( QObject::tr(
"Raster Histogram" ) );
397 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
399 mpPlot->setAxisTitle( QwtPlot::xBottom, QObject::tr(
"Pixel Value" ) );
400 mpPlot->setAxisTitle( QwtPlot::yLeft, QObject::tr(
"Frequency" ) );
401 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
405 QwtPlotGrid *myGrid =
new QwtPlotGrid();
406 myGrid->attach( mpPlot );
409 mHistoColors.clear();
410 mHistoColors << Qt::black;
411 QVector<QColor> myColors;
412 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
415 QRandomGenerator colorGenerator( myBandCountInt * 100 );
416 while ( myColors.size() <= myBandCountInt )
418 myColors << QColor( colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ) );
423 QList<int> mySelectedBands = rendererSelectedBands();
424 if ( mRendererName ==
"singlebandgray"_L1 )
426 const int myGrayBand = mySelectedBands[0];
427 for (
int i = 1; i <= myBandCountInt; i++ )
429 if ( i == myGrayBand )
431 mHistoColors << Qt::darkGray;
432 cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
436 if ( !myColors.isEmpty() )
438 mHistoColors << myColors.first();
439 myColors.pop_front();
443 mHistoColors << Qt::black;
445 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
450 else if ( mRendererName ==
"multibandcolor"_L1 )
452 const int myRedBand = mySelectedBands[0];
453 const int myGreenBand = mySelectedBands[1];
454 const int myBlueBand = mySelectedBands[2];
457 myColors.remove( 0, 3 );
458 for (
int i = 1; i <= myBandCountInt; i++ )
461 if ( i == myRedBand )
463 else if ( i == myGreenBand )
465 else if ( i == myBlueBand )
469 if ( !myColors.isEmpty() )
471 myColor = myColors.first();
472 myColors.pop_front();
478 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
480 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
482 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
484 mHistoColors << myColor;
489 mHistoColors << myColors;
504 bool myFirstIteration =
true;
506 mySelectedBands = histoSelectedBands();
507 double myBinXStep = 1;
510 for (
int bandNumber = 1;
511 bandNumber <= myBandCountInt;
515 if ( mHistoShowBands != ShowAll )
517 if ( !mySelectedBands.contains( bandNumber ) )
526 const int binCount = getBinCount( mRasterLayer->dataProvider(), bandNumber, sampleSize );
527 const QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( bandNumber, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
531 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( bandNumber );
532 bool myDrawLines =
true;
538 QwtPlotCurve *mypCurve =
nullptr;
541 mypCurve =
new QwtPlotCurve( tr(
"Band %1" ).arg( bandNumber ) );
543 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
544 mypCurve->setPen( QPen( mHistoColors.at( bandNumber ) ) );
547 QwtPlotHistogram *mypHisto =
nullptr;
550 mypHisto =
new QwtPlotHistogram( tr(
"Band %1" ).arg( bandNumber ) );
551 mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
553 mypHisto->setPen( QPen( Qt::lightGray ) );
555 mypHisto->setBrush( QBrush( mHistoColors.at( bandNumber ) ) );
558 QVector<QPointF> data;
559 QVector<QwtIntervalSample> dataHisto;
563 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
565 for (
int myBin = 0; myBin < myHistogram.
binCount; myBin++ )
570 data << QPointF( myBinX, myBinValue );
574 dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
576 myBinX += myBinXStep;
581 mypCurve->setSamples( data );
582 mypCurve->attach( mpPlot );
586 mypHisto->setSamples( dataHisto );
587 mypHisto->attach( mpPlot );
590 if ( myFirstIteration || mHistoMin > myHistogram.
minimum )
592 mHistoMin = myHistogram.
minimum;
594 if ( myFirstIteration || mHistoMax < myHistogram.
maximum )
596 mHistoMax = myHistogram.
maximum;
598 QgsDebugMsgLevel( u
"computed histo min = %1 max = %2"_s.arg( mHistoMin ).arg( mHistoMax ), 2 );
599 myFirstIteration =
false;
602 if ( mHistoMin < mHistoMax )
608 mpPlot->setAxisScale( QwtPlot::xBottom, mHistoMin - myBinXStep / 2, mHistoMax + myBinXStep / 2 );
609 mpPlot->setEnabled(
true );
614 mHistoMarkerMin =
new QwtPlotMarker();
615 mHistoMarkerMin->attach( mpPlot );
616 mHistoMarkerMax =
new QwtPlotMarker();
617 mHistoMarkerMax->attach( mpPlot );
618 updateHistoMarkers();
623 mHistoPicker =
new QwtPlotPicker( mpPlot->canvas() );
625 mHistoPicker->setTrackerMode( QwtPicker::AlwaysOff );
626 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
627 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
628 connect( mHistoPicker,
static_cast<void ( QwtPlotPicker::* )(
const QPointF & )
>( &QwtPlotPicker::selected ),
this, &QgsRasterHistogramWidget::histoPickerSelected );
630 mHistoPicker->setEnabled(
false );
635 mHistoZoomer =
new QwtPlotZoomer( mpPlot->canvas() );
636 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
637 mHistoZoomer->setTrackerMode( QwtPicker::AlwaysOff );
639 mHistoZoomer->setEnabled(
true );
643 mpPlot->setDisabled(
true );
645 mHistoPicker->setEnabled(
false );
647 mHistoZoomer->setEnabled(
false );
650 stackedWidget2->setCurrentIndex( 0 );
654 QApplication::restoreOverrideCursor();
657void QgsRasterHistogramWidget::mSaveAsImageButton_clicked()
663 const QFileInfo myInfo( myFileNameAndFilter.first );
664 if ( !myInfo.baseName().isEmpty() )
673 const QFileInfo myInfo( filename );
674 const QDir myDir( myInfo.dir() );
675 if ( !myDir.exists() )
677 QgsDebugError( u
"Error, directory %1 non-existent (theFilename = %2)"_s.arg( myDir.absolutePath(), filename ) );
682 QPixmap myPixmap( width, height );
683 const QRect myQRect( 5, 5, width - 10, height - 10 );
684 myPixmap.fill( Qt::white );
686 QwtPlotRenderer myRenderer;
687 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground | QwtPlotRenderer::DiscardCanvasBackground );
688 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
691 myPainter.begin( &myPixmap );
692 myRenderer.render( mpPlot, &myPainter, myQRect );
696 myPixmap.save( filename,
nullptr, quality );
704 cboHistoBand->setCurrentIndex( bandNo - 1 );
707void QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged(
int index )
709 if ( mHistoShowBands == ShowSelected )
713 index = cboHistoBand->currentIndex();
716 mHistoPicker->setEnabled(
false );
717 mHistoPicker->setRubberBandPen( QPen( mHistoColors.at( index + 1 ) ) );
720 mHistoZoomer->setEnabled(
true );
721 btnHistoMin->setEnabled(
true );
722 btnHistoMax->setEnabled(
true );
724 const QPair<QString, QString> myMinMax = rendererMinMax( index + 1 );
725 leHistoMin->setText( myMinMax.first );
726 leHistoMax->setText( myMinMax.second );
732void QgsRasterHistogramWidget::histoActionTriggered( QAction *action )
736 histoAction( action->data().toString(), action->isChecked() );
741 if ( actionName.isEmpty() )
745 QgsDebugMsgLevel( u
"band = %1 action = %2"_s.arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ), 2 );
748 if ( actionName ==
"Show markers"_L1 )
750 mHistoShowMarkers = actionFlag;
752 settings.
setValue( u
"Raster/histogram/showMarkers"_s, mHistoShowMarkers );
753 updateHistoMarkers();
756 else if ( actionName ==
"Zoom min_max"_L1 )
758 mHistoZoomToMinMax = actionFlag;
760 settings.
setValue( u
"Raster/histogram/zoomToMinMax"_s, mHistoZoomToMinMax );
763 else if ( actionName ==
"Update min_max"_L1 )
765 mHistoUpdateStyleToMinMax = actionFlag;
767 settings.
setValue( u
"Raster/histogram/updateStyleToMinMax"_s, mHistoUpdateStyleToMinMax );
770 else if ( actionName ==
"Show all"_L1 )
772 mHistoShowBands = ShowAll;
777 else if ( actionName ==
"Show selected"_L1 )
779 mHistoShowBands = ShowSelected;
784 else if ( actionName ==
"Show RGB"_L1 )
786 mHistoShowBands = ShowRGB;
791 else if ( actionName ==
"Draw lines"_L1 )
793 mHistoDrawLines = actionFlag;
795 settings.
setValue( u
"Raster/histogram/drawLines"_s, mHistoDrawLines );
796 btnHistoCompute_clicked();
800 else if ( actionName ==
"Load apply all" )
802 mHistoLoadApplyAll = actionFlag;
803 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
809 else if ( actionName.left( 5 ) ==
"Load "_L1 && mRendererWidget )
811 QVector<int> myBands;
815 double minMaxValues[2];
818 if ( mHistoLoadApplyAll )
820 int myBandCountInt = mRasterLayer->bandCount();
821 for (
int i = 1; i <= myBandCountInt; i++ )
823 if ( i != cboHistoBand->currentIndex() + 1 )
830 myBands << cboHistoBand->currentIndex() + 1;
834 double myStdDev = 1.0;
835 if ( actionName ==
"Load stddev" )
837 myStdDev = mRendererWidget->stdDev().toDouble();
842 leHistoMin->blockSignals(
true );
843 leHistoMax->blockSignals(
true );
846 const auto constMyBands = myBands;
847 for (
const int bandNo : constMyBands )
851 if ( actionName ==
"Load actual" )
853 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Actual,
854 bandNo, minMaxValues );
856 else if ( actionName ==
"Load estimate" )
858 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Estimate,
859 bandNo, minMaxValues );
861 else if ( actionName ==
"Load extent" )
863 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::CurrentExtent,
864 bandNo, minMaxValues );
866 else if ( actionName ==
"Load 1 stddev" ||
867 actionName ==
"Load stddev" )
869 ok = mRendererWidget->bandMinMaxFromStdDev( myStdDev, bandNo, minMaxValues );
874 cboHistoBand->setCurrentIndex( bandNo - 1 );
875 if ( !ok || actionName ==
"Load reset"_L1 )
883 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
885 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
889 leHistoMin->setText( QString::number( minMaxValues[0] ) );
890 leHistoMax->setText( QString::number( minMaxValues[1] ) );
897 leHistoMin->blockSignals(
false );
898 leHistoMax->blockSignals(
false );
899 updateHistoMarkers();
901 else if ( actionName ==
"Compute histogram"_L1 )
903 btnHistoCompute_clicked();
912void QgsRasterHistogramWidget::applyHistoMin()
914 if ( !mRendererWidget )
917 const int bandNo = cboHistoBand->currentIndex() + 1;
918 const QList<int> selectedBands = rendererSelectedBands();
920 for (
int i = 0; i <= selectedBands.size(); i++ )
924 min = leHistoMin->text();
925 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
min( i ) != min )
927 mRendererWidget->
setMin( min, i );
932 if ( mRendererWidget->minMaxWidget() )
934 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
940 updateHistoMarkers();
942 if ( !min.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
944 QRectF rect = mHistoZoomer->zoomRect();
945 rect.setLeft( min.toDouble() );
946 mHistoZoomer->zoom( rect );
951void QgsRasterHistogramWidget::applyHistoMax()
953 if ( !mRendererWidget )
956 const int bandNo = cboHistoBand->currentIndex() + 1;
957 const QList<int> mySelectedBands = rendererSelectedBands();
959 for (
int i = 0; i <= mySelectedBands.size(); i++ )
961 if ( bandNo == mRendererWidget->selectedBand( i ) )
963 max = leHistoMax->text();
964 if ( mHistoUpdateStyleToMinMax && mRendererWidget->max( i ) != max )
966 mRendererWidget->setMax( max, i );
971 if ( mRendererWidget->minMaxWidget() )
973 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
979 updateHistoMarkers();
981 if ( !max.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
983 QRectF rect = mHistoZoomer->zoomRect();
984 rect.setRight( max.toDouble() );
985 mHistoZoomer->zoom( rect );
990void QgsRasterHistogramWidget::btnHistoMin_toggled()
992 if ( mpPlot && mHistoPicker )
994 if ( QApplication::overrideCursor() )
995 QApplication::restoreOverrideCursor();
996 if ( btnHistoMin->isChecked() )
998 btnHistoMax->setChecked(
false );
999 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1002 mHistoZoomer->setEnabled( !btnHistoMin->isChecked() );
1003 mHistoPicker->setEnabled( btnHistoMin->isChecked() );
1005 updateHistoMarkers();
1008void QgsRasterHistogramWidget::btnHistoMax_toggled()
1010 if ( mpPlot && mHistoPicker )
1012 if ( QApplication::overrideCursor() )
1013 QApplication::restoreOverrideCursor();
1014 if ( btnHistoMax->isChecked() )
1016 btnHistoMin->setChecked(
false );
1017 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1020 mHistoZoomer->setEnabled( !btnHistoMax->isChecked() );
1021 mHistoPicker->setEnabled( btnHistoMax->isChecked() );
1023 updateHistoMarkers();
1033 QList<double> minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1034 QList<double> majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1035 const double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1036 double min = majorTicks[0] - diff;
1038 min -= ( majorTicks[1] - majorTicks[0] );
1039 const double max = scale->upperBound();
1040 double closest = target;
1041 double current = min;
1043 while ( current < max )
1046 if ( current > target )
1048 closest = ( std::fabs( target - current + diff ) < std::fabs( target - current ) ) ? current - diff : current;
1054 return QLocale().toString( closest );
1057void QgsRasterHistogramWidget::histoPickerSelected( QPointF pos )
1059 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1061 const QwtScaleDiv *scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1063 if ( btnHistoMin->isChecked() )
1067 btnHistoMin->setChecked(
false );
1073 btnHistoMax->setChecked(
false );
1076 if ( QApplication::overrideCursor() )
1077 QApplication::restoreOverrideCursor();
1080void QgsRasterHistogramWidget::histoPickerSelectedQwt5(
QwtDoublePoint pos )
1082 histoPickerSelected( QPointF( pos.x(), pos.y() ) );
1085void QgsRasterHistogramWidget::updateHistoMarkers()
1088 if ( leHistoMin->signalsBlocked() )
1091 if ( !mpPlot || !mHistoMarkerMin || !mHistoMarkerMax )
1094 const int bandNo = cboHistoBand->currentIndex() + 1;
1095 const QList<int> mySelectedBands = histoSelectedBands();
1097 if ( ( !mHistoShowMarkers && !btnHistoMin->isChecked() && !btnHistoMax->isChecked() ) || ( !mySelectedBands.isEmpty() && !mySelectedBands.contains( bandNo ) ) )
1099 mHistoMarkerMin->hide();
1100 mHistoMarkerMax->hide();
1105 double minVal = mHistoMin;
1106 double maxVal = mHistoMax;
1107 const QString minStr = leHistoMin->text();
1108 const QString maxStr = leHistoMax->text();
1109 if ( !minStr.isEmpty() )
1110 minVal = minStr.toDouble();
1111 if ( !maxStr.isEmpty() )
1112 maxVal = maxStr.toDouble();
1114 QPen linePen = QPen( mHistoColors.at( bandNo ) );
1115 linePen.setStyle( Qt::DashLine );
1116 mHistoMarkerMin->setLineStyle( QwtPlotMarker::VLine );
1117 mHistoMarkerMin->setLinePen( linePen );
1118 mHistoMarkerMin->setXValue( minVal );
1119 mHistoMarkerMin->show();
1120 mHistoMarkerMax->setLineStyle( QwtPlotMarker::VLine );
1121 mHistoMarkerMax->setLinePen( linePen );
1122 mHistoMarkerMax->setXValue( maxVal );
1123 mHistoMarkerMax->show();
1129QList<int> QgsRasterHistogramWidget::histoSelectedBands()
1131 QList<int> mySelectedBands;
1133 if ( mHistoShowBands != ShowAll )
1135 if ( mHistoShowBands == ShowSelected )
1137 mySelectedBands << cboHistoBand->currentIndex() + 1;
1139 else if ( mHistoShowBands == ShowRGB )
1141 mySelectedBands = rendererSelectedBands();
1145 return mySelectedBands;
1148QList<int> QgsRasterHistogramWidget::rendererSelectedBands()
1150 QList<int> mySelectedBands;
1152 if ( !mRendererWidget )
1154 mySelectedBands << -1 << -1 << -1;
1155 return mySelectedBands;
1158 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1160 mySelectedBands << mRendererWidget->selectedBand();
1162 else if ( mRendererName ==
"multibandcolor"_L1 )
1164 for (
int i = 0; i <= 2; i++ )
1166 mySelectedBands << mRendererWidget->selectedBand( i );
1170 return mySelectedBands;
1173QPair<QString, QString> QgsRasterHistogramWidget::rendererMinMax(
int bandNo )
1175 QPair<QString, QString> myMinMax;
1177 if ( !mRendererWidget )
1180 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1182 if ( bandNo == mRendererWidget->selectedBand() )
1184 myMinMax.first = mRendererWidget->min();
1185 myMinMax.second = mRendererWidget->max();
1188 else if ( mRendererName ==
"multibandcolor"_L1 )
1190 for (
int i = 0; i <= 2; i++ )
1192 if ( bandNo == mRendererWidget->selectedBand( i ) )
1194 myMinMax.first = mRendererWidget->min( i );
1195 myMinMax.second = mRendererWidget->max( i );
1211 if ( myMinMax.first.isEmpty() )
1212 myMinMax.first = QLocale().toString( mHistoMin );
1213 if ( myMinMax.second.isEmpty() )
1214 myMinMax.second = QLocale().toString( mHistoMax );
1216 QgsDebugMsgLevel( u
"bandNo %1 got min/max [%2] [%3]"_s.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.
A custom validator which allows entry of doubles in a locale-tolerant way.
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.
A container for a 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 int ySize() const
virtual QgsRectangle extent() const
Gets the extent of the interface.
Represents a raster layer.
A rectangle specified with double values.
Stores settings for use within QGIS.
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)