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; myIteratorInt <= myBandCountInt; ++myIteratorInt )
103 cboHistoBand->addItem( mRasterLayer->bandName( myIteratorInt ) );
104 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( myIteratorInt );
118 connect( leHistoMin, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMin );
119 connect( leHistoMax, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMax );
123 QMenu *menu =
new QMenu(
this );
124 menu->setSeparatorsCollapsible(
false );
125 btnHistoActions->setMenu( menu );
126 QActionGroup *group =
nullptr;
127 QAction *action =
nullptr;
130 group =
new QActionGroup(
this );
131 group->setExclusive(
false );
132 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
133 action =
new QAction( tr(
"Min/Max options" ), group );
134 action->setSeparator(
true );
135 menu->addAction( action );
136 action =
new QAction( tr(
"Always show min/max markers" ), group );
137 action->setData( QVariant(
"Show markers" ) );
138 action->setCheckable(
true );
139 action->setChecked( mHistoShowMarkers );
140 menu->addAction( action );
141 action =
new QAction( tr(
"Zoom to min/max" ), group );
142 action->setData( QVariant(
"Zoom min_max" ) );
143 action->setCheckable(
true );
144 action->setChecked( mHistoZoomToMinMax );
145 menu->addAction( action );
146 action =
new QAction( tr(
"Update style to min/max" ), group );
147 action->setData( QVariant(
"Update min_max" ) );
148 action->setCheckable(
true );
149 action->setChecked( mHistoUpdateStyleToMinMax );
150 menu->addAction( action );
153 group =
new QActionGroup(
this );
154 group->setExclusive(
false );
155 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
156 action =
new QAction( tr(
"Visibility" ), group );
157 action->setSeparator(
true );
158 menu->addAction( action );
159 group =
new QActionGroup(
this );
160 group->setExclusive(
true );
161 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
162 action =
new QAction( tr(
"Show all bands" ), group );
163 action->setData( QVariant(
"Show all" ) );
164 action->setCheckable(
true );
165 action->setChecked( mHistoShowBands == ShowAll );
166 menu->addAction( action );
167 action =
new QAction( tr(
"Show RGB/Gray band(s)" ), group );
168 action->setData( QVariant(
"Show RGB" ) );
169 action->setCheckable(
true );
170 action->setChecked( mHistoShowBands == ShowRGB );
171 menu->addAction( action );
172 action =
new QAction( tr(
"Show selected band" ), group );
173 action->setData( QVariant(
"Show selected" ) );
174 action->setCheckable(
true );
175 action->setChecked( mHistoShowBands == ShowSelected );
176 menu->addAction( action );
179 group =
new QActionGroup(
this );
180 group->setExclusive(
false );
181 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
182 action =
new QAction( tr(
"Display" ), group );
183 action->setSeparator(
true );
184 menu->addAction( action );
186 action =
new QAction( QString(), group );
187 action->setData( QVariant(
"Draw lines" ) );
190 action->setText( tr(
"Draw as lines" ) );
191 action->setCheckable(
true );
192 action->setChecked( mHistoDrawLines );
196 action->setText( tr(
"Draw as lines (only int layers)" ) );
197 action->setEnabled(
false );
199 menu->addAction( action );
202 action =
new QAction( tr(
"Actions" ), group );
203 action->setSeparator(
true );
204 menu->addAction( action );
207 group =
new QActionGroup(
this );
208 group->setExclusive(
false );
209 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
210 action =
new QAction( tr(
"Reset" ), group );
211 action->setData( QVariant(
"Load reset" ) );
212 menu->addAction( action );
218 action =
new QAction( tr(
"Load min/max" ), group );
219 action->setSeparator(
true );
220 menu->addAction( action );
221 action =
new QAction( tr(
"Estimate (faster)" ), group );
222 action->setData( QVariant(
"Load estimate" ) );
223 menu->addAction( action );
224 action =
new QAction( tr(
"Actual (slower)" ), group );
225 action->setData( QVariant(
"Load actual" ) );
226 menu->addAction( action );
227 action =
new QAction( tr(
"Current extent" ), group );
228 action->setData( QVariant(
"Load extent" ) );
229 menu->addAction( action );
230 action =
new QAction( tr(
"Use stddev (1.0)" ), group );
231 action->setData( QVariant(
"Load 1 stddev" ) );
232 menu->addAction( action );
233 action =
new QAction( tr(
"Use stddev (custom)" ), group );
234 action->setData( QVariant(
"Load stddev" ) );
235 menu->addAction( action );
236 action =
new QAction( tr(
"Load for each band" ), group );
237 action->setData( QVariant(
"Load apply all" ) );
238 action->setCheckable(
true );
239 action->setChecked( mHistoLoadApplyAll );
240 menu->addAction( action );
244 action =
new QAction( tr(
"Recompute Histogram" ), group );
245 action->setData( QVariant(
"Compute histogram" ) );
246 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()
291static int getBinCount(
QgsRasterInterface *rasterInterface,
int bandNo,
int sampleSize )
300 xRes = yRes = std::sqrt( (
static_cast<double>( extent.width() ) * extent.height() ) / sampleSize );
305 const double srcXRes = extent.width() / rasterInterface->
xSize();
306 const double srcYRes = extent.height() / rasterInterface->
ySize();
307 if ( xRes < srcXRes )
309 if ( yRes < srcYRes )
313 const int histogramWidth =
static_cast<int>( extent.width() / xRes );
314 const int histogramHeight =
static_cast<int>( extent.height() / yRes );
316 int binCount =
static_cast<int>( std::min(
static_cast<qint64
>( 1000 ),
static_cast<qint64
>( histogramWidth ) * histogramHeight ) );
320 binCount =
static_cast<int>( std::min(
static_cast<qint64
>( binCount ),
static_cast<qint64
>( std::ceil( statsMax - statsMin + 1 ) ) ) );
330 const int myBandCountInt = mRasterLayer->bandCount();
333 if ( !forceComputeFlag )
335 for (
int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
338 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
339 if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize ) )
341 QgsDebugMsgLevel( u
"band %1 does not have cached histo"_s.arg( myIteratorInt ), 2 );
348 stackedWidget2->setCurrentIndex( 1 );
352 QApplication::setOverrideCursor( Qt::WaitCursor );
354 for (
int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
357 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
358 mRasterLayer->dataProvider()->histogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
362 stackedWidget2->setCurrentIndex( 0 );
363 QApplication::restoreOverrideCursor();
380 const int myBandCountInt = mRasterLayer->bandCount();
386 stackedWidget2->setCurrentIndex( 2 );
391 mpPlot->detachItems();
394 mpPlot->setAutoDelete(
true );
395 mpPlot->setTitle( QObject::tr(
"Raster Histogram" ) );
396 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
398 mpPlot->setAxisTitle( QwtPlot::xBottom, QObject::tr(
"Pixel Value" ) );
399 mpPlot->setAxisTitle( QwtPlot::yLeft, QObject::tr(
"Frequency" ) );
400 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
404 QwtPlotGrid *myGrid =
new QwtPlotGrid();
405 myGrid->attach( mpPlot );
408 mHistoColors.clear();
409 mHistoColors << Qt::black;
410 QVector<QColor> myColors;
411 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
414 QRandomGenerator colorGenerator( myBandCountInt * 100 );
415 while ( myColors.size() <= myBandCountInt )
417 myColors << QColor( colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ) );
422 QList<int> mySelectedBands = rendererSelectedBands();
423 if ( mRendererName ==
"singlebandgray"_L1 )
425 const int myGrayBand = mySelectedBands[0];
426 for (
int i = 1; i <= myBandCountInt; i++ )
428 if ( i == myGrayBand )
430 mHistoColors << Qt::darkGray;
431 cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
435 if ( !myColors.isEmpty() )
437 mHistoColors << myColors.first();
438 myColors.pop_front();
442 mHistoColors << Qt::black;
444 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
449 else if ( mRendererName ==
"multibandcolor"_L1 )
451 const int myRedBand = mySelectedBands[0];
452 const int myGreenBand = mySelectedBands[1];
453 const int myBlueBand = mySelectedBands[2];
456 myColors.remove( 0, 3 );
457 for (
int i = 1; i <= myBandCountInt; i++ )
460 if ( i == myRedBand )
462 else if ( i == myGreenBand )
464 else if ( i == myBlueBand )
468 if ( !myColors.isEmpty() )
470 myColor = myColors.first();
471 myColors.pop_front();
477 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
479 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
481 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
483 mHistoColors << myColor;
488 mHistoColors << myColors;
503 bool myFirstIteration =
true;
505 mySelectedBands = histoSelectedBands();
506 double myBinXStep = 1;
509 for (
int bandNumber = 1; bandNumber <= myBandCountInt; ++bandNumber )
512 if ( mHistoShowBands != ShowAll )
514 if ( !mySelectedBands.contains( bandNumber ) )
523 const int binCount = getBinCount( mRasterLayer->dataProvider(), bandNumber, sampleSize );
525 = mRasterLayer->dataProvider()->histogram( bandNumber, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
529 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( bandNumber );
530 bool myDrawLines =
true;
531 if ( !mHistoDrawLines
537 QwtPlotCurve *mypCurve =
nullptr;
540 mypCurve =
new QwtPlotCurve( tr(
"Band %1" ).arg( bandNumber ) );
542 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
543 mypCurve->setPen( QPen( mHistoColors.at( bandNumber ) ) );
546 QwtPlotHistogram *mypHisto =
nullptr;
549 mypHisto =
new QwtPlotHistogram( tr(
"Band %1" ).arg( bandNumber ) );
550 mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
552 mypHisto->setPen( QPen( Qt::lightGray ) );
554 mypHisto->setBrush( QBrush( mHistoColors.at( bandNumber ) ) );
557 QVector<QPointF> data;
558 QVector<QwtIntervalSample> dataHisto;
562 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
564 for (
int myBin = 0; myBin < myHistogram.
binCount; myBin++ )
569 data << QPointF( myBinX, myBinValue );
573 dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
575 myBinX += myBinXStep;
580 mypCurve->setSamples( data );
581 mypCurve->attach( mpPlot );
585 mypHisto->setSamples( dataHisto );
586 mypHisto->attach( mpPlot );
589 if ( myFirstIteration || mHistoMin > myHistogram.
minimum )
591 mHistoMin = myHistogram.
minimum;
593 if ( myFirstIteration || mHistoMax < myHistogram.
maximum )
595 mHistoMax = myHistogram.
maximum;
597 QgsDebugMsgLevel( u
"computed histo min = %1 max = %2"_s.arg( mHistoMin ).arg( mHistoMax ), 2 );
598 myFirstIteration =
false;
601 if ( mHistoMin < mHistoMax )
607 mpPlot->setAxisScale( QwtPlot::xBottom, mHistoMin - myBinXStep / 2, mHistoMax + myBinXStep / 2 );
608 mpPlot->setEnabled(
true );
613 mHistoMarkerMin =
new QwtPlotMarker();
614 mHistoMarkerMin->attach( mpPlot );
615 mHistoMarkerMax =
new QwtPlotMarker();
616 mHistoMarkerMax->attach( mpPlot );
617 updateHistoMarkers();
622 mHistoPicker =
new QwtPlotPicker( mpPlot->canvas() );
624 mHistoPicker->setTrackerMode( QwtPicker::AlwaysOff );
625 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
626 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
627 connect( mHistoPicker,
static_cast<void ( QwtPlotPicker::* )(
const QPointF & )
>( &QwtPlotPicker::selected ),
this, &QgsRasterHistogramWidget::histoPickerSelected );
629 mHistoPicker->setEnabled(
false );
634 mHistoZoomer =
new QwtPlotZoomer( mpPlot->canvas() );
635 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
636 mHistoZoomer->setTrackerMode( QwtPicker::AlwaysOff );
638 mHistoZoomer->setEnabled(
true );
642 mpPlot->setDisabled(
true );
644 mHistoPicker->setEnabled(
false );
646 mHistoZoomer->setEnabled(
false );
649 stackedWidget2->setCurrentIndex( 0 );
653 QApplication::restoreOverrideCursor();
656void QgsRasterHistogramWidget::mSaveAsImageButton_clicked()
662 const QFileInfo myInfo( myFileNameAndFilter.first );
663 if ( !myInfo.baseName().isEmpty() )
672 const QFileInfo myInfo( filename );
673 const QDir myDir( myInfo.dir() );
674 if ( !myDir.exists() )
676 QgsDebugError( u
"Error, directory %1 non-existent (theFilename = %2)"_s.arg( myDir.absolutePath(), filename ) );
681 QPixmap myPixmap( width, height );
682 const QRect myQRect( 5, 5, width - 10, height - 10 );
683 myPixmap.fill( Qt::white );
685 QwtPlotRenderer myRenderer;
686 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground | QwtPlotRenderer::DiscardCanvasBackground );
687 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
690 myPainter.begin( &myPixmap );
691 myRenderer.render( mpPlot, &myPainter, myQRect );
695 myPixmap.save( filename,
nullptr, quality );
703 cboHistoBand->setCurrentIndex( bandNo - 1 );
706void QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged(
int index )
708 if ( mHistoShowBands == ShowSelected )
712 index = cboHistoBand->currentIndex();
715 mHistoPicker->setEnabled(
false );
716 mHistoPicker->setRubberBandPen( QPen( mHistoColors.at( index + 1 ) ) );
719 mHistoZoomer->setEnabled(
true );
720 btnHistoMin->setEnabled(
true );
721 btnHistoMax->setEnabled(
true );
723 const QPair<QString, QString> myMinMax = rendererMinMax( index + 1 );
724 leHistoMin->setText( myMinMax.first );
725 leHistoMax->setText( myMinMax.second );
731void QgsRasterHistogramWidget::histoActionTriggered( QAction *action )
735 histoAction( action->data().toString(), action->isChecked() );
740 if ( actionName.isEmpty() )
744 QgsDebugMsgLevel( u
"band = %1 action = %2"_s.arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ), 2 );
747 if ( actionName ==
"Show markers"_L1 )
749 mHistoShowMarkers = actionFlag;
751 settings.
setValue( u
"Raster/histogram/showMarkers"_s, mHistoShowMarkers );
752 updateHistoMarkers();
755 else if ( actionName ==
"Zoom min_max"_L1 )
757 mHistoZoomToMinMax = actionFlag;
759 settings.
setValue( u
"Raster/histogram/zoomToMinMax"_s, mHistoZoomToMinMax );
762 else if ( actionName ==
"Update min_max"_L1 )
764 mHistoUpdateStyleToMinMax = actionFlag;
766 settings.
setValue( u
"Raster/histogram/updateStyleToMinMax"_s, mHistoUpdateStyleToMinMax );
769 else if ( actionName ==
"Show all"_L1 )
771 mHistoShowBands = ShowAll;
776 else if ( actionName ==
"Show selected"_L1 )
778 mHistoShowBands = ShowSelected;
783 else if ( actionName ==
"Show RGB"_L1 )
785 mHistoShowBands = ShowRGB;
790 else if ( actionName ==
"Draw lines"_L1 )
792 mHistoDrawLines = actionFlag;
794 settings.
setValue( u
"Raster/histogram/drawLines"_s, mHistoDrawLines );
795 btnHistoCompute_clicked();
799 else if ( actionName ==
"Load apply all" )
801 mHistoLoadApplyAll = actionFlag;
802 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
808 else if ( actionName.left( 5 ) ==
"Load "_L1 && mRendererWidget )
810 QVector<int> myBands;
814 double minMaxValues[2];
817 if ( mHistoLoadApplyAll )
819 int myBandCountInt = mRasterLayer->bandCount();
820 for (
int i = 1; i <= myBandCountInt; i++ )
822 if ( i != cboHistoBand->currentIndex() + 1 )
829 myBands << cboHistoBand->currentIndex() + 1;
833 double myStdDev = 1.0;
834 if ( actionName ==
"Load stddev" )
836 myStdDev = mRendererWidget->stdDev().toDouble();
841 leHistoMin->blockSignals(
true );
842 leHistoMax->blockSignals(
true );
845 const auto constMyBands = myBands;
846 for (
const int bandNo : constMyBands )
850 if ( actionName ==
"Load actual" )
852 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Actual,
853 bandNo, minMaxValues );
855 else if ( actionName ==
"Load estimate" )
857 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Estimate,
858 bandNo, minMaxValues );
860 else if ( actionName ==
"Load extent" )
862 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::CurrentExtent,
863 bandNo, minMaxValues );
865 else if ( actionName ==
"Load 1 stddev" ||
866 actionName ==
"Load stddev" )
868 ok = mRendererWidget->bandMinMaxFromStdDev( myStdDev, bandNo, minMaxValues );
873 cboHistoBand->setCurrentIndex( bandNo - 1 );
874 if ( !ok || actionName ==
"Load reset"_L1 )
882 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
884 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
888 leHistoMin->setText( QString::number( minMaxValues[0] ) );
889 leHistoMax->setText( QString::number( minMaxValues[1] ) );
896 leHistoMin->blockSignals(
false );
897 leHistoMax->blockSignals(
false );
898 updateHistoMarkers();
900 else if ( actionName ==
"Compute histogram"_L1 )
902 btnHistoCompute_clicked();
911void QgsRasterHistogramWidget::applyHistoMin()
913 if ( !mRendererWidget )
916 const int bandNo = cboHistoBand->currentIndex() + 1;
917 const QList<int> selectedBands = rendererSelectedBands();
919 for (
int i = 0; i <= selectedBands.size(); i++ )
923 min = leHistoMin->text();
924 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
min( i ) != min )
926 mRendererWidget->
setMin( min, i );
931 if ( mRendererWidget->minMaxWidget() )
933 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
939 updateHistoMarkers();
941 if ( !min.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
943 QRectF rect = mHistoZoomer->zoomRect();
944 rect.setLeft( min.toDouble() );
945 mHistoZoomer->zoom( rect );
950void QgsRasterHistogramWidget::applyHistoMax()
952 if ( !mRendererWidget )
955 const int bandNo = cboHistoBand->currentIndex() + 1;
956 const QList<int> mySelectedBands = rendererSelectedBands();
958 for (
int i = 0; i <= mySelectedBands.size(); i++ )
960 if ( bandNo == mRendererWidget->selectedBand( i ) )
962 max = leHistoMax->text();
963 if ( mHistoUpdateStyleToMinMax && mRendererWidget->max( i ) != max )
965 mRendererWidget->setMax( max, i );
970 if ( mRendererWidget->minMaxWidget() )
972 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
978 updateHistoMarkers();
980 if ( !max.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
982 QRectF rect = mHistoZoomer->zoomRect();
983 rect.setRight( max.toDouble() );
984 mHistoZoomer->zoom( rect );
989void QgsRasterHistogramWidget::btnHistoMin_toggled()
991 if ( mpPlot && mHistoPicker )
993 if ( QApplication::overrideCursor() )
994 QApplication::restoreOverrideCursor();
995 if ( btnHistoMin->isChecked() )
997 btnHistoMax->setChecked(
false );
998 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1001 mHistoZoomer->setEnabled( !btnHistoMin->isChecked() );
1002 mHistoPicker->setEnabled( btnHistoMin->isChecked() );
1004 updateHistoMarkers();
1007void QgsRasterHistogramWidget::btnHistoMax_toggled()
1009 if ( mpPlot && mHistoPicker )
1011 if ( QApplication::overrideCursor() )
1012 QApplication::restoreOverrideCursor();
1013 if ( btnHistoMax->isChecked() )
1015 btnHistoMin->setChecked(
false );
1016 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1019 mHistoZoomer->setEnabled( !btnHistoMax->isChecked() );
1020 mHistoPicker->setEnabled( btnHistoMax->isChecked() );
1022 updateHistoMarkers();
1032 QList<double> minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1033 QList<double> majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1034 const double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1035 double min = majorTicks[0] - diff;
1037 min -= ( majorTicks[1] - majorTicks[0] );
1038 const double max = scale->upperBound();
1039 double closest = target;
1040 double current = min;
1042 while ( current < max )
1045 if ( current > target )
1047 closest = ( std::fabs( target - current + diff ) < std::fabs( target - current ) ) ? current - diff : current;
1053 return QLocale().toString( closest );
1056void QgsRasterHistogramWidget::histoPickerSelected( QPointF pos )
1058 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1060 const QwtScaleDiv *scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1062 if ( btnHistoMin->isChecked() )
1066 btnHistoMin->setChecked(
false );
1072 btnHistoMax->setChecked(
false );
1075 if ( QApplication::overrideCursor() )
1076 QApplication::restoreOverrideCursor();
1079void QgsRasterHistogramWidget::histoPickerSelectedQwt5(
QwtDoublePoint pos )
1081 histoPickerSelected( QPointF( pos.x(), pos.y() ) );
1084void QgsRasterHistogramWidget::updateHistoMarkers()
1087 if ( leHistoMin->signalsBlocked() )
1090 if ( !mpPlot || !mHistoMarkerMin || !mHistoMarkerMax )
1093 const int bandNo = cboHistoBand->currentIndex() + 1;
1094 const QList<int> mySelectedBands = histoSelectedBands();
1096 if ( ( !mHistoShowMarkers && !btnHistoMin->isChecked() && !btnHistoMax->isChecked() ) || ( !mySelectedBands.isEmpty() && !mySelectedBands.contains( bandNo ) ) )
1098 mHistoMarkerMin->hide();
1099 mHistoMarkerMax->hide();
1104 double minVal = mHistoMin;
1105 double maxVal = mHistoMax;
1106 const QString minStr = leHistoMin->text();
1107 const QString maxStr = leHistoMax->text();
1108 if ( !minStr.isEmpty() )
1109 minVal = minStr.toDouble();
1110 if ( !maxStr.isEmpty() )
1111 maxVal = maxStr.toDouble();
1113 QPen linePen = QPen( mHistoColors.at( bandNo ) );
1114 linePen.setStyle( Qt::DashLine );
1115 mHistoMarkerMin->setLineStyle( QwtPlotMarker::VLine );
1116 mHistoMarkerMin->setLinePen( linePen );
1117 mHistoMarkerMin->setXValue( minVal );
1118 mHistoMarkerMin->show();
1119 mHistoMarkerMax->setLineStyle( QwtPlotMarker::VLine );
1120 mHistoMarkerMax->setLinePen( linePen );
1121 mHistoMarkerMax->setXValue( maxVal );
1122 mHistoMarkerMax->show();
1128QList<int> QgsRasterHistogramWidget::histoSelectedBands()
1130 QList<int> mySelectedBands;
1132 if ( mHistoShowBands != ShowAll )
1134 if ( mHistoShowBands == ShowSelected )
1136 mySelectedBands << cboHistoBand->currentIndex() + 1;
1138 else if ( mHistoShowBands == ShowRGB )
1140 mySelectedBands = rendererSelectedBands();
1144 return mySelectedBands;
1147QList<int> QgsRasterHistogramWidget::rendererSelectedBands()
1149 QList<int> mySelectedBands;
1151 if ( !mRendererWidget )
1153 mySelectedBands << -1 << -1 << -1;
1154 return mySelectedBands;
1157 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1159 mySelectedBands << mRendererWidget->selectedBand();
1161 else if ( mRendererName ==
"multibandcolor"_L1 )
1163 for (
int i = 0; i <= 2; i++ )
1165 mySelectedBands << mRendererWidget->selectedBand( i );
1169 return mySelectedBands;
1172QPair<QString, QString> QgsRasterHistogramWidget::rendererMinMax(
int bandNo )
1174 QPair<QString, QString> myMinMax;
1176 if ( !mRendererWidget )
1179 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1181 if ( bandNo == mRendererWidget->selectedBand() )
1183 myMinMax.first = mRendererWidget->min();
1184 myMinMax.second = mRendererWidget->max();
1187 else if ( mRendererName ==
"multibandcolor"_L1 )
1189 for (
int i = 0; i <= 2; i++ )
1191 if ( bandNo == mRendererWidget->selectedBand( i ) )
1193 myMinMax.first = mRendererWidget->min( i );
1194 myMinMax.second = mRendererWidget->max( i );
1210 if ( myMinMax.first.isEmpty() )
1211 myMinMax.first = QLocale().toString( mHistoMin );
1212 if ( myMinMax.second.isEmpty() )
1213 myMinMax.second = QLocale().toString( mHistoMax );
1215 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)