Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
PolyConnectivity.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 //== IMPLEMENTATION ==========================================================
50 #include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
51 #include <set>
52 
53 namespace OpenMesh {
54 
55 const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle;
56 const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle;
57 const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle;
58 const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle;
59 
60 //-----------------------------------------------------------------------------
61 
62 PolyConnectivity::HalfedgeHandle
64 {
65  assert(_start_vh.is_valid() && _end_vh.is_valid());
66 
67  for (ConstVertexOHalfedgeIter voh_it = cvoh_iter(_start_vh); voh_it.is_valid(); ++voh_it)
68  if (to_vertex_handle(*voh_it) == _end_vh)
69  return *voh_it;
70 
71  return InvalidHalfedgeHandle;
72 }
73 
74 
75 bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const
76 {
77  for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit.is_valid(); ++cfeit)
78  if (is_boundary( *cfeit ) )
79  return true;
80 
81  if (_check_vertex)
82  {
83  for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit.is_valid(); ++cfvit)
84  if (is_boundary( *cfvit ) )
85  return true;
86  }
87  return false;
88 }
89 
91 {
92  /* The vertex is non-manifold if more than one gap exists, i.e.
93  more than one outgoing boundary halfedge. If (at least) one
94  boundary halfedge exists, the vertex' halfedge must be a
95  boundary halfedge. If iterating around the vertex finds another
96  boundary halfedge, the vertex is non-manifold. */
97 
98  ConstVertexOHalfedgeIter vh_it(*this, _vh);
99  if (vh_it.is_valid())
100  for (++vh_it; vh_it.is_valid(); ++vh_it)
101  if (is_boundary(*vh_it))
102  return false;
103  return true;
104 }
105 
106 //-----------------------------------------------------------------------------
108 {
109  for (ConstVertexOHalfedgeIter vh_it=cvoh_iter(_vh); vh_it.is_valid(); ++vh_it)
110  {
111  if (is_boundary(*vh_it))
112  {
113  set_halfedge_handle(_vh, *vh_it);
114  break;
115  }
116  }
117 }
118 
119 //-----------------------------------------------------------------------------
120 
121 PolyConnectivity::FaceHandle
122 PolyConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size)
123 {
124  VertexHandle vh;
125  size_t i, ii, n(_vhs_size);
126  HalfedgeHandle inner_next, inner_prev,
127  outer_next, outer_prev,
128  boundary_next, boundary_prev,
129  patch_start, patch_end;
130 
131 
132  // Check sufficient working storage available
133  if (edgeData_.size() < n)
134  {
135  edgeData_.resize(n);
136  next_cache_.resize(6*n);
137  }
138 
139  size_t next_cache_count = 0;
140 
141  // don't allow degenerated faces
142  assert (n > 2);
143 
144  // test for topological errors
145  for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
146  {
147  if ( !is_boundary(_vertex_handles[i]) )
148  {
149  omerr() << "PolyMeshT::add_face: complex vertex\n";
150  return InvalidFaceHandle;
151  }
152 
153  // Initialise edge attributes
154  edgeData_[i].halfedge_handle = find_halfedge(_vertex_handles[i],
155  _vertex_handles[ii]);
156  edgeData_[i].is_new = !edgeData_[i].halfedge_handle.is_valid();
157  edgeData_[i].needs_adjust = false;
158 
159  if (!edgeData_[i].is_new && !is_boundary(edgeData_[i].halfedge_handle))
160  {
161  omerr() << "PolyMeshT::add_face: complex edge\n";
162  return InvalidFaceHandle;
163  }
164  }
165 
166  // re-link patches if necessary
167  for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
168  {
169  if (!edgeData_[i].is_new && !edgeData_[ii].is_new)
170  {
171  inner_prev = edgeData_[i].halfedge_handle;
172  inner_next = edgeData_[ii].halfedge_handle;
173 
174 
175  if (next_halfedge_handle(inner_prev) != inner_next)
176  {
177  // here comes the ugly part... we have to relink a whole patch
178 
179  // search a free gap
180  // free gap will be between boundary_prev and boundary_next
181  outer_prev = opposite_halfedge_handle(inner_next);
182  outer_next = opposite_halfedge_handle(inner_prev);
183  boundary_prev = outer_prev;
184  do
185  boundary_prev =
186  opposite_halfedge_handle(next_halfedge_handle(boundary_prev));
187  while (!is_boundary(boundary_prev));
188  boundary_next = next_halfedge_handle(boundary_prev);
189 
190  // ok ?
191  if (boundary_prev == inner_prev)
192  {
193  omerr() << "PolyMeshT::add_face: patch re-linking failed\n";
194  return InvalidFaceHandle;
195  }
196 
197  assert(is_boundary(boundary_prev));
198  assert(is_boundary(boundary_next));
199 
200  // other halfedges' handles
201  patch_start = next_halfedge_handle(inner_prev);
202  patch_end = prev_halfedge_handle(inner_next);
203 
204  assert(boundary_prev.is_valid());
205  assert(patch_start.is_valid());
206  assert(patch_end.is_valid());
207  assert(boundary_next.is_valid());
208  assert(inner_prev.is_valid());
209  assert(inner_next.is_valid());
210 
211  // relink
212  next_cache_[next_cache_count++] = std::make_pair(boundary_prev, patch_start);
213  next_cache_[next_cache_count++] = std::make_pair(patch_end, boundary_next);
214  next_cache_[next_cache_count++] = std::make_pair(inner_prev, inner_next);
215  }
216  }
217  }
218 
219  // create missing edges
220  for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
221  if (edgeData_[i].is_new)
222  edgeData_[i].halfedge_handle = new_edge(_vertex_handles[i], _vertex_handles[ii]);
223 
224  // create the face
225  FaceHandle fh(new_face());
226  set_halfedge_handle(fh, edgeData_[n-1].halfedge_handle);
227 
228  // setup halfedges
229  for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
230  {
231  vh = _vertex_handles[ii];
232 
233  inner_prev = edgeData_[i].halfedge_handle;
234  inner_next = edgeData_[ii].halfedge_handle;
235  assert(inner_prev.is_valid());
236  assert(inner_next.is_valid());
237 
238  size_t id = 0;
239  if (edgeData_[i].is_new) id |= 1;
240  if (edgeData_[ii].is_new) id |= 2;
241 
242 
243  if (id)
244  {
245  outer_prev = opposite_halfedge_handle(inner_next);
246  outer_next = opposite_halfedge_handle(inner_prev);
247  assert(outer_prev.is_valid());
248  assert(outer_next.is_valid());
249 
250  // set outer links
251  switch (id)
252  {
253  case 1: // prev is new, next is old
254  boundary_prev = prev_halfedge_handle(inner_next);
255  assert(boundary_prev.is_valid());
256  next_cache_[next_cache_count++] = std::make_pair(boundary_prev, outer_next);
257  set_halfedge_handle(vh, outer_next);
258  break;
259 
260  case 2: // next is new, prev is old
261  boundary_next = next_halfedge_handle(inner_prev);
262  assert(boundary_next.is_valid());
263  next_cache_[next_cache_count++] = std::make_pair(outer_prev, boundary_next);
264  set_halfedge_handle(vh, boundary_next);
265  break;
266 
267  case 3: // both are new
268  if (!halfedge_handle(vh).is_valid())
269  {
270  set_halfedge_handle(vh, outer_next);
271  next_cache_[next_cache_count++] = std::make_pair(outer_prev, outer_next);
272  }
273  else
274  {
275  boundary_next = halfedge_handle(vh);
276  boundary_prev = prev_halfedge_handle(boundary_next);
277  assert(boundary_prev.is_valid());
278  assert(boundary_next.is_valid());
279  next_cache_[next_cache_count++] = std::make_pair(boundary_prev, outer_next);
280  next_cache_[next_cache_count++] = std::make_pair(outer_prev, boundary_next);
281  }
282  break;
283  }
284 
285  // set inner link
286  next_cache_[next_cache_count++] = std::make_pair(inner_prev, inner_next);
287  }
288  else edgeData_[ii].needs_adjust = (halfedge_handle(vh) == inner_next);
289 
290 
291  // set face handle
292  set_face_handle(edgeData_[i].halfedge_handle, fh);
293  }
294 
295  // process next halfedge cache
296  for (i = 0; i < next_cache_count; ++i)
297  set_next_halfedge_handle(next_cache_[i].first, next_cache_[i].second);
298 
299 
300  // adjust vertices' halfedge handle
301  for (i=0; i<n; ++i)
302  if (edgeData_[i].needs_adjust)
303  adjust_outgoing_halfedge(_vertex_handles[i]);
304 
305  return fh;
306 }
307 
308 //-----------------------------------------------------------------------------
309 
311 {
312  VertexHandle vhs[4] = { _vh0, _vh1, _vh2, _vh3 };
313  return add_face(vhs, 4);
314 }
315 
316 //-----------------------------------------------------------------------------
317 
319 {
320  VertexHandle vhs[3] = { _vh0, _vh1, _vh2 };
321  return add_face(vhs, 3);
322 }
323 
324 //-----------------------------------------------------------------------------
325 
326 FaceHandle PolyConnectivity::add_face(const std::vector<VertexHandle>& _vhandles)
327 { return add_face(&_vhandles.front(), _vhandles.size()); }
328 
329 
330 //-----------------------------------------------------------------------------
332 {
333  //is edge already deleteed?
334  if (status(edge_handle(v0v1)).deleted())
335  {
336  return false;
337  }
338 
339  HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1));
340  VertexHandle v0(to_vertex_handle(v1v0));
341  VertexHandle v1(to_vertex_handle(v0v1));
342 
343  bool v0v1_triangle = false;
344  bool v1v0_triangle = false;
345 
346  if (!is_boundary(v0v1))
347  v0v1_triangle = valence(face_handle(v0v1)) == 3;
348 
349  if (!is_boundary(v1v0))
350  v1v0_triangle = valence(face_handle(v1v0)) == 3;
351 
352  //in a quadmesh we dont have the "next" or "previous" vhandle, so we need to look at previous and next on both sides
353  //VertexHandle v_01_p = from_vertex_handle(prev_halfedge_handle(v0v1));
354  VertexHandle v_01_n = to_vertex_handle(next_halfedge_handle(v0v1));
355 
356  //VertexHandle v_10_p = from_vertex_handle(prev_halfedge_handle(v1v0));
357  VertexHandle v_10_n = to_vertex_handle(next_halfedge_handle(v1v0));
358 
359  //are the vertices already deleted ?
360  if (status(v0).deleted() || status(v1).deleted())
361  {
362  return false;
363  }
364 
365  //the edges v1-vl and vl-v0 must not be both boundary edges
366  //this test makes only sense in a polymesh if the side face is a triangle
367  if (!is_boundary(v0v1))
368  {
369  if (v0v1_triangle)
370  {
371  //VertexHandle vl = to_vertex_handle(next_halfedge_handle(v0v1));
372 
373  HalfedgeHandle h1 = next_halfedge_handle(v0v1);
374  HalfedgeHandle h2 = next_halfedge_handle(h1);
375  if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2)))
376  return false;
377  }
378  }
379 
380  //the edges v0-vr and vr-v1 must not be both boundary edges
381  //this test makes only sense in a polymesh if the side face is a triangle
382  if (!is_boundary(v1v0))
383  {
384  if (v1v0_triangle)
385  {
386  //VertexHandle vr = to_vertex_handle(next_halfedge_handle(v1v0));
387 
388  HalfedgeHandle h1 = next_halfedge_handle(v1v0);
389  HalfedgeHandle h2 = next_halfedge_handle(h1);
390  if (is_boundary(opposite_halfedge_handle(h1)) && is_boundary(opposite_halfedge_handle(h2)))
391  return false;
392  }
393  }
394 
395  // edge between two boundary vertices should be a boundary edge
396  if ( is_boundary(v0) && is_boundary(v1) && !is_boundary(v0v1) && !is_boundary(v1v0))
397  return false;
398 
399  VertexVertexIter vv_it;
400  // test intersection of the one-rings of v0 and v1
401  for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it)
402  {
403  status(*vv_it).set_tagged(false);
404  }
405 
406  for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it)
407  {
408  status(*vv_it).set_tagged(true);
409  }
410 
411  for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it)
412  {
413  if (status(*vv_it).tagged() &&
414  !(*vv_it == v_01_n && v0v1_triangle) &&
415  !(*vv_it == v_10_n && v1v0_triangle)
416  )
417  {
418  return false;
419  }
420  }
421 
422  //test for a face on the backside/other side that might degenerate
423  if (v0v1_triangle)
424  {
425  HalfedgeHandle one, two;
426  one = next_halfedge_handle(v0v1);
427  two = next_halfedge_handle(one);
428 
429  one = opposite_halfedge_handle(one);
430  two = opposite_halfedge_handle(two);
431 
432  if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3)
433  {
434  return false;
435  }
436  }
437 
438  if (v1v0_triangle)
439  {
440  HalfedgeHandle one, two;
441  one = next_halfedge_handle(v1v0);
442  two = next_halfedge_handle(one);
443 
444  one = opposite_halfedge_handle(one);
445  two = opposite_halfedge_handle(two);
446 
447  if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3)
448  {
449  return false;
450  }
451  }
452 
453  if (status(*vv_it).tagged() && v_01_n == v_10_n && v0v1_triangle && v1v0_triangle)
454  {
455  return false;
456  }
457 
458  // passed all tests
459  return true;
460 }
461 
462 //-----------------------------------------------------------------------------
463 
464 void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices)
465 {
466  // store incident faces
467  std::vector<FaceHandle> face_handles;
468  face_handles.reserve(8);
469  for (VFIter vf_it(vf_iter(_vh)); vf_it.is_valid(); ++vf_it)
470  face_handles.push_back(*vf_it);
471 
472 
473  // delete collected faces
474  std::vector<FaceHandle>::iterator fh_it(face_handles.begin()),
475  fh_end(face_handles.end());
476 
477  for (; fh_it!=fh_end; ++fh_it)
478  delete_face(*fh_it, _delete_isolated_vertices);
479 
480  status(_vh).set_deleted(true);
481 }
482 
483 //-----------------------------------------------------------------------------
484 
485 void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices)
486 {
487  FaceHandle fh0(face_handle(halfedge_handle(_eh, 0)));
488  FaceHandle fh1(face_handle(halfedge_handle(_eh, 1)));
489 
490  if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices);
491  if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices);
492 
493  // If there is no face, we delete the edge
494  // here
495  if ( ! fh0.is_valid() && !fh1.is_valid()) {
496  // mark edge deleted if the mesh has a edge status
497  if ( has_edge_status() )
498  status(_eh).set_deleted(true);
499 
500  // mark corresponding halfedges as deleted
501  // As the deleted edge is boundary,
502  // all corresponding halfedges will also be deleted.
503  if ( has_halfedge_status() ) {
504  status(halfedge_handle(_eh, 0)).set_deleted(true);
505  status(halfedge_handle(_eh, 1)).set_deleted(true);
506  }
507  }
508 }
509 
510 //-----------------------------------------------------------------------------
511 
512 void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices)
513 {
514  assert(_fh.is_valid() && !status(_fh).deleted());
515 
516  // mark face deleted
517  status(_fh).set_deleted(true);
518 
519 
520  // this vector will hold all boundary edges of face _fh
521  // these edges will be deleted
522  std::vector<EdgeHandle> deleted_edges;
523  deleted_edges.reserve(3);
524 
525 
526  // this vector will hold all vertices of face _fh
527  // for updating their outgoing halfedge
528  std::vector<VertexHandle> vhandles;
529  vhandles.reserve(3);
530 
531 
532  // for all halfedges of face _fh do:
533  // 1) invalidate face handle.
534  // 2) collect all boundary halfedges, set them deleted
535  // 3) store vertex handles
536  HalfedgeHandle hh;
537  for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it.is_valid(); ++fh_it)
538  {
539  hh = *fh_it;
540 
541  set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle);
542 
543  if (is_boundary(opposite_halfedge_handle(hh)))
544  deleted_edges.push_back(edge_handle(hh));
545 
546  vhandles.push_back(to_vertex_handle(hh));
547  }
548 
549 
550  // delete all collected (half)edges
551  // these edges were all boundary
552  // delete isolated vertices (if _delete_isolated_vertices is true)
553  if (!deleted_edges.empty())
554  {
555  std::vector<EdgeHandle>::iterator del_it(deleted_edges.begin()),
556  del_end(deleted_edges.end());
557  HalfedgeHandle h0, h1, next0, next1, prev0, prev1;
558  VertexHandle v0, v1;
559 
560  for (; del_it!=del_end; ++del_it)
561  {
562  h0 = halfedge_handle(*del_it, 0);
563  v0 = to_vertex_handle(h0);
564  next0 = next_halfedge_handle(h0);
565  prev0 = prev_halfedge_handle(h0);
566 
567  h1 = halfedge_handle(*del_it, 1);
568  v1 = to_vertex_handle(h1);
569  next1 = next_halfedge_handle(h1);
570  prev1 = prev_halfedge_handle(h1);
571 
572  // adjust next and prev handles
573  set_next_halfedge_handle(prev0, next1);
574  set_next_halfedge_handle(prev1, next0);
575 
576  // mark edge deleted if the mesh has a edge status
577  if ( has_edge_status() )
578  status(*del_it).set_deleted(true);
579 
580 
581  // mark corresponding halfedges as deleted
582  // As the deleted edge is boundary,
583  // all corresponding halfedges will also be deleted.
584  if ( has_halfedge_status() ) {
585  status(h0).set_deleted(true);
586  status(h1).set_deleted(true);
587  }
588 
589  // update v0
590  if (halfedge_handle(v0) == h1)
591  {
592  // isolated ?
593  if (next0 == h1)
594  {
595  if (_delete_isolated_vertices)
596  status(v0).set_deleted(true);
597  set_isolated(v0);
598  }
599  else set_halfedge_handle(v0, next0);
600  }
601 
602  // update v1
603  if (halfedge_handle(v1) == h0)
604  {
605  // isolated ?
606  if (next1 == h0)
607  {
608  if (_delete_isolated_vertices)
609  status(v1).set_deleted(true);
610  set_isolated(v1);
611  }
612  else set_halfedge_handle(v1, next1);
613  }
614  }
615  }
616 
617  // update outgoing halfedge handles of remaining vertices
618  std::vector<VertexHandle>::iterator v_it(vhandles.begin()),
619  v_end(vhandles.end());
620  for (; v_it!=v_end; ++v_it)
622 }
623 
624 //-----------------------------------------------------------------------------
626 {
627  return VertexIter(*this, VertexHandle(0));
628 }
629 
630 //-----------------------------------------------------------------------------
632 {
633  return ConstVertexIter(*this, VertexHandle(0));
634 }
635 
636 //-----------------------------------------------------------------------------
638 {
639  return VertexIter(*this, VertexHandle( int(n_vertices() ) ));
640 }
641 
642 //-----------------------------------------------------------------------------
644 {
645  return ConstVertexIter(*this, VertexHandle( int(n_vertices()) ));
646 }
647 
648 //-----------------------------------------------------------------------------
650 {
651  return HalfedgeIter(*this, HalfedgeHandle(0));
652 }
653 
654 //-----------------------------------------------------------------------------
656 {
657  return ConstHalfedgeIter(*this, HalfedgeHandle(0));
658 }
659 
660 //-----------------------------------------------------------------------------
662 {
663  return HalfedgeIter(*this, HalfedgeHandle(int(n_halfedges())));
664 }
665 
666 //-----------------------------------------------------------------------------
668 {
669  return ConstHalfedgeIter(*this, HalfedgeHandle(int(n_halfedges())));
670 }
671 
672 //-----------------------------------------------------------------------------
674 {
675  return EdgeIter(*this, EdgeHandle(0));
676 }
677 
678 //-----------------------------------------------------------------------------
680 {
681  return ConstEdgeIter(*this, EdgeHandle(0));
682 }
683 
684 //-----------------------------------------------------------------------------
686 {
687  return EdgeIter(*this, EdgeHandle(int(n_edges())));
688 }
689 
690 //-----------------------------------------------------------------------------
692 {
693  return ConstEdgeIter(*this, EdgeHandle(int(n_edges())));
694 }
695 
696 //-----------------------------------------------------------------------------
698 {
699  return FaceIter(*this, FaceHandle(0));
700 }
701 
702 //-----------------------------------------------------------------------------
704 {
705  return ConstFaceIter(*this, FaceHandle(0));
706 }
707 
708 //-----------------------------------------------------------------------------
710 {
711  return FaceIter(*this, FaceHandle(int(n_faces())));
712 }
713 
714 //-----------------------------------------------------------------------------
716 {
717  return ConstFaceIter(*this, FaceHandle(int(n_faces())));
718 }
719 
720 //-----------------------------------------------------------------------------
722 {
723  HalfedgeHandle h0 = _hh;
724  HalfedgeHandle h1 = next_halfedge_handle(h0);
725  HalfedgeHandle o0 = opposite_halfedge_handle(h0);
726  HalfedgeHandle o1 = next_halfedge_handle(o0);
727 
728  // remove edge
729  collapse_edge(h0);
730 
731  // remove loops
732  if (next_halfedge_handle(next_halfedge_handle(h1)) == h1)
733  collapse_loop(next_halfedge_handle(h1));
734  if (next_halfedge_handle(next_halfedge_handle(o1)) == o1)
735  collapse_loop(o1);
736 }
737 
738 //-----------------------------------------------------------------------------
740 {
741  HalfedgeHandle h = _hh;
742  HalfedgeHandle hn = next_halfedge_handle(h);
743  HalfedgeHandle hp = prev_halfedge_handle(h);
744 
745  HalfedgeHandle o = opposite_halfedge_handle(h);
746  HalfedgeHandle on = next_halfedge_handle(o);
747  HalfedgeHandle op = prev_halfedge_handle(o);
748 
749  FaceHandle fh = face_handle(h);
750  FaceHandle fo = face_handle(o);
751 
752  VertexHandle vh = to_vertex_handle(h);
753  VertexHandle vo = to_vertex_handle(o);
754 
755 
756 
757  // halfedge -> vertex
758  for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it.is_valid(); ++vih_it)
759  set_vertex_handle(*vih_it, vh);
760 
761 
762  // halfedge -> halfedge
763  set_next_halfedge_handle(hp, hn);
764  set_next_halfedge_handle(op, on);
765 
766 
767  // face -> halfedge
768  if (fh.is_valid()) set_halfedge_handle(fh, hn);
769  if (fo.is_valid()) set_halfedge_handle(fo, on);
770 
771 
772  // vertex -> halfedge
773  if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn);
775  set_isolated(vo);
776 
777  // delete stuff
778  status(edge_handle(h)).set_deleted(true);
779  status(vo).set_deleted(true);
780 }
781 
782 //-----------------------------------------------------------------------------
784 {
785  HalfedgeHandle h0 = _hh;
786  HalfedgeHandle h1 = next_halfedge_handle(h0);
787 
788  HalfedgeHandle o0 = opposite_halfedge_handle(h0);
789  HalfedgeHandle o1 = opposite_halfedge_handle(h1);
790 
791  VertexHandle v0 = to_vertex_handle(h0);
792  VertexHandle v1 = to_vertex_handle(h1);
793 
794  FaceHandle fh = face_handle(h0);
795  FaceHandle fo = face_handle(o0);
796 
797 
798 
799  // is it a loop ?
800  assert ((next_halfedge_handle(h1) == h0) && (h1 != o0));
801 
802 
803  // halfedge -> halfedge
804  set_next_halfedge_handle(h1, next_halfedge_handle(o0));
805  set_next_halfedge_handle(prev_halfedge_handle(o0), h1);
806 
807 
808  // halfedge -> face
809  set_face_handle(h1, fo);
810 
811 
812  // vertex -> halfedge
813  set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0);
814  set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1);
815 
816 
817  // face -> halfedge
818  if (fo.is_valid() && halfedge_handle(fo) == o0)
819  {
820  set_halfedge_handle(fo, h1);
821  }
822 
823  // delete stuff
824  if (fh.is_valid())
825  {
826  set_halfedge_handle(fh, InvalidHalfedgeHandle);
827  status(fh).set_deleted(true);
828  }
829  status(edge_handle(h0)).set_deleted(true);
830 }
831 
832 //-----------------------------------------------------------------------------
834 {
835  HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
836  HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
837 
838  //FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid,
839  FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary
840 
841  HalfedgeHandle next_heh = next_halfedge_handle(heh0);
842  while (next_heh != heh0)
843  {//check if there are no other edges shared between fh0 & fh1
844  if (opposite_face_handle(next_heh) == fh1)
845  {
846  return false;
847  }
848  next_heh = next_halfedge_handle(next_heh);
849  }
850  return true;
851 }
852 
853 //-----------------------------------------------------------------------------
855 {
856  std::set<FaceHandle> nb_fhs;
857  for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it.is_valid(); ++cff_it)
858  {
859  if (nb_fhs.find(*cff_it) == nb_fhs.end())
860  {
861  nb_fhs.insert(*cff_it);
862  }
863  else
864  {//there is more than one link
865  return false;
866  }
867  }
868  return true;
869 }
870 
871 //-----------------------------------------------------------------------------
872 PolyConnectivity::FaceHandle
874 {
875  //don't allow "dangling" vertices and edges
876  assert(!status(_eh).deleted() && is_simple_link(_eh));
877 
878  HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
879  HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
880 
881  //deal with the faces
882  FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1);
883  if (!del_fh.is_valid())
884  {//boundary case - we must delete the rem_fh
885  std::swap(del_fh, rem_fh);
886  }
887  assert(del_fh.is_valid());
888 /* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it)
889  {//set the face handle of the halfedges of del_fh to point to rem_fh
890  set_face_handle(fh_it, rem_fh);
891  } */
892  //fix the halfedge relations
893  HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0);
894  HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1);
895 
896  HalfedgeHandle next_heh0 = next_halfedge_handle(heh0);
897  HalfedgeHandle next_heh1 = next_halfedge_handle(heh1);
898 
899  set_next_halfedge_handle(prev_heh0, next_heh1);
900  set_next_halfedge_handle(prev_heh1, next_heh0);
901  //correct outgoing vertex handles for the _eh vertices (if needed)
902  VertexHandle vh0 = to_vertex_handle(heh0);
903  VertexHandle vh1 = to_vertex_handle(heh1);
904 
905  if (halfedge_handle(vh0) == heh1)
906  {
907  set_halfedge_handle(vh0, next_heh0);
908  }
909  if (halfedge_handle(vh1) == heh0)
910  {
911  set_halfedge_handle(vh1, next_heh1);
912  }
913 
914  //correct the hafledge handle of rem_fh if needed and preserve its first vertex
915  if (halfedge_handle(rem_fh) == heh0)
916  {//rem_fh is the face at heh0
917  set_halfedge_handle(rem_fh, prev_heh1);
918  }
919  else if (halfedge_handle(rem_fh) == heh1)
920  {//rem_fh is the face at heh1
921  set_halfedge_handle(rem_fh, prev_heh0);
922  }
923  for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it.is_valid(); ++fh_it)
924  {//set the face handle of the halfedges of del_fh to point to rem_fh
925  set_face_handle(*fh_it, rem_fh);
926  }
927 
928  status(_eh).set_deleted(true);
929  status(del_fh).set_deleted(true);
930  return rem_fh;//returns the remaining face handle
931 }
932 
933 //-----------------------------------------------------------------------------
935 {
936  //this does not work without prev_halfedge_handle
937  assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev));
938  //shoudl be deleted
939  assert(status(_eh).deleted());
940  status(_eh).set_deleted(false);
941 
942  HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
943  HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
944  FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1);
945  if (!del_fh.is_valid())
946  {//boundary case - we must delete the rem_fh
947  std::swap(del_fh, rem_fh);
948  }
949  assert(status(del_fh).deleted());
950  status(del_fh).set_deleted(false);
951 
952  //restore halfedge relations
953  HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0);
954  HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1);
955 
956  HalfedgeHandle next_heh0 = next_halfedge_handle(heh0);
957  HalfedgeHandle next_heh1 = next_halfedge_handle(heh1);
958 
959  set_next_halfedge_handle(prev_heh0, heh0);
960  set_prev_halfedge_handle(next_heh0, heh0);
961 
962  set_next_halfedge_handle(prev_heh1, heh1);
963  set_prev_halfedge_handle(next_heh1, heh1);
964 
965  for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it.is_valid(); ++fh_it)
966  {//reassign halfedges to del_fh
967  set_face_handle(*fh_it, del_fh);
968  }
969 
970  if (face_handle(halfedge_handle(rem_fh)) == del_fh)
971  {//correct the halfedge handle of rem_fh
972  if (halfedge_handle(rem_fh) == prev_heh0)
973  {//rem_fh is the face at heh1
974  set_halfedge_handle(rem_fh, heh1);
975  }
976  else
977  {//rem_fh is the face at heh0
978  assert(halfedge_handle(rem_fh) == prev_heh1);
979  set_halfedge_handle(rem_fh, heh0);
980  }
981  }
982 }
983 
984 //-----------------------------------------------------------------------------
987 {
988  assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case
989  assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done
990  VertexHandle vh0 = to_vertex_handle(_prev_heh);
991  VertexHandle vh1 = from_vertex_handle(_next_heh);
992  //create the link between vh0 and vh1
993  HalfedgeHandle heh0 = new_edge(vh0, vh1);
994  HalfedgeHandle heh1 = opposite_halfedge_handle(heh0);
995  HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh);
996  HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh);
997  set_next_halfedge_handle(_prev_heh, heh0);
998  set_next_halfedge_handle(heh0, _next_heh);
999  set_next_halfedge_handle(prev_next_heh, heh1);
1000  set_next_halfedge_handle(heh1, next_prev_heh);
1001 
1002  //now set the face handles - the new face is assigned to heh0
1003  FaceHandle new_fh = new_face();
1004  set_halfedge_handle(new_fh, heh0);
1005  for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it.is_valid(); ++fh_it)
1006  {
1007  set_face_handle(*fh_it, new_fh);
1008  }
1009  FaceHandle old_fh = face_handle(next_prev_heh);
1010  set_face_handle(heh1, old_fh);
1011  if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh)
1012  {//fh pointed to one of the halfedges now assigned to new_fh
1013  set_halfedge_handle(old_fh, heh1);
1014  }
1017  return heh0;
1018 }
1019 
1020 //-----------------------------------------------------------------------------
1022 {
1023  /*
1024  Split an arbitrary face into triangles by connecting
1025  each vertex of fh after its second to vh.
1026 
1027  - fh will remain valid (it will become one of the
1028  triangles)
1029  - the halfedge handles of the new triangles will
1030  point to the old halfedges
1031  */
1032 
1033  HalfedgeHandle base_heh(halfedge_handle(_fh));
1034  VertexHandle start_vh = from_vertex_handle(base_heh);
1035  HalfedgeHandle prev_heh(prev_halfedge_handle(base_heh));
1036  HalfedgeHandle next_heh(next_halfedge_handle(base_heh));
1037 
1038  while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh)
1039  {
1040  HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh));
1041 
1042  FaceHandle new_fh = new_face();
1043  set_halfedge_handle(new_fh, base_heh);
1044 
1045  HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh);
1046 
1047  set_next_halfedge_handle(base_heh, next_heh);
1048  set_next_halfedge_handle(next_heh, new_heh);
1049  set_next_halfedge_handle(new_heh, base_heh);
1050 
1051  set_face_handle(base_heh, new_fh);
1052  set_face_handle(next_heh, new_fh);
1053  set_face_handle(new_heh, new_fh);
1054 
1055  copy_all_properties(prev_heh, new_heh, true);
1056  copy_all_properties(prev_heh, opposite_halfedge_handle(new_heh), true);
1057  copy_all_properties(_fh, new_fh, true);
1058 
1059  base_heh = opposite_halfedge_handle(new_heh);
1060  next_heh = next_next_heh;
1061  }
1062  set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh
1063 
1064  set_next_halfedge_handle(base_heh, next_heh);
1065  set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh);
1066 
1067  set_face_handle(base_heh, _fh);
1068 }
1069 
1070 //-----------------------------------------------------------------------------
1072 {
1073  /* The iterators will stay valid, even though new faces are added,
1074  because they are now implemented index-based instead of
1075  pointer-based.
1076  */
1077  FaceIter f_it(faces_begin()), f_end(faces_end());
1078  for (; f_it!=f_end; ++f_it)
1079  triangulate(*f_it);
1080 }
1081 
1082 //-----------------------------------------------------------------------------
1084 {
1085  HalfedgeHandle hend = halfedge_handle(fh);
1086  HalfedgeHandle hh = next_halfedge_handle(hend);
1087 
1088  HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh);
1089 
1090  set_next_halfedge_handle(hend, hold);
1091  set_face_handle(hold, fh);
1092 
1093  hold = opposite_halfedge_handle(hold);
1094 
1095  while (hh != hend) {
1096 
1097  HalfedgeHandle hnext = next_halfedge_handle(hh);
1098 
1099  FaceHandle fnew = new_face();
1100  set_halfedge_handle(fnew, hh);
1101 
1102  HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh);
1103 
1104  set_next_halfedge_handle(hnew, hold);
1105  set_next_halfedge_handle(hold, hh);
1106  set_next_halfedge_handle(hh, hnew);
1107 
1108  set_face_handle(hnew, fnew);
1109  set_face_handle(hold, fnew);
1110  set_face_handle(hh, fnew);
1111 
1112  hold = opposite_halfedge_handle(hnew);
1113 
1114  hh = hnext;
1115  }
1116 
1117  set_next_halfedge_handle(hold, hend);
1118  set_next_halfedge_handle(next_halfedge_handle(hend), hold);
1119 
1120  set_face_handle(hold, fh);
1121 
1122  set_halfedge_handle(vh, hold);
1123 }
1124 
1125 
1127 
1128  // Split the given face (fh will still be valid)
1129  split(fh, vh);
1130 
1131  // Copy the property of the original face to all new faces
1132  for(VertexFaceIter vf_it = vf_iter(vh); vf_it.is_valid(); ++vf_it)
1133  copy_all_properties(fh, *vf_it);
1134 }
1135 
1136 //-----------------------------------------------------------------------------
1138 {
1139  uint count(0);
1140  for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it.is_valid(); ++vv_it)
1141  ++count;
1142  return count;
1143 }
1144 
1145 //-----------------------------------------------------------------------------
1147 {
1148  uint count(0);
1149  for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it.is_valid(); ++fv_it)
1150  ++count;
1151  return count;
1152 }
1153 
1154 //-----------------------------------------------------------------------------
1156 {
1157  HalfedgeHandle h0 = halfedge_handle(_eh, 0);
1158  HalfedgeHandle h1 = halfedge_handle(_eh, 1);
1159 
1160  VertexHandle vfrom = from_vertex_handle(h0);
1161 
1162  HalfedgeHandle ph0 = prev_halfedge_handle(h0);
1163  //HalfedgeHandle ph1 = prev_halfedge_handle(h1);
1164 
1165  //HalfedgeHandle nh0 = next_halfedge_handle(h0);
1166  HalfedgeHandle nh1 = next_halfedge_handle(h1);
1167 
1168  bool boundary0 = is_boundary(h0);
1169  bool boundary1 = is_boundary(h1);
1170 
1171  //add the new edge
1172  HalfedgeHandle new_e = new_edge(from_vertex_handle(h0), _vh);
1173 
1174  //fix the vertex of the opposite halfedge
1175  set_vertex_handle(h1, _vh);
1176 
1177  //fix the halfedge connectivity
1178  set_next_halfedge_handle(new_e, h0);
1179  set_next_halfedge_handle(h1, opposite_halfedge_handle(new_e));
1180 
1181  set_next_halfedge_handle(ph0, new_e);
1182  set_next_halfedge_handle(opposite_halfedge_handle(new_e), nh1);
1183 
1184 // set_prev_halfedge_handle(new_e, ph0);
1185 // set_prev_halfedge_handle(opposite_halfedge_handle(new_e), h1);
1186 
1187 // set_prev_halfedge_handle(nh1, opposite_halfedge_handle(new_e));
1188 // set_prev_halfedge_handle(h0, new_e);
1189 
1190  if (!boundary0)
1191  {
1192  set_face_handle(new_e, face_handle(h0));
1193  }
1194  else
1195  {
1196  set_boundary(new_e);
1197  }
1198 
1199  if (!boundary1)
1200  {
1201  set_face_handle(opposite_halfedge_handle(new_e), face_handle(h1));
1202  }
1203  else
1204  {
1205  set_boundary(opposite_halfedge_handle(new_e));
1206  }
1207 
1208  set_halfedge_handle( _vh, h0 );
1209  adjust_outgoing_halfedge( _vh );
1210 
1211  if (halfedge_handle(vfrom) == h0)
1212  {
1213  set_halfedge_handle(vfrom, new_e);
1214  adjust_outgoing_halfedge( vfrom );
1215  }
1216 }
1217 
1218 //-----------------------------------------------------------------------------
1219 
1221 {
1222  // Split the edge (handle is kept!)
1223  split_edge(_eh, _vh);
1224 
1225  // Navigate to the new edge
1226  EdgeHandle eh0 = edge_handle( next_halfedge_handle( halfedge_handle(_eh, 1) ) );
1227 
1228  // Copy the property from the original to the new edge
1229  copy_all_properties(_eh, eh0);
1230 }
1231 
1232 } // namespace OpenMesh
1233 
ConstVertexVertexIter cvv_iter(VertexHandle _vh) const
const vertex circulator
void collapse(HalfedgeHandle _heh)
void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices=true)
bool is_collapse_ok(HalfedgeHandle _he)
void split_edge_copy(EdgeHandle _eh, VertexHandle _vh)
HalfedgeIter halfedges_end()
End iterator for halfedges.
void split(FaceHandle _fh, VertexHandle _vh)
Face split (= 1-to-n split).
ConstFaceFaceIter cff_iter(FaceHandle _fh) const
const face - face circulator
Iterators::GenericIteratorT< This, This::VertexHandle, ArrayKernel,&ArrayKernel::has_vertex_status,&ArrayKernel::n_vertices > VertexIter
Linear iterator.
Iterators::GenericIteratorT< This, This::EdgeHandle, ArrayKernel,&ArrayKernel::has_edge_status,&ArrayKernel::n_edges > EdgeIter
Linear iterator.
HalfedgeIter halfedges_begin()
Begin iterator for halfedges.
FaceIter faces_end()
End iterator for faces.
ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const
const face - edge circulator
void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true)
void set_deleted(bool _b)
set deleted
Definition: Status.hh:110
HalfedgeIter ConstHalfedgeIter
Linear iterator.
void split_copy(FaceHandle _fh, VertexHandle _vh)
Face split (= 1-to-n split).
const StatusInfo & status(VertexHandle _vh) const
Status Query API.
Definition: ArrayKernel.hh:506
FaceHandle opposite_face_handle(HalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
bool is_valid() const
The handle is valid iff the index is not equal to -1.
Definition: Handles.hh:77
Handle for a halfedge entity.
Definition: Handles.hh:132
HalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const
Find halfedge from _vh0 to _vh1. Returns invalid handle if not found.
void set_tagged(bool _b)
set tagged
Definition: Status.hh:140
void copy_all_properties(VertexHandle _vh_from, VertexHandle _vh_to, bool _copyBuildIn=false)
Definition: BaseKernel.hh:476
bool is_manifold(VertexHandle _vh) const
Is (the mesh at) vertex _vh two-manifold ?
EdgeIter edges_begin()
Begin iterator for edges.
FaceIter faces_begin()
Begin iterator for faces.
bool is_simple_link(EdgeHandle _eh) const
static const VertexHandle InvalidVertexHandle
Invalid handle.
VertexFaceIter vf_iter(VertexHandle _vh)
vertex - face circulator
void reinsert_edge(EdgeHandle _eh)
HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh)
FaceIter ConstFaceIter
Linear iterator.
uint valence(VertexHandle _vh) const
Vertex valence.
bool tagged() const
is tagged ?
Definition: Status.hh:138
bool is_simply_connected(FaceHandle _fh) const
static const EdgeHandle InvalidEdgeHandle
Invalid handle.
VertexVertexIter vv_iter(VertexHandle _vh)
vertex - vertex circulator
void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true)
Handle for a vertex entity.
Definition: Handles.hh:125
Iterators::GenericIteratorT< This, This::HalfedgeHandle, ArrayKernel,&ArrayKernel::has_halfedge_status,&ArrayKernel::n_halfedges > HalfedgeIter
Linear iterator.
void split_edge(EdgeHandle _eh, VertexHandle _vh)
VertexIter vertices_begin()
Begin iterator for vertices.
void triangulate()
triangulate the entire mesh
Handle for a edge entity.
Definition: Handles.hh:139
VertexIter vertices_end()
End iterator for vertices.
void collapse_loop(HalfedgeHandle _hh)
Helper for halfedge collapse.
FaceHalfedgeIter fh_end(FaceHandle _fh)
face - halfedge circulator
bool deleted() const
is deleted ?
Definition: Status.hh:108
static const HalfedgeHandle InvalidHalfedgeHandle
Invalid handle.
Handle for a face entity.
Definition: Handles.hh:146
bool is_boundary(HalfedgeHandle _heh) const
Check if the halfedge is at the boundary.
Iterators::GenericIteratorT< This, This::FaceHandle, ArrayKernel,&ArrayKernel::has_face_status,&ArrayKernel::n_faces > FaceIter
Linear iterator.
void adjust_outgoing_halfedge(VertexHandle _vh)
EdgeIter edges_end()
End iterator for edges.
ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const
const vertex - outgoing halfedge circulator
FaceHalfedgeIter fh_iter(FaceHandle _fh)
face - halfedge circulator
VertexIter ConstVertexIter
Linear iterator.
static const FaceHandle InvalidFaceHandle
Invalid handle.
VertexIHalfedgeIter vih_iter(VertexHandle _vh)
vertex - incoming halfedge circulator
FaceHandle add_face(const std::vector< VertexHandle > &_vhandles)
Add and connect a new face.
void collapse_edge(HalfedgeHandle _hh)
Helper for halfedge collapse.
ConstFaceVertexIter cfv_iter(FaceHandle _fh) const
const face - vertex circulator
EdgeIter ConstEdgeIter
Linear iterator.
FaceHandle remove_edge(EdgeHandle _eh)