VCGLib中邻接关系的实现

VCGLib中邻接关系的维护依赖于各种单形中存储的相关信息。在VCGLib中几乎所有的算法实现都假设存在vcg::face::VertexRef,该属性存储了三个指向顶点对象的指针,可以通过V()函数访问。

面-面邻接关系

面之间的邻接关系存储于vcg::face::FFAdj(正四面体为vcg::face::TTAdj),该属性通过边来记录面之间的邻接关系。下图显示了两个三角形面:

FF_Adj

图中顶点编号从0到2,以逆时针顺序编号,边i(i=0..2)的两个端点分别为i和(i+1)%3,因此图中面f0和面f1的公共边对f0而言是0,对f1而言是1。

对于面f的每个边e,vcg::face::FFAdj存储以下信息:

  • FFp(e):指向共享边e的面的指针,若e是border,则该指针指向自己;
  • FFi(e):在指向的面中e的索引。

例如在上图中,有:

  • f1->FFp(1) == f0
  • f1->FFi(1) == 0
  • f0->FFp(0) == f1
  • f0->FFi(0) == 1

VCGLib中对于非流形的情况也有考虑,因为只是想简单了解,没有看。

Pos

三角网格中,Pos为一三元组,pos = {v,e,f},e是f的边,v是e的端点。下图以小三角形的形式显示了三角网格中的一些pos,在每个面中,每个小三角形指向一个顶点倚靠一条边。这样就能保证任意给定一个pos c,若只改变c的三元组的一个分量,能够唯一确定一个邻居pos。

pos

从一个pos移动到该pos的一个邻居的操作称为Flip,把改变顶点的Flip操作分别记做FlipVFlipEFlipF

例如,对于上图中的c0而言,其三元组中除了顶点,其他分量都相同的pos只有一个,即c2。记c2 = FlipV(c1)。

类似地,有:

  • c2 = FlipV(c1)
  • c0 = FlipE(c1)
  • c3 = FlipF(c0)

环绕v逆时针遍历:

  • c4 = FlipE(FlipF(c0))
  • c5 = FlipE(FlipF(c4))

在border上的情况:

  • c6 = FlipE(FlipF(c5))

环绕v顺时针遍历:

  • c3 = FlipE(FlipF(c6))
  • c1 = FlipE(FlipF(c3))

border:

  • c0 = FlipE(FlipF(c1))

可以发现,当两个flip嵌套操作的时候,根据pos与面的关系,可以实现顺时针或逆时针的pos转换。并且由于面-面邻接关系的定义方式,当pos在border上的时候,FlipF操作会返回到pos本身所在的面。

下面的例子展示了如何使用pos在顶点周围迭代

/* vcglib/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp */
 
#include <vcg/simplex/face/pos.h> // include the definition of pos
 
//...includes to define your mesh type
 
//class MyVertex: ...
class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef, vcg::face::FFAdj>{};
 
void OneRingNeighborhood( MyFace * f)
{
  MyVertex * v = f->V(0);  
  MyFace* start = f;
  vcg::face::Pos<MyFace> p(f,0,v);// constructor that takes face, edge and vertex
  do
  {
    p.FlipF();
    p.FlipE();
  }while(p.f!=start);
}

Jumping Pos

Jumping Pos类似Pos,但在遇到border的时候不会反弹回去,而是跨到下一个border-face上去。下面这个例子中,上图中的p会从f0跨到f2。

/* vcglib/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp */
 
#include <vcg/simplex/face/jumping_pos.h> // include the definition of jumping pos
 
//...includes to define your mesh type 
 
//class MyVertex: ...
class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef,vcg::face::FFAdj>{};
 
void OneRingNeighborhoodJP( MyFace * f)
{
  MyVertex * v = f->V(0);  
  MyFace* start = f;
  vcg::face::JumpingPos<MyFace> p(f,0,v);// constructor that takes face, edge and vertex
  do
  {
    p.NextFE();
  }while(p.f!=start);
}

顶点-面(VF)的邻接关系

VCG lib中,顶点与面之间也实现了邻接关系,即给定一个顶点v,可以找出所有与其关联的面。

设v_star = (f0,f1,f2,…,fk)为一个列表,该列表中的元素都是与顶点v关联的面。可以通过以下属性索引v_star:

  • vcg::vertex::VFAdj:这是一个顶点的属性,包含了指向f0的指针
  • vcg::face::VFAdj:这是面的属性,该面三个顶点中的每一个顶点都包含了指向v_star列表中下一个面的指针

vfadj

这两个属性不仅是指针,还包含顶点在所指向的面中的索引。例如上图中,有:

v.VFp() == f2

v.VFi() == 0

f2->VFp(0) == f3

f2->VFi(0) == 1    //f2中索引为0的顶点(即v)指向了面f3,而v在f3中的索引为1

f3->VFp(1) == f1

f3->VFi(1) == 2

f1->VFp(2) == f0

f1->VFi(2) == 2

f0->VFp(2) == NULL

f0->VFi(2) == –1

 

英文原文地址:http://vcg.sourceforge.net/index.php/Tutorial

你可能感兴趣的:(cglib)