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

创建元素

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

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

class MyMesh : public vcg::tri::TriMesh< std::vector, std::vector > {};
int main()
{MyMesh m;MyMesh::VertexIterator vi = vcg::tri::Allocator::AddVertices(m,3);MyMesh::FaceIterator fi = vcg::tri::Allocator::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::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::AddFace(m, ivp[1],ivp[0],ivp[3]);

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

  // a potentially dangerous pointer to a mesh elementMyMesh::FacePointer fp = &m.face[0];vcg::tri::Allocator::PointerUpdater pu;// now the fp pointer could be no more valid due to eventual re-allocation of the m.face vector.vcg::tri::Allocator::AddVertices(m,3);vcg::tri::Allocator::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 facesvcg::tri::Icosahedron(m);vcg::tri::Allocator<MyMesh>::DeleteFace(m,m.face[1]);vcg::tri::Allocator::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 elementsfor(int i=0;iif(!fi->IsD()){b += vcg::Barycenter(*fi);}}

如何Copy 曲面

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

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

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部