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 "TetrahedralMeshTopologyKernel.hh"
36 
37 #include <iostream>
38 
39 namespace OpenVolumeMesh {
40 
41 FaceHandle TetrahedralMeshTopologyKernel::add_face(const 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(_halfedges, _topologyCheck);
52 }
53 
54 //========================================================================================
55 
56 
58 TetrahedralMeshTopologyKernel::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 
75 TetrahedralMeshTopologyKernel::add_cell(const 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(std::vector<HalfFaceHandle>::const_iterator it = _halffaces.begin();
85  it != _halffaces.end(); ++it) {
86  if(TopologyKernel::halfface(*it).halfedges().size() != 3) {
87 #ifndef NDEBUG
88  std::cerr << "Incident face does not have valence three! Aborting." << std::endl;
89 #endif
90  return TopologyKernel::InvalidCellHandle;
91  }
92  }
93 
94  return TopologyKernel::add_cell(_halffaces, _topologyCheck);
95 }
96 
97 
98 HalfEdgeHandle TetrahedralMeshTopologyKernel::add_halfedge(const VertexHandle& _fromVertex, const VertexHandle& _toVertex)
99 {
100  HalfEdgeHandle he = halfedge(_fromVertex, _toVertex);
101  if (he != InvalidHalfEdgeHandle)
102  return he;
103  else
104  return halfedge_handle(add_edge(_fromVertex, _toVertex), 0);
105 }
106 
107 HalfFaceHandle TetrahedralMeshTopologyKernel::add_halfface(const std::vector<HalfEdgeHandle>& _halfedges, bool _topologyCheck)
108 {
109  HalfFaceHandle hf = halfface(_halfedges);
110  if (hf != InvalidHalfFaceHandle)
111  return hf;
112  else
113  return halfface_handle(add_face(_halfedges, _topologyCheck), 0);
114 }
115 
116 HalfFaceHandle 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 
137 void 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 /*
158 void 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
311 VertexHandle 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  for (const CellHandle &ch: incidentCells)
337  {
338  if (collapsingCells.find(ch) != collapsingCells.end())
339  continue;
340 
341  Cell c = cell(ch);
342 
343  std::vector<HalfFaceHandle> newHalffaces;
344 
345  for (unsigned int hf_idx = 0; hf_idx < 4; ++hf_idx)
346  {
347  Face hf = halfface(c.halffaces()[hf_idx]);
348  std::vector<HalfEdgeHandle> newHalfedges;
349 
350  for (unsigned int j = 0; j < 3; ++j)
351  {
352  Edge e = halfedge(hf.halfedges()[j]);
353  VertexHandle newStart = (e.from_vertex() == from_vh) ? to_vh: e.from_vertex();
354  VertexHandle newEnd = (e.to_vertex() == from_vh) ? to_vh : e.to_vertex();
355 
356  HalfEdgeHandle heh = add_halfedge(newStart, newEnd);
357  newHalfedges.push_back(heh);
358  swap_halfedge_properties(hf.halfedges()[j], heh);
359  }
360 
361  HalfFaceHandle hfh = add_halfface(newHalfedges);
362  newHalffaces.push_back(hfh);
363  swap_halfface_properties(c.halffaces()[hf_idx], hfh);
364  }
365 
366  delete_cell(ch);
367 
368  CellHandle newCell = add_cell(newHalffaces);
369 
370  swap_cell_properties(ch, newCell);
371 
372  }
373 
374 
375  VertexHandle survivingVertex = to_vh;
376 
377  if (!deferred_deletion_tmp)
378  {
379  if (fast_deletion_enabled())
380  {
381  // from_vh is swapped with last vertex and then deleted
382  if (to_vh.idx() == (int)n_vertices() - 1)
383  survivingVertex = from_vh;
384  }
385  else
386  {
387  // from_vh is deleted and every vertex id larger than from_vh is reduced by one
388  if (from_vh.idx() < to_vh.idx())
389  survivingVertex = VertexHandle(to_vh.idx() - 1);
390  }
391  }
392 
393  delete_vertex(from_vh);
394 
395  enable_deferred_deletion(deferred_deletion_tmp);
396 
397  return survivingVertex;
398 
399 }
400 
401 // cppcheck-suppress unusedFunction ; public interface
402 void TetrahedralMeshTopologyKernel::split_edge(HalfEdgeHandle _heh, VertexHandle _vh)
403 {
404  bool deferred_deletion_tmp = deferred_deletion_enabled();
405 
406  if (!deferred_deletion_tmp)
407  enable_deferred_deletion(true);
408 
409  std::vector<HalfFaceHandle> incident_halffaces_with_cells;
410  for (HalfEdgeHalfFaceIter hehf_it = hehf_iter(_heh); hehf_it.valid(); ++hehf_it)
411  {
412  CellHandle ch = incident_cell(*hehf_it);
413  if (ch.is_valid())
414  incident_halffaces_with_cells.push_back(*hehf_it);
415  }
416 
417  for (auto hfh : incident_halffaces_with_cells)
418  {
419  CellHandle ch = incident_cell(hfh);
420 
421  std::vector<VertexHandle> vertices = get_cell_vertices(hfh, _heh);
422 
423  delete_cell(ch);
424 
425  add_cell(vertices[0], _vh, vertices[2], vertices[3]);
426  add_cell(_vh, vertices[1], vertices[2], vertices[3]);
427  }
428 
429  delete_edge(edge_handle(_heh));
430 
431  enable_deferred_deletion(deferred_deletion_tmp);
432 
433 }
434 
435 // cppcheck-suppress unusedFunction ; public interface
436 void TetrahedralMeshTopologyKernel::split_face(FaceHandle _fh, VertexHandle _vh)
437 {
438  bool deferred_deletion_tmp = deferred_deletion_enabled();
439 
440  if (!deferred_deletion_tmp)
441  enable_deferred_deletion(true);
442 
443  for (char i = 0; i < 2; ++i)
444  {
445  HalfFaceHandle hfh = halfface_handle(_fh, i);
446  CellHandle ch = incident_cell(hfh);
447  if (ch.is_valid())
448  {
449  std::vector<VertexHandle> vertices = get_cell_vertices(hfh);
450 
451  delete_cell(ch);
452 
453  add_cell(vertices[0], vertices[1], _vh, vertices[3]);
454  add_cell(vertices[0], _vh, vertices[2], vertices[3]);
455  add_cell(_vh, vertices[1], vertices[2], vertices[3]);
456  }
457  }
458 
459  delete_face(_fh);
460 
461  enable_deferred_deletion(deferred_deletion_tmp);
462 
463 }
464 
465 
466 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(CellHandle ch) const
467 {
468  return get_cell_vertices(cell(ch).halffaces().front());
469 }
470 
471 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(CellHandle ch, VertexHandle vh) const
472 {
473  HalfFaceHandle hfh = cell(ch).halffaces()[0];
474  Face f = halfface(hfh);
475  HalfEdgeHandle heh;
476  for (unsigned int i = 0; i < 3; ++i)
477  {
478  Edge e = halfedge(f.halfedges()[i]);
479  if (e.from_vertex() == vh)
480  {
481  heh = f.halfedges()[i];
482  break;
483  }
484  }
485  if (!heh.is_valid())
486  {
487  hfh = adjacent_halfface_in_cell(hfh, f.halfedges()[0]);
488  heh = prev_halfedge_in_halfface(opposite_halfedge_handle(f.halfedges()[0]), hfh);
489  }
490 
491  return get_cell_vertices(hfh,heh);
492 
493 }
494 
495 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(HalfFaceHandle hfh) const
496 {
497  return get_cell_vertices(hfh, halfface(hfh).halfedges().front());
498 }
499 
500 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_cell_vertices(HalfFaceHandle hfh, HalfEdgeHandle heh) const
501 {
502  std::vector<VertexHandle> vertices;
503 
504  // add vertices of halfface
505  for (unsigned int i = 0; i < 3; ++i)
506  {
507  Edge e = halfedge(heh);
508  vertices.push_back(e.from_vertex());
509  heh = next_halfedge_in_halfface(heh, hfh);
510  }
511 
512  Cell c = cell(incident_cell(hfh));
513  HalfFaceHandle otherHfh = c.halffaces()[0];
514  if (otherHfh == hfh)
515  otherHfh = c.halffaces()[1];
516 
517  Face otherF = halfface(otherHfh);
518 
519  for (unsigned int i = 0; i < otherF.halfedges().size(); ++i)
520  {
521  HalfEdgeHandle he = otherF.halfedges()[i];
522  Edge e = halfedge(he);
523  if (std::find(vertices.begin(), vertices.end(), e.to_vertex()) == vertices.end())
524  {
525  vertices.push_back(e.to_vertex());
526  return vertices;
527  }
528  }
529 
530  return vertices;
531 }
532 
533 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_halfface_vertices(HalfFaceHandle hfh) const
534 {
535  return get_halfface_vertices(hfh, halfface(hfh).halfedges().front());
536 }
537 
538 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_halfface_vertices(HalfFaceHandle hfh, VertexHandle vh) const
539 {
540  Face hf = halfface(hfh);
541  for (unsigned int i = 0; i < 3; ++i)
542  if (halfedge(hf.halfedges()[i]).from_vertex() == vh)
543  return get_halfface_vertices(hfh, hf.halfedges()[i]);
544 
545  return std::vector<VertexHandle>();
546 }
547 
548 // cppcheck-suppress unusedFunction ; public interface
549 std::vector<VertexHandle> TetrahedralMeshTopologyKernel::get_halfface_vertices(HalfFaceHandle hfh, HalfEdgeHandle heh) const
550 {
551  std::vector<VertexHandle> vertices;
552 
553  // add vertices of halfface
554  for (unsigned int i = 0; i < 3; ++i)
555  {
556  Edge e = halfedge(heh);
557  vertices.push_back(e.from_vertex());
558  heh = next_halfedge_in_halfface(heh, hfh);
559  }
560 
561  return vertices;
562 }
563 
564 VertexHandle TetrahedralMeshTopologyKernel::halfface_opposite_vertex(HalfFaceHandle hfh) const
565 {
566  if (is_boundary(hfh)) {
567  return InvalidVertexHandle;
568  }
569 
570  const std::vector<VertexHandle> base = get_halfface_vertices(hfh);
571  for (CellVertexIter it = cv_iter(incident_cell(hfh)); it.valid(); ++it) {
572  const VertexHandle vh = *it;
573  if (vh != base[0] && vh != base[1] && vh != base[2]) {
574  return vh;
575  }
576  }
577 
578  return InvalidVertexHandle;
579 }
580 
581 
582 //========================================================================================
583 
585 TetrahedralMeshTopologyKernel::add_cell(const std::vector<VertexHandle>& _vertices, bool _topologyCheck) {
586 
587  // debug mode checks
588  assert(TopologyKernel::has_full_bottom_up_incidences());
589  assert(_vertices.size() == 4);
590 
591  // release mode checks
592  if(!TopologyKernel::has_full_bottom_up_incidences()) {
593  return CellHandle(-1);
594  }
595 
596  if(_vertices.size() != 4) {
597  return CellHandle(-1);
598  }
599 
600  HalfFaceHandle hf0, hf1, hf2, hf3;
601 
602  std::vector<VertexHandle> vs;
603 
604  vs.push_back(_vertices[0]);
605  vs.push_back(_vertices[1]);
606  vs.push_back(_vertices[2]);
607  hf0 = TopologyKernel::halfface(vs);
608  if(!hf0.is_valid()) {
610  hf0 = halfface_handle(fh, 0);
611  }
612  vs.clear();
613 
614  vs.push_back(_vertices[0]);
615  vs.push_back(_vertices[2]);
616  vs.push_back(_vertices[3]);
617  hf1 = TopologyKernel::halfface(vs);
618  if(!hf1.is_valid()) {
620  hf1 = halfface_handle(fh, 0);
621  }
622  vs.clear();
623 
624  vs.push_back(_vertices[0]);
625  vs.push_back(_vertices[3]);
626  vs.push_back(_vertices[1]);
627  hf2 = TopologyKernel::halfface(vs);
628  if(!hf2.is_valid()) {
630  hf2 = halfface_handle(fh, 0);
631  }
632  vs.clear();
633 
634  vs.push_back(_vertices[1]);
635  vs.push_back(_vertices[3]);
636  vs.push_back(_vertices[2]);
637  hf3 = TopologyKernel::halfface(vs);
638  if(!hf3.is_valid()) {
640  hf3 = halfface_handle(fh, 0);
641  }
642  vs.clear();
643 
644  assert(hf0.is_valid());
645  assert(hf1.is_valid());
646  assert(hf2.is_valid());
647  assert(hf3.is_valid());
648 
649 
650  std::vector<HalfFaceHandle> hfs;
651  hfs.push_back(hf0);
652  hfs.push_back(hf1);
653  hfs.push_back(hf2);
654  hfs.push_back(hf3);
655 
656  if (_topologyCheck) {
657  /*
658  * Test if all halffaces are connected and form a two-manifold
659  * => Cell is closed
660  *
661  * This test is simple: The number of involved half-edges has to be
662  * exactly twice the number of involved edges.
663  */
664 
665  std::set<HalfEdgeHandle> incidentHalfedges;
666  std::set<EdgeHandle> incidentEdges;
667 
668  for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
669  end = hfs.end(); it != end; ++it) {
670 
671  OpenVolumeMeshFace hface = halfface(*it);
672  for(std::vector<HalfEdgeHandle>::const_iterator he_it = hface.halfedges().begin(),
673  he_end = hface.halfedges().end(); he_it != he_end; ++he_it) {
674  incidentHalfedges.insert(*he_it);
675  incidentEdges.insert(edge_handle(*he_it));
676  }
677  }
678 
679  if(incidentHalfedges.size() != (incidentEdges.size() * 2u)) {
680 #ifndef NDEBUG
681  std::cerr << "The specified halffaces are not connected!" << std::endl;
682 #endif
683  return InvalidCellHandle;
684  }
685  // The halffaces are now guaranteed to form a two-manifold
686 
687  if(has_face_bottom_up_incidences()) {
688 
689  for(std::vector<HalfFaceHandle>::const_iterator it = hfs.begin(),
690  end = hfs.end(); it != end; ++it) {
691  if(incident_cell(*it) != InvalidCellHandle) {
692 #ifndef NDEBUG
693  std::cerr << "Warning: One of the specified half-faces is already incident to another cell!" << std::endl;
694 #endif
695  return InvalidCellHandle;
696  }
697  }
698 
699  }
700 
701  }
702 
703  return TopologyKernel::add_cell(hfs, false);
704 }
705 
707 {
708  std::vector<HalfFaceHandle> halffaces;
709  halffaces.push_back(add_halfface(_vh0, _vh1, _vh2));
710  halffaces.push_back(add_halfface(_vh0, _vh2, _vh3));
711  halffaces.push_back(add_halfface(_vh0, _vh3, _vh1));
712  halffaces.push_back(add_halfface(_vh1, _vh3, _vh2));
713  return add_cell(halffaces, _topologyCheck);
714 }
715 
716 //========================================================================================
717 
718 } // Namespace OpenVolumeMesh
virtual FaceHandle add_face(const std::vector< HalfEdgeHandle > &_halfedges, bool _topologyCheck=false)
Add face via incident edges.
virtual CellIter delete_cell(const CellHandle &_h)
Delete cell from mesh.
CellHandle incident_cell(const HalfFaceHandle &_halfFaceHandle) const
Get cell that is incident to the given halfface.
virtual EdgeHandle add_edge(const VertexHandle &_fromVertex, const VertexHandle &_toHandle, bool _allowDuplicates=false)
Add edge.
virtual EdgeIter delete_edge(const EdgeHandle &_h)
Delete edge from mesh.
static EdgeHandle edge_handle(const HalfEdgeHandle &_h)
Handle conversion.
HalfFaceHandle adjacent_halfface_in_cell(const HalfFaceHandle &_halfFaceHandle, const HalfEdgeHandle &_halfEdgeHandle) const
Get halfface that is adjacent (w.r.t. a common halfedge) within the same cell.
static HalfFaceHandle halfface_handle(const FaceHandle &_h, const unsigned char _subIdx)
Conversion function.
HalfEdgeHandle prev_halfedge_in_halfface(const HalfEdgeHandle &_heh, const HalfFaceHandle &_hfh) const
Get previous halfedge within a halfface.
HalfEdgeHandle next_halfedge_in_halfface(const HalfEdgeHandle &_heh, const HalfFaceHandle &_hfh) const
Get next halfedge within a halfface.
size_t n_vertices() const override
Get number of vertices in mesh.
Face halfface(const HalfFaceHandle &_halfFaceHandle) const
Get face that corresponds to halfface with handle _halfFaceHandle.
virtual VertexIter delete_vertex(const VertexHandle &_h)
Delete vertex from mesh.
virtual CellHandle add_cell(const std::vector< HalfFaceHandle > &_halffaces, bool _topologyCheck=false)
Add cell via incident halffaces.
Edge halfedge(const HalfEdgeHandle &_halfEdgeHandle) const
Get edge that corresponds to halfedge with handle _halfEdgeHandle.
virtual FaceIter delete_face(const FaceHandle &_h)
Delete face from mesh.
FaceHandle add_face(const std::vector< HalfEdgeHandle > &_halfedges, bool _topologyCheck=false) override
Add face via incident edges.
const Cell & cell(const CellHandle &_cellHandle) const
Get cell with handle _cellHandle.
CellHandle add_cell(const std::vector< HalfFaceHandle > &_halffaces, bool _topologyCheck=false) override
Add cell via incident halffaces.
static HalfEdgeHandle halfedge_handle(const EdgeHandle &_h, const unsigned char _subIdx)
Conversion function.