This section provides a hands-on tutorial on the basic usage of the pmp-library. For a thorough introduction into polygon mesh processing we refer to the book of Botsch et al. [2].

Introduction

In general, a polygonal surface mesh is composed of vertices, edges and faces as well as the incidence relationships between them. pmp::SurfaceMesh stores the connectivity information based on halfedges, i.e., pairs of directed edges with opposing direction. To be more precise:

Each vertex stores an outgoing halfedge.

Each face stores an incident halfedge.

Each halfedge stores its incident face, its target vertex, and its previous and next halfedges within the face.

The halfedge connectivity is illustrated in the figure below:

Halfedge connectivity.

In the following sections we describe the basic usage of pmp::SurfaceMesh by means of simple example programs and code excerpts.

Basics

The very basic usage of pmp::SurfaceMesh is demonstrated in the example below. The program first instantiates a pmp::SurfaceMesh object as well as four vertex handles. These handles, as well as the handles for the other mesh entities Halfedge, Edge and Face basically indices. Four vertices are added to the mesh, as well as four triangular faces composing a tetrahedron. Finally, the number of vertices, edges, and faces is printed to standard output.

Dynamic Properties

Attaching additional attributes to mesh entities is important for many applications. pmp::SurfaceMesh supports properties by means of synchronized arrays that can be (de-)allocated dynamically at run-time. Property arrays are also used internally, e.g., to store vertex coordinates. The example program below shows how to access vertex coordinates through the (pre-defined) point property.

In addition to the per-entity properties described above it is also possible to attach global per-object properties to a mesh. This can be used, e.g., for storing minimum or maximum values of a scalar field or for storing a set of region markers present in the mesh:

auto markers = mesh.object_property<std::vector<int>>("o:regions");

markers[0].push_back(0);

markers[0].push_back(1);

Note in the above that access to the object property simply uses a zero index since there is no concept of an object handle.

Connectivity Queries

Commonly used connectivity queries such as retrieving the next halfedge or the target vertex of an halfedge are illustrated below.

Halfedge h;

auto h0 = mesh.next_halfedge(h);

auto h1 = mesh.prev_halfedge(h);

auto h2 = mesh.opposite_halfedge(h);

auto f = mesh.face(h);

auto v0 = mesh.from_vertex(h);

auto v1 = mesh.to_vertex(h);

Connectivity queries

Topological Operations

pmp::SurfaceMesh also offers higher-level topological operations, such as performing edge flips, edge splits, face splits, or halfedge collapses. The figure below illustrates some of these operations.

High-level operations changing the topology.

The corresponding member functions and their syntax is demonstrated in the pseudo-code below.

Vertex v;

Edge e;

Halfedge h;

Face f;

mesh.split(f, v);

mesh.split(e, v);

mesh.flip(e);

mesh.collapse(h);

When entities are removed from the mesh due to topological changes, the member function pmp::SurfaceMesh::garbage_collection() has to be called in order to ensure the consistency of the data structure.

File I/O

We currently support reading and writing several standard (and not so standard) file formats: OFF, OBJ, STL, PLY, PMP, XYZ, AGI. See the reference documentation for the pmp::SurfaceMesh::read() and pmp::SurfaceMesh::write() functions for details on which format supports reading / writing which type of data.