Developer Documentation
TetrahedralMeshTopologyKernel.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#include <OpenVolumeMesh/Mesh/TetrahedralMeshTopologyKernel.hh>
36
37#include <iostream>
38
39namespace OpenVolumeMesh {
40
41FaceHandle TetrahedralMeshTopologyKernel::add_face(std::vector<HalfEdgeHandle> _halfedges, bool _topologyCheck) {
42
43 if(_halfedges.size() != 3) {
44#ifndef NDEBUG
45 std::cerr << "TetrahedralMeshTopologyKernel::add_face(): Face valence is not three! 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
58TetrahedralMeshTopologyKernel::add_face(const std::vector<VertexHandle>& _vertices) {
59
60 if(_vertices.size() != 3) {
61#ifndef NDEBUG
62 std::cerr << "TetrahedralMeshTopologyKernel::add_face(): Face valence is not three! 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
75TetrahedralMeshTopologyKernel::add_cell(std::vector<HalfFaceHandle> _halffaces, bool _topologyCheck) {
76
77 if(_halffaces.size() != 4) {
78// To make this consistent with add_face
79#ifndef NDEBUG
80 std::cerr << "Cell valence is not four! Aborting." << std::endl;
81#endif
82 return TopologyKernel::InvalidCellHandle;
83 }
84 for(const auto &hfh: _halffaces) {
85 auto n_halfedges = TopologyKernel::valence(TopologyKernel::face_handle(hfh));
86 if (n_halfedges != 3) {
87#ifndef NDEBUG
88 std::cerr << "TetrahedralMeshTopologyKernel::add_cell(): Incident face " << hfh.idx() << " does not have valence three: " << n_halfedges << "; not adding cell." << std::endl;
89#endif
90 return TopologyKernel::InvalidCellHandle;
91 }
92 }
93
94 return TopologyKernel::add_cell(std::move(_halffaces), _topologyCheck);
95}
96
97
98HalfEdgeHandle TetrahedralMeshTopologyKernel::add_halfedge(VertexHandle _fromVertex, VertexHandle _toVertex)
99{
100 HalfEdgeHandle he = find_halfedge(_fromVertex, _toVertex);
101 if (he != InvalidHalfEdgeHandle)
102 return he;
103 else
104 return halfedge_handle(add_edge(_fromVertex, _toVertex), 0);
105}
106
107HalfFaceHandle TetrahedralMeshTopologyKernel::add_halfface(const std::vector<HalfEdgeHandle>& _halfedges, bool _topologyCheck)
108{
109 HalfFaceHandle hf = find_halfface(_halfedges);
110 if (hf != InvalidHalfFaceHandle)
111 return hf;
112 else
113 return halfface_handle(add_face(_halfedges, _topologyCheck), 0);
114}
115
116HalfFaceHandle TetrahedralMeshTopologyKernel::add_halfface(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, bool _topologyCheck)
117{
118 std::vector<HalfEdgeHandle> halfedges;
119 halfedges.push_back(add_halfedge(_vh0, _vh1));
120 halfedges.push_back(add_halfedge(_vh1, _vh2));
121 halfedges.push_back(add_halfedge(_vh2, _vh0));
122 return add_halfface(halfedges, _topologyCheck);
123}
124
125/*void TetrahedralMeshTopologyKernel::replaceHalfFace(CellHandle ch, HalfFaceHandle hf_del, HalfFaceHandle hf_ins)
126{
127 Cell& c = cells_[ch.idx()];
128 std::vector<HalfFaceHandle> hfs;
129 for (unsigned int i = 0; i < c.halffaces().size(); ++i)
130 if (c.halffaces()[i] != hf_del)
131 hfs.push_back(c.halffaces()[i]);
132 else
133 hfs.push_back(hf_ins);
134 c.set_halffaces(hfs);
135}
136
137void TetrahedralMeshTopologyKernel::replaceHalfEdge(HalfFaceHandle hfh, HalfEdgeHandle he_del, HalfEdgeHandle he_ins)
138{
139 FaceHandle fh = face_handle(hfh);
140 unsigned char oppF = hfh.idx() - halfface_handle(fh, 0);
141 if (oppF == 1)
142 {
143 he_del = opposite_halfedge_handle(he_del);
144 he_ins = opposite_halfedge_handle(he_ins);
145 }
146 Face& f = faces_[fh.idx()];
147 std::vector<HalfEdgeHandle> hes;
148 for (unsigned int i = 0; i < f.halfedges().size(); ++i)
149 if (f.halfedges()[i] != he_del)
150 hes.push_back(f.halfedges()[i]);
151 else
152 hes.push_back(he_ins);
153 f.set_halfedges(hes);
154
155}*/
156
157/*
158void TetrahedralMeshTopologyKernel::collapse_edge(HalfEdgeHandle _heh)
159{
160
161 std::vector<bool> deleteTagFaces(faces_.size(), false);
162 std::vector<bool> deleteTagEdges(edges_.size(), false);
163 std::vector<bool> deleteTagCells(cells_.size(), false);
164
165 for (HalfEdgeHalfFaceIter hehf_it = hehf_iter(_heh); hehf_it.valid(); ++hehf_it)
166 {
167 CellHandle ch = incident_cell(*hehf_it);
168 if (ch.is_valid())
169 {
170 HalfFaceHandle hf134 = *hehf_it;
171 HalfFaceHandle hf143 = opposite_halfface_handle(hf143);
172 HalfEdgeHandle he13 = prev_halfedge_in_halfface(_heh, hf134);
173 HalfEdgeHandle he41 = next_halfedge_in_halfface(_heh, hf134);
174 HalfFaceHandle hf123 = adjacent_halfface_in_cell(hf134, he13);
175 HalfFaceHandle hf142 = adjacent_halfface_in_cell(hf134, he41);
176 HalfFaceHandle hf132 = opposite_halfface_handle(hf123);
177 CellHandle ch0123 = incident_cell(hf132);
178 HalfEdgeHandle he32 = next_halfedge_in_halfface(he13, hf132);
179 HalfEdgeHandle he23 = opposite_halfedge_handle(he32);
180 HalfEdgeHandle he14 = opposite_halfedge_handle(he41);
181 HalfEdgeHandle he31 = opposite_halfedge_handle(he13);
182 HalfEdgeHandle he42 = next_halfedge_in_halfface(he14, hf142);
183 HalfEdgeHandle he24 = opposite_halfedge_handle(he42);
184 HalfFaceHandle hf243 = adjacent_halfface_in_cell(hf134, he41);
185 HalfFaceHandle hf234 = opposite_halfface_handle(hf234);
186 HalfEdgeHandle he12 = next_halfedge_in_halfface(he42, hf142);
187 HalfEdgeHandle he21 = opposite_halfedge_handle(he12);
188
189 if (ch0123.is_valid())
190 {
191 HalfFaceHandle hf031 = adjacent_halfface_in_cell(hf132, he13);
192 HalfFaceHandle hf023 = adjacent_halfface_in_cell(hf132, he32);
193
194 replaceHalfEdge(hf031, he31, he41);
195 replaceHalfEdge(hf023, he23, he24);
196 replaceHalfFace(ch0123, hf132, hf142);
197 }
198
199 //copyHalfFaceAndHalfEdgeProperties(hf132, 142);
200
201 incident_cell_per_hf_[hf142.idx()] = ch0123;
202
203
204 deleteTagCells[ch.idx()] = true;
205 deleteTagFaces[face_handle(hf132).idx()] = true;
206 deleteTagFaces[face_handle(*hehf_it).idx()] = true;
207 deleteTagEdges[edge_handle(he13).idx()] = true;
208 deleteTagEdges[edge_handle(he32).idx()] = true;
209
210 std::set<HalfFaceHandle> excludeFaces;
211 excludeFaces.insert(hf134);
212 excludeFaces.insert(hf143);
213 excludeFaces.insert(hf123);
214 excludeFaces.insert(hf132);
215 excludeFaces.insert(hf243);
216 excludeFaces.insert(hf234);
217
218 std::vector<std::pair<HalfEdgeHandle, HalfEdgeHandle> > joinpartners;
219 joinpartners.push_back(std::make_pair(he41, he31));
220 joinpartners.push_back(std::make_pair(he14, he13));
221 joinpartners.push_back(std::make_pair(he42, he32));
222 joinpartners.push_back(std::make_pair(he24, he23));
223
224 for (unsigned int i = 0; i < joinpartners.size(); ++i)
225 {
226 HalfEdgeHandle target = joinpartners[i].first;
227 HalfEdgeHandle source = joinpartners[i].second;
228 std::vector<HalfFaceHandle> incidentHfs;
229 for (unsigned int j = 0; j < incident_hfs_per_he_[target.idx()].size(); ++j)
230 {
231 HalfFaceHandle cur_hf = incident_hfs_per_he_[target.idx()][j];
232 if ((excludeFaces.find(cur_hf) == excludeFaces.end()) && !deleteTagFaces[face_handle(cur_hf).idx()])
233 incidentHfs.push_back(cur_hf);
234 }
235 for (unsigned int i = 0; i < incident_hfs_per_he_[source.idx()].size(); ++i)
236 {
237 HalfFaceHandle cur_hf = incident_hfs_per_he_[source.idx()][i];
238 if ((excludeFaces.find(cur_hf) == excludeFaces.end()) && !deleteTagFaces[face_handle(cur_hf).idx()])
239 incidentHfs.push_back(cur_hf);
240 }
241
242 std::swap(incident_hfs_per_he_[target], incidentHfs);
243 }
244
245 std::vector<HalfFaceHandle>& vec = incident_hfs_per_he_[he21];
246 vec.erase(std::remove(vec.begin(), vec.end(), hf132), vec.end());
247 std::vector<HalfFaceHandle>& vec2 = incident_hfs_per_he_[he12];
248 vec2.erase(std::remove(vec2.begin(), vec2.end(), hf123), vec2.end());
249
250 }
251 else
252 {
253 deleteTagFaces[face_handle(*hehf_it).idx()] = true;
254 }
255 }
256
257
258 VertexHandle from_vh = halfedge(_heh).from_vertex();
259 VertexHandle to_vh = halfedge(_heh).to_vertex();
260 for (VertexOHalfEdgeIter voh_it = voh_iter(from_vh); voh_it.valid(); ++voh_it )
261 {
262 Edge he = halfedge(*voh_it);
263 if (he.to_vertex() == to_vh)
264 {
265 std::vector<HalfEdgeHandle>& vec = outgoing_hes_per_vertex_[to_vh];
266 vec.erase(std::remove(vec.begin(), vec.end(), opposite_halfedge_handle(*voh_it)), vec.end());
267 }
268 EdgeHandle eh = edge_handle(*voh_it);
269 if (!deleteTagEdges[eh.idx()])
270 {
271 std::vector<HalfEdgeHandle>& vec = outgoing_hes_per_vertex_[to_vh];
272 vec.push_back(opposite_halfedge_handle(*voh_it));
273
274 Edge& e = edges_[eh.idx()];
275 if (e.from_vertex() == from_vh)
276 e.set_from_vertex(to_vh);
277 if (e.to_vertex() == from_vh)
278 e.set_to_vertex(to_vh);
279
280 }
281 }
282
283 outgoing_hes_per_vertex_[from_vh].clear();
284
285 deleteTagEdges[edge_handle(_heh).idx()] = true;
286
287 delete_multiple_cells(deleteTagCells);
288 delete_multiple_faces(deleteTagFaces);
289 delete_multiple_edges(deleteTagEdges);
290 delete_vertex(from_vh);
291}
292*/
293
294
295//void TetrahedralMeshTopologyKernel::swapCellProperties(CellHandle source, CellHandle destination)
296//{
297// swapPropertyElements(cell_props_begin(), cell_props_end(), source, destination);
298//}
299
300//void TetrahedralMeshTopologyKernel::swapHalfFaceProperties(HalfFaceHandle source, HalfFaceHandle destination)
301//{
302// swapPropertyElements(halfface_props_begin(), halfface_props_end(), source, destination);
303//}
304
305//void TetrahedralMeshTopologyKernel::swapHalfEdgeProperties(HalfEdgeHandle source, HalfEdgeHandle destination)
306//{
307// swapPropertyElements(halfedge_props_begin(), halfedge_props_end(), source, destination);
308//}
309
310// cppcheck-suppress unusedFunction ; public interface
311VertexHandle TetrahedralMeshTopologyKernel::collapse_edge(HalfEdgeHandle _heh)
312{
313 bool deferred_deletion_tmp = deferred_deletion_enabled();
314
315 if (!deferred_deletion_tmp)
316 enable_deferred_deletion(true);
317
318 VertexHandle from_vh = halfedge(_heh).from_vertex();
319 VertexHandle to_vh = halfedge(_heh).to_vertex();
320
321
322 // find cells that will collapse, i.e. are incident to the collapsing halfedge
323 std::set<CellHandle> collapsingCells;
324 for (HalfEdgeHalfFaceIter hehf_it = hehf_iter(_heh); hehf_it.valid(); ++hehf_it)
325 {
326 HalfFaceHandle hfh = *hehf_it;
327 CellHandle ch = incident_cell(hfh);
328 if (ch.is_valid())
329 collapsingCells.insert(ch);
330 }
331
332 std::vector<CellHandle> incidentCells;
333 for (VertexCellIter vc_it = vc_iter(from_vh); vc_it.valid(); ++vc_it)
334 incidentCells.push_back(*vc_it);
335
336 std::vector<std::pair<CellHandle, std::vector<HalfFaceHandle>>> new_cells;
337
338 for (const CellHandle &ch: incidentCells)
339 {
340 if (collapsingCells.find(ch) != collapsingCells.end())
341 continue;
342
343 Cell c = cell(ch);
344
345 std::vector<HalfFaceHandle> newHalffaces;
346 newHalffaces.reserve(4);
347
348 for (unsigned int hf_idx = 0; hf_idx < 4; ++hf_idx)
349 {
350 Face hf = halfface(c.halffaces()[hf_idx]);
351 std::vector<HalfEdgeHandle> newHalfedges;
352
353 for (unsigned int j = 0; j < 3; ++j)
354 {
355 Edge e = halfedge(hf.halfedges()[j]);
356 VertexHandle newStart = (e.from_vertex() == from_vh) ? to_vh: e.from_vertex();
357 VertexHandle newEnd = (e.to_vertex() == from_vh) ? to_vh : e.to_vertex();
358
359 HalfEdgeHandle heh = add_halfedge(newStart, newEnd);
360 newHalfedges.push_back(heh);
361 swap_property_elements(hf.halfedges()[j], heh);
362 }
363
364 HalfFaceHandle hfh = add_halfface(newHalfedges);
365 newHalffaces.push_back(hfh);
366 swap_property_elements(c.halffaces()[hf_idx], hfh);
367 }
368
369 delete_cell(ch);
370 new_cells.emplace_back(ch, newHalffaces);
371
372 }
373 VertexHandle survivingVertex = to_vh;
374
375 if (!deferred_deletion_tmp)
376 {
377 if (fast_deletion_enabled())
378 {
379 // from_vh is swapped with last vertex and then deleted
380 if (to_vh.idx() == (int)n_vertices() - 1)
381 survivingVertex = from_vh;
382 }
383 else
384 {
385 // from_vh is deleted and every vertex id larger than from_vh is reduced by one
386 if (from_vh.idx() < to_vh.idx())
387 survivingVertex = VertexHandle(to_vh.idx() - 1);
388 }
389 }
390
391 delete_vertex(from_vh);
392
393 for (const auto &n: new_cells) {
394 CellHandle newCell = add_cell(std::move(n.second));
395 swap_property_elements(n.first, newCell);
396 }
397
398
399 enable_deferred_deletion(deferred_deletion_tmp);
400
401 return survivingVertex;
402
403}
404
405// cppcheck-suppress unusedFunction ; public interface
406void TetrahedralMeshTopologyKernel::split_edge(HalfEdgeHandle _heh, VertexHandle _vh)
407{
408 bool deferred_deletion_tmp = deferred_deletion_enabled();
409
410 if (!deferred_deletion_tmp)
411 enable_deferred_deletion(true);
412
413 std::vector<HalfFaceHandle> incident_halffaces_with_cells;
414 for (HalfEdgeHalfFaceIter hehf_it = hehf_iter(_heh); hehf_it.valid(); ++hehf_it)
415 {
416 CellHandle ch = incident_cell(*hehf_it);
417 if (ch.is_valid())
418 incident_halffaces_with_cells.push_back(*hehf_it);
419 }
420
421 std::vector<std::pair<CellHandle, std::array<VertexHandle, 4>>> new_cells;
422
423 for (auto hfh : incident_halffaces_with_cells)
424 {
425 CellHandle ch = incident_cell(hfh);
426
427 std::vector<VertexHandle> vertices = get_cell_vertices(hfh, _heh);
428
429 delete_cell(ch);
430
431 new_cells.emplace_back(ch, std::array<VertexHandle, 4>{vertices[0], _vh, vertices[2], vertices[3]});
432 new_cells.emplace_back(ch, std::array<VertexHandle, 4>{_vh, vertices[1], vertices[2], vertices[3]});
433 }
434
436
437 for (const auto &n: new_cells) {
438 const auto &vhs = n.second;
439 CellHandle newCell = add_cell(vhs[0], vhs[1], vhs[2], vhs[3]);
440 copy_property_elements(n.first, newCell);
441 }
442
443
444 enable_deferred_deletion(deferred_deletion_tmp);
445
446}
447
448// cppcheck-suppress unusedFunction ; public interface
449void TetrahedralMeshTopologyKernel::split_face(FaceHandle _fh, VertexHandle _vh)
450{
451 bool deferred_deletion_tmp = deferred_deletion_enabled();
452
453 if (!deferred_deletion_tmp)
454 enable_deferred_deletion(true);
455
456 std::vector<std::pair<CellHandle, std::array<VertexHandle, 4>>> new_cells;
457
458 for (char i = 0; i < 2; ++i)
459 {
460 HalfFaceHandle hfh = halfface_handle(_fh, i);
461 CellHandle ch = incident_cell(hfh);
462 if (ch.is_valid())
463 {
464 std::vector<VertexHandle> vertices = get_cell_vertices(hfh);
465
466 delete_cell(ch);
467 new_cells.emplace_back(ch, std::array<VertexHandle, 4>{vertices[0], vertices[1], _vh, vertices[3]});
468 new_cells.emplace_back(ch, std::array<VertexHandle, 4>{vertices[0], _vh, vertices[2], vertices[3]});
469 new_cells.emplace_back(ch, std::array<VertexHandle, 4>{_vh, vertices[1], vertices[2], vertices[3]});
470 }
471 }
472
473 delete_face(_fh);
474
475 for (const auto &n: new_cells) {
476 const auto &vhs = n.second;
477 CellHandle newCell = add_cell(vhs[0], vhs[1], vhs[2], vhs[3]);
478 copy_property_elements(n.first, newCell);
479 }
480
481 enable_deferred_deletion(deferred_deletion_tmp);
482
483}
484
485
486std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(CellHandle ch) const
487{
488 return get_cell_vertices(cell(ch).halffaces().front());
489}
490
491std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(CellHandle ch, VertexHandle vh) const
492{
493 HalfFaceHandle hfh = cell(ch).halffaces()[0];
494 Face f = halfface(hfh);
495 HalfEdgeHandle heh;
496 for (unsigned int i = 0; i < 3; ++i)
497 {
498 Edge e = halfedge(f.halfedges()[i]);
499 if (e.from_vertex() == vh)
500 {
501 heh = f.halfedges()[i];
502 break;
503 }
504 }
505 if (!heh.is_valid())
506 {
507 hfh = adjacent_halfface_in_cell(hfh, f.halfedges()[0]);
508 heh = prev_halfedge_in_halfface(opposite_halfedge_handle(f.halfedges()[0]), hfh);
509 }
510
511 return get_cell_vertices(hfh,heh);
512
513}
514
515std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(HalfFaceHandle hfh) const
516{
517 return get_cell_vertices(hfh, halfface(hfh).halfedges().front());
518}
519
520std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(HalfFaceHandle hfh, HalfEdgeHandle heh) const
521{
522 std::vector<VertexHandle> vertices;
523
524 // add vertices of halfface
525 for (unsigned int i = 0; i < 3; ++i)
526 {
527 Edge e = halfedge(heh);
528 vertices.push_back(e.from_vertex());
529 heh = next_halfedge_in_halfface(heh, hfh);
530 }
531
532 Cell c = cell(incident_cell(hfh));
533 HalfFaceHandle otherHfh = c.halffaces()[0];
534 if (otherHfh == hfh)
535 otherHfh = c.halffaces()[1];
536
537 Face otherF = halfface(otherHfh);
538
539 for (unsigned int i = 0; i < otherF.halfedges().size(); ++i)
540 {
541 HalfEdgeHandle he = otherF.halfedges()[i];
542 Edge e = halfedge(he);
543 if (std::find(vertices.begin(), vertices.end(), e.to_vertex()) == vertices.end())
544 {
545 vertices.push_back(e.to_vertex());
546 return vertices;
547 }
548 }
549
550 return vertices;
551}
552
553VertexHandle TetrahedralMeshTopologyKernel::halfface_opposite_vertex(HalfFaceHandle hfh) const
554{
555 if (is_boundary(hfh)) {
556 return InvalidVertexHandle;
557 }
558
559 const std::vector<VertexHandle> base = get_halfface_vertices(hfh);
560 for (CellVertexIter it = cv_iter(incident_cell(hfh)); it.valid(); ++it) {
561 const VertexHandle vh = *it;
562 if (vh != base[0] && vh != base[1] && vh != base[2]) {
563 return vh;
564 }
565 }
566
567 return InvalidVertexHandle;
568}
569
570
571//========================================================================================
572
573CellHandle
574TetrahedralMeshTopologyKernel::add_cell(const std::vector<VertexHandle>& _vertices, bool _topologyCheck)
575{
576 if(_vertices.size() != 4) {
577 return CellHandle(-1);
578 }
579
580 // debug mode checks
581 assert(TopologyKernel::has_full_bottom_up_incidences());
582
583 // release mode checks
584 if(!TopologyKernel::has_full_bottom_up_incidences()) {
585 return CellHandle(-1);
586 }
587
588
589 HalfFaceHandle hf0, hf1, hf2, hf3;
590
591 std::vector<VertexHandle> vs;
592
593 vs.push_back(_vertices[0]);
594 vs.push_back(_vertices[1]);
595 vs.push_back(_vertices[2]);
597 if(!hf0.is_valid()) {
598 FaceHandle fh = TopologyKernel::add_face(vs);
599 hf0 = halfface_handle(fh, 0);
600 }
601 vs.clear();
602
603 vs.push_back(_vertices[0]);
604 vs.push_back(_vertices[2]);
605 vs.push_back(_vertices[3]);
607 if(!hf1.is_valid()) {
608 FaceHandle fh = TopologyKernel::add_face(vs);
609 hf1 = halfface_handle(fh, 0);
610 }
611 vs.clear();
612
613 vs.push_back(_vertices[0]);
614 vs.push_back(_vertices[3]);
615 vs.push_back(_vertices[1]);
617 if(!hf2.is_valid()) {
618 FaceHandle fh = TopologyKernel::add_face(vs);
619 hf2 = halfface_handle(fh, 0);
620 }
621 vs.clear();
622
623 vs.push_back(_vertices[1]);
624 vs.push_back(_vertices[3]);
625 vs.push_back(_vertices[2]);
627 if(!hf3.is_valid()) {
628 FaceHandle fh = TopologyKernel::add_face(vs);
629 hf3 = halfface_handle(fh, 0);
630 }
631 vs.clear();
632
633 assert(hf0.is_valid());
634 assert(hf1.is_valid());
635 assert(hf2.is_valid());
636 assert(hf3.is_valid());
637
638
639 std::vector<HalfFaceHandle> hfs;
640 hfs.push_back(hf0);
641 hfs.push_back(hf1);
642 hfs.push_back(hf2);
643 hfs.push_back(hf3);
644
645 if (_topologyCheck) {
646 /*
647 * Test if all halffaces are connected and form a two-manifold
648 * => Cell is closed
649 *
650 * This test is simple: The number of involved half-edges has to be
651 * exactly twice the number of involved edges.
652 */
653
654 std::set<HalfEdgeHandle> incidentHalfedges;
655 std::set<EdgeHandle> incidentEdges;
656
657 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
658 end = hfs.end(); it != end; ++it) {
659
660 OpenVolumeMeshFace hface = halfface(*it);
661 for(std::vector<HalfEdgeHandle>::const_iterator he_it = hface.halfedges().begin(),
662 he_end = hface.halfedges().end(); he_it != he_end; ++he_it) {
663 incidentHalfedges.insert(*he_it);
664 incidentEdges.insert(edge_handle(*he_it));
665 }
666 }
667
668 if(incidentHalfedges.size() != (incidentEdges.size() * 2u)) {
669#ifndef NDEBUG
670 std::cerr << "The specified halffaces are not connected!" << std::endl;
671#endif
672 return InvalidCellHandle;
673 }
674 // The halffaces are now guaranteed to form a two-manifold
675
676 if(has_face_bottom_up_incidences()) {
677
678 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
679 end = hfs.end(); it != end; ++it) {
680 if(incident_cell(*it) != InvalidCellHandle) {
681#ifndef NDEBUG
682 std::cerr << "Warning: One of the specified half-faces is already incident to another cell!" << std::endl;
683#endif
684 return InvalidCellHandle;
685 }
686 }
687
688 }
689
690 }
691
692 return TopologyKernel::add_cell(hfs, false);
693}
694
695CellHandle TetrahedralMeshTopologyKernel::add_cell(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3, bool _topologyCheck)
696{
697 std::vector<HalfFaceHandle> halffaces;
698 halffaces.push_back(add_halfface(_vh0, _vh1, _vh2));
699 halffaces.push_back(add_halfface(_vh0, _vh2, _vh3));
700 halffaces.push_back(add_halfface(_vh0, _vh3, _vh1));
701 halffaces.push_back(add_halfface(_vh1, _vh3, _vh2));
702 return add_cell(halffaces, _topologyCheck);
703}
704
705//========================================================================================
706
707} // Namespace OpenVolumeMesh
size_t n() const
Get number of entities of given kind in mesh.
CellHandle add_cell(std::vector< HalfFaceHandle > _halffaces, bool _topologyCheck=false) override
Add cell via incident halffaces.
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)
virtual VertexIter delete_vertex(VertexHandle _h)
Delete vertex from mesh.
CellHandle incident_cell(HalfFaceHandle _halfFaceHandle) const
Get cell that is incident to the given halfface.
const Cell & cell(CellHandle _cellHandle) const
Get cell with handle _cellHandle.
size_t n_halfedges() const override
Get number of halfedges in mesh.
HalfEdgeHandle prev_halfedge_in_halfface(HalfEdgeHandle _heh, HalfFaceHandle _hfh) const
Get previous halfedge within a halfface.
static HalfEdgeHandle halfedge_handle(EdgeHandle _h, const unsigned char _subIdx)
Conversion function.
HalfEdgeHandle find_halfedge(VertexHandle _vh1, VertexHandle _vh2) const
Get halfedge from vertex _vh1 to _vh2.
virtual CellIter delete_cell(CellHandle _h)
Delete cell from mesh.
HalfEdgeHandle next_halfedge_in_halfface(HalfEdgeHandle _heh, HalfFaceHandle _hfh) const
Get next halfedge within a halfface.
static EdgeHandle edge_handle(HalfEdgeHandle _h)
Handle conversion.
size_t n_vertices() const override
Get number of vertices in mesh.
virtual FaceIter delete_face(FaceHandle _h)
Delete face from mesh.
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.
std::vector< VertexHandle > get_halfface_vertices(HalfFaceHandle hfh) const
Get vertices of a halfface.
Face halfface(HalfFaceHandle _halfFaceHandle) const
Get face that corresponds to halfface with handle _halfFaceHandle.
Edge halfedge(HalfEdgeHandle _halfEdgeHandle) const
Get edge that corresponds to halfedge with handle _halfEdgeHandle.
HalfFaceHandle find_halfface(const std::vector< VertexHandle > &_vs) const
virtual EdgeHandle add_edge(VertexHandle _fromVertex, VertexHandle _toHandle, bool _allowDuplicates=false)
Add edge.
virtual EdgeIter delete_edge(EdgeHandle _h)
Delete edge from mesh.
HalfFaceHandle adjacent_halfface_in_cell(HalfFaceHandle _halfFaceHandle, HalfEdgeHandle _halfEdgeHandle) const
Get halfface that is adjacent (w.r.t. a common halfedge) within the same cell. It correctly handles s...