OpenMesh
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 >
72HoleFillerT< MeshT >::~HoleFillerT()
73{
74 mesh_.release_vertex_status();
75 mesh_.release_edge_status();
76
77 if ( mesh_.get_property_handle(scale_,"scale") )
78 mesh_.remove_property( scale_ );
79}
80
81
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//=============================================================================
Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...
Definition: MeshItems.hh:59
SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity *_mesh)
Creats a SmartVertexHandle from a VertexHandle and a Mesh.
Definition: SmartHandles.hh:265
T angle(T _cos_angle, T _sin_angle)
returns the angle determined by its cos and the sign of its sin result is positive if the angle is in...
Definition: MathDefs.hh:140
VectorT< Scalar, DIM > & normalize(VectorT< Scalar, DIM > &_v)
non-member normalize
Definition: Vector11T.hh:769
Scalar dot(const VectorT< Scalar, DIM > &_v1, const VectorT< Scalar, DIM > &_v2)
symmetric version of the dot product
Definition: Vector11T.hh:725
auto cross(const VectorT< LScalar, DIM > &_v1, const VectorT< RScalar, DIM > &_v2) -> decltype(_v1 % _v2)
symmetric version of the cross product
Definition: Vector11T.hh:733
Scalar norm(const VectorT< Scalar, DIM > &_v)
non-member norm
Definition: Vector11T.hh:749
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
bool is_boundary() const
Returns true iff the handle is boundary.
Definition: SmartHandles.hh:350
Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...
Definition: SmartHandles.hh:110
PolyConnectivity::ConstVertexFaceRange faces() const
Returns a range of faces incident to the vertex (PolyConnectivity::vf_range())
Definition: PolyConnectivity_inline_impl.hh:972
PolyConnectivity::ConstVertexOHalfedgeRange outgoing_halfedges() const
Returns a range of incoming halfedges incident to the vertex (PolyConnectivity::voh_range())
Definition: PolyConnectivity_inline_impl.hh:992
PolyConnectivity::ConstVertexEdgeRange edges() const
Returns a range of edges incident to the vertex (PolyConnectivity::ve_range())
Definition: PolyConnectivity_inline_impl.hh:976
Definition: SmartHandles.hh:170
SmartVertexHandle from() const
Returns vertex at start of halfedge.
Definition: SmartHandles.hh:409
SmartHalfedgeHandle next() const
Returns next halfedge handle.
Definition: SmartHandles.hh:385
SmartHalfedgeHandle opp() const
Returns opposite halfedge handle.
Definition: SmartHandles.hh:397
SmartVertexHandle to() const
Returns vertex pointed to by halfedge.
Definition: SmartHandles.hh:403
Definition: SmartHandles.hh:197
SmartHalfedgeHandle h1() const
Shorthand for halfedge(1)
Definition: SmartHandles.hh:443
SmartHalfedgeHandle h0() const
Shorthand for halfedge(0)
Definition: SmartHandles.hh:438
Definition: SmartHandles.hh:228
Handle representing an edge property.
Definition: Property.hh:447
Definition: HoleFillerT.hh:54
Laplacian Smoothing.
Definition: JacobiLaplaceSmootherT.hh:76
void smooth(unsigned int _n)
Do _n smoothing iterations.
Definition: JacobiLaplaceSmootherT_impl.hh:74
Base class for smoothing algorithms.
Definition: SmootherT.hh:77

Project OpenMesh, ©  Visual Computing Institute, RWTH Aachen. Documentation generated using doxygen .