CGAL join_vertex source code analysis

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;
}




let's explain the codes line by line:

  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);

these lines do some preparing work as our picture depicts.


  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);
  }

these sentences set the target of the half-edges I mark red to v. At this part, I had been confused for a while. I mean here we just set the target of halfedges tp, Ap, Bp, bp, qp, but what about their opposite, i.e. pt, pA, pB, pb, pq. Another problem is why there don't change the data structure after halfedge pq collapsing, for example, when the triangle Apt, ABp become Aqt, ABq, shouldn't we do some fix work to guarantee the topology of the graph is valid.


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);


these two lines are to keep the neighbors relationship  after pq removed.

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);

this line just guarantees the incident halfedge of v is valid.


  remove_edge(edge(h, g), g);
  remove_vertex(v_to_remove, g);

Finally, we remove the edge pq(note here is edge not halfedge), then we remove vertex p. Done!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值