MyMesh::FPropHandleT<
int>), the data types of the standard properties are defined by so-called mesh traits. With traits we can customize and extend the mesh data structure. We can do this by changing three important features
OpenMesh::Attributes
.
struct MyTraits : OpenMesh::DefaultTraits
MyMesh::Point
, MyMesh::Normal
, MyMesh::Color
, and MyMesh::TexCoord
. We can use the provided vector class or we use a different one from another library. Here we simply replace the default type OpenMesh::Vec3f
(defined in the OpenMesh::DefaultTraits)
for positions and normals with OpenMesh::Vec3d
typedef OpenMesh::Vec3d Point; typedef OpenMesh::Vec3d Normal;
double
in this case. Otherwise we have to casts quite a lot depending on the implementation of the vector class.)
The second feature are attributes. Using attributes allows us to do two things
VertexAttributes ( OpenMesh::Attributes::Normal ); FaceAttributes ( OpenMesh::Attributes::Normal );
Actually the struct OpenMesh::DefaultTraits
is merely empty. It solely defines the types for Point
, Normal
, TexCoord
, and Color
and one attribute, that we used implicitly all the time:
// HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
PrevHalfedge
is different, as it does not control a property. Yet it has a great impact on the resulting mesh type, as it adds additional information to the halfedge structure. The impact is twofold:
// HalfedgeAttributes( OpenMesh::Attributes::None );
The complete source looks like this:
#include <iostream> #include <typeinfo> // -------------------- #include <OpenMesh/Core/IO/MeshIO.hh> #include <OpenMesh/Core/Mesh/Types/TriMesh_ArrayKernelT.hh> #include <OpenMesh/Core/Math/VectorT.hh> #ifndef DOXY_IGNORE_THIS // Define my personal traits struct MyTraits : OpenMesh::DefaultTraits { // let Point and Normal be a vector made from doubles typedef OpenMesh::Vec3d Point; typedef OpenMesh::Vec3d Normal; // add normal property to vertices and faces VertexAttributes ( OpenMesh::Attributes::Normal ); FaceAttributes ( OpenMesh::Attributes::Normal ); // Already defined in OpenMesh::DefaultTraits // HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); // Uncomment next line to disable attribute PrevHalfedge // HalfedgeAttributes( OpenMesh::Attributes::None ); // // or // // HalfedgeAttributes( 0 ); }; #endif // Define my mesh with the new traits! typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> MyMesh; // ------------------------------------------------------------------ main ---- int main(int argc, char **argv) { MyMesh mesh; if (argc!=2) { std::cerr << "Usage: attributes <input>\n"; return 1; } // just make sure that 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; } if ( typeid( OpenMesh::vector_traits<MyMesh::Normal>::value_type ) != typeid(double) ) { std::cerr << "Ouch! ERROR! Data type is wrong!\n"; return 1; } // load a mesh OpenMesh::IO::Options opt; if ( ! OpenMesh::IO::read_mesh(mesh,argv[1], opt)) { std::cerr << "Error loading mesh from file " << argv[1] << std::endl; return 1; } // If the file did not provide vertex normals, then calculate them if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) && mesh.has_face_normals() && mesh.has_vertex_normals() ) { // let the mesh update the normals mesh.update_normals(); } // move all vertices 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; }