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 ) );
114 connect( leHistoMin, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMin );
115 connect( leHistoMax, &QLineEdit::editingFinished,
this, &QgsRasterHistogramWidget::applyHistoMax );
119 QMenu *menu =
new QMenu(
this );
120 menu->setSeparatorsCollapsible(
false );
121 btnHistoActions->setMenu( menu );
122 QActionGroup *group =
nullptr;
123 QAction *action =
nullptr;
126 group =
new QActionGroup(
this );
127 group->setExclusive(
false );
128 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
129 action =
new QAction( tr(
"Min/Max options" ), group );
130 action->setSeparator(
true );
131 menu->addAction( action );
132 action =
new QAction( tr(
"Always show min/max markers" ), group );
133 action->setData( QVariant(
"Show markers" ) );
134 action->setCheckable(
true );
135 action->setChecked( mHistoShowMarkers );
136 menu->addAction( action );
137 action =
new QAction( tr(
"Zoom to min/max" ), group );
138 action->setData( QVariant(
"Zoom min_max" ) );
139 action->setCheckable(
true );
140 action->setChecked( mHistoZoomToMinMax );
141 menu->addAction( action );
142 action =
new QAction( tr(
"Update style to min/max" ), group );
143 action->setData( QVariant(
"Update min_max" ) );
144 action->setCheckable(
true );
145 action->setChecked( mHistoUpdateStyleToMinMax );
146 menu->addAction( action );
149 group =
new QActionGroup(
this );
150 group->setExclusive(
false );
151 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
152 action =
new QAction( tr(
"Visibility" ), group );
153 action->setSeparator(
true );
154 menu->addAction( action );
155 group =
new QActionGroup(
this );
156 group->setExclusive(
true );
157 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
158 action =
new QAction( tr(
"Show all bands" ), group );
159 action->setData( QVariant(
"Show all" ) );
160 action->setCheckable(
true );
161 action->setChecked( mHistoShowBands == ShowAll );
162 menu->addAction( action );
163 action =
new QAction( tr(
"Show RGB/Gray band(s)" ), group );
164 action->setData( QVariant(
"Show RGB" ) );
165 action->setCheckable(
true );
166 action->setChecked( mHistoShowBands == ShowRGB );
167 menu->addAction( action );
168 action =
new QAction( tr(
"Show selected band" ), group );
169 action->setData( QVariant(
"Show selected" ) );
170 action->setCheckable(
true );
171 action->setChecked( mHistoShowBands == ShowSelected );
172 menu->addAction( action );
175 group =
new QActionGroup(
this );
176 group->setExclusive(
false );
177 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
178 action =
new QAction( tr(
"Display" ), group );
179 action->setSeparator(
true );
180 menu->addAction( action );
182 action =
new QAction( QString(), group );
183 action->setData( QVariant(
"Draw lines" ) );
186 action->setText( tr(
"Draw as lines" ) );
187 action->setCheckable(
true );
188 action->setChecked( mHistoDrawLines );
192 action->setText( tr(
"Draw as lines (only int layers)" ) );
193 action->setEnabled(
false );
195 menu->addAction( action );
198 action =
new QAction( tr(
"Actions" ), group );
199 action->setSeparator(
true );
200 menu->addAction( action );
203 group =
new QActionGroup(
this );
204 group->setExclusive(
false );
205 connect( group, &QActionGroup::triggered,
this, &QgsRasterHistogramWidget::histoActionTriggered );
206 action =
new QAction( tr(
"Reset" ), group );
207 action->setData( QVariant(
"Load reset" ) );
208 menu->addAction( action );
214 action =
new QAction( tr(
"Load min/max" ), group );
215 action->setSeparator(
true );
216 menu->addAction( action );
217 action =
new QAction( tr(
"Estimate (faster)" ), group );
218 action->setData( QVariant(
"Load estimate" ) );
219 menu->addAction( action );
220 action =
new QAction( tr(
"Actual (slower)" ), group );
221 action->setData( QVariant(
"Load actual" ) );
222 menu->addAction( action );
223 action =
new QAction( tr(
"Current extent" ), group );
224 action->setData( QVariant(
"Load extent" ) );
225 menu->addAction( action );
226 action =
new QAction( tr(
"Use stddev (1.0)" ), group );
227 action->setData( QVariant(
"Load 1 stddev" ) );
228 menu->addAction( action );
229 action =
new QAction( tr(
"Use stddev (custom)" ), group );
230 action->setData( QVariant(
"Load stddev" ) );
231 menu->addAction( action );
232 action =
new QAction( tr(
"Load for each band" ), group );
233 action->setData( QVariant(
"Load apply all" ) );
234 action->setCheckable(
true );
235 action->setChecked( mHistoLoadApplyAll );
236 menu->addAction( action );
240 action =
new QAction( tr(
"Recompute Histogram" ), group );
241 action->setData( QVariant(
"Compute histogram" ) );
242 menu->addAction( action );
249 mRendererName = name;
250 mRendererWidget = rendererWidget;
252 cboHistoBand_currentIndexChanged( -1 );
260 cboHistoBand_currentIndexChanged( -1 );
264 if ( QApplication::overrideCursor() )
265 QApplication::restoreOverrideCursor();
266 btnHistoMin->setChecked(
false );
267 btnHistoMax->setChecked(
false );
271void QgsRasterHistogramWidget::btnHistoCompute_clicked()
287static int getBinCount(
QgsRasterInterface *rasterInterface,
int bandNo,
int sampleSize )
296 xRes = yRes = std::sqrt( (
static_cast<double>( extent.width() ) * extent.height() ) / sampleSize );
301 const double srcXRes = extent.width() / rasterInterface->
xSize();
302 const double srcYRes = extent.height() / rasterInterface->
ySize();
303 if ( xRes < srcXRes )
305 if ( yRes < srcYRes )
309 const int histogramWidth =
static_cast<int>( extent.width() / xRes );
310 const int histogramHeight =
static_cast<int>( extent.height() / yRes );
312 int binCount =
static_cast<int>( std::min(
static_cast<qint64
>( 1000 ),
static_cast<qint64
>( histogramWidth ) * histogramHeight ) );
316 binCount =
static_cast<int>( std::min(
static_cast<qint64
>( binCount ),
static_cast<qint64
>( std::ceil( statsMax - statsMin + 1 ) ) ) );
326 const int myBandCountInt = mRasterLayer->
bandCount();
329 if ( !forceComputeFlag )
331 for (
int myIteratorInt = 1;
332 myIteratorInt <= myBandCountInt;
336 const int binCount = getBinCount( mRasterLayer->
dataProvider(), myIteratorInt, sampleSize );
337 if ( !mRasterLayer->
dataProvider()->
hasHistogram( myIteratorInt, binCount, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
QgsRectangle(), sampleSize ) )
339 QgsDebugMsgLevel( QStringLiteral(
"band %1 does not have cached histo" ).arg( myIteratorInt ), 2 );
346 stackedWidget2->setCurrentIndex( 1 );
350 QApplication::setOverrideCursor( Qt::WaitCursor );
352 for (
int myIteratorInt = 1;
353 myIteratorInt <= myBandCountInt;
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();
385 QgsDebugMsgLevel( QStringLiteral(
"raster does not have cached histogram" ), 2 );
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 == QLatin1String(
"singlebandgray" ) )
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 == QLatin1String(
"multibandcolor" ) )
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;
510 bandNumber <= myBandCountInt;
514 if ( mHistoShowBands != ShowAll )
516 if ( !mySelectedBands.contains( bandNumber ) )
525 const int binCount = getBinCount( mRasterLayer->
dataProvider(), bandNumber, sampleSize );
528 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 );
531 bool myDrawLines =
true;
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( QStringLiteral(
"computed histo min = %1 max = %2" ).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( QStringLiteral(
"Error, directory %1 non-existent (theFilename = %2)" ).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( QStringLiteral(
"band = %1 action = %2" ).arg( cboHistoBand->currentIndex() + 1 ).arg( actionName ), 2 );
747 if ( actionName == QLatin1String(
"Show markers" ) )
749 mHistoShowMarkers = actionFlag;
751 settings.
setValue( QStringLiteral(
"Raster/histogram/showMarkers" ), mHistoShowMarkers );
752 updateHistoMarkers();
755 else if ( actionName == QLatin1String(
"Zoom min_max" ) )
757 mHistoZoomToMinMax = actionFlag;
759 settings.
setValue( QStringLiteral(
"Raster/histogram/zoomToMinMax" ), mHistoZoomToMinMax );
762 else if ( actionName == QLatin1String(
"Update min_max" ) )
764 mHistoUpdateStyleToMinMax = actionFlag;
766 settings.
setValue( QStringLiteral(
"Raster/histogram/updateStyleToMinMax" ), mHistoUpdateStyleToMinMax );
769 else if ( actionName == QLatin1String(
"Show all" ) )
771 mHistoShowBands = ShowAll;
776 else if ( actionName == QLatin1String(
"Show selected" ) )
778 mHistoShowBands = ShowSelected;
783 else if ( actionName == QLatin1String(
"Show RGB" ) )
785 mHistoShowBands = ShowRGB;
790 else if ( actionName == QLatin1String(
"Draw lines" ) )
792 mHistoDrawLines = actionFlag;
794 settings.
setValue( QStringLiteral(
"Raster/histogram/drawLines" ), 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 ) == QLatin1String(
"Load " ) && 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 == QLatin1String(
"Load reset" ) )
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 == QLatin1String(
"Compute histogram" ) )
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 );
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++ )
962 max = leHistoMax->text();
963 if ( mHistoUpdateStyleToMinMax && mRendererWidget->
max( i ) != max )
965 mRendererWidget->
setMax( max, i );
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 == QLatin1String(
"singlebandgray" ) || mRendererName == QLatin1String(
"singlebandpseudocolor" ) )
1161 else if ( mRendererName == QLatin1String(
"multibandcolor" ) )
1163 for (
int i = 0; i <= 2; i++ )
1169 return mySelectedBands;
1172QPair<QString, QString> QgsRasterHistogramWidget::rendererMinMax(
int bandNo )
1174 QPair<QString, QString> myMinMax;
1176 if ( !mRendererWidget )
1179 if ( mRendererName == QLatin1String(
"singlebandgray" ) || mRendererName == QLatin1String(
"singlebandpseudocolor" ) )
1183 myMinMax.first = mRendererWidget->
min();
1184 myMinMax.second = mRendererWidget->
max();
1187 else if ( mRendererName == QLatin1String(
"multibandcolor" ) )
1189 for (
int i = 0; i <= 2; 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( 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)