使用mesh屬性和特徵
本例中,我們將演示如何修改位置、法線、顏色、紋理座標等標準屬性的數據類型。前一節中,我們已經學習了通過調用合適的request方法使用標準屬性。與自定義屬性不同,用戶可以指定數據類型,並傳遞給句柄給mesh,而標準屬性中,數據類型通過所謂的特徵(traits)結構定義。通過特徵結構traits,我們可以自定義並擴展mesh的數據結構,實現這一目的,我們需要修改兩個重要的特性:
1.修改位置、法線、顏色及紋理座標的數據類型
2.擴展mesh實體的節點、表面、邊緣及半邊
開始吧。
每一個自定義特徵,都應該繼承自缺省特徵。
struct MyTraits: OpenMesh::DefaultTraits
正如前面提到的,我們可以把諸如MyMesh::Point, MyMesh::Normal, MyMesh::Color, 及 MyMesh::TexCoord等這些標準屬性的基本類型都改掉。改成OpenMesh提供的向量(vector)類,甚至用另外一個庫的其他類型都可以。這裏,我們簡單地將位置和法線的數據類型,從缺省的OpenMesh::Vec3f(在 OpenMesh::DefaultTraits中定義)類型修改爲OpenMesh::Vec3d類型。
typedef OpenMesh::Vec3dPoint;
typedef OpenMesh::Vec3dNormal;
(常規的,位置和法線最好是一樣的類型,否則,我們就不得不進行大量的,依賴於vector類的,類型轉換)
注意這些設置將覆蓋其traits父類中的對應元素!既然我們一般都從DefaultTraits類中派生我們自己的traits,那麼,現在就看看DefaultTraits是什麼樣:
實際上,OpenMesh::DefaultTraits僅僅是一個空的結構。它僅定義了位置、法線、紋理座標和顏色的類型,還有一個我們需要顯式調用的屬性。
//HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
PrevHalfedge 屬性有所不同,它不控制一個屬性,但他仍然對mesh數據有巨大影響,它在halfedge結構中添加額外的信息,但其對下列因素的影響是雙倍的:
1.快速訪問前一個半邊
2.增加內存開銷
使用這個特性,取決於我們的具體需求。一種情況是前一個半邊需要經常訪問的,如頻繁調用add_face()函數,使用這個屬性將使其執行時間將會顯著下降。但如果不是必要的,我們一般不用它,這樣可以降低內存開銷。
//HalfedgeAttributes( OpenMesh::Attributes::None );
Then we need 8bytes less per edge, which can be quite a lot as one can derive from the Eulerformula ( ), that for aregular triangle meshes with genus the number ofedges is approximatelythree times the number of vertices : .(譯者注:不太懂這段說什麼,不翻譯了)
完整代碼如下:
#include<iostream>
#include<typeinfo>
//--------------------
#include<OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include<OpenMesh/Core/Geometry/VectorT.hh>
#ifndefDOXY_IGNORE_THIS
// Define mypersonal traits
struct MyTraits: OpenMesh::DefaultTraits
{
// Let Point andNormal be a vector of doubles
typedef OpenMesh::Vec3dPoint;
typedef OpenMesh::Vec3dNormal;
// Alreadydefined in OpenMesh::DefaultTraits
//HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
// Uncomment nextline to disable attribute PrevHalfedge
//HalfedgeAttributes( OpenMesh::Attributes::None );
//
// or
//
//HalfedgeAttributes( 0 );
};
#endif
// Define my meshwith the new traits!
typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits>MyMesh;
//------------------------------------------------------------------ main ----
int main(int argc, char **argv)
{
MyMesh mesh;
if (argc!=2)
{
std::cerr <<"Usage:"<< argv[0] << " <input>\n";
return 1;
}
// Just make surethat point element type is double
if ( typeid( OpenMesh::vector_traits<MyMesh::Point>::value_type)
!= typeid(double) )
{
std::cerr <<"Ouch!ERROR! Data type is wrong!\n";
return 1;
}
// Make sure thatnormal element type is double
if ( typeid( OpenMesh::vector_traits<MyMesh::Normal>::value_type)
!= typeid(double) )
{
std::cerr <<"Ouch!ERROR! Data type is wrong!\n";
return 1;
}
// Add vertexnormals as default property (ref. previous tutorial)
mesh.request_vertex_normals();
// Add facenormals as default property
mesh.request_face_normals();
// load a mesh
if ( ! OpenMesh::IO::read_mesh(mesh,argv[1],opt))
{
std::cerr <<"Errorloading mesh from file " << argv[1] << std::endl;
return 1;
}
// If the filedid not provide vertex normals, then calculate them
if ( !opt.check( OpenMesh::IO::Options::VertexNormal) &&
mesh.has_face_normals()&& mesh.has_vertex_normals() )
{
// let the meshupdate the normals
mesh.update_normals();
}
// move allvertices one unit length along it's normal direction
for(MyMesh::VertexIter v_it = mesh.vertices_begin();
v_it !=mesh.vertices_end(); ++v_it)
{
std::cout <<"Vertex#"<< *v_it << ": " << mesh.point( *v_it );
mesh.set_point(*v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
std::cout <<" moved to"<< mesh.point( *v_it ) << std::endl;
}
return 0;
}