1 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 // + This file is part of enGrid. +
5 // + Copyright 2008-2014 enGits GmbH +
7 // + enGrid is free software: you can redistribute it and/or modify +
8 // + it under the terms of the GNU General Public License as published by +
9 // + the Free Software Foundation, either version 3 of the License, or +
10 // + (at your option) any later version. +
12 // + enGrid 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. +
17 // + You should have received a copy of the GNU General Public License +
18 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
20 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 #include "gridsmoother.h"
22 #include "guimainwindow.h"
24 #include "optimisenormalvector.h"
25 #include "pointfinder.h"
29 GridSmoother::GridSmoother()
33 m_NumBoundaryCorrections
= 50;
34 m_DesiredStretching
= 1.2;
37 getSet("boundary layer", "number of smoothing sub-iterations", 5, m_NumIterations
);
38 getSet("boundary layer", "use strict prism checking", false, m_StrictPrismChecking
);
39 getSet("boundary layer", "number of normal vector relax iterations", 10, m_NumNormalRelaxations
);
40 getSet("boundary layer", "number of layer height relax iterations", 3, m_NumHeightRelaxations
);
41 getSet("boundary layer", "radar angle", 45, m_RadarAngle
);
42 getSet("boundary layer", "maximal layer height in gaps", 0.2, m_MaxHeightInGaps
);
43 getSet("boundary layer", "relative face size (lower limit)", 0.5, m_FaceSizeLowerLimit
);
44 getSet("boundary layer", "relative face size (upper limit)", 2.0, m_FaceSizeUpperLimit
);
45 getSet("boundary layer", "angle between top and bottom face", 45.0, m_FaceAngleLimit
);
47 m_FaceAngleLimit
= deg2rad(m_FaceAngleLimit
);
49 //m_CritAngle = GeometryTools::deg2rad(m_CritAngle);
52 void GridSmoother::markNodes()
54 m_NodeMarked
.fill(false,m_Grid
->GetNumberOfPoints());
55 QVector
<bool> new_mark(m_Grid
->GetNumberOfPoints());
56 for (int i_iterations
= 0; i_iterations
< 1; ++i_iterations
) {
57 qCopy(m_NodeMarked
.begin(),m_NodeMarked
.end(),new_mark
.begin());
58 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
59 bool mark_cell
= false;
60 vtkIdType type_cell
, N_pts
, *pts
;
61 type_cell
= m_Grid
->GetCellType(id_cell
);
62 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
63 if (type_cell
== VTK_WEDGE
) {
66 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
67 if (m_NodeMarked
[pts
[i_pts
]]) {
73 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
74 new_mark
[pts
[i_pts
]] = true;
78 qCopy(new_mark
.begin(),new_mark
.end(),m_NodeMarked
.begin());
80 QSet
<int> free_bcs
= m_BoundaryCodes
+ m_LayerAdjacentBoundaryCodes
;
81 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
82 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
83 if (isSurface(id_cell
, m_Grid
)) {
84 if (!free_bcs
.contains(cell_code
->GetValue(id_cell
))) {
85 vtkIdType N_pts
, *pts
;
86 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
87 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
88 m_NodeMarked
[pts
[i_pts
]] = false;
94 QVector
<vtkIdType
> nodes
= m_Part
.getNodes();
95 foreach (vtkIdType id_node
, nodes
) {
96 if (id_node
< 0) EG_BUG
;
97 if (id_node
> m_Grid
->GetNumberOfPoints()) EG_BUG
;
98 if (m_NodeMarked
[id_node
]) {
104 bool GridSmoother::setNewPosition(vtkIdType id_node
, vec3_t x_new
)
106 using namespace GeometryTools
;
109 m_Grid
->GetPoint(id_node
, x_old
.data());
110 m_Grid
->GetPoints()->SetPoint(id_node
, x_new
.data());
116 l2g_t cells
= m_Part
.getCells();
117 l2l_t n2c
= m_Part
.getN2C();
119 foreach (int i_cells
, n2c
[id_node
]) {
120 vtkIdType id_cell
= cells
[i_cells
];
121 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
123 if (type_cell
== VTK_TRIANGLE
) {
124 vtkIdType N_pts
, *pts
;
126 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
127 for (int i
= 0; i
< 3; ++i
) {
128 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
131 for (int i
= 0; i
< 3; ++i
) {
132 for (int j
= 0; j
< 3; ++j
) {
134 L_max
= max(L_max
, (x
[i
]-x
[j
]).abs());
138 double A
= GeometryTools::cellVA(m_Grid
, id_cell
);
139 if (A
< 1e-3*L_max
*L_max
) {
141 } else if (m_NodeNormal
[id_node
].abs() > 0.1) {
142 vec3_t n
= GeometryTools::triNormal(x
[0], x
[1], x
[2]);
144 if (n
*m_NodeNormal
[id_node
] < 0.1) {
150 if (type_cell
== VTK_TETRA
) {
151 vtkIdType N_pts
, *pts
;
153 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
154 for (int i
= 0; i
< 4; ++i
) {
155 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
158 for (int i
= 0; i
< 4; ++i
) {
159 for (int j
= 0; j
< 4; ++j
) {
161 L_max
= max(L_max
, (x
[i
]-x
[j
]).abs());
165 if (GeometryTools::cellVA(m_Grid
, id_cell
) < 1e-3*L_max
*L_max
*L_max
) {
170 if (type_cell
== VTK_WEDGE
&& m_StrictPrismChecking
) {
171 vtkIdType N_pts
, *pts
;
173 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
175 for (int i
= 0; i
< 4; ++i
) { // variation
177 for (int j
= 0; j
< 3; ++j
) { // tetrahedron
178 for (int k
= 0; k
< 4; ++k
) { // node
179 m_Grid
->GetPoint(pts
[E
.priTet(i
,j
,k
)], xtet
[k
].data());
181 double V
= GeometryTools::tetraVol(xtet
[0], xtet
[1], xtet
[2], xtet
[3]);
197 m_Grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
202 void GridSmoother::correctDx(int i_nodes
, vec3_t
&Dx
)
204 l2g_t nodes
= m_Part
.getNodes();
205 l2l_t n2c
= m_Part
.getN2C();
206 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
208 m_Grid
->GetPoint(nodes
[i_nodes
],x_old
.data());
209 for (int i_boundary_correction
= 0; i_boundary_correction
< m_NumBoundaryCorrections
; ++i_boundary_correction
) {
210 foreach (vtkIdType id_cell
, n2c
[i_nodes
]) {
211 if (isSurface(id_cell
, m_Grid
)) {
212 int bc
= cell_code
->GetValue(id_cell
);
213 vec3_t x_new
= x_old
+ Dx
;
214 x_new
= GuiMainWindow::pointer()->getCadInterface(bc
)->snapNode(nodes
[i_nodes
], x_new
, false);
217 if (m_Grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
218 vtkIdType N_pts
, *pts
;
219 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
220 vtkIdType id_surf_node
= -1;
221 if (pts
[3] == nodes
[i_nodes
]) id_surf_node
= pts
[0];
222 if (pts
[4] == nodes
[i_nodes
]) id_surf_node
= pts
[1];
223 if (pts
[5] == nodes
[i_nodes
]) id_surf_node
= pts
[2];
224 if (id_surf_node
!= -1) {
226 m_Grid
->GetPoint(pts
[0],x0
.data());
227 m_Grid
->GetPoint(pts
[1],x1
.data());
228 m_Grid
->GetPoint(pts
[2],x2
.data());
232 double L
= (a
.abs()+b
.abs()+c
.abs())/3.0;
233 vec3_t n
= b
.cross(a
);
236 m_Grid
->GetPoint(nodes
[i_nodes
],x_old
.data());
237 vec3_t x_new
= x_old
+ Dx
- x0
;
238 if ( (n
*x_new
) <= 0 ) {
239 x_new
-= (x_new
*n
)*n
;
251 bool GridSmoother::moveNode(int i_nodes
, vec3_t
&Dx
)
253 m_CollisionDetected
= false;
254 l2g_t nodes
= m_Part
.getNodes();
255 vtkIdType id_node
= nodes
[i_nodes
];
257 m_Grid
->GetPoint(id_node
, x_old
.data());
259 for (int i_relaxation
= 0; i_relaxation
< m_NumRelaxations
; ++i_relaxation
) {
260 if (setNewPosition(id_node
, x_old
+ Dx
)) {
265 correctDx(i_nodes
, Dx
);
270 void GridSmoother::computeNormals()
272 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
273 m_NodeNormal
.fill(vec3_t(0,0,0), m_Grid
->GetNumberOfPoints());
274 QVector
<int> num_bcs(m_Grid
->GetNumberOfPoints());
275 QVector
<OptimiseNormalVector
> n_opt(m_Grid
->GetNumberOfPoints());
276 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
278 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
279 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
280 if (isSurface(id_cell
, m_Grid
)) {
281 int bc
= cell_code
->GetValue(id_cell
);
282 if (m_BoundaryCodes
.contains(bc
)) {
287 num_bcs
[id_node
] = bcs
.size();
288 QVector
<vec3_t
> normal(num_bcs
[id_node
], vec3_t(0,0,0));
291 foreach (int bc
, bcs
) {
295 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
296 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
297 if (isSurface(id_cell
, m_Grid
)) {
298 int bc
= cell_code
->GetValue(id_cell
);
299 vtkIdType N_pts
, *pts
;
300 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
302 for (int j
= 0; j
< N_pts
; ++j
) {
303 if (pts
[j
] == id_node
) {
304 m_Grid
->GetPoint(pts
[j
], a
.data());
306 m_Grid
->GetPoint(pts
[j
-1], b
.data());
308 m_Grid
->GetPoint(pts
[N_pts
-1], b
.data());
311 m_Grid
->GetPoint(pts
[j
+1], c
.data());
313 m_Grid
->GetPoint(pts
[0], c
.data());
319 double alpha
= GeometryTools::angle(u
, v
);
320 vec3_t n
= u
.cross(v
);
322 if (m_BoundaryCodes
.contains(bc
)) {
323 normal
[bcmap
[bc
]] += alpha
*n
;
324 n_opt
[id_node
].addFace(n
);
326 n_opt
[id_node
].addConstraint(n
);
330 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
331 normal
[i
].normalise();
333 if (num_bcs
[id_node
] > 0) {
334 if (num_bcs
[id_node
] > 1) {
335 if (num_bcs
[id_node
] == 3) {
336 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
337 for (int j
= i
+ 1; j
< num_bcs
[id_node
]; ++j
) {
338 vec3_t n
= normal
[i
] + normal
[j
];
340 m_NodeNormal
[id_node
] += n
;
344 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
345 m_NodeNormal
[id_node
] += normal
[i
];
349 m_NodeNormal
[id_node
] = normal
[0];
351 m_NodeNormal
[id_node
].normalise();
352 m_NodeNormal
[id_node
] = n_opt
[id_node
](m_NodeNormal
[id_node
]);
353 m_NodeNormal
[id_node
].normalise();
357 m_GeoNormal
= m_NodeNormal
;
358 relaxNormalVectors();
360 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
361 if (m_NodeNormal
[id_node
].abs() < 0.1) {
364 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
365 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
366 if (isSurface(id_cell
, m_Grid
)) {
367 n
+= GeometryTools::cellNormal(m_Grid
, id_cell
);
373 m_NodeNormal
[id_node
] = n
;
375 if (num_bcs
[id_node
] > 1) {
376 m_NodeNormal
[id_node
] = n_opt
[id_node
](m_NodeNormal
[id_node
]);
382 void GridSmoother::relaxNormalVectors()
384 m_SurfNode
.fill(false, m_Grid
->GetNumberOfPoints());
385 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
386 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
387 if (isSurface(m_Part
.n2cGG(id_node
,i
), m_Grid
)) {
388 m_SurfNode
[id_node
] = true;
393 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
394 QVector
<QSet
<int> > n2bc(m_Grid
->GetNumberOfPoints());
395 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
396 if (isSurface(id_cell
, m_Grid
)) {
397 vtkIdType N_pts
, *pts
;
398 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
399 for (int i
= 0; i
< N_pts
; ++i
) {
400 if (m_SurfNode
[pts
[i
]] && m_BoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
401 n2bc
[pts
[i
]].insert(bc
->GetValue(id_cell
));
406 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
407 if (n2bc
[id_node
].size() == 0) {
408 m_SurfNode
[id_node
] = false;
411 for (int iter
= 0; iter
< m_NumNormalRelaxations
; ++iter
) {
412 QVector
<vec3_t
> n_new(m_NodeNormal
.size(), vec3_t(0,0,0));
413 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
414 if (m_SurfNode
[id_node
] ) {
415 QList
<vtkIdType
> snap_points
;
416 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
417 vtkIdType id_neigh
= m_Part
.n2nGG(id_node
,i
);
419 foreach (int bc
, n2bc
[id_node
]) {
420 if (!n2bc
[id_neigh
].contains(bc
)) {
426 if (!m_SurfNode
[id_neigh
]) {
429 snap_points
.append(id_neigh
);
432 if (snap_points
.size() > 0) {
433 n_new
[id_node
] = vec3_t(0,0,0);
434 foreach (vtkIdType id_snap
, snap_points
) {
435 n_new
[id_node
] += m_NodeNormal
[id_snap
];
437 n_new
[id_node
].normalise();
439 n_new
[id_node
] = m_NodeNormal
[id_node
];
441 if (n_new
[id_node
].abs() < 0.1) {
446 m_NodeNormal
= n_new
;
447 correctNormalVectors();
451 void GridSmoother::getRules()
453 QString rules_text
= GuiMainWindow::pointer()->getXmlSection("engrid/blayer/rules");
454 QStringList rules
= rules_text
.split(";", QString::SkipEmptyParts
);
455 foreach (QString rule
, rules
) {
456 rule
= rule
.trimmed();
457 QStringList parts
= rule
.split("=");
458 if (parts
.count() > 1) {
460 QString left
= parts
[0].trimmed();
461 rule
.h
= parts
[1].trimmed().toDouble();
462 QStringList rows
= left
.split("<OR>");
463 foreach (QString row
, rows
) {
464 QStringList cols
= row
.split("<AND>");
465 foreach (QString col
, cols
) {
466 rule
.bcs
.insert(col
.toInt());
473 void GridSmoother::computeDesiredHeights()
475 // first pass (intial height)
476 EG_VTKDCN(vtkDoubleArray
, cl
, m_Grid
, "node_meshdensity_desired" );
477 m_Height
.fill(0, m_Grid
->GetNumberOfPoints());
478 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
479 if (m_SurfNode
[id_node
]) {
480 m_Height
[id_node
] = cl
->GetValue(id_node
);
481 // if undefined: compute height from surrounding edges
482 if (m_Height
[id_node
] < 1e-99) {
483 m_Height
[id_node
] = 0;
486 m_Grid
->GetPoint(id_node
, x
.data());
487 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
488 vtkIdType id_neigh_node
= m_Part
.n2nGG(id_node
, i
);
489 if (m_SurfNode
[id_neigh_node
]) {
492 m_Grid
->GetPoint(id_neigh_node
, xn
.data());
493 m_Height
[id_node
] += (x
- xn
).abs();
499 m_Height
[id_node
] /= N
;
503 QVector
<double> Dh_max
= m_Height
;
504 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
505 Dh_max
[id_node
] *= m_FarRatio
;
509 // second pass (correct with absolute height if required)
510 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
511 if (m_SurfNode
[id_node
]) {
512 m_Height
[id_node
] = m_Blending
*m_AbsoluteHeight
+ (1.0-m_Blending
)*m_RelativeHeight
*m_Height
[id_node
];
513 double h_rule
= 1e99
;
514 foreach (rule_t rule
, m_Rules
) {
515 bool apply_rule
= true;
516 foreach (int bc
, rule
.bcs
) {
517 if (!m_Part
.hasBC(id_node
, bc
)) {
523 h_rule
= min(h_rule
, rule
.h
);
527 //m_Height[id_node] = h_rule;
533 QVector
<double> h(m_Grid
->GetNumberOfPoints(), 0);
534 QVector
<double> h_opt(m_Grid
->GetNumberOfPoints(), 0);
536 double err_sq_max
= 1e99
;
541 double err_max_iter
= 0;
542 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
543 if (m_SurfNode
[id_node
]) {
544 double Dh
= m_Height
[id_node
];
545 h
[id_node
] = m_Height
[id_node
];
546 double total_ratio
= Dh_max
[id_node
]/Dh
;
547 double stretch
= pow(total_ratio
, 1.0/num_layers
);
548 for (int i
= 1; i
< num_layers
; ++i
) {
553 if (fabs(stretch
) > fabs(m_DesiredStretching
)) {
554 err
= fabs(stretch
- m_DesiredStretching
)/m_DesiredStretching
;
556 err
= fabs(stretch
- m_DesiredStretching
)/stretch
;
558 err_max_iter
= max(err_max_iter
, err
);
562 if (err_sq
< err_sq_max
) {
563 m_NumLayers
= num_layers
;
567 } while (num_layers
< 200);
570 // correct with angle between face normal and propagation direction (node normals)
571 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
572 if (m_SurfNode
[id_node
]) {
575 for (int j
= 0; j
< m_Part
.n2cGSize(id_node
); ++j
) {
576 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, j
);
577 if (isSurface(id_cell
, m_Grid
)) {
578 scale
+= m_NodeNormal
[id_node
]*cellNormal(m_Grid
, id_cell
).normalise();
583 m_Height
[id_node
] /= scale
;
589 bool GridSmoother::faceFine(vtkIdType id_face
, double scale
)
591 EG_GET_CELL(id_face
, m_Grid
);
592 if (type_cell
!= VTK_TRIANGLE
) {
595 QVector
<vec3_t
> x1(num_pts
);
596 for (vtkIdType i
= 0; i
< num_pts
; ++i
) {
597 m_Grid
->GetPoint(pts
[i
], x1
[i
].data());
599 vec3_t n1
= triNormal(x1
[0], x1
[1], x1
[2]);
600 QVector
<vec3_t
> x2(num_pts
);
601 for (vtkIdType i
= 0; i
< num_pts
; ++i
) {
602 x2
[i
] = x1
[i
] + scale
*m_Height
[pts
[i
]]*m_NodeNormal
[pts
[i
]];
604 vec3_t n2
= triNormal(x2
[0], x2
[1], x2
[2]);
605 double A1
= n1
.abs();
606 double A2
= n2
.abs();
607 if (A2
/A1
>= m_FaceSizeLowerLimit
&& A2
/A1
<= m_FaceSizeUpperLimit
){
608 if (angle(n1
, n2
) < m_FaceAngleLimit
) {
615 void GridSmoother::computeHeights()
617 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
620 QString blayer_txt
= GuiMainWindow::pointer()->getXmlSection("blayer/global");
621 QTextStream
s(&blayer_txt
);
622 if (!s
.atEnd()) s
>> m_AbsoluteHeight
;
623 if (!s
.atEnd()) s
>> m_RelativeHeight
;
624 if (!s
.atEnd()) s
>> m_Blending
;
625 if (!s
.atEnd()) s
>> m_DesiredStretching
;
626 if (!s
.atEnd()) s
>> m_FarRatio
;
627 if (!s
.atEnd()) s
>> m_NumLayers
;
628 if (!s
.atEnd()) s
>> m_NumHeightRelaxations
;
629 if (!s
.atEnd()) s
>> m_NumNormalRelaxations
;
631 computeDesiredHeights();
633 QString blayer_txt
= "";
634 QTextStream
s(&blayer_txt
);
635 s
<< m_AbsoluteHeight
<< " ";
636 s
<< m_RelativeHeight
<< " ";
637 s
<< m_Blending
<< " ";
638 s
<< m_DesiredStretching
<< " ";
639 s
<< m_FarRatio
<< " ";
640 s
<< m_NumLayers
<< " ";
641 s
<< m_NumHeightRelaxations
<< " ";
642 s
<< m_NumNormalRelaxations
<< " ";
643 GuiMainWindow::pointer()->setXmlSection("blayer/global", blayer_txt
);
649 // prepare search list of potential "crash" partner points
650 QList
<vtkIdType
> search_nodes
;
651 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
652 bool append_node
= m_SurfNode
[id_node
];
654 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
655 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
656 if (isSurface(id_cell
, m_Grid
)) {
657 if (!m_LayerAdjacentBoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
665 search_nodes
.append(id_node
);
670 QVector
<vec3_t
> points(search_nodes
.size());
671 for (int i
= 0; i
< search_nodes
.size(); ++i
) {
672 m_Grid
->GetPoint(search_nodes
[i
], points
[i
].data());
675 pfind
.setPoints(points
);
677 // check for potential collisions
678 for (vtkIdType id_node1
= 0; id_node1
< m_Grid
->GetNumberOfPoints(); ++id_node1
) {
679 if (m_SurfNode
[id_node1
]) {
681 m_Grid
->GetPoint(id_node1
, x1
.data());
682 QVector
<int> close_points
;
683 pfind
.getClosePoints(x1
, close_points
, 20*m_Height
[id_node1
]/m_MaxHeightInGaps
);
684 foreach (int i
, close_points
) {
686 // maybe check for topological neighbours and exclude them from the search ...
688 vtkIdType id_node2
= search_nodes
[i
];
689 if (id_node1
!= id_node2
) {
690 const vec3_t
& n1
= m_NodeNormal
[id_node1
];
692 m_Grid
->GetPoint(id_node1
, x1
.data());
693 m_Grid
->GetPoint(id_node2
, x2
.data());
698 double alpha
= 180.0/M_PI
*acos(a
/b
); /// @todo This is very slow; look at alternatives!
699 if (alpha
< m_RadarAngle
) {
700 m_Height
[id_node1
] = min(m_Height
[id_node1
], m_MaxHeightInGaps
*a
);
709 // limit face size difference (neighbour collisions)
714 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
715 if (isSurface(id_cell
, m_Grid
)) {
716 vtkIdType num_pts
, *pts
;
717 m_Grid
->GetCellPoints(id_cell
, num_pts
, pts
);
718 bool check_face
= true;
719 for (vtkIdType i
= 0; i
< num_pts
; ++i
) {
720 if (!m_SurfNode
[pts
[i
]]) {
726 if (!faceFine(id_cell
, 1)) {
730 while (scale2
- scale1
> 1e-3) {
731 if (faceFine(id_cell
, 0.5*(scale1
+ scale2
))) {
732 scale1
= 0.5*(scale1
+ scale2
);
734 scale2
= 0.5*(scale1
+ scale2
);
737 for (vtkIdType i
= 0; i
< num_pts
; ++i
) {
738 m_Height
[pts
[i
]] *= 0.5*(scale1
+ scale2
);
748 QVector
<int> num_bcs(m_Grid
->GetNumberOfPoints(),0);
749 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
750 if (m_SurfNode
[id_node
]) {
751 for (int i
= 0; i
< m_Part
.n2bcGSize(id_node
); ++i
) {
752 int bc
= m_Part
.n2bcG(id_node
, i
);
753 if (m_BoundaryCodes
.contains(bc
)) {
759 for (int iter
= 0; iter
< m_NumHeightRelaxations
; ++iter
) {
760 QVector
<double> h_new
= m_Height
;
761 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
762 if (m_SurfNode
[id_node
]) {
763 QList
<vtkIdType
> snap_points
;
764 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
765 vtkIdType id_neigh
= m_Part
.n2nGG(id_node
,i
);
766 if (num_bcs
[id_node
] <= num_bcs
[id_neigh
]) {
767 if (!m_SurfNode
[id_neigh
]) {
770 snap_points
.append(id_neigh
);
773 if (snap_points
.size() > 0) {
775 if (snap_points
.size() == 2) {
776 snap_points
.append(id_node
);
778 foreach (vtkIdType id_snap
, snap_points
) {
779 h_new
[id_node
] += m_Height
[id_snap
];
781 h_new
[id_node
] /= snap_points
.size();
782 //h_new[id_node] = min(h_new[id_node], m_Height[id_node]);
784 h_new
[id_node
] = m_Height
[id_node
];
786 //h_new[id_node] = min(h_new[id_node], height_limit[id_node]);
795 void GridSmoother::correctNormalVectors()
797 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
798 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
799 if (m_NodeNormal
[id_node
].abs() > 0.1) {
800 for (int iter
= 0; iter
< m_NumBoundaryCorrections
; ++iter
) {
801 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
802 vtkIdType id_cell
= m_Part
.n2cGG(id_node
,i
);
803 if (isSurface(id_cell
, m_Grid
)) {
804 if (!m_BoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
805 vec3_t v
= m_NodeNormal
[id_node
];
806 vec3_t n
= GeometryTools::cellNormal(m_Grid
, id_cell
);
808 v
-= (n
*m_NodeNormal
[id_node
])*n
;
810 m_NodeNormal
[id_node
] = v
;
819 void GridSmoother::computeFeet()
821 m_IdFoot
.fill(-1, m_Grid
->GetNumberOfPoints());
822 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
823 if (m_Grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
824 vtkIdType N_pts
, *pts
;
825 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
826 m_IdFoot
[pts
[3]] = pts
[0];
827 m_IdFoot
[pts
[4]] = pts
[1];
828 m_IdFoot
[pts
[5]] = pts
[2];
829 m_NodeMarked
[pts
[0]] = false;
830 m_NodeMarked
[pts
[1]] = false;
831 m_NodeMarked
[pts
[2]] = false;
836 void GridSmoother::simpleNodeMovement(int i_nodes
)
838 vtkIdType id_node
= m_Part
.globalNode(i_nodes
);
839 vtkIdType id_foot
= m_IdFoot
[id_node
];
840 vec3_t
x_new(0,0,0), x_node
;
841 m_Grid
->GetPoint(id_node
, x_node
.data());
843 vec3_t
x_surf(0,0,0);
844 if (m_SurfNode
[id_node
]) {
846 for (int i
= 0; i
< m_Part
.n2nLSize(i_nodes
); ++i
) {
847 vtkIdType id_neigh
= m_Part
.n2nLG(i_nodes
,i
);
848 if (m_SurfNode
[id_neigh
]) {
850 m_Grid
->GetPoint(id_neigh
, x_neigh
.data());
863 vec3_t x_foot
, x_node
;
864 m_Grid
->GetPoint(id_foot
, x_foot
.data());
865 //double H = m_Blending*m_AbsoluteHeight + (1.0-m_Blending)*m_RelativeHeight*m_Height[id_foot];
866 double H
= m_Height
[id_foot
];
867 x_new
= x_foot
+ H
*m_NodeNormal
[id_foot
];
869 if (m_SurfNode
[id_node
]) {
872 if (m_Part
.n2nLSize(i_nodes
) == 0) {
875 for (int i
= 0; i
< m_Part
.n2nLSize(i_nodes
); ++i
) {
876 vtkIdType id_neigh
= m_Part
.n2nLG(i_nodes
,i
);
878 m_Grid
->GetPoint(id_neigh
, x_neigh
.data());
881 x_new
*= 1.0/m_Part
.n2nLSize(i_nodes
);
884 vec3_t Dx
= x_new
- x_node
;
885 correctDx(i_nodes
, Dx
);
886 moveNode(i_nodes
, Dx
);
889 void GridSmoother::operate()
898 l2g_t nodes
= m_Part
.getNodes();
899 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
900 if (m_NodeMarked
[nodes
[i_nodes
]]) {
901 simpleNodeMovement(i_nodes
);
906 void GridSmoother::writeDebugFile(QString file_name
)
908 QVector
<vtkIdType
> bcells
;
909 QSet
<int> bcs
= getAllBoundaryCodes(m_Grid
);
910 getSurfaceCells(bcs
, bcells
, m_Grid
);
911 MeshPartition
bpart(m_Grid
);
912 bpart
.setCells(bcells
);
913 file_name
= GuiMainWindow::pointer()->getCwd() + "/" + file_name
+ ".vtk";
914 QFile
file(file_name
);
915 file
.open(QIODevice::WriteOnly
);
916 QTextStream
f(&file
);
917 f
<< "# vtk DataFile Version 2.0\n";
918 f
<< "m_NodeNormal\n";
920 f
<< "DATASET UNSTRUCTURED_GRID\n";
921 f
<< "POINTS " << bpart
.getNumberOfNodes() << " float\n";
922 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
924 vtkIdType id_node
= bpart
.globalNode(i
);
925 m_Grid
->GetPoint(id_node
, x
.data());
926 f
<< x
[0] << " " << x
[1] << " " << x
[2] << "\n";
928 f
<< "CELLS " << bpart
.getNumberOfCells() << " ";
930 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
931 vtkIdType id_cell
= bpart
.globalCell(i
);
932 vtkIdType N_pts
, *pts
;
933 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
937 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
938 vtkIdType id_cell
= bpart
.globalCell(i
);
939 vtkIdType N_pts
, *pts
;
940 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
942 for (int j
= 0; j
< N_pts
; ++j
) {
943 f
<< " " << bpart
.localNode(pts
[j
]);
948 f
<< "CELL_TYPES " << bpart
.getNumberOfCells() << "\n";
949 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
950 vtkIdType id_cell
= bpart
.globalCell(i
);
951 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
952 f
<< type_cell
<< "\n";
954 f
<< "POINT_DATA " << bpart
.getNumberOfNodes() << "\n";
956 f
<< "VECTORS N float\n";
957 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
958 vtkIdType id_node
= bpart
.globalNode(i
);
959 f
<< m_NodeNormal
[id_node
][0] << " " << m_NodeNormal
[id_node
][1] << " " << m_NodeNormal
[id_node
][2] << "\n";
962 f
<< "SCALARS h float\n";
963 f
<< "LOOKUP_TABLE default\n";
964 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
965 vtkIdType id_node
= bpart
.globalNode(i
);
966 f
<< m_Height
[id_node
] << "\n";