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 "facefinder.h"
24 FaceFinder::FaceFinder()
28 m_CollectedPointsIncrement
= 10000;
29 m_CollectedPoints
.resize(10000);
30 getSet("surface meshing", "use improved face search", false, m_UseImprovedFaceSearch
);
33 void FaceFinder::setGrid(vtkUnstructuredGrid
*grid
)
36 m_Triangles
.resize(m_Grid
->GetNumberOfCells());
37 m_Centres
.resize(m_Grid
->GetNumberOfCells());
38 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
39 if (m_Grid
->GetCellType(id_cell
) != VTK_TRIANGLE
) {
42 m_Triangles
[id_cell
] = Triangle(m_Grid
, id_cell
);
43 m_Centres
[id_cell
] = cellCentre(m_Grid
, id_cell
);
47 m_Grid
->GetBounds(bounds
);
48 vec3_t
x1(bounds
[0], bounds
[2], bounds
[4]);
49 vec3_t
x2(bounds
[1], bounds
[3], bounds
[5]);
50 vec3_t xc
= 0.5*(x1
+ x2
);
52 double dx_max
= max(Dx
[0], max(Dx
[1], Dx
[2]));
53 Dx
= vec3_t(dx_max
, dx_max
, dx_max
);
56 m_Octree
.setBounds(x1
, x2
);
57 if (m_UseImprovedFaceSearch
) {
58 m_MinSize
= 0.005*Dx
[0];
60 m_MinSize
= 0.0001*Dx
[0];
64 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
65 m_Faces
[0].append(id_cell
);
67 if (m_UseImprovedFaceSearch
) {
68 m_CritLengthOctreeCell
.fill(EG_LARGE_REAL
, 1);
69 foreach (vtkIdType id_cell
, m_Faces
[0]) {
70 m_CritLengthOctreeCell
[0] = min(m_CritLengthOctreeCell
[0], calcCritLength(id_cell
));
72 calcCritLengthForAllNodes();
74 m_CritLengthOctreeCell
.fill(0, 1);
75 foreach (vtkIdType id_cell
, m_Faces
[0]) {
76 m_CritLengthOctreeCell
[0] = max(m_CritLengthOctreeCell
[0], calcCritLength(id_cell
));
85 int max_num_faces
= 0;
88 for (int i_cell
= 0; i_cell
< m_Octree
.getNumCells(); ++i_cell
) {
89 if (!m_Octree
.hasChildren(i_cell
)) {
91 while (m_Faces
[cell
].size() == 0) {
92 cell
= m_Octree
.getParent(cell
);
97 max_num_faces
= max(m_Faces
[cell
].size(), max_num_faces
);
98 ave_num_faces
+= double(m_Faces
[cell
].size());
103 cout
<< "refining octree for FaceFinder ..." << endl
;
104 cout
<< " minimal cell size: " << m_MinSize
<< endl
;
105 cout
<< " maximal number of faces: " << max_num_faces
<< endl
;
106 cout
<< " average number of faces: " << ave_num_faces
/num_buckets
<< endl
;
107 cout
<< " number of buckets: " << num_buckets
<< endl
;
108 //cout << " largest critical length: " << m_CritLength[0] << endl;
110 //EG_VTKSP(vtkUnstructuredGrid, otg);
111 //m_Octree.toVtkGrid(otg);
112 //writeGrid(otg, "facefinder");
115 double FaceFinder::calcCritLength(vtkIdType id_cell
)
117 if (m_UseImprovedFaceSearch
) {
118 return max(m_MinSize
, 10*m_Triangles
[id_cell
].smallestLength());
121 vtkIdType N_pts
, *pts
;
122 m_Grid
->GetCellPoints(id_cell
, N_pts
, pts
);
124 for (int i
= 0; i
< N_pts
; ++i
) {
125 m_Grid
->GetPoint(pts
[i
], x
[i
].data());
129 for (int i
= 0; i
< N_pts
; ++i
) {
130 L
= max(L
, (x
[i
]-x
[i
+1]).abs());
135 void FaceFinder::calcCritLengthForAllNodes()
137 m_CritLengthNode
.fill(EG_LARGE_REAL
, m_Grid
->GetNumberOfPoints());
138 for (vtkIdType id_face
= 0; id_face
< m_Grid
->GetNumberOfCells(); ++id_face
) {
139 double l_crit
= calcCritLength(id_face
);
140 vtkIdType num_pts
, *pts
;
141 m_Grid
->GetCellPoints(id_face
, num_pts
, pts
);
142 for (int i
= 0; i
< num_pts
; ++i
) {
143 m_CritLengthNode
[pts
[i
]] = min(m_CritLengthNode
[pts
[i
]], l_crit
);
148 void FaceFinder::getPointsOfFace(vtkIdType id_face
)
150 m_NumCollectedPoints
= 3;
151 Triangle T
= m_Triangles
[id_face
];
152 m_CollectedPoints
[0] = T
.a();
153 m_CollectedPoints
[1] = T
.b();
154 m_CollectedPoints
[2] = T
.c();
155 QVector
<vec3_t
> x_tri(4);
156 QVector
<vtkIdType
> id_tri(4);
165 for (int i
= 0; i
< 3; ++i
) {
166 vec3_t x1
= x_tri
[i
];
167 vec3_t x2
= x_tri
[i
+1];
168 double l
= (x2
- x1
).abs();
169 double h
= 0.5*(m_CritLengthNode
[id_tri
[i
]] + m_CritLengthNode
[id_tri
[i
+1]]);
170 int N
= int(l
/h
) + 1;
171 vec3_t dx
= (1.0/N
)*(x2
- x1
);
173 for (int j
= 1; j
< N
; ++j
) {
174 if (m_NumCollectedPoints
>= m_CollectedPoints
.size()) {
175 m_CollectedPoints
.resize(m_CollectedPoints
.size() + m_CollectedPointsIncrement
);
177 m_CollectedPoints
[m_NumCollectedPoints
] = x
;
178 ++m_NumCollectedPoints
;
184 int FaceFinder::refine()
186 int N
= m_Octree
.getNumCells();
187 m_Octree
.setSmoothTransitionOff();
189 m_Octree
.resetRefineMarks();
190 for (int cell
= 0; cell
< m_Octree
.getNumCells(); ++cell
) {
191 double dx
= m_Octree
.getDx(cell
);
192 if (!m_Octree
.hasChildren(cell
) && m_Faces
[cell
].size() > m_MaxFaces
&& dx
> 2*m_MinSize
&& dx
> 2*m_CritLengthOctreeCell
[cell
]) {
193 m_Octree
.markToRefine(cell
);
198 for (int cell
= 0; cell
< m_Octree
.getNumCells(); ++cell
) {
199 if (m_Octree
.markedForRefine(cell
)) {
204 m_Octree
.refineAll();
205 if (m_Octree
.getNumCells() != N
+ N_new
) {
208 m_Faces
.insert(N
, N_new
, QList
<vtkIdType
>());
209 if (m_UseImprovedFaceSearch
) {
210 m_CritLengthOctreeCell
.insert(N
, N_new
, 1e99
);
212 m_CritLengthOctreeCell
.insert(N
, N_new
, 0);
214 int N_min
= m_Grid
->GetNumberOfCells();
217 for (int cell
= N
; cell
< m_Octree
.getNumCells(); ++cell
) {
218 m_Timer
<< " " << m_Octree
.getNumCells() << " octree cells" << Timer::endl
;
219 if (m_Octree
.getNumCells() != N
+ N_new
) {
222 int parent
= m_Octree
.getParent(cell
);
226 foreach (vtkIdType id_cell
, m_Faces
[parent
]) {
227 if (m_UseImprovedFaceSearch
) {
228 getPointsOfFace(id_cell
);
229 for (int i
= 0; i
< m_NumCollectedPoints
; ++i
) {
230 if (m_Octree
.isInsideCell(cell
, m_CollectedPoints
[i
], 2.0)) {
231 m_Faces
[cell
].append(id_cell
);
232 m_CritLengthOctreeCell
[cell
] = min(m_CritLengthOctreeCell
[cell
], calcCritLength(id_cell
));
237 for (int node
= 0; node
< 8; ++node
) {
238 vec3_t x
= m_Octree
.getNodePosition(cell
, node
);
240 d
= (x
- m_Centres
[id_cell
]).abs();
241 if (d
< m_Octree
.getDx(cell
)) {
242 m_Faces
[cell
].append(id_cell
);
243 m_CritLengthOctreeCell
[cell
] = max(m_CritLengthOctreeCell
[cell
], calcCritLength(id_cell
));
249 N_min
= min(N_min
, m_Faces
[cell
].size());
250 N_max
= max(N_max
, m_Faces
[cell
].size());
251 N_ave
+= m_Faces
[cell
].size();
255 for (int cell
= 0; cell
< m_Octree
.getNumCells(); ++cell
) {
256 if (!m_Octree
.hasChildren(cell
)) {
258 N_faces
+= m_Faces
[cell
].size();
267 void FaceFinder::getCloseFaces(vec3_t x
, QVector
<vtkIdType
> &faces
)
269 if (m_Octree
.isInsideBounds(x
)) {
270 int cell
= m_Octree
.findCell(x
);
274 if (m_Octree
.hasChildren(cell
)) {
277 while (m_Faces
[cell
].size() == 0 && m_Octree
.getParent(cell
) >= 0) {
278 cell
= m_Octree
.getParent(cell
);
280 faces
.resize(m_Faces
[cell
].size());
281 qCopy(m_Faces
[cell
].begin(), m_Faces
[cell
].end(), faces
.begin());
287 vtkIdType
FaceFinder::getClosestFace(vec3_t x
, double &L_min
)
289 QVector
<vtkIdType
> faces
;
290 getCloseFaces(x
, faces
);
291 vtkIdType id_close
= -1;
292 foreach (vtkIdType id_face
, faces
) {
296 m_Triangles
[id_face
].snapOntoTriangle(x
, xi
, ri
, L
, side
, true);