Developer Documentation
Loading...
Searching...
No Matches
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
487{
488 return get_cell_vertices(cell(ch).halffaces().front());
489}
490
492{
493 auto vhs = get_cell_vertices(cell(ch).halffaces()[0]);
494
495 if (vhs[1]==vh) {return {vhs[1], vhs[2], vhs[0], vhs[3]};}
496 if (vhs[2]==vh) {return {vhs[2], vhs[0], vhs[1], vhs[3]};}
497 if (vhs[3]==vh) {return {vhs[3], vhs[1], vhs[0], vhs[2]};}
498 return vhs;
499}
500
502{
503 const CellHandle ch = incident_cell(hfh);
504 assert(ch.is_valid());
505 if (!ch.is_valid()) return {};
506
507 const auto& hfhs = cell(ch).halffaces();
508
509 // Start with the 3 vertices of the given halfface
510 std::vector<VertexHandle> cell_vhs;
511 cell_vhs.reserve(4);
512 for (VertexHandle vh : halfface_vertices(hfh)) {
513 cell_vhs.push_back(vh);
514 }
515
516 // Look for the 4th vertex in another halfface of the cell
517 HalfFaceHandle other_hfh = (hfh!=hfhs[0])? hfhs[0] : hfhs[1];
518 for (VertexHandle other_vh : halfface_vertices(other_hfh))
519 {
520 if (cell_vhs[0] != other_vh && cell_vhs[1] != other_vh && cell_vhs[2] != other_vh)
521 {
522 cell_vhs.push_back(other_vh);
523 return cell_vhs;
524 }
525 }
526
527 // If we end up here, the tet contains less than 4 vertices
528 assert(false);
529 return {};
530}
531
533{
534 auto vh0 = from_vertex_handle(heh);
535 auto vh1 = to_vertex_handle(heh);
536
537 // Ensure that first 3 vertices are of hfh -> 4th vertex stays fixed
538 auto vhs = get_cell_vertices(hfh);
539
540 // Ensure, we start with vh0 (note that vh0 cant be the 4th vertex cause heh must be contained in hfh)
541 if (vhs[1] == vh0) vhs = {vhs[1],vhs[2],vhs[0],vhs[3]};
542 else if (vhs[2] == vh0) vhs = {vhs[2],vhs[0],vhs[1],vhs[3]};
543
544 // Ensure the 2nd vertex is vh1
545 if (vhs[2] == vh1) vhs = {vhs[0],vhs[1],vhs[2],vhs[3]};
546 else if (vhs[3] == vh1) vhs = {vhs[0],vhs[1],vhs[2],vhs[3]};
547
548 return vhs;
549}
550
552{
553 return is_boundary(hfh)? InvalidVertexHandle : get_cell_vertices(hfh)[3];
554}
555
557{
558 for (HalfFaceHandle hfh : cell(ch).halffaces())
559 {
560 const auto& vhs = get_halfface_vertices(hfh);
561 if (vhs[0] != vh && vhs[1] != vh && vhs[2] != vh)
562 {
563 return hfh;
564 }
565 }
566 return InvalidHalfFaceHandle;
567}
568
569
570//========================================================================================
571
573TetrahedralMeshTopologyKernel::add_cell(const std::vector<VertexHandle>& _vertices, bool _topologyCheck)
574{
575 if(_vertices.size() != 4) {
576 return CellHandle(-1);
577 }
578
579 // debug mode checks
580 assert(TopologyKernel::has_full_bottom_up_incidences());
581
582 // release mode checks
583 if(!TopologyKernel::has_full_bottom_up_incidences()) {
584 return CellHandle(-1);
585 }
586
587
588 HalfFaceHandle hf0, hf1, hf2, hf3;
589
590 std::vector<VertexHandle> vs;
591
592 vs.push_back(_vertices[0]);
593 vs.push_back(_vertices[1]);
594 vs.push_back(_vertices[2]);
596 if(!hf0.is_valid()) {
597 FaceHandle fh = TopologyKernel::add_face(vs);
598 hf0 = halfface_handle(fh, 0);
599 }
600 vs.clear();
601
602 vs.push_back(_vertices[0]);
603 vs.push_back(_vertices[2]);
604 vs.push_back(_vertices[3]);
606 if(!hf1.is_valid()) {
607 FaceHandle fh = TopologyKernel::add_face(vs);
608 hf1 = halfface_handle(fh, 0);
609 }
610 vs.clear();
611
612 vs.push_back(_vertices[0]);
613 vs.push_back(_vertices[3]);
614 vs.push_back(_vertices[1]);
616 if(!hf2.is_valid()) {
617 FaceHandle fh = TopologyKernel::add_face(vs);
618 hf2 = halfface_handle(fh, 0);
619 }
620 vs.clear();
621
622 vs.push_back(_vertices[1]);
623 vs.push_back(_vertices[3]);
624 vs.push_back(_vertices[2]);
626 if(!hf3.is_valid()) {
627 FaceHandle fh = TopologyKernel::add_face(vs);
628 hf3 = halfface_handle(fh, 0);
629 }
630 vs.clear();
631
632 assert(hf0.is_valid());
633 assert(hf1.is_valid());
634 assert(hf2.is_valid());
635 assert(hf3.is_valid());
636
637
638 std::vector<HalfFaceHandle> hfs;
639 hfs.push_back(hf0);
640 hfs.push_back(hf1);
641 hfs.push_back(hf2);
642 hfs.push_back(hf3);
643
644 if (_topologyCheck) {
645 /*
646 * Test if all halffaces are connected and form a two-manifold
647 * => Cell is closed
648 *
649 * This test is simple: The number of involved half-edges has to be
650 * exactly twice the number of involved edges.
651 */
652
653 std::set<HalfEdgeHandle> incidentHalfedges;
654 std::set<EdgeHandle> incidentEdges;
655
656 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
657 end = hfs.end(); it != end; ++it) {
658
659 OpenVolumeMeshFace hface = halfface(*it);
660 for(std::vector<HalfEdgeHandle>::const_iterator he_it = hface.halfedges().begin(),
661 he_end = hface.halfedges().end(); he_it != he_end; ++he_it) {
662 incidentHalfedges.insert(*he_it);
663 incidentEdges.insert(edge_handle(*he_it));
664 }
665 }
666
667 if(incidentHalfedges.size() != (incidentEdges.size() * 2u)) {
668#ifndef NDEBUG
669 std::cerr << "The specified halffaces are not connected!" << std::endl;
670#endif
671 return InvalidCellHandle;
672 }
673 // The halffaces are now guaranteed to form a two-manifold
674
675 if(has_face_bottom_up_incidences()) {
676
677 for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
678 end = hfs.end(); it != end; ++it) {
679 if(incident_cell(*it) != InvalidCellHandle) {
680#ifndef NDEBUG
681 std::cerr << "Warning: One of the specified half-faces is already incident to another cell!" << std::endl;
682#endif
683 return InvalidCellHandle;
684 }
685 }
686
687 }
688
689 }
690
691 return TopologyKernel::add_cell(hfs, false);
692}
693
694CellHandle TetrahedralMeshTopologyKernel::add_cell(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3, bool _topologyCheck)
695{
696 std::vector<HalfFaceHandle> halffaces;
697 halffaces.push_back(add_halfface(_vh0, _vh1, _vh2));
698 halffaces.push_back(add_halfface(_vh0, _vh2, _vh3));
699 halffaces.push_back(add_halfface(_vh0, _vh3, _vh1));
700 halffaces.push_back(add_halfface(_vh1, _vh3, _vh2));
701 return add_cell(halffaces, _topologyCheck);
702}
703
704//========================================================================================
705
706} // 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.
std::vector< VertexHandle > get_cell_vertices(CellHandle ch) const
FaceHandle add_face(std::vector< HalfEdgeHandle > _halfedges, bool _topologyCheck=false) override
Add face via incident edges.
HalfFaceHandle vertex_opposite_halfface(CellHandle ch, VertexHandle vh) const
Get the first halfface of the tet ch that does not contain the vertex vh.
VertexHandle halfface_opposite_vertex(HalfFaceHandle hfh) const
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.
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.
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.
VertexHandle from_vertex_handle(HalfEdgeHandle _h) const
Get the vertex the halfedge starts from.
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.
VertexHandle to_vertex_handle(HalfEdgeHandle _h) const
Get the vertex the halfedge points to.