2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 // + This file is part of enGrid. +
6 // + Copyright 2008-2010 enGits GmbH +
8 // + enGrid is free software: you can redistribute it and/or modify +
9 // + it under the terms of the GNU General Public License as published by +
10 // + the Free Software Foundation, either version 3 of the License, or +
11 // + (at your option) any later version. +
13 // + enGrid is distributed in the hope that it will be useful, +
14 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
15 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
16 // + GNU General Public License for more details. +
18 // + You should have received a copy of the GNU General Public License +
19 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 #include "laplacesmoother.h"
24 #include <vtkCellLocator.h>
25 #include <vtkCharArray.h>
26 #include <vtkGenericCell.h>
27 #include "guimainwindow.h"
29 using namespace GeometryTools
;
31 LaplaceSmoother::LaplaceSmoother() : SurfaceOperation()
35 m_UseProjection
= true;
36 // m_UseNormalCorrection = false;
37 getSet("surface meshing", "under relaxation for smoothing", 0.5, m_UnderRelaxation
);
38 getSet("surface meshing", "correct curvature (experimental)", false, m_correctCurvature
);
40 m_ProjectionIterations
= 20;
43 bool LaplaceSmoother::setNewPosition(vtkIdType id_node
, vec3_t x_new
)
45 using namespace GeometryTools
;
48 m_Grid
->GetPoint(id_node
, x_old
.data());
49 m_Grid
->GetPoints()->SetPoint(id_node
, x_new
.data());
52 if(m_NoCheck
) return move
;
55 QVector
<vec3_t
> cell_normals(m_Part
.n2cGSize(id_node
));
56 double A_max
= 0;//area of the biggest neighbour cell of id_node
57 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
58 double A
= fabs(GeometryTools::cellVA(m_Grid
, m_Part
.n2cGG(id_node
, i
)));
59 A_max
= max(A
, A_max
);
60 cell_normals
[i
] = GeometryTools::cellNormal(m_Grid
, m_Part
.n2cGG(id_node
, i
));
61 cell_normals
[i
].normalise();
64 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
65 double A
= fabs(GeometryTools::cellVA(m_Grid
, m_Part
.n2cGG(id_node
, i
)));
76 double L_max
= 0;// distance to the furthest neighbour node of id_node
77 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
79 m_Grid
->GetPoint(m_Part
.n2nGG(id_node
, i
), xn
.data());
80 double L
= (xn
- x_old
).abs();
81 L_max
= max(L
, L_max
);
85 if(m_correctCurvature
) {
86 // better for mesher with interpolation
87 x_summit
= x_new
+ L_max
*n
;
90 // better for mesher without interpolation
91 x_summit
= x_old
+ L_max
*n
;
94 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
96 vtkIdType N_pts
, *pts
;
97 m_Grid
->GetCellPoints(m_Part
.n2cGG(id_node
, i
), N_pts
, pts
);
101 for (int j
= 0; j
< N_pts
; ++j
) {
102 m_Grid
->GetPoint(pts
[j
], x
[j
].data());
104 if (GeometryTools::tetraVol(x
[0], x
[1], x
[2], x_summit
, false) <= 0) {
105 // saveGrid(m_Grid, "after_move1");
106 // qWarning()<<"Cannot move point "<<id_node<<" because negative tetraVol.";
108 // m_Grid->GetPoints()->SetPoint(id_node, x_old.data());
109 // saveGrid(m_Grid, "before_move1");
116 for (int i
= 0; i
< cell_normals
.size(); ++i
) {
117 for (int j
= 0; j
< cell_normals
.size(); ++j
) {
118 if (cell_normals
[i
]*cell_normals
[j
] < -1000*0.1) {//Why -1000*0.1?
119 saveGrid(m_Grid
, "after_move2");
120 qWarning()<<"Cannot move point "<<id_node
<<" because opposite cell_normals.";
122 m_Grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
123 saveGrid(m_Grid
, "before_move2");
132 // comment this out if you want points to always move
133 m_Grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
134 // saveGrid(m_Grid, "before_move");
139 bool LaplaceSmoother::moveNode(vtkIdType id_node
, vec3_t
&Dx
)
142 m_Grid
->GetPoint(id_node
, x_old
.data());
144 for (int i_relaxation
= 0; i_relaxation
< 1; ++i_relaxation
) {
145 vec3_t x_new
= x_old
+ Dx
;
146 if (m_UseProjection
) {
147 int i_nodes
= m_Part
.localNode(id_node
);
148 if (m_NodeToBc
[i_nodes
].size() == 1) {
149 int bc
= m_NodeToBc
[i_nodes
][0];
150 x_new
= GuiMainWindow::pointer()->getSurfProj(bc
)->project(x_new
, id_node
);
152 for (int i_proj_iter
= 0; i_proj_iter
< m_ProjectionIterations
; ++i_proj_iter
) {
153 foreach (int bc
, m_NodeToBc
[i_nodes
]) {
154 x_new
= GuiMainWindow::pointer()->getSurfProj(bc
)->project(x_new
, id_node
);
159 if (setNewPosition(id_node
, x_new
)) {
170 void LaplaceSmoother::operate()
172 // qDebug()<<"LaplaceSmoother::operate() called";
175 GuiMainWindow::pointer()->getAllBoundaryCodes(bcs
);
176 if (m_UseProjection
) {
177 foreach (int bc
, bcs
) {
178 GuiMainWindow::pointer()->getSurfProj(bc
)->setForegroundGrid(m_Grid
);
179 GuiMainWindow::pointer()->getSurfProj(bc
)->setCorrectCurvature(m_correctCurvature
);
182 UpdatePotentialSnapPoints(false, false);
183 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
184 EG_VTKDCN(vtkCharArray
, node_type
, m_Grid
, "node_type" );
185 QVector
<vtkIdType
> smooth_node(m_Grid
->GetNumberOfPoints(), false);
187 l2g_t nodes
= m_Part
.getNodes();
188 foreach (vtkIdType id_node
, nodes
) {
189 smooth_node
[id_node
] = true;
192 setAllSurfaceCells();
193 l2g_t nodes
= m_Part
.getNodes();
194 g2l_t _nodes
= m_Part
.getLocalNodes();
195 m_NodeToBc
.resize(nodes
.size());
196 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
198 for (int j
= 0; j
< m_Part
.n2cLSize(i_nodes
); ++j
) {
199 bcs
.insert(cell_code
->GetValue(m_Part
.n2cLG(i_nodes
, j
)));
201 m_NodeToBc
[i_nodes
].resize(bcs
.size());
202 qCopy(bcs
.begin(), bcs
.end(), m_NodeToBc
[i_nodes
].begin());
205 QVector
<vec3_t
> x_new(nodes
.size());
207 for (int i_iter
= 0; i_iter
< m_NumberOfIterations
; ++i_iter
) {
211 // QVector<vec3_t> node_normals;
212 // if (m_UseNormalCorrection) {
213 // node_normals.fill(vec3_t(0,0,0), m_Grid->GetNumberOfPoints());
215 // for (vtkIdType id_node = 0; id_node < m_Grid->GetNumberOfPoints(); ++id_node) {
216 // for (int i = 0; i < m_Part.n2cGSize(id_node); ++i) {
217 // node_normals[id_node] += GeometryTools::cellNormal(m_Grid, m_Part.n2cGG(id_node, i));
219 // node_normals[id_node].normalise();
223 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
224 vtkIdType id_node
= nodes
[i_nodes
];
225 if (smooth_node
[id_node
] && node_type
->GetValue(id_node
) != VTK_FIXED_VERTEX
) {
226 if (node_type
->GetValue(id_node
) != VTK_FIXED_VERTEX
) {
227 QVector
<vtkIdType
> snap_points
= getPotentialSnapPoints(id_node
);
229 if (snap_points
.size() > 0) {
232 x_new
[i_nodes
] = vec3_t(0,0,0);
233 m_Grid
->GetPoint(id_node
, x_old
.data());
234 foreach (vtkIdType id_snap_node
, snap_points
) {
235 m_Grid
->GetPoint(id_snap_node
, x
.data());
237 // n += node_normals[id_snap_node];
240 x_new
[i_nodes
] *= 1.0/snap_points
.size();
242 // if (m_UseNormalCorrection) {
243 // vec3_t dx = x_new[i_nodes] - x_old;
245 // x_new[i_nodes] -= dx;
248 vec3_t Dx
= x_new
[i_nodes
] - x_old
;
249 Dx
*= m_UnderRelaxation
;
250 if (moveNode(id_node
, Dx
)) {
251 x_new
[i_nodes
] = x_old
+ Dx
;
253 x_new
[i_nodes
] = x_old
;