QGIS API Documentation 3.43.0-Master (0cdc48caa8d)
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#include "moc_qgsmeshrendererscalarsettingswidget.cpp"
18
19#include "QDialogButtonBox"
20
21#include "qgis.h"
22#include "qgsmeshlayer.h"
24#include "qgsmapcanvas.h"
25#include <QPointer>
26#include "qgsmessagelog.h"
27
29 : QWidget( parent )
30
31{
32 setupUi( this );
33
34 mScalarMinSpinBox->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue );
35 mScalarMinSpinBox->setSpecialValueText( QString() );
36 mScalarMaxSpinBox->setClearValueMode( QgsDoubleSpinBox::ClearValueMode::MinimumValue );
37 mScalarMaxSpinBox->setSpecialValueText( QString() );
38
39 mScalarMinSpinBox->setEnabled( true );
40 mScalarMaxSpinBox->setEnabled( true );
41
42 // add items to data interpolation combo box
43 mScalarInterpolationTypeComboBox->addItem( tr( "No Resampling" ), QgsMeshRendererScalarSettings::NoResampling );
44 mScalarInterpolationTypeComboBox->addItem( tr( "Neighbour Average" ), QgsMeshRendererScalarSettings::NeighbourAverage );
45 mScalarInterpolationTypeComboBox->setCurrentIndex( 0 );
46
47 mMinMaxValueTypeComboBox->addItem( tr( "Whole Mesh" ), QVariant::fromValue( Qgis::MeshRangeExtent::WholeMesh ) );
48 mMinMaxValueTypeComboBox->addItem( tr( "Current Canvas" ), QVariant::fromValue( Qgis::MeshRangeExtent::FixedCanvas ) );
49 mMinMaxValueTypeComboBox->addItem( tr( "Updated Canvas" ), QVariant::fromValue( Qgis::MeshRangeExtent::UpdatedCanvas ) );
50 mMinMaxValueTypeComboBox->setCurrentIndex( 0 );
51
52 mUserDefinedRadioButton->setChecked( true );
53 mMinMaxValueTypeComboBox->setEnabled( false );
54
55 mScalarEdgeStrokeWidthUnitSelectionWidget->setUnits(
56 {
61 }
62 );
63
64 // connect
65 connect( mScalarRecalculateMinMaxButton, &QPushButton::clicked, this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked );
66 connect( mScalarMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [=]( double ) { minMaxChanged(); } );
67 connect( mScalarMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [=]( double ) { minMaxChanged(); } );
68 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged );
69
72 connect( mScalarInterpolationTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
73
74 connect( mScalarEdgeStrokeWidthUnitSelectionWidget, &QgsUnitSelectionWidget::changed, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
75 connect( mScalarEdgeStrokeWidthSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
76 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
77 connect( mScalarEdgeStrokeWidthFixedRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
78 connect( mScalarEdgeStrokeWidthVariablePushButton, &QgsMeshVariableStrokeWidthButton::widgetChanged, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
79
80 connect( mUserDefinedRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled );
81 connect( mMinMaxRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled );
82
83 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMax );
84 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
85}
86
88{
89 mMeshLayer = layer;
90 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
91}
92
94{
95 mActiveDatasetGroup = groupIndex;
96 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
97}
98
100{
102 settings.setClassificationMinimumMaximum( spinBoxValue( mScalarMinSpinBox ), spinBoxValue( mScalarMaxSpinBox ) );
103 settings.setColorRampShader( mScalarColorRampShaderWidget->shader() );
104 settings.setOpacity( mOpacityWidget->opacity() );
105 settings.setDataResamplingMethod( dataIntepolationMethod() );
106
107 settings.setExtent( mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>() );
108
109 if ( mUserDefinedRadioButton->isChecked() )
110 {
112 }
113 else
114 {
116 }
117
118 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
119 if ( hasEdges )
120 {
121 QgsInterpolatedLineWidth edgeStrokeWidth = mScalarEdgeStrokeWidthVariablePushButton->variableStrokeWidth();
122 edgeStrokeWidth.setIsVariableWidth( mScalarEdgeStrokeWidthVariableRadioButton->isChecked() );
123 edgeStrokeWidth.setFixedStrokeWidth( mScalarEdgeStrokeWidthSpinBox->value() );
124 settings.setEdgeStrokeWidth( edgeStrokeWidth );
125 settings.setEdgeStrokeWidthUnit( mScalarEdgeStrokeWidthUnitSelectionWidget->unit() );
126 }
127
128 return settings;
129}
130
132{
133 if ( !mMeshLayer )
134 return;
135
136 if ( mActiveDatasetGroup < 0 )
137 return;
138
139 const QgsMeshRendererSettings rendererSettings = mMeshLayer->rendererSettings();
140 const QgsMeshRendererScalarSettings settings = rendererSettings.scalarSettings( mActiveDatasetGroup );
142
143 const double min = settings.classificationMinimum();
144 const double max = settings.classificationMaximum();
145
146 if ( std::abs( max ) < 1e-2 )
147 {
148 mScalarMinSpinBox->setDecimals( 8 );
149 mScalarMaxSpinBox->setDecimals( 8 );
150 }
151 else
152 {
153 mScalarMinSpinBox->setDecimals( 2 );
154 mScalarMaxSpinBox->setDecimals( 2 );
155 }
156
157 whileBlocking( mScalarMinSpinBox )->setValue( min );
158 whileBlocking( mScalarMaxSpinBox )->setValue( max );
159
160 whileBlocking( mMinMaxValueTypeComboBox )->setCurrentIndex( mMinMaxValueTypeComboBox->findData( QVariant::fromValue( settings.extent() ) ) );
161
163 {
164 whileBlocking( mUserDefinedRadioButton )->setChecked( false );
165 whileBlocking( mMinMaxRadioButton )->setChecked( true );
166 mScalarMinSpinBox->setEnabled( false );
167 mScalarMaxSpinBox->setEnabled( false );
168 mMinMaxValueTypeComboBox->setEnabled( true );
169 }
170 else
171 {
172 whileBlocking( mUserDefinedRadioButton )->setChecked( true );
173 whileBlocking( mMinMaxRadioButton )->setChecked( false );
174 mScalarMinSpinBox->setEnabled( true );
175 mScalarMaxSpinBox->setEnabled( true );
176 mMinMaxValueTypeComboBox->setEnabled( false );
177 }
178
179 whileBlocking( mScalarColorRampShaderWidget )->setFromShader( shader );
180 whileBlocking( mScalarColorRampShaderWidget )->setMinimumMaximum( min, max );
181 whileBlocking( mOpacityWidget )->setOpacity( settings.opacity() );
182 const int index = mScalarInterpolationTypeComboBox->findData( settings.dataResamplingMethod() );
183 whileBlocking( mScalarInterpolationTypeComboBox )->setCurrentIndex( index );
184
185 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
186 const bool hasFaces = ( mMeshLayer->contains( QgsMesh::ElementType::Face ) );
187
188 mScalarResamplingWidget->setVisible( hasFaces );
189
190 mEdgeWidthGroupBox->setVisible( hasEdges );
191
192 if ( hasEdges )
193 {
194 const QgsInterpolatedLineWidth edgeStrokeWidth = settings.edgeStrokeWidth();
195 whileBlocking( mScalarEdgeStrokeWidthVariablePushButton )->setVariableStrokeWidth( edgeStrokeWidth );
196 whileBlocking( mScalarEdgeStrokeWidthSpinBox )->setValue( edgeStrokeWidth.fixedStrokeWidth() );
197 whileBlocking( mScalarEdgeStrokeWidthVariableRadioButton )->setChecked( edgeStrokeWidth.isVariableWidth() );
198 whileBlocking( mScalarEdgeStrokeWidthUnitSelectionWidget )->setUnit( settings.edgeStrokeWidthUnit() );
199 if ( !hasFaces )
200 mOpacityContainerWidget->setVisible( false );
201
202 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
203 const double min = metadata.minimum();
204 const double max = metadata.maximum();
205 mScalarEdgeStrokeWidthVariablePushButton->setDefaultMinMaxValue( min, max );
206 }
207
208 onEdgeStrokeWidthMethodChanged();
209}
210
211double QgsMeshRendererScalarSettingsWidget::spinBoxValue( const QgsDoubleSpinBox *spinBox ) const
212{
213 if ( spinBox->value() == spinBox->clearValue() )
214 {
215 return std::numeric_limits<double>::quiet_NaN();
216 }
217
218 return spinBox->value();
219}
220
221void QgsMeshRendererScalarSettingsWidget::minMaxChanged()
222{
223 const double min = spinBoxValue( mScalarMinSpinBox );
224 const double max = spinBoxValue( mScalarMaxSpinBox );
225 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
226}
227
228void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
229{
230 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
231 const double min = metadata.minimum();
232 const double max = metadata.maximum();
233
234 if ( std::abs( max ) < 1e-2 )
235 {
236 mScalarMinSpinBox->setDecimals( 8 );
237 mScalarMaxSpinBox->setDecimals( 8 );
238 }
239 else
240 {
241 mScalarMinSpinBox->setDecimals( 2 );
242 mScalarMaxSpinBox->setDecimals( 2 );
243 }
244
245 whileBlocking( mScalarMinSpinBox )->setValue( min );
246 whileBlocking( mScalarMaxSpinBox )->setValue( max );
247 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
248}
249
250void QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged()
251{
252 const bool variableWidth = mScalarEdgeStrokeWidthVariableRadioButton->isChecked();
253 mScalarEdgeStrokeWidthVariablePushButton->setVisible( variableWidth );
254 mScalarEdgeStrokeWidthSpinBox->setVisible( !variableWidth );
255}
256
257QgsMeshRendererScalarSettings::DataResamplingMethod QgsMeshRendererScalarSettingsWidget::dataIntepolationMethod() const
258{
259 const int data = mScalarInterpolationTypeComboBox->currentData().toInt();
261 return method;
262}
263
264bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnFaces() const
265{
266 if ( !mMeshLayer )
267 return false;
268
269 if ( mActiveDatasetGroup < 0 )
270 return false;
271
272 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
273 const bool onFaces = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces );
274 return onFaces;
275}
276
277bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnEdges() const
278{
279 if ( !mMeshLayer )
280 return false;
281
282 if ( mActiveDatasetGroup < 0 )
283 return false;
284
285 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
286 const bool onEdges = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnEdges );
287 return onEdges;
288}
289
291{
292 mCanvas = canvas;
293}
294
295void QgsMeshRendererScalarSettingsWidget::recalculateMinMax()
296{
297 QgsRectangle searchExtent;
298
299 Qgis::MeshRangeExtent extentRange = mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>();
300
301 switch ( extentRange )
302 {
304 {
305 searchExtent = mMeshLayer->extent();
306 break;
307 }
310 {
312 searchExtent = mCanvas->extent();
313 try
314 {
315 searchExtent = ct.transform( searchExtent );
316 }
317 catch ( const QgsCsException &e )
318 {
319 QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( e.what() ), QObject::tr( "CRS" ) );
320 // can properly transform canvas extent to meshlayer crs, use full mesh layer extent
321 searchExtent = mMeshLayer->extent();
322 }
323 break;
324 }
325 default:
326 break;
327 }
328
329 if ( !searchExtent.isEmpty() )
330 {
331 QgsMeshDatasetIndex datasetIndex = mMeshLayer->activeScalarDatasetAtTime( mCanvas->temporalRange(), mActiveDatasetGroup );
332 double min, max;
333 bool found;
334
335 found = mMeshLayer->minimumMaximumActiveScalarDataset( searchExtent, datasetIndex, min, max );
336 if ( found )
337 {
338 whileBlocking( mScalarMinSpinBox )->setValue( min );
339 whileBlocking( mScalarMaxSpinBox )->setValue( max );
340 minMaxChanged();
341 }
342 }
343}
344
345void QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled( bool toggled )
346{
347 mMinMaxValueTypeComboBox->setEnabled( !toggled );
348 mScalarMinSpinBox->setEnabled( toggled );
349 mScalarMaxSpinBox->setEnabled( toggled );
350 mScalarRecalculateMinMaxButton->setEnabled( toggled );
351 emit widgetChanged();
352}
353
354void QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled( bool toggled )
355{
356 mMinMaxValueTypeComboBox->setEnabled( toggled );
357 mScalarMinSpinBox->setEnabled( !toggled );
358 mScalarMaxSpinBox->setEnabled( !toggled );
359 mScalarRecalculateMinMaxButton->setEnabled( !toggled );
360 emit widgetChanged();
361}
@ MinimumMaximum
Real min-max values.
@ NotSet
User defined.
MeshRangeExtent
Describes the extent used to compute mesh ranges (min/max values).
Definition qgis.h:5852
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
@ WholeMesh
Whole mesh is used to compute statistics.
@ FixedCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes)
@ MetersInMapUnits
Meters value as Map units.
void widgetChanged()
Widget changed.
A ramp shader will color a raster pixel based on a list of values ranges in a ramp.
Handles coordinate transforms between two coordinate systems.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
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.
const QgsDateTimeRange & temporalRange() const
Returns map canvas datetime range.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:84
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
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.
An index that identifies the dataset group (e.g.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsRectangle extent() const override
Returns the extent of the layer.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
bool minimumMaximumActiveScalarDataset(const QgsRectangle &extent, const QgsMeshDatasetIndex &datasetIndex, double &min, double &max)
Extracts minimum and maximum value for active scalar dataset on mesh faces.
QgsMeshDatasetIndex activeScalarDatasetAtTime(const QgsDateTimeRange &timeRange, int group=-1) const
Returns dataset index from active scalar group depending on the time range.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
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.
void setClassificationMinimumMaximum(double minimum, double maximum)
Sets min/max values used for creation of the color ramp shader.
Qgis::MeshRangeExtent extent() const
Returns the mesh extent for minimum maximum calculation.
double opacity() const
Returns opacity.
void setEdgeStrokeWidthUnit(Qgis::RenderUnit edgeStrokeWidthUnit)
Sets the stroke width unit used to render edges scalar dataset.
void setColorRampShader(const QgsColorRampShader &shader)
Sets color ramp shader function.
Qgis::MeshRangeLimit limits() const
Returns the range limits type for minimum maximum calculation.
QgsColorRampShader colorRampShader() const
Returns color ramp shader function.
void setExtent(Qgis::MeshRangeExtent extent)
Sets the mesh extent for minimum maximum calculation.
double classificationMinimum() const
Returns min value used for creation of the color ramp shader.
void setOpacity(double opacity)
Sets opacity.
DataResamplingMethod
Resampling of value from dataset.
@ NoResampling
Does not use resampling.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
Qgis::RenderUnit edgeStrokeWidthUnit() const
Returns the stroke width unit used to render edges scalar dataset.
DataResamplingMethod dataResamplingMethod() const
Returns the type of interpolation to use to convert face defined datasets to values on vertices.
void setEdgeStrokeWidth(const QgsInterpolatedLineWidth &strokeWidth)
Sets the stroke width used to render edges scalar dataset.
double classificationMaximum() const
Returns max value used for creation of the color ramp shader.
void setLimits(Qgis::MeshRangeLimit limits)
Sets the range limits type for minimum maximum calculation.
QgsInterpolatedLineWidth edgeStrokeWidth() const
Returns the stroke width used to render edges scalar dataset.
void setDataResamplingMethod(const DataResamplingMethod &dataResamplingMethod)
Sets data interpolation method.
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())
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:6206