location: CGAL\boost\graph\Euler_operations.h
http://doc.cgal.org/latest/BGL/group__PkgBGLEulerOperations.html#ga585a3324ef493cc1340da5cb364b772c
/** * joins the two vertices incident to `h`, (that is `source(h, g)` and * `target(h, g)`) and removes `source(h,g)`. Returns the predecessor * of `h` around the vertex, i.e., `prev(opposite(h,g))`. The * invariant `join_vertex(split_vertex(h,g),g)` returns `h`. The * time complexity is linear in the degree of the vertex removed. * * \image html join_vertex.svg * * \tparam Graph must be a model of `MutableFaceGraph` * * \param g the graph * \param h the halfedge which incident vertices are joint * * \returns `prev(opposite(h,g))` * * \pre The size of the faces incident to `h` and `opposite(h,g)` is at least 4. * * \post `source(h, g)` is invalidated * \post `h` is invalidated * * \sa `split_vertex()` */ template<typename Graph> typename boost::graph_traits<Graph>::halfedge_descriptor join_vertex(typename boost::graph_traits<Graph>::halfedge_descriptor h, Graph& g) { typedef typename boost::graph_traits<Graph> Traits; typedef typename Traits::halfedge_descriptor halfedge_descriptor; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef Halfedge_around_target_iterator<Graph> halfedge_around_vertex_iterator; halfedge_descriptor hop = opposite(h, g) , hprev = prev(hop, g) , gprev = prev(h, g) , hnext = next(hop, g) , gnext = next(h, g); vertex_descriptor v_to_remove = target(hop, g) , v = target(h, g); // this assertion fires needlessly // CGAL_precondition(std::distance( // halfedges_around_face(e, g).first, // halfedges_around_face(e, g).second) >= 4); CGAL_assertion( halfedge(v_to_remove, v, g).first == h ); halfedge_around_vertex_iterator ieb, iee; for(boost::tie(ieb, iee) = halfedges_around_target(hop, g); ieb != iee; ++ieb) { CGAL_assertion( target(*ieb,g) == v_to_remove); set_target(*ieb ,v , g); } set_next(hprev, hnext, g); set_next(gprev, gnext, g); set_halfedge(v, gprev, g); // internal::set_constant_vertex_is_border(g, v); remove_edge(edge(h, g), g); remove_vertex(v_to_remove, g); return hprev; }
halfedge_descriptor hop = opposite(h, g) , hprev = prev(hop, g) , gprev = prev(h, g) , hnext = next(hop, g) , gnext = next(h, g); vertex_descriptor v_to_remove = target(hop, g) , v = target(h, g);
halfedge_around_vertex_iterator ieb, iee; for(boost::tie(ieb, iee) = halfedges_around_target(hop, g); ieb != iee; ++ieb) { CGAL_assertion( target(*ieb,g) == v_to_remove); set_target(*ieb ,v , g); }
okay, let me tackle these problems one by one.
first, let us recall some basic knowledge about the data structure of halfedge graph.
Each edge is represented by two halfedges with opposite orientation. Each halfedge stores a reference to an incident face and to an incident vertex. Additionally, it stores a reference to the next and previous halfedge incident to its incident face. For each face and each vertex an incident halfedge is stored.
so each halfedge only cares about its target vertex. After setting the target of halfedges tp, Ap, Bp, bp, qp, we don't need to care about their opposite, because the target vertex of those edges stay the same. First problem solved.
the answer to the second problem is we don't need to do any fix work. Because the topology of triangles related with vertex p will stay the same after the halfedge pq collapsing. For instance, the previous and next halfedges of pt are Ap and tA, after halfedge pq collasped, the previous and next halfedges of qt are Aq and tA, The relative relationship between them aren't actually changed. So we just leave them as they are.
Go back to our analysis,
set_next(hprev, hnext, g); set_next(gprev, gnext, g);
the set_next actually does bilateral work
template<class Gt, class I, CGAL_HDS_PARAM_, class A> void set_next(typename boost::graph_traits< CGAL::Polyhedron_3<Gt,I,HDS,A> >::halfedge_descriptor h1 , typename boost::graph_traits< CGAL::Polyhedron_3<Gt,I,HDS,A> >::halfedge_descriptor h2 , CGAL::Polyhedron_3<Gt,I,HDS,A>&) { typedef typename CGAL::Polyhedron_3<Gt,I,HDS,A>::Halfedge::Base Sneak; static_cast<Sneak&>(*h1).set_next(h2); static_cast<Sneak&>(*h2).set_prev(h1); }
set_halfedge(v, gprev, g);
remove_edge(edge(h, g), g); remove_vertex(v_to_remove, g);