Developer Documentation
Loading...
Searching...
No Matches
HoleFillerT_impl.hh
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2023, 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//=============================================================================
45#include "HoleFillerT.hh"
47//=============================================================================
48
49//== NAMESPACES ===============================================================
50
51
52namespace OpenMesh {
53namespace HoleFiller {
54
55template< class MeshT >
56HoleFillerT< MeshT >::HoleFillerT(MeshT &_mesh )
57 : mesh_( _mesh )
58{
59 mesh_.request_vertex_status();
60 mesh_.request_edge_status();
61
62 if (! mesh_.get_property_handle(scale_,"scale") )
63 mesh_.add_property( scale_ , "scale" );
64}
65
66
67//=============================================================================
68
69
70
71template< class MeshT >
73{
74 mesh_.release_vertex_status();
75 mesh_.release_edge_status();
77 if ( mesh_.get_property_handle(scale_,"scale") )
78 mesh_.remove_property( scale_ );
79}
80
82//=============================================================================
83//
84// Identify and fill all holes of the mesh.
85//
86//=============================================================================
87
88
89template< class MeshT >
90void
92{
93
94
95 // Collect all boundary edges
96 std::vector< typename MeshT::EdgeHandle > bdry_edge;
97
98 for (auto ei : mesh_.edges())
99 if ( ei.is_boundary() )
100 bdry_edge.push_back( ei );
101
102
103 // Fill holes
104 int cnt = 0;
105 for (auto i : bdry_edge)
106 if ( mesh_.is_boundary( i ) )
107 {
108 ++cnt;
109 omlog() << "Filling hole " << cnt << "\n";
110 fill_hole( i, _stages );
111 }
112
113 // Smooth fillings
114 if ( _stages <= 2 )
115 return;
116
117 omlog() << "Stage 3 : Smoothing the hole fillings ... ";
118
120 smoother.initialize( OpenMesh::Smoother::SmootherT< MeshT >::
121 Tangential_and_Normal,
123
124 smoother.smooth( 500 );
125}
126
127
128//=============================================================================
129//
130// Fill a hole which is identified by one of its boundary edges.
131//
132//=============================================================================
133
134
135template< class MeshT >
136void
137HoleFillerT< MeshT >::fill_hole(typename MeshT::EdgeHandle _eh, int _stages )
138{
139
140 omlog() << " Stage 1 : Computing a minimal triangulation ... ";
141
142 // remember last vertex for selection of new ones
143 typename MeshT::VertexHandle old_last_handle = *(--mesh_.vertices_end());
144
145 // No boundary edge, no hole
146 if ( ! mesh_.is_boundary( _eh ) ) {
147 omerr() << "fill_hole: Given edge handle is not a boundary edge at a hole!" << std::endl;
148 return;
149 }
150
151 // Get boundary halfedge
152 OpenMesh::SmartHalfedgeHandle hh = make_smart(_eh, mesh_).h0();
153
154 if ( ! hh.is_boundary() )
155 hh = hh.opp();
156
157 // Collect boundary vertices
158 boundary_vertex_.clear();
159 opposite_vertex_.clear();
160
162
163 do {
164 boundary_vertex_.push_back( ch.from() );
165 opposite_vertex_.push_back( ch.opp().next().to() );
166 //check number of outgoing boundary HEH's at Vertex
167 int c = 0;
169
170 for (auto voh_it : vh.outgoing_halfedges())
171 if ( voh_it.is_boundary() )
172 c++;
173
174 if ( c >= 2){
176 typename MeshT::VertexOHalfedgeIter voh_it(mesh_,op);
177
178 ch = *(++voh_it);
179 }else
180 ch = ch.next();
181
182 } while ( ch != hh );
183
184
185 int nv = boundary_vertex_.size();
186
187 // Compute an initial triangulation
188 w_.clear();
189 w_.resize( nv, std::vector<Weight>( nv, Weight() ) );
190
191 l_.clear();
192 l_.resize( nv, std::vector<int>( nv, 0 ) );
193
194
195 for ( int i = 0; i < nv - 1; ++i )
196 w_[i][i+1] = Weight( 0, 0 );
197
198 for ( int j = 2; j < nv; ++j )
199 {
200 #pragma omp parallel for shared(j, nv)
201 for(int i = 0; i < nv-j; ++i)
202 {
203 Weight valmin;
204 int argmin = -1;
205 for ( int m = i + 1; m < i + j; ++m )
206 {
207 Weight newval = w_[i][m] + w_[m][i+j] + weight( i, m, i+j );
208 if ( newval < valmin )
209 {
210 valmin = newval;
211 argmin = m;
212 }
213 }
214
215 w_[i][i+j] = valmin;
216 l_[i][i+j] = argmin;
217 }
218 }
219
220 // Actually fill the hole. We collect all triangles and edges of
221 // this filling for further processing.
222 hole_edge_.clear();
223 hole_triangle_.clear();
224 if ( fill( 0, nv - 1 ) ){
225
226 if ( _stages <= 1 )
227 return;
228
229 omlog() << " Stage 2 : Fairing the filling ... " << std::endl;
230
231 std::vector< OpenMesh::SmartFaceHandle > handles = hole_triangle_;
232
233 fairing(handles);
234
235 //select all new vertices
236 typename MeshT::VertexIter old_end = ++typename MeshT::VertexIter(mesh_,old_last_handle);
237 typename MeshT::VertexIter v_end = mesh_.vertices_end();
238
239 for(; old_end != v_end; ++old_end)
240 if ( !mesh_.status(*old_end).deleted() )
241 mesh_.status(*old_end).set_selected( true );
242
243 }else
244 omerr() << "Could not create triangulation" << std::endl;
245}
246
247
249template< class MeshT >
250void
251HoleFillerT< MeshT >::fairing( std::vector< OpenMesh::SmartFaceHandle >& _faceHandles ){
252
253 //generate vector of all edges
254 hole_edge_.clear();
255
256 hole_triangle_ = _faceHandles;
257
262
263 if (! mesh_.get_property_handle(edgeProp,"edgeProp") )
264 mesh_.add_property( edgeProp, "edgeProp" );
265 if (! mesh_.get_property_handle(vertexProp,"vertexProp") )
266 mesh_.add_property( vertexProp, "vertexProp" );
267 if (! mesh_.get_property_handle(faceProp,"faceProp") )
268 mesh_.add_property( faceProp, "faceProp" );
269 if (! mesh_.get_property_handle(orderProp,"orderProp") )
270 mesh_.add_property( orderProp, "orderProp" );
271
272 //init properties by setting all of them to false
273 for (auto fIt : mesh_.faces()) {
274 mesh_.property( orderProp, fIt ) = false;
275 mesh_.property( faceProp, fIt ) = false;
276 }
277
278 for (auto eIt : mesh_.edges())
279 mesh_.property( edgeProp, eIt ) = false;
280
281 for (auto vIt : mesh_.vertices()) {
282 mesh_.property( vertexProp, vIt ) = false;
283 }
284
285 //set face property
286 for (uint i = 0; i < hole_triangle_.size(); i++){
287 mesh_.property( faceProp, hole_triangle_[i] ) = true;
288 }
289
290 //set properties
291 for (unsigned int i = 0; i < hole_triangle_.size(); i++){
292 for (auto fei : hole_triangle_[i].edges()) {
293 mesh_.status( fei ).set_locked(true);
294 //set edge property for all edges inside the hole (eg not on the hole boundary)
295 if (mesh_.property( faceProp, fei.h0().face() ) &&
296 mesh_.property( faceProp, fei.h1().face() ) ){
297
298 mesh_.property( edgeProp, fei ) = true;
299 hole_edge_.push_back( fei );
300 mesh_.status( fei ).set_locked(false);
301 }
302 }
303
305 for (auto fvi : hole_triangle_[i].vertices()){
306 //set vertex property for all vertices of the hole
307 for ( auto vfi : fvi.faces() )
308 mesh_.property( vertexProp, fvi ) = true;
309 }
310 }
311
312 //calculate scaling weights for vertices
313 for (auto vIt : mesh_.vertices())
314 if (mesh_.property(vertexProp, vIt)){
315
316 Scalar cnt = 0;
317 Scalar scale = 0;
318
319 for ( auto voh_it : vIt.outgoing_halfedges())
320 {
321
322 if (voh_it.face().is_valid() &&
323 voh_it.opp().face().is_valid() &&
324 mesh_.property(faceProp, voh_it.face() ) &&
325 mesh_.property(faceProp, voh_it.opp().face() ))
326 continue;
327
328 cnt += 1.0f;
329 Point p0 = mesh_.point( vIt );
330 Point p1 = mesh_.point( voh_it.to() );
331 scale += norm( p1 - p0 );
332
333 }
334
335 scale /= cnt;
336
337 mesh_.property( scale_, vIt ) = scale;
338 }
339
340 mesh_.remove_property(edgeProp);
341 mesh_.remove_property(vertexProp);
342 mesh_.remove_property(faceProp);
343 mesh_.remove_property(orderProp);
344
345 // Do the patch fairing
346 bool did_refine = true;
347
348 for ( int k = 0; k < 40 && did_refine; ++k )
349 {
350 uint end = hole_triangle_.size();
351
352 did_refine = false;
353 for ( unsigned int j = 0; j < end; ++j )
354 did_refine |= refine( hole_triangle_[j] );
355
356 for ( int i = 0; i < 10; ++i )
357 for ( unsigned int j = 0; j < hole_edge_.size(); ++j )
358 relax_edge( hole_edge_[j] );
359 }
360
361 // unlock everything
362 for ( auto ei : mesh_.edges())
363 mesh_.status( ei ).set_locked( false );
364}
365
366//=============================================================================
367//
368// Refine a face: Apply a 1-to-3 split if the edge lengths of the
369// face do not match the interpolated edge lengths of the hole
370// boundary.
371//
372//=============================================================================
373
374
375template< class MeshT >
376bool
377HoleFillerT< MeshT >::refine(typename MeshT::FaceHandle _fh )
378{
379
380 // Collect the three edges of the face into e0, e1, e2
381
382 typename MeshT::FEIter fei = mesh_.fe_iter( _fh );
383 OpenMesh::SmartEdgeHandle e0 = *fei; ++fei;
384 OpenMesh::SmartEdgeHandle e1 = *fei; ++fei;
385 OpenMesh::SmartEdgeHandle e2 = *fei; ++fei;
386
387
388 // Collect the vertices, vertex positions and scale factors of the face.
389
390 typename MeshT::FVIter fvi = mesh_.fv_iter( _fh );
391
392 typename MeshT::VertexHandle v0 = *fvi; ++fvi;
393 typename MeshT::VertexHandle v1 = *fvi; ++fvi;
394 typename MeshT::VertexHandle v2 = *fvi; ++fvi;
395
396 Point p0 = mesh_.point( v0 );
397 Point p1 = mesh_.point( v1 );
398 Point p2 = mesh_.point( v2 );
399
400 Scalar scale0 = mesh_.property( scale_, v0 );
401 Scalar scale1 = mesh_.property( scale_, v1 );
402 Scalar scale2 = mesh_.property( scale_, v2 );
403
404 // Interpolate the scale factor.
405
406 Scalar scale = ( scale0 + scale1 + scale2 ) / 3.0f;
407 Point center = typename MeshT::Scalar(1.0/3.0) * ( p0 + p1 + p2 );
408
409 Scalar d0 = 1.0f * norm( p0 - center );
410 Scalar d1 = 1.0f * norm( p1 - center );
411 Scalar d2 = 1.0f * norm( p2 - center );
412
413
414 //dont split triangles which tend to degenerate
415 if ( (d0 + d1 + d2) / 3.0f < scale) return false;
416
417
418 // If the edge lengths differ too much from the scale, perform a
419 // triangle split.
420
421 if ( ( d0 > scale && d0 > scale0 ) ||
422 ( d1 > scale && d1 > scale1 ) ||
423 ( d2 > scale && d2 > scale2 ) )
424 {
425 // Split the face ...
426 OpenMesh::SmartVertexHandle ch = mesh_.add_vertex( center );
427 mesh_.split( _fh, ch );
428
429 // ... put the new triangles into the global triangle list ...
430
431 for ( auto vfi : ch.faces() )
432 if ( vfi != _fh )
433 hole_triangle_.push_back( vfi );
434
435 // ... put the new edges into the global edge list ...
436
437 for ( auto vei : ch.edges() )
438 hole_edge_.push_back( vei );
439
440 // ... and set the appropriate scale factor for the new vertex.
441
442 mesh_.property( scale_, ch ) = scale;
443
444 relax_edge( e0 );
445 relax_edge( e1 );
446 relax_edge( e2 );
447
448 return true;
449 }
450
451 return false;
452}
453
454
455//=============================================================================
456//
457// Relax an edge: Flip it if one of its opposing vertices lies in
458// the circumsphere of the other three vertices.
459//
460//=============================================================================
461
462
463template< class MeshT >
464bool
465HoleFillerT< MeshT >::relax_edge( OpenMesh::SmartEdgeHandle _eh )
466{
467 if ( mesh_.status( _eh ).locked() )
468 return false;
469
470 // Abbreviations for the two halfedges of _eh
471
474
475 // Get the two end-vertices u and v of the edge
476
477 Point u( mesh_.point( h0.to() ) );
478 Point v( mesh_.point( h1.to() ) );
479
480 // Get the two opposing vertices a and b
481
482 Point a( mesh_.point( h0.next().to() ) );
483 Point b( mesh_.point( h1.next().to() ) );
484
485 // If the circumsphere criterion is fullfilled AND if the flip is
486 // topologically admissible, we do it.
487
488 if ( in_circumsphere( a, u, v, b ) || in_circumsphere( b, u, v, a ) ){
489 if ( mesh_.is_flip_ok( _eh ) )
490 {
491
492 mesh_.flip( _eh );
493
494 return true;
495 }else
496 mesh_.status(_eh).set_selected( true );
497}
498 return false;
499}
500
501
502//=============================================================================
503//
504// Test whether a point _x lies in the circumsphere of _a,_b,_c.
505//
506//=============================================================================
507
508
509template< class MeshT >
510bool
511HoleFillerT< MeshT >::in_circumsphere( const Point & _x,
512 const Point & _a,
513 const Point & _b,
514 const Point & _c ) const
515{
516 Point ab = _b - _a;
517 Point ac = _c - _a;
518
519 Scalar a00 = -2.0f * ( dot(ab , _a ) );
520 Scalar a01 = -2.0f * ( dot(ab , _b ) );
521 Scalar a02 = -2.0f * ( dot(ab , _c ) );
522 Scalar b0 = norm(_a)*norm(_a) - norm(_b)*norm(_b);
523
524 Scalar a10 = -2.0f * ( dot(ac , _a ) );
525 Scalar a11 = -2.0f * ( dot(ac , _b ) );
526 Scalar a12 = -2.0f * ( dot(ac , _c ) );
527 Scalar b1 = norm(_a)*norm(_a) - norm(_c)*norm(_c);
528
529 typename MeshT::Scalar alpha = -(-a11*a02+a01*a12-a12*b0+b1*a02+a11*b0-a01*b1)
530 / (-a11*a00+a11*a02-a10*a02+a00*a12+a01*a10-a01*a12);
531 typename MeshT::Scalar beta = (a10*b0-a10*a02-a12*b0+a00*a12+b1*a02-a00*b1)
532 / (-a11*a00+a11*a02-a10*a02+a00*a12+a01*a10-a01*a12);
533 typename MeshT::Scalar gamma = (-a11*a00-a10*b0+a00*b1+a11*b0+a01*a10-a01*b1)
534 / (-a11*a00+a11*a02-a10*a02+a00*a12+a01*a10-a01*a12);
535
536 Point center = alpha * _a + beta * _b + gamma * _c;
537
538 return norm( _x - center ) * norm( _x - center ) < norm( _a - center ) * norm( _a - center );
539}
540
541
542//=============================================================================
543//
544// Create the triangulation
545//
546// Recursively creates the triangulation for polygon (_i,...,_j).
547//
548//=============================================================================
549
550
551template< class MeshT >
552bool
553HoleFillerT< MeshT >::fill( int _i, int _j )
554{
555 // If the two vertices _i and _j are adjacent, there is nothing to do.
556
557 if ( _i + 1 == _j )
558 return true;
559
560
561 // Create and store the middle triangle, store its edges.
562
563 OpenMesh::SmartFaceHandle fh = mesh_.add_face( boundary_vertex_[_i],
564 boundary_vertex_[ l_[_i][_j] ],
565 boundary_vertex_[_j] );
566 hole_triangle_.push_back( fh );
567
568 if (!fh.is_valid())
569 return false;
570
571 hole_edge_.push_back( mesh_.edge_handle
572 ( mesh_.find_halfedge( boundary_vertex_[_i],
573 boundary_vertex_[ l_[_i][_j] ] ) ) );
574 hole_edge_.push_back( mesh_.edge_handle
575 ( mesh_.find_halfedge( boundary_vertex_[ l_[_i][_j] ],
576 boundary_vertex_[_j] ) ) );
577
578
579 // Recursively create the left and right side of the
580 // triangulation.
581
582 if (!fill( _i, l_[_i][_j] ) || !fill( l_[_i][_j], _j ))
583 return false;
584 else
585 return true;
586}
587
588
589
590//=============================================================================
591//
592// Compute the weight of the triangle (_i,_j,_k).
593//
594//=============================================================================
595
596
597template< class MeshT >
598typename HoleFillerT< MeshT >::Weight
599HoleFillerT< MeshT >::weight( int _i, int _j, int _k )
600{
601 // Return an infinite weight if the insertion of this triangle
602 // would create complex edges.
603
604 if ( exists_edge( boundary_vertex_[_i], boundary_vertex_[_j] ) ||
605 exists_edge( boundary_vertex_[_j], boundary_vertex_[_k] ) ||
606 exists_edge( boundary_vertex_[_k], boundary_vertex_[_i] ) )
607 return Weight();
608
609
610 // Return an infinite weight, if one of the neighboring patches
611 // could not be created.
612
613
614 if ( l_[_i][_j] == -1 ) return Weight();
615 if ( l_[_j][_k] == -1 ) return Weight();
616
617
618 // Compute the maxmimum dihedral angles to the adjacent triangles
619 // (if they exist)
620
621 Scalar angle = 0.0f;
622
623 if ( _i + 1 == _j )
624 angle = std::max( angle, dihedral_angle( boundary_vertex_[_i],
625 boundary_vertex_[_j],
626 boundary_vertex_[_k],
627 opposite_vertex_[_i] ) );
628 else
629 angle = std::max( angle, dihedral_angle( boundary_vertex_[_i],
630 boundary_vertex_[_j],
631 boundary_vertex_[_k],
632 boundary_vertex_[l_[_i][_j]] ) );
633
634 if ( _j + 1 == _k )
635 angle = std::max( angle, dihedral_angle( boundary_vertex_[_j],
636 boundary_vertex_[_k],
637 boundary_vertex_[_i],
638 opposite_vertex_[_j] ) );
639 else
640 angle = std::max( angle, dihedral_angle( boundary_vertex_[_j],
641 boundary_vertex_[_k],
642 boundary_vertex_[_i],
643 boundary_vertex_[l_[_j][_k]] ) );
644
645 if ( _i == 0 && _k == (int) boundary_vertex_.size() - 1 )
646 angle = std::max( angle, dihedral_angle( boundary_vertex_[_k],
647 boundary_vertex_[_i],
648 boundary_vertex_[_j],
649 opposite_vertex_[_k] ) );
650
651
652 return Weight( angle, area( boundary_vertex_[_i],
653 boundary_vertex_[_j],
654 boundary_vertex_[_k] ) );
655}
656
657
658
659//=============================================================================
660//
661// Does an edge from vertex _u to _v exist?
662//
663//=============================================================================
664
665
666template< class MeshT >
667bool
668HoleFillerT< MeshT >::exists_edge( OpenMesh::SmartVertexHandle _u, typename MeshT::VertexHandle _w )
669{
670 for ( auto vohi : _u.outgoing_halfedges() )
671 if ( ! vohi.edge().is_boundary() )
672 if ( vohi.to() == _w )
673 return true;
674
675 return false;
676}
677
678
679
680//=============================================================================
681//
682// Compute the area of the triangle (_a,_b,_c).
683//
684//=============================================================================
685
686
687template< class MeshT >
688typename MeshT::Scalar
689HoleFillerT< MeshT >::area( typename MeshT::VertexHandle _a, typename MeshT::VertexHandle _b, typename MeshT::VertexHandle _c )
690{
691 Point a( mesh_.point( _a ) );
692 Point b( mesh_.point( _b ) );
693 Point c( mesh_.point( _c ) );
694
695 Point n( cross(( b - a ) , ( c - b )) );
696
697 return 0.5 * norm(n);
698}
699
700
701//=============================================================================
702//
703// Compute a dihedral angle
704//
705// Computes the dihedral angle (in degrees) between triangle
706// (_u,_v,_a) and triangle (_v,_u,_b), no matter whether these
707// triangles actually exist in the current mesh or not).
708//
709//=============================================================================
710
711
712template< class MeshT >
713typename MeshT::Scalar
714HoleFillerT< MeshT >::dihedral_angle( typename MeshT::VertexHandle _u, typename MeshT::VertexHandle _v, typename MeshT::VertexHandle _a, typename MeshT::VertexHandle _b )
715{
716 Point u( mesh_.point( _u ) );
717 Point v( mesh_.point( _v ) );
718 Point a( mesh_.point( _a ) );
719 Point b( mesh_.point( _b ) );
720
721 Point n0( cross(( v - u ) , ( a - v )) );
722 Point n1( cross(( u - v ) , ( b - u )) );
723
724 normalize(n0);
725 normalize(n1);
726
727 return acos( dot(n0,n1) ) * 180.0 / M_PI;
728}
729
730
732template< class MeshT >
733void
734HoleFillerT< MeshT >::removeDegeneratedFaces( std::vector< typename MeshT::FaceHandle >& _faceHandles ){
735
736 for (int i = _faceHandles.size()-1; i >= 0 ; i--){
737
738 if ( mesh_.status( _faceHandles[i] ).deleted() ){
739 // face might be deleted because of a previous edge collapse
740 // erase the face from the vector
741 _faceHandles.erase( _faceHandles.begin() + i );
742 continue;
743 }
744
745 //get the vertices (works only on triMeshes)
746 typename MeshT::FaceVertexIterator fvi = mesh_.fv_iter( _faceHandles[i] );
747 Point v0 = mesh_.point( *fvi);
748 ++fvi;
749 Point v1 = mesh_.point( *fvi );
750 ++fvi;
751 Point v2 = mesh_.point( *fvi );
752
753 //check if its degenerated
754 Point v0v1 = v1 - v0;
755 Point v0v2 = v2 - v0;
756 Point n = v0v1 % v0v2; // not normalized !
757 double d = n.sqrnorm();
758
759 if (d < FLT_MIN && d > -FLT_MIN) {
760 // degenerated face found
761 typename MeshT::FaceHalfedgeIterator hIt = mesh_.fh_iter( _faceHandles[i] );
762
763 //try to collapse one of the edges
764 while (hIt.is_valid()){
765 if ( mesh_.is_collapse_ok( *hIt ) ){
766 // collapse the edge to remove the triangle
767 mesh_.collapse( *hIt );
768 // and erase the corresponding face from the vector
769 _faceHandles.erase( _faceHandles.begin() + i );
770 break;
771 } else {
772 ++hIt;
773 }
774 }
775 }
776 }
777}
778
779//=============================================================================
780
781
782//=============================================================================
783} // namespace HoleFiller
784} // namespace OpenMesh
785//=============================================================================
bool is_valid() const
The handle is valid iff the index is not negative.
Definition Handles.hh:72
SmartVertexHandle add_vertex(const Point _p)
Definition PolyMeshT.hh:255
bool is_boundary() const
Returns true iff the handle is boundary.
void smooth(unsigned int _n)
Do _n smoothing iterations.
SmartVertexHandle split(EdgeHandle _eh, const Point &_p)
Edge split (= 2-to-4 split)
Definition TriMeshT.hh:275
SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity *_mesh)
Creats a SmartVertexHandle from a VertexHandle and a Mesh.
T angle(T _cos_angle, T _sin_angle)
Definition MathDefs.hh:140
SmartHalfedgeHandle h1() const
Shorthand for halfedge(1)
SmartHalfedgeHandle h0() const
Shorthand for halfedge(0)
SmartVertexHandle from() const
Returns vertex at start of halfedge.
SmartHalfedgeHandle next() const
Returns next halfedge handle.
SmartHalfedgeHandle opp() const
Returns opposite halfedge handle.
SmartVertexHandle to() const
Returns vertex pointed to by halfedge.
Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...
PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges() const
Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range())