QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsmeshrendererscalarsettingswidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmeshrendererscalarsettingswidget.cpp
3 ---------------------------------------
4 begin : June 2018
5 copyright : (C) 2018 by Peter Petrik
6 email : zilolv 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 ***************************************************************************/
15
17
18#include "qgis.h"
19#include "qgsmapcanvas.h"
20#include "qgsmeshlayer.h"
22#include "qgsmessagelog.h"
23
24#include <QDialogButtonBox>
25#include <QPointer>
26
27#include "moc_qgsmeshrendererscalarsettingswidget.cpp"
28
30 : QWidget( parent )
31
32{
33 setupUi( this );
34
35 mScalarMinSpinBox->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue );
36 mScalarMinSpinBox->setSpecialValueText( QString() );
37 mScalarMaxSpinBox->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue );
38 mScalarMaxSpinBox->setSpecialValueText( QString() );
39
40 mScalarMinSpinBox->setEnabled( true );
41 mScalarMaxSpinBox->setEnabled( true );
42
43 // add items to data interpolation combo box
44 mScalarInterpolationTypeComboBox->addItem( tr( "No Resampling" ), QgsMeshRendererScalarSettings::NoResampling );
45 mScalarInterpolationTypeComboBox->addItem( tr( "Neighbour Average" ), QgsMeshRendererScalarSettings::NeighbourAverage );
46 mScalarInterpolationTypeComboBox->setCurrentIndex( 0 );
47
48 mMinMaxValueTypeComboBox->addItem( tr( "Whole Mesh" ), QVariant::fromValue( Qgis::MeshRangeExtent::WholeMesh ) );
49 mMinMaxValueTypeComboBox->addItem( tr( "Current Canvas" ), QVariant::fromValue( Qgis::MeshRangeExtent::FixedCanvas ) );
50 mMinMaxValueTypeComboBox->addItem( tr( "Updated Canvas" ), QVariant::fromValue( Qgis::MeshRangeExtent::UpdatedCanvas ) );
51 mMinMaxValueTypeComboBox->setCurrentIndex( 0 );
52
53 mUserDefinedRadioButton->setChecked( true );
54 mMinMaxValueTypeComboBox->setEnabled( false );
55
56 mScalarEdgeStrokeWidthUnitSelectionWidget->setUnits( {
61 } );
62
63 // connect
64 connect( mScalarRecalculateMinMaxButton, &QPushButton::clicked, this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked );
65 connect( mScalarMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( double ) { minMaxChanged(); } );
66 connect( mScalarMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( double ) { minMaxChanged(); } );
67 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged );
68
71 connect( mScalarInterpolationTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
72
73 connect( mScalarEdgeStrokeWidthUnitSelectionWidget, &QgsUnitSelectionWidget::changed, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
74 connect( mScalarEdgeStrokeWidthSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
75 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
76 connect( mScalarEdgeStrokeWidthFixedRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
77 connect( mScalarEdgeStrokeWidthVariablePushButton, &QgsMeshVariableStrokeWidthButton::widgetChanged, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
78
79 connect( mUserDefinedRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled );
80 connect( mMinMaxRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled );
81
82 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMax );
83 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
84}
85
87{
88 mMeshLayer = layer;
89 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
90}
91
93{
94 mActiveDatasetGroup = groupIndex;
95 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
96}
97
99{
101 settings.setClassificationMinimumMaximum( spinBoxValue( mScalarMinSpinBox ), spinBoxValue( mScalarMaxSpinBox ) );
102 settings.setColorRampShader( mScalarColorRampShaderWidget->shader() );
103 settings.setOpacity( mOpacityWidget->opacity() );
104 settings.setDataResamplingMethod( dataIntepolationMethod() );
105
106 settings.setExtent( mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>() );
107
108 if ( mUserDefinedRadioButton->isChecked() )
109 {
111 }
112 else
113 {
115 }
116
117 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
118 if ( hasEdges )
119 {
120 QgsInterpolatedLineWidth edgeStrokeWidth = mScalarEdgeStrokeWidthVariablePushButton->variableStrokeWidth();
121 edgeStrokeWidth.setIsVariableWidth( mScalarEdgeStrokeWidthVariableRadioButton->isChecked() );
122 edgeStrokeWidth.setFixedStrokeWidth( mScalarEdgeStrokeWidthSpinBox->value() );
123 settings.setEdgeStrokeWidth( edgeStrokeWidth );
124 settings.setEdgeStrokeWidthUnit( mScalarEdgeStrokeWidthUnitSelectionWidget->unit() );
125 }
126
127 return settings;
128}
129
131{
132 if ( !mMeshLayer )
133 return;
134
135 if ( mActiveDatasetGroup < 0 )
136 return;
137
138 const QgsMeshRendererSettings rendererSettings = mMeshLayer->rendererSettings();
139 const QgsMeshRendererScalarSettings settings = rendererSettings.scalarSettings( mActiveDatasetGroup );
140 const QgsColorRampShader shader = settings.colorRampShader();
141
142 const double min = settings.classificationMinimum();
143 const double max = settings.classificationMaximum();
144
145 if ( std::abs( max ) < 1e-2 )
146 {
147 mScalarMinSpinBox->setDecimals( 8 );
148 mScalarMaxSpinBox->setDecimals( 8 );
149 }
150 else
151 {
152 mScalarMinSpinBox->setDecimals( 2 );
153 mScalarMaxSpinBox->setDecimals( 2 );
154 }
155
156 whileBlocking( mScalarMinSpinBox )->setValue( min );
157 whileBlocking( mScalarMaxSpinBox )->setValue( max );
158
159 whileBlocking( mMinMaxValueTypeComboBox )->setCurrentIndex( mMinMaxValueTypeComboBox->findData( QVariant::fromValue( settings.extent() ) ) );
160
162 {
163 whileBlocking( mUserDefinedRadioButton )->setChecked( false );
164 whileBlocking( mMinMaxRadioButton )->setChecked( true );
165 mScalarMinSpinBox->setEnabled( false );
166 mScalarMaxSpinBox->setEnabled( false );
167 mMinMaxValueTypeComboBox->setEnabled( true );
168 }
169 else
170 {
171 whileBlocking( mUserDefinedRadioButton )->setChecked( true );
172 whileBlocking( mMinMaxRadioButton )->setChecked( false );
173 mScalarMinSpinBox->setEnabled( true );
174 mScalarMaxSpinBox->setEnabled( true );
175 mMinMaxValueTypeComboBox->setEnabled( false );
176 }
177
178 whileBlocking( mScalarColorRampShaderWidget )->setFromShader( shader );
179 whileBlocking( mScalarColorRampShaderWidget )->setMinimumMaximum( min, max );
180 whileBlocking( mOpacityWidget )->setOpacity( settings.opacity() );
181 const int index = mScalarInterpolationTypeComboBox->findData( settings.dataResamplingMethod() );
182 whileBlocking( mScalarInterpolationTypeComboBox )->setCurrentIndex( index );
183
184 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
185 const bool hasFaces = ( mMeshLayer->contains( QgsMesh::ElementType::Face ) );
186
187 mScalarResamplingWidget->setVisible( hasFaces );
188
189 mEdgeWidthGroupBox->setVisible( hasEdges );
190
191 if ( hasEdges )
192 {
193 const QgsInterpolatedLineWidth edgeStrokeWidth = settings.edgeStrokeWidth();
194 whileBlocking( mScalarEdgeStrokeWidthVariablePushButton )->setVariableStrokeWidth( edgeStrokeWidth );
195 whileBlocking( mScalarEdgeStrokeWidthSpinBox )->setValue( edgeStrokeWidth.fixedStrokeWidth() );
196 whileBlocking( mScalarEdgeStrokeWidthVariableRadioButton )->setChecked( edgeStrokeWidth.isVariableWidth() );
197 whileBlocking( mScalarEdgeStrokeWidthUnitSelectionWidget )->setUnit( settings.edgeStrokeWidthUnit() );
198 if ( !hasFaces )
199 mOpacityContainerWidget->setVisible( false );
200
201 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
202 const double min = metadata.minimum();
203 const double max = metadata.maximum();
204 mScalarEdgeStrokeWidthVariablePushButton->setDefaultMinMaxValue( min, max );
205 }
206
207 onEdgeStrokeWidthMethodChanged();
208}
209
210double QgsMeshRendererScalarSettingsWidget::spinBoxValue( const QgsDoubleSpinBox *spinBox ) const
211{
212 if ( spinBox->value() == spinBox->clearValue() )
213 {
214 return std::numeric_limits<double>::quiet_NaN();
215 }
216
217 return spinBox->value();
218}
219
220void QgsMeshRendererScalarSettingsWidget::minMaxChanged()
221{
222 const double min = spinBoxValue( mScalarMinSpinBox );
223 const double max = spinBoxValue( mScalarMaxSpinBox );
224 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
225}
226
227void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
228{
229 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
230 const double min = metadata.minimum();
231 const double max = metadata.maximum();
232
233 if ( std::abs( max ) < 1e-2 )
234 {
235 mScalarMinSpinBox->setDecimals( 8 );
236 mScalarMaxSpinBox->setDecimals( 8 );
237 }
238 else
239 {
240 mScalarMinSpinBox->setDecimals( 2 );
241 mScalarMaxSpinBox->setDecimals( 2 );
242 }
243
244 whileBlocking( mScalarMinSpinBox )->setValue( min );
245 whileBlocking( mScalarMaxSpinBox )->setValue( max );
246 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
247}
248
249void QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged()
250{
251 const bool variableWidth = mScalarEdgeStrokeWidthVariableRadioButton->isChecked();
252 mScalarEdgeStrokeWidthVariablePushButton->setVisible( variableWidth );
253 mScalarEdgeStrokeWidthSpinBox->setVisible( !variableWidth );
254}
255
256QgsMeshRendererScalarSettings::DataResamplingMethod QgsMeshRendererScalarSettingsWidget::dataIntepolationMethod() const
257{
258 const int data = mScalarInterpolationTypeComboBox->currentData().toInt();
260 return method;
261}
262
263bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnFaces() const
264{
265 if ( !mMeshLayer )
266 return false;
267
268 if ( mActiveDatasetGroup < 0 )
269 return false;
270
271 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
272 const bool onFaces = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces );
273 return onFaces;
274}
275
276bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnEdges() const
277{
278 if ( !mMeshLayer )
279 return false;
280
281 if ( mActiveDatasetGroup < 0 )
282 return false;
283
284 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
285 const bool onEdges = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnEdges );
286 return onEdges;
287}
288
290{
291 mCanvas = canvas;
292}
293
294void QgsMeshRendererScalarSettingsWidget::recalculateMinMax()
295{
296 QgsRectangle searchExtent;
297
298 Qgis::MeshRangeExtent extentRange = mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>();
299
300 switch ( extentRange )
301 {
303 {
304 searchExtent = mMeshLayer->extent();
305 break;
306 }
309 {
310 QgsCoordinateTransform ct = QgsCoordinateTransform( mCanvas->mapSettings().destinationCrs(), mMeshLayer->crs(), QgsProject::instance() );
311 searchExtent = mCanvas->extent();
312 try
313 {
314 searchExtent = ct.transform( searchExtent );
315 }
316 catch ( const QgsCsException &e )
317 {
318 QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( e.what() ), QObject::tr( "CRS" ) );
319 // can properly transform canvas extent to meshlayer crs, use full mesh layer extent
320 searchExtent = mMeshLayer->extent();
321 }
322 break;
323 }
324 default:
325 break;
326 }
327
328 if ( !searchExtent.isEmpty() )
329 {
330 QgsMeshDatasetIndex datasetIndex = mMeshLayer->activeScalarDatasetAtTime( mCanvas->temporalRange(), mActiveDatasetGroup );
331 double min, max;
332 bool found;
333
334 found = mMeshLayer->minimumMaximumActiveScalarDataset( searchExtent, datasetIndex, min, max );
335 if ( found )
336 {
337 whileBlocking( mScalarMinSpinBox )->setValue( min );
338 whileBlocking( mScalarMaxSpinBox )->setValue( max );
339 minMaxChanged();
340 }
341 }
342}
343
344void QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled( bool toggled )
345{
346 mMinMaxValueTypeComboBox->setEnabled( !toggled );
347 mScalarMinSpinBox->setEnabled( toggled );
348 mScalarMaxSpinBox->setEnabled( toggled );
349 mScalarRecalculateMinMaxButton->setEnabled( toggled );
350 emit widgetChanged();
351}
352
353void QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled( bool toggled )
354{
355 mMinMaxValueTypeComboBox->setEnabled( toggled );
356 mScalarMinSpinBox->setEnabled( !toggled );
357 mScalarMaxSpinBox->setEnabled( !toggled );
358 mScalarRecalculateMinMaxButton->setEnabled( !toggled );
359 emit widgetChanged();
360}
@ MinimumMaximum
Real min-max values.
Definition qgis.h:6408
@ NotSet
User defined.
Definition qgis.h:6407
MeshRangeExtent
Describes the extent used to compute mesh ranges (min/max values).
Definition qgis.h:6418
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
Definition qgis.h:6421
@ WholeMesh
Whole mesh is used to compute statistics.
Definition qgis.h:6419
@ FixedCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
Definition qgis.h:6420
@ Millimeters
Millimeters.
Definition qgis.h:5341
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5345
@ Pixels
Pixels.
Definition qgis.h:5343
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5348
void widgetChanged()
Widget changed.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
@ MinimumValue
Reset value to minimum().
QString what() const
Represents a width that can vary depending on values.
void setFixedStrokeWidth(double fixedWidth)
Sets the fixed width.
void setIsVariableWidth(bool isVariableWidth)
Returns whether the width is variable.
double fixedStrokeWidth() const
Returns the fixed width.
bool isVariableWidth() const
Returns whether the width is variable.
Map canvas is a class for displaying all GIS data types on a canvas.
A collection of dataset group metadata such as whether the data is vector or scalar,...
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsRectangle extent() const override
Returns the extent of the layer.
void syncToLayer()
Synchronizes widgets state with associated mesh layer.
void setCanvas(QgsMapCanvas *canvas)
Associates map canvas with the widget.
void setLayer(QgsMeshLayer *layer)
Associates mesh layer with the widget.
void widgetChanged()
Mesh rendering settings changed.
QgsMeshRendererScalarSettings settings() const
Returns scalar settings.
QgsMeshRendererScalarSettingsWidget(QWidget *parent=nullptr)
A widget to hold the renderer scalar settings for a mesh layer.
void setActiveDatasetGroup(int groupIndex)
Associates a dataset group with the widget (should be set before syncToLayer()).
Represents a mesh renderer settings for scalar datasets.
DataResamplingMethod
Resampling of value from dataset.
@ NoResampling
Does not use resampling.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
Represents all mesh renderer settings.
QgsMeshRendererScalarSettings scalarSettings(int groupIndex) const
Returns renderer settings.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
static QgsProject * instance()
Returns the QgsProject singleton instance.
A rectangle specified with double values.
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6880