QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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(
57 {
62 }
63 );
64
65 // connect
66 connect( mScalarRecalculateMinMaxButton, &QPushButton::clicked, this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked );
67 connect( mScalarMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( double ) { minMaxChanged(); } );
68 connect( mScalarMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( double ) { minMaxChanged(); } );
69 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged );
70
73 connect( mScalarInterpolationTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
74
75 connect( mScalarEdgeStrokeWidthUnitSelectionWidget, &QgsUnitSelectionWidget::changed, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
76 connect( mScalarEdgeStrokeWidthSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
77 connect( mScalarEdgeStrokeWidthVariableRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
78 connect( mScalarEdgeStrokeWidthFixedRadioButton, &QCheckBox::toggled, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
79 connect( mScalarEdgeStrokeWidthVariablePushButton, &QgsMeshVariableStrokeWidthButton::widgetChanged, this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
80
81 connect( mUserDefinedRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled );
82 connect( mMinMaxRadioButton, &QRadioButton::toggled, this, &QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled );
83
84 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::recalculateMinMax );
85 connect( mMinMaxValueTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsMeshRendererScalarSettingsWidget::widgetChanged );
86}
87
89{
90 mMeshLayer = layer;
91 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
92}
93
95{
96 mActiveDatasetGroup = groupIndex;
97 mScalarInterpolationTypeComboBox->setEnabled( !dataIsDefinedOnEdges() );
98}
99
101{
103 settings.setClassificationMinimumMaximum( spinBoxValue( mScalarMinSpinBox ), spinBoxValue( mScalarMaxSpinBox ) );
104 settings.setColorRampShader( mScalarColorRampShaderWidget->shader() );
105 settings.setOpacity( mOpacityWidget->opacity() );
106 settings.setDataResamplingMethod( dataIntepolationMethod() );
107
108 settings.setExtent( mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>() );
109
110 if ( mUserDefinedRadioButton->isChecked() )
111 {
113 }
114 else
115 {
117 }
118
119 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
120 if ( hasEdges )
121 {
122 QgsInterpolatedLineWidth edgeStrokeWidth = mScalarEdgeStrokeWidthVariablePushButton->variableStrokeWidth();
123 edgeStrokeWidth.setIsVariableWidth( mScalarEdgeStrokeWidthVariableRadioButton->isChecked() );
124 edgeStrokeWidth.setFixedStrokeWidth( mScalarEdgeStrokeWidthSpinBox->value() );
125 settings.setEdgeStrokeWidth( edgeStrokeWidth );
126 settings.setEdgeStrokeWidthUnit( mScalarEdgeStrokeWidthUnitSelectionWidget->unit() );
127 }
128
129 return settings;
130}
131
133{
134 if ( !mMeshLayer )
135 return;
136
137 if ( mActiveDatasetGroup < 0 )
138 return;
139
140 const QgsMeshRendererSettings rendererSettings = mMeshLayer->rendererSettings();
141 const QgsMeshRendererScalarSettings settings = rendererSettings.scalarSettings( mActiveDatasetGroup );
142 const QgsColorRampShader shader = settings.colorRampShader();
143
144 const double min = settings.classificationMinimum();
145 const double max = settings.classificationMaximum();
146
147 if ( std::abs( max ) < 1e-2 )
148 {
149 mScalarMinSpinBox->setDecimals( 8 );
150 mScalarMaxSpinBox->setDecimals( 8 );
151 }
152 else
153 {
154 mScalarMinSpinBox->setDecimals( 2 );
155 mScalarMaxSpinBox->setDecimals( 2 );
156 }
157
158 whileBlocking( mScalarMinSpinBox )->setValue( min );
159 whileBlocking( mScalarMaxSpinBox )->setValue( max );
160
161 whileBlocking( mMinMaxValueTypeComboBox )->setCurrentIndex( mMinMaxValueTypeComboBox->findData( QVariant::fromValue( settings.extent() ) ) );
162
164 {
165 whileBlocking( mUserDefinedRadioButton )->setChecked( false );
166 whileBlocking( mMinMaxRadioButton )->setChecked( true );
167 mScalarMinSpinBox->setEnabled( false );
168 mScalarMaxSpinBox->setEnabled( false );
169 mMinMaxValueTypeComboBox->setEnabled( true );
170 }
171 else
172 {
173 whileBlocking( mUserDefinedRadioButton )->setChecked( true );
174 whileBlocking( mMinMaxRadioButton )->setChecked( false );
175 mScalarMinSpinBox->setEnabled( true );
176 mScalarMaxSpinBox->setEnabled( true );
177 mMinMaxValueTypeComboBox->setEnabled( false );
178 }
179
180 whileBlocking( mScalarColorRampShaderWidget )->setFromShader( shader );
181 whileBlocking( mScalarColorRampShaderWidget )->setMinimumMaximum( min, max );
182 whileBlocking( mOpacityWidget )->setOpacity( settings.opacity() );
183 const int index = mScalarInterpolationTypeComboBox->findData( settings.dataResamplingMethod() );
184 whileBlocking( mScalarInterpolationTypeComboBox )->setCurrentIndex( index );
185
186 const bool hasEdges = ( mMeshLayer->contains( QgsMesh::ElementType::Edge ) );
187 const bool hasFaces = ( mMeshLayer->contains( QgsMesh::ElementType::Face ) );
188
189 mScalarResamplingWidget->setVisible( hasFaces );
190
191 mEdgeWidthGroupBox->setVisible( hasEdges );
192
193 if ( hasEdges )
194 {
195 const QgsInterpolatedLineWidth edgeStrokeWidth = settings.edgeStrokeWidth();
196 whileBlocking( mScalarEdgeStrokeWidthVariablePushButton )->setVariableStrokeWidth( edgeStrokeWidth );
197 whileBlocking( mScalarEdgeStrokeWidthSpinBox )->setValue( edgeStrokeWidth.fixedStrokeWidth() );
198 whileBlocking( mScalarEdgeStrokeWidthVariableRadioButton )->setChecked( edgeStrokeWidth.isVariableWidth() );
199 whileBlocking( mScalarEdgeStrokeWidthUnitSelectionWidget )->setUnit( settings.edgeStrokeWidthUnit() );
200 if ( !hasFaces )
201 mOpacityContainerWidget->setVisible( false );
202
203 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
204 const double min = metadata.minimum();
205 const double max = metadata.maximum();
206 mScalarEdgeStrokeWidthVariablePushButton->setDefaultMinMaxValue( min, max );
207 }
208
209 onEdgeStrokeWidthMethodChanged();
210}
211
212double QgsMeshRendererScalarSettingsWidget::spinBoxValue( const QgsDoubleSpinBox *spinBox ) const
213{
214 if ( spinBox->value() == spinBox->clearValue() )
215 {
216 return std::numeric_limits<double>::quiet_NaN();
217 }
218
219 return spinBox->value();
220}
221
222void QgsMeshRendererScalarSettingsWidget::minMaxChanged()
223{
224 const double min = spinBoxValue( mScalarMinSpinBox );
225 const double max = spinBoxValue( mScalarMaxSpinBox );
226 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
227}
228
229void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
230{
231 const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
232 const double min = metadata.minimum();
233 const double max = metadata.maximum();
234
235 if ( std::abs( max ) < 1e-2 )
236 {
237 mScalarMinSpinBox->setDecimals( 8 );
238 mScalarMaxSpinBox->setDecimals( 8 );
239 }
240 else
241 {
242 mScalarMinSpinBox->setDecimals( 2 );
243 mScalarMaxSpinBox->setDecimals( 2 );
244 }
245
246 whileBlocking( mScalarMinSpinBox )->setValue( min );
247 whileBlocking( mScalarMaxSpinBox )->setValue( max );
248 mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );
249}
250
251void QgsMeshRendererScalarSettingsWidget::onEdgeStrokeWidthMethodChanged()
252{
253 const bool variableWidth = mScalarEdgeStrokeWidthVariableRadioButton->isChecked();
254 mScalarEdgeStrokeWidthVariablePushButton->setVisible( variableWidth );
255 mScalarEdgeStrokeWidthSpinBox->setVisible( !variableWidth );
256}
257
258QgsMeshRendererScalarSettings::DataResamplingMethod QgsMeshRendererScalarSettingsWidget::dataIntepolationMethod() const
259{
260 const int data = mScalarInterpolationTypeComboBox->currentData().toInt();
262 return method;
263}
264
265bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnFaces() const
266{
267 if ( !mMeshLayer )
268 return false;
269
270 if ( mActiveDatasetGroup < 0 )
271 return false;
272
273 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
274 const bool onFaces = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces );
275 return onFaces;
276}
277
278bool QgsMeshRendererScalarSettingsWidget::dataIsDefinedOnEdges() const
279{
280 if ( !mMeshLayer )
281 return false;
282
283 if ( mActiveDatasetGroup < 0 )
284 return false;
285
286 const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( mActiveDatasetGroup );
287 const bool onEdges = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnEdges );
288 return onEdges;
289}
290
292{
293 mCanvas = canvas;
294}
295
296void QgsMeshRendererScalarSettingsWidget::recalculateMinMax()
297{
298 QgsRectangle searchExtent;
299
300 Qgis::MeshRangeExtent extentRange = mMinMaxValueTypeComboBox->currentData().value<Qgis::MeshRangeExtent>();
301
302 switch ( extentRange )
303 {
305 {
306 searchExtent = mMeshLayer->extent();
307 break;
308 }
311 {
312 QgsCoordinateTransform ct = QgsCoordinateTransform( mCanvas->mapSettings().destinationCrs(), mMeshLayer->crs(), QgsProject::instance() );
313 searchExtent = mCanvas->extent();
314 try
315 {
316 searchExtent = ct.transform( searchExtent );
317 }
318 catch ( const QgsCsException &e )
319 {
320 QgsMessageLog::logMessage( QObject::tr( "Transform error caught: %1" ).arg( e.what() ), QObject::tr( "CRS" ) );
321 // can properly transform canvas extent to meshlayer crs, use full mesh layer extent
322 searchExtent = mMeshLayer->extent();
323 }
324 break;
325 }
326 default:
327 break;
328 }
329
330 if ( !searchExtent.isEmpty() )
331 {
332 QgsMeshDatasetIndex datasetIndex = mMeshLayer->activeScalarDatasetAtTime( mCanvas->temporalRange(), mActiveDatasetGroup );
333 double min, max;
334 bool found;
335
336 found = mMeshLayer->minimumMaximumActiveScalarDataset( searchExtent, datasetIndex, min, max );
337 if ( found )
338 {
339 whileBlocking( mScalarMinSpinBox )->setValue( min );
340 whileBlocking( mScalarMaxSpinBox )->setValue( max );
341 minMaxChanged();
342 }
343 }
344}
345
346void QgsMeshRendererScalarSettingsWidget::mUserDefinedRadioButton_toggled( bool toggled )
347{
348 mMinMaxValueTypeComboBox->setEnabled( !toggled );
349 mScalarMinSpinBox->setEnabled( toggled );
350 mScalarMaxSpinBox->setEnabled( toggled );
351 mScalarRecalculateMinMaxButton->setEnabled( toggled );
352 emit widgetChanged();
353}
354
355void QgsMeshRendererScalarSettingsWidget::mMinMaxRadioButton_toggled( bool toggled )
356{
357 mMinMaxValueTypeComboBox->setEnabled( toggled );
358 mScalarMinSpinBox->setEnabled( !toggled );
359 mScalarMaxSpinBox->setEnabled( !toggled );
360 mScalarRecalculateMinMaxButton->setEnabled( !toggled );
361 emit widgetChanged();
362}
@ MinimumMaximum
Real min-max values.
Definition qgis.h:6050
@ NotSet
User defined.
Definition qgis.h:6049
MeshRangeExtent
Describes the extent used to compute mesh ranges (min/max values).
Definition qgis.h:6060
@ UpdatedCanvas
Constantly updated extent of the canvas is used to compute statistics.
Definition qgis.h:6063
@ WholeMesh
Whole mesh is used to compute statistics.
Definition qgis.h:6061
@ FixedCanvas
Current extent of the canvas (at the time of computation) is used to compute statistics.
Definition qgis.h:6062
@ Millimeters
Millimeters.
Definition qgis.h:5184
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5188
@ Pixels
Pixels.
Definition qgis.h:5186
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5191
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())
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:6511