CGAL进行半边塌缩之前的可塌缩性判断

曲面简化中通过边塌缩的方式删除顶点、边和面。边塌缩有两种方式:一种是“edge-collapse”,另一种是“halfedge-collapse”。给定一个边e,其关联的顶点分别是w和v,edge-collapse用一个新顶点r取代边e和顶点w、v,而半边塌缩则是把顶点v移到w处,即w的位置是不变的。两种方式都能够删掉边e,以及e连接的两个三角形。CGAL中使用的是halfedge-collapse。

在对某个半边进行塌缩操作之前,要检查该半边是否可进行塌缩,代码如下:

// Edge_collapse_impl.h
// 有些边塌缩之后,会导致网格的拓扑一致性被破坏,因此不能对这些边进行塌缩操作。
// 该函数用于检查边p->q的可塌缩性,若p->q可塌缩,该函数返回true
// 判断p->q是否具有可塌缩性的依据是1993年Hoppe等人的论文“Mesh Optimization”中的“link condition”,
// link condition: 对于网格中每个既是p又是q的邻居的顶点k,p-k-q是网格的一个面。
//
template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>
bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Is_collapse_topologically_valid( Profile const& aProfile )
{
  bool rR = true ;
 
  CGAL_ECMS_TRACE(3,"Testing topological collapsabilty of p_q=V" << aProfile.v0()->id() << "(%" << aProfile.v0()->vertex_degree() << ")"
                 << "->V" << aProfile.v1()->id() << "(%" << aProfile.v1()->vertex_degree() << ")" 
                 );
                 
  CGAL_ECMS_TRACE(4, "is p_q border:" << aProfile.is_v0_v1_a_border() );
  CGAL_ECMS_TRACE(4, "is q_q border:" << aProfile.is_v1_v0_a_border() );
 
  out_edge_iterator eb1, ee1 ; 
  out_edge_iterator eb2, ee2 ; 
 
  CGAL_ECMS_TRACE(4,"  t=V" 
                   << ( aProfile.left_face_exists() ? aProfile.vL()->id() : -1 )
                   << "(%" 
                   << ( aProfile.left_face_exists() ? aProfile.vL()->vertex_degree() : 0 ) 
                   << ")" 
                 );
  CGAL_ECMS_TRACE(4,"  b=V" 
                   << ( aProfile.right_face_exists() ? aProfile.vR()->id() : -1 )
                   << "(%" 
                   << ( aProfile.right_face_exists() ? aProfile.vR()->vertex_degree() :0 ) 
                   << ")" 
                   );
 
  // The following loop checks the link condition for v0_v1.
  // Specifically, that for every vertex 'k' adjacent to both 'p and 'q', 'pkq' is a face of the mesh.
  // 
  for ( boost::tie(eb1,ee1) = out_edges(aProfile.v0(),mSurface) ; rR && eb1 != ee1 ; ++ eb1 )
  {
    edge_descriptor v0_k = *eb1 ;
    
    if ( v0_k != aProfile.v0_v1() )//边v0_k不是边v0_v1
    {
      vertex_descriptor k = target(v0_k,mSurface);
      
      for ( boost::tie(eb2,ee2) = out_edges(k,mSurface) ; rR && eb2 != ee2 ; ++ eb2 )//遍历环绕k的半边,找出连接k与v1的那条
      {
        edge_descriptor k_v1 = *eb2 ;
 
        if ( target(k_v1,mSurface) == aProfile.v1() )//找到了连接k和v1的半边
        {
          // 现在已知p-q-k是连通的,接下来要判断这个三角形是否是网格的一个面
          //
          // 由于必须是三角网格,所以至多有两个面共享边p-q
          //
          // 若p->q不是border edge, 设t = target(next(p->q)),则p->q上方的面为p-q-t
          // 若q->p不是border edge, 设b = target(next(q->p)),则q->p下方的面为q-p-b
          //
          // 若k是t或者b,则p-q-k ★可能★是网格的一个面。 It won't be if k==t but p->q is border
          // 若p-q-k是一个面的话,则不会出现k==t,而k->q是border或k==b而q->b是border的情况
     
          bool lIsFace =   ( aProfile.vL() == k && aProfile.left_face_exists () )
                        || ( aProfile.vR() == k && aProfile.right_face_exists() ) ;
                        
          CGAL_SURF_SIMPL_TEST_assertion_code
          ( 
            if ( lIsFace )
            {
              // Is k_v1 the halfedge bounding the face 'k-v1-v0'?
              if ( !k_v1->is_border() && k_v1->next()->vertex() == aProfile.v0() )
              {
                CGAL_SURF_SIMPL_TEST_assertion( !k_v1->is_border() ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  k_v1                ->vertex() == aProfile.v1() ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  k_v1->next()        ->vertex() == aProfile.v0() ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  k_v1->next()->next()->vertex() == k ) ;
              }
              else // or is it the opposite?
              {
                edge_descriptor v1_k = k_v1->opposite();
                CGAL_SURF_SIMPL_TEST_assertion( !v1_k->is_border() ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  v1_k                ->vertex() == k ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  v1_k->next()        ->vertex() == aProfile.v0() ) ;
                CGAL_SURF_SIMPL_TEST_assertion(  v1_k->next()->next()->vertex() == aProfile.v1() ) ;
              }
            }
          );
 
          if ( !lIsFace )
          {
            CGAL_ECMS_TRACE(3,"  k=V" << k->id() << " IS NOT in a face with p-q. NON-COLLAPSABLE edge." ) ;
            rR = false ;
            break ;
          }  
          else 
          {
            CGAL_ECMS_TRACE(4,"  k=V" << k->id() << " is in a face with p-q") ;
          }
        }
      }  
    }
  }   
     
  if ( rR )//rR为真,说明p-q-k是个面,但是有可能pq边关联的另一个三角形是个洞,或者顶点p、q周围存在border
  {
    if ( aProfile.is_v0_v1_a_border() )
    {
      if ( Is_open_triangle(aProfile.v0_v1()) )
      {
        rR = false ;
        CGAL_ECMS_TRACE(3,"  p-q belongs to an open triangle. NON-COLLAPSABLE edge." ) ;
      }
    }
    else if ( aProfile.is_v1_v0_a_border() )
    {
      if ( Is_open_triangle(aProfile.v1_v0()) )
      {
        rR = false ;
        CGAL_ECMS_TRACE(3,"  p-q belongs to an open triangle. NON-COLLAPSABLE edge." ) ;
      }
    }
    else
    {
      if ( is_border(aProfile.v0()) && is_border(aProfile.v1()) )
      {
        rR = false ;
        CGAL_ECMS_TRACE(3,"  both p and q are boundary vertices but p-q is not. NON-COLLAPSABLE edge." ) ;
      }  
      else
      {
        bool lTetra = Is_tetrahedron(aProfile.v0_v1());
 
        CGAL_SURF_SIMPL_TEST_assertion( lTetra == mSurface.is_tetrahedron(aProfile.v0_v1()) ) ;
 
        if ( lTetra )
        {
          rR = false ;
          CGAL_ECMS_TRACE(3,"  p-q belongs to a tetrahedron. NON-COLLAPSABLE edge." ) ;
        }
      }
    }
  }
  
  return rR ;
}

你可能感兴趣的:(判断)