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 TriangulatedSurface.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 TriangulatedSurface.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32//////////////////////////////////////////////////////////////////////////////
34///////////////////////////////////////////////////////////////////////////////
35// IMPLEMENTATION of inline methods.
36///////////////////////////////////////////////////////////////////////////////
38///////////////////////////////////////////////////////////////////////////////
39// ----------------------- Standard services ------------------------------
41//-----------------------------------------------------------------------------
42template <typename TPoint>
45DGtal::TriangulatedSurface<TPoint>::build()
48 trace.warning() << "[DGtal::TriangulatedSurface<TPoint>::build()]"
49 << " attempting to rebuild a triangulated surface." << std::endl;
52 isHEDSValid = myHEDS.build( myTriangles );
53 if ( myHEDS.nbVertices() != myPositions.size() ) {
54 trace.warning() << "[DGtal::TriangulatedSurface<TPoint>::build()]"
55 << " the size of vertex data array (s1) and the number of vertices (s2) in the triangulated surface does not match:"
56 << " s1=" << myPositions.size()
57 << " s2=" << myHEDS.nbVertices() << std::endl;
63//-----------------------------------------------------------------------------
64template <typename TPoint>
67DGtal::TriangulatedSurface<TPoint>::clear()
75//-----------------------------------------------------------------------------
76template <typename TPoint>
78typename DGtal::TriangulatedSurface<TPoint>::VertexIndex
79DGtal::TriangulatedSurface<TPoint>::addVertex( const Point& vdata )
81 VertexIndex vi = myPositions.size();
82 myPositions.push_back( vdata );
86//-----------------------------------------------------------------------------
87template <typename TPoint>
89typename DGtal::TriangulatedSurface<TPoint>::FaceIndex
90DGtal::TriangulatedSurface<TPoint>::addTriangle
91( VertexIndex v0, VertexIndex v1, VertexIndex v2 )
93 FaceIndex fi = myTriangles.size();
94 myTriangles.push_back( Triangle( v0, v1, v2 ) );
97//-----------------------------------------------------------------------------
98template <typename TPoint>
100typename DGtal::TriangulatedSurface<TPoint>::Point&
101DGtal::TriangulatedSurface<TPoint>::position( Vertex v )
103 ASSERT( v < myPositions.size() );
104 return myPositions[ v ];
106//-----------------------------------------------------------------------------
107template <typename TPoint>
109const typename DGtal::TriangulatedSurface<TPoint>::Point&
110DGtal::TriangulatedSurface<TPoint>::position( Vertex v ) const
112 ASSERT( v < myPositions.size() );
113 return myPositions[ v ];
115//-----------------------------------------------------------------------------
116template <typename TPoint>
118typename DGtal::TriangulatedSurface<TPoint>::Size
119DGtal::TriangulatedSurface<TPoint>::size() const
121 return myPositions.size();
123//-----------------------------------------------------------------------------
124template <typename TPoint>
126typename DGtal::TriangulatedSurface<TPoint>::Size
127DGtal::TriangulatedSurface<TPoint>::bestCapacity() const
131//-----------------------------------------------------------------------------
132template <typename TPoint>
134typename DGtal::TriangulatedSurface<TPoint>::Size
135DGtal::TriangulatedSurface<TPoint>::degree( const Vertex & v ) const
138 return myHEDS.nbNeighboringVertices( v );
141//-----------------------------------------------------------------------------
142template <typename TPoint>
143template <typename OutputIterator>
146DGtal::TriangulatedSurface<TPoint>::writeNeighbors
147( OutputIterator &it, const Vertex & v ) const
150 typedef HalfEdgeDataStructure::VertexIndexRange VertexIndexRange;
151 VertexIndexRange neighbors;
152 myHEDS.getNeighboringVertices( v, neighbors );
153 for ( Vertex nv : neighbors ) *it++ = nv;
156//-----------------------------------------------------------------------------
157template <typename TPoint>
158template <typename OutputIterator, typename VertexPredicate>
161DGtal::TriangulatedSurface<TPoint>::writeNeighbors
162( OutputIterator &it, const Vertex & v, const VertexPredicate & pred) const
165 typedef HalfEdgeDataStructure::VertexIndexRange VertexIndexRange;
166 VertexIndexRange neighbors;
167 myHEDS.getNeighboringVertices( v, neighbors );
168 for ( Vertex nv : neighbors ) if ( pred( nv ) ) *it++ = nv;
171//-----------------------------------------------------------------------------
172template <typename TPoint>
174typename DGtal::TriangulatedSurface<TPoint>::ArcRange
175DGtal::TriangulatedSurface<TPoint>::outArcs( const Vertex & v ) const
178 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
179 Index hei = start_hei;
182 const HalfEdge& he = myHEDS.halfEdge( hei );
183 if( INVALID_FACE != he.face ) result.push_back( hei );
184 hei = myHEDS.halfEdge( he.opposite ).next;
186 while ( hei != start_hei );
190//-----------------------------------------------------------------------------
191template <typename TPoint>
193typename DGtal::TriangulatedSurface<TPoint>::ArcRange
194DGtal::TriangulatedSurface<TPoint>::inArcs( const Vertex & v ) const
197 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
198 Index hei = start_hei;
201 const HalfEdge& he = myHEDS.halfEdge( hei );
202 if( INVALID_FACE != he.face ) result.push_back( he.opposite );
203 hei = myHEDS.halfEdge( he.opposite ).next;
205 while ( hei != start_hei );
209//-----------------------------------------------------------------------------
210template <typename TPoint>
212typename DGtal::TriangulatedSurface<TPoint>::FaceRange
213DGtal::TriangulatedSurface<TPoint>::facesAroundVertex( const Vertex & v ) const
216 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
217 Index hei = start_hei;
220 const HalfEdge& he = myHEDS.halfEdge( hei );
221 if( INVALID_FACE != he.face ) result.push_back( he.face );
222 hei = myHEDS.halfEdge( he.opposite ).next;
224 while ( hei != start_hei );
228//-----------------------------------------------------------------------------
229template <typename TPoint>
231typename DGtal::TriangulatedSurface<TPoint>::Vertex
232DGtal::TriangulatedSurface<TPoint>::head( const Arc & a ) const
234 return myHEDS.halfEdge( a ).toVertex;
237//-----------------------------------------------------------------------------
238template <typename TPoint>
240typename DGtal::TriangulatedSurface<TPoint>::Vertex
241DGtal::TriangulatedSurface<TPoint>::tail( const Arc & a ) const
243 return head( opposite( a ) );
246//-----------------------------------------------------------------------------
247template <typename TPoint>
249typename DGtal::TriangulatedSurface<TPoint>::Arc
250DGtal::TriangulatedSurface<TPoint>::opposite( const Arc & a ) const
252 return myHEDS.halfEdge( a ).opposite;
255//-----------------------------------------------------------------------------
256template <typename TPoint>
258typename DGtal::TriangulatedSurface<TPoint>::Arc
259DGtal::TriangulatedSurface<TPoint>::next( const Arc & a ) const
261 return myHEDS.halfEdge( a ).next;
263//-----------------------------------------------------------------------------
264template <typename TPoint>
266typename DGtal::TriangulatedSurface<TPoint>::Arc
267DGtal::TriangulatedSurface<TPoint>::arc
268( const Vertex & t, const Vertex & h ) const
270 return myHEDS.findHalfEdgeIndexFromArc( t, h );
273//-----------------------------------------------------------------------------
274template <typename TPoint>
276typename DGtal::TriangulatedSurface<TPoint>::Face
277DGtal::TriangulatedSurface<TPoint>::faceAroundArc( const Arc & a ) const
279 return myHEDS.halfEdge( a ).face;
281//-----------------------------------------------------------------------------
282template <typename TPoint>
284typename DGtal::TriangulatedSurface<TPoint>::FaceRange
285DGtal::TriangulatedSurface<TPoint>::facesAroundArc( const Arc & a ) const
288 Face f = faceAroundArc( a );
289 if ( f != INVALID_FACE ) result.push_back( f );
293//-----------------------------------------------------------------------------
294template <typename TPoint>
296typename DGtal::TriangulatedSurface<TPoint>::VertexRange
297DGtal::TriangulatedSurface<TPoint>::verticesAroundFace( const Face & f ) const
300 const Index start_hei = myHEDS.halfEdgeIndexFromFaceIndex( f );
301 Index hei = start_hei;
303 const HalfEdge& he = myHEDS.halfEdge( hei );
304 ASSERT( ( he.face == f )
305 && "[TriangulatedSurface::verticesAroundFace] invalid face." );
306 result.push_back( he.toVertex );
308 } while ( hei != start_hei );
309 ASSERT( result.size() == 3 );
313//-----------------------------------------------------------------------------
314template <typename TPoint>
316typename DGtal::TriangulatedSurface<TPoint>::ArcRange
317DGtal::TriangulatedSurface<TPoint>::arcsAroundFace( const Face & f ) const
321 const Index start_hei = myHEDS.halfEdgeIndexFromFaceIndex( f );
322 Index hei = start_hei;
324 result.push_back( hei );
325 const HalfEdge& he = myHEDS.halfEdge( hei );
326 ASSERT( ( he.face == f )
327 && "[TriangulatedSurface::arcsAroundFace] invalid face." );
329 } while ( hei != start_hei );
330 ASSERT( result.size() == 3 );
334//-----------------------------------------------------------------------------
335template <typename TPoint>
338DGtal::TriangulatedSurface<TPoint>::isVertexBoundary( const Vertex& v ) const
340 return myHEDS.isVertexBoundary( v );
343//-----------------------------------------------------------------------------
344template <typename TPoint>
347DGtal::TriangulatedSurface<TPoint>::isArcBoundary( const Arc& v ) const
349 return INVALID_FACE == myHEDS.halfEdge( v ).face;
352//-----------------------------------------------------------------------------
353template <typename TPoint>
355typename DGtal::TriangulatedSurface<TPoint>::VertexRange
356DGtal::TriangulatedSurface<TPoint>::verticesOfFacesAroundArc( Arc a ) const
358 Arc a2 = opposite( a );
359 if ( isArcBoundary( a ) )
364 V[ 2 ] = head( next( a2 ) );
367 else if ( isArcBoundary( a2 ) )
371 V[ 1 ] = head( next( a ) );
379 V[ 1 ] = head( next( a ) );
381 V[ 3 ] = head( next( a2 ) );
386//-----------------------------------------------------------------------------
387template <typename TPoint>
389typename DGtal::TriangulatedSurface<TPoint>::FaceRange
390DGtal::TriangulatedSurface<TPoint>::allFaces() const
392 FaceRange result( nbFaces() );
393 for ( Face fi = 0; fi < result.size(); ++fi )
397//-----------------------------------------------------------------------------
398template <typename TPoint>
400typename DGtal::TriangulatedSurface<TPoint>::ArcRange
401DGtal::TriangulatedSurface<TPoint>::allArcs() const
403 ArcRange result( nbArcs() );
404 for ( Arc fi = 0; fi < result.size(); ++fi )
408//-----------------------------------------------------------------------------
409template <typename TPoint>
411typename DGtal::TriangulatedSurface<TPoint>::VertexRange
412DGtal::TriangulatedSurface<TPoint>::allVertices() const
414 VertexRange result( nbVertices() );
415 for ( Vertex fi = 0; fi < result.size(); ++fi )
420//-----------------------------------------------------------------------------
421template <typename TPoint>
423typename DGtal::TriangulatedSurface<TPoint>::ArcRange
424DGtal::TriangulatedSurface<TPoint>::allBoundaryArcs() const
426 return myHEDS.boundaryHalfEdgeIndices();
429//-----------------------------------------------------------------------------
430template <typename TPoint>
432typename DGtal::TriangulatedSurface<TPoint>::VertexRange
433DGtal::TriangulatedSurface<TPoint>::allBoundaryVertices() const
435 return myHEDS.boundaryVertices();
438//-----------------------------------------------------------------------------
439template <typename TPoint>
442DGtal::TriangulatedSurface<TPoint>::isFlippable( const Arc a ) const
444 if ( isArcBoundary( a ) || isArcBoundary( opposite( a ) ) ) return false;
445 const auto v1 = head( next( a ) );
446 const auto v2 = head( next( opposite( a ) ) );
447 std::vector< Index > neighbors_v1;
448 auto outIt = std::back_inserter( neighbors_v1 );
449 writeNeighbors( outIt, v1 );
450 const auto itv2 = std::find( neighbors_v1.cbegin(), neighbors_v1.cend(), v2 );
451 return itv2 == neighbors_v1.cend();
454//-----------------------------------------------------------------------------
455template <typename TPoint>
458DGtal::TriangulatedSurface<TPoint>::flip( const Arc a )
460 myHEDS.flip( a, false );
464//-----------------------------------------------------------------------------
465template <typename TPoint>
467typename DGtal::TriangulatedSurface<TPoint>::Vertex
468DGtal::TriangulatedSurface<TPoint>::split( const Arc a, const Point& data )
470 Vertex v = myHEDS.split( a, false );
471 ASSERT( v == myPositions.size() );
472 myPositions.push_back( data );
476//-----------------------------------------------------------------------------
477template <typename TPoint>
480DGtal::TriangulatedSurface<TPoint>::isMergeable( const Arc a ) const
482 const Vertex v3 = head( next( a ) );
483 if ( degree( v3 ) < 4 ) return false;
484 const Vertex v4 = head( next( opposite( a ) ) );
485 if ( degree( v4 ) < 4 ) return false;
486 auto A1 = outArcs( head( a ) );
487 auto A2 = outArcs( tail( a ) );
488 std::vector<Vertex> V1, V2;
489 for ( Arc a1 : A1 ) V1.push_back( head( a1 ) );
490 for ( Arc a2 : A2 ) V2.push_back( head( a2 ) );
491 std::sort( V1.begin(), V1.end() );
492 std::sort( V2.begin(), V2.end() );
493 std::vector<Vertex> VI( V1.size() );
494 auto it = std::set_intersection( V1.begin(), V1.end(), V2.begin(), V2.end(),
496 if ( ( it - VI.begin() ) != 2 ) return false;
497 return myHEDS.isMergeable( a );
500//-----------------------------------------------------------------------------
501template <typename TPoint>
503typename DGtal::TriangulatedSurface<TPoint>::Vertex
504DGtal::TriangulatedSurface<TPoint>::merge( const Arc a, const Point& data )
506 const Vertex v_sup = head( a );
507 const Vertex v = myHEDS.merge( a, false );
508 ASSERT( v < myPositions.size() );
509 myPositions[ v ] = data;
510 myPositions[ v_sup ] = myPositions.back();
511 myPositions.pop_back();
515///////////////////////////////////////////////////////////////////////////////
516// Interface - public :
519 * Writes/Displays the object on an output stream.
520 * @param out the output stream where the object is written.
522template <typename TPoint>
525DGtal::TriangulatedSurface<TPoint>::selfDisplay ( std::ostream & out ) const
527 out << "[TriangulatedSurface #V=" << myHEDS.nbVertices()
528 << " #E=" << myHEDS.nbEdges() << " #F=" << myHEDS.nbFaces()
529 << " Chi=" << Euler() << "]";
533 * Checks the validity/consistency of the object.
534 * @return 'true' if the object is valid, 'false' otherwise.
536template <typename TPoint>
539DGtal::TriangulatedSurface<TPoint>::isValid() const
546///////////////////////////////////////////////////////////////////////////////
547// Implementation of inline functions //
549template <typename TPoint>
552DGtal::operator<< ( std::ostream & out,
553 const TriangulatedSurface<TPoint> & object )
555 object.selfDisplay( out );
560///////////////////////////////////////////////////////////////////////////////