Developer Documentation
Loading...
Searching...
No Matches
PolyConnectivity.cc
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, 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
48namespace OpenMesh {
49
50const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle;
51const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle;
52const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle;
53const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle;
54
55//-----------------------------------------------------------------------------
56
58{
59 assert(_start_vh.is_valid() && _end_vh.is_valid());
60
61 for (ConstVertexOHalfedgeIter voh_it = cvoh_iter(_start_vh); voh_it.is_valid(); ++voh_it)
62 if (to_vertex_handle(*voh_it) == _end_vh)
63 return *voh_it;
64
66}
67
68
69bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const
70{
71 for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit.is_valid(); ++cfeit)
72 if (is_boundary( *cfeit ) )
73 return true;
74
75 if (_check_vertex)
76 {
77 for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit.is_valid(); ++cfvit)
78 if (is_boundary( *cfvit ) )
79 return true;
80 }
81 return false;
82}
83
85{
86 /* The vertex is non-manifold if more than one gap exists, i.e.
87 more than one outgoing boundary halfedge. If (at least) one
88 boundary halfedge exists, the vertex' halfedge must be a
89 boundary halfedge. If iterating around the vertex finds another
90 boundary halfedge, the vertex is non-manifold. */
91
92 ConstVertexOHalfedgeIter vh_it(*this, _vh);
93 if (vh_it.is_valid())
94 for (++vh_it; vh_it.is_valid(); ++vh_it)
95 if (is_boundary(*vh_it))
96 return false;
97 return true;
98}
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
117PolyConnectivity::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 make_smart(InvalidFaceHandle, this);
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 make_smart(InvalidFaceHandle, this);
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 =
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 make_smart(InvalidFaceHandle, this);
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 make_smart(fh, this);
301}
302
303//-----------------------------------------------------------------------------
304
306{
307 // Check if we have been given a degenerate configuration (2 vertices are identical)
308 assert(_vh0!=_vh1);
309 assert(_vh0!=_vh2);
310 assert(_vh1!=_vh2);
311 assert(_vh0!=_vh3);
312 assert(_vh1!=_vh3);
313 assert(_vh2!=_vh3);
314
315 VertexHandle vhs[4] = { _vh0, _vh1, _vh2, _vh3 };
316 return add_face(vhs, 4);
317}
318
319//-----------------------------------------------------------------------------
320
322{
323 // Check if we have been given a degenerate configuration (2 vertices are identical)
324 assert(_vh0!=_vh1);
325 assert(_vh0!=_vh2);
326 assert(_vh1!=_vh2);
327
328 VertexHandle vhs[3] = { _vh0, _vh1, _vh2 };
329 return add_face(vhs, 3);
330}
331
332//-----------------------------------------------------------------------------
333
334SmartFaceHandle PolyConnectivity::add_face(const std::vector<VertexHandle>& _vhandles)
335{ return add_face(&_vhandles.front(), _vhandles.size()); }
336
337//-----------------------------------------------------------------------------
338
339SmartFaceHandle PolyConnectivity::add_face(const std::vector<SmartVertexHandle>& _vhandles)
340{
341 std::vector<VertexHandle> vhandles(_vhandles.begin(), _vhandles.end());
342 return add_face(&vhandles.front(), vhandles.size());
343}
344
345
346//-----------------------------------------------------------------------------
348{
349 //is edge already deleteed?
350 if (status(edge_handle(v0v1)).deleted())
351 {
352 return false;
353 }
354
356 VertexHandle v0(to_vertex_handle(v1v0));
357 VertexHandle v1(to_vertex_handle(v0v1));
358
359 bool v0v1_triangle = false;
360 bool v1v0_triangle = false;
361
362 if (!is_boundary(v0v1))
363 v0v1_triangle = valence(face_handle(v0v1)) == 3;
364
365 if (!is_boundary(v1v0))
366 v1v0_triangle = valence(face_handle(v1v0)) == 3;
367
368 //in a quadmesh we dont have the "next" or "previous" vhandle, so we need to look at previous and next on both sides
369 //VertexHandle v_01_p = from_vertex_handle(prev_halfedge_handle(v0v1));
370 VertexHandle v_01_n = to_vertex_handle(next_halfedge_handle(v0v1));
371
372 //VertexHandle v_10_p = from_vertex_handle(prev_halfedge_handle(v1v0));
373 VertexHandle v_10_n = to_vertex_handle(next_halfedge_handle(v1v0));
374
375 //are the vertices already deleted ?
376 if (status(v0).deleted() || status(v1).deleted())
377 {
378 return false;
379 }
380
381 //the edges v1-vl and vl-v0 must not be both boundary edges
382 //this test makes only sense in a polymesh if the side face is a triangle
383 VertexHandle vl;
384 if (!is_boundary(v0v1))
385 {
386 if (v0v1_triangle)
387 {
390
391 vl = to_vertex_handle(h1);
392
394 return false;
395 }
396 }
397
398 //the edges v0-vr and vr-v1 must not be both boundary edges
399 //this test makes only sense in a polymesh if the side face is a triangle
400 VertexHandle vr;
401 if (!is_boundary(v1v0))
402 {
403 if (v1v0_triangle)
404 {
407
408 vr = to_vertex_handle(h1);
409
411 return false;
412 }
413 }
414
415 // if vl and vr are equal and valid (e.g. triangle case) -> fail
416 if ( vl.is_valid() && (vl == vr)) return false;
417
418 // edge between two boundary vertices should be a boundary edge
419 if ( is_boundary(v0) && is_boundary(v1) && !is_boundary(v0v1) && !is_boundary(v1v0))
420 return false;
421
422 VertexVertexIter vv_it;
423 // test intersection of the one-rings of v0 and v1
424 for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it)
425 {
426 status(*vv_it).set_tagged(false);
427 }
428
429 for (vv_it = vv_iter(v1); vv_it.is_valid(); ++vv_it)
430 {
431 status(*vv_it).set_tagged(true);
432 }
433
434 for (vv_it = vv_iter(v0); vv_it.is_valid(); ++vv_it)
435 {
436 if (status(*vv_it).tagged() &&
437 !(*vv_it == v_01_n && v0v1_triangle) &&
438 !(*vv_it == v_10_n && v1v0_triangle)
439 )
440 {
441 return false;
442 }
443 }
444
445 //test for a face on the backside/other side that might degenerate
446 if (v0v1_triangle)
447 {
448 HalfedgeHandle one, two;
449 one = next_halfedge_handle(v0v1);
450 two = next_halfedge_handle(one);
451
452 one = opposite_halfedge_handle(one);
453 two = opposite_halfedge_handle(two);
454
455 if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3)
456 {
457 return false;
458 }
459 }
460
461 if (v1v0_triangle)
462 {
463 HalfedgeHandle one, two;
464 one = next_halfedge_handle(v1v0);
465 two = next_halfedge_handle(one);
466
467 one = opposite_halfedge_handle(one);
468 two = opposite_halfedge_handle(two);
469
470 if (face_handle(one) == face_handle(two) && valence(face_handle(one)) != 3)
471 {
472 return false;
473 }
474 }
475
476 if (status(*vv_it).tagged() && v_01_n == v_10_n && v0v1_triangle && v1v0_triangle)
477 {
478 return false;
479 }
480
481 // passed all tests
482 return true;
483}
484
485//-----------------------------------------------------------------------------
486
487void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices)
488{
489 // store incident faces
490 std::vector<FaceHandle> face_handles;
491 face_handles.reserve(8);
492 for (VFIter vf_it(vf_iter(_vh)); vf_it.is_valid(); ++vf_it)
493 face_handles.push_back(*vf_it);
494
495
496 // delete collected faces
497 for (auto delete_fh_it : face_handles)
498 delete_face(delete_fh_it, _delete_isolated_vertices);
499
500 status(_vh).set_deleted(true);
501}
502
503//-----------------------------------------------------------------------------
504
505void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices)
506{
509
510 if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices);
511 if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices);
512
513 // If there is no face, we delete the edge
514 // here
515 if ( ! fh0.is_valid() && !fh1.is_valid()) {
516 // mark edge deleted if the mesh has a edge status
517 if ( has_edge_status() )
518 status(_eh).set_deleted(true);
519
520 // mark corresponding halfedges as deleted
521 // As the deleted edge is boundary,
522 // all corresponding halfedges will also be deleted.
523 if ( has_halfedge_status() ) {
524 status(halfedge_handle(_eh, 0)).set_deleted(true);
525 status(halfedge_handle(_eh, 1)).set_deleted(true);
526 }
527 }
528}
529
530//-----------------------------------------------------------------------------
531
532void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices)
533{
534 assert(_fh.is_valid() && !status(_fh).deleted());
535
536 // mark face deleted
537 status(_fh).set_deleted(true);
538
539
540 // this vector will hold all boundary edges of face _fh
541 // these edges will be deleted
542 std::vector<EdgeHandle> deleted_edges;
543 deleted_edges.reserve(3);
544
545
546 // this vector will hold all vertices of face _fh
547 // for updating their outgoing halfedge
548 std::vector<VertexHandle> vhandles;
549 vhandles.reserve(3);
550
551
552 // for all halfedges of face _fh do:
553 // 1) invalidate face handle.
554 // 2) collect all boundary halfedges, set them deleted
555 // 3) store vertex handles
557 for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it.is_valid(); ++fh_it)
558 {
559 hh = *fh_it;
560
561 set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle);
562
564 deleted_edges.push_back(edge_handle(hh));
565
566 vhandles.push_back(to_vertex_handle(hh));
567 }
568
569
570 // delete all collected (half)edges
571 // these edges were all boundary
572 // delete isolated vertices (if _delete_isolated_vertices is true)
573 if (!deleted_edges.empty())
574 {
575 std::vector<EdgeHandle>::iterator del_it(deleted_edges.begin()),
576 del_end(deleted_edges.end());
577 HalfedgeHandle h0, h1, next0, next1, prev0, prev1;
578 VertexHandle v0, v1;
579
580 for (; del_it!=del_end; ++del_it)
581 {
582 h0 = halfedge_handle(*del_it, 0);
583 v0 = to_vertex_handle(h0);
584 next0 = next_halfedge_handle(h0);
585 prev0 = prev_halfedge_handle(h0);
586
587 h1 = halfedge_handle(*del_it, 1);
588 v1 = to_vertex_handle(h1);
589 next1 = next_halfedge_handle(h1);
590 prev1 = prev_halfedge_handle(h1);
591
592 // adjust next and prev handles
593 set_next_halfedge_handle(prev0, next1);
594 set_next_halfedge_handle(prev1, next0);
595
596 // mark edge deleted if the mesh has a edge status
597 if ( has_edge_status() )
598 status(*del_it).set_deleted(true);
599
600
601 // mark corresponding halfedges as deleted
602 // As the deleted edge is boundary,
603 // all corresponding halfedges will also be deleted.
604 if ( has_halfedge_status() ) {
605 status(h0).set_deleted(true);
606 status(h1).set_deleted(true);
607 }
608
609 // update v0
610 if (halfedge_handle(v0) == h1)
611 {
612 // isolated ?
613 if (next0 == h1)
614 {
615 if (_delete_isolated_vertices)
616 status(v0).set_deleted(true);
617 set_isolated(v0);
618 }
619 else set_halfedge_handle(v0, next0);
620 }
621
622 // update v1
623 if (halfedge_handle(v1) == h0)
624 {
625 // isolated ?
626 if (next1 == h0)
627 {
628 if (_delete_isolated_vertices)
629 status(v1).set_deleted(true);
630 set_isolated(v1);
631 }
632 else set_halfedge_handle(v1, next1);
633 }
634 }
635 }
636
637 // update outgoing halfedge handles of remaining vertices
638 std::vector<VertexHandle>::iterator v_it(vhandles.begin()),
639 v_end(vhandles.end());
640 for (; v_it!=v_end; ++v_it)
642}
643
644
645//-----------------------------------------------------------------------------
647{
648 HalfedgeHandle h0 = _hh;
652
653 // remove edge
654 collapse_edge(h0);
655
656 // remove loops
660 collapse_loop(o1);
661}
662
663//-----------------------------------------------------------------------------
665{
666 HalfedgeHandle h = _hh;
669
673
674 FaceHandle fh = face_handle(h);
675 FaceHandle fo = face_handle(o);
676
677 VertexHandle vh = to_vertex_handle(h);
678 VertexHandle vo = to_vertex_handle(o);
679
680
681
682 // halfedge -> vertex
683 for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it.is_valid(); ++vih_it)
684 set_vertex_handle(*vih_it, vh);
685
686
687 // halfedge -> halfedge
688 set_next_halfedge_handle(hp, hn);
689 set_next_halfedge_handle(op, on);
690
691
692 // face -> halfedge
693 if (fh.is_valid()) set_halfedge_handle(fh, hn);
694 if (fo.is_valid()) set_halfedge_handle(fo, on);
695
696
697 // vertex -> halfedge
698 if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn);
700 set_isolated(vo);
701
702 // delete stuff
704 status(vo).set_deleted(true);
705 if (has_halfedge_status())
706 {
707 status(h).set_deleted(true);
708 status(o).set_deleted(true);
709 }
710}
711
712//-----------------------------------------------------------------------------
714{
715 HalfedgeHandle h0 = _hh;
717
720
721 VertexHandle v0 = to_vertex_handle(h0);
722 VertexHandle v1 = to_vertex_handle(h1);
723
724 FaceHandle fh = face_handle(h0);
725 FaceHandle fo = face_handle(o0);
726
727
728
729 // is it a loop ?
730 assert ((next_halfedge_handle(h1) == h0) && (h1 != o0));
731
732
733 // halfedge -> halfedge
734 set_next_halfedge_handle(h1, next_halfedge_handle(o0));
735 set_next_halfedge_handle(prev_halfedge_handle(o0), h1);
736
737
738 // halfedge -> face
739 set_face_handle(h1, fo);
740
741
742 // vertex -> halfedge
743 set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0);
744 set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1);
745
746
747 // face -> halfedge
748 if (fo.is_valid() && halfedge_handle(fo) == o0)
749 {
750 set_halfedge_handle(fo, h1);
751 }
752
753 // delete stuff
754 if (fh.is_valid())
755 {
756 set_halfedge_handle(fh, InvalidHalfedgeHandle);
757 status(fh).set_deleted(true);
758 }
759 status(edge_handle(h0)).set_deleted(true);
760 if (has_halfedge_status())
761 {
762 status(h0).set_deleted(true);
763 status(o0).set_deleted(true);
764 }
765}
766
767//-----------------------------------------------------------------------------
769{
770 HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
771 HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
772
773 //FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid,
774 FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary
775
776 HalfedgeHandle next_heh = next_halfedge_handle(heh0);
777 while (next_heh != heh0)
778 {//check if there are no other edges shared between fh0 & fh1
779 if (opposite_face_handle(next_heh) == fh1)
780 {
781 return false;
782 }
783 next_heh = next_halfedge_handle(next_heh);
784 }
785 return true;
786}
787
788//-----------------------------------------------------------------------------
790{
791 std::set<FaceHandle> nb_fhs;
792 for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it.is_valid(); ++cff_it)
793 {
794 if (nb_fhs.find(*cff_it) == nb_fhs.end())
795 {
796 nb_fhs.insert(*cff_it);
797 }
798 else
799 {//there is more than one link
800 return false;
801 }
802 }
803 return true;
804}
805
806//-----------------------------------------------------------------------------
809{
810 //don't allow "dangling" vertices and edges
811 assert(!status(_eh).deleted() && is_simple_link(_eh));
812
813 HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
814 HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
815
816 //deal with the faces
817 FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1);
818 if (!del_fh.is_valid())
819 {//boundary case - we must delete the rem_fh
820 std::swap(del_fh, rem_fh);
821 }
822 assert(del_fh.is_valid());
823/* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it)
824 {//set the face handle of the halfedges of del_fh to point to rem_fh
825 set_face_handle(fh_it, rem_fh);
826 } */
827 //fix the halfedge relations
828 HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0);
829 HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1);
830
831 HalfedgeHandle next_heh0 = next_halfedge_handle(heh0);
832 HalfedgeHandle next_heh1 = next_halfedge_handle(heh1);
833
834 set_next_halfedge_handle(prev_heh0, next_heh1);
835 set_next_halfedge_handle(prev_heh1, next_heh0);
836 //correct outgoing vertex handles for the _eh vertices (if needed)
837 VertexHandle vh0 = to_vertex_handle(heh0);
838 VertexHandle vh1 = to_vertex_handle(heh1);
839
840 if (halfedge_handle(vh0) == heh1)
841 {
842 set_halfedge_handle(vh0, next_heh0);
843 }
844 if (halfedge_handle(vh1) == heh0)
845 {
846 set_halfedge_handle(vh1, next_heh1);
847 }
848
849 //correct the hafledge handle of rem_fh if needed and preserve its first vertex
850 if (halfedge_handle(rem_fh) == heh0)
851 {//rem_fh is the face at heh0
852 set_halfedge_handle(rem_fh, prev_heh1);
853 }
854 else if (halfedge_handle(rem_fh) == heh1)
855 {//rem_fh is the face at heh1
856 set_halfedge_handle(rem_fh, prev_heh0);
857 }
858 for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it.is_valid(); ++fh_it)
859 {//set the face handle of the halfedges of del_fh to point to rem_fh
860 set_face_handle(*fh_it, rem_fh);
861 }
862
863 status(_eh).set_deleted(true);
864 status(del_fh).set_deleted(true);
865 return rem_fh;//returns the remaining face handle
866}
867
868//-----------------------------------------------------------------------------
870{
871 //this does not work without prev_halfedge_handle
872 assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev));
873 //shoudl be deleted
874 assert(status(_eh).deleted());
875 status(_eh).set_deleted(false);
876
877 HalfedgeHandle heh0 = halfedge_handle(_eh, 0);
878 HalfedgeHandle heh1 = halfedge_handle(_eh, 1);
879 FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1);
880 if (!del_fh.is_valid())
881 {//boundary case - we must delete the rem_fh
882 std::swap(del_fh, rem_fh);
883 }
884 assert(status(del_fh).deleted());
885 status(del_fh).set_deleted(false);
886
887 //restore halfedge relations
888 HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0);
889 HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1);
890
891 HalfedgeHandle next_heh0 = next_halfedge_handle(heh0);
892 HalfedgeHandle next_heh1 = next_halfedge_handle(heh1);
893
894 set_next_halfedge_handle(prev_heh0, heh0);
895 set_prev_halfedge_handle(next_heh0, heh0);
896
897 set_next_halfedge_handle(prev_heh1, heh1);
898 set_prev_halfedge_handle(next_heh1, heh1);
899
900 for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it.is_valid(); ++fh_it)
901 {//reassign halfedges to del_fh
902 set_face_handle(*fh_it, del_fh);
903 }
904
905 if (face_handle(halfedge_handle(rem_fh)) == del_fh)
906 {//correct the halfedge handle of rem_fh
907 if (halfedge_handle(rem_fh) == prev_heh0)
908 {//rem_fh is the face at heh1
909 set_halfedge_handle(rem_fh, heh1);
910 }
911 else
912 {//rem_fh is the face at heh0
913 assert(halfedge_handle(rem_fh) == prev_heh1);
914 set_halfedge_handle(rem_fh, heh0);
915 }
916 }
917}
918
919//-----------------------------------------------------------------------------
922{
923 assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case
924 assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done
925 VertexHandle vh0 = to_vertex_handle(_prev_heh);
926 VertexHandle vh1 = from_vertex_handle(_next_heh);
927 //create the link between vh0 and vh1
928 HalfedgeHandle heh0 = new_edge(vh0, vh1);
930 HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh);
931 HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh);
932 set_next_halfedge_handle(_prev_heh, heh0);
933 set_next_halfedge_handle(heh0, _next_heh);
934 set_next_halfedge_handle(prev_next_heh, heh1);
935 set_next_halfedge_handle(heh1, next_prev_heh);
936
937 //now set the face handles - the new face is assigned to heh0
938 FaceHandle new_fh = new_face();
939 set_halfedge_handle(new_fh, heh0);
940 for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it.is_valid(); ++fh_it)
941 {
942 set_face_handle(*fh_it, new_fh);
943 }
944 FaceHandle old_fh = face_handle(next_prev_heh);
945 set_face_handle(heh1, old_fh);
946 if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh)
947 {//fh pointed to one of the halfedges now assigned to new_fh
948 set_halfedge_handle(old_fh, heh1);
949 }
952 return heh0;
953}
954
955//-----------------------------------------------------------------------------
957{
958 /*
959 Split an arbitrary face into triangles by connecting
960 each vertex of fh after its second to vh.
961
962 - fh will remain valid (it will become one of the
963 triangles)
964 - the halfedge handles of the new triangles will
965 point to the old halfedges
966 */
967
968 HalfedgeHandle base_heh(halfedge_handle(_fh));
969 VertexHandle start_vh = from_vertex_handle(base_heh);
970 HalfedgeHandle prev_heh(prev_halfedge_handle(base_heh));
971 HalfedgeHandle next_heh(next_halfedge_handle(base_heh));
972
973 while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh)
974 {
975 HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh));
976
977 FaceHandle new_fh = new_face();
978 set_halfedge_handle(new_fh, base_heh);
979
980 HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh);
981
982 set_next_halfedge_handle(base_heh, next_heh);
983 set_next_halfedge_handle(next_heh, new_heh);
984 set_next_halfedge_handle(new_heh, base_heh);
985
986 set_face_handle(base_heh, new_fh);
987 set_face_handle(next_heh, new_fh);
988 set_face_handle(new_heh, new_fh);
989
990 copy_all_properties(prev_heh, new_heh, true);
991 copy_all_properties(prev_heh, opposite_halfedge_handle(new_heh), true);
992 copy_all_properties(_fh, new_fh, true);
993
994 base_heh = opposite_halfedge_handle(new_heh);
995 next_heh = next_next_heh;
996 }
997 set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh
998
999 set_next_halfedge_handle(base_heh, next_heh);
1000 set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh);
1001
1002 set_face_handle(base_heh, _fh);
1003}
1004
1005//-----------------------------------------------------------------------------
1007{
1008 /* The iterators will stay valid, even though new faces are added,
1009 because they are now implemented index-based instead of
1010 pointer-based.
1011 */
1012 FaceIter f_it(faces_begin()), f_end(faces_end());
1013 for (; f_it!=f_end; ++f_it)
1014 triangulate(*f_it);
1015}
1016
1017//-----------------------------------------------------------------------------
1019{
1022
1023 HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh);
1024
1025 set_next_halfedge_handle(hend, hold);
1026 set_face_handle(hold, fh);
1027
1028 hold = opposite_halfedge_handle(hold);
1029
1030 while (hh != hend) {
1031
1033
1034 FaceHandle fnew = new_face();
1035 set_halfedge_handle(fnew, hh);
1036
1037 HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh);
1038
1039 set_next_halfedge_handle(hnew, hold);
1040 set_next_halfedge_handle(hold, hh);
1041 set_next_halfedge_handle(hh, hnew);
1042
1043 set_face_handle(hnew, fnew);
1044 set_face_handle(hold, fnew);
1045 set_face_handle(hh, fnew);
1046
1047 hold = opposite_halfedge_handle(hnew);
1048
1049 hh = hnext;
1050 }
1051
1052 set_next_halfedge_handle(hold, hend);
1053 set_next_halfedge_handle(next_halfedge_handle(hend), hold);
1054
1055 set_face_handle(hold, fh);
1056
1057 set_halfedge_handle(vh, hold);
1058}
1059
1060
1062
1063 // Split the given face (fh will still be valid)
1064 split(fh, vh);
1065
1066 // Copy the property of the original face to all new faces
1067 for(VertexFaceIter vf_it = vf_iter(vh); vf_it.is_valid(); ++vf_it)
1068 copy_all_properties(fh, *vf_it, true);
1069}
1070
1071//-----------------------------------------------------------------------------
1073{
1074 uint count(0);
1075 for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it.is_valid(); ++vv_it)
1076 ++count;
1077 return count;
1078}
1079
1080//-----------------------------------------------------------------------------
1082{
1083 uint count(0);
1084 for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it.is_valid(); ++fv_it)
1085 ++count;
1086 return count;
1087}
1088
1089//-----------------------------------------------------------------------------
1091{
1092 HalfedgeHandle h0 = halfedge_handle(_eh, 0);
1093 HalfedgeHandle h1 = halfedge_handle(_eh, 1);
1094
1095 VertexHandle vfrom = from_vertex_handle(h0);
1096
1098 //HalfedgeHandle ph1 = prev_halfedge_handle(h1);
1099
1100 //HalfedgeHandle nh0 = next_halfedge_handle(h0);
1102
1103 bool boundary0 = is_boundary(h0);
1104 bool boundary1 = is_boundary(h1);
1105
1106 //add the new edge
1107 HalfedgeHandle new_e = new_edge(from_vertex_handle(h0), _vh);
1108
1109 //fix the vertex of the opposite halfedge
1110 set_vertex_handle(h1, _vh);
1111
1112 //fix the halfedge connectivity
1113 set_next_halfedge_handle(new_e, h0);
1114 set_next_halfedge_handle(h1, opposite_halfedge_handle(new_e));
1115
1116 set_next_halfedge_handle(ph0, new_e);
1117 set_next_halfedge_handle(opposite_halfedge_handle(new_e), nh1);
1118
1119// set_prev_halfedge_handle(new_e, ph0);
1120// set_prev_halfedge_handle(opposite_halfedge_handle(new_e), h1);
1121
1122// set_prev_halfedge_handle(nh1, opposite_halfedge_handle(new_e));
1123// set_prev_halfedge_handle(h0, new_e);
1124
1125 if (!boundary0)
1126 {
1127 set_face_handle(new_e, face_handle(h0));
1128 }
1129 else
1130 {
1131 set_boundary(new_e);
1132 }
1133
1134 if (!boundary1)
1135 {
1136 set_face_handle(opposite_halfedge_handle(new_e), face_handle(h1));
1137 }
1138 else
1139 {
1140 set_boundary(opposite_halfedge_handle(new_e));
1141 }
1142
1143 set_halfedge_handle( _vh, h0 );
1145
1146 if (halfedge_handle(vfrom) == h0)
1147 {
1148 set_halfedge_handle(vfrom, new_e);
1149 adjust_outgoing_halfedge( vfrom );
1150 }
1151}
1152
1153//-----------------------------------------------------------------------------
1154
1156{
1157 // Split the edge (handle is kept!)
1158 split_edge(_eh, _vh);
1159
1160 // Navigate to the new edge
1162
1163 // Copy the property from the original to the new edge
1164 copy_all_properties(_eh, eh0, true);
1165}
1166
1167} // namespace OpenMesh
1168
const StatusInfo & status(VertexHandle _vh) const
Status Query API.
bool tagged() const
is tagged ?
Definition Status.hh:133
void set_deleted(bool _b)
set deleted
Definition Status.hh:105
void set_tagged(bool _b)
set tagged
Definition Status.hh:135
bool is_valid() const
The handle is valid iff the index is not negative.
Definition Handles.hh:72
void copy_all_properties(VertexHandle _vh_from, VertexHandle _vh_to, bool _copyBuildIn=false)
uint valence(VertexHandle _vh) const
Vertex valence.
ConstVertexVertexIter cvv_iter(VertexHandle _vh) const
const vertex circulator
bool is_manifold(VertexHandle _vh) const
Is (the mesh at) vertex _vh two-manifold ?
void split_copy(FaceHandle _fh, VertexHandle _vh)
Face split (= 1-to-n split).
void adjust_outgoing_halfedge(VertexHandle _vh)
static const HalfedgeHandle InvalidHalfedgeHandle
Invalid handle.
SmartHalfedgeHandle opposite_halfedge_handle(SmartHalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh)
SmartHalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const
Find halfedge from _vh0 to _vh1. Returns invalid handle if not found.
SmartHalfedgeHandle prev_halfedge_handle(SmartHalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
void collapse_edge(HalfedgeHandle _hh)
Helper for halfedge collapse.
ConstFaceVertexIter cfv_iter(FaceHandle _fh) const
const face - vertex circulator
void reinsert_edge(EdgeHandle _eh)
ConstFaceFaceIter cff_iter(FaceHandle _fh) const
const face - face circulator
void collapse(HalfedgeHandle _heh)
FaceHandle remove_edge(EdgeHandle _eh)
VertexVertexIter vv_iter(VertexHandle _vh)
vertex - vertex circulator
static const FaceHandle InvalidFaceHandle
Invalid handle.
SmartHalfedgeHandle next_halfedge_handle(SmartHalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const
const face - edge circulator
void triangulate()
triangulate the entire mesh
void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true)
void collapse_loop(HalfedgeHandle _hh)
Helper for halfedge collapse.
SmartFaceHandle face_handle(SmartHalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
std::vector< std::pair< HalfedgeHandle, HalfedgeHandle > > next_cache_
Get item from handle.
static const VertexHandle InvalidVertexHandle
Invalid handle.
static const EdgeHandle InvalidEdgeHandle
Invalid handle.
void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices=true)
FaceIter faces_end()
End iterator for faces.
void split_edge(EdgeHandle _eh, VertexHandle _vh)
ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const
const vertex - outgoing halfedge circulator
SmartFaceHandle add_face(const std::vector< VertexHandle > &_vhandles)
Add and connect a new face.
void split_edge_copy(EdgeHandle _eh, VertexHandle _vh)
bool is_boundary(HalfedgeHandle _heh) const
Check if the halfedge is at the boundary.
SmartEdgeHandle edge_handle(SmartHalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
SmartFaceHandle opposite_face_handle(HalfedgeHandle _heh) const
returns the face handle of the opposite halfedge
bool is_simply_connected(FaceHandle _fh) const
VertexIHalfedgeIter vih_iter(VertexHandle _vh)
vertex - incoming halfedge circulator
void split(FaceHandle _fh, VertexHandle _vh)
Face split (= 1-to-n split).
void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true)
FaceHalfedgeIter fh_iter(FaceHandle _fh)
face - halfedge circulator
FaceIter faces_begin()
Begin iterator for faces.
bool is_collapse_ok(HalfedgeHandle _he)
SmartHalfedgeHandle halfedge_handle(SmartEdgeHandle _eh, unsigned int _i=0) const
returns the face handle of the opposite halfedge
VertexFaceIter vf_iter(VertexHandle _vh)
vertex - face circulator
std::vector< AddFaceEdgeInfo > edgeData_
Get item from handle.
bool is_simple_link(EdgeHandle _eh) const
SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity *_mesh)
Creats a SmartVertexHandle from a VertexHandle and a Mesh.
Handle for a edge entity.
Definition Handles.hh:135
Handle for a face entity.
Definition Handles.hh:142
Handle for a halfedge entity.
Definition Handles.hh:128
Handle for a vertex entity.
Definition Handles.hh:121