Developer Documentation
Loading...
Searching...
No Matches
HexahedralMeshTopologyKernel.cc
1/*===========================================================================*\
2 * *
3 * OpenVolumeMesh *
4 * Copyright (C) 2011 by Computer Graphics Group, RWTH Aachen *
5 * www.openvolumemesh.org *
6 * *
7 *---------------------------------------------------------------------------*
8 * This file is part of OpenVolumeMesh. *
9 * *
10 * OpenVolumeMesh is free software: you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License as *
12 * published by the Free Software Foundation, either version 3 of *
13 * the License, or (at your option) any later version with the *
14 * following exceptions: *
15 * *
16 * If other files instantiate templates or use macros *
17 * or inline functions from this file, or you compile this file and *
18 * link it with other files to produce an executable, this file does *
19 * not by itself cause the resulting executable to be covered by the *
20 * GNU Lesser General Public License. This exception does not however *
21 * invalidate any other reasons why the executable file might be *
22 * covered by the GNU Lesser General Public License. *
23 * *
24 * OpenVolumeMesh is distributed in the hope that it will be useful, *
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
27 * GNU Lesser General Public License for more details. *
28 * *
29 * You should have received a copy of the GNU LesserGeneral Public *
30 * License along with OpenVolumeMesh. If not, *
31 * see <http://www.gnu.org/licenses/>. *
32 * *
33\*===========================================================================*/
34
35
36#include <OpenVolumeMesh/Mesh/HexahedralMeshTopologyKernel.hh>
37
38namespace OpenVolumeMesh {
39
40
41FaceHandle HexahedralMeshTopologyKernel::add_face(std::vector<HalfEdgeHandle> _halfedges, bool _topologyCheck) {
42
43 if(_halfedges.size() != 4) {
44#ifndef NDEBUG
45 std::cerr << "HexahedralMeshTopologyKernel::add_face(): Face valence is not four! Returning" << std::endl;
46 std::cerr << "invalid handle." << std::endl;
47#endif
48 return TopologyKernel::InvalidFaceHandle;
49 }
50
51 return TopologyKernel::add_face(std::move(_halfedges), _topologyCheck);
52}
53
54//========================================================================================
55
56
58HexahedralMeshTopologyKernel::add_face(const std::vector<VertexHandle>& _vertices) {
59
60 if(_vertices.size() != 4) {
61#ifndef NDEBUG
62 std::cerr << "HexahedralMeshTopologyKernel::add_face(): Face valence is not four! Returning" << std::endl;
63 std::cerr << "invalid handle." << std::endl;
64#endif
65 return TopologyKernel::InvalidFaceHandle;
66 }
67
68 return TopologyKernel::add_face(_vertices);
69}
70
71//========================================================================================
72
73
75HexahedralMeshTopologyKernel::add_cell(std::vector<HalfFaceHandle> _halffaces, bool _topologyCheck) {
76
77 if(_halffaces.size() != 6) {
78// To make this consistent with add_face
79#ifndef NDEBUG
80 std::cerr << "Cell valence is not six! Aborting." << std::endl;
81#endif
82 return TopologyKernel::InvalidCellHandle;
83 }
84 for(std::vector<HalfFaceHandle>::const_iterator it = _halffaces.begin();
85 it != _halffaces.end(); ++it)
86 {
87 if (valence(it->face_handle()) != 4) {
88#ifndef NDEBUG
89 std::cerr << "Incident face does not have valence four! Aborting." << std::endl;
90#endif
91 return TopologyKernel::InvalidCellHandle;
92 }
93 }
94
95 // Create new halffaces vector
96 std::vector<HalfFaceHandle> ordered_halffaces;
97
98 if(!_topologyCheck) {
99 // Assume right ordering at the user's risk
100 return TopologyKernel::add_cell(std::move(_halffaces), _topologyCheck);
101 }
102 if(check_halfface_ordering(_halffaces)) {
103 // The order is okay :)
104 return TopologyKernel::add_cell(std::move(_halffaces), _topologyCheck);
105 }
106
107#ifndef NDEBUG
108 std::cerr << "The specified half-faces are not in correct order. Trying automatic re-ordering." << std::endl;
109#endif
110
111 // Ordering array (see below for details)
112 const int orderTop[] = {2, 4, 3, 5};
113 //const int orderBot[] = {3, 4, 2, 5};
114
115 ordered_halffaces.resize(6, TopologyKernel::InvalidHalfFaceHandle);
116
117 // Create top side
118 ordered_halffaces[0] = _halffaces[0];
119
120 // Go over all incident halfedges
121 std::vector<HalfEdgeHandle> hes = TopologyKernel::halfface(ordered_halffaces[0]).halfedges();
122 unsigned int idx = 0;
123 for(std::vector<HalfEdgeHandle>::const_iterator he_it = hes.begin();
124 he_it != hes.end(); ++he_it) {
125
126 HalfFaceHandle ahfh = get_adjacent_halfface(ordered_halffaces[0], *he_it, _halffaces);
127 if(ahfh == TopologyKernel::InvalidHalfFaceHandle) {
128#ifndef NDEBUG
129 std::cerr << "The current halfface is invalid!" << std::endl;
130#endif
131 continue;
132 }
133 ordered_halffaces[orderTop[idx]] = ahfh;
134 ++idx;
135 }
136
137 // Now set bottom-halfface
138 HalfFaceHandle cur_hf = ordered_halffaces[0];
139 HalfEdgeHandle cur_he = *(TopologyKernel::halfface(cur_hf).halfedges().begin());
140 cur_hf = get_adjacent_halfface(cur_hf, cur_he, _halffaces);
141 cur_he = TopologyKernel::opposite_halfedge_handle(cur_he);
142 cur_he = TopologyKernel::next_halfedge_in_halfface(cur_he, cur_hf);
143 cur_he = TopologyKernel::next_halfedge_in_halfface(cur_he, cur_hf);
144 cur_hf = get_adjacent_halfface(cur_hf, cur_he, _halffaces);
145
146 if(cur_hf != TopologyKernel::InvalidHalfFaceHandle) {
147 ordered_halffaces[1] = cur_hf;
148 } else {
149#ifndef NDEBUG
150 std::cerr << "The current halfface is invalid!" << std::endl;
151#endif
152 return TopologyKernel::InvalidCellHandle;
153 }
154
155 return TopologyKernel::add_cell(std::move(ordered_halffaces), _topologyCheck);
156}
157
158//========================================================================================
159
160bool HexahedralMeshTopologyKernel::check_halfface_ordering(const std::vector<HalfFaceHandle>& _hfs) const {
161
162 /*
163 * The test works as follows: Test for both the first and second face in the list,
164 * whether the following order holds (clockwise):
165 *
166 * View from above, outside.
167 * ____
168 * | 4 |
169 * ____|____|____
170 * | 5 | 1 | 6 |
171 * |____|____|____|
172 * | 3 |
173 * |____|
174 *
175 * View from below, outside.
176 * ____
177 * | 3 |
178 * ____|____|____
179 * | 5 | 2 | 6 |
180 * |____|____|____|
181 * | 4 |
182 * |____|
183 */
184
185 const int orderTop[] = {2, 4, 3, 5};
186 const int orderBot[] = {3, 4, 2, 5};
187
188 HalfFaceHandle hfhTop = _hfs[0];
189 HalfFaceHandle hfhBot = _hfs[1];
190
191 std::vector<HalfEdgeHandle> halfedgesTop = TopologyKernel::halfface(_hfs[0]).halfedges();
192 std::vector<HalfEdgeHandle> halfedgesBot = TopologyKernel::halfface(_hfs[1]).halfedges();
193
194 int offsetTop = -1;
195 int offsetBot = -1;
196
197 // Traverse halfedges top
198 for(std::vector<HalfEdgeHandle>::const_iterator it = halfedgesTop.begin();
199 it != halfedgesTop.end(); ++it) {
200
201 HalfFaceHandle ahfh = get_adjacent_halfface(hfhTop, *it, _hfs);
202
203 if(offsetTop == -1) {
204 if(ahfh == _hfs[2]) offsetTop = 0;
205 else if(ahfh == _hfs[4]) offsetTop = 1;
206 else if(ahfh == _hfs[3]) offsetTop = 2;
207 else if(ahfh == _hfs[5]) offsetTop = 3;
208 } else {
209 offsetTop = (offsetTop + 1) % 4;
210 if(ahfh != _hfs[orderTop[offsetTop]]) {
211#ifndef NDEBUG
212 std::cerr << "Faces not in right order!" << std::endl;
213#endif
214 return false;
215 }
216 }
217 }
218
219 if(offsetTop == -1) {
220#ifndef NDEBUG
221 std::cerr << "Faces not in right order!" << std::endl;
222#endif
223 return false;
224 }
225
226 // Traverse halfedges bottom
227 for(std::vector<HalfEdgeHandle>::const_iterator it = halfedgesBot.begin();
228 it != halfedgesBot.end(); ++it) {
229
230 HalfFaceHandle ahfh = get_adjacent_halfface(hfhBot, *it, _hfs);
231
232 if(offsetBot == -1) {
233 if(ahfh == _hfs[3]) offsetBot = 0;
234 else if(ahfh == _hfs[4]) offsetBot = 1;
235 else if(ahfh == _hfs[2]) offsetBot = 2;
236 else if(ahfh == _hfs[5]) offsetBot = 3;
237 } else {
238 offsetBot = (offsetBot + 1) % 4;
239 if(ahfh != _hfs[orderBot[offsetBot]]) {
240#ifndef NDEBUG
241 std::cerr << "Faces not in right order!" << std::endl;
242#endif
243 return false;
244 }
245 }
246 }
247
248 if(offsetBot == -1) {
249#ifndef NDEBUG
250 std::cerr << "Faces not in right order!" << std::endl;
251#endif
252 return false;
253 }
254
255 return true;
256}
257
258//========================================================================================
259
260CellHandle
261HexahedralMeshTopologyKernel::add_cell(const std::vector<VertexHandle>& _vertices, bool _topologyCheck) {
262
263 // debug mode checks
264 assert(TopologyKernel::has_full_bottom_up_incidences());
265 assert(_vertices.size() == 8);
266
267 // release mode checks
268 if(!TopologyKernel::has_full_bottom_up_incidences()) {
269 return CellHandle(-1);
270 }
271
272 if(_vertices.size() != 8) {
273 return CellHandle(-1);
274 }
275
276 HalfFaceHandle hf0, hf1, hf2, hf3, hf4, hf5;
277
278 std::vector<VertexHandle> vs;
279
280 // Half-face XF
281 vs.push_back(_vertices[3]);
282 vs.push_back(_vertices[2]);
283 vs.push_back(_vertices[1]);
284 vs.push_back(_vertices[0]);
285 hf0 = TopologyKernel::find_halfface_extensive(vs); vs.clear();
286
287 // Half-face XB
288 vs.push_back(_vertices[7]);
289 vs.push_back(_vertices[6]);
290 vs.push_back(_vertices[5]);
291 vs.push_back(_vertices[4]);
292 hf1 = TopologyKernel::find_halfface_extensive(vs); vs.clear();
293
294 // Half-face YF
295 vs.push_back(_vertices[1]);
296 vs.push_back(_vertices[2]);
297 vs.push_back(_vertices[6]);
298 vs.push_back(_vertices[7]);
299 hf2 = TopologyKernel::find_halfface_extensive(vs); vs.clear();
300
301 // Half-face YB
302 vs.push_back(_vertices[4]);
303 vs.push_back(_vertices[5]);
304 vs.push_back(_vertices[3]);
305 vs.push_back(_vertices[0]);
306 hf3 = TopologyKernel::find_halfface_extensive(vs); vs.clear();
307
308 // Half-face ZF
309 vs.push_back(_vertices[1]);
310 vs.push_back(_vertices[7]);
311 vs.push_back(_vertices[4]);
312 vs.push_back(_vertices[0]);
313 hf4 = TopologyKernel::find_halfface_extensive(vs); vs.clear();
314
315 // Half-face ZB
316 vs.push_back(_vertices[2]);
317 vs.push_back(_vertices[3]);
318 vs.push_back(_vertices[5]);
319 vs.push_back(_vertices[6]);
321
322 if(!hf0.is_valid()) {
323
324 vs.clear();
325 vs.push_back(_vertices[3]); vs.push_back(_vertices[2]);
326 vs.push_back(_vertices[1]); vs.push_back(_vertices[0]);
328 hf0 = halfface_handle(fh, 0);
329 }
330
331 if(!hf1.is_valid()) {
332
333 vs.clear();
334 vs.push_back(_vertices[7]); vs.push_back(_vertices[6]);
335 vs.push_back(_vertices[5]); vs.push_back(_vertices[4]);
337 hf1 = halfface_handle(fh, 0);
338 }
339
340 if(!hf2.is_valid()) {
341
342 vs.clear();
343 vs.push_back(_vertices[1]); vs.push_back(_vertices[2]);
344 vs.push_back(_vertices[6]); vs.push_back(_vertices[7]);
346 hf2 = halfface_handle(fh, 0);
347 }
348
349 if(!hf3.is_valid()) {
350
351 vs.clear();
352 vs.push_back(_vertices[4]); vs.push_back(_vertices[5]);
353 vs.push_back(_vertices[3]); vs.push_back(_vertices[0]);
355 hf3 = halfface_handle(fh, 0);
356 }
357
358 if(!hf4.is_valid()) {
359
360 vs.clear();
361 vs.push_back(_vertices[1]); vs.push_back(_vertices[7]);
362 vs.push_back(_vertices[4]); vs.push_back(_vertices[0]);
364 hf4 = halfface_handle(fh, 0);
365 }
366
367 if(!hf5.is_valid()) {
368
369 vs.clear();
370 vs.push_back(_vertices[2]); vs.push_back(_vertices[3]);
371 vs.push_back(_vertices[5]); vs.push_back(_vertices[6]);
373 hf5 = halfface_handle(fh, 0);
374 }
375
376 assert(hf0.is_valid()); assert(hf1.is_valid()); assert(hf2.is_valid());
377 assert(hf3.is_valid()); assert(hf4.is_valid()); assert(hf5.is_valid());
378
379
380 std::vector<HalfFaceHandle> hfs;
381 hfs.push_back(hf0); hfs.push_back(hf1); hfs.push_back(hf2);
382 hfs.push_back(hf3); hfs.push_back(hf4); hfs.push_back(hf5);
383
384 if (_topologyCheck) {
385 /*
386 * Test if all halffaces are connected and form a two-manifold
387 * => Cell is closed
388 *
389 * This test is simple: The number of involved half-edges has to be
390 * exactly twice the number of involved edges.
391 */
392
393 std::set<HalfEdgeHandle> incidentHalfedges;
394 std::set<EdgeHandle> incidentEdges;
395
396 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
397 end = hfs.end(); it != end; ++it) {
398
399 OpenVolumeMeshFace hface = halfface(*it);
400 for(std::vector<HalfEdgeHandle>::const_iterator he_it = hface.halfedges().begin(),
401 he_end = hface.halfedges().end(); he_it != he_end; ++he_it) {
402 incidentHalfedges.insert(*he_it);
403 incidentEdges.insert(edge_handle(*he_it));
404 }
405 }
406
407 if(incidentHalfedges.size() != (incidentEdges.size() * 2u)) {
408#ifndef NDEBUG
409 std::cerr << "The specified halffaces are not connected!" << std::endl;
410#endif
411 return InvalidCellHandle;
412 }
413 // The halffaces are now guaranteed to form a two-manifold
414
415 if(has_face_bottom_up_incidences()) {
416
417 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
418 end = hfs.end(); it != end; ++it) {
419 if(incident_cell(*it) != InvalidCellHandle) {
420#ifndef NDEBUG
421 std::cerr << "Warning: One of the specified half-faces is already incident to another cell!" << std::endl;
422#endif
423 return InvalidCellHandle;
424 }
425 }
426
427 }
428
429 }
430
431 return TopologyKernel::add_cell(hfs, false);
432}
433
434//========================================================================================
435
437HexahedralMeshTopologyKernel::get_adjacent_halfface(HalfFaceHandle _hfh, HalfEdgeHandle _heh,
438 const std::vector<HalfFaceHandle>& _halffaces) const {
439
440 // Search for halfface that is incident to the opposite
441 // halfedge of _heh
442 HalfEdgeHandle o_he = TopologyKernel::opposite_halfedge_handle(_heh);
443
444 for(std::vector<HalfFaceHandle>::const_iterator it = _halffaces.begin();
445 it != _halffaces.end(); ++it) {
446 if(*it == _hfh) continue;
447 std::vector<HalfEdgeHandle> halfedges = TopologyKernel::halfface(*it).halfedges();
448 for(std::vector<HalfEdgeHandle>::const_iterator h_it = halfedges.begin();
449 h_it != halfedges.end(); ++h_it) {
450 if(*h_it == o_he) return *it;
451 }
452 }
453
454 return TopologyKernel::InvalidHalfFaceHandle;
455}
456
457} // Namespace OpenVolumeMesh
CellHandle add_cell(std::vector< HalfFaceHandle > _halffaces, bool _topologyCheck=false) override
Overridden function.
FaceHandle add_face(std::vector< HalfEdgeHandle > _halfedges, bool _topologyCheck=false) override
Add face via incident edges.
size_t valence(VertexHandle _vh) const
Get valence of vertex (number of incident edges)
CellHandle incident_cell(HalfFaceHandle _halfFaceHandle) const
Get cell that is incident to the given halfface.
HalfFaceHandle find_halfface_extensive(const std::vector< VertexHandle > &_vs) const
HalfEdgeHandle next_halfedge_in_halfface(HalfEdgeHandle _heh, HalfFaceHandle _hfh) const
Get next halfedge within a halfface.
static EdgeHandle edge_handle(HalfEdgeHandle _h)
Handle conversion.
virtual FaceHandle add_face(std::vector< HalfEdgeHandle > _halfedges, bool _topologyCheck=false)
Add face via incident edges.
static HalfFaceHandle halfface_handle(FaceHandle _h, const unsigned char _subIdx)
Conversion function.
virtual CellHandle add_cell(std::vector< HalfFaceHandle > _halffaces, bool _topologyCheck=false)
Add cell via incident halffaces.
Face halfface(HalfFaceHandle _halfFaceHandle) const
Get face that corresponds to halfface with handle _halfFaceHandle.