Developer Documentation
Specifying your MyMesh

This section will show how to build your own custom tailored type 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:

  1. Choose between triangle mesh and general polygonal mesh.

  2. Select the mesh kernel

  3. Parameterize the mesh by a so-called Traits class. You can add arbitrary classes to the mesh items, specify the types Scalar, Point, Normal and Color, and use predefined attributes like Attributes::Normal and Attributes::Color.

  4. Dynamically bind data to the mesh or the mesh entities (vertex, (half-)edge, face) using custom properties.

We will explain these four parameterization steps and give a code example at the end of this page.



Polygonal or Triangle Mesh?

This decision is quite simple: Whenever possible choose the triangle mesh. The restriction to triangular faces usually leads to more efficient algorithms (e.g. rendering triangles is much faster than rendering arbitrary polygons). Additionally some algorithms are only implemented for triangle meshes while triangle meshes inherit the full functionality of polygonal meshes. For a list of them refer to the following links.

See also
OpenMesh::PolyMeshT
OpenMesh::TriMeshT



Choosing the right kernel

The mesh kernel specifies how the mesh entities (vertices, (half-)edges, faces) are internally stored. In fact the entities are kept in so-called properties. A property itself provides an array like interface. The kernel defines the corresponding handle types, i.e. the way items reference each other. Since the properties have an array like interface the handles are represented internally as indices.

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.

See also
Mesh Kernels



Mesh Traits

While the last two sections only have chosen from a list of predefined meshes or kernels, respectively, we now come to the user-defined customization.

The resulting mesh MyMesh will provide the following types:

  • The point and scalar type: MyMesh::Point and MyMesh::Scalar.
  • The mesh items: MyMesh::Vertex, MyMesh::Halfedge, MyMesh::Edge, MyMesh::Face.
  • The handle types: 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

  1. change the coordinate type MyMesh::Point and the resulting scalar type MyMesh::Scalar == MyMesh::Point::value_type,
  2. change the normal type MyMesh::Normal
  3. change the color type MyMesh::Color
  4. use predefined attributes like normal vector, color, texture coordinates, ... for the mesh items.
  5. add arbitrary classes to the mesh items.

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:

{
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.


Changing the Point type

Changing the type that is used to store the point coordinates as well as the normal vectors can simply be done by defining this type in the traits class. The following code changes the coordinate type in order to use double instead of float.

{
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 Predefined Attributes

There are some pre-defined attributes that can be appended to the mesh items. These global attributes are defined in the namespace OpenMesh::Attributes. The advantage of these attributes is that they are registered at the items they are added to. Therefore algorithms can check for these attributes at run-time as well as at compile-time. This is important if you want to implement algorithms acting on different meshes, that may or may not have e.g. normal vectors per vertex/face.

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:

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.

See also
OpenMesh::DefaultTraits
OpenMesh::Attributes
OpenMesh::GenProg


Adding User-Defined Elements

You can also add arbitrary types/elements/methods to the mesh items by providing a corresponding traits class for these items. Adding some index to the Vertex class is easily done by

{
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:

{
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:

{
VertexTraits
{
int some_additional_index;
typename Base::Refs::FaceHandle my_face_handle;
};
};

Adding elements to other mesh items works in the same manner.


Using traits defined by algorithms

From version 0.10.3 on algorithms can define traits/attributes they require and the user can merge these traits into his own traits. A more elegant way is to use dynamic properites, which can be added/removed during runtime by the algorithm. This is the preferred way to attach custom data to the mesh.

An example for an algorithm as well as the application using traits is given in Using mesh attributes and traits.



Dynamic Properties

From version 1.0 on OpenMesh provides dynamic properties. Instead of using traits to bind data at compile time algorithms or the application can use dynamic properties. Similar to entities the properties are accessed and manipulated via handles.

An example for an algorithm as well as the application using properties is given in Using (custom) properties and Using STL algorithms.



Final Implementation Example

Consider an application where we just want to render triangle meshes. This means we will select the triangle mesh and the 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/TriMesh_ArrayKernelT.hh>
// define traits
{
// use double valued coordinates
typedef OpenMesh::Vec3d Point;
// use vertex normals and vertex colors
// store the previous halfedge
// use face normals
// 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)
int main(int argc, char **argv)
{
MyMesh mesh;
// -------------------- Add dynamic data
// for each vertex an extra double value
mesh.add_property( vprop_double );
// for the mesh an extra string
mesh.add_property( mprop_string );
// -------------------- do something
...;
}

That's it.