2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 // + This file is part of enGrid. +
6 // + Copyright 2008-2012 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 "gridsmoother.h"
24 #include "guimainwindow.h"
26 #include "optimisenormalvector.h"
27 #include "pointfinder.h"
28 #include "trisurfaceprojection.h"
32 GridSmoother::GridSmoother()
36 m_NumBoundaryCorrections
= 50;
37 m_DesiredStretching
= 1.2;
40 getSet("boundary layer", "number of smoothing sub-iterations", 5, m_NumIterations
);
41 getSet("boundary layer", "use strict prism checking", false, m_StrictPrismChecking
);
42 getSet("boundary layer", "number of normal vector relax iterations", 10, m_NumNormalRelaxations
);
43 getSet("boundary layer", "number of layer height relax iterations", 3, m_NumHeightRelaxations
);
44 getSet("boundary layer", "radar angle", 45, m_RadarAngle
);
45 getSet("boundary layer", "maximal layer height in gaps", 0.2, m_MaxHeightInGaps
);
47 //m_CritAngle = GeometryTools::deg2rad(m_CritAngle);
50 void GridSmoother::markNodes()
52 m_NodeMarked
.fill(false,m_Grid
->GetNumberOfPoints());
53 QVector
<bool> new_mark(m_Grid
->GetNumberOfPoints());
54 for (int i_iterations
= 0; i_iterations
< 1; ++i_iterations
) {
55 qCopy(m_NodeMarked
.begin(),m_NodeMarked
.end(),new_mark
.begin());
56 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
57 bool mark_cell
= false;
58 vtkIdType type_cell
, N_pts
, *pts
;
59 type_cell
= m_Grid
->GetCellType(id_cell
);
60 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
61 if (type_cell
== VTK_WEDGE
) {
64 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
65 if (m_NodeMarked
[pts
[i_pts
]]) {
71 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
72 new_mark
[pts
[i_pts
]] = true;
76 qCopy(new_mark
.begin(),new_mark
.end(),m_NodeMarked
.begin());
78 QSet
<int> free_bcs
= m_BoundaryCodes
+ m_LayerAdjacentBoundaryCodes
;
79 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
80 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
81 if (isSurface(id_cell
, m_Grid
)) {
82 if (!free_bcs
.contains(cell_code
->GetValue(id_cell
))) {
83 vtkIdType N_pts
, *pts
;
84 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
85 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
86 m_NodeMarked
[pts
[i_pts
]] = false;
92 QVector
<vtkIdType
> nodes
= m_Part
.getNodes();
93 foreach (vtkIdType id_node
, nodes
) {
94 if (id_node
< 0) EG_BUG
;
95 if (id_node
> m_Grid
->GetNumberOfPoints()) EG_BUG
;
96 if (m_NodeMarked
[id_node
]) {
102 bool GridSmoother::setNewPosition(vtkIdType id_node
, vec3_t x_new
)
104 using namespace GeometryTools
;
107 m_Grid
->GetPoint(id_node
, x_old
.data());
108 m_Grid
->GetPoints()->SetPoint(id_node
, x_new
.data());
114 l2g_t cells
= m_Part
.getCells();
115 l2l_t n2c
= m_Part
.getN2C();
117 foreach (int i_cells
, n2c
[id_node
]) {
118 vtkIdType id_cell
= cells
[i_cells
];
119 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
121 if (type_cell
== VTK_TRIANGLE
) {
122 vtkIdType N_pts
, *pts
;
124 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
125 for (int i
= 0; i
< 3; ++i
) {
126 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
129 for (int i
= 0; i
< 3; ++i
) {
130 for (int j
= 0; j
< 3; ++j
) {
132 L_max
= max(L_max
, (x
[i
]-x
[j
]).abs());
136 double A
= GeometryTools::cellVA(m_Grid
, id_cell
);
137 if (A
< 1e-3*L_max
*L_max
) {
139 } else if (m_NodeNormal
[id_node
].abs() > 0.1) {
140 vec3_t n
= GeometryTools::triNormal(x
[0], x
[1], x
[2]);
142 if (n
*m_NodeNormal
[id_node
] < 0.1) {
148 if (type_cell
== VTK_TETRA
) {
149 vtkIdType N_pts
, *pts
;
151 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
152 for (int i
= 0; i
< 4; ++i
) {
153 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
156 for (int i
= 0; i
< 4; ++i
) {
157 for (int j
= 0; j
< 4; ++j
) {
159 L_max
= max(L_max
, (x
[i
]-x
[j
]).abs());
163 if (GeometryTools::cellVA(m_Grid
, id_cell
) < 1e-3*L_max
*L_max
*L_max
) {
168 if (type_cell
== VTK_WEDGE
&& m_StrictPrismChecking
) {
169 vtkIdType N_pts
, *pts
;
171 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
173 for (int i
= 0; i
< 4; ++i
) { // variation
175 for (int j
= 0; j
< 3; ++j
) { // tetrahedron
176 for (int k
= 0; k
< 4; ++k
) { // node
177 m_Grid
->GetPoint(pts
[E
.priTet(i
,j
,k
)], xtet
[k
].data());
179 double V
= GeometryTools::tetraVol(xtet
[0], xtet
[1], xtet
[2], xtet
[3]);
195 m_Grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
200 void GridSmoother::correctDx(int i_nodes
, vec3_t
&Dx
)
202 l2g_t nodes
= m_Part
.getNodes();
203 l2l_t n2c
= m_Part
.getN2C();
204 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
206 m_Grid
->GetPoint(nodes
[i_nodes
],x_old
.data());
207 for (int i_boundary_correction
= 0; i_boundary_correction
< m_NumBoundaryCorrections
; ++i_boundary_correction
) {
208 foreach (vtkIdType id_cell
, n2c
[i_nodes
]) {
209 if (isSurface(id_cell
, m_Grid
)) {
210 int bc
= cell_code
->GetValue(id_cell
);
211 vec3_t x_new
= x_old
+ Dx
;
212 x_new
= GuiMainWindow::pointer()->getSurfProj(bc
)->projectRestricted(x_new
, nodes
[i_nodes
]);
215 if (m_Grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
216 vtkIdType N_pts
, *pts
;
217 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
218 vtkIdType id_surf_node
= -1;
219 if (pts
[3] == nodes
[i_nodes
]) id_surf_node
= pts
[0];
220 if (pts
[4] == nodes
[i_nodes
]) id_surf_node
= pts
[1];
221 if (pts
[5] == nodes
[i_nodes
]) id_surf_node
= pts
[2];
222 if (id_surf_node
!= -1) {
224 m_Grid
->GetPoint(pts
[0],x0
.data());
225 m_Grid
->GetPoint(pts
[1],x1
.data());
226 m_Grid
->GetPoint(pts
[2],x2
.data());
230 double L
= (a
.abs()+b
.abs()+c
.abs())/3.0;
231 vec3_t n
= b
.cross(a
);
234 m_Grid
->GetPoint(nodes
[i_nodes
],x_old
.data());
235 vec3_t x_new
= x_old
+ Dx
- x0
;
236 if ( (n
*x_new
) <= 0 ) {
237 x_new
-= (x_new
*n
)*n
;
249 bool GridSmoother::moveNode(int i_nodes
, vec3_t
&Dx
)
251 m_CollisionDetected
= false;
252 l2g_t nodes
= m_Part
.getNodes();
253 vtkIdType id_node
= nodes
[i_nodes
];
255 m_Grid
->GetPoint(id_node
, x_old
.data());
257 for (int i_relaxation
= 0; i_relaxation
< m_NumRelaxations
; ++i_relaxation
) {
258 if (setNewPosition(id_node
, x_old
+ Dx
)) {
267 void GridSmoother::computeNormals()
269 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
270 m_NodeNormal
.fill(vec3_t(0,0,0), m_Grid
->GetNumberOfPoints());
271 QVector
<int> num_bcs(m_Grid
->GetNumberOfPoints());
272 QVector
<OptimiseNormalVector
> n_opt(m_Grid
->GetNumberOfPoints());
273 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
275 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
276 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
277 if (isSurface(id_cell
, m_Grid
)) {
278 int bc
= cell_code
->GetValue(id_cell
);
279 if (m_BoundaryCodes
.contains(bc
)) {
284 num_bcs
[id_node
] = bcs
.size();
285 QVector
<vec3_t
> normal(num_bcs
[id_node
], vec3_t(0,0,0));
288 foreach (int bc
, bcs
) {
292 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
293 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
294 if (isSurface(id_cell
, m_Grid
)) {
295 int bc
= cell_code
->GetValue(id_cell
);
296 vtkIdType N_pts
, *pts
;
297 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
299 for (int j
= 0; j
< N_pts
; ++j
) {
300 if (pts
[j
] == id_node
) {
301 m_Grid
->GetPoint(pts
[j
], a
.data());
303 m_Grid
->GetPoint(pts
[j
-1], b
.data());
305 m_Grid
->GetPoint(pts
[N_pts
-1], b
.data());
308 m_Grid
->GetPoint(pts
[j
+1], c
.data());
310 m_Grid
->GetPoint(pts
[0], c
.data());
316 double alpha
= GeometryTools::angle(u
, v
);
317 vec3_t n
= u
.cross(v
);
319 if (m_BoundaryCodes
.contains(bc
)) {
320 normal
[bcmap
[bc
]] += alpha
*n
;
321 n_opt
[id_node
].addFace(n
);
323 n_opt
[id_node
].addConstraint(n
);
327 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
328 normal
[i
].normalise();
330 if (num_bcs
[id_node
] > 0) {
331 if (num_bcs
[id_node
] > 1) {
332 if (num_bcs
[id_node
] == 3) {
333 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
334 for (int j
= i
+ 1; j
< num_bcs
[id_node
]; ++j
) {
335 vec3_t n
= normal
[i
] + normal
[j
];
337 m_NodeNormal
[id_node
] += n
;
341 for (int i
= 0; i
< num_bcs
[id_node
]; ++i
) {
342 m_NodeNormal
[id_node
] += normal
[i
];
346 m_NodeNormal
[id_node
] = normal
[0];
348 m_NodeNormal
[id_node
].normalise();
349 m_NodeNormal
[id_node
] = n_opt
[id_node
](m_NodeNormal
[id_node
]);
350 m_NodeNormal
[id_node
].normalise();
354 m_GeoNormal
= m_NodeNormal
;
355 relaxNormalVectors();
357 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
358 if (m_NodeNormal
[id_node
].abs() < 0.1) {
361 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
362 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
363 if (isSurface(id_cell
, m_Grid
)) {
364 n
+= GeometryTools::cellNormal(m_Grid
, id_cell
);
370 m_NodeNormal
[id_node
] = n
;
372 if (num_bcs
[id_node
] > 1) {
373 m_NodeNormal
[id_node
] = n_opt
[id_node
](m_NodeNormal
[id_node
]);
379 void GridSmoother::relaxNormalVectors()
381 m_SurfNode
.fill(false, m_Grid
->GetNumberOfPoints());
382 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
383 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
384 if (isSurface(m_Part
.n2cGG(id_node
,i
), m_Grid
)) {
385 m_SurfNode
[id_node
] = true;
390 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
391 QVector
<QSet
<int> > n2bc(m_Grid
->GetNumberOfPoints());
392 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
393 if (isSurface(id_cell
, m_Grid
)) {
394 vtkIdType N_pts
, *pts
;
395 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
396 for (int i
= 0; i
< N_pts
; ++i
) {
397 if (m_SurfNode
[pts
[i
]] && m_BoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
398 n2bc
[pts
[i
]].insert(bc
->GetValue(id_cell
));
403 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
404 if (n2bc
[id_node
].size() == 0) {
405 m_SurfNode
[id_node
] = false;
408 for (int iter
= 0; iter
< m_NumNormalRelaxations
; ++iter
) {
409 QVector
<vec3_t
> n_new(m_NodeNormal
.size(), vec3_t(0,0,0));
410 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
411 if (m_SurfNode
[id_node
] ) {
412 QList
<vtkIdType
> snap_points
;
413 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
414 vtkIdType id_neigh
= m_Part
.n2nGG(id_node
,i
);
416 foreach (int bc
, n2bc
[id_node
]) {
417 if (!n2bc
[id_neigh
].contains(bc
)) {
423 if (!m_SurfNode
[id_neigh
]) {
426 snap_points
.append(id_neigh
);
429 if (snap_points
.size() > 0) {
430 n_new
[id_node
] = vec3_t(0,0,0);
431 foreach (vtkIdType id_snap
, snap_points
) {
432 n_new
[id_node
] += m_NodeNormal
[id_snap
];
434 n_new
[id_node
].normalise();
436 n_new
[id_node
] = m_NodeNormal
[id_node
];
438 if (n_new
[id_node
].abs() < 0.1) {
443 m_NodeNormal
= n_new
;
444 correctNormalVectors();
448 void GridSmoother::getRules()
450 QString rules_text
= GuiMainWindow::pointer()->getXmlSection("engrid/blayer/rules");
451 QStringList rules
= rules_text
.split(";", QString::SkipEmptyParts
);
452 foreach (QString rule
, rules
) {
453 rule
= rule
.trimmed();
454 QStringList parts
= rule
.split("=");
455 if (parts
.count() > 1) {
457 QString left
= parts
[0].trimmed();
458 rule
.h
= parts
[1].trimmed().toDouble();
459 QStringList rows
= left
.split("<OR>");
460 foreach (QString row
, rows
) {
461 QStringList cols
= row
.split("<AND>");
462 foreach (QString col
, cols
) {
463 rule
.bcs
.insert(col
.toInt());
470 void GridSmoother::computeDesiredHeights()
472 // first pass (intial height)
473 EG_VTKDCN(vtkDoubleArray
, cl
, m_Grid
, "node_meshdensity_desired" );
474 m_Height
.fill(0, m_Grid
->GetNumberOfPoints());
475 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
476 if (m_SurfNode
[id_node
]) {
477 m_Height
[id_node
] = cl
->GetValue(id_node
);
478 // if undefined: compute height from surrounding edges
479 if (m_Height
[id_node
] < 1e-99) {
480 m_Height
[id_node
] = 0;
483 m_Grid
->GetPoint(id_node
, x
.data());
484 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
485 vtkIdType id_neigh_node
= m_Part
.n2nGG(id_node
, i
);
486 if (m_SurfNode
[id_neigh_node
]) {
489 m_Grid
->GetPoint(id_neigh_node
, xn
.data());
490 m_Height
[id_node
] += (x
- xn
).abs();
496 m_Height
[id_node
] /= N
;
500 QVector
<double> Dh_max
= m_Height
;
501 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
502 Dh_max
[id_node
] *= m_FarRatio
;
506 // second pass (correct with absolute height if required)
507 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
508 if (m_SurfNode
[id_node
]) {
509 m_Height
[id_node
] = m_Blending
*m_AbsoluteHeight
+ (1.0-m_Blending
)*m_RelativeHeight
*m_Height
[id_node
];
510 double h_rule
= 1e99
;
511 foreach (rule_t rule
, m_Rules
) {
512 bool apply_rule
= true;
513 foreach (int bc
, rule
.bcs
) {
514 if (!m_Part
.hasBC(id_node
, bc
)) {
520 h_rule
= min(h_rule
, rule
.h
);
524 //m_Height[id_node] = h_rule;
530 QVector
<double> h(m_Grid
->GetNumberOfPoints(), 0);
531 QVector
<double> h_opt(m_Grid
->GetNumberOfPoints(), 0);
533 double err_sq_max
= 1e99
;
538 double err_max_iter
= 0;
539 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
540 if (m_SurfNode
[id_node
]) {
541 double Dh
= m_Height
[id_node
];
542 h
[id_node
] = m_Height
[id_node
];
543 double total_ratio
= Dh_max
[id_node
]/Dh
;
544 double stretch
= pow(total_ratio
, 1.0/num_layers
);
545 for (int i
= 1; i
< num_layers
; ++i
) {
550 if (fabs(stretch
) > fabs(m_DesiredStretching
)) {
551 err
= fabs(stretch
- m_DesiredStretching
)/m_DesiredStretching
;
553 err
= fabs(stretch
- m_DesiredStretching
)/stretch
;
555 err_max_iter
= max(err_max_iter
, err
);
559 if (err_sq
< err_sq_max
) {
560 m_NumLayers
= num_layers
;
564 } while (num_layers
< 200);
568 void GridSmoother::computeHeights()
570 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
573 QString blayer_txt
= GuiMainWindow::pointer()->getXmlSection("blayer/global");
574 QTextStream
s(&blayer_txt
);
575 if (!s
.atEnd()) s
>> m_AbsoluteHeight
;
576 if (!s
.atEnd()) s
>> m_RelativeHeight
;
577 if (!s
.atEnd()) s
>> m_Blending
;
578 if (!s
.atEnd()) s
>> m_DesiredStretching
;
579 if (!s
.atEnd()) s
>> m_FarRatio
;
580 if (!s
.atEnd()) s
>> m_NumLayers
;
581 if (!s
.atEnd()) s
>> m_NumHeightRelaxations
;
582 if (!s
.atEnd()) s
>> m_NumNormalRelaxations
;
584 computeDesiredHeights();
586 QString blayer_txt
= "";
587 QTextStream
s(&blayer_txt
);
588 s
<< m_AbsoluteHeight
<< " ";
589 s
<< m_RelativeHeight
<< " ";
590 s
<< m_Blending
<< " ";
591 s
<< m_DesiredStretching
<< " ";
592 s
<< m_FarRatio
<< " ";
593 s
<< m_NumLayers
<< " ";
594 s
<< m_NumHeightRelaxations
<< " ";
595 s
<< m_NumNormalRelaxations
<< " ";
596 GuiMainWindow::pointer()->setXmlSection("blayer/global", blayer_txt
);
599 // compute height limiters
600 QVector
<double> height_limit(m_Grid
->GetNumberOfPoints(), 1e99
);
603 QList
<vtkIdType
> search_nodes
;
604 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
605 bool append_node
= m_SurfNode
[id_node
];
607 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
608 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
609 if (isSurface(id_cell
, m_Grid
)) {
610 if (!m_LayerAdjacentBoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
618 search_nodes
.append(id_node
);
622 QVector
<vec3_t
> points(search_nodes
.size());
623 for (int i
= 0; i
< search_nodes
.size(); ++i
) {
624 m_Grid
->GetPoint(search_nodes
[i
], points
[i
].data());
627 pfind
.setPoints(points
);
629 for (vtkIdType id_node1
= 0; id_node1
< m_Grid
->GetNumberOfPoints(); ++id_node1
) {
630 if (m_SurfNode
[id_node1
]) {
632 m_Grid
->GetPoint(id_node1
, x1
.data());
633 QVector
<int> close_points
;
634 pfind
.getClosePoints(x1
, close_points
, 20*m_Height
[id_node1
]/m_MaxHeightInGaps
);
635 foreach (int i
, close_points
) {
636 vtkIdType id_node2
= search_nodes
[i
];
637 if (id_node1
!= id_node2
) {
639 if (m_GeoNormal[id_node1]*m_GeoNormal[id_node2] < 0) {
641 m_Grid->GetPoint(id_node2, x2.data());
643 double a = Dx*m_GeoNormal[id_node1];
646 double b = sqrt(sqr(c) - sqr(a));
647 double cos_beta = acos(fabs(m_GeoNormal[id_node1]*m_GeoNormal[id_node2]));
648 double e = b/cos_beta;
649 double d = sqrt(sqr(e) - sqr(b));
650 double alpha = 180.0/M_PI*acos(a/c);
651 if (alpha < m_RadarAngle) {
652 height_limit[id_node1] = min(height_limit[id_node1], m_MaxHeightInGaps*(a+d));
657 const vec3_t
& n1
= m_NodeNormal
[id_node1
];
659 m_Grid
->GetPoint(id_node1
, x1
.data());
660 m_Grid
->GetPoint(id_node2
, x2
.data());
665 double alpha
= 180.0/M_PI
*acos(a
/b
);
666 if (alpha
< m_RadarAngle
) {
667 m_Height
[id_node1
] = min(m_Height
[id_node1
], m_MaxHeightInGaps
*a
);
676 for (vtkIdType id_node1
= 0; id_node1
< m_Grid
->GetNumberOfPoints(); ++id_node1
) {
677 if (m_SurfNode
[id_node1
]) {
679 m_Grid
->GetPoint(id_node1
, x1
.data());
680 for (int i
= 0; i
< m_Part
.n2nGSize(id_node1
); ++i
) {
681 vtkIdType id_node2
= m_Part
.n2nGG(id_node1
, i
);
682 if (m_SurfNode
[id_node2
]) {
684 m_Grid
->GetPoint(id_node2
, x2
.data());
688 vec3_t n_plane
= v
.cross(m_NodeNormal
[id_node1
]);
689 n_plane
.normalise(); //??
690 vec3_t n1_2d
= m_NodeNormal
[id_node1
] - (m_NodeNormal
[id_node1
]*n_plane
)*n_plane
;
691 vec3_t n2_2d
= m_NodeNormal
[id_node2
] - (m_NodeNormal
[id_node2
]*n_plane
)*n_plane
;
694 double m1
= sign1(s1
)*sqrt(1 - sqr(s1
))/max(1e-3, fabs(s1
));
695 double m2
= sign1(s2
)*sqrt(1 - sqr(s2
))/max(1e-3, fabs(s2
));
696 if (fabs(m1
) < 100 && fabs(m2
) < 100) {
697 double C
= sign1(m2
- m1
)*max(1e-3, fabs(m2
- m1
));
700 height_limit
[id_node1
] = min(height_limit
[id_node1
], 2*m_MaxHeightInGaps
*h
*L
);
707 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
708 m_Height
[id_node
] = min(height_limit
[id_node
], m_Height
[id_node
]);
711 // fifth pass (smoothing)
712 QVector
<int> num_bcs(m_Grid
->GetNumberOfPoints(),0);
713 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
714 if (m_SurfNode
[id_node
]) {
715 for (int i
= 0; i
< m_Part
.n2bcGSize(id_node
); ++i
) {
716 int bc
= m_Part
.n2bcG(id_node
, i
);
717 if (m_BoundaryCodes
.contains(bc
)) {
723 for (int iter
= 0; iter
< m_NumHeightRelaxations
; ++iter
) {
724 QVector
<double> h_new
= m_Height
;
725 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
726 if (m_SurfNode
[id_node
]) {
727 QList
<vtkIdType
> snap_points
;
728 for (int i
= 0; i
< m_Part
.n2nGSize(id_node
); ++i
) {
729 vtkIdType id_neigh
= m_Part
.n2nGG(id_node
,i
);
730 if (num_bcs
[id_node
] <= num_bcs
[id_neigh
]) {
731 if (!m_SurfNode
[id_neigh
]) {
734 snap_points
.append(id_neigh
);
737 if (snap_points
.size() > 0) {
739 foreach (vtkIdType id_snap
, snap_points
) {
740 h_new
[id_node
] += m_Height
[id_snap
];
742 h_new
[id_node
] /= snap_points
.size();
744 h_new
[id_node
] = m_Height
[id_node
];
746 //h_new[id_node] = min(h_new[id_node], height_limit[id_node]);
753 void GridSmoother::correctNormalVectors()
755 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
756 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
757 if (m_NodeNormal
[id_node
].abs() > 0.1) {
758 for (int iter
= 0; iter
< m_NumBoundaryCorrections
; ++iter
) {
759 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
760 vtkIdType id_cell
= m_Part
.n2cGG(id_node
,i
);
761 if (isSurface(id_cell
, m_Grid
)) {
762 if (!m_BoundaryCodes
.contains(bc
->GetValue(id_cell
))) {
763 vec3_t v
= m_NodeNormal
[id_node
];
764 vec3_t n
= GeometryTools::cellNormal(m_Grid
, id_cell
);
766 v
-= (n
*m_NodeNormal
[id_node
])*n
;
768 m_NodeNormal
[id_node
] = v
;
777 void GridSmoother::computeFeet()
779 m_IdFoot
.fill(-1, m_Grid
->GetNumberOfPoints());
780 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
781 if (m_Grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
782 vtkIdType N_pts
, *pts
;
783 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
784 m_IdFoot
[pts
[3]] = pts
[0];
785 m_IdFoot
[pts
[4]] = pts
[1];
786 m_IdFoot
[pts
[5]] = pts
[2];
787 m_NodeMarked
[pts
[0]] = false;
788 m_NodeMarked
[pts
[1]] = false;
789 m_NodeMarked
[pts
[2]] = false;
794 void GridSmoother::simpleNodeMovement(int i_nodes
)
796 vtkIdType id_node
= m_Part
.globalNode(i_nodes
);
797 vtkIdType id_foot
= m_IdFoot
[id_node
];
798 vec3_t
x_new(0,0,0), x_node
;
799 m_Grid
->GetPoint(id_node
, x_node
.data());
801 vec3_t
x_surf(0,0,0);
802 if (m_SurfNode
[id_node
]) {
804 for (int i
= 0; i
< m_Part
.n2nLSize(i_nodes
); ++i
) {
805 vtkIdType id_neigh
= m_Part
.n2nLG(i_nodes
,i
);
806 if (m_SurfNode
[id_neigh
]) {
808 m_Grid
->GetPoint(id_neigh
, x_neigh
.data());
821 vec3_t x_foot
, x_node
;
822 m_Grid
->GetPoint(id_foot
, x_foot
.data());
823 //double H = m_Blending*m_AbsoluteHeight + (1.0-m_Blending)*m_RelativeHeight*m_Height[id_foot];
824 double H
= m_Height
[id_foot
];
825 x_new
= x_foot
+ H
*m_NodeNormal
[id_foot
];
827 if (m_SurfNode
[id_node
]) {
830 if (m_Part
.n2nLSize(i_nodes
) == 0) {
833 for (int i
= 0; i
< m_Part
.n2nLSize(i_nodes
); ++i
) {
834 vtkIdType id_neigh
= m_Part
.n2nLG(i_nodes
,i
);
836 m_Grid
->GetPoint(id_neigh
, x_neigh
.data());
839 x_new
*= 1.0/m_Part
.n2nLSize(i_nodes
);
842 vec3_t Dx
= x_new
- x_node
;
843 correctDx(i_nodes
, Dx
);
844 moveNode(i_nodes
, Dx
);
847 void GridSmoother::operate()
856 l2g_t nodes
= m_Part
.getNodes();
857 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
858 if (m_NodeMarked
[nodes
[i_nodes
]]) {
859 simpleNodeMovement(i_nodes
);
864 void GridSmoother::writeDebugFile(QString file_name
)
866 QVector
<vtkIdType
> bcells
;
867 QSet
<int> bcs
= getAllBoundaryCodes(m_Grid
);
868 getSurfaceCells(bcs
, bcells
, m_Grid
);
869 MeshPartition
bpart(m_Grid
);
870 bpart
.setCells(bcells
);
871 file_name
= GuiMainWindow::pointer()->getCwd() + "/" + file_name
+ ".vtk";
872 QFile
file(file_name
);
873 file
.open(QIODevice::WriteOnly
);
874 QTextStream
f(&file
);
875 f
<< "# vtk DataFile Version 2.0\n";
876 f
<< "m_NodeNormal\n";
878 f
<< "DATASET UNSTRUCTURED_GRID\n";
879 f
<< "POINTS " << bpart
.getNumberOfNodes() << " float\n";
880 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
882 vtkIdType id_node
= bpart
.globalNode(i
);
883 m_Grid
->GetPoint(id_node
, x
.data());
884 f
<< x
[0] << " " << x
[1] << " " << x
[2] << "\n";
886 f
<< "CELLS " << bpart
.getNumberOfCells() << " ";
888 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
889 vtkIdType id_cell
= bpart
.globalCell(i
);
890 vtkIdType N_pts
, *pts
;
891 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
895 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
896 vtkIdType id_cell
= bpart
.globalCell(i
);
897 vtkIdType N_pts
, *pts
;
898 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
899 QVector
<int> nds(N_pts
);
901 for (int j
= 0; j
< N_pts
; ++j
) {
902 f
<< " " << bpart
.localNode(pts
[j
]);
907 f
<< "CELL_TYPES " << bpart
.getNumberOfCells() << "\n";
908 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
909 vtkIdType id_cell
= bpart
.globalCell(i
);
910 vtkIdType type_cell
= m_Grid
->GetCellType(id_cell
);
911 f
<< type_cell
<< "\n";
913 f
<< "POINT_DATA " << bpart
.getNumberOfNodes() << "\n";
914 f
<< "VECTORS N float\n";
916 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
917 vtkIdType id_node
= bpart
.globalNode(i
);
918 f
<< m_NodeNormal
[id_node
][0] << " " << m_NodeNormal
[id_node
][1] << " " << m_NodeNormal
[id_node
][2] << "\n";