VCG文档 - 创建和删除曲面元素(Creating and destroying elements)

创建元素

为了创建一个简单的三角形网格或添加元素到存在的曲面, 应当使用 AddVertices(), AddFaces() 函数, 添加的元素在曲面的尾部. 这些函数返回分配的元素的指针.

vector 添加元素会引起内存重新分配, 会导致一些元素的指针失效 . 这些函数可以保证安全的内存重分配, 并且可以正确的更新指针. 例如, 如果你添加一些顶点引起了内存重新分配, 那么 Allocator 函数会对面对应的顶点的指针进行自动更新. 所以你永远不要直接 reallocate 或者 resize 顶点或者面的 vector.

class MyMesh : public vcg::tri::TriMesh< std::vector<MyVertex>, std::vector<MyFace> > {};
int main()
{
  MyMesh m;
  MyMesh::VertexIterator vi = vcg::tri::Allocator<MyMesh>::AddVertices(m,3);
  MyMesh::FaceIterator fi = vcg::tri::Allocator<MyMesh>::AddFaces(m,1);
  MyMesh::VertexPointer ivp[4];
  ivp[0]=&*vi; vi->P()=MyMesh::CoordType ( 0.0, 0.0, 0.0); ++vi;
  ivp[1]=&*vi; vi->P()=MyMesh::CoordType ( 1.0, 0.0, 0.0); ++vi;
  ivp[2]=&*vi; vi->P()=MyMesh::CoordType ( 0.0, 1.0, 0.0); ++vi;
  fi->V(0)=ivp[0];
  fi->V(1)=ivp[1];
  fi->V(2)=ivp[2];

更多的例子可以参考 platonic.h.

作为另一种选择, 你可以以更加简洁的方式添加顶点和面:

  // Alternative, more compact, method for adding a single vertex
  ivp[3]= &*vcg::tri::Allocator<MyMesh>::AddVertex(m,MyMesh::CoordType ( 1.0, 1.0, 0.0));
  // Alternative, more compact, method for adding a single face (once you have the vertex pointers)
  vcg::tri::Allocator<MyMesh>::AddFace(m, ivp[1],ivp[0],ivp[3]);

如果你在持有一些曲面元素的指针, 那么添加元素将会使它们不可用(因为vector 进行了内存重分配). 这种情况下, 应当使用传递给 vcg::tri::Allocator 函数一个 PointerUpdater() 用来更新指针:

  // a potentially dangerous pointer to a mesh element
  MyMesh::FacePointer fp = &m.face[0];
  vcg::tri::Allocator<MyMesh>::PointerUpdater<MyMesh::FacePointer> pu;
  // now the fp pointer could be no more valid due to eventual re-allocation of the m.face vector.
  vcg::tri::Allocator<MyMesh>::AddVertices(m,3);
  vcg::tri::Allocator<MyMesh>::AddFaces(m,1,pu);
  // check if an update of the pointer is needed and do it.
  if(pu.NeedUpdate()) pu.Update(fp);

销毁元素

VCG 采取了 Lazy Deletion 的策略. 即vector 中被删除的元素只是被标记为删除, 但是仍然存在着.

注意, 基本删除函数是非常低级的函数. 他们仅仅简单的将对应的实体标记为 delete, 但不会影响其余对应的结构. 所以, 如果你删除一个顶点而没有移除与它关联的面, 这将会导致不一致的情况. 类似的, 删除一个面将会导致有多余的没有引用的顶点. 再一次注意, 永远不要尝试通过将一个顶点标记为 delete 的方式去删除顶点. 而是要使用 Allocator 工具库的函数. 下面的例子展示了从一个二十面体中删除一些面:

  // Now fill the mesh with an Icosahedron and then delete some faces
  vcg::tri::Icosahedron(m);
  vcg::tri::Allocator<MyMesh>::DeleteFace(m,m.face[1]);
  vcg::tri::Allocator<MyMesh>::DeleteFace(m,m.face[3]);

在上面这样的操作之后, 面的vector 仍然是包含着 20 个元素的(即二十面体的20个面), 但是函数m.FN() 会正确的返回18. 所以, 如果你的算法涉及了删除操作, 那么

m.vert.size() != m.VN()
m.face.size() != m.FN()

所以,当你遍历顶点和面的vector 时, 你应当注意使用 !IsD() 进行检查:

  // If you loop in a mesh with deleted elements you have to skip them!
  MyMesh::CoordType b(0,0,0);
  for(fi = m.face.begin(); fi!=m.face.end(); ++fi )
  {
     if(!fi->IsD()) //    <---- Check added
       {
        b += vcg::Barycenter(*fi);
       }
  }

在一些情况下, 特别是需要多次循环遍历网格但不删除\创建任何元素时, 可以方便的通过使用两个函数来排除删除元素:

  vcg::tri::Allocator<MyMesh>::CompactFaceVector(m);
  vcg::tri::Allocator<MyMesh>::CompactVertexVector(m);

调用这两个函数后, 不再使用 !IsD() 进行检查也是安全的,因为:

m.vert.size() == m.VN()
m.face.size() == m.FN()

注意

如果你的曲面没有删除元素, Compact...() 函数直接返回(它只是检测了元素数目和容器的尺寸是否一致), 所以在漫长的操作开始前调用它的安全的.

如果你的曲面操作有各种删除操作, 那么在for 循环遍历元素时使用FN() , VN() 将是十分危险的, 下面的代码片段是错误的.

 // WRONG WAY of iterating: FN() != m.face.size() if there are deleted elements
  for(int i=0;i<m.FN();++i)
  {
     if(!fi->IsD())
       {
       b += vcg::Barycenter(*fi);
       }
  }

如何Copy 曲面

由于曲面复杂度性质, 任何企图将它作为一个对象去拷贝都是禁止的. 拷贝曲面应当使用 Append 工具类:

MyMesh m2;
  vcg::tri::Append<MyMesh,MyMesh>::MeshCopy(m2,m);

更多的使用说明参见vcg::tri::Append 工具类.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值