1 /*****************************************************************************
2  *                                                                           *
3  *  Elmer, A Finite Element Software for Multiphysical Problems              *
4  *                                                                           *
5  *  Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland    *
6  *                                                                           *
7  *  This program is free software; you can redistribute it and/or            *
8  *  modify it under the terms of the GNU General Public License              *
9  *  as published by the Free Software Foundation; either version 2           *
10  *  of the License, or (at your option) any later version.                   *
11  *                                                                           *
12  *  This program is distributed in the hope that it will be useful,          *
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
15  *  GNU General Public License for more details.                             *
16  *                                                                           *
17  *  You should have received a copy of the GNU General Public License        *
18  *  along with this program (in file fem/GPL-2); if not, write to the        *
19  *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,         *
20  *  Boston, MA 02110-1301, USA.                                              *
21  *                                                                           *
22  *****************************************************************************/
23 
24 /*****************************************************************************
25  *                                                                           *
26  *  ElmerGUI surface                                                         *
27  *                                                                           *
28  *****************************************************************************
29  *                                                                           *
30  *  Authors: Mikko Lyly, Juha Ruokolainen and Peter R�back                   *
31  *  Email:   Juha.Ruokolainen@csc.fi                                         *
32  *  Web:     http://www.csc.fi/elmer                                         *
33  *  Address: CSC - IT Center for Science Ltd.                                 *
34  *           Keilaranta 14                                                   *
35  *           02101 Espoo, Finland                                            *
36  *                                                                           *
37  *  Original Date: 15 Mar 2008                                               *
38  *                                                                           *
39  *****************************************************************************/
40 
41 #include <QtGui>
42 #include <iostream>
43 #include "epmesh.h"
44 #include "vtkpost.h"
45 #include "surface.h"
46 #include "timestep.h"
47 
48 #include <vtkUnstructuredGrid.h>
49 #include <vtkPointData.h>
50 #include <vtkFloatArray.h>
51 #include <vtkGeometryFilter.h>
52 #include <vtkClipPolyData.h>
53 #include <vtkPlane.h>
54 #include <vtkPolyDataNormals.h>
55 #include <vtkDataSetMapper.h>
56 #include <vtkLookupTable.h>
57 #include <vtkProperty.h>
58 #include <vtkActor.h>
59 
60 using namespace std;
61 
Surface(QWidget * parent)62 Surface::Surface(QWidget *parent)
63   : QDialog(parent)
64 {
65   ui.setupUi(this);
66 
67   connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(cancelButtonClicked()));
68   connect(ui.applyButton, SIGNAL(clicked()), this, SLOT(applyButtonClicked()));
69   connect(ui.okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked()));
70   connect(ui.surfaceCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(surfaceSelectionChanged(int)));
71   connect(ui.keepLimits, SIGNAL(stateChanged(int)), this, SLOT(keepLimitsSlot(int)));
72 
73   setWindowIcon(QIcon(":/icons/Mesh3D.png"));
74 }
75 
~Surface()76 Surface::~Surface()
77 {
78 }
79 
cancelButtonClicked()80 void Surface::cancelButtonClicked()
81 {
82   emit(hideSurfaceSignal());
83   close();
84 }
85 
applyButtonClicked()86 void Surface::applyButtonClicked()
87 {
88   emit(drawSurfaceSignal());
89 }
90 
okButtonClicked()91 void Surface::okButtonClicked()
92 {
93   applyButtonClicked();
94   close();
95 }
96 
populateWidgets(VtkPost * vtkPost)97 void Surface::populateWidgets(VtkPost* vtkPost)
98 {
99   this->scalarField = vtkPost->GetScalarField();
100   this->scalarFields = vtkPost->GetScalarFields();
101 
102   QString name = ui.surfaceCombo->currentText();
103 
104   ui.surfaceCombo->clear();
105 
106   for(int i = 0; i < scalarFields; i++) {
107     ScalarField *sf = &scalarField[i];
108     QString name = sf->name;
109     ui.surfaceCombo->addItem(sf->name);
110   }
111 
112   this->SetFieldName(name);
113 
114   surfaceSelectionChanged(ui.surfaceCombo->currentIndex());
115 }
116 
surfaceSelectionChanged(int newIndex)117 void Surface::surfaceSelectionChanged(int newIndex)
118 {
119   ScalarField *sf = &this->scalarField[newIndex];
120   if(!ui.keepLimits->isChecked()) {
121     ui.minEdit->setText(QString::number(sf->minVal));
122     ui.maxEdit->setText(QString::number(sf->maxVal));
123   }
124 }
125 
keepLimitsSlot(int state)126 void Surface::keepLimitsSlot(int state)
127 {
128   if(state == 0)
129     surfaceSelectionChanged(ui.surfaceCombo->currentIndex());
130 }
131 
draw(VtkPost * vtkPost,TimeStep * timeStep)132 void Surface::draw(VtkPost* vtkPost, TimeStep* timeStep)
133 {
134   int surfaceIndex = ui.surfaceCombo->currentIndex();
135   QString surfaceName = ui.surfaceCombo->currentText();
136   double minVal = ui.minEdit->text().toDouble();
137   double maxVal = ui.maxEdit->text().toDouble();
138   bool useNormals = ui.useNormals->isChecked();
139   int featureAngle = ui.featureAngle->value();
140   double opacity = ui.opacitySpin->value() / 100.0;
141   bool useClip = ui.clipPlane->isChecked();
142   useClip |= vtkPost->GetClipAll();
143 
144   ScalarField* sf = &scalarField[surfaceIndex];
145   int maxDataSteps = sf->values / vtkPost->NofNodes();
146   int step = timeStep->ui.timeStep->value();
147   if(step > maxDataSteps) step = maxDataSteps;
148   if(step > timeStep->maxSteps) step = timeStep->maxSteps;
149   int offset = vtkPost->NofNodes() * (step-1);
150 
151   // Scalars:
152   //---------
153   vtkPost->GetSurfaceGrid()->GetPointData()->RemoveArray("Surface");
154   vtkFloatArray* scalars = vtkFloatArray::New();
155   scalars->SetNumberOfComponents(1);
156   scalars->SetNumberOfTuples(vtkPost->NofNodes());
157   scalars->SetName("Surface");
158   for(int i = 0; i < vtkPost->NofNodes(); i++)
159     scalars->SetComponent(i, 0, sf->value[i + offset]);
160   vtkPost->GetSurfaceGrid()->GetPointData()->AddArray(scalars);
161 
162   // Convert from vtkUnstructuredGrid to vtkPolyData:
163   //-------------------------------------------------
164   vtkGeometryFilter* filter = vtkGeometryFilter::New();
165 
166 #if VTK_MAJOR_VERSION <= 5
167   filter->SetInput(vtkPost->GetSurfaceGrid());
168 #else
169   filter->SetInputData(vtkPost->GetSurfaceGrid());
170 #endif
171 #if VTK_MAJOR_VERSION <= 5
172   filter->GetOutput()->ReleaseDataFlagOn();
173 #else
174   filter->ReleaseDataFlagOn();
175 #endif
176 
177   // Apply the clip plane:
178   //-----------------------
179   vtkClipPolyData *clipper = vtkClipPolyData::New();
180 
181   if(useClip) {
182     clipper->SetInputConnection(filter->GetOutputPort());
183     clipper->SetClipFunction(vtkPost->GetClipPlane());
184     clipper->GenerateClipScalarsOn();
185     clipper->GenerateClippedOutputOn();
186   }
187 
188   // Normals:
189   //---------
190   vtkPolyDataNormals *normals = vtkPolyDataNormals::New();
191 
192   if(useNormals) {
193     if(useClip) {
194       normals->SetInputConnection(clipper->GetOutputPort());
195     } else {
196       normals->SetInputConnection(filter->GetOutputPort());
197     }
198     normals->SetFeatureAngle(featureAngle);
199   }
200 
201   // Mapper:
202   //--------
203   vtkDataSetMapper *mapper = vtkDataSetMapper::New();
204 
205   if(useNormals) {
206     mapper->SetInputConnection(normals->GetOutputPort());
207   } else {
208     if(useClip) {
209       mapper->SetInputConnection(clipper->GetOutputPort());
210     } else {
211 #if VTK_MAJOR_VERSION <= 5
212       mapper->SetInput(vtkPost->GetSurfaceGrid());
213 #else
214       mapper->SetInputData(vtkPost->GetSurfaceGrid());
215 #endif
216     }
217   }
218 
219   mapper->SetScalarModeToUsePointFieldData();
220   mapper->SelectColorArray("Surface");
221   mapper->ScalarVisibilityOn();
222   mapper->SetScalarRange(minVal, maxVal);
223   mapper->SetResolveCoincidentTopologyToPolygonOffset();
224   //mapper->SetLookupTable(vtkPost->GetCurrentLut());
225   mapper->SetLookupTable(vtkPost->GetLut("Surface"));
226   // mapper->ImmediateModeRenderingOn();
227 
228   // Actor:
229   //--------
230   vtkPost->GetSurfaceActor()->SetMapper(mapper);
231   vtkPost->GetSurfaceActor()->GetProperty()->SetOpacity(opacity);
232   vtkPost->SetCurrentSurfaceName(sf->name);
233 
234   // Clean up:
235   //-----------
236   mapper->Delete();
237   normals->Delete();
238   clipper->Delete();
239   filter->Delete();
240   scalars->Delete();
241 }
242 
243 // Public slots:
244 //---------------
GetFieldName()245 QString Surface::GetFieldName()
246 {
247   return ui.surfaceCombo->currentText();
248 }
249 
SetFieldName(QString name)250 bool Surface::SetFieldName(QString name)
251 {
252   for(int i = 0; i < ui.surfaceCombo->count(); i++) {
253     if(ui.surfaceCombo->itemText(i) == name) {
254       ui.surfaceCombo->setCurrentIndex(i);
255       return true;
256     }
257   }
258   return false;
259 }
260 
SetMinVal(double f)261 void Surface::SetMinVal(double f)
262 {
263   ui.minEdit->setText(QString::number(f));
264 }
265 
SetMaxVal(double f)266 void Surface::SetMaxVal(double f)
267 {
268   ui.maxEdit->setText(QString::number(f));
269 }
270 
KeepLimits(bool b)271 void Surface::KeepLimits(bool b)
272 {
273   ui.keepLimits->setChecked(b);
274 }
275 
SetComputeNormals(bool b)276 void Surface::SetComputeNormals(bool b)
277 {
278   ui.useNormals->setChecked(b);
279 }
280 
SetFeatureAngle(int n)281 void Surface::SetFeatureAngle(int n)
282 {
283   ui.featureAngle->setValue(n);
284 }
285 
SetOpacity(int n)286 void Surface::SetOpacity(int n)
287 {
288   ui.opacitySpin->setValue(n);
289 }
290 
SetClipPlane(bool b)291 void Surface::SetClipPlane(bool b)
292 {
293   ui.clipPlane->setChecked(b);
294 }
295