Skip to content

Local Mesh Operations

Minjae Lee edited this page Apr 20, 2018 · 1 revision

Many of the actions that need to be implemented in the MeshEdit mode are local mesh operations (like edge collapse, face bevel, etc.). Here we provide a step-by-step guide to implementing a simplified version of the EdgeFlip operation for a pair of triangles---the final version, however, must be implemented for general polygons (i.e., any n-gon). The basic strategy for implementing the other local operations is quite similar to the procedure outlined below. Note: if you're not familiar with C++, you should definitely take a moment to learn about the standard library class std::vector, especially the method push_back(), which will make it easy to accumulate a list of pointers as you walk around a polygon, vertex, etc.

A good recipe for ensuring that all pointers are still valid after a local remeshing operation is:

  1. Draw a picture of all the elements (vertices, edges, faces, halfedges) that will be needed from the original mesh, and all the elements that should appear in the modified mesh.
  2. Allocate any new elements that are needed in the modified mesh, but do not appear in the original mesh.
  3. For every element in the "modified" picture, set all of its pointers -- even if they didn't change. For instance, for each halfedge, make sure to set next, twin, vertex, edge, and face to the correct values in the new (modified) picture. For each vertex, make sure to set its halfedge pointer. Etc. A convenience method Halfedge::setNeighbors() has been created for this purpose.
  4. Deallocate any elements that are no longer used in the modified mesh, which can be done by calling HalfedgeMesh::deleteVertex(), HalfedgeMesh::deleteEdge(), etc.

The reason for setting all the pointers (and not just the ones that changed) is that it is very easy to miss a pointer, causing your code to crash. Once the code is working, you can remove these unnecessary assignments if you wish -- but remember that premature optimization is the root of all evil

Interface with global mesh operations

To facilitate user interaction, as well as global mesh processing operations (described below), local mesh operations should return the following values when possible. If the specified values are not available, you should think about a reasonable alternative value to return. First and foremost, the program should not crash! So for instance, you should not return a pointer to an element that was deleted. Second, you should try as much as possible to return a value related to the argument. For instance, if the user asks to flip an edge e that cannot be flipped (e.g., a boundary edge), the most natural solution would be to simply return e. Likewise, if the user asks to erase an edge e that cannot be erased, a natural return value might be an adjacent (non-boundary) face. Etc.

  • HalfedgeMesh::flipEdge - should return the edge that was flipped
  • HalfedgeMesh::splitEdge - should return the inserted vertex
  • HalfedgeMesh::collapseEdge - should return the new vertex, corresponding to the collapsed edge
  • HalfedgeMesh::collapseFace - should return the new vertex, corresponding to the collapsed face
  • HalfedgeMesh::eraseVertex - should return the new face, corresponding to the faces originally containing the vertex
  • HalfedgeMesh::eraseEdge - should return the new face, corresponding to the faces originally containing the edge
  • HalfedgeMesh::bevelVertex - should return the new face, corresponding to the beveled vertex
  • HalfedgeMesh::bevelEdge - should return the new face, corresponding to the beveled edge
  • HalfedgeMesh::bevelFace - should return the new, inset face