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 HalfEdgeDataStructure.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 HalfEdgeDataStructure.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32//////////////////////////////////////////////////////////////////////////////
34///////////////////////////////////////////////////////////////////////////////
35// IMPLEMENTATION of inline methods.
36///////////////////////////////////////////////////////////////////////////////
38///////////////////////////////////////////////////////////////////////////////
39// ----------------------- Standard services ------------------------------
41//-----------------------------------------------------------------------------
43DGtal::HalfEdgeDataStructure::Size
44DGtal::HalfEdgeDataStructure::getUnorderedEdgesFromPolygonalFaces
45( const std::vector<PolygonalFace>& polygonal_faces, std::vector< Edge >& edges_out )
47 typedef std::set< Edge > EdgeSet;
48 typedef std::set< VertexIndex > VertexIndexSet;
49 VertexIndexSet vertexSet;
51 for( const PolygonalFace& P : polygonal_faces )
53 ASSERT( P.size() >= 3 ); // a face has at least 3 vertices
54 for ( unsigned int i = 0; i < P.size(); ++i )
56 edgeSet.insert( Edge( P[ i ], P[ (i+1) % P.size() ] ) );
57 vertexSet.insert( P[ i ] );
60 edges_out.resize( edgeSet.size() );
62 for ( const Edge& edge : edgeSet )
64 edges_out.at(e) = edge;
67 return vertexSet.size();
70//-----------------------------------------------------------------------------
73DGtal::HalfEdgeDataStructure::
74build( const Size num_vertices,
75 const std::vector<Triangle>& triangles,
76 const std::vector<Edge>& edges )
80 // Visiting triangles to associates faces to arcs.
82 for( const Triangle& T : triangles )
84 auto it01 = de2fi.find( Arc( T.v[0], T.v[1] ) );
85 auto it12 = de2fi.find( Arc( T.v[1], T.v[2] ) );
86 auto it20 = de2fi.find( Arc( T.v[2], T.v[0] ) );
87 if ( ( it01 != de2fi.end() ) || ( it12 != de2fi.end() ) || ( it20 != de2fi.end() ) )
89 trace.warning() << "[HalfEdgeDataStructure::build] Some arcs belongs to more than one face. Dropping triangle."
90 << " Triangle (" << T.v[ 0 ] << "," << T.v[ 1 ] << "," << T.v[ 2 ] << ")"
91 << " arc01 " << ( it01 != de2fi.end() ? it01->second : HALF_EDGE_INVALID_INDEX )
92 << " arc12 " << ( it12 != de2fi.end() ? it12->second : HALF_EDGE_INVALID_INDEX )
93 << " arc20 " << ( it20 != de2fi.end() ? it20->second : HALF_EDGE_INVALID_INDEX )
96 // JOL: if we continue here, we may create infinite loops
97 // afterwards. Stopping now.
100 de2fi[ Arc( T.v[0], T.v[1] ) ] = fi;
101 de2fi[ Arc( T.v[1], T.v[2] ) ] = fi;
102 de2fi[ Arc( T.v[2], T.v[0] ) ] = fi;
105 // JOL: if we continue here, we may create infinite loops
106 // afterwards. Stopping now.
107 if ( !ok ) return false;
108 // Clearing and resizing data structure to start from scratch and
109 // prepare everything.
111 Size num_edges = edges.size();
112 Size num_triangles = triangles.size();
113 myVertexHalfEdges.resize( num_vertices, HALF_EDGE_INVALID_INDEX );
114 myFaceHalfEdges.resize( num_triangles, HALF_EDGE_INVALID_INDEX );
115 myEdgeHalfEdges.resize( num_edges, HALF_EDGE_INVALID_INDEX );
116 myHalfEdges.reserve( num_edges*2 );
117 // Visiting edges to connect everything.
118 for( EdgeIndex ei = 0; ei < num_edges; ++ei )
120 const Edge& edge = edges[ ei ];
122 // Add the halfedge_t structures to the end of the list.
123 const Index he0index = myHalfEdges.size();
124 myHalfEdges.push_back( HalfEdge() );
125 const Index he1index = myHalfEdges.size();
126 myHalfEdges.push_back( HalfEdge() );
127 HalfEdge& he0 = myHalfEdges[ he0index ];
128 HalfEdge& he1 = myHalfEdges[ he1index ];
130 // The face will be HALF_EDGE_INVALID_INDEX if it is a boundary half-edge.
131 he0.face = arc2FaceIndex( de2fi, edge.v[0], edge.v[1] );
132 he0.toVertex = edge.v[1];
135 // The face will be HALF_EDGE_INVALID_INDEX if it is a boundary half-edge.
136 he1.face = arc2FaceIndex( de2fi, edge.v[1], edge.v[0] );
137 he1.toVertex = edge.v[0];
140 // Store the opposite half-edge index.
141 he0.opposite = he1index;
142 he1.opposite = he0index;
144 // Also store the index in our myArc2Index map.
145 assert( myArc2Index.find( Arc( edge.v[0], edge.v[1] ) ) == myArc2Index.end() );
146 assert( myArc2Index.find( Arc( edge.v[1], edge.v[0] ) ) == myArc2Index.end() );
147 myArc2Index[ std::make_pair( edge.v[0], edge.v[1] ) ] = he0index;
148 myArc2Index[ std::make_pair( edge.v[1], edge.v[0] ) ] = he1index;
150 // If the vertex pointed to by a half-edge doesn't yet have an out-going
151 // halfedge, store the opposite halfedge.
152 // Also, if the vertex is a boundary vertex, make sure its
153 // out-going halfedge is a boundary halfedge.
154 // NOTE: Halfedge data structure can't properly handle butterfly vertices.
155 // If the mesh has butterfly vertices, there will be multiple outgoing
156 // boundary halfedges. Because we have to pick one as the vertex's outgoing
157 // halfedge, we can't iterate over all neighbors, only a single wing of the
159 if( myVertexHalfEdges[ he0.toVertex ] == HALF_EDGE_INVALID_INDEX || HALF_EDGE_INVALID_INDEX == he1.face )
160 myVertexHalfEdges[ he0.toVertex ] = he0.opposite;
161 if( myVertexHalfEdges[ he1.toVertex ] == HALF_EDGE_INVALID_INDEX || HALF_EDGE_INVALID_INDEX == he0.face )
162 myVertexHalfEdges[ he1.toVertex ] = he1.opposite;
164 // If the face pointed to by a half-edge doesn't yet have a
165 // halfedge pointing to it, store the halfedge.
166 if( HALF_EDGE_INVALID_INDEX != he0.face && myFaceHalfEdges[ he0.face ] == HALF_EDGE_INVALID_INDEX )
167 myFaceHalfEdges[ he0.face ] = he0index;
168 if( HALF_EDGE_INVALID_INDEX != he1.face && myFaceHalfEdges[ he1.face ] == HALF_EDGE_INVALID_INDEX )
169 myFaceHalfEdges[ he1.face ] = he1index;
171 // Store one of the half-edges for the edge.
172 assert( myEdgeHalfEdges[ ei ] == HALF_EDGE_INVALID_INDEX );
173 myEdgeHalfEdges[ ei ] = he0index;
176 // Now that all the half-edges are created, set the remaining next_he field.
177 // We can't yet handle boundary halfedges, so store them for later.
178 HalfEdgeIndexRange boundary_heis;
179 for( Index hei = 0; hei < myHalfEdges.size(); ++hei )
181 HalfEdge& he = myHalfEdges.at( hei );
182 // Store boundary halfedges for later.
183 if( HALF_EDGE_INVALID_INDEX == he.face )
185 boundary_heis.push_back( hei );
189 const Triangle& face = triangles[ he.face ];
190 const VertexIndex i = he.toVertex;
191 VertexIndex j = HALF_EDGE_INVALID_INDEX;
192 if( face.v[0] == i ) j = face.v[1];
193 else if( face.v[1] == i ) j = face.v[2];
194 else if( face.v[2] == i ) j = face.v[0];
195 ASSERT( HALF_EDGE_INVALID_INDEX != j );
196 he.next = myArc2Index[ Arc( i, j ) ];
199 // Make a map from vertices to boundary halfedges (indices)
200 // originating from them. NOTE: There will only be multiple
201 // originating boundary halfedges at butterfly vertices.
202 std::map< VertexIndex, std::set< Index > > vertex2outgoing_boundary_hei;
203 for ( Index hei : boundary_heis )
205 const VertexIndex origin_v = myHalfEdges[ myHalfEdges[ hei ].opposite ].toVertex;
206 vertex2outgoing_boundary_hei[ origin_v ].insert( hei );
207 if( vertex2outgoing_boundary_hei[ origin_v ].size() > 1 )
209 trace.error() << "Butterfly vertex encountered." << std::endl;
214 // For each boundary halfedge, make its next_he one of the boundary halfedges
215 // originating at its to_vertex.
216 for ( Index hei : boundary_heis )
218 HalfEdge& he = myHalfEdges[ hei ];
220 std::set< Index >& outgoing = vertex2outgoing_boundary_hei[ he.toVertex ];
221 if( !outgoing.empty() )
223 std::set< Index >::iterator outgoing_hei = outgoing.begin();
224 he.next = *outgoing_hei;
225 outgoing.erase( outgoing_hei );
230 for( auto it = vertex2outgoing_boundary_hei.begin();
231 it != vertex2outgoing_boundary_hei.end(); ++it )
233 ASSERT( it->second.empty() );
240//-----------------------------------------------------------------------------
243DGtal::HalfEdgeDataStructure::
244build( const Size num_vertices,
245 const std::vector<PolygonalFace>& polygonal_faces,
246 const std::vector<Edge>& edges )
251 // Visiting triangles to associates faces to arcs.
253 for( const PolygonalFace& P : polygonal_faces )
255 ASSERT( P.size() >= 3 ); // a face has at least 3 vertices
257 for ( unsigned int i = 0; i < P.size(); ++i )
259 const VertexIndex v0 = P[ i ];
260 const VertexIndex v1 = P[ (i+1) % P.size() ];
261 auto it01 = de2fi.find( Arc( v0, v1 ) );
262 if ( it01 != de2fi.end() )
264 trace.warning() << "[HalfEdgeDataStructure::build] Arc (" << v0 << "," << v1 << ")"
265 << " of polygonal face " << fi << " belongs to more than one face. "
266 << " Dropping face " << fi << std::endl;
272 for ( unsigned int i = 0; i < P.size(); ++i )
274 const VertexIndex v0 = P[ i ];
275 const VertexIndex v1 = P[ (i+1) % P.size() ];
276 de2fi[ Arc( v0, v1 ) ] = fi;
278 // JOL: if we continue here, we may create infinite loops
279 // afterwards. Stopping now.
283 // Clearing and resizing data structure to start from scratch and
284 // prepare everything.
286 Size num_edges = edges.size();
287 Size num_polygons = polygonal_faces.size();
288 myVertexHalfEdges.resize( num_vertices, HALF_EDGE_INVALID_INDEX );
289 myFaceHalfEdges.resize( num_polygons, HALF_EDGE_INVALID_INDEX );
290 myEdgeHalfEdges.resize( num_edges, HALF_EDGE_INVALID_INDEX );
291 myHalfEdges.reserve( num_edges*2 );
292 // Visiting edges to connect everything.
293 for( EdgeIndex ei = 0; ei < num_edges; ++ei )
295 const Edge& edge = edges[ ei ];
297 // Add the halfedge_t structures to the end of the list.
298 const Index he0index = myHalfEdges.size();
299 myHalfEdges.push_back( HalfEdge() );
300 const Index he1index = myHalfEdges.size();
301 myHalfEdges.push_back( HalfEdge() );
302 HalfEdge& he0 = myHalfEdges[ he0index ];
303 HalfEdge& he1 = myHalfEdges[ he1index ];
305 // The face will be HALF_EDGE_INVALID_INDEX if it is a boundary half-edge.
306 he0.face = arc2FaceIndex( de2fi, edge.v[0], edge.v[1] );
307 he0.toVertex = edge.v[1];
310 // The face will be HALF_EDGE_INVALID_INDEX if it is a boundary half-edge.
311 he1.face = arc2FaceIndex( de2fi, edge.v[1], edge.v[0] );
312 he1.toVertex = edge.v[0];
315 // Store the opposite half-edge index.
316 he0.opposite = he1index;
317 he1.opposite = he0index;
319 // Also store the index in our myArc2Index map.
320 assert( myArc2Index.find( Arc( edge.v[0], edge.v[1] ) ) == myArc2Index.end() );
321 assert( myArc2Index.find( Arc( edge.v[1], edge.v[0] ) ) == myArc2Index.end() );
322 myArc2Index[ std::make_pair( edge.v[0], edge.v[1] ) ] = he0index;
323 myArc2Index[ std::make_pair( edge.v[1], edge.v[0] ) ] = he1index;
325 // If the vertex pointed to by a half-edge doesn't yet have an out-going
326 // halfedge, store the opposite halfedge.
327 // Also, if the vertex is a boundary vertex, make sure its
328 // out-going halfedge is a boundary halfedge.
329 // NOTE: Halfedge data structure can't properly handle butterfly vertices.
330 // If the mesh has butterfly vertices, there will be multiple outgoing
331 // boundary halfedges. Because we have to pick one as the vertex's outgoing
332 // halfedge, we can't iterate over all neighbors, only a single wing of the
334 if( myVertexHalfEdges[ he0.toVertex ] == HALF_EDGE_INVALID_INDEX
335 || HALF_EDGE_INVALID_INDEX == he1.face )
336 myVertexHalfEdges[ he0.toVertex ] = he0.opposite;
337 if( myVertexHalfEdges[ he1.toVertex ] == HALF_EDGE_INVALID_INDEX
338 || HALF_EDGE_INVALID_INDEX == he0.face )
339 myVertexHalfEdges[ he1.toVertex ] = he1.opposite;
341 // If the face pointed to by a half-edge doesn't yet have a
342 // halfedge pointing to it, store the halfedge.
343 if( HALF_EDGE_INVALID_INDEX != he0.face
344 && myFaceHalfEdges[ he0.face ] == HALF_EDGE_INVALID_INDEX )
345 myFaceHalfEdges[ he0.face ] = he0index;
346 if( HALF_EDGE_INVALID_INDEX != he1.face
347 && myFaceHalfEdges[ he1.face ] == HALF_EDGE_INVALID_INDEX )
348 myFaceHalfEdges[ he1.face ] = he1index;
350 // Store one of the half-edges for the edge.
351 assert( myEdgeHalfEdges[ ei ] == HALF_EDGE_INVALID_INDEX );
352 myEdgeHalfEdges[ ei ] = he0index;
355 // Now that all the half-edges are created, set the remaining next_he field.
356 // We can't yet handle boundary halfedges, so store them for later.
357 HalfEdgeIndexRange boundary_heis;
358 for( Index hei = 0; hei < myHalfEdges.size(); ++hei )
360 HalfEdge& he = myHalfEdges.at( hei );
361 // Store boundary halfedges for later.
362 if( HALF_EDGE_INVALID_INDEX == he.face )
364 boundary_heis.push_back( hei );
368 const PolygonalFace& face = polygonal_faces[ he.face ];
369 const VertexIndex i = he.toVertex;
370 auto it = std::find( face.cbegin(), face.cend(), i );
371 if ( it == face.cend() )
373 trace.error() << "[HalfEdgeDataStructure::build]"
374 << " Unable to find vertex " << i << " in face "
375 << he.face << std::endl;
382 it = ( it == face.cend() ) ? face.cbegin() : it;
383 const VertexIndex j = *it ;
384 he.next = myArc2Index[ Arc( i, j ) ];
388 // Make a map from vertices to boundary halfedges (indices)
389 // originating from them. NOTE: There will only be multiple
390 // originating boundary halfedges at butterfly vertices.
391 std::map< VertexIndex, std::set< Index > > vertex2outgoing_boundary_hei;
392 for ( Index hei : boundary_heis )
394 const VertexIndex origin_v = myHalfEdges[ myHalfEdges[ hei ].opposite ].toVertex;
395 vertex2outgoing_boundary_hei[ origin_v ].insert( hei );
396 if( vertex2outgoing_boundary_hei[ origin_v ].size() > 1 )
398 trace.error() << "[HalfEdgeDataStructure::build]"
399 << " Butterfly vertex encountered at he index=" << hei
405 // For each boundary halfedge, make its next_he one of the boundary halfedges
406 // originating at its to_vertex.
407 for ( Index hei : boundary_heis )
409 HalfEdge& he = myHalfEdges[ hei ];
411 std::set< Index >& outgoing = vertex2outgoing_boundary_hei[ he.toVertex ];
412 if( !outgoing.empty() )
414 std::set< Index >::iterator outgoing_hei = outgoing.begin();
415 he.next = *outgoing_hei;
416 outgoing.erase( outgoing_hei );
421 for( auto it = vertex2outgoing_boundary_hei.begin();
422 it != vertex2outgoing_boundary_hei.end(); ++it )
424 ASSERT( it->second.empty() );
430//-----------------------------------------------------------------------------
433///////////////////////////////////////////////////////////////////////////////
434// Interface - public :
437 * Writes/Displays the object on an output stream.
438 * @param out the output stream where the object is written.
442DGtal::HalfEdgeDataStructure::selfDisplay ( std::ostream & out ) const
444 out << "[HalfEdgeDataStructure"
445 << " #he=" << myHalfEdges.size()
446 << " #V=" << myVertexHalfEdges.size()
447 << " #E=" << myEdgeHalfEdges.size()
448 << " #F=" << myFaceHalfEdges.size()
454///////////////////////////////////////////////////////////////////////////////
455// Implementation of inline functions //
459DGtal::operator<< ( std::ostream & out,
460 const HalfEdgeDataStructure & object )
462 object.selfDisplay( out );
467///////////////////////////////////////////////////////////////////////////////