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