QGIS API Documentation 3.43.0-Master (c67cf405802)
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 whileBlocking( mScalarMinSpinBox )->setValue( min );
147 whileBlocking( mScalarMaxSpinBox )->setValue( max );
148
149 whileBlocking( mMinMaxValueTypeComboBox )->setCurrentIndex( mMinMaxValueTypeComboBox->findData( QVariant::fromValue( settings.extent() ) ) );
150
152 {
153 whileBlocking( mUserDefinedRadioButton )->setChecked( false );
154 whileBlocking( mMinMaxRadioButton )->setChecked( true );
155 mScalarMinSpinBox->setEnabled( false );
156 mScalarMaxSpinBox->setEnabled( false );
157 mMinMaxValueTypeComboBox->setEnabled( true );
158 }
159 else
160 {
161 whileBlocking( mUserDefinedRadioButton )->setChecked( true );
162 whileBlocking( mMinMaxRadioButton )->setChecked( false );
163 mScalarMinSpinBox->setEnabled( true );
164 mScalarMaxSpinBox->setEnabled( true );
165 mMinMaxValueTypeComboBox->setEnabled( false );
166 }
167
168 whileBlocking( mScalarColorRampShaderWidget )->setFromShader( shader );
169 whileBlocking( mScalarColorRampShaderWidget )->setMinimumMaximum( min, max );
170 whileBlocking( mOpacityWidget )->setOpacity( settings.opacity() );
171 const int index = mScalarInterpolationTypeComboBox->findData( settings.dataResamplingMethod() );
172 whileBlocking( mScalarInterpolationTypeComboBox )->setCurrentIndex( index );
173
174 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
175 const bool hasFaces = ( mMeshLayer->contains( QgsMesh::ElementType::Face ) );
176
177 mScalarResamplingWidget->setVisible( hasFaces );
178
179 mEdgeWidthGroupBox->setVisible( hasEdges );
180
181 if ( hasEdges )
182 {
183 const QgsInterpolatedLineWidth edgeStrokeWidth = settings.edgeStrokeWidth();
184 whileBlocking( mScalarEdgeStrokeWidthVariablePushButton )->setVariableStrokeWidth( edgeStrokeWidth );
185 whileBlocking( mScalarEdgeStrokeWidthSpinBox )->setValue( edgeStrokeWidth.fixedStrokeWidth() );
186 whileBlocking( mScalarEdgeStrokeWidthVariableRadioButton )->setChecked( edgeStrokeWidth.isVariableWidth() );
187 whileBlocking( mScalarEdgeStrokeWidthUnitSelectionWidget )->setUnit( settings.edgeStrokeWidthUnit() );
188 if ( !hasFaces )
189 mOpacityContainerWidget->setVisible( false );
190
191 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
192 const double min = metadata.minimum();
193 const double max = metadata.maximum();
194 mScalarEdgeStrokeWidthVariablePushButton->setDefaultMinMaxValue( min, max );
195 }
196
197 onEdgeStrokeWidthMethodChanged();
198}
199
200double QgsMeshRendererScalarSettingsWidget::spinBoxValue( const QgsDoubleSpinBox *spinBox ) const
201{
202 if ( spinBox->value() == spinBox->clearValue() )
203 {
204 return std::numeric_limits<double>::quiet_NaN();
205 }
206
207 return spinBox->value();
208}
209
210void QgsMeshRendererScalarSettingsWidget::minMaxChanged()
211{
212 const double min = spinBoxValue( mScalarMinSpinBox );
213 const double max = spinBoxValue( mScalarMaxSpinBox );
214 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
215}
216
217void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
218{
219 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
220 const double min = metadata.minimum();
221 const double max = metadata.maximum();
222 whileBlocking( mScalarMinSpinBox )->setValue( min );
223 whileBlocking( mScalarMaxSpinBox )->setValue( max );
224 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
225}
226
227void QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged()
228{
229 const bool variableWidth = mScalarEdgeStrokeWidthVariableRadioButton->isChecked();
230 mScalarEdgeStrokeWidthVariablePushButton->setVisible( variableWidth );
231 mScalarEdgeStrokeWidthSpinBox->setVisible( !variableWidth );
232}
233
234QgsMeshRendererScalarSettings::DataResamplingMethod QgsMeshRendererScalarSettingsWidget::dataIntepolationMethod() const
235{
236 const int data = mScalarInterpolationTypeComboBox->currentData().toInt();
238 return method;
239}
240
241bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnFaces() const
242{
243 if ( !mMeshLayer )
244 return false;
245
246 if ( mActiveDatasetGroup < 0 )
247 return false;
248
249 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
250 const bool onFaces = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces );
251 return onFaces;
252}
253
254bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnEdges() const
255{
256 if ( !mMeshLayer )
257 return false;
258
259 if ( mActiveDatasetGroup < 0 )
260 return false;
261
262 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
263 const bool onEdges = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnEdges );
264 return onEdges;
265}
266
268{
269 mCanvas = canvas;
270}
271
272void QgsMeshRendererScalarSettingsWidget::recalculateMinMax()
273{
274 QgsRectangle searchExtent;
275
276 Qgis::MeshRangeExtent extentRange = mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>();
277
278 switch ( extentRange )
279 {
281 {
282 searchExtent = mMeshLayer->extent();
283 break;
284 }
287 {
289 searchExtent = mCanvas->extent();
290 try
291 {
292 searchExtent = ct.transform( searchExtent );
293 }
294 catch ( const QgsCsException &e )
295 {
296 QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( e.what() ), QObject::tr( "CRS" ) );
297 // can properly transform canvas extent to meshlayer crs, use full mesh layer extent
298 searchExtent = mMeshLayer->extent();
299 }
300 break;
301 }
302 default:
303 break;
304 }
305
306 if ( !searchExtent.isEmpty() )
307 {
308 QgsMeshDatasetIndex datasetIndex = mMeshLayer->activeScalarDatasetAtTime( mCanvas->temporalRange(), mActiveDatasetGroup );
309 double min, max;
310 bool found;
311
312 found = mMeshLayer->minimumMaximumActiveScalarDataset( searchExtent, datasetIndex, min, max );
313 if ( found )
314 {
315 whileBlocking( mScalarMinSpinBox )->setValue( min );
316 whileBlocking( mScalarMaxSpinBox )->setValue( max );
317 minMaxChanged();
318 }
319 }
320}
321
322void QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled( bool toggled )
323{
324 mMinMaxValueTypeComboBox->setEnabled( !toggled );
325 mScalarMinSpinBox->setEnabled( toggled );
326 mScalarMaxSpinBox->setEnabled( toggled );
327 mScalarRecalculateMinMaxButton->setEnabled( toggled );
328 emit widgetChanged();
329}
330
331void QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled( bool toggled )
332{
333 mMinMaxValueTypeComboBox->setEnabled( toggled );
334 mScalarMinSpinBox->setEnabled( !toggled );
335 mScalarMaxSpinBox->setEnabled( !toggled );
336 mScalarRecalculateMinMaxButton->setEnabled( !toggled );
337 emit widgetChanged();
338}
@ MinimumMaximum
Real min-max values.
@ NotSet
User defined.
MeshRangeExtent
Describes the extent used to compute mesh ranges (min/max values).
Definition qgis.h:5836
@ 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:6190