/* $Id$ * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). * * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef HALFEDGEDIAGRAM_HPP #define HALFEDGEDIAGRAM_HPP #include #include #include #include // bundled BGL properties, see: http://www.boost.org/doc/libs/1_44_0/libs/graph/doc/bundles.html // dcel notes from http://www.holmes3d.net/graphics/dcel/ // vertex (boost::out_edges) // -leaving pointer to HalfEdge that has this vertex as origin // if many HalfEdges have this vertex as origin, choose one arbitrarily // HalfEdge // - origin pointer to vertex (boost::source) // - face to the left of halfedge // - twin pointer to HalfEdge (on the right of this edge) // - next pointer to HalfEdge // this edge starts from h->twin->origin and ends at next vertex in h->face // traveling ccw around boundary // (allows face traverse, follow h->next until we arrive back at h) // Face // - edge pointer to HalfEdge // this edge has this Face object as face // half-edge can be any one on the boundary of face // special "infinite face", face on "outside" of boundary // may or may not store edge pointer /// HEDIGraph is a A half-edge diagram class. /// Templated on Vertex/Edge/Face property classes which allow /// attaching information to vertices/edges/faces that is /// required for a particular algorithm. /// /// Inherits from boost::adjacency_list /// minor additions allow storing face-properties. /// /// the hedi namespace contains functions for manipulating HEDIGraphs /// /// For a general description of the half-edge data structure see e.g.: /// - http://www.holmes3d.net/graphics/dcel/ /// - http://openmesh.org/index.php?id=228 namespace ocl { namespace hedi { template class HEDIGraph { public: typedef typename boost::adjacency_list< TOutEdgeList, TVertexList, TDirected, TVertexProperties, TEdgeProperties, TGraphProperties, TEdgeList > BGLGraph; typedef unsigned int Face; typedef typename boost::graph_traits< BGLGraph >::edge_descriptor Edge; typedef typename boost::graph_traits< BGLGraph >::vertex_descriptor Vertex; typedef typename boost::graph_traits< BGLGraph >::vertex_iterator VertexItr; typedef typename boost::graph_traits< BGLGraph >::edge_iterator EdgeItr; typedef typename boost::graph_traits< BGLGraph >::out_edge_iterator OutEdgeItr; typedef typename boost::graph_traits< BGLGraph >::adjacency_iterator AdjacencyItr; typedef std::vector VertexVector; typedef std::vector FaceVector; typedef std::vector EdgeVector; inline TFaceProperties& operator[](Face f) { return faces[f]; } inline const TFaceProperties& operator[](Face f) const { return faces[f]; } inline TEdgeProperties& operator[](Edge e) { return g[e]; } inline const TEdgeProperties& operator[](Edge e) const { return g[e]; } inline TVertexProperties& operator[](Vertex v) { return g[v]; } inline const TVertexProperties& operator[](Vertex v) const { return g[v]; } //DATA std::vector< TFaceProperties > faces; BGLGraph g; Vertex null_vertex() { return boost::graph_traits::null_vertex(); } /// add a blank vertex and return its descriptor Vertex add_vertex() { return boost::add_vertex( g ); } /* /// add a vertex with given properties, return vertex descriptor template < class FVertexProperty> typename boost::graph_traits< BGLGraph >::vertex_descriptor add_vertex(typedef const FVertexProperty& prop) { return boost::add_vertex( prop, g ); }*/ /// add an edge between vertices v1-v2 Edge add_edge(Vertex v1, Vertex v2) { Edge e; bool b; boost::tie( e , b ) = boost::add_edge( v1, v2, g); return e; } /// add an edge with given properties between vertices v1-v2 //template < class EdgeProperty> /* typename boost::graph_traits< BGLGraph >::edge_descriptor add_edge( typename boost::graph_traits< BGLGraph >::vertex_descriptor v1, typename boost::graph_traits< BGLGraph >::vertex_descriptor v2, typename TEdgeProperties prop ) { typename boost::graph_traits< BGLGraph >::edge_descriptor e; bool b; boost::tie( e , b ) = boost::add_edge( v1, v2, prop, g); return e; }*/ /// make e1 the twin of e2 (and vice versa) void twin_edges( Edge e1, Edge e2 ) { g[e1].twin = e2; g[e2].twin = e1; } /// add a face Face add_face() { TFaceProperties f_prop; faces.push_back( f_prop); Face index = faces.size()-1; faces[index].idx = index; return index; } /// return the target vertex of the given edge Vertex target( Edge e ) { return boost::target( e, g); } /// return the source vertex of the given edge Vertex source( Edge e ) { return boost::source( e, g); } /// return all vertices in a vector of vertex descriptors VertexVector vertices() { typedef typename boost::graph_traits< BGLGraph >::vertex_descriptor HEVertex; typedef std::vector VertexVector; typedef typename boost::graph_traits< BGLGraph >::vertex_iterator HEVertexItr; VertexVector vv; HEVertexItr it_begin, it_end, itr; boost::tie( it_begin, it_end ) = boost::vertices( g ); for ( itr=it_begin ; itr != it_end ; ++itr ) { vv.push_back( *itr ); } return vv; } /// return all vertices adjacent to given vertex VertexVector adjacent_vertices( Vertex v) { VertexVector vv; BOOST_FOREACH( Edge edge, out_edges( v ) ) { vv.push_back( target( edge ) ); } return vv; } /// return all vertices of given face VertexVector face_vertices(Face face_idx) { VertexVector verts; Edge startedge = faces[face_idx].edge; // the edge where we start Vertex start_target = boost::target( startedge, g); verts.push_back(start_target); Edge current = g[startedge].next; do { Vertex current_target = boost::target( current, g); verts.push_back(current_target); current = g[current].next; } while ( current != startedge ); return verts; } /// return edges of face f EdgeVector face_edges( Face f ) { //Edge start_edge = g[ f ].edge; // was cast: (Face)f Edge start_edge = faces[f].edge; Edge current_edge = start_edge; EdgeVector out; do { out.push_back(current_edge); current_edge = g[current_edge].next; } while( current_edge != start_edge ); return out; } /// return degree of given vertex unsigned int degree( Vertex v) { return boost::degree( v, g); } /// return number of vertices in graph unsigned int num_vertices() const { return static_cast(boost::num_vertices( g )); } /// return out_edges of given vertex EdgeVector out_edges( Vertex v) { typedef typename boost::graph_traits< BGLGraph >::out_edge_iterator HEOutEdgeItr; EdgeVector ev; HEOutEdgeItr it, it_end; boost::tie( it, it_end ) = boost::out_edges( v, g ); for ( ; it != it_end ; ++it ) { ev.push_back(*it); } return ev; } /// return all edges EdgeVector edges() { typedef typename boost::graph_traits< BGLGraph >::edge_iterator HEEdgeItr; EdgeVector ev; HEEdgeItr it, it_end; boost::tie( it, it_end ) = boost::edges( g ); for ( ; it != it_end ; ++it ) { ev.push_back(*it); } return ev; } /// return v1-v2 edge descriptor Edge edge( Vertex v1, Vertex v2 ) { typedef typename std::pair EdgeBool; EdgeBool result = boost::edge(v1, v2, g ); return result.first; } /// return the previous edge. traverses all edges in face until previous found. Edge previous_edge( Edge e ) { Edge previous = g[e].next; while ( g[previous].next != e ) { previous = g[previous].next; } return previous; } /// return true if v1-v2 edge exists bool has_edge( Vertex v1, Vertex v2) { typedef typename std::pair EdgeBool; EdgeBool result = boost::edge(v1, v2, g ); return result.second; } /// return adjacent faces to the given vertex FaceVector adjacent_faces( Vertex q ) { typedef typename boost::graph_traits< BGLGraph >::out_edge_iterator HEOutEdgeItr; std::set face_set; HEOutEdgeItr itr, itr_end; boost::tie( itr, itr_end) = boost::out_edges(q, g); for ( ; itr!=itr_end ; ++itr ) { face_set.insert( g[*itr].face ); } FaceVector fv; BOOST_FOREACH(unsigned int m, face_set) { fv.push_back(m); } return fv; } /// return number of faces in graph unsigned int num_faces() const { return faces.size(); } /// return number of edges in graph unsigned int num_edges() const { return static_cast(boost::num_edges( g )); } /// inserts given vertex into edge e, and into the twin edge e_twin void insert_vertex_in_edge(Vertex v, Edge e ) { // the vertex v is in the middle of edge e // face // e1 e2 // previous-> source -> v -> target -> next // tw_trg <- v <- tw_src <- tw_previous // te2 te1 // twin_face Edge twin = g[e].twin; Vertex source = boost::source( e , g ); Vertex target = boost::target( e , g); Vertex twin_source = boost::source( twin , g); Vertex twin_target = boost::target( twin , g ); assert( source == twin_target ); assert( target == twin_source ); Face face = g[e].face; Face twin_face = g[twin].face; Edge previous = previous_edge(e); assert( g[previous].face == g[e].face ); Edge twin_previous = previous_edge(twin); assert( g[twin_previous].face == g[twin].face ); Edge e1 = add_edge( source, v ); Edge e2 = add_edge( v, target ); // preserve the left/right face link g[e1].face = face; g[e2].face = face; // next-pointers g[previous].next = e1; g[e1].next = e2; g[e2].next = g[e].next; Edge te1 = add_edge( twin_source, v ); Edge te2 = add_edge( v, twin_target ); g[te1].face = twin_face; g[te2].face = twin_face; g[twin_previous].next = te1; g[te1].next = te2; g[te2].next = g[twin].next; // TWINNING (note indices 'cross', see ASCII art above) g[e1].twin = te2; g[te2].twin = e1; g[e2].twin = te1; g[te1].twin = e2; // update the faces (required here?) faces[face].edge = e1; faces[twin_face].edge = te1; // finally, remove the old edge boost::remove_edge( e , g); boost::remove_edge( twin, g); } /// inserts given vertex into edge e /* template void insert_vertex_in_half_edge(typename boost::graph_traits< BGLGraph >::vertex_descriptor v, typename boost::graph_traits< BGLGraph >::edge_descriptor e, BGLGraph& g) { typedef typename boost::graph_traits< BGLGraph >::edge_descriptor HEEdge; typedef typename boost::graph_traits< BGLGraph >::vertex_descriptor HEVertex; // the vertex v is in the middle of edge e // face // e1 e2 // previous-> source -> v -> target -> next HEVertex source = boost::source( e , g ); HEVertex target = boost::target( e , g); unsigned int face = g[e].face; HEEdge previous = previous_edge(e, g); assert( g[previous].face == g[e].face ); HEEdge e1 = add_edge( source, v , g); HEEdge e2 = add_edge( v, target , g); // preserve the left/right face link g[e1].face = face; g[e2].face = face; // next-pointers g[previous].next = e1; g[e1].next = e2; g[e2].next = g[e].next; // update the faces (required here?) g.faces[face].edge = e1; // finally, remove the old edge boost::remove_edge( e , g); // NOTE: twinning is not done here, since the twin edge is not split... } */ /// check that all edges belong to the correct face, TODO: template this to make it a useful check /* bool checkFaces() { BOOST_FOREACH(FaceProps f, faces) { BOOST_FOREACH( HEEdge e, face_edges(f.idx)) { if ( g[e].face != f.idx ) return false; } } return true; }*/ /// delete a vertex void delete_vertex(Vertex v) { clear_vertex(v); remove_vertex(v); } /// clear given vertex. this removes all edges connecting to the vertex. void clear_vertex( Vertex v) { boost::clear_vertex( v, g ); } /// remove given vertex void remove_vertex( Vertex v) { boost::remove_vertex( v , g ); } void remove_edge( Vertex v1, Vertex v2) { boost::remove_edge( v1, v2 , g); } void remove_edge( Edge e) { boost::remove_edge( e , g); } }; // end class definition } // end hedi namespace } // end ocl namespace #endif // end halfedgediagram.hpp