QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsrendererrasterpropertieswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrendererrasterpropertieswidget.cpp
3  ---------------------
4  begin : May 2016
5  copyright : (C) 2016 by Nathan Woodrow
6  email : woodrow dot nathan at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
17 #include "qgis.h"
18 #include "qgsmapcanvas.h"
20 #include "qgshuesaturationfilter.h"
21 #include "qgsrasterlayer.h"
34 #include "qgsapplication.h"
35 
36 
37 #include "qgsmessagelog.h"
38 
39 static void _initRendererWidgetFunctions()
40 {
41  static bool sInitialized = false;
42  if ( sInitialized )
43  return;
44 
50 
51  sInitialized = true;
52 }
53 
54 
55 
57  : QgsMapLayerConfigWidget( layer, canvas, parent )
58 
59 {
60  mRasterLayer = qobject_cast<QgsRasterLayer *>( layer );
61 
62  if ( !mRasterLayer )
63  return;
64 
65  setupUi( this );
66  connect( mResetColorRenderingBtn, &QToolButton::clicked, this, &QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked );
67 
68  _initRendererWidgetFunctions();
69 
70  mZoomedInResamplingComboBox->insertItem( 0, tr( "Nearest neighbour" ) );
71  mZoomedInResamplingComboBox->insertItem( 1, tr( "Bilinear" ) );
72  mZoomedInResamplingComboBox->insertItem( 2, tr( "Cubic" ) );
73  mZoomedOutResamplingComboBox->insertItem( 0, tr( "Nearest neighbour" ) );
74  mZoomedOutResamplingComboBox->insertItem( 1, tr( "Average" ) );
75 
76  connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::rendererChanged );
77 
78  connect( mSliderBrightness, &QAbstractSlider::valueChanged, mBrightnessSpinBox, &QSpinBox::setValue );
79  connect( mBrightnessSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderBrightness, &QAbstractSlider::setValue );
80 
81  connect( mSliderContrast, &QAbstractSlider::valueChanged, mContrastSpinBox, &QSpinBox::setValue );
82  connect( mContrastSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), mSliderContrast, &QAbstractSlider::setValue );
83 
84  // Connect saturation slider and spin box
85  connect( sliderSaturation, &QAbstractSlider::valueChanged, spinBoxSaturation, &QSpinBox::setValue );
86  connect( spinBoxSaturation, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderSaturation, &QAbstractSlider::setValue );
87 
88  // Connect colorize strength slider and spin box
89  connect( sliderColorizeStrength, &QAbstractSlider::valueChanged, spinColorizeStrength, &QSpinBox::setValue );
90  connect( spinColorizeStrength, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), sliderColorizeStrength, &QAbstractSlider::setValue );
91 
92  // enable or disable saturation slider and spin box depending on grayscale combo choice
93  connect( comboGrayscale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::toggleSaturationControls );
94 
95  // enable or disable colorize colorbutton with colorize checkbox
96  connect( mColorizeCheck, &QAbstractButton::toggled, this, &QgsRendererRasterPropertiesWidget::toggleColorizeControls );
97 
98  // Just connect the spin boxes because the sliders update the spinners
99  connect( mBrightnessSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
100  connect( mContrastSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
101  connect( spinBoxSaturation, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
102  connect( spinColorizeStrength, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
103  connect( btnColorizeColor, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
104 
105  connect( mBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
106  connect( mZoomedInResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
107  connect( mZoomedOutResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
108  connect( mMaximumOversamplingSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
109 
110  // finally sync to the layer - even though some actions may emit widgetChanged signal,
111  // this is not a problem - nobody is listening to our signals yet
112  syncToLayer( mRasterLayer );
113 
114  connect( mRasterLayer, &QgsMapLayer::styleChanged, this, &QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged );
115 }
116 
118 {
119  mMapCanvas = canvas;
120 }
121 
123 {
124  QString rendererName = cboRenderers->currentData().toString();
125  setRendererWidget( rendererName );
126  emit widgetChanged();
127 }
128 
130 {
131  if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
132  {
133  brightnessFilter->setBrightness( mSliderBrightness->value() );
134  brightnessFilter->setContrast( mSliderContrast->value() );
135  }
136 
137  if ( QgsRasterRendererWidget *rendererWidget = dynamic_cast<QgsRasterRendererWidget *>( stackedWidget->currentWidget() ) )
138  {
139  rendererWidget->doComputations();
140 
141  if ( QgsRasterRenderer *newRenderer = rendererWidget->renderer() )
142  {
143  // there are transparency related data stored in renderer instances, but they
144  // are not configured in the widget, so we need to copy them over from existing renderer
145  if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
146  newRenderer->copyCommonProperties( oldRenderer, false );
147  mRasterLayer->setRenderer( newRenderer );
148  }
149  }
150 
151  // Hue and saturation controls
152  if ( QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
153  {
154  hueSaturationFilter->setSaturation( sliderSaturation->value() );
155  hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
156  hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
157  hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
158  hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
159  }
160 
161  if ( QgsRasterResampleFilter *resampleFilter = mRasterLayer->resampleFilter() )
162  {
163  QgsRasterResampler *zoomedInResampler = nullptr;
164  QString zoomedInResamplingMethod = mZoomedInResamplingComboBox->currentText();
165  if ( zoomedInResamplingMethod == tr( "Bilinear" ) )
166  {
167  zoomedInResampler = new QgsBilinearRasterResampler();
168  }
169  else if ( zoomedInResamplingMethod == tr( "Cubic" ) )
170  {
171  zoomedInResampler = new QgsCubicRasterResampler();
172  }
173 
174  resampleFilter->setZoomedInResampler( zoomedInResampler );
175 
176  //raster resampling
177  QgsRasterResampler *zoomedOutResampler = nullptr;
178  QString zoomedOutResamplingMethod = mZoomedOutResamplingComboBox->currentText();
179  if ( zoomedOutResamplingMethod == tr( "Average" ) )
180  {
181  zoomedOutResampler = new QgsBilinearRasterResampler();
182  }
183 
184  resampleFilter->setZoomedOutResampler( zoomedOutResampler );
185 
186  resampleFilter->setMaxOversampling( mMaximumOversamplingSpinBox->value() );
187  }
188 
189  mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
190 }
191 
193 {
194  mRasterLayer = layer;
195 
196  cboRenderers->blockSignals( true );
197  cboRenderers->clear();
199  const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
200  for ( const QString &name : constRenderersList )
201  {
202  if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
203  {
204  if ( ( mRasterLayer->rasterType() != QgsRasterLayer::ColorLayer && entry.name != QLatin1String( "singlebandcolordata" ) ) ||
205  ( mRasterLayer->rasterType() == QgsRasterLayer::ColorLayer && entry.name == QLatin1String( "singlebandcolordata" ) ) )
206  {
207  cboRenderers->addItem( entry.icon(), entry.visibleName, entry.name );
208  }
209  }
210  }
211  cboRenderers->setCurrentIndex( -1 );
212  cboRenderers->blockSignals( false );
213 
214  if ( QgsRasterRenderer *renderer = mRasterLayer->renderer() )
215  {
216  setRendererWidget( renderer->type() );
217  }
218 
219  if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
220  {
221  mSliderBrightness->setValue( brightnessFilter->brightness() );
222  mSliderContrast->setValue( brightnessFilter->contrast() );
223  }
224 
225  btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
226  btnColorizeColor->setContext( QStringLiteral( "symbology" ) );
227 
228  // Hue and saturation color control
229  //set hue and saturation controls to current values
230  if ( const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
231  {
232  sliderSaturation->setValue( hueSaturationFilter->saturation() );
233  comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
234 
235  // Set initial state of saturation controls based on grayscale mode choice
236  toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
237 
238  // Set initial state of colorize controls
239  mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
240  btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
241  toggleColorizeControls( hueSaturationFilter->colorizeOn() );
242  sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
243  }
244 
245  //blend mode
246  mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
247 
248  //set combo boxes to current resampling types
249  if ( const QgsRasterResampleFilter *resampleFilter = mRasterLayer->resampleFilter() )
250  {
251  const QgsRasterResampler *zoomedInResampler = resampleFilter->zoomedInResampler();
252  if ( zoomedInResampler )
253  {
254  if ( zoomedInResampler->type() == QLatin1String( "bilinear" ) )
255  {
256  mZoomedInResamplingComboBox->setCurrentIndex( 1 );
257  }
258  else if ( zoomedInResampler->type() == QLatin1String( "cubic" ) )
259  {
260  mZoomedInResamplingComboBox->setCurrentIndex( 2 );
261  }
262  }
263  else
264  {
265  mZoomedInResamplingComboBox->setCurrentIndex( 0 );
266  }
267 
268  const QgsRasterResampler *zoomedOutResampler = resampleFilter->zoomedOutResampler();
269  if ( zoomedOutResampler )
270  {
271  if ( zoomedOutResampler->type() == QLatin1String( "bilinear" ) ) //bilinear resampler does averaging when zooming out
272  {
273  mZoomedOutResamplingComboBox->setCurrentIndex( 1 );
274  }
275  }
276  else
277  {
278  mZoomedOutResamplingComboBox->setCurrentIndex( 0 );
279  }
280  mMaximumOversamplingSpinBox->setValue( resampleFilter->maxOversampling() );
281  }
282 }
283 
284 void QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked()
285 {
286  mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
287  mSliderBrightness->setValue( 0 );
288  mSliderContrast->setValue( 0 );
289  sliderSaturation->setValue( 0 );
290  comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
291  mColorizeCheck->setChecked( false );
292  sliderColorizeStrength->setValue( 100 );
293 }
294 
295 void QgsRendererRasterPropertiesWidget::toggleSaturationControls( int grayscaleMode )
296 {
297  // Enable or disable saturation controls based on choice of grayscale mode
298  if ( grayscaleMode == 0 )
299  {
300  sliderSaturation->setEnabled( true );
301  spinBoxSaturation->setEnabled( true );
302  }
303  else
304  {
305  sliderSaturation->setEnabled( false );
306  spinBoxSaturation->setEnabled( false );
307  }
308  emit widgetChanged();
309 }
310 
311 void QgsRendererRasterPropertiesWidget::toggleColorizeControls( bool colorizeEnabled )
312 {
313  // Enable or disable colorize controls based on checkbox
314  btnColorizeColor->setEnabled( colorizeEnabled );
315  sliderColorizeStrength->setEnabled( colorizeEnabled );
316  spinColorizeStrength->setEnabled( colorizeEnabled );
317  emit widgetChanged();
318 }
319 
320 void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
321 {
322  QgsDebugMsg( "rendererName = " + rendererName );
323  QgsRasterRendererWidget *oldWidget = mRendererWidget;
324 
325  int alphaBand = -1;
326  double opacity = 1;
327  if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
328  {
329  // Retain alpha band and opacity when switching renderer
330  alphaBand = oldRenderer->alphaBand();
331  opacity = oldRenderer->opacity();
332  }
333 
334  QgsRasterRendererRegistryEntry rendererEntry;
335  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
336  {
337  if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
338  {
339  QgsDebugMsg( QStringLiteral( "renderer has widgetCreateFunction" ) );
340  // Current canvas extent (used to calc min/max) in layer CRS
342  if ( oldWidget )
343  {
344  if ( rendererName == QLatin1String( "singlebandgray" ) )
345  {
346  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::SingleBandGray, mRasterLayer->dataProvider() ) );
347  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
348  }
349  else if ( rendererName == QLatin1String( "multibandcolor" ) )
350  {
351  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::MultiBandColor, mRasterLayer->dataProvider() ) );
352  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
353  }
354  }
355  mRasterLayer->renderer()->setAlphaBand( alphaBand );
356  mRasterLayer->renderer()->setOpacity( opacity );
357  mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
358  mRendererWidget->setMapCanvas( mMapCanvas );
359  connect( mRendererWidget, &QgsRasterRendererWidget::widgetChanged, this, &QgsPanelWidget::widgetChanged );
360  stackedWidget->addWidget( mRendererWidget );
361  stackedWidget->setCurrentWidget( mRendererWidget );
362  if ( oldWidget )
363  {
364  // Compare used bands in new and old renderer and reset transparency dialog if different
365  QgsRasterRenderer *oldRenderer = oldWidget->renderer();
366  QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
367 #if 0
368  QList<int> oldBands = oldRenderer->usesBands();
369  QList<int> newBands = newRenderer->usesBands();
370 
371  if ( oldBands != newBands )
372  {
373  populateTransparencyTable( newRenderer );
374  }
375 #endif
376 
377  delete oldRenderer;
378  delete newRenderer;
379  }
380  }
381  }
382 
383  if ( mRendererWidget != oldWidget )
384  delete oldWidget;
385 
386  int widgetIndex = cboRenderers->findData( rendererName );
387  if ( widgetIndex != -1 )
388  {
389  whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
390  }
391 
392 }
393 
394 void QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged()
395 {
396  if ( mRendererWidget )
397  {
398  QgsRasterRenderer *renderer = mRasterLayer->renderer();
399  if ( QgsMultiBandColorRenderer *mbcr = dynamic_cast<QgsMultiBandColorRenderer *>( renderer ) )
400  {
401  const QgsContrastEnhancement *redCe = mbcr->redContrastEnhancement();
402  if ( redCe )
403  {
404  mRendererWidget->setMin( QString::number( redCe->minimumValue() ), 0 );
405  mRendererWidget->setMax( QString::number( redCe->maximumValue() ), 0 );
406  }
407  const QgsContrastEnhancement *greenCe = mbcr->greenContrastEnhancement();
408  if ( greenCe )
409  {
410  mRendererWidget->setMin( QString::number( greenCe->minimumValue() ), 1 );
411  mRendererWidget->setMax( QString::number( greenCe->maximumValue() ), 1 );
412  }
413  const QgsContrastEnhancement *blueCe = mbcr->blueContrastEnhancement();
414  if ( blueCe )
415  {
416  mRendererWidget->setMin( QString::number( blueCe->minimumValue() ), 2 );
417  mRendererWidget->setMax( QString::number( blueCe->maximumValue() ), 2 );
418  }
419  }
420  else if ( QgsSingleBandGrayRenderer *sbgr = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer ) )
421  {
422  const QgsContrastEnhancement *ce = sbgr->contrastEnhancement();
423  if ( ce )
424  {
425  mRendererWidget->setMin( QString::number( ce->minimumValue() ) );
426  mRendererWidget->setMax( QString::number( ce->maximumValue() ) );
427  }
428  }
429  }
430 }
A panel widget that can be shown in the map style dock.
double maximumValue() const
Returns the maximum value for the contrast enhancement range.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Base class for all map layer types.
Definition: qgsmaplayer.h:79
Cubic Raster Resampler.
Interface for resampling rasters (e.g.
QgsHueSaturationFilter * hueSaturationFilter() const
Returns the raster&#39;s hue/saturation filter.
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction
void setRenderer(QgsRasterRenderer *renderer)
Sets the raster&#39;s renderer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QgsRectangle outputExtentToLayerExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from output CRS to layer&#39;s CRS
double minimumValue() const
Returns the minimum value for the contrast enhancement range.
Resample filter pipe for rasters.
void syncToLayer(QgsRasterLayer *layer)
Sync the widget to the given layer.
QgsRasterRenderer * renderer() const
Returns the raster&#39;s renderer.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
virtual void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
QgsBrightnessContrastFilter * brightnessFilter() const
Returns the raster&#39;s brightness/contrast filter.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
virtual void setMax(const QString &value, int index=0)
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Creates new raster renderer widget.
QgsRendererRasterPropertiesWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
A widget to hold the renderer properties for a raster layer.
virtual QString type() const =0
Gets a descriptive type identifier for this raster resampler.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
Raster renderer pipe for single band gray.
LayerType rasterType()
Returns the raster layer type (which is a read only property).
void setAlphaBand(int band)
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
void widgetChanged()
Emitted when the widget state changes.
void apply() override
Apply the changes from the dialog to the layer.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Registry for raster renderer entries.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the dialog.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void rendererChanged()
called when user changes renderer type
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:227
QgsRasterResampleFilter * resampleFilter() const
Returns the raster&#39;s resample filter.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Factory method to create the renderer for this type.
Brightness/contrast filter pipe for rasters.
Bilinear Raster Resampler.
Color and saturation filter pipe for rasters.
Renderer for multiband images with the color components.
Manipulates raster pixel values so that they enhanceContrast or clip into a specified numerical range...
virtual void setMin(const QString &value, int index=0)
void setOpacity(double opacity)
Sets the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1...
void widgetChanged()
Emitted when something on the widget has changed.
virtual QgsRasterRenderer * renderer()=0
void insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application&#39;s raster renderer registry, used for managing raster layer renderers...
Raster renderer pipe that applies colors to a raster.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.