Openmesh函数库设计及与CGAL的对比
2015-09-11 12:44
274 查看
Openmesh函数库设计及与CGAL的对比
http://www.cnblogs.com/rocketfan/category/261367.html在前面写了CGAL模板类设计的一些思路,这里尝试写一点openmesh库的设计思路以及和CGAL的对比.虽然OPENMESH代码量小,不过还是只看懂皮毛,很大部分算是翻译帮助文档吧,主要用作笔记,
方便以后继续分析。
相对CGAL的功能强大和庞大(包含大量计算几何算法的实现),Openmesh显得更加小巧轻量化,它更专注在三维网格数据结构的表示,
外围也提供在此基础上的网格简化算法及框架,网格细分等等应用算法。
同样是在实现上大量依赖模版类,但是Openmesh源代码的可读性更好些(很大程度上也因为它的小巧,CGAL实现文件太多了,层次结构复杂),
在提供给用户的类,
Openmesh的设计是尽可能少的让用户去知晓模版参数,也就是除非必须,
尽量减少模版参数甚至不带模板参数。
Openmesh设计的一个亮点是用户可以在程序运行时动态为网格添加属性和删除属性
这个功能很赞的。一个典型的应用,可以写一个对网格进行光顺的smooth算法template<classMesh>classSmootherT { public: typedeftypenameMesh::Pointcog_t; typedefOpenMesh::VPropHandleT<cog_t>Property_cog; public: //constructwithagivenmesh SmootherT(Mesh&_mesh) :mesh_(_mesh) { mesh_.add_property(cog_); } ~SmootherT() { mesh_.remove_property(cog_); } //smoothmesh_iterationstimes voidsmooth(unsignedint_iterations) { for(unsignedinti=0;i<_iterations;++i) { std::for_each(mesh_.vertices_begin(), mesh_.vertices_end(), ComputeCOG(mesh_,cog_)); std::for_each(mesh_.vertices_begin(), mesh_.vertices_end(), SetCOG(mesh_,cog_)); } } private: //---privateclasses--- classComputeCOG { public: ComputeCOG(Mesh&_mesh,Property_cog&_cog) :mesh_(_mesh),cog_(_cog) {} voidoperator()(typenameMesh::Vertex&_v) { typenameMesh::VertexHandlevh(mesh_.handle(_v)); typenameMesh::VertexVertexItervv_it; typenameMesh::Scalarvalence(0.0); mesh_.property(cog_,vh)=typenameMesh::Point(0.0,0.0,0.0); for(vv_it=mesh_.vv_iter(vh);vv_it;++vv_it) { mesh_.property(cog_,vh)+=mesh_.point(vv_it); ++valence; } mesh_.property(cog_,mesh_.handle(_v))/=valence; } private: Mesh&mesh_; Property_cog&cog_; }; classSetCOG { public: SetCOG(Mesh&_mesh,Property_cog&_cog) :mesh_(_mesh),cog_(_cog) {} voidoperator()(typenameMesh::Vertex&_v) { typenameMesh::VertexHandlevh(mesh_.handle(_v)); if(!mesh_.is_boundary(vh)) mesh_.set_point(vh,mesh_.property(cog_,vh)); } private: Mesh&mesh_; Property_cog&cog_; }; //---privateelements--- Mesh&mesh_; Property_cogcog_; };
当用户希望对其所持有的mesh做光顺处理的时候,就可以交给SmooterT类来完成。
//smoothingmeshargv[1]times SmootherT<MyMesh>smoother(mesh); smoother.smooth(atoi(argv[1]));
这个实例也显示了openmesh和STL的结合,foreach,函数对象的使用。
最酷的还是SmootherT类会给传入的mesh对象添加顶点参数,即每一个顶点添加一个cog_,记录光顺后的位置,最后
所有顶点都计算好,原顶点位置可以改变的时候再赋值给原顶点。当完成了smooth操作后析构函数自动又把这个属性从mesh中删除,这样对于用户而言这些就是透明的,对用户而言mesh只是被光顺。
这种实现很漂亮,如果不采用动态添加属性的话,用户就需要在定义自己的mesh的时候考虑到由于光顺操作的需要,添加一个cog_属性,但是当光顺完不需要这个属性的时候,该属性也还会存在,
占用内存。
如果不想这样,那也只好在调用smooth的时候建立一个一维数组,大小和顶点数目相同,将属性值记录到该数组中,不用了删除数组占用空间。但是这样的可读性就差了。
另外一个应用,点法向的计算。(法向属性常规属性,用户也可以自由添加删除,但是调用函数和用户自定义属性有所不同)
首先可以给网格添加顶点属性即
mesh.request_vertex_normals();
因为计算顶点法向是需要面法相的(所有相邻面法向的和),所以我们需要添加面法向属性
mesh.request_face_normals(); //letthemeshupdatethenormals mesh.update_normals(); //disposethefacenormals,aswedon'tneedthemanymore不需要面法向了就去掉它 mesh.release_face_normals();
相当的灵活。
CGAL的网格模型数据结构部分(半边数据结构)的架构。
半边结构示意图。半边结构非常适合描述网格结构,因为它可以方便的改变网格拓扑形态,如删除边,分裂边等待.
上图为CGAL中的类结构设计.
各个模块关系.
默认的顶点,边,面
这里我们只关心,最上层的Polyhedron
用户使用默认的Polyhedron
#include<CGAL/Simple_cartesian.h> #include<CGAL/Polyhedron_3.h> #include<iostream> typedefCGAL::Simple_cartesian<double>Kernel; typedefKernel::Point_3Point_3; typedefCGAL::Polyhedron_3<Kernel>Polyhedron; typedefPolyhedron::Vertex_iteratorVertex_iterator; intmain(){ Point_3p(1.0,0.0,0.0); Point_3q(0.0,1.0,0.0); Point_3r(0.0,0.0,1.0); Point_3s(0.0,0.0,0.0); PolyhedronP; P.make_tetrahedron(p,q,r,s); CGAL::set_ascii_mode(std::cout); for(Vertex_iteratorv=P.vertices_begin();v!=P.vertices_end();++v) std::cout<<v->point()<<std::endl; return0; }
默认情况下用的是HalfedgeDS_defualt,是基于list的,用户可以选择使用基于vector实现的半边结构。
基于vector的半边结构适合静态的网格结构。
typedefCGAL::Polyhedron_3<Traits, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default>Polyhedron;
#include<CGAL/Cartesian.h> #include<CGAL/HalfedgeDS_vector.h> #include<CGAL/Polyhedron_3.h> #include<iostream> typedefCGAL::Cartesian<double>Kernel;//CGAL用Traits(Kernel)表示采用的数据精度类型如这里的Cartesian<double>
typedefKernel::Point_3Point_3; typedefCGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_vector>Polyhedron;//使用基于vector实现的半边结构 intmain(){ Point_3p(1.0,0.0,0.0); Point_3q(0.0,1.0,0.0); Point_3r(0.0,0.0,1.0); Point_3s(0.0,0.0,0.0); PolyhedronP;//alternativeconstructor:PolyhedronP(4,12,4); P.make_tetrahedron(p,q,r,s); CGAL::set_ascii_mode(std::cout); std::copy(P.points_begin(),P.points_end(), std::ostream_iterator<Point_3>(std::cout,"\n")); return0; }
用户如何定义自己的特定的mesh顶点,边,面属性?
#include<CGAL/Simple_cartesian.h> #include<CGAL/IO/Color.h> #include<CGAL/Polyhedron_3.h> //Afacetypewithacolormembervariable. template<classRefs> structMy_face:publicCGAL::HalfedgeDS_face_base<Refs>{ CGAL::Colorcolor; }; //Anitemstypeusingmyface. structMy_items:publicCGAL::Polyhedron_items_3{ template<classRefs,classTraits> structFace_wrapper{ typedefMy_face<Refs>Face; }; }; typedefCGAL::Simple_cartesian<double>Kernel; typedefCGAL::Polyhedron_3<Kernel,My_items>Polyhedron; typedefPolyhedron::Halfedge_handleHalfedge_handle; intmain(){ PolyhedronP; Halfedge_handleh=P.make_tetrahedron(); h->facet()->color=CGAL::RED; return0; }
注意这种方式虽然也算方便,但是对用户而言其实他不关系Refs,Traits,最好应该能够将这些模板参数去掉,尽量少的让用户接触模板参数。Openmesh做到了这一点。
具体上面的方法怎么起到能够让程序选择使用用户自定义的结构可以看我前面关于CGAL模板类设计的文章。
openmesh,的设计
考虑能够提供动态存储管理的基于array存储的网格。考虑提供普通的半边网格结构,和特殊的三角网格半边结构(更快,专为三角网格优化)
考虑能够兼容诸如quadtree的网格表示方法,用以实现快速的细分。也可定义其它的kernal以便实现诸如允许非流形存在的网格结构。
Openmesh中的接口:
网格提供的可选参数FaceType
什么样的Mesh普通的还是三角网格Mesh?
Kernal(WELL当前版本的OPENMESH只提供基于ARRAY(std::vector)的kernal,当然kernal还是可选)
选择采用doublelinkedlist还是array作为底层的存储方式?container
Traits
(注意这里和CGAL的Traits表示意义不同那里是表示采用什么精度类型的数据等等,一般不需要过多考虑)
这里通过这个参数,
用户可以定义它自己的顶点类型,面,边,加入自己需要的属性,方法。
以及修改坐标的数据类型如double,float,三维坐标还是二维坐标。
Openmesh的用户接口API等待更加友好,可以对比下
使用默认的网格结构
使用默认的普通网格,arraybased
typedefOpenMesh::PolyMesh_ArrayKernelT<>MyMesh;
使用默认的三角网格,arraybased
typedefOpenMesh::TriMesh_ArrayKernelT<>MyMesh;
用户自定义自己的traits
//Definemypersonaltraits structMyTraits:OpenMesh::DefaultTraits { //LetPointandNormalbeavectorofdoubles typedefOpenMesh::Vec3dPoint;//Point的类型被定义为3维double类型 typedefOpenMesh::Vec3dNormal; //AlreadydefinedinOpenMesh::DefaultTraits //HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); //UncommentnextlinetodisableattributePrevHalfedge //HalfedgeAttributes(OpenMesh::Attributes::None); // //or // //HalfedgeAttributes(0); }; #endif //Definemymeshwiththenewtraits! typedefOpenMesh::TriMesh_ArrayKernelT<MyTraits>MyMesh; //------------------------------------------------------------------main---- MyMeshmesh; //Justmakesurethatpointelementtypeisdouble if(typeid(OpenMesh::vector_traits<MyMesh::Point>::value_type) !=typeid(double)) { std::cerr<<"Ouch!ERROR!Datatypeiswrong!\n"; return1; } //另外一个例子
structMyTraits:publicOpenMesh::DefaultTraits { //storebarycenterofneighborsinthismember VertexTraits { private: Pointcog_; public: VertexT():cog_(Point(0.0f,0.0f,0.0f)){} constPoint&cog()const{returncog_;} voidset_cog(constPoint&_p){cog_=_p;} }; }; #endif typedefOpenMesh::TriMesh_ArrayKernelT<MyTraits>MyMesh; typedefOpenMesh::TriMesh_ArrayKernelT<>MyMesh2;
注意和CGAL的不同这里用户自定义traits更加简单友好,没有任何的模板参数。
以前旧版本的openmesh里面的vertex还要写成下面的形式,有模板参数,那么现在这个是如何实现的呢?
template<classBase>classVertexT:publicBase
OPENMESH同样运用了与CGAL相同的利用前置声明的技术解决类型依赖问题,见
Sincethehandletypesdependonthecontainersusedbythemesh
kernel(e.g.aVertexHandlemaybeaVertex*oranint),the
kernelitselfdependsonthemeshitems(inordertoconstructthe
handletypes),andtheitemsrequirethehandles(avertexmuststore
ahalfedgehandle),wehavetousetemplateforwarddeclarations
toget“safe”handletypes(see[7]).Usingthistechnique,theitem
typesknoweachotherandtheirrespectivehandletypes,thereby
avoidingtouseandcastvoidpointers.Thisalsoenablesustouse
thehandlestypesinthetraitsclasses,e.g.ifthefacetypeshould
containavertexhandle。
不同的mesh将会是不同的类型,为了让mesh算法能够为所有类型的mesh服务,采用了泛型方法,将Mesh类型作为所有
算法的一个模板参数。
Aswehaveseen,weuseacustom–tailoredmeshforeachapplication.
AllthesemesheswillbedifferentC++types.Ifwewant
todesignalgorithmsoperatingonallofthesemeshtypes,weeither
havetoderiveallmeshesfromacommonvirtualbaseclass,ordo
ittheSTLwayandusegenericprogrammingmethods.Sincevirtual
functions/classesleadtoacertainoverheadinspaceandtime,
wehavechosenthegenericapproach:everyalgorithmgetsthetype
Meshinformofatemplateparameter.
对比一下CGAL看一下Openmesh是如何定义顶点,边和面的。
///DefinitionofmeshitemsforuseintheArrayKernel
structArrayItems
{
//------------------------------------------------------internalvertextype
///Thevertexitem
classVertex
{
friendclassArrayKernel;
HalfedgeHandlehalfedge_handle_;
};
//----------------------------------------------------internalhalfedgetype
#ifndefDOXY_IGNORE_THIS
classHalfedge_without_prev
{
friendclassArrayKernel;
FaceHandleface_handle_;
VertexHandlevertex_handle_;
HalfedgeHandlenext_halfedge_handle_;
};
#endif
#ifndefDOXY_IGNORE_THIS
classHalfedge_with_prev:publicHalfedge_without_prev
{
friendclassArrayKernel;
HalfedgeHandleprev_halfedge_handle_;
};
#endif
//TODO:shouldbeselectedwithconfig.hdefine
typedefHalfedge_with_prevHalfedge;
typedefGenProg::Bool2Type<true>HasPrevHalfedge;
//--------------------------------------------------------internaledgetype
#ifndefDOXY_IGNORE_THIS
classEdge
{
friendclassArrayKernel;
Halfedgehalfedges_[2];
};
#endif
//--------------------------------------------------------internalfacetype
#ifndefDOXY_IGNORE_THIS
classFace
{
friendclassArrayKernel;
HalfedgeHandlehalfedge_handle_;
};
};
//上面都用到了handle,
//那么handle是怎么定义的呢?
classBaseHandle;
///Handleforavertexentity
structVertexHandle:publicBaseHandle
{
explicitVertexHandle(int_idx=-1):BaseHandle(_idx){}
};
///Handleforahalfedgeentity
structHalfedgeHandle:publicBaseHandle
{
explicitHalfedgeHandle(int_idx=-1):BaseHandle(_idx){}
};
///Handleforaedgeentity
structEdgeHandle:publicBaseHandle
{
explicitEdgeHandle(int_idx=-1):BaseHandle(_idx){}
};
///Handleforafaceentity
structFaceHandle:publicBaseHandle
{
explicitFaceHandle(int_idx=-1):BaseHandle(_idx){}
};
//一个具体的kernel如何定义的呢
classArrayKernel:publicBaseKernel,publicArrayItems
{
public:
//handles
typedefOpenMesh::VertexHandleVertexHandle;
typedefOpenMesh::HalfedgeHandleHalfedgeHandle;
typedefOpenMesh::EdgeHandleEdgeHandle;
typedefOpenMesh::FaceHandleFaceHandle;
typedefAttributes::StatusInfoStatusInfo;
typedefVPropHandleT<StatusInfo>VertexStatusPropertyHandle;
typedefHPropHandleT<StatusInfo>HalfedgeStatusPropertyHandle;
typedefEPropHandleT<StatusInfo>EdgeStatusPropertyHandle;
typedefFPropHandleT<StatusInfo>FaceStatusPropertyHandle;
HalfedgeHandleopposite_halfedge_handle(HalfedgeHandle_heh)const
{returnHalfedgeHandle((_heh.idx()&1)?_heh.idx()-1:_heh.idx()+1);}
private:
//iterators
typedefstd::vector<Vertex>VertexContainer;
typedefstd::vector<Edge>EdgeContainer;
typedefstd::vector<Face>FaceContainer;
typedefVertexContainer::iteratorKernelVertexIter;
typedefVertexContainer::const_iteratorKernelConstVertexIter;
typedefEdgeContainer::iteratorKernelEdgeIter;
typedefEdgeContainer::const_iteratorKernelConstEdgeIter;
typedefFaceContainer::iteratorKernelFaceIter;
typedefFaceContainer::const_iteratorKernelConstFaceIter;
typedefstd::vector<uint>BitMaskContainer;
KernelVertexItervertices_begin(){returnvertices_.begin();}
KernelConstVertexItervertices_begin()const{returnvertices_.begin();}
KernelVertexItervertices_end(){returnvertices_.end();}
KernelConstVertexItervertices_end()const{returnvertices_.end();}
KernelEdgeIteredges_begin(){returnedges_.begin();}
KernelConstEdgeIteredges_begin()const{returnedges_.begin();}
KernelEdgeIteredges_end(){returnedges_.end();}
KernelConstEdgeIteredges_end()const{returnedges_.end();}
KernelFaceIterfaces_begin(){returnfaces_.begin();}
KernelConstFaceIterfaces_begin()const{returnfaces_.begin();}
KernelFaceIterfaces_end(){returnfaces_.end();}
KernelConstFaceIterfaces_end()const{returnfaces_.end();}
private:
VertexContainervertices_;
EdgeContaineredges_;
FaceContainerfaces_;
}
事实上当前版本的OPENMESH的顶点,边,面的基本结构非常简单,就是相关的handle,而handle类型也是定死了的。不存在模板循环依赖技术,与CGAL不同。
OPENMESH当前只采用基于VECTOR的构架,它把其余的顶点属性其实统统存在顶点之外,用数组保存,由于有handle即index,
所以访问的时候是用的MESH::Kernal的方法如mesh_.property(cog_,vh)+=mesh_.point(vv_it);,mesh_根据vh找到数组中
该cog_的值。本质上是和vertex分离的,否则应该类似调用vh->cog_了,另外包括像顶点的位置,也是如此通过mesh_.point(vh)来得到
而不是CGAL中vh->point(),即坐标属性没有存储在vertex之中。vertex只存一个halfedge_handle。
所以用户用traits自定义属性如cog_或者动态添加cog_本质上和自己定义一个cog[vertex_num]数组差不多,只不过openmesh封装了实现,提供统一方便的接口,
看上去似乎就像是给vertex本身加了个cog_域。mesh_.property(cog_,vh)还是反映了实际的存储情况。
但是问题是如果要提供基于list的meshkernal呢,当前的架构似乎不能支持list吧?
不过对于自己定义traits的时候给vertex_traits加入的属性cog_,方法cog()是可以按照下面的方式访问的。(注,这个是老的版本这样支持的,
新版本去除了这一方式,其余的属性本质上就是顶点Vertex之外,由Mesh利用顶点属性数组统一管理的)
MyMesh::VertexIterv_it
v_it->cog()//旧版本
//新版本要用mesh.data(v_it)->cog()//看了一版本变化说明,似乎是说因为MS不支持模版的前置循环声明好像,不得已为之的。
mesh.data(v_it).set_cog(cog/valence);
下面是02年的修改声明。应该就是因为这个原因,就把顶点,边,面定死了,不过看CGAL应该是支持的啊,奇怪:)现在的MSVC8应该肯定支持的。
Removedcyclicdependencybetweenitemsandkernel,becauseMSVC++cannothandletheresultingtemplateforwarddeclaration:-(.
ThereforetheBase::Refsclass,givenforthetraitsclasses,nolongerprovidesthetypes\cVertex,\cHalfedge,\cEdge,and\cFace.
Itnowonlyprovidesallhandletypes,thepointandthescalartype.
我们看下为了实现下面的应用代码,程序内部是怎么构架的。
应用代码:
structMyTraits:publicOpenMesh::DefaultTraits
{
//storebarycenterofneighborsinthismember
VertexTraits
{
private:
Pointcog_;
public:
VertexT():cog_(Point(0.0f,0.0f,0.0f)){}
constPoint&cog()const{returncog_;}
voidset_cog(constPoint&_p){cog_=_p;}
};
};
#endif
typedefOpenMesh::TriMesh_ArrayKernelT<MyTraits>MyMesh;//下面就可以MyMeshmesh;使用这个mesh了。
//OK具体上面的代码内部是如何实现的呢。
先看DefaultTraits
//只显示部分内容
structDefaultTraits
{
///ThedefaultcoordinatetypeisOpenMesh::Vec3f.
typedefVec3fPoint;
///ThedefaultnormaltypeisOpenMesh::Vec3f.
typedefVec3fNormal;
…
#ifndefDOXY_IGNORE_THIS
VertexTraits{};
HalfedgeTraits{};
EdgeTraits{};
FaceTraits{};
#endif
VertexAttributes(0);
…
};
先不管Atrtributes,我们就看VertexTraits,
这里其实是用了宏,来对用户隐藏了模板参数。
///Macrofordefiningthevertextraits.See\refmesh_type.
#defineVertexTraits\
template<classBase,classRefs>structVertexT:publicBase//其余Tratis如face,halfedge的一样的方式处理
所以实际代码展开之后类似下面
structMyTraits:publicOpenMesh::DefaultTraits
{
template<classBase,classRefs>structVertexT:publicBase
{
intsome_additional_index;
};
};
这也就是为什么构造函数要写VertexT()的原因。
ThetemplateargumentBaseprovidesaccesstothemeshhandlesandtothePointandScalartypebyitsmemberclassRefs.
AddingaMyMesh::FaceHandletothevertexclasscanthereforebeimplementedlikethis:
下面显示如何给顶点添加面handle属性。
structMyTraits:publicOpenMesh::DefaultTraits
{
VertexTraits
{
intsome_additional_index;
typenameBase::Refs::FaceHandlemy_face_handle;
};
};
下面再看typedefOpenMesh::TriMesh_ArrayKernelT<MyTraits>MyMesh;意味着什么呢?
TriMesh_ArrayKernelT
它的实现利用了继承TriMesh_ArrayKernel_GeneratorT<Traits>::Mesh
template<classTraits=DefaultTraits>
classTriMesh_ArrayKernelT
:publicTriMesh_ArrayKernel_GeneratorT<Traits>::Mesh
{};
template<classTraits>
structTriMesh_ArrayKernel_GeneratorT
{
typedefFinalMeshItemsT<Traits,true>MeshItems;
typedefAttribKernelT<MeshItems,TriConnectivity>AttribKernel;
typedefTriMeshT<AttribKernel>Mesh;//其实就是最终使用的mesh类型
};
代码所表示的正是如上图所示的继承关系。OPENMESH大量利用template<classBase>classDerived:publicBase的继承模式。
1.TheBaseKerneldefinesthebasicoperationsonpropertieslikeadd/remove/access.
2.NexttheAttribKernelTaddsthestandardpropertiesallassociatedmethods.
3.FinallytheArrayKernelTprovidesthemethodstoadd/remove/accessthemeshitemsvertices,(half-)edges,andfaces.Thebaseclassispassedasatemplateparameter,sincedependingontheunderlyingstoragetypetheAttribKernelmightchange.
1.ThePolyMeshTinheritsfromthekernelandprovideallnecessarymethodstoworkwithpolygonalmeshes.
2.FinallywederiveTriMeshTfromPolyMeshTtohaveanspecializationfortrianglemeshes.
1.先来看FinalMeshItemsT,为了方便去掉了一些代码如attributes的部分。
FinalMeshItemsT<Traits,true>MeshItems;
template<classTraits,boolIsTriMesh>
structFinalMeshItemsT
{
structRefs
{
typedeftypenameTraits::PointPoint;//所以用户提供的MyTraits可能会改变Point的类型
typedeftypenamevector_traits<Point>::value_typeScalar;
…
typedefOpenMesh::VertexHandleVertexHandle;
…
};
//---exportRefstypes---
typedeftypenameRefs::PointPoint;
…
classITraits
{};
typedeftypenameTraits::templateVertexT<ITraits,Refs>VertexData;//这里用到了VertexT(可能由用户修改提供)
typedeftypenameTraits::templateHalfedgeT<ITraits,Refs>HalfedgeData;
…
};
}//namespaceOpenMesh
2.再看AttribKernelT
AttribKernelT<MeshItems,TriConnectivity>AttribKernel;通过继承Connectivity继承TriConnectivity->PolyConnectivity->ArrayKernel->BaseKernel
+ArrayItems
template<classMeshItems,classConnectivity>
classAttribKernelT:publicConnectivity//classTriConnectivity:publicPolyConnectivity
{//classPolyConnectivity:publicArrayKernel
public:
//----------------------------------------------------------------itemtypes
typedeftypenameConnectivity::VertexVertex;
typedeftypenameConnectivity::HalfedgeHalfedge;
typedeftypenameConnectivity::EdgeEdge;
typedeftypenameConnectivity::FaceFace;
typedeftypenameMeshItems::PointPoint;
typedeftypenameMeshItems::NormalNormal;
…
typedeftypenameMeshItems::VertexDataVertexData;
typedeftypenameMeshItems::HalfedgeDataHalfedgeData;
typedeftypenameMeshItems::EdgeDataEdgeData;
typedeftypenameMeshItems::FaceDataFaceData;
typedefAttribKernelT<MeshItems,Connectivity>AttribKernel;
enumAttribs{
VAttribs=MeshItems::VAttribs,
HAttribs=MeshItems::HAttribs,
EAttribs=MeshItems::EAttribs,
FAttribs=MeshItems::FAttribs
};
typedefVPropHandleT<VertexData>DataVPropHandle;
typedefHPropHandleT<HalfedgeData>DataHPropHandle;
typedefEPropHandleT<EdgeData>DataEPropHandle;
typedefFPropHandleT<FaceData>DataFPropHandle;
public:
//--------------------------------------------------constructor/destructor
AttribKernelT()
:refcount_vnormals_(0),
refcount_vcolors_(0),
…
{
add_property(points_,"v:points");
if(VAttribs&Attributes::Normal)
request_vertex_normals();
…
//FIXME:datapropertiesmightactuallycoststorageeven
//iftherearenodatatraits??
add_property(data_vpph_);
add_property(data_fpph_);
add_property(data_hpph_);
add_property(data_epph_);
}
virtual~AttribKernelT()
{
//shouldremoveproperties,butthiswillbedonein
//BaseKernel'sdestructoranyway...
}
/**Assignmentfromanothermeshof\emanothertype.
\noteAllthat'scopiedisconnectivityandvertexpositions.
Allotherinformation(likee.g.attributesoradditional
elementsfromtraitsclasses)isnotcopied.
\noteIfyouwanttocopyallinformation,including*custom*properties,
usePolyMeshT::operator=()instead.
TODO:versionwhichcopiesstandardpropertiesspecifiedbytheuser
*/
template<class_AttribKernel>
voidassign(const_AttribKernel&_other)
{
assign_connectivity(_other);
for(typenameConnectivity::VertexIterv_it=Connectivity::vertices_begin();
v_it!=Connectivity::vertices_end();++v_it)
{//assumesPointconstructorsupportscastfrom_AttribKernel::Point
set_point(v_it,(Point)_other.point(v_it));
}
}
…
//------------------------------------------------request/allocproperties
voidrequest_vertex_normals()
{
if(!refcount_vnormals_++)
add_property(vertex_normals_,"v:normals");
}
…
//-------------------------------------------------release/freeproperties
voidrelease_vertex_normals()
{
if((refcount_vnormals_>0)&&(!--refcount_vnormals_))
remove_property(vertex_normals_);
}
….
//----------------------------------------------dynamiccheckforproperties
boolhas_vertex_normals()const{returnvertex_normals_.is_valid();}
…
public:
typedefVPropHandleT<Point>PointsPropertyHandle;
typedefVPropHandleT<Normal>VertexNormalsPropertyHandle;
…
public:
//standardvertexproperties
PointsPropertyHandlepoints_pph()const
{returnpoints_;}
…
VertexData&data(VertexHandle_vh)
{returnproperty(data_vpph_,_vh);}
…
private:
//standardvertexproperties
PointsPropertyHandlepoints_;
VertexNormalsPropertyHandlevertex_normals_;
…
//datapropertieshandles
DataVPropHandledata_vpph_;
DataHPropHandledata_hpph_;
DataEPropHandledata_epph_;
DataFPropHandledata_fpph_;
…
};
关于add_property在classBaseKernel中。
template<classT>
voidadd_property(VPropHandleT<T>&_ph,conststd::string&_name="<vprop>")
{
_ph=VPropHandleT<T>(vprops_.add(T(),_name));
vprops_.resize(n_vertices());//inBaseKernelPropertyContainervprops_;
}
//
classArrayKernel:publicBaseKernel,publicArrayItems
{
public:
//handles
typedefOpenMesh::VertexHandleVertexHandle;
typedefOpenMesh::HalfedgeHandleHalfedgeHandle;
typedefOpenMesh::EdgeHandleEdgeHandle;
typedefOpenMesh::FaceHandleFaceHandle;
typedefstd::vector<Vertex>VertexContainer;
Vertex&vertex(VertexHandle_vh)
{
assert(is_valid_handle(_vh));
returnvertices_[_vh.idx()];
}
private:
VertexContainervertices_;
EdgeContaineredges_;
FaceContainerfaces_;
}
classBaseKernel
{
private:
PropertyContainervprops_;
PropertyContainerhprops_;
PropertyContainereprops_;
PropertyContainerfprops_;
PropertyContainermprops_;
};
3.最后看TriMeshT
TriMeshT<AttribKernel>Mesh;
template<classKernel>
classTriMeshT:publicPolyMeshT<Kernel>
{
public:
//self
typedefTriMeshT<Kernel>This;
typedefPolyMeshT<Kernel>PolyMesh;
//---items---
typedeftypenamePolyMesh::ScalarScalar;
typedeftypenamePolyMesh::PointPoint;
…
//---handles---
typedeftypenamePolyMesh::VertexHandleVertexHandle;
typedeftypenamePolyMesh::HalfedgeHandleHalfedgeHandle;
typedeftypenamePolyMesh::EdgeHandleEdgeHandle;
typedeftypenamePolyMesh::FaceHandleFaceHandle;
//---iterators---
typedeftypenamePolyMesh::VertexIterVertexIter;
…
//---circulators---
typedeftypenamePolyMesh::VertexVertexIterVertexVertexIter;
…
}
template<classKernel>
classPolyMeshT:publicKernel
看一下具体执行Meshmesh;的时候构造函数的调用,其中PorpertyContainer是BaseKernel类的一个成员变量被初始化,其余都是代表类的默认初始化。可以看出类的层次关系。
(gdb)bt
#0new_allocator(this=0xbfc56563)at/usr/include/c++/4.2/ext/new_allocator.h:68
#10xb7f4f07binallocator(this=0xbfc56563)at/usr/include/c++/4.2/bits/allocator.h:100
#20xb7f50a81inPropertyContainer(this=0xbfc566ac)at/home/allen/study/OpenMesh/src/OpenMesh/Core/../../OpenMesh/Core/Utils/PropertyContainer.hh:66
#30xb7f56a76inBaseKernel(this=0xbfc566a8)at/home/allen/study/OpenMesh/src/OpenMesh/Core/../../OpenMesh/Core/Mesh/BaseKernel.hh:95
#40xb7f4ce46inArrayKernel(this=0xbfc566a8)at/home/allen/study/OpenMesh/src/OpenMesh/Core/Mesh/ArrayKernel.cc:49
#50x0805854finPolyConnectivity(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/PolyConnectivity.hh:164
#60x0805856dinTriConnectivity(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/TriConnectivity.hh:55
#70x08061720inAttribKernelT(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/AttribKernelT.hh:124
#80x08061c21inPolyMeshT(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/PolyMeshT.hh:181
#90x08061c3finTriMeshT(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/TriMeshT.hh:164
#100x08061c5dinTriMesh_ArrayKernelT(this=0xbfc566a8)at../../../../src/OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh:93
#110x080503fainmain(argc=1,argv=0xbfc56934)atsmooth.cc:50
TODO
1.关于动态添加属性,究竟是如何实现的
template<classT>
typenameVPropHandleT<T>::reference
property(VPropHandleT<T>_ph,VertexHandle_vh){
returnvprops_.property(_ph)[_vh.idx()];
}
vprops_是PropertyContainer类型的
mesh.property(cogs,v_it)+=mesh.point(vv_it);
调用property(cogs,v_it)->调用vprops_.property(cogs)[v_it.idx()]
template<classT>PropertyT<T>&property(BasePropHandleT<T>_h)
{
assert(_h.idx()>=0&&_h.idx()<(int)properties_.size());
assert(properties_[_h.idx()]!=NULL);
#ifdefOM_FORCE_STATIC_CAST
return*static_cast<PropertyT<T>*>(properties_[_h.idx()]);
#else
PropertyT<T>*p=dynamic_cast<PropertyT<T>*>(properties_[_h.idx()]);
assert(p!=NULL);
return*p;
#endif
}
大概是mesh根据cogs找到它的属性数组,然后利用v_it的顶点索引,找到具体的值,
不过太复杂了,有时间再弄清细节吧。
2.用array的话,如何能够在拓扑变化的情况下,如点的删除,保证高效率的。
3.简化和细分模块是如何架构的。
相关文章推荐
- 29个你必须知道的Linux命令
- elicpse之tomcat配置
- 新建tomcat的server服务,在左侧项目浏览处,右键空白的地方,选择new,再选择other选项
- VS2010下配置Openmesh+openGL29
- linux下简易socket编程
- Linux下软件常见安装方式
- 如何更改linux文件的拥有者及用户组(chown和chgrp)--- chown root:root testfile // 使用 chown 一次性修改拥有者及组
- Nginx和LVS概述
- linux 部署多个tomcat
- Info.plist Utility Error: “Info.plist couldn't be opened because there is no such file”
- 【转】Apache 关于 mod_rewrite 遇到 %2F或%5C (正反斜杠)等特殊符号导致URL重写失效出现404的问题
- nginx之基础命令(压缩、自动列目录、浏览器本地缓存)
- apache 安装
- 第二天半:VMware和centos的安装 (补昨天)
- php和bom头的冤仇 和 如何在linux下使用命令去掉bom头
- Linux系统中的切换用户命令宝典
- Nginx+Lua+GraphicsMagick实现动态生成指定尺寸的图片
- 常用的也是最容易忘记的Shell知识
- 在linux上格式化U 盘
- Odoo(Openerp)中隐藏button按钮,根据组隐藏