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