29#include <QActionGroup>
34#include <QRandomGenerator>
37#include "moc_qgsrasterhistogramwidget.cpp"
39using namespace Qt::StringLiterals;
42#include <qwt_global.h>
43#include <qwt_plot_canvas.h>
44#include <qwt_legend.h>
46#include <qwt_plot_curve.h>
47#include <qwt_plot_grid.h>
48#include <qwt_plot_marker.h>
49#include <qwt_plot_picker.h>
50#include <qwt_picker_machine.h>
51#include <qwt_plot_zoomer.h>
52#include <qwt_plot_layout.h>
53#include <qwt_plot_renderer.h>
54#include <qwt_plot_histogram.h>
55#include <qwt_scale_div.h>
69 connect( mSaveAsImageButton, &QToolButton::clicked,
this, &QgsRasterHistogramWidget::mSaveAsImageButton_clicked );
70 connect( cboHistoBand,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged );
71 connect( btnHistoMin, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMin_toggled );
72 connect( btnHistoMax, &QToolButton::toggled,
this, &QgsRasterHistogramWidget::btnHistoMax_toggled );
73 connect( btnHistoCompute, &QPushButton::clicked,
this, &QgsRasterHistogramWidget::btnHistoCompute_clicked );
77 mRendererWidget =
nullptr;
78 mRendererName = u
"singlebandgray"_s;
83 mHistoPicker =
nullptr;
84 mHistoZoomer =
nullptr;
85 mHistoMarkerMin =
nullptr;
86 mHistoMarkerMax =
nullptr;
95 mHistoShowBands = ShowAll;
101 const int myBandCountInt = mRasterLayer->bandCount();
102 for (
int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
104 cboHistoBand->addItem( mRasterLayer->bandName( myIteratorInt ) );
105 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( myIteratorInt );
119 connect( leHistoMin, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMin );
120 connect( leHistoMax, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMax );
124 QMenu *menu =
new QMenu(
this );
125 menu->setSeparatorsCollapsible(
false );
126 btnHistoActions->setMenu( menu );
127 QActionGroup *group =
nullptr;
128 QAction *action =
nullptr;
131 group =
new QActionGroup(
this );
132 group->setExclusive(
false );
133 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
134 action =
new QAction( tr(
"Min/Max options" ), group );
135 action->setSeparator(
true );
136 menu->addAction( action );
137 action =
new QAction( tr(
"Always show min/max markers" ), group );
138 action->setData( QVariant(
"Show markers" ) );
139 action->setCheckable(
true );
140 action->setChecked( mHistoShowMarkers );
141 menu->addAction( action );
142 action =
new QAction( tr(
"Zoom to min/max" ), group );
143 action->setData( QVariant(
"Zoom min_max" ) );
144 action->setCheckable(
true );
145 action->setChecked( mHistoZoomToMinMax );
146 menu->addAction( action );
147 action =
new QAction( tr(
"Update style to min/max" ), group );
148 action->setData( QVariant(
"Update min_max" ) );
149 action->setCheckable(
true );
150 action->setChecked( mHistoUpdateStyleToMinMax );
151 menu->addAction( action );
154 group =
new QActionGroup(
this );
155 group->setExclusive(
false );
156 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
157 action =
new QAction( tr(
"Visibility" ), group );
158 action->setSeparator(
true );
159 menu->addAction( action );
160 group =
new QActionGroup(
this );
161 group->setExclusive(
true );
162 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
163 action =
new QAction( tr(
"Show all bands" ), group );
164 action->setData( QVariant(
"Show all" ) );
165 action->setCheckable(
true );
166 action->setChecked( mHistoShowBands == ShowAll );
167 menu->addAction( action );
168 action =
new QAction( tr(
"Show RGB/Gray band(s)" ), group );
169 action->setData( QVariant(
"Show RGB" ) );
170 action->setCheckable(
true );
171 action->setChecked( mHistoShowBands == ShowRGB );
172 menu->addAction( action );
173 action =
new QAction( tr(
"Show selected band" ), group );
174 action->setData( QVariant(
"Show selected" ) );
175 action->setCheckable(
true );
176 action->setChecked( mHistoShowBands == ShowSelected );
177 menu->addAction( action );
180 group =
new QActionGroup(
this );
181 group->setExclusive(
false );
182 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
183 action =
new QAction( tr(
"Display" ), group );
184 action->setSeparator(
true );
185 menu->addAction( action );
187 action =
new QAction( QString(), group );
188 action->setData( QVariant(
"Draw lines" ) );
191 action->setText( tr(
"Draw as lines" ) );
192 action->setCheckable(
true );
193 action->setChecked( mHistoDrawLines );
197 action->setText( tr(
"Draw as lines (only int layers)" ) );
198 action->setEnabled(
false );
200 menu->addAction( action );
203 action =
new QAction( tr(
"Actions" ), group );
204 action->setSeparator(
true );
205 menu->addAction( action );
208 group =
new QActionGroup(
this );
209 group->setExclusive(
false );
210 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
211 action =
new QAction( tr(
"Reset" ), group );
212 action->setData( QVariant(
"Load reset" ) );
213 menu->addAction( action );
219 action =
new QAction( tr(
"Load min/max" ), group );
220 action->setSeparator(
true );
221 menu->addAction( action );
222 action =
new QAction( tr(
"Estimate (faster)" ), group );
223 action->setData( QVariant(
"Load estimate" ) );
224 menu->addAction( action );
225 action =
new QAction( tr(
"Actual (slower)" ), group );
226 action->setData( QVariant(
"Load actual" ) );
227 menu->addAction( action );
228 action =
new QAction( tr(
"Current extent" ), group );
229 action->setData( QVariant(
"Load extent" ) );
230 menu->addAction( action );
231 action =
new QAction( tr(
"Use stddev (1.0)" ), group );
232 action->setData( QVariant(
"Load 1 stddev" ) );
233 menu->addAction( action );
234 action =
new QAction( tr(
"Use stddev (custom)" ), group );
235 action->setData( QVariant(
"Load stddev" ) );
236 menu->addAction( action );
237 action =
new QAction( tr(
"Load for each band" ), group );
238 action->setData( QVariant(
"Load apply all" ) );
239 action->setCheckable(
true );
240 action->setChecked( mHistoLoadApplyAll );
241 menu->addAction( action );
245 action =
new QAction( tr(
"Recompute Histogram" ), group );
246 action->setData( QVariant(
"Compute histogram" ) );
247 menu->addAction( action );
251 QwtPlotCanvas *canvas = qobject_cast<QwtPlotCanvas *>( mpPlot->canvas() );
254 canvas->setFrameStyle( QFrame::NoFrame );
260 mRendererName = name;
261 mRendererWidget = rendererWidget;
263 cboHistoBand_currentIndexChanged( -1 );
271 cboHistoBand_currentIndexChanged( -1 );
275 if ( QApplication::overrideCursor() )
276 QApplication::restoreOverrideCursor();
277 btnHistoMin->setChecked(
false );
278 btnHistoMax->setChecked(
false );
282void QgsRasterHistogramWidget::btnHistoCompute_clicked()
298static int getBinCount(
QgsRasterInterface *rasterInterface,
int bandNo,
int sampleSize )
307 xRes = yRes = std::sqrt( (
static_cast<double>( extent.width() ) * extent.height() ) / sampleSize );
312 const double srcXRes = extent.width() / rasterInterface->
xSize();
313 const double srcYRes = extent.height() / rasterInterface->
ySize();
314 if ( xRes < srcXRes )
316 if ( yRes < srcYRes )
320 const int histogramWidth =
static_cast<int>( extent.width() / xRes );
321 const int histogramHeight =
static_cast<int>( extent.height() / yRes );
323 int binCount =
static_cast<int>( std::min(
static_cast<qint64
>( 1000 ),
static_cast<qint64
>( histogramWidth ) * histogramHeight ) );
327 binCount =
static_cast<int>( std::min(
static_cast<qint64
>( binCount ),
static_cast<qint64
>( std::ceil( statsMax - statsMin + 1 ) ) ) );
337 const int myBandCountInt = mRasterLayer->bandCount();
340 if ( !forceComputeFlag )
342 for (
int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
345 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
346 if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize ) )
348 QgsDebugMsgLevel( u
"band %1 does not have cached histo"_s.arg( myIteratorInt ), 2 );
355 stackedWidget2->setCurrentIndex( 1 );
359 QApplication::setOverrideCursor( Qt::WaitCursor );
361 for (
int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt )
364 const int binCount = getBinCount( mRasterLayer->dataProvider(), myIteratorInt, sampleSize );
365 mRasterLayer->dataProvider()->histogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
369 stackedWidget2->setCurrentIndex( 0 );
370 QApplication::restoreOverrideCursor();
387 const int myBandCountInt = mRasterLayer->bandCount();
393 stackedWidget2->setCurrentIndex( 2 );
398 mpPlot->detachItems();
401 mpPlot->setAutoDelete(
true );
402 mpPlot->setTitle( QObject::tr(
"Raster Histogram" ) );
403 mpPlot->insertLegend(
new QwtLegend(), QwtPlot::BottomLegend );
405 mpPlot->setAxisTitle( QwtPlot::xBottom, QObject::tr(
"Pixel Value" ) );
406 mpPlot->setAxisTitle( QwtPlot::yLeft, QObject::tr(
"Frequency" ) );
407 mpPlot->setAxisAutoScale( QwtPlot::yLeft );
412 QwtPlotGrid *plotGrid =
new QwtPlotGrid();
413 plotGrid->setMajorPen( palette().color( QPalette::WindowText ), 1, Qt::PenStyle::DotLine );
414 plotGrid->attach( mpPlot );
417 mHistoColors.clear();
418 mHistoColors << Qt::black;
419 QVector<QColor> myColors;
420 myColors << Qt::red << Qt::green << Qt::blue << Qt::magenta << Qt::darkYellow << Qt::cyan;
423 QRandomGenerator colorGenerator( myBandCountInt * 100 );
424 while ( myColors.size() <= myBandCountInt )
426 myColors << QColor( colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ), colorGenerator.bounded( 1, 256 ) );
431 QList<int> mySelectedBands = rendererSelectedBands();
432 if ( mRendererName ==
"singlebandgray"_L1 )
434 const int myGrayBand = mySelectedBands[0];
435 for (
int i = 1; i <= myBandCountInt; i++ )
437 if ( i == myGrayBand )
439 mHistoColors << Qt::darkGray;
440 cboHistoBand->setItemData( i - 1, QColor( Qt::darkGray ), Qt::ForegroundRole );
444 if ( !myColors.isEmpty() )
446 mHistoColors << myColors.first();
447 myColors.pop_front();
451 mHistoColors << Qt::black;
453 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
458 else if ( mRendererName ==
"multibandcolor"_L1 )
460 const int myRedBand = mySelectedBands[0];
461 const int myGreenBand = mySelectedBands[1];
462 const int myBlueBand = mySelectedBands[2];
465 myColors.remove( 0, 3 );
466 for (
int i = 1; i <= myBandCountInt; i++ )
469 if ( i == myRedBand )
471 else if ( i == myGreenBand )
473 else if ( i == myBlueBand )
477 if ( !myColors.isEmpty() )
479 myColor = myColors.first();
480 myColors.pop_front();
486 cboHistoBand->setItemData( i - 1, QColor( Qt::black ), Qt::ForegroundRole );
488 if ( i == myRedBand || i == myGreenBand || i == myBlueBand )
490 cboHistoBand->setItemData( i - 1, myColor, Qt::ForegroundRole );
492 mHistoColors << myColor;
497 mHistoColors << myColors;
512 bool myFirstIteration =
true;
514 mySelectedBands = histoSelectedBands();
515 double myBinXStep = 1;
518 for (
int bandNumber = 1; bandNumber <= myBandCountInt; ++bandNumber )
521 if ( mHistoShowBands != ShowAll )
523 if ( !mySelectedBands.contains( bandNumber ) )
532 const int binCount = getBinCount( mRasterLayer->dataProvider(), bandNumber, sampleSize );
534 = mRasterLayer->dataProvider()->histogram( bandNumber, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize,
false, feedback.get() );
538 const Qgis::DataType mySrcDataType = mRasterLayer->dataProvider()->sourceDataType( bandNumber );
539 bool myDrawLines =
true;
540 if ( !mHistoDrawLines
546 QwtPlotCurve *mypCurve =
nullptr;
549 mypCurve =
new QwtPlotCurve( tr(
"Band %1" ).arg( bandNumber ) );
551 mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
552 mypCurve->setPen( QPen( mHistoColors.at( bandNumber ) ) );
555 QwtPlotHistogram *mypHisto =
nullptr;
558 mypHisto =
new QwtPlotHistogram( tr(
"Band %1" ).arg( bandNumber ) );
559 mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
561 mypHisto->setPen( QPen( Qt::lightGray ) );
563 mypHisto->setBrush( QBrush( mHistoColors.at( bandNumber ) ) );
566 QVector<QPointF> data;
567 QVector<QwtIntervalSample> dataHisto;
571 myBinX = myHistogram.
minimum + myBinXStep / 2.0;
573 for (
int myBin = 0; myBin < myHistogram.
binCount; myBin++ )
578 data << QPointF( myBinX, myBinValue );
582 dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
584 myBinX += myBinXStep;
589 mypCurve->setSamples( data );
590 mypCurve->attach( mpPlot );
594 mypHisto->setSamples( dataHisto );
595 mypHisto->attach( mpPlot );
598 if ( myFirstIteration || mHistoMin > myHistogram.
minimum )
600 mHistoMin = myHistogram.
minimum;
602 if ( myFirstIteration || mHistoMax < myHistogram.
maximum )
604 mHistoMax = myHistogram.
maximum;
606 QgsDebugMsgLevel( u
"computed histo min = %1 max = %2"_s.arg( mHistoMin ).arg( mHistoMax ), 2 );
607 myFirstIteration =
false;
610 if ( mHistoMin < mHistoMax )
616 mpPlot->setAxisScale( QwtPlot::xBottom, mHistoMin - myBinXStep / 2, mHistoMax + myBinXStep / 2 );
617 mpPlot->setEnabled(
true );
622 mHistoMarkerMin =
new QwtPlotMarker();
623 mHistoMarkerMin->attach( mpPlot );
624 mHistoMarkerMax =
new QwtPlotMarker();
625 mHistoMarkerMax->attach( mpPlot );
626 updateHistoMarkers();
631 mHistoPicker =
new QwtPlotPicker( mpPlot->canvas() );
633 mHistoPicker->setTrackerMode( QwtPicker::AlwaysOff );
634 mHistoPicker->setRubberBand( QwtPicker::VLineRubberBand );
635 mHistoPicker->setStateMachine(
new QwtPickerDragPointMachine );
636 connect( mHistoPicker,
static_cast<void ( QwtPlotPicker::* )(
const QPointF & )
>( &QwtPlotPicker::selected ),
this, &QgsRasterHistogramWidget::histoPickerSelected );
638 mHistoPicker->setEnabled(
false );
643 mHistoZoomer =
new QwtPlotZoomer( mpPlot->canvas() );
644 mHistoZoomer->setStateMachine(
new QwtPickerDragRectMachine );
645 mHistoZoomer->setTrackerMode( QwtPicker::AlwaysOff );
647 mHistoZoomer->setEnabled(
true );
651 mpPlot->setDisabled(
true );
653 mHistoPicker->setEnabled(
false );
655 mHistoZoomer->setEnabled(
false );
658 stackedWidget2->setCurrentIndex( 0 );
662 QApplication::restoreOverrideCursor();
665void QgsRasterHistogramWidget::mSaveAsImageButton_clicked()
671 const QFileInfo myInfo( myFileNameAndFilter.first );
672 if ( !myInfo.baseName().isEmpty() )
681 const QFileInfo myInfo( filename );
682 const QDir myDir( myInfo.dir() );
683 if ( !myDir.exists() )
685 QgsDebugError( u
"Error, directory %1 non-existent (theFilename = %2)"_s.arg( myDir.absolutePath(), filename ) );
690 QPixmap myPixmap( width, height );
691 const QRect myQRect( 5, 5, width - 10, height - 10 );
692 myPixmap.fill( Qt::white );
694 QwtPlotRenderer myRenderer;
695 myRenderer.setDiscardFlags( QwtPlotRenderer::DiscardBackground | QwtPlotRenderer::DiscardCanvasBackground );
696 myRenderer.setLayoutFlags( QwtPlotRenderer::FrameWithScales );
699 myPainter.begin( &myPixmap );
700 myRenderer.render( mpPlot, &myPainter, myQRect );
704 myPixmap.save( filename,
nullptr, quality );
712 cboHistoBand->setCurrentIndex( bandNo - 1 );
715void QgsRasterHistogramWidget::cboHistoBand_currentIndexChanged(
int index )
717 if ( mHistoShowBands == ShowSelected )
721 index = cboHistoBand->currentIndex();
724 mHistoPicker->setEnabled(
false );
725 mHistoPicker->setRubberBandPen( QPen( mHistoColors.at( index + 1 ) ) );
728 mHistoZoomer->setEnabled(
true );
729 btnHistoMin->setEnabled(
true );
730 btnHistoMax->setEnabled(
true );
732 const QPair<QString, QString> myMinMax = rendererMinMax( index + 1 );
733 leHistoMin->setText( myMinMax.first );
734 leHistoMax->setText( myMinMax.second );
740void QgsRasterHistogramWidget::histoActionTriggered( QAction *action )
744 histoAction( action->data().toString(), action->isChecked() );
749 if ( actionName.isEmpty() )
753 QgsDebugMsgLevel( u
"band = %1 action = %2"_s.arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ), 2 );
756 if ( actionName ==
"Show markers"_L1 )
758 mHistoShowMarkers = actionFlag;
760 updateHistoMarkers();
763 else if ( actionName ==
"Zoom min_max"_L1 )
765 mHistoZoomToMinMax = actionFlag;
769 else if ( actionName ==
"Update min_max"_L1 )
771 mHistoUpdateStyleToMinMax = actionFlag;
775 else if ( actionName ==
"Show all"_L1 )
777 mHistoShowBands = ShowAll;
782 else if ( actionName ==
"Show selected"_L1 )
784 mHistoShowBands = ShowSelected;
789 else if ( actionName ==
"Show RGB"_L1 )
791 mHistoShowBands = ShowRGB;
796 else if ( actionName ==
"Draw lines"_L1 )
798 mHistoDrawLines = actionFlag;
800 btnHistoCompute_clicked();
804 else if ( actionName ==
"Load apply all" )
806 mHistoLoadApplyAll = actionFlag;
807 settings.setValue(
"/Raster/histogram/loadApplyAll", mHistoLoadApplyAll );
813 else if ( actionName.left( 5 ) ==
"Load "_L1 && mRendererWidget )
815 QVector<int> myBands;
819 double minMaxValues[2];
822 if ( mHistoLoadApplyAll )
824 int myBandCountInt = mRasterLayer->bandCount();
825 for (
int i = 1; i <= myBandCountInt; i++ )
827 if ( i != cboHistoBand->currentIndex() + 1 )
834 myBands << cboHistoBand->currentIndex() + 1;
838 double myStdDev = 1.0;
839 if ( actionName ==
"Load stddev" )
841 myStdDev = mRendererWidget->stdDev().toDouble();
846 leHistoMin->blockSignals(
true );
847 leHistoMax->blockSignals(
true );
850 const auto constMyBands = myBands;
851 for (
const int bandNo : constMyBands )
855 if ( actionName ==
"Load actual" )
857 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Actual,
858 bandNo, minMaxValues );
860 else if ( actionName ==
"Load estimate" )
862 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::Estimate,
863 bandNo, minMaxValues );
865 else if ( actionName ==
"Load extent" )
867 ok = mRendererWidget->bandMinMax( QgsRasterRendererWidget::CurrentExtent,
868 bandNo, minMaxValues );
870 else if ( actionName ==
"Load 1 stddev" ||
871 actionName ==
"Load stddev" )
873 ok = mRendererWidget->bandMinMaxFromStdDev( myStdDev, bandNo, minMaxValues );
878 cboHistoBand->setCurrentIndex( bandNo - 1 );
879 if ( !ok || actionName ==
"Load reset"_L1 )
887 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
889 (
Qgis::DataType ) mRasterLayer->dataProvider()->dataType( bandNo ) );
893 leHistoMin->setText( QString::number( minMaxValues[0] ) );
894 leHistoMax->setText( QString::number( minMaxValues[1] ) );
901 leHistoMin->blockSignals(
false );
902 leHistoMax->blockSignals(
false );
903 updateHistoMarkers();
905 else if ( actionName ==
"Compute histogram"_L1 )
907 btnHistoCompute_clicked();
916void QgsRasterHistogramWidget::applyHistoMin()
918 if ( !mRendererWidget )
921 const int bandNo = cboHistoBand->currentIndex() + 1;
922 const QList<int> selectedBands = rendererSelectedBands();
924 for (
int i = 0; i <= selectedBands.size(); i++ )
928 min = leHistoMin->text();
929 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
min( i ) != min )
931 mRendererWidget->
setMin( min, i );
936 if ( mRendererWidget->minMaxWidget() )
938 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
944 updateHistoMarkers();
946 if ( !min.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
948 QRectF rect = mHistoZoomer->zoomRect();
949 rect.setLeft( min.toDouble() );
950 mHistoZoomer->zoom( rect );
955void QgsRasterHistogramWidget::applyHistoMax()
957 if ( !mRendererWidget )
960 const int bandNo = cboHistoBand->currentIndex() + 1;
961 const QList<int> mySelectedBands = rendererSelectedBands();
963 for (
int i = 0; i <= mySelectedBands.size(); i++ )
965 if ( bandNo == mRendererWidget->selectedBand( i ) )
967 max = leHistoMax->text();
968 if ( mHistoUpdateStyleToMinMax && mRendererWidget->max( i ) != max )
970 mRendererWidget->setMax( max, i );
975 if ( mRendererWidget->minMaxWidget() )
977 mRendererWidget->minMaxWidget()->userHasSetManualMinMaxValues();
983 updateHistoMarkers();
985 if ( !max.isEmpty() && mHistoZoomToMinMax && mHistoZoomer )
987 QRectF rect = mHistoZoomer->zoomRect();
988 rect.setRight( max.toDouble() );
989 mHistoZoomer->zoom( rect );
994void QgsRasterHistogramWidget::btnHistoMin_toggled()
996 if ( mpPlot && mHistoPicker )
998 if ( QApplication::overrideCursor() )
999 QApplication::restoreOverrideCursor();
1000 if ( btnHistoMin->isChecked() )
1002 btnHistoMax->setChecked(
false );
1003 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1006 mHistoZoomer->setEnabled( !btnHistoMin->isChecked() );
1007 mHistoPicker->setEnabled( btnHistoMin->isChecked() );
1009 updateHistoMarkers();
1012void QgsRasterHistogramWidget::btnHistoMax_toggled()
1014 if ( mpPlot && mHistoPicker )
1016 if ( QApplication::overrideCursor() )
1017 QApplication::restoreOverrideCursor();
1018 if ( btnHistoMax->isChecked() )
1020 btnHistoMin->setChecked(
false );
1021 QApplication::setOverrideCursor( Qt::PointingHandCursor );
1024 mHistoZoomer->setEnabled( !btnHistoMax->isChecked() );
1025 mHistoPicker->setEnabled( btnHistoMax->isChecked() );
1027 updateHistoMarkers();
1037 QList<double> minorTicks = scale->ticks( QwtScaleDiv::MinorTick );
1038 QList<double> majorTicks = scale->ticks( QwtScaleDiv::MajorTick );
1039 const double diff = ( minorTicks[1] - minorTicks[0] ) / div;
1040 double min = majorTicks[0] - diff;
1042 min -= ( majorTicks[1] - majorTicks[0] );
1043 const double max = scale->upperBound();
1044 double closest = target;
1045 double current = min;
1047 while ( current < max )
1050 if ( current > target )
1052 closest = ( std::fabs( target - current + diff ) < std::fabs( target - current ) ) ? current - diff : current;
1058 return QLocale().toString( closest );
1061void QgsRasterHistogramWidget::histoPickerSelected( QPointF pos )
1063 if ( btnHistoMin->isChecked() || btnHistoMax->isChecked() )
1065 const QwtScaleDiv *scale = &mpPlot->axisScaleDiv( QwtPlot::xBottom );
1067 if ( btnHistoMin->isChecked() )
1071 btnHistoMin->setChecked(
false );
1077 btnHistoMax->setChecked(
false );
1080 if ( QApplication::overrideCursor() )
1081 QApplication::restoreOverrideCursor();
1084void QgsRasterHistogramWidget::histoPickerSelectedQwt5(
QwtDoublePoint pos )
1086 histoPickerSelected( QPointF( pos.x(), pos.y() ) );
1089void QgsRasterHistogramWidget::updateHistoMarkers()
1092 if ( leHistoMin->signalsBlocked() )
1095 if ( !mpPlot || !mHistoMarkerMin || !mHistoMarkerMax )
1098 const int bandNo = cboHistoBand->currentIndex() + 1;
1099 const QList<int> mySelectedBands = histoSelectedBands();
1101 if ( ( !mHistoShowMarkers && !btnHistoMin->isChecked() && !btnHistoMax->isChecked() ) || ( !mySelectedBands.isEmpty() && !mySelectedBands.contains( bandNo ) ) )
1103 mHistoMarkerMin->hide();
1104 mHistoMarkerMax->hide();
1109 double minVal = mHistoMin;
1110 double maxVal = mHistoMax;
1111 const QString minStr = leHistoMin->text();
1112 const QString maxStr = leHistoMax->text();
1113 if ( !minStr.isEmpty() )
1114 minVal = minStr.toDouble();
1115 if ( !maxStr.isEmpty() )
1116 maxVal = maxStr.toDouble();
1118 QPen linePen = QPen( mHistoColors.at( bandNo ) );
1119 linePen.setStyle( Qt::DashLine );
1120 mHistoMarkerMin->setLineStyle( QwtPlotMarker::VLine );
1121 mHistoMarkerMin->setLinePen( linePen );
1122 mHistoMarkerMin->setXValue( minVal );
1123 mHistoMarkerMin->show();
1124 mHistoMarkerMax->setLineStyle( QwtPlotMarker::VLine );
1125 mHistoMarkerMax->setLinePen( linePen );
1126 mHistoMarkerMax->setXValue( maxVal );
1127 mHistoMarkerMax->show();
1133QList<int> QgsRasterHistogramWidget::histoSelectedBands()
1135 QList<int> mySelectedBands;
1137 if ( mHistoShowBands != ShowAll )
1139 if ( mHistoShowBands == ShowSelected )
1141 mySelectedBands << cboHistoBand->currentIndex() + 1;
1143 else if ( mHistoShowBands == ShowRGB )
1145 mySelectedBands = rendererSelectedBands();
1149 return mySelectedBands;
1152QList<int> QgsRasterHistogramWidget::rendererSelectedBands()
1154 QList<int> mySelectedBands;
1156 if ( !mRendererWidget )
1158 mySelectedBands << -1 << -1 << -1;
1159 return mySelectedBands;
1162 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1164 mySelectedBands << mRendererWidget->selectedBand();
1166 else if ( mRendererName ==
"multibandcolor"_L1 )
1168 for (
int i = 0; i <= 2; i++ )
1170 mySelectedBands << mRendererWidget->selectedBand( i );
1174 return mySelectedBands;
1177QPair<QString, QString> QgsRasterHistogramWidget::rendererMinMax(
int bandNo )
1179 QPair<QString, QString> myMinMax;
1181 if ( !mRendererWidget )
1184 if ( mRendererName ==
"singlebandgray"_L1 || mRendererName ==
"singlebandpseudocolor"_L1 )
1186 if ( bandNo == mRendererWidget->selectedBand() )
1188 myMinMax.first = mRendererWidget->min();
1189 myMinMax.second = mRendererWidget->max();
1192 else if ( mRendererName ==
"multibandcolor"_L1 )
1194 for (
int i = 0; i <= 2; i++ )
1196 if ( bandNo == mRendererWidget->selectedBand( i ) )
1198 myMinMax.first = mRendererWidget->min( i );
1199 myMinMax.second = mRendererWidget->max( i );
1215 if ( myMinMax.first.isEmpty() )
1216 myMinMax.first = QLocale().toString( mHistoMin );
1217 if ( myMinMax.second.isEmpty() )
1218 myMinMax.second = QLocale().toString( mHistoMax );
1220 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.
static const QgsSettingsEntryBool * settingsRasterHistogramDrawLines
Settings entry raster histogram draw lines.
static const QgsSettingsEntryBool * settingsRasterHistogramZoomToMinMax
Settings entry raster histogram zoom to min/max.
static const QgsSettingsEntryBool * settingsRasterHistogramUpdateStyleToMinMax
Settings entry raster histogram update style to min/max.
static const QgsSettingsEntryBool * settingsRasterHistogramShowMarkers
Settings entry raster histogram show markers.
Stores settings for use within QGIS.
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)