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