QGIS API Documentation  3.12.1-București (121cc00ff0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
323  QgsRasterRendererWidget *oldWidget = mRendererWidget;
324 
325  int alphaBand = -1;
326  double opacity = 1;
327  QColor nodataColor;
328  if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
329  {
330  // Retain alpha band and opacity when switching renderer
331  alphaBand = oldRenderer->alphaBand();
332  opacity = oldRenderer->opacity();
333  nodataColor = oldRenderer->nodataColor();
334  }
335 
336  QgsRasterRendererRegistryEntry rendererEntry;
337  if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
338  {
339  if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
340  {
341  QgsDebugMsg( QStringLiteral( "renderer has widgetCreateFunction" ) );
342  // Current canvas extent (used to calc min/max) in layer CRS
344  if ( oldWidget )
345  {
346  if ( rendererName == QLatin1String( "singlebandgray" ) )
347  {
348  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::SingleBandGray, mRasterLayer->dataProvider() ) );
349  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
350  }
351  else if ( rendererName == QLatin1String( "multibandcolor" ) )
352  {
353  whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( QgsRaster::MultiBandColor, mRasterLayer->dataProvider() ) );
354  whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
355  }
356  }
357  mRasterLayer->renderer()->setAlphaBand( alphaBand );
358  mRasterLayer->renderer()->setOpacity( opacity );
359  mRasterLayer->renderer()->setNodataColor( nodataColor );
360  mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
361  mRendererWidget->setMapCanvas( mMapCanvas );
362  connect( mRendererWidget, &QgsRasterRendererWidget::widgetChanged, this, &QgsPanelWidget::widgetChanged );
363  stackedWidget->addWidget( mRendererWidget );
364  stackedWidget->setCurrentWidget( mRendererWidget );
365  if ( oldWidget )
366  {
367  // Compare used bands in new and old renderer and reset transparency dialog if different
368  QgsRasterRenderer *oldRenderer = oldWidget->renderer();
369  QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
370 #if 0
371  QList<int> oldBands = oldRenderer->usesBands();
372  QList<int> newBands = newRenderer->usesBands();
373 
374  if ( oldBands != newBands )
375  {
376  populateTransparencyTable( newRenderer );
377  }
378 #endif
379 
380  delete oldRenderer;
381  delete newRenderer;
382  }
383  }
384  }
385 
386  if ( mRendererWidget != oldWidget )
387  delete oldWidget;
388 
389  int widgetIndex = cboRenderers->findData( rendererName );
390  if ( widgetIndex != -1 )
391  {
392  whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
393  }
394 
395 }
396 
397 void QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged()
398 {
399  if ( mRendererWidget )
400  {
401  QgsRasterRenderer *renderer = mRasterLayer->renderer();
402  if ( QgsMultiBandColorRenderer *mbcr = dynamic_cast<QgsMultiBandColorRenderer *>( renderer ) )
403  {
404  const QgsContrastEnhancement *redCe = mbcr->redContrastEnhancement();
405  if ( redCe )
406  {
407  mRendererWidget->setMin( QString::number( redCe->minimumValue() ), 0 );
408  mRendererWidget->setMax( QString::number( redCe->maximumValue() ), 0 );
409  }
410  const QgsContrastEnhancement *greenCe = mbcr->greenContrastEnhancement();
411  if ( greenCe )
412  {
413  mRendererWidget->setMin( QString::number( greenCe->minimumValue() ), 1 );
414  mRendererWidget->setMax( QString::number( greenCe->maximumValue() ), 1 );
415  }
416  const QgsContrastEnhancement *blueCe = mbcr->blueContrastEnhancement();
417  if ( blueCe )
418  {
419  mRendererWidget->setMin( QString::number( blueCe->minimumValue() ), 2 );
420  mRendererWidget->setMax( QString::number( blueCe->maximumValue() ), 2 );
421  }
422  }
423  else if ( QgsSingleBandGrayRenderer *sbgr = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer ) )
424  {
425  const QgsContrastEnhancement *ce = sbgr->contrastEnhancement();
426  if ( ce )
427  {
428  mRendererWidget->setMin( QString::number( ce->minimumValue() ) );
429  mRendererWidget->setMax( QString::number( ce->maximumValue() ) );
430  }
431  }
432  }
433 }
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
Represents a raster layer.
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.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
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
void setNodataColor(const QColor &color)
Sets the color to use for shading nodata pixels.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
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.