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 //-----------------------------------------------------------------------------
42 template <typename TPoint>
45 DGtal::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 //-----------------------------------------------------------------------------
64 template <typename TPoint>
67 DGtal::TriangulatedSurface<TPoint>::clear()
75 //-----------------------------------------------------------------------------
76 template <typename TPoint>
78 typename DGtal::TriangulatedSurface<TPoint>::VertexIndex
79 DGtal::TriangulatedSurface<TPoint>::addVertex( const Point& vdata )
81 VertexIndex vi = myPositions.size();
82 myPositions.push_back( vdata );
86 //-----------------------------------------------------------------------------
87 template <typename TPoint>
89 typename DGtal::TriangulatedSurface<TPoint>::FaceIndex
90 DGtal::TriangulatedSurface<TPoint>::addTriangle
91 ( VertexIndex v0, VertexIndex v1, VertexIndex v2 )
93 FaceIndex fi = myTriangles.size();
94 myTriangles.push_back( Triangle( v0, v1, v2 ) );
97 //-----------------------------------------------------------------------------
98 template <typename TPoint>
100 typename DGtal::TriangulatedSurface<TPoint>::Point&
101 DGtal::TriangulatedSurface<TPoint>::position( Vertex v )
103 ASSERT( v < myPositions.size() );
104 return myPositions[ v ];
106 //-----------------------------------------------------------------------------
107 template <typename TPoint>
109 const typename DGtal::TriangulatedSurface<TPoint>::Point&
110 DGtal::TriangulatedSurface<TPoint>::position( Vertex v ) const
112 ASSERT( v < myPositions.size() );
113 return myPositions[ v ];
115 //-----------------------------------------------------------------------------
116 template <typename TPoint>
118 typename DGtal::TriangulatedSurface<TPoint>::Size
119 DGtal::TriangulatedSurface<TPoint>::size() const
121 return myPositions.size();
123 //-----------------------------------------------------------------------------
124 template <typename TPoint>
126 typename DGtal::TriangulatedSurface<TPoint>::Size
127 DGtal::TriangulatedSurface<TPoint>::bestCapacity() const
131 //-----------------------------------------------------------------------------
132 template <typename TPoint>
134 typename DGtal::TriangulatedSurface<TPoint>::Size
135 DGtal::TriangulatedSurface<TPoint>::degree( const Vertex & v ) const
138 return myHEDS.nbNeighboringVertices( v );
141 //-----------------------------------------------------------------------------
142 template <typename TPoint>
143 template <typename OutputIterator>
146 DGtal::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 //-----------------------------------------------------------------------------
157 template <typename TPoint>
158 template <typename OutputIterator, typename VertexPredicate>
161 DGtal::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 //-----------------------------------------------------------------------------
172 template <typename TPoint>
174 typename DGtal::TriangulatedSurface<TPoint>::ArcRange
175 DGtal::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 //-----------------------------------------------------------------------------
191 template <typename TPoint>
193 typename DGtal::TriangulatedSurface<TPoint>::ArcRange
194 DGtal::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 //-----------------------------------------------------------------------------
210 template <typename TPoint>
212 typename DGtal::TriangulatedSurface<TPoint>::FaceRange
213 DGtal::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 //-----------------------------------------------------------------------------
229 template <typename TPoint>
231 typename DGtal::TriangulatedSurface<TPoint>::Vertex
232 DGtal::TriangulatedSurface<TPoint>::head( const Arc & a ) const
234 return myHEDS.halfEdge( a ).toVertex;
237 //-----------------------------------------------------------------------------
238 template <typename TPoint>
240 typename DGtal::TriangulatedSurface<TPoint>::Vertex
241 DGtal::TriangulatedSurface<TPoint>::tail( const Arc & a ) const
243 return head( opposite( a ) );
246 //-----------------------------------------------------------------------------
247 template <typename TPoint>
249 typename DGtal::TriangulatedSurface<TPoint>::Arc
250 DGtal::TriangulatedSurface<TPoint>::opposite( const Arc & a ) const
252 return myHEDS.halfEdge( a ).opposite;
255 //-----------------------------------------------------------------------------
256 template <typename TPoint>
258 typename DGtal::TriangulatedSurface<TPoint>::Arc
259 DGtal::TriangulatedSurface<TPoint>::next( const Arc & a ) const
261 return myHEDS.halfEdge( a ).next;
263 //-----------------------------------------------------------------------------
264 template <typename TPoint>
266 typename DGtal::TriangulatedSurface<TPoint>::Arc
267 DGtal::TriangulatedSurface<TPoint>::arc
268 ( const Vertex & t, const Vertex & h ) const
270 return myHEDS.findHalfEdgeIndexFromArc( t, h );
273 //-----------------------------------------------------------------------------
274 template <typename TPoint>
276 typename DGtal::TriangulatedSurface<TPoint>::Face
277 DGtal::TriangulatedSurface<TPoint>::faceAroundArc( const Arc & a ) const
279 return myHEDS.halfEdge( a ).face;
281 //-----------------------------------------------------------------------------
282 template <typename TPoint>
284 typename DGtal::TriangulatedSurface<TPoint>::FaceRange
285 DGtal::TriangulatedSurface<TPoint>::facesAroundArc( const Arc & a ) const
288 Face f = faceAroundArc( a );
289 if ( f != INVALID_FACE ) result.push_back( f );
293 //-----------------------------------------------------------------------------
294 template <typename TPoint>
296 typename DGtal::TriangulatedSurface<TPoint>::VertexRange
297 DGtal::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 //-----------------------------------------------------------------------------
314 template <typename TPoint>
316 typename DGtal::TriangulatedSurface<TPoint>::ArcRange
317 DGtal::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 //-----------------------------------------------------------------------------
335 template <typename TPoint>
338 DGtal::TriangulatedSurface<TPoint>::isVertexBoundary( const Vertex& v ) const
340 return myHEDS.isVertexBoundary( v );
343 //-----------------------------------------------------------------------------
344 template <typename TPoint>
347 DGtal::TriangulatedSurface<TPoint>::isArcBoundary( const Arc& v ) const
349 return INVALID_FACE == myHEDS.halfEdge( v ).face;
352 //-----------------------------------------------------------------------------
353 template <typename TPoint>
355 typename DGtal::TriangulatedSurface<TPoint>::VertexRange
356 DGtal::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 //-----------------------------------------------------------------------------
387 template <typename TPoint>
389 typename DGtal::TriangulatedSurface<TPoint>::FaceRange
390 DGtal::TriangulatedSurface<TPoint>::allFaces() const
392 FaceRange result( nbFaces() );
393 for ( Face fi = 0; fi < result.size(); ++fi )
397 //-----------------------------------------------------------------------------
398 template <typename TPoint>
400 typename DGtal::TriangulatedSurface<TPoint>::ArcRange
401 DGtal::TriangulatedSurface<TPoint>::allArcs() const
403 ArcRange result( nbArcs() );
404 for ( Arc fi = 0; fi < result.size(); ++fi )
408 //-----------------------------------------------------------------------------
409 template <typename TPoint>
411 typename DGtal::TriangulatedSurface<TPoint>::VertexRange
412 DGtal::TriangulatedSurface<TPoint>::allVertices() const
414 VertexRange result( nbVertices() );
415 for ( Vertex fi = 0; fi < result.size(); ++fi )
420 //-----------------------------------------------------------------------------
421 template <typename TPoint>
423 typename DGtal::TriangulatedSurface<TPoint>::ArcRange
424 DGtal::TriangulatedSurface<TPoint>::allBoundaryArcs() const
426 return myHEDS.boundaryHalfEdgeIndices();
429 //-----------------------------------------------------------------------------
430 template <typename TPoint>
432 typename DGtal::TriangulatedSurface<TPoint>::VertexRange
433 DGtal::TriangulatedSurface<TPoint>::allBoundaryVertices() const
435 return myHEDS.boundaryVertices();
438 //-----------------------------------------------------------------------------
439 template <typename TPoint>
442 DGtal::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 //-----------------------------------------------------------------------------
455 template <typename TPoint>
458 DGtal::TriangulatedSurface<TPoint>::flip( const Arc a )
460 myHEDS.flip( a, false );
464 //-----------------------------------------------------------------------------
465 template <typename TPoint>
467 typename DGtal::TriangulatedSurface<TPoint>::Vertex
468 DGtal::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 //-----------------------------------------------------------------------------
477 template <typename TPoint>
480 DGtal::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 //-----------------------------------------------------------------------------
501 template <typename TPoint>
503 typename DGtal::TriangulatedSurface<TPoint>::Vertex
504 DGtal::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.
522 template <typename TPoint>
525 DGtal::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.
536 template <typename TPoint>
539 DGtal::TriangulatedSurface<TPoint>::isValid() const
546 ///////////////////////////////////////////////////////////////////////////////
547 // Implementation of inline functions //
549 template <typename TPoint>
552 DGtal::operator<< ( std::ostream & out,
553 const TriangulatedSurface<TPoint> & object )
555 object.selfDisplay( out );
560 ///////////////////////////////////////////////////////////////////////////////