1 /***************************************************************************
2 qgsmeshrenderer3daveragingwidget.cpp
3 ------------------------------------
4 begin : November 2019
5 copyright : (C) 2019 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
16 #include <memory>
17 #include <QSvgRenderer>
18 #include <QPainter>
19 #include <QScreen>
20 #include <QPixmap>
21 #include <QDesktopWidget>
22
23 #include "qgsmeshrenderer3daveragingwidget.h"
24
25 #include "qgis.h"
26 #include "qgsmeshlayer.h"
27 #include "qgsmessagelog.h"
28 #include "qgsmeshrenderersettings.h"
29 #include "qgsmesh3daveraging.h"
30 #include "qgsapplication.h"
31
_setSvg(QLabel * imageLabel,const QString & imgName)32 static void _setSvg( QLabel *imageLabel,
33 const QString &imgName )
34 {
35 const qreal dpi = QgsApplication::instance()->desktop()->logicalDpiX();
36 const int desiredWidth = static_cast<int>( 100 * dpi / 25.4 );
37
38 QSvgRenderer renderer( QStringLiteral( ":/images/themes/default/mesh/%1" ).arg( imgName ) );
39 if ( renderer.isValid() )
40 {
41 const QSize defaultSvgSize = renderer.defaultSize();
42 const int desiredHeight = defaultSvgSize.height() * desiredWidth / defaultSvgSize.width();
43
44 QPixmap pixmap( QSize( desiredWidth, desiredHeight ) );
45 pixmap.fill( Qt::transparent );
46 QPainter painter;
47
48 painter.begin( &pixmap );
49 renderer.render( &painter );
50 painter.end();
51 imageLabel->setPixmap( pixmap );
52 }
53 }
54
QgsMeshRenderer3dAveragingWidget(QWidget * parent)55 QgsMeshRenderer3dAveragingWidget::QgsMeshRenderer3dAveragingWidget( QWidget *parent )
56 : QWidget( parent )
57
58 {
59 setupUi( this );
60 connect( mAveragingMethodComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
61 this, &QgsMeshRenderer3dAveragingWidget::onAveragingMethodChanged );
62
63 // Single Level Average Method (top)
64 connect( mSingleVerticalLayerIndexTopSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
65 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
66 _setSvg( mSingleTopPngLabel,
67 QStringLiteral( "SingleTop.svg" )
68 );
69 mSingleTopGroup->adjustSize();
70
71 // Single Level Average Method (bottom)
72 connect( mSingleVerticalLayerIndexBottomSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
73 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
74 _setSvg( mSingleBottomPngLabel,
75 QStringLiteral( "SingleBottom.svg" )
76 );
77
78 // Multi Levels Averaging Method (top)
79 connect( mMultiTopVerticalLayerStartIndexSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
80 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
81 connect( mMultiTopVerticalLayerEndIndexSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
82 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
83 _setSvg( mMultiTopPngLabel,
84 QStringLiteral( "MultiTop.svg" )
85 );
86
87 // MultiLevels Averaging Method (bottom)
88 connect( mMultiBottomVerticalLayerStartIndexSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
89 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
90 connect( mMultiBottomVerticalLayerEndIndexSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ),
91 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
92 _setSvg( mMultiBottomPngLabel,
93 QStringLiteral( "MultiBottom.svg" )
94 );
95
96 // Sigma Averaging Method
97 connect( mSigmaStartFractionSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
98 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
99 connect( mSigmaEndFractionSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
100 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
101 _setSvg( mSigmaPngLabel,
102 QStringLiteral( "Sigma.svg" )
103 );
104
105 // Depth Averaging Method
106 connect( mDepthStartSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
107 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
108 connect( mDepthEndSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
109 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
110 _setSvg( mDepthPngLabel,
111 QStringLiteral( "Depth.svg" )
112 );
113
114 // Height Averaging Method
115 connect( mHeightStartSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
116 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
117 connect( mHeightEndSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
118 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
119 _setSvg( mHeightPngLabel,
120 QStringLiteral( "Height.svg" )
121 );
122
123 // Elevation Averaging Method
124 connect( mElevationStartSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
125 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
126 connect( mElevationEndSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ),
127 this, &QgsMeshRenderer3dAveragingWidget::widgetChanged );
128 _setSvg( mElevationPngLabel,
129 QStringLiteral( "Elevation.svg" )
130 );
131 }
132
setLayer(QgsMeshLayer * layer)133 void QgsMeshRenderer3dAveragingWidget::setLayer( QgsMeshLayer *layer )
134 {
135 mMeshLayer = layer;
136 }
137
averagingMethod() const138 std::unique_ptr<QgsMesh3dAveragingMethod> QgsMeshRenderer3dAveragingWidget::averagingMethod() const
139 {
140 std::unique_ptr<QgsMesh3dAveragingMethod> averaging;
141
142 switch ( mAveragingMethodComboBox->currentIndex() )
143 {
144 case 0: // single level from top
145 {
146 const int verticalLevel = mSingleVerticalLayerIndexTopSpinBox->value();
147 averaging.reset( new QgsMeshMultiLevelsAveragingMethod( verticalLevel, true ) );
148 break;
149 }
150 case 1: // single level from bottom
151 {
152 const int verticalLevel = mSingleVerticalLayerIndexBottomSpinBox->value();
153 averaging.reset( new QgsMeshMultiLevelsAveragingMethod( verticalLevel, false ) );
154 break;
155 }
156 case 2: // multi level from top
157 {
158 const int startVerticalLevel = mMultiTopVerticalLayerStartIndexSpinBox->value();
159 const int endVerticalLevel = mMultiTopVerticalLayerEndIndexSpinBox->value();
160 averaging.reset( new QgsMeshMultiLevelsAveragingMethod( startVerticalLevel, endVerticalLevel, true ) );
161 break;
162 }
163 case 3: // multi level from bottom
164 {
165 const int startVerticalLevel = mMultiBottomVerticalLayerStartIndexSpinBox->value();
166 const int endVerticalLevel = mMultiBottomVerticalLayerEndIndexSpinBox->value();
167 averaging.reset( new QgsMeshMultiLevelsAveragingMethod( startVerticalLevel, endVerticalLevel, false ) );
168 break;
169 }
170 case 4: // sigma
171 {
172 const double startFraction = mSigmaStartFractionSpinBox->value();
173 const double endFraction = mSigmaEndFractionSpinBox->value();
174 averaging.reset( new QgsMeshSigmaAveragingMethod( startFraction, endFraction ) );
175 break;
176 }
177 case 5: // depth (from surface)
178 {
179 const double startDepth = mDepthStartSpinBox->value();
180 const double endDepth = mDepthEndSpinBox->value();
181 averaging.reset( new QgsMeshRelativeHeightAveragingMethod( startDepth, endDepth, true ) );
182 break;
183 }
184 case 6: // height (from bed elevation)
185 {
186 const double startHeight = mHeightStartSpinBox->value();
187 const double endHeight = mHeightEndSpinBox->value();
188 averaging.reset( new QgsMeshRelativeHeightAveragingMethod( startHeight, endHeight, false ) );
189 break;
190 }
191 case 7: // elevation
192 {
193 const double startVerticalLevel = mElevationStartSpinBox->value();
194 const double endVerticalLevel = mElevationEndSpinBox->value();
195 averaging.reset( new QgsMeshElevationAveragingMethod( startVerticalLevel, endVerticalLevel ) );
196 break;
197 }
198 }
199 return averaging;
200 }
201
syncToLayer()202 void QgsMeshRenderer3dAveragingWidget::syncToLayer( )
203 {
204 if ( !mMeshLayer )
205 return;
206
207 const QgsMeshRendererSettings rendererSettings = mMeshLayer->rendererSettings();
208 const QgsMesh3dAveragingMethod *method = rendererSettings.averagingMethod();
209 if ( method )
210 {
211 const QgsMesh3dAveragingMethod::Method type = method->method();
212 int pageIndex = 0;
213
214 switch ( type )
215 {
216 case QgsMesh3dAveragingMethod::MultiLevelsAveragingMethod:
217 {
218 const QgsMeshMultiLevelsAveragingMethod *averagingMethod = static_cast<const QgsMeshMultiLevelsAveragingMethod *>( method );
219 if ( averagingMethod->isSingleLevel() )
220 {
221 if ( averagingMethod->countedFromTop() )
222 {
223 // Single Vertical Layer settings from top
224 whileBlocking( mSingleVerticalLayerIndexTopSpinBox )->setValue( averagingMethod->startVerticalLevel() );
225 pageIndex = 0;
226 }
227 else
228 {
229 // Single Vertical Layer settings from bottom
230 whileBlocking( mSingleVerticalLayerIndexBottomSpinBox )->setValue( averagingMethod->startVerticalLevel() );
231 pageIndex = 1;
232 }
233 }
234 else
235 {
236 if ( averagingMethod->countedFromTop() )
237 {
238 // Multi Vertical Layer settings from top
239 whileBlocking( mMultiTopVerticalLayerStartIndexSpinBox )->setValue( averagingMethod->startVerticalLevel() );
240 whileBlocking( mMultiTopVerticalLayerEndIndexSpinBox )->setValue( averagingMethod->endVerticalLevel() );
241 pageIndex = 2;
242 }
243 else
244 {
245 // Multi Vertical Layer settings from bottom
246 whileBlocking( mMultiBottomVerticalLayerStartIndexSpinBox )->setValue( averagingMethod->startVerticalLevel() );
247 whileBlocking( mMultiBottomVerticalLayerEndIndexSpinBox )->setValue( averagingMethod->endVerticalLevel() );
248 pageIndex = 3;
249 }
250 }
251 break;
252 }
253 case QgsMesh3dAveragingMethod::SigmaAveragingMethod:
254 {
255 const QgsMeshSigmaAveragingMethod *sigmaAveragingMethod = static_cast<const QgsMeshSigmaAveragingMethod *>( method );
256 whileBlocking( mSigmaStartFractionSpinBox )->setValue( sigmaAveragingMethod->startFraction() );
257 whileBlocking( mSigmaEndFractionSpinBox )->setValue( sigmaAveragingMethod->endFraction() );
258 pageIndex = 4;
259 break;
260 }
261 case QgsMesh3dAveragingMethod::RelativeHeightAveragingMethod:
262 {
263 const QgsMeshRelativeHeightAveragingMethod *averagingMethod = static_cast<const QgsMeshRelativeHeightAveragingMethod *>( method );
264 if ( averagingMethod->countedFromTop() )
265 {
266 whileBlocking( mDepthStartSpinBox )->setValue( averagingMethod->startHeight() );
267 whileBlocking( mDepthEndSpinBox )->setValue( averagingMethod->endHeight() );
268 pageIndex = 5;
269 }
270 else
271 {
272 whileBlocking( mHeightStartSpinBox )->setValue( averagingMethod->startHeight() );
273 whileBlocking( mHeightEndSpinBox )->setValue( averagingMethod->endHeight() );
274 pageIndex = 6;
275 }
276 break;
277 }
278 case QgsMesh3dAveragingMethod::ElevationAveragingMethod:
279 {
280 const QgsMeshElevationAveragingMethod *elevationAveragingMethod = static_cast<const QgsMeshElevationAveragingMethod *>( method );
281 whileBlocking( mElevationStartSpinBox )->setValue( elevationAveragingMethod->startElevation() );
282 whileBlocking( mElevationEndSpinBox )->setValue( elevationAveragingMethod->endElevation() );
283 pageIndex = 7;
284 break;
285 }
286 }
287 whileBlocking( mAveragingMethodComboBox )->setCurrentIndex( pageIndex );
288 whileBlocking( mAveragingMethodStackedWidget )->setCurrentIndex( pageIndex );
289 }
290 }
291
onAveragingMethodChanged(int methodIndex)292 void QgsMeshRenderer3dAveragingWidget::onAveragingMethodChanged( int methodIndex )
293 {
294 whileBlocking( mAveragingMethodStackedWidget )->setCurrentIndex( methodIndex );
295 emit widgetChanged();
296 }
297