Skip to content

Commit 3d8e3bd

Browse files
committed
new widget for raster min/max load
1 parent 64d1c02 commit 3d8e3bd

24 files changed

+610
-428
lines changed

src/app/qgsrasterlayerproperties.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,9 @@ void QgsRasterLayerProperties::setRendererWidget( const QString& rendererName )
410410
{
411411
if ( rendererEntry.widgetCreateFunction ) //single band color data renderer e.g. has no widget
412412
{
413-
mRendererWidget = ( *rendererEntry.widgetCreateFunction )( mRasterLayer );
413+
// Current canvas extent (used to calc min/max) in layer CRS
414+
QgsRectangle myExtent = mMapCanvas->mapRenderer()->outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() );
415+
mRendererWidget = ( *rendererEntry.widgetCreateFunction )( mRasterLayer, myExtent );
414416
mRendererStackedWidget->addWidget( mRendererWidget );
415417
if ( oldWidget )
416418
{

src/core/qgsmaprenderer.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,6 @@ bool QgsMapRenderer::splitLayersExtent( QgsMapLayer* layer, QgsRectangle& extent
767767
return split;
768768
}
769769

770-
771770
QgsRectangle QgsMapRenderer::layerExtentToOutputExtent( QgsMapLayer* theLayer, QgsRectangle extent )
772771
{
773772
QgsDebugMsg( QString( "sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
@@ -790,6 +789,28 @@ QgsRectangle QgsMapRenderer::layerExtentToOutputExtent( QgsMapLayer* theLayer, Q
790789
return extent;
791790
}
792791

792+
QgsRectangle QgsMapRenderer::outputExtentToLayerExtent( QgsMapLayer* theLayer, QgsRectangle extent )
793+
{
794+
QgsDebugMsg( QString( "layer sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
795+
QgsDebugMsg( QString( "layer destCRS = " + tr( theLayer )->destCRS().authid() ) );
796+
QgsDebugMsg( QString( "extent = " + extent.toString() ) );
797+
if ( hasCrsTransformEnabled() )
798+
{
799+
try
800+
{
801+
extent = tr( theLayer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
802+
}
803+
catch ( QgsCsException &cse )
804+
{
805+
QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
806+
}
807+
}
808+
809+
QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
810+
811+
return extent;
812+
}
813+
793814
QgsPoint QgsMapRenderer::layerToMapCoordinates( QgsMapLayer* theLayer, QgsPoint point )
794815
{
795816
if ( hasCrsTransformEnabled() )

src/core/qgsmaprenderer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ class CORE_EXPORT QgsMapRenderer : public QObject
168168
//! transform extent in layer's CRS to extent in output CRS
169169
QgsRectangle layerExtentToOutputExtent( QgsMapLayer* theLayer, QgsRectangle extent );
170170

171+
//! transform extent in output CRS to extent in layer's CRS
172+
QgsRectangle outputExtentToLayerExtent( QgsMapLayer* theLayer, QgsRectangle extent );
173+
171174
//! transform coordinates from layer's CRS to output CRS
172175
QgsPoint layerToMapCoordinates( QgsMapLayer* theLayer, QgsPoint point );
173176

src/core/qgsrasterdataprovider.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,44 @@ QgsRasterHistogram QgsRasterDataProvider::histogram( int theBandNo,
869869
return myHistogram;
870870
}
871871

872+
void QgsRasterDataProvider::cumulativeCut( int theBandNo,
873+
double theLowerCount, double theUpperCount,
874+
double &theLowerValue, double &theUpperValue,
875+
const QgsRectangle & theExtent,
876+
int theSampleSize )
877+
{
878+
QgsDebugMsg( QString( "theBandNo = %1 theLowerCount = %2 theUpperCount = %3 theSampleSize = %4" ).arg( theBandNo ).arg( theLowerCount ).arg( theUpperCount ).arg( theSampleSize ) );
879+
880+
QgsRasterHistogram myHistogram = histogram( theBandNo, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), theExtent, theSampleSize );
881+
882+
// Init to NaN is better than histogram min/max to catch errors
883+
theLowerValue = std::numeric_limits<double>::quiet_NaN();
884+
theUpperValue = std::numeric_limits<double>::quiet_NaN();
885+
886+
double myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
887+
int myCount = 0;
888+
int myMinCount = ( int ) qRound( theLowerCount * myHistogram.nonNullCount );
889+
int myMaxCount = ( int ) qRound( theUpperCount * myHistogram.nonNullCount );
890+
bool myLowerFound = false;
891+
QgsDebugMsg( QString( "binCount = %1 minimum = %2 maximum = %3 myBinXStep = %4" ).arg( myHistogram.binCount ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myBinXStep ) );
892+
893+
for ( int myBin = 0; myBin < myHistogram.histogramVector.size(); myBin++ )
894+
{
895+
int myBinValue = myHistogram.histogramVector.value( myBin );
896+
myCount += myBinValue;
897+
if ( !myLowerFound && myCount > myMinCount )
898+
{
899+
theLowerValue = myHistogram.minimum + myBin * myBinXStep;
900+
myLowerFound = true;
901+
}
902+
if ( myCount >= myMaxCount )
903+
{
904+
theUpperValue = myHistogram.minimum + myBin * myBinXStep;
905+
break;
906+
}
907+
}
908+
}
909+
872910
double QgsRasterDataProvider::readValue( void *data, int type, int index )
873911
{
874912
if ( !data )

src/core/qgsrasterdataprovider.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,22 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
322322
int theSampleSize = 0,
323323
bool theIncludeOutOfRange = false );
324324

325+
/** \brief Find values for cumulative pixel count cut.
326+
* @param theBandNo The band (number).
327+
* @param theLowerCount The lower count as fraction of 1, e.g. 0.02 = 2%
328+
* @param theUpperCount The upper count as fraction of 1, e.g. 0.98 = 98%
329+
* @param theLowerValue Location into which the lower value will be set.
330+
* @param theUpperValue Location into which the upper value will be set.
331+
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
332+
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
333+
*/
334+
virtual void cumulativeCut( int theBandNo,
335+
double theLowerCount,
336+
double theUpperCount,
337+
double &theLowerValue,
338+
double &theUpperValue,
339+
const QgsRectangle & theExtent = QgsRectangle(),
340+
int theSampleSize = 0 );
325341

326342
/** \brief Create pyramid overviews */
327343
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,

src/core/raster/qgsrasterrendererregistry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class QgsRasterRenderer;
3030
class QgsRasterRendererWidget;
3131

3232
typedef QgsRasterRenderer*( *QgsRasterRendererCreateFunc )( const QDomElement&, QgsRasterInterface* input );
33-
typedef QgsRasterRendererWidget*( *QgsRasterRendererWidgetCreateFunc )( QgsRasterLayer* );
33+
typedef QgsRasterRendererWidget*( *QgsRasterRendererWidgetCreateFunc )( QgsRasterLayer*, const QgsRectangle &extent );
3434

3535
struct CORE_EXPORT QgsRasterRendererRegistryEntry
3636
{

src/gui/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
SET(QGIS_GUI_SRCS
33

4+
raster/qgsrasterminmaxwidget.cpp
45
raster/qgsrasterrendererwidget.cpp
56
raster/qgsmultibandcolorrendererwidget.cpp
67
raster/qgspalettedrendererwidget.cpp
@@ -100,6 +101,7 @@ ENDIF (WITH_TOUCH)
100101

101102
SET(QGIS_GUI_MOC_HDRS
102103

104+
raster/qgsrasterminmaxwidget.h
103105
raster/qgspalettedrendererwidget.h
104106
raster/qgsmultibandcolorrendererwidget.h
105107
raster/qgssinglebandgrayrendererwidget.h

src/gui/raster/qgsmultibandcolorrendererwidget.cpp

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "qgsmultibandcolorrenderer.h"
2020
#include "qgsrasterlayer.h"
2121

22-
QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer ): QgsRasterRendererWidget( layer )
22+
QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ): QgsRasterRendererWidget( layer, extent )
2323
{
2424
setupUi( this );
2525
createValidators();
@@ -32,6 +32,19 @@ QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer
3232
return;
3333
}
3434

35+
mMinMaxWidget = new QgsRasterMinMaxWidget( layer, this );
36+
mMinMaxWidget->setExtent( extent );
37+
layout()->addWidget( mMinMaxWidget );
38+
connect( mMinMaxWidget, SIGNAL( load( int, double, double ) ),
39+
this, SLOT( loadMinMax( int, double, double ) ) );
40+
41+
connect( mRedBandComboBox, SIGNAL( currentIndexChanged( int ) ),
42+
this, SLOT( onBandChanged( int ) ) );
43+
connect( mGreenBandComboBox, SIGNAL( currentIndexChanged( int ) ),
44+
this, SLOT( onBandChanged( int ) ) );
45+
connect( mBlueBandComboBox, SIGNAL( currentIndexChanged( int ) ),
46+
this, SLOT( onBandChanged( int ) ) );
47+
3548
//fill available bands into combo boxes
3649
mRedBandComboBox->addItem( tr( "Not set" ), -1 );
3750
mGreenBandComboBox->addItem( tr( "Not set" ), -1 );
@@ -53,6 +66,7 @@ QgsMultiBandColorRendererWidget::QgsMultiBandColorRendererWidget( QgsRasterLayer
5366
}
5467

5568
setFromRenderer( mRasterLayer->renderer() );
69+
onBandChanged( 0 ); // reset mMinMaxWidget bands
5670
}
5771
}
5872

@@ -166,77 +180,82 @@ void QgsMultiBandColorRendererWidget::setCustomMinMaxValues( QgsMultiBandColorRe
166180
r->setBlueContrastEnhancement( blueEnhancement );
167181
}
168182

169-
void QgsMultiBandColorRendererWidget::on_mLoadPushButton_clicked()
183+
void QgsMultiBandColorRendererWidget::onBandChanged( int index )
170184
{
171-
int redBand = mRedBandComboBox->itemData( mRedBandComboBox->currentIndex() ).toInt();
172-
int greenBand = mGreenBandComboBox->itemData( mGreenBandComboBox->currentIndex() ).toInt();
173-
int blueBand = mBlueBandComboBox->itemData( mBlueBandComboBox->currentIndex() ).toInt();
174-
175-
loadMinMaxValueForBand( redBand, mRedMinLineEdit, mRedMaxLineEdit );
176-
loadMinMaxValueForBand( greenBand, mGreenMinLineEdit, mGreenMaxLineEdit );
177-
loadMinMaxValueForBand( blueBand, mBlueMinLineEdit, mBlueMaxLineEdit );
185+
QList<int> myBands;
186+
myBands.append( mRedBandComboBox->itemData( mRedBandComboBox->currentIndex() ).toInt() );
187+
myBands.append( mGreenBandComboBox->itemData( mGreenBandComboBox->currentIndex() ).toInt() );
188+
myBands.append( mBlueBandComboBox->itemData( mBlueBandComboBox->currentIndex() ).toInt() );
189+
mMinMaxWidget->setBands( myBands );
178190
}
179191

180-
void QgsMultiBandColorRendererWidget::setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit )
192+
void QgsMultiBandColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax )
181193
{
182-
if ( !minEdit || !maxEdit )
194+
QgsDebugMsg( QString( "theBandNo = %1 theMin = %2 theMax = %3" ).arg( theBandNo ).arg( theMin ).arg( theMax ) );
195+
196+
QLineEdit *myMinLineEdit, *myMaxLineEdit;
197+
198+
if ( mRedBandComboBox->itemData( mRedBandComboBox->currentIndex() ).toInt() == theBandNo )
183199
{
184-
return;
200+
myMinLineEdit = mRedMinLineEdit;
201+
myMaxLineEdit = mRedMaxLineEdit;
185202
}
186-
187-
if ( !ce )
203+
else if ( mGreenBandComboBox->itemData( mGreenBandComboBox->currentIndex() ).toInt() == theBandNo )
188204
{
189-
minEdit->clear();
190-
maxEdit->clear();
191-
return;
205+
myMinLineEdit = mGreenMinLineEdit;
206+
myMaxLineEdit = mGreenMaxLineEdit;
192207
}
193-
194-
minEdit->setText( QString::number( ce->minimumValue() ) );
195-
maxEdit->setText( QString::number( ce->maximumValue() ) );
196-
mContrastEnhancementAlgorithmComboBox->setCurrentIndex( mContrastEnhancementAlgorithmComboBox->findData(
197-
( int )( ce->contrastEnhancementAlgorithm() ) ) );
198-
}
199-
200-
void QgsMultiBandColorRendererWidget::loadMinMaxValueForBand( int band, QLineEdit* minEdit, QLineEdit* maxEdit )
201-
{
202-
if ( !minEdit || !maxEdit || !mRasterLayer )
208+
else if ( mBlueBandComboBox->itemData( mBlueBandComboBox->currentIndex() ).toInt() == theBandNo )
209+
{
210+
myMinLineEdit = mBlueMinLineEdit;
211+
myMaxLineEdit = mBlueMaxLineEdit;
212+
}
213+
else // should not happen
203214
{
215+
QgsDebugMsg( "Band not found" );
204216
return;
205217
}
206218

207-
double minMaxValues[2];
208-
bool ok = false;
209-
210-
if ( mEstimateRadioButton->isChecked() )
219+
if ( qIsNaN( theMin ) )
211220
{
212-
ok = bandMinMax( Estimate, band, minMaxValues );
221+
myMinLineEdit->clear();
213222
}
214-
else if ( mActualRadioButton->isChecked() )
223+
else
215224
{
216-
ok = bandMinMax( Actual, band, minMaxValues );
225+
myMinLineEdit->setText( QString::number( theMin ) );
217226
}
218-
else if ( mCurrentExtentRadioButton->isChecked() )
227+
228+
if ( qIsNaN( theMax ) )
219229
{
220-
ok = bandMinMax( CurrentExtent, band, minMaxValues );
230+
myMaxLineEdit->clear();
221231
}
222-
else if ( mUseStdDevRadioButton->isChecked() )
232+
else
223233
{
224-
QgsRasterBandStats rasterBandStats = mRasterLayer->dataProvider()->bandStatistics( band );
225-
double diff = mStdDevSpinBox->value() * rasterBandStats.stdDev;
226-
minMaxValues[0] = rasterBandStats.mean - diff;
227-
minMaxValues[1] = rasterBandStats.mean + diff;
234+
myMaxLineEdit->setText( QString::number( theMax ) );
228235
}
236+
}
229237

230-
if ( ok )
238+
void QgsMultiBandColorRendererWidget::setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit )
239+
{
240+
if ( !minEdit || !maxEdit )
231241
{
232-
minEdit->setText( QString::number( minMaxValues[0] ) );
233-
maxEdit->setText( QString::number( minMaxValues[1] ) );
242+
return;
234243
}
235-
else
244+
245+
if ( !ce )
236246
{
237247
minEdit->clear();
238248
maxEdit->clear();
249+
return;
239250
}
251+
252+
minEdit->setText( QString::number( ce->minimumValue() ) );
253+
maxEdit->setText( QString::number( ce->maximumValue() ) );
254+
255+
// QgsMultiBandColorRenderer is using individual contrast enhancements for each
256+
// band, but this widget GUI has one for all
257+
mContrastEnhancementAlgorithmComboBox->setCurrentIndex( mContrastEnhancementAlgorithmComboBox->findData(
258+
( int )( ce->contrastEnhancementAlgorithm() ) ) );
240259
}
241260

242261
void QgsMultiBandColorRendererWidget::setFromRenderer( const QgsRasterRenderer* r )

src/gui/raster/qgsmultibandcolorrendererwidget.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef QGSMULTIBANDCOLORRENDERERWIDGET_H
1919
#define QGSMULTIBANDCOLORRENDERERWIDGET_H
2020

21+
#include "qgsrasterminmaxwidget.h"
2122
#include "qgsrasterrendererwidget.h"
2223
#include "ui_qgsmultibandcolorrendererwidgetbase.h"
2324

@@ -32,8 +33,8 @@ class GUI_EXPORT QgsMultiBandColorRendererWidget: public QgsRasterRendererWidget
3233
Q_OBJECT
3334

3435
public:
35-
QgsMultiBandColorRendererWidget( QgsRasterLayer* layer );
36-
static QgsRasterRendererWidget* create( QgsRasterLayer* layer ) { return new QgsMultiBandColorRendererWidget( layer ); }
36+
QgsMultiBandColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent = QgsRectangle() );
37+
static QgsRasterRendererWidget* create( QgsRasterLayer* layer, const QgsRectangle &theExtent ) { return new QgsMultiBandColorRendererWidget( layer, theExtent ); }
3738
~QgsMultiBandColorRendererWidget();
3839

3940
QgsRasterRenderer* renderer();
@@ -44,20 +45,24 @@ class GUI_EXPORT QgsMultiBandColorRendererWidget: public QgsRasterRendererWidget
4445
QString max( int index = 0 );
4546
void setMin( QString value, int index = 0 );
4647
void setMax( QString value, int index = 0 );
47-
QString stdDev( ) { return QString::number( mStdDevSpinBox->value() ); }
48-
void setStdDev( QString value ) { mStdDevSpinBox->setValue( value.toDouble() ); }
48+
//QString stdDev( ) { return QString::number( mStdDevSpinBox->value() ); }
49+
//void setStdDev( QString value ) { mStdDevSpinBox->setValue( value.toDouble() ); }
4950
int selectedBand( int index = 0 );
5051

52+
public slots:
53+
void loadMinMax( int theBandNo, double theMin, double theMax );
54+
5155
private slots:
52-
void on_mLoadPushButton_clicked();
56+
//void on_mLoadPushButton_clicked();
57+
void onBandChanged( int );
5358

5459
private:
5560
void createValidators();
5661
void setCustomMinMaxValues( QgsMultiBandColorRenderer* r, const QgsRasterDataProvider* provider, int redBand, int GreenBand,
5762
int blueBand );
5863
/**Reads min/max values from contrast enhancement and fills values into the min/max line edits*/
5964
void setMinMaxValue( const QgsContrastEnhancement* ce, QLineEdit* minEdit, QLineEdit* maxEdit );
60-
void loadMinMaxValueForBand( int band, QLineEdit* minEdit, QLineEdit* maxEdit );
65+
QgsRasterMinMaxWidget * mMinMaxWidget;
6166
};
6267

6368
#endif // QGSMULTIBANDCOLORRENDERERWIDGET_H

src/gui/raster/qgspalettedrendererwidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "qgsrasterlayer.h"
2121
#include <QColorDialog>
2222

23-
QgsPalettedRendererWidget::QgsPalettedRendererWidget( QgsRasterLayer* layer ): QgsRasterRendererWidget( layer )
23+
QgsPalettedRendererWidget::QgsPalettedRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ): QgsRasterRendererWidget( layer, extent )
2424
{
2525
setupUi( this );
2626

src/gui/raster/qgspalettedrendererwidget.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class GUI_EXPORT QgsPalettedRendererWidget: public QgsRasterRendererWidget, priv
2828
Q_OBJECT
2929

3030
public:
31-
QgsPalettedRendererWidget( QgsRasterLayer* layer );
32-
static QgsRasterRendererWidget* create( QgsRasterLayer* layer ) { return new QgsPalettedRendererWidget( layer ); }
31+
QgsPalettedRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent = QgsRectangle() );
32+
static QgsRasterRendererWidget* create( QgsRasterLayer* layer, const QgsRectangle &theExtent ) { return new QgsPalettedRendererWidget( layer, theExtent ); }
3333
~QgsPalettedRendererWidget();
3434

3535
QgsRasterRenderer* renderer();

0 commit comments

Comments
 (0)