MyMesh
. As we have seen in the section on goals and features there are some parameters to be specified for a mesh. This is done in the following four steps:
Scalar
, Point
, Normal
and Color
, and use predefined attributes like Attributes::Normal
and Attributes::Color
.
We will explain these four parameterization steps and give a code example at the end of this page.
The default kernel is ArrayKernelT
. Which is good for most situations. But depending on the application a different kernel would be better. E.g. the OpenSG integration has been realized be replacing the kernel by a custom kernel, since OpenSG provides already array like properties, which could be reused for the intergration. In case of a an OpenSG environment one might be better off using OSG_Kernel::ArrayKernelT
.
The resulting mesh MyMesh
will provide the following types:
MyMesh::Point
and MyMesh::Scalar
. MyMesh::Vertex
, MyMesh::Halfedge
, MyMesh::Edge
, MyMesh::Face
. MyMesh::VertexHandle
, MyMesh::HalfedgeHandle
, MyMesh::EdgeHandle
, MyMesh::FaceHandle
. While the handle types are fixed, the other types can be customized. Each mesh type (see Predefined Mesh Types) can be parameterized by a so-called traits class. Using this mechanism one can
MyMesh::Point
and the resulting scalar type MyMesh::Scalar
== MyMesh::Point::value_type
, MyMesh::Normal
MyMesh::Color
All these customizations are encapsulated in one class MyTraits
, that is used as template argument to the mesh, e.g.
struct MyTraits { // your customization }; typedef PolyMesh_ArrayKernelT<MyTraits> MyMesh;
The rest of this section explains the construction of this traits class, its application to the mesh will be the topic of the next section.
For each mesh entity one can control the predefined attributes to be attached by a traits class using some convenience macros, e.g. OpenMesh::VertexAttributes
and OpenMesh::VertexTraits
for vertices. The default traits class looks like this:
struct DefaultTraits { typedef Vec3f Point; typedef Vec3f Normal; typedef Vec2f TexCoord; typedef Vec3uc Color; VertexTraits {}; HalfedgeTraits {}; EdgeTraits {}; FaceTraits {}; VertexAttributes(0); HalfedgeAttributes(Attributes::PrevHalfedge); EdgeAttributes(0); FaceAttributes(0); };
Please note that for example VertexTraits
is a define concealing a template declaration. The actual template class name is VertexT
, which is further simplified to a specific type Vertex
at a later stage during the construction of the mesh kernel.
Because the traits classes always have to provide the template classes VertexT
, HalfedgeT
, EdgeT
, FaceT
, and the types Point
, Normal
, Color
, and TexCoord
one should derive this class from the default implementation DefaultTraits
. In this case you will only have to define the classes or types you want to override or substitute.
double
instead of float
.
struct MyTraits : public OpenMesh::DefaultTraits { typedef OpenMesh::Vec3d Point; // use double-values points };
Using the OpenMesh::VectorT class you can easily plug in any scalar type for the use in point coordinates, e.g. some exact arithmetic. You can also exchange the whole class representing points as long as it provides the same interface as the OpenMesh::VectorT class.
Adding these predefined attributes is quite simple. You provide an unsigned int
in the traits class, whose bits control whether or not a certain attribute should be attached or not.
If you want to add a normal vector to your vertices and faces, and also want to have color information for vertices, the code would look like this:
struct MyTraits : public OpenMesh::DefaultTraits { VertexAttributes( OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color ); FaceAttributes( OpenMesh::Attributes::Normal ); };
Internally each mesh item contains an enum
defining the integer Attributes
(containing the bits of used attributes OR'ed together). From its set/unset bits you can see whether a certain attribute is used. OpenMesh provides the macro OM_Check_Attrib for doing this:
if (OM_Check_Attrib(MyMesh::Vertex, Normal)
do_something_with_normals();
These run-time checks may not be sufficient in some cases. You can also check for attributes at compile-time and instantiate the correct functions by using function overloading. The class GenProg::Bool2Type
maps true/false information to two different types, Bool2Type<true>
and Bool2Type<false>
. An example that draws OpenGL normals if they are available would look like this:
#include <OpenMesh/Core/Utils/GenProg.hh> // draw a face normal if we have one void drawFaceNormal(const MyMesh::Face& _f) { drawFaceNormal(_f, GenProg::Bool2Type<OM_Check_Attrib(MyMesh::Face, Normal)>()); } // normal exists -> use it void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type<true>) { glNormal3fv(_f.normal()); } // empty dummy (no normals) void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type<false>){}
Especially the compile-time checking for attributes is extremely useful because it does not generate any unnecessary code and does not perform expensive tests at run-time.
Vertex
class is easily done by
struct MyTraits : public OpenMesh::DefaultTraits { VertexTraits { int some_additional_index; }; };
The macro VertexTraits
hides some ugly template stuff. In fact, it is defined as
#define VertexTraits template <class Base, class Refs> struct VertexT : public Base
hence the traits class actually looks like this:
struct MyTraits : public OpenMesh::DefaultTraits { template <class Base, class Refs> struct VertexT : public Base { int some_additional_index; }; };
You have to keep this in mind when you want to define constructors for your vertex type or when you want to derive the vertex type from other classes.
The template argument Base
provides access to the mesh handles and to the Point
and Scalar
type by its member class Refs
. Adding a MyMesh::FaceHandle
to the vertex class can therefore be implemented like this:
struct MyTraits : public OpenMesh::DefaultTraits { VertexTraits { int some_additional_index; typename Base::Refs::FaceHandle my_face_handle; }; };
Adding elements to other mesh items works in the same manner.
An example for an algorithm as well as the application using traits is given in Using mesh traits and attributes.
An example for an algorithm as well as the application using properties is given in Using (custom) properites and Using STL algorithms.
ArrayKernelT
. Faces that are not triangles will automatically be tesselated into triangles. Because we only display meshes and do not dynamically add or remove items, we can just use the ArrayKernelT
.
All mesh-kernel combinations are predefined in the directory OpenMesh/Mesh/Types
. Refer to Predefined Mesh Types for a complete list of them. For our example we use the TriMesh_ArrayKernelT
and parameterize it by our MyTraits
class.
We will need face and vertex normals and e.g. for color coding vertex curvature, i.e. vertex color.
#include <OpenMesh/Core/Mesh/Types/TriMesh_ArrayKernelT.hh> // define traits struct MyTraits : public OpenMesh::DefaultTraits { // use double valued coordinates typedef OpenMesh::Vec3d Point; // use vertex normals and vertex colors VertexAttributes( OpenMesh::DefaultAttributer::Normal | OpenMesh::DefaultAttributer::Color ); // store the previous halfedge HalfedgeAttributes( OpenMesh::DefaultAttributer::PrevHalfedge ); // use face normals FaceAttributes( OpenMesh::DefaultAttributer::Normal ); // store a face handle for each vertex VertexTraits { typename Base::Refs::FaceHandle my_face_handle; }; }; // Select mesh type (TriMesh) and kernel (ArrayKernel) // and define my personal mesh type (MyMesh) typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> MyMesh; int main(int argc, char **argv) { MyMesh mesh; // -------------------- Add dynamic data // for each vertex an extra double value OpenMesh::VPropHandleT< double > vprop_double; mesh.add_property( vprop_double ); // for the mesh an extra string OpenMesh::MPropHandleT< string > mprop_string; mesh.add_property( mprop_string ); // -------------------- do something ...; }
That's it.