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 IndexedDigitalSurface.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 IndexedDigitalSurface.h
26 * This file is part of the DGtal library.
30 //////////////////////////////////////////////////////////////////////////////
33 #include "DGtal/topology/DigitalSurface.h"
34 #include "DGtal/topology/CanonicSCellEmbedder.h"
35 //////////////////////////////////////////////////////////////////////////////
37 ///////////////////////////////////////////////////////////////////////////////
38 // IMPLEMENTATION of inline methods.
39 ///////////////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////////////
42 // ----------------------- Standard services ------------------------------
44 //-----------------------------------------------------------------------------
45 template <typename TDigitalSurfaceContainer>
48 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::build
49 ( ConstAlias< DigitalSurfaceContainer > surfContainer )
52 trace.warning() << "[DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::build()]"
53 << " attempting to rebuild a polygonal surface." << std::endl;
56 myContainer = CountedConstPtrOrConstPtr< DigitalSurfaceContainer >( surfContainer );
57 DigitalSurface< DigitalSurfaceContainer > surface( *myContainer );
58 CanonicSCellEmbedder< KSpace > embedder( myContainer->space() );
59 // Numbering surfels / vertices
61 for ( SCell aSurfel : surface )
63 myPositions.push_back( embedder( aSurfel ) );
64 mySurfel2VertexIndex[ aSurfel ] = i++;
66 // Numbering pointels / faces
68 auto faces = surface.allClosedFaces();
69 for ( auto aFace : faces )
71 auto vtcs = surface.verticesAroundFace( aFace );
72 PolygonalFace idx_face( vtcs.size() );
73 std::transform( vtcs.cbegin(), vtcs.cend(), idx_face.begin(),
75 ( const SCell& v ) { return mySurfel2VertexIndex[ v ]; } );
76 myPolygonalFaces.push_back( idx_face );
77 myPointel2FaceIndex[ surface.pivot( aFace ) ] = j++;
79 isHEDSValid = myHEDS.build( myPolygonalFaces );
80 if ( myHEDS.nbVertices() != myPositions.size() ) {
81 trace.warning() << "[DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::build()]"
82 << " the size of vertex data array (s1) and the number of vertices (s2) in the polygonal surface does not match:"
83 << " s1=" << myPositions.size()
84 << " s2=" << myHEDS.nbVertices() << std::endl;
88 { // We build the mapping for vertices and faces
89 myVertexIndex2Surfel.resize( nbVertices() );
90 myFaceIndex2Pointel .resize( nbFaces() );
91 myArc2Linel .resize( nbArcs() );
92 for ( auto p : mySurfel2VertexIndex )
93 myVertexIndex2Surfel[ p.second ] = p.first;
94 for ( auto p : myPointel2FaceIndex )
95 myFaceIndex2Pointel [ p.second ] = p.first;
96 // We build the mapping for arcs
98 for ( Arc fi = 0; fi < myArc2Linel.size(); ++fi )
100 auto vi_vj = myHEDS.arcFromHalfEdgeIndex( fi );
101 SCell surfi = myVertexIndex2Surfel[ vi_vj.first ];
102 SCell surfj = myVertexIndex2Surfel[ vi_vj.second ];
103 SCell lnl = surface.separator( surface.arc( surfi, surfj ) );
104 myLinel2Arc[ lnl ] = fi;
105 myArc2Linel[ fi ] = lnl;
106 // trace.info() << "- Arc " << fi
107 // << " (" << vi_vj.first << "," << vi_vj.second << ") "
108 // << " (" << surfi << "," << surfj << ") "
109 // << " lnl=" << lnl << space().sDim( lnl ) << std::endl;
115 //-----------------------------------------------------------------------------
116 template <typename TDigitalSurfaceContainer>
119 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::clear()
125 myPolygonalFaces.clear();
126 mySurfel2VertexIndex.clear();
128 myPointel2FaceIndex.clear();
129 myVertexIndex2Surfel.clear();
131 myFaceIndex2Pointel.clear();
134 //-----------------------------------------------------------------------------
135 template <typename TDigitalSurfaceContainer>
137 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::RealPoint&
138 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::position( Vertex v )
140 ASSERT( 0 <= v && v < myPositions.size() );
141 return myPositions[ v ];
143 //-----------------------------------------------------------------------------
144 template <typename TDigitalSurfaceContainer>
146 const typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::RealPoint&
147 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::position( Vertex v ) const
149 ASSERT( 0 <= v && v < myPositions.size() );
150 return myPositions[ v ];
152 //-----------------------------------------------------------------------------
153 template <typename TDigitalSurfaceContainer>
155 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Size
156 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::size() const
158 return myPositions.size();
160 //-----------------------------------------------------------------------------
161 template <typename TDigitalSurfaceContainer>
163 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Size
164 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::bestCapacity() const
168 //-----------------------------------------------------------------------------
169 template <typename TDigitalSurfaceContainer>
171 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Size
172 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::degree( const Vertex & v ) const
175 return myHEDS.nbNeighboringVertices( v );
178 //-----------------------------------------------------------------------------
179 template <typename TDigitalSurfaceContainer>
180 template <typename OutputIterator>
183 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::writeNeighbors
184 ( OutputIterator &it, const Vertex & v ) const
187 typedef HalfEdgeDataStructure::VertexIndexRange VertexIndexRange;
188 VertexIndexRange neighbors;
189 myHEDS.getNeighboringVertices( v, neighbors );
190 for ( Vertex nv : neighbors ) *it++ = nv;
193 //-----------------------------------------------------------------------------
194 template <typename TDigitalSurfaceContainer>
195 template <typename OutputIterator, typename VertexPredicate>
198 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::writeNeighbors
199 ( OutputIterator &it, const Vertex & v, const VertexPredicate & pred) const
202 typedef HalfEdgeDataStructure::VertexIndexRange VertexIndexRange;
203 VertexIndexRange neighbors;
204 myHEDS.getNeighboringVertices( v, neighbors );
205 for ( Vertex nv : neighbors ) if ( pred( nv ) ) *it++ = nv;
208 //-----------------------------------------------------------------------------
209 template <typename TDigitalSurfaceContainer>
211 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::ArcRange
212 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::outArcs( const Vertex & v ) const
215 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
216 Index hei = start_hei;
219 const HalfEdge& he = myHEDS.halfEdge( hei );
220 if( INVALID_FACE != he.face ) result.push_back( hei );
221 hei = myHEDS.halfEdge( he.opposite ).next;
223 while ( hei != start_hei );
227 //-----------------------------------------------------------------------------
228 template <typename TDigitalSurfaceContainer>
230 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::ArcRange
231 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::inArcs( const Vertex & v ) const
234 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
235 Index hei = start_hei;
238 const HalfEdge& he = myHEDS.halfEdge( hei );
239 if( INVALID_FACE != he.face ) result.push_back( he.opposite );
240 hei = myHEDS.halfEdge( he.opposite ).next;
242 while ( hei != start_hei );
246 //-----------------------------------------------------------------------------
247 template <typename TDigitalSurfaceContainer>
249 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::FaceRange
250 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::facesAroundVertex( const Vertex & v ) const
253 const Index start_hei = myHEDS.halfEdgeIndexFromVertexIndex( v );
254 Index hei = start_hei;
257 const HalfEdge& he = myHEDS.halfEdge( hei );
258 if( INVALID_FACE != he.face ) result.push_back( he.face );
259 hei = myHEDS.halfEdge( he.opposite ).next;
261 while ( hei != start_hei );
265 //-----------------------------------------------------------------------------
266 template <typename TDigitalSurfaceContainer>
268 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Vertex
269 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::head( const Arc & a ) const
271 return myHEDS.halfEdge( a ).toVertex;
274 //-----------------------------------------------------------------------------
275 template <typename TDigitalSurfaceContainer>
277 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Vertex
278 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::tail( const Arc & a ) const
280 return head( opposite( a ) );
283 //-----------------------------------------------------------------------------
284 template <typename TDigitalSurfaceContainer>
286 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Arc
287 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::opposite( const Arc & a ) const
289 return myHEDS.halfEdge( a ).opposite;
292 //-----------------------------------------------------------------------------
293 template <typename TDigitalSurfaceContainer>
295 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Arc
296 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::next( const Arc & a ) const
298 return myHEDS.halfEdge( a ).next;
300 //-----------------------------------------------------------------------------
301 template <typename TDigitalSurfaceContainer>
303 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Arc
304 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::arc
305 ( const Vertex & t, const Vertex & h ) const
307 return myHEDS.halfEdgeIndexFromArc( t, h );
310 //-----------------------------------------------------------------------------
311 template <typename TDigitalSurfaceContainer>
313 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::Face
314 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::faceAroundArc( const Arc & a ) const
316 return myHEDS.halfEdge( a ).face;
318 //-----------------------------------------------------------------------------
319 template <typename TDigitalSurfaceContainer>
321 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::FaceRange
322 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::facesAroundArc( const Arc & a ) const
325 Face f = faceAroundArc( a );
326 if ( f != INVALID_FACE ) result.push_back( f );
330 //-----------------------------------------------------------------------------
331 template <typename TDigitalSurfaceContainer>
333 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::VertexRange
334 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::verticesAroundFace( const Face & f ) const
337 const Index start_hei = myHEDS.halfEdgeIndexFromFaceIndex( f );
338 Index hei = start_hei;
340 const HalfEdge& he = myHEDS.halfEdge( hei );
341 ASSERT( ( he.face == f )
342 && "[IndexedDigitalSurface::verticesAroundFace] invalid face." );
343 result.push_back( he.toVertex );
345 } while ( hei != start_hei );
346 ASSERT( result.size() >= 3 );
350 //-----------------------------------------------------------------------------
351 template <typename TDigitalSurfaceContainer>
354 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::isVertexBoundary( const Vertex& v ) const
356 return myHEDS.isVertexBoundary( v );
359 //-----------------------------------------------------------------------------
360 template <typename TDigitalSurfaceContainer>
363 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::isArcBoundary( const Arc& v ) const
365 return INVALID_FACE == myHEDS.halfEdge( v ).face;
368 //-----------------------------------------------------------------------------
369 template <typename TDigitalSurfaceContainer>
371 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::FaceRange
372 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::allFaces() const
374 FaceRange result( nbFaces() );
375 for ( Face fi = 0; fi < result.size(); ++fi )
379 //-----------------------------------------------------------------------------
380 template <typename TDigitalSurfaceContainer>
382 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::ArcRange
383 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::allArcs() const
385 ArcRange result( nbArcs() );
386 for ( Arc fi = 0; fi < result.size(); ++fi )
390 //-----------------------------------------------------------------------------
391 template <typename TDigitalSurfaceContainer>
393 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::VertexRange
394 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::allVertices() const
396 VertexRange result( nbVertices() );
397 for ( Vertex fi = 0; fi < result.size(); ++fi )
402 //-----------------------------------------------------------------------------
403 template <typename TDigitalSurfaceContainer>
405 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::ArcRange
406 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::allBoundaryArcs() const
408 return myHEDS.boundaryHalfEdgeIndices();
411 //-----------------------------------------------------------------------------
412 template <typename TDigitalSurfaceContainer>
414 typename DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::VertexRange
415 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::allBoundaryVertices() const
417 return myHEDS.boundaryVertices();
421 ///////////////////////////////////////////////////////////////////////////////
422 // Interface - public :
425 * Writes/Displays the object on an output stream.
426 * @param out the output stream where the object is written.
428 template <typename TDigitalSurfaceContainer>
431 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::selfDisplay ( std::ostream & out ) const
433 out << "[IndexedDigitalSurface #V=" << myHEDS.nbVertices()
434 << " #E=" << myHEDS.nbEdges() << " #F=" << myHEDS.nbFaces()
435 << " Chi=" << Euler() << "]";
439 * Checks the validity/consistency of the object.
440 * @return 'true' if the object is valid, 'false' otherwise.
442 template <typename TDigitalSurfaceContainer>
445 DGtal::IndexedDigitalSurface<TDigitalSurfaceContainer>::isValid() const
452 ///////////////////////////////////////////////////////////////////////////////
453 // Implementation of inline functions //
455 template <typename TDigitalSurfaceContainer>
458 DGtal::operator<< ( std::ostream & out,
459 const IndexedDigitalSurface<TDigitalSurfaceContainer> & object )
461 object.selfDisplay( out );
466 ///////////////////////////////////////////////////////////////////////////////