2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file SurfaceMesh.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
24 * Implementation of inline methods defined in SurfaceMesh.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
33//////////////////////////////////////////////////////////////////////////////
35///////////////////////////////////////////////////////////////////////////////
36// IMPLEMENTATION of inline methods.
37///////////////////////////////////////////////////////////////////////////////
39///////////////////////////////////////////////////////////////////////////////
40// ----------------------- Standard services ------------------------------
42//-----------------------------------------------------------------------------
43template <typename TRealPoint, typename TRealVector>
44template <typename RealPointIterator, typename VerticesIterator>
45DGtal::SurfaceMesh<TRealPoint, TRealVector>::
46SurfaceMesh( RealPointIterator itPos, RealPointIterator itPosEnd,
47 VerticesIterator itVertices, VerticesIterator itVerticesEnd )
49 bool ok = init( itPos, itPosEnd, itVertices, itVerticesEnd );
53//-----------------------------------------------------------------------------
54template <typename TRealPoint, typename TRealVector>
55template <typename RealPointIterator, typename VerticesIterator>
57DGtal::SurfaceMesh<TRealPoint, TRealVector>::
58init( RealPointIterator itPos, RealPointIterator itPosEnd,
59 VerticesIterator itVertices, VerticesIterator itVerticesEnd )
62 myPositions = std::vector< RealPoint >( itPos, itPosEnd );
63 myIncidentFaces.resize( myPositions.size() );
64 Index f = 0; // current face index
66 for ( ; itVertices != itVerticesEnd; ++itVertices, ++f )
69 for ( auto it = itVertices->begin(), itE = itVertices->end(); it != itE; ++it )
72 if ( vtx >= nbVertices() )
74 trace.warning() << "[SurfaceMesh::init] Invalid vtx "
75 << vtx << " at face " << f
76 << " since #V=" << nbVertices()
77 << ". Ignoring vertex." << std::endl;
82 myIncidentFaces[ vtx ].push_back( f );
83 f_vtcs.push_back( vtx );
86 myIncidentVertices.push_back( f_vtcs );
93//-----------------------------------------------------------------------------
94template <typename TRealPoint, typename TRealVector>
96DGtal::SurfaceMesh<TRealPoint, TRealVector>::
99 myIncidentVertices.clear();
100 myIncidentFaces.clear();
102 myVertexNormals.clear();
103 myFaceNormals.clear();
104 myNeighborFaces.clear();
105 myNeighborVertices.clear();
106 myEdgeVertices.clear();
107 myVertexPairEdge.clear();
109 myEdgeRightFaces.clear();
110 myEdgeLeftFaces.clear();
113//-----------------------------------------------------------------------------
114template <typename TRealPoint, typename TRealVector>
115template <typename RealVectorIterator>
117DGtal::SurfaceMesh<TRealPoint, TRealVector>::
118setVertexNormals( RealVectorIterator itN, RealVectorIterator itNEnd )
120 myVertexNormals = std::vector< RealVector >( itN, itNEnd );
121 return myVertexNormals.size() == myPositions.size();
124//-----------------------------------------------------------------------------
125template <typename TRealPoint, typename TRealVector>
126template <typename RealVectorIterator>
128DGtal::SurfaceMesh<TRealPoint, TRealVector>::
129setFaceNormals( RealVectorIterator itN, RealVectorIterator itNEnd )
131 myFaceNormals = std::vector< RealVector >( itN, itNEnd );
132 return myFaceNormals.size() == myIncidentVertices.size();
135//-----------------------------------------------------------------------------
136template <typename TRealPoint, typename TRealVector>
138DGtal::SurfaceMesh<TRealPoint, TRealVector>::
139computeFaceNormalsFromPositions()
141 myFaceNormals.resize( myIncidentVertices.size() );
142 for ( Face f = 0; f < myFaceNormals.size(); f++ )
143 computeFaceNormalFromPositions( f );
146//-----------------------------------------------------------------------------
147template <typename TRealPoint, typename TRealVector>
149DGtal::SurfaceMesh<TRealPoint, TRealVector>::
150computeFaceNormalFromPositions( const Face f )
152 RealPoint p; // barycenter
153 RealVector n; // normal
154 const Vertices& vtcs = incidentVertices( f );
155 // compute barycenter
156 for ( auto idx : vtcs ) p += myPositions[ idx ];
158 // compute normal as sum of triangle normal vectors.
159 for ( Index i = 0; i < vtcs.size(); ++i )
161 const Index j = vtcs[ i ];
162 const Index nj = vtcs[ (i+1) % vtcs.size() ];
163 n += ( myPositions[ j ] - p ).crossProduct( myPositions[ nj ] - p );
165 auto n_norm = n.norm();
166 myFaceNormals[ f ] = n_norm != 0.0 ? n / n_norm : n;
169//-----------------------------------------------------------------------------
170template <typename TRealPoint, typename TRealVector>
172DGtal::SurfaceMesh<TRealPoint, TRealVector>::
173computeFaceNormalsFromVertexNormals()
175 if ( myVertexNormals.empty() ) return;
176 myFaceNormals.resize( myIncidentVertices.size() );
178 for ( auto face : myIncidentVertices )
180 RealVector n; // normal
181 for ( auto idx : face ) n += myVertexNormals[ idx ];
182 auto n_norm = n.norm();
183 myFaceNormals[ f ] = n_norm != 0.0 ? n / n_norm : n;
187//-----------------------------------------------------------------------------
188template <typename TRealPoint, typename TRealVector>
190DGtal::SurfaceMesh<TRealPoint, TRealVector>::
191computeVertexNormalsFromFaceNormals()
193 if ( myFaceNormals.empty() ) return;
194 myVertexNormals.resize( myIncidentFaces.size() );
196 for ( auto vertex : myIncidentFaces )
198 RealVector n; // normal
199 for ( auto idx : vertex ) n += myFaceNormals[ idx ];
200 auto n_norm = n.norm();
201 myVertexNormals[ v ] = n_norm != 0.0 ? n / n_norm : n;
205//-----------------------------------------------------------------------------
206template <typename TRealPoint, typename TRealVector>
208DGtal::SurfaceMesh<TRealPoint, TRealVector>::
209computeVertexNormalsFromFaceNormalsWithMaxWeights()
211 if ( myFaceNormals.empty() ) return;
212 myVertexNormals.resize( myIncidentFaces.size() );
214 for ( auto incident_faces : myIncidentFaces )
216 RealVector n; // normal
217 const auto weights = getMaxWeights( v );
219 for ( auto idx_f : incident_faces ) n += weights[ i++ ] * myFaceNormals[ idx_f ];
220 auto n_norm = n.norm();
221 myVertexNormals[ v ] = n_norm != 0.0 ? n / n_norm : n;
226//-----------------------------------------------------------------------------
227template <typename TRealPoint, typename TRealVector>
228typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalars
229DGtal::SurfaceMesh<TRealPoint, TRealVector>::
230getMaxWeights( Index v ) const
233 const auto & neighbors = myNeighborVertices[ v ];
234 const RealPoint x = myPositions[ v ];
235 for ( auto idx_f : myIncidentFaces[ v ] )
237 // Find adjacent vertices to v
238 std::vector< Index > adj_vertices;
239 for ( auto idx_v : myIncidentVertices[ idx_f ] )
241 auto it = std::find( neighbors.cbegin(), neighbors.cend(), idx_v );
242 if ( it != neighbors.cend() ) adj_vertices.push_back( *it );
244 if ( adj_vertices.size() != 2 )
246 trace.warning() << "[SurfaceMesh::getMaxWeights] "
247 << adj_vertices.size() << " adjacent vertices to vertex "
248 << v << " on face" << idx_f << "." << std::endl;
249 for ( auto a : adj_vertices ) std::cerr << " " << a;
250 std::cerr << std::endl;
252 if (adj_vertices.size() >= 2 )
254 const Scalar area = faceArea( idx_f );
255 const Scalar l1 = ( myPositions[ adj_vertices[ 0 ] ] - x ).squaredNorm();
256 const Scalar l2 = ( myPositions[ adj_vertices[ 1 ] ] - x ).squaredNorm();
257 const Scalar l1l2 = l1 * l2;
258 weights.push_back( l1l2 != 0 ? fabs( area ) / l1l2 : 0.0 );
260 else weights.push_back( 0.0 );
265//-----------------------------------------------------------------------------
266template <typename TRealPoint, typename TRealVector>
267template <typename AnyRing>
269DGtal::SurfaceMesh<TRealPoint, TRealVector>::
270computeFaceValuesFromVertexValues( const std::vector<AnyRing>& vvalues ) const
272 ASSERT( vvalues.size() == nbVertices() );
273 std::vector<AnyRing> fvalues( nbFaces() );
275 for ( auto face : myIncidentVertices )
277 AnyRing n = NumberTraits<AnyRing>::ZERO;
278 for ( auto idx : face ) n += vvalues[ idx ];
279 fvalues[ f++ ] = n / face.size();
284template <typename TRealPoint, typename TRealVector>
285template <typename AnyRing>
287DGtal::SurfaceMesh<TRealPoint, TRealVector>::
288computeVertexValuesFromFaceValues( const std::vector<AnyRing>& fvalues ) const
290 ASSERT( fvalues.size() == nbFaces() );
291 std::vector<AnyRing> vvalues( nbVertices() );
293 for ( auto vertex : myIncidentFaces )
295 AnyRing n = NumberTraits<AnyRing>::ZERO;
296 for ( auto idx : vertex ) n += fvalues[ idx ];
297 vvalues[ v++ ] = n / vertex.size();
302//-----------------------------------------------------------------------------
303template <typename TRealPoint, typename TRealVector>
304std::vector<TRealVector>
305DGtal::SurfaceMesh<TRealPoint, TRealVector>::
306computeFaceUnitVectorsFromVertexUnitVectors
307( const std::vector<RealVector>& vuvectors ) const
309 ASSERT( vuvectors.size() == nbVertices() );
310 std::vector<RealVector> fuvectors( nbFaces() );
312 for ( auto face : myIncidentVertices )
315 for ( auto idx : face ) n += vuvectors[ idx ];
316 const auto n_norm = n.norm();
317 fuvectors[ f++ ] = n_norm != 0.0 ? n / n_norm : n;
322//-----------------------------------------------------------------------------
323template <typename TRealPoint, typename TRealVector>
324std::vector<TRealVector>
325DGtal::SurfaceMesh<TRealPoint, TRealVector>::
326computeVertexUnitVectorsFromFaceUnitVectors
327( const std::vector<RealVector>& fuvectors ) const
329 ASSERT( fuvectors.size() == nbFaces() );
330 std::vector<RealVector> vuvectors( nbVertices() );
332 for ( auto vertex : myIncidentFaces )
335 for ( auto idx : vertex ) n += fuvectors[ idx ];
336 const auto n_norm = n.norm();
337 vuvectors[ v++ ] = n_norm != 0.0 ? n / n_norm : n;
343//-----------------------------------------------------------------------------
344template <typename TRealPoint, typename TRealVector>
345typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edge
346DGtal::SurfaceMesh<TRealPoint, TRealVector>::
347makeEdge( Vertex i, Vertex j ) const
349 VertexPair vp = i < j ? std::make_pair( i,j ) : std::make_pair( j,i );
350 const auto it = myVertexPairEdge.find( vp );
351 if ( it == myVertexPairEdge.cend() ) return nbEdges();
355//-----------------------------------------------------------------------------
356template <typename TRealPoint, typename TRealVector>
357typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
358DGtal::SurfaceMesh<TRealPoint, TRealVector>::
359averageEdgeLength() const
361 double lengths = 0.0;
362 for ( Edge e = 0; e < nbEdges(); ++e )
364 auto vtcs = edgeVertices( e );
365 const RealPoint p = myPositions[ vtcs.first ];
366 const RealVector pq = myPositions[ vtcs.second ] - p;
367 lengths += pq.norm();
369 lengths /= nbEdges();
373//-----------------------------------------------------------------------------
374template <typename TRealPoint, typename TRealVector>
375typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
376DGtal::SurfaceMesh<TRealPoint, TRealVector>::
377localWindow( Face f ) const
379 const RealPoint x = faceCentroid( f );
380 Scalar local_length = 0.0;
381 for ( auto v : incidentVertices( f ) )
382 local_length += ( myPositions[ v ] - x ).norm();
383 return local_length / incidentVertices( f ).size();
386//-----------------------------------------------------------------------------
387template <typename TRealPoint, typename TRealVector>
389DGtal::SurfaceMesh<TRealPoint, TRealVector>::
390perturbateWithUniformRandomNoise( Scalar p )
392 for ( auto& x : myPositions )
394 RealVector d( rand01()*2.0 - 1.0, rand01()*2.0 - 1.0, rand01()*2.0 - 1.0 );
395 d = d.getNormalized();
396 Scalar l = rand01() * p;
401//-----------------------------------------------------------------------------
402template <typename TRealPoint, typename TRealVector>
404DGtal::SurfaceMesh<TRealPoint, TRealVector>::
405perturbateWithAdaptiveUniformRandomNoise( Scalar p )
407 Scalars local_average_lengths( nbVertices() );
408 for ( Index v = 0; v < nbVertices(); ++v )
410 const RealPoint x = myPositions[ v ];
411 Scalar local_length = 0.0;
412 for ( auto nv : myNeighborVertices[ v ] )
413 local_length += ( myPositions[ nv ] - x ).norm();
414 local_average_lengths[ v ] = local_length / myNeighborVertices[ v ].size();
416 for ( Index v = 0; v < nbVertices(); ++v )
418 RealVector d( rand01()*2.0 - 1.0, rand01()*2.0 - 1.0, rand01()*2.0 - 1.0 );
419 d = d.getNormalized();
420 Scalar l = rand01() * p * local_average_lengths[ v ];
421 myPositions[ v ] += l * d;
425//-----------------------------------------------------------------------------
426template <typename TRealPoint, typename TRealVector>
427typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::RealPoint
428DGtal::SurfaceMesh<TRealPoint, TRealVector>::
429faceCentroid( Index f ) const
432 for ( auto v : myIncidentVertices[ f ] )
433 c += myPositions[ v ];
434 return c / myIncidentVertices[ f ].size();
437//-----------------------------------------------------------------------------
438template <typename TRealPoint, typename TRealVector>
439typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::RealPoint
440DGtal::SurfaceMesh<TRealPoint, TRealVector>::
441edgeCentroid( Index e ) const
443 const auto& vtcs = edgeVertices( e );
444 RealPoint c = myPositions[ vtcs.first ] + myPositions[ vtcs.second ];
448//-----------------------------------------------------------------------------
449template <typename TRealPoint, typename TRealVector>
450typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
451DGtal::SurfaceMesh<TRealPoint, TRealVector>::
452faceArea( Index f ) const
455 const auto & inc_vtcs = myIncidentVertices[ f ];
456 RealPoint p = myPositions[ inc_vtcs.back() ];
457 const Index m = inc_vtcs.size() - 2;
458 for ( Index i = 0; i < m; ++i )
459 area += ( myPositions[ inc_vtcs[ i ] ] - p )
460 .crossProduct( myPositions[ inc_vtcs[ i+1 ] ] - p ).norm();
464//-----------------------------------------------------------------------------
465template <typename TRealPoint, typename TRealVector>
466typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedFaces
467DGtal::SurfaceMesh<TRealPoint, TRealVector>::
468computeFacesInclusionsInBall( Scalar r, Index f ) const
470 return computeFacesInclusionsInBall( r, f, faceCentroid( f ) );
473//-----------------------------------------------------------------------------
474template <typename TRealPoint, typename TRealVector>
475typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedFaces
476DGtal::SurfaceMesh<TRealPoint, TRealVector>::
477computeFacesInclusionsInBall( Scalar r, Index f, RealPoint p ) const
479 WeightedFaces result;
482 result.push_back( std::make_pair( f, 0.000001 ) );
485 std::unordered_set< Index > marked;
486 std::queue< Index > active;
489 while ( ! active.empty() )
491 Index current = active.front();
493 Scalar weight = faceInclusionRatio( p, r, current );
496 result.push_back( std::make_pair( current, weight ) );
497 auto neighbors = myNeighborFaces[ current ];
498 for ( auto n : neighbors )
499 if ( marked.find( n ) == marked.end() )
509//-----------------------------------------------------------------------------
510template <typename TRealPoint, typename TRealVector>
512< typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Vertices,
513 typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedEdges,
514 typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedFaces >
515DGtal::SurfaceMesh<TRealPoint, TRealVector>::
516computeCellsInclusionsInBall( Scalar r, Index f ) const
518 return computeCellsInclusionsInBall( r, f, faceCentroid( f ) );
521//-----------------------------------------------------------------------------
522template <typename TRealPoint, typename TRealVector>
524< typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Vertices,
525 typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedEdges,
526 typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::WeightedFaces >
527DGtal::SurfaceMesh<TRealPoint, TRealVector>::
528computeCellsInclusionsInBall( Scalar r, Index f, RealPoint p ) const
531 std::set<Vertex> set_v;
532 WeightedEdges result_e;
533 WeightedFaces result_f;
536 result_f.push_back( std::make_pair( f, 0.000001 ) );
537 return std::make_tuple( result_v, result_e, result_f );
539 std::set< Index > marked;
540 std::queue< Index > active;
543 while ( ! active.empty() )
545 Index current = active.front();
547 Scalar fweight = faceInclusionRatio( p, r, current );
550 result_f.push_back( std::make_pair( current, fweight ) );
551 // Taking care of faces, and the breadth-first traversal
552 const auto& neighbors = myNeighborFaces[ current ];
553 for ( auto n : neighbors )
554 if ( marked.find( n ) == marked.end() )
559 // Taking care of edges and vertices
560 const auto& inc_v = myIncidentVertices[ current ];
561 for ( Size i = 0; i < inc_v.size(); ++i )
563 const Vertex vi = inc_v[ i ];
564 const Vertex vn = inc_v[ (i+1) % inc_v.size() ];
565 if ( vertexInclusionRatio( p, r, vi ) > 0.0 )
567 if ( vn < vi ) continue; // edges are ordered pairs
568 const Edge e_ij = makeEdge( vi, vn );
569 if ( e_ij >= nbEdges() ) {
570 trace.error() << "bad edge " << vi << " " << vn << std::endl;
573 Scalar eweight = edgeInclusionRatio( p, r, e_ij );
575 result_e.push_back( std::make_pair( e_ij, eweight ) );
579 result_v = Vertices( set_v.cbegin(), set_v.cend() );
580 return std::make_tuple( result_v, result_e, result_f );
583//-----------------------------------------------------------------------------
584template <typename TRealPoint, typename TRealVector>
585typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
586DGtal::SurfaceMesh<TRealPoint, TRealVector>::
587faceInclusionRatio( RealPoint p, Scalar r, Index f ) const
589 const auto vertices = myIncidentVertices[ f ];
590 const RealPoint b = faceCentroid( f );
591 Scalar d_min = ( b - p ).norm();
592 Scalar d_max = d_min;
593 for ( auto v : vertices )
595 Scalar d = ( myPositions[ v ] - p ).norm();
596 d_max = std::max( d_max, d );
597 d_min = std::min( d_min, d );
599 if ( d_max <= r ) return 1.0;
600 else if ( r <= d_min ) return 0.0;
601 return ( r - d_min ) / ( d_max - d_min );
604//-----------------------------------------------------------------------------
605template <typename TRealPoint, typename TRealVector>
606typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
607DGtal::SurfaceMesh<TRealPoint, TRealVector>::
608edgeInclusionRatio( RealPoint p, Scalar r, Index e ) const
610 const auto vertices = edgeVertices( e );
611 const RealPoint b = edgeCentroid( e );
612 const Scalar d0 = ( myPositions[ vertices.first ] - p ).norm();
613 const Scalar d1 = ( myPositions[ vertices.second ] - p ).norm();
614 Scalar d_min = ( b - p ).norm();
615 Scalar d_max = d_min;
616 d_max = std::max( d_max, std::max( d0, d1 ) );
617 d_min = std::min( d_min, std::min( d0, d1 ) );
618 if ( d_max <= r ) return 1.0;
619 else if ( r <= d_min ) return 0.0;
620 return ( r - d_min ) / ( d_max - d_min );
623//-----------------------------------------------------------------------------
624template <typename TRealPoint, typename TRealVector>
625typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Scalar
626DGtal::SurfaceMesh<TRealPoint, TRealVector>::
627vertexInclusionRatio( RealPoint p, Scalar r, Index v ) const
629 const RealPoint b = myPositions[ v ];
630 return ( ( b - p ).norm() <= r ) ? 1.0 : 0.0;
634///////////////////////////////////////////////////////////////////////////////
635// Interface - public :
637//-----------------------------------------------------------------------------
638template <typename TRealPoint, typename TRealVector>
640DGtal::SurfaceMesh<TRealPoint, TRealVector>::
641selfDisplay ( std::ostream & out ) const
643 out << "[SurfaceMesh" << ( isValid() ? " (OK)" : " (KO)" )
644 << " #V=" << myPositions.size()
645 << " #VN=" << myVertexNormals.size()
646 << " #E=" << myEdgeVertices.size()
647 << " #F=" << myIncidentVertices.size()
648 << " #FN=" << myFaceNormals.size();
652 for ( auto nf : myNeighborFaces ) nb_nf += nf.size();
653 for ( auto nv : myNeighborVertices ) nb_nv += nv.size();
654 for ( auto nfe : myEdgeFaces ) nb_nfe += nfe.size();
656 nb_nv /= nbVertices();
658 out << " E[IF]=" << nb_nf << " E[IV]=" << nb_nv << " E[IFE]=" << nb_nfe;
662//-----------------------------------------------------------------------------
663template <typename TRealPoint, typename TRealVector>
665DGtal::SurfaceMesh<TRealPoint, TRealVector>::
668 return myPositions.size() == myIncidentFaces.size()
669 && ( myVertexNormals.size() == 0
670 || ( myVertexNormals.size() == myPositions.size() ) )
671 && ( myFaceNormals.size() == 0
672 || ( myFaceNormals.size() == myIncidentVertices.size() ) );
676//-----------------------------------------------------------------------------
677template <typename TRealPoint, typename TRealVector>
679DGtal::SurfaceMesh<TRealPoint, TRealVector>::
682 myNeighborFaces .resize( nbFaces() );
683 myNeighborVertices.resize( nbVertices() );
684 std::vector< std::set< Index > > tmp( nbVertices() );
685 // For each vertex, computes its neighboring vertices
686 for ( auto incident_vertices : allIncidentVertices() )
688 const Size nb_iv = incident_vertices.size();
689 for ( Size k = 0; k < nb_iv; ++k )
691 tmp[ incident_vertices[ k ] ].insert( incident_vertices[ (k+1)%nb_iv ] );
692 tmp[ incident_vertices[ (k+1)%nb_iv ] ].insert( incident_vertices[ k ] );
695 // For each vertex, computes its neighboring vertices
696 for ( Index idx_v = 0; idx_v < nbVertices(); ++idx_v )
697 myNeighborVertices[ idx_v ] = Vertices( tmp[ idx_v ].cbegin(), tmp[ idx_v ].cend() );
699 // For each face, computes its neighboring faces
701 for ( auto incident_vertices : allIncidentVertices() )
703 std::set< Index > neighbor_faces_set;
704 std::sort( incident_vertices.begin(), incident_vertices.end() );
705 for ( auto idx_v : incident_vertices )
707 const auto & incident_faces = incidentFaces( idx_v );
708 for ( auto inc_f : incident_faces )
710 // Keep only faces incident to two vertices of f.
711 auto incident_vertices2 = incidentVertices( inc_f );
712 std::sort( incident_vertices2.begin(), incident_vertices2.end() );
714 std::set_intersection( incident_vertices.cbegin(), incident_vertices.cend(),
715 incident_vertices2.cbegin(), incident_vertices2.cend(),
716 std::back_inserter( common ) );
717 if ( common.size() == 2 )
718 neighbor_faces_set.insert( inc_f );
721 neighbor_faces_set.erase( idx_f );
722 Faces neighbor_faces( neighbor_faces_set.begin(), neighbor_faces_set.end() );
723 myNeighborFaces[ idx_f++ ] = neighbor_faces;
727//-----------------------------------------------------------------------------
728template <typename TRealPoint, typename TRealVector>
730DGtal::SurfaceMesh<TRealPoint, TRealVector>::
733 std::map< VertexPair, std::vector<Face> > edge2face_right;
734 std::map< VertexPair, std::vector<Face> > edge2face_left;
735 std::set< VertexPair > edges;
737 for ( auto incident_vertices : allIncidentVertices() )
739 const Size n = incident_vertices.size();
740 for ( Size i = 0; i < n; i++ )
742 VertexPair e = std::make_pair( incident_vertices[ i ],
743 incident_vertices[ (i+1) % n ] );
744 if ( e.first < e.second ) {
745 edge2face_left[ e ].push_back( idx_f );
747 std::swap( e.first, e.second );
748 edge2face_right[ e ].push_back( idx_f );
754 const Size nbe = edges.size();
755 myVertexPairEdge.clear();
756 myEdgeVertices.resize ( nbe );
757 myEdgeFaces.resize ( nbe );
758 myEdgeRightFaces.resize( nbe );
759 myEdgeLeftFaces.resize ( nbe );
761 for ( auto e : edges )
763 myEdgeVertices [ idx_e ] = e;
764 myVertexPairEdge[ e ] = idx_e;
765 myEdgeLeftFaces [ idx_e ] = edge2face_left [ e ];
766 myEdgeRightFaces[ idx_e ] = edge2face_right[ e ];
767 myEdgeFaces [ idx_e ] = myEdgeRightFaces[ idx_e ];
768 myEdgeFaces [ idx_e ].insert( myEdgeFaces[ idx_e ].end(),
769 myEdgeLeftFaces[ idx_e ].cbegin(),
770 myEdgeLeftFaces[ idx_e ].cend() );
775//-----------------------------------------------------------------------------
776template <typename TRealPoint, typename TRealVector>
777typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edges
778DGtal::SurfaceMesh<TRealPoint, TRealVector>::
779computeManifoldBoundaryEdges() const
782 for ( Index e = 0; e < myEdgeFaces.size(); ++e )
784 if ( myEdgeFaces[ e ].size() == 1 )
785 edges.push_back( e );
790//-----------------------------------------------------------------------------
791template <typename TRealPoint, typename TRealVector>
792typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edges
793DGtal::SurfaceMesh<TRealPoint, TRealVector>::
794computeManifoldInnerEdges() const
797 for ( Index e = 0; e < myEdgeFaces.size(); ++e )
799 if ( myEdgeFaces[ e ].size() == 2 )
800 edges.push_back( e );
805//-----------------------------------------------------------------------------
806template <typename TRealPoint, typename TRealVector>
807typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edges
808DGtal::SurfaceMesh<TRealPoint, TRealVector>::
809computeManifoldInnerConsistentEdges() const
812 for ( Index e = 0; e < myEdgeFaces.size(); ++e )
814 if ( ( myEdgeRightFaces[ e ].size() == 1 )
815 && ( myEdgeLeftFaces[ e ].size() == 1 ) )
816 edges.push_back( e );
821//-----------------------------------------------------------------------------
822template <typename TRealPoint, typename TRealVector>
823typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edges
824DGtal::SurfaceMesh<TRealPoint, TRealVector>::
825computeManifoldInnerUnconsistentEdges() const
828 for ( Index e = 0; e < myEdgeFaces.size(); ++e )
830 if ( ( myEdgeRightFaces[ e ].size() == 2 )
831 || ( myEdgeLeftFaces[ e ].size() == 2 ) )
832 edges.push_back( e );
837//-----------------------------------------------------------------------------
838template <typename TRealPoint, typename TRealVector>
839typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::Edges
840DGtal::SurfaceMesh<TRealPoint, TRealVector>::
841computeNonManifoldEdges() const
844 for ( Index e = 0; e < myEdgeFaces.size(); ++e )
846 if ( myEdgeFaces[ e ].size() >= 3 )
847 edges.push_back( e );
853//-----------------------------------------------------------------------------
854template <typename TRealPoint, typename TRealVector>
856DGtal::SurfaceMesh<TRealPoint, TRealVector>::
857isFlippable( const Edge e ) const
859 /// An edge is (topologically) flippable iff: (1) it does not lie
860 /// on the boundary, (2) it is bordered by two triangles, one that
861 /// to its right, one to its left, (3) the two other vertices of
862 /// the quad are not already neighbors.
864 // edge is (i,j) with i<j
866 // (1) the edge must be bordered by two faces, one on its left, one on its right.
867 const Faces& rfaces = edgeRightFaces( e );
868 if ( rfaces.size() != 1 ) return false; //< not one face to the right
869 const Faces& lfaces = edgeLeftFaces ( e );
870 if ( lfaces.size() != 1 ) return false; //< not one face to the left
872 // (2) both faces must be triangles
873 const Face rf = rfaces.front(); //< some `(..., j, i, ... )` since faces are ccw.
874 const Face lf = lfaces.front(); //< some `(..., i, j, ... )` since faces are ccw.
875 const Vertices& rvtx = incidentVertices( rf );
876 if ( rvtx.size() != 3 ) return false; //< right face is not a triangle
877 const Vertices& lvtx = incidentVertices( lf );
878 if ( lvtx.size() != 3 ) return false; //< left face is not a triangle
880 // (3) the two other vertices of the quad are not already neighbors.
882 std::tie( i, j ) = edgeVertices( e );
883 const auto ir = ( rvtx[ 0 ] == i ) ? 0 : ( ( rvtx[ 1 ] == i ) ? 1 : 2 );
884 const auto il = ( lvtx[ 0 ] == i ) ? 0 : ( ( lvtx[ 1 ] == i ) ? 1 : 2 );
885 const Vertex k = rvtx[ (ir + 1) % 3 ]; // right triangle is (j,i,k)
886 const Vertex l = lvtx[ (il + 2) % 3 ]; // left triangle is (i,j,l).
887 if ( ! ( k != i && k != j && l != i && l != j && k != l ) )
889 /// May happen if we have identical triangles (i,j,k) and (j,i,k)
890 if ( k == l ) return false;
891 /// Otherwise there is a problem.
892 trace.error() << "[SurfaceMesh::isFlippable] Invalid neighbors to edge: "
893 << "(i,j,k,l) == (" << i << "," << j << "," << k << "," << l << ")"
895 << "right=(" << rvtx[ 0 ] << "," << rvtx[ 1 ] << "," << rvtx[ 2 ] << ")" << std::endl
896 << "left =(" << lvtx[ 0 ] << "," << lvtx[ 1 ] << "," << lvtx[ 2 ] << ")" << std::endl;
899 const Vertices& Nk = neighborVertices( k );
900 const auto itl = std::find( Nk.cbegin(), Nk.cend(), l );
901 return itl == Nk.cend();
904//-----------------------------------------------------------------------------
905template <typename TRealPoint, typename TRealVector>
906typename DGtal::SurfaceMesh<TRealPoint, TRealVector>::VertexPair
907DGtal::SurfaceMesh<TRealPoint, TRealVector>::
908otherDiagonal( const Edge e ) const
910 // only valid if `isFlippable( e )` is true.
911 const Faces& rfaces = edgeRightFaces( e );
912 const Faces& lfaces = edgeLeftFaces ( e );
913 const Face rf = rfaces.front(); //< some `(..., j, i, ... )` since faces are ccw.
914 const Face lf = lfaces.front(); //< some `(..., i, j, ... )` since faces are ccw.
915 const Vertices& rvtx = incidentVertices( rf );
916 const Vertices& lvtx = incidentVertices( lf );
918 std::tie( i, j ) = edgeVertices( e );
919 const auto ir = ( rvtx[ 0 ] == i ) ? 0 : ( ( rvtx[ 1 ] == i ) ? 1 : 2 );
920 const auto il = ( lvtx[ 0 ] == i ) ? 0 : ( ( lvtx[ 1 ] == i ) ? 1 : 2 );
921 const Vertex k = rvtx[ (ir + 1) % 3 ]; // right triangle is (j,i,k)
922 const Vertex l = lvtx[ (il + 2) % 3 ]; // left triangle is (i,j,l).
923 return ( k < l ) ? std::make_pair( k, l ) : std::make_pair( l, k );
927//-----------------------------------------------------------------------------
928template <typename TRealPoint, typename TRealVector>
930DGtal::SurfaceMesh<TRealPoint, TRealVector>::
931flip( const Edge e, bool recompute_face_normals )
940 i --- e --- j ==> i lf e rf j if k < l otherwise rf and lf are swapped
949 // (1) We must collect all information: right and left face, vertices k and l
950 const Face rf = edgeRightFaces( e ).front(); //< some `(..., j, i, ... )` since faces are ccw.
951 const Face lf = edgeLeftFaces ( e ).front(); //< some `(..., i, j, ... )` since faces are ccw.
952 Vertices& rvtx = myIncidentVertices[ rf ];
953 Vertices& lvtx = myIncidentVertices[ lf ];
955 std::tie( i, j ) = edgeVertices( e );
956 const auto ir = ( rvtx[ 0 ] == i ) ? 0 : ( ( rvtx[ 1 ] == i ) ? 1 : 2 );
957 const auto il = ( lvtx[ 0 ] == i ) ? 0 : ( ( lvtx[ 1 ] == i ) ? 1 : 2 );
958 const Vertex k = rvtx[ (ir + 1) % 3 ]; // right triangle is (j,i,k)
959 const Vertex l = lvtx[ (il + 2) % 3 ]; // left triangle is (i,j,l).
961 // (2) we must update all arrays.
962 // std::vector< Faces > myNeighborFaces; //< not done
972 i --- e --- j ==> i lf e rf j ( k < l )
980 // e=(k,l) with rf as right face et lf as left face
981 rvtx[ 0 ] = l; rvtx[ 1 ] = k; rvtx[ 2 ] = j;
982 lvtx[ 0 ] = k; lvtx[ 1 ] = l; lvtx[ 2 ] = i;
983 VertexPair kl = std::make_pair( k, l );
984 myEdgeVertices [ e ] = kl;
985 myVertexPairEdge[ kl ] = e;
986 removeIndex ( myIncidentFaces[ i ], rf );
987 removeIndex ( myIncidentFaces[ j ], lf );
988 addIndex ( myIncidentFaces[ k ], lf );
989 addIndex ( myIncidentFaces[ l ], rf );
990 removeIndex ( myNeighborVertices[ i ], j );
991 removeIndex ( myNeighborVertices[ j ], i );
992 addIndex ( myNeighborVertices[ k ], l );
993 addIndex ( myNeighborVertices[ l ], k );
994 // No need to update myEdgeFaces, myEdgeRightFaces and myEdgeLeftFaces for edge e.
995 const auto e_ik = makeEdge( i, k );
996 const bool e_ik_left = i < k;
997 replaceIndex( myEdgeFaces[ e_ik ], rf, lf );
998 if ( e_ik_left ) myEdgeLeftFaces [ e_ik ][ 0 ] = lf;
999 else myEdgeRightFaces[ e_ik ][ 0 ] = lf;
1000 // nothing to change for e_kj (rf is still the incident face)
1001 const auto e_jl = makeEdge( j, l );
1002 const bool e_jl_left = j < l;
1003 replaceIndex( myEdgeFaces[ e_jl ], lf, rf );
1004 if ( e_jl_left ) myEdgeLeftFaces [ e_jl ][ 0 ] = rf;
1005 else myEdgeRightFaces[ e_jl ][ 0 ] = rf;
1006 // nothing to change for e_li (lf is still the incident face)
1007 // vertex normals are not updated.
1008 // face normals are recomputed if asked for.
1009 if ( recompute_face_normals )
1011 computeFaceNormalFromPositions( rf );
1012 computeFaceNormalFromPositions( lf );
1024 i --- e --- j ==> i rf e lf j (k > l)
1032 // e=(l,k) with rf as right face et lf as left face
1033 rvtx[ 0 ] = i; rvtx[ 1 ] = k; rvtx[ 2 ] = l;
1034 lvtx[ 0 ] = j; lvtx[ 1 ] = l; lvtx[ 2 ] = k;
1035 VertexPair lk = std::make_pair( l, k );
1036 myEdgeVertices [ e ] = lk;
1037 myVertexPairEdge[ lk ] = e;
1038 removeIndex ( myIncidentFaces[ i ], lf );
1039 removeIndex ( myIncidentFaces[ j ], rf );
1040 addIndex ( myIncidentFaces[ k ], lf );
1041 addIndex ( myIncidentFaces[ l ], rf );
1042 removeIndex ( myNeighborVertices[ i ], j );
1043 removeIndex ( myNeighborVertices[ j ], i );
1044 addIndex ( myNeighborVertices[ k ], l );
1045 addIndex ( myNeighborVertices[ l ], k );
1046 // No need to update myEdgeFaces, myEdgeRightFaces and myEdgeLeftFaces for edge e.
1047 const auto e_kj = makeEdge( k, j );
1048 const bool e_kj_left = k < j;
1049 replaceIndex( myEdgeFaces[ e_kj ], rf, lf );
1050 if ( e_kj_left ) myEdgeLeftFaces [ e_kj ][ 0 ] = lf;
1051 else myEdgeRightFaces[ e_kj ][ 0 ] = lf;
1052 // nothing to change for e_jl (lf is still the incident face)
1053 const auto e_li = makeEdge( l, i );
1054 const bool e_li_left = l < i;
1055 replaceIndex( myEdgeFaces[ e_li ], lf, rf );
1056 if ( e_li_left ) myEdgeLeftFaces [ e_li ][ 0 ] = rf;
1057 else myEdgeRightFaces[ e_li ][ 0 ] = rf;
1058 // nothing to change for e_ik (rf is still the incident face)
1059 // vertex normals are not updated.
1060 // face normals are recomputed if asked for.
1061 if ( recompute_face_normals )
1063 computeFaceNormalFromPositions( rf );
1064 computeFaceNormalFromPositions( lf );
1069///////////////////////////////////////////////////////////////////////////////
1070// Implementation of inline functions //
1072//-----------------------------------------------------------------------------
1073template <typename TRealPoint, typename TRealVector>
1075DGtal::operator<< ( std::ostream & out,
1076 const SurfaceMesh<TRealPoint, TRealVector> & object )
1078 object.selfDisplay( out );
1083///////////////////////////////////////////////////////////////////////////////
1084///////////////////////////////////////////////////////////////////////////////