OpenMesh
|
The mesh provides linear iterators (that enumerate vertices, halfedges, edges, and faces). These can be used to easily navigate through a mesh. Each iterator XYZIter
also exists in a const version ConstXYZIter
.
All iterators are defined in the namespace OpenMesh::Iterators. They are template classes that expect a mesh as template argument to be fully specified. You should use the iterator types provided by the mesh itself, i.e. MyMesh::VertexIter
instead of OpenMesh::Iterators::VertexIterT<MyMesh>
.
The iterators are:
The corresponding const
counterparts are
ConstVertexIter
, ConstHalfedgeIter
, ConstEdgeIter
, ConstFaceIter
.The linear iterators are conformant to STL iterators. For a description of their interface see OpenMesh::Concepts::IteratorT.
When using iterators, use the pre-increment operation (++it) for efficiency reasons.
handle()
to get the handle of the item referred to by the iterator, this function is deprecated. Simply dereference the iterator instead.If no elements of a mesh are marked as deleted, the indices provided by idx()
are consecutive numbers from 0 to number of elements-1 (in the case of vertices this would be from 0 to n_vertices()-1).
However, note that this is not the case when elements are marked as deleted and OpenMesh::ArrayKernel::garbage_collection() has not yet been called.
After garbage_collection() has been called the elements are reorganized and their handles and iterators are guaranteed to be consecutive numbers again.
OpenMesh uses a lazy deletion scheme to avoid unnecessary updates to the data structure. The halfedge data structure will always be updated directly to ensure that following algorithms will have the correct iterator setups.
So if you delete a face, The face itself will still exist but the halfedges which are now located at the hole will be updated directly, which means that circulators on the adjacent vertices will not come across the face anymore.
If an edge is deleted, the adjacent faces will be removed as well (flagging them deleted and updating the surrounding halfedges). The edge itself will also be flagged as deleted. Again the circulators will not see the deleted primitives anymore.
For a vertex, all adjacent faces and edges are deleted with the schemes above and the vertex flagged as deleted.
The iterators, going across vertices edges and faces will still enumerate all primitives (including deleted ones). Except if you use the skipping iterators, which will skip deleted primitives. The circulators always only enumerate primitives which are not deleted.
This example shows how to iterate over all faces of a mesh:
All iterators are also available as skipping iterators. If elements are deleted on a mesh, the standard iterators go over all elements, even deleted ones(which are available until a garbage_collection is done). The skipping iterators ignore these elements. You can retrieve a skipping iterator by calling one of the following functions:
vertices_sbegin()
, edges_sbegin()
, halfedges_sbegin()
, faces_sbegin()
The ends for these iterators are equal to the standard iterator ends (e.g. vertices_end()
).
OpenMesh also provides so called Circulators that provide means to enumerate items adjacent to another item of the same or another type. For example, a VertexVertexIter
allows to enumerate all vertices immediately adjacent to a (center) vertex (i.e. it allows to enumerate the so-called 1-ring of the center vertex). Analogously, a FaceHalfedgeIter
enumerates all the halfedges belonging to a face. In general, CenterItem_AuxiliaryInformation_TargetItem_Iter
designates a circulator that enumerates all the target items around a given center item.
The constructor of a circulator is of the form Circulator(MeshType mesh, TargetHandle center_handle)
, i.e. it takes a mesh and the handle of the item to circulate around.
The circulators around a vertex are:
VertexVertexIter:
iterate over all neighboring vertices. VertexIHalfedgeIter:
iterate over all incoming halfedges. VertexOHalfedgeIter:
iterate over all outgoing halfedges. VertexEdgeIter:
iterate over all incident edges. VertexFaceIter:
iterate over all adjacent faces.The circulators around a face are:
FaceVertexIter:
iterate over the face's vertices. FaceHalfedgeIter:
iterate over the face's halfedges. FaceEdgeIter:
iterate over the face's edges. FaceFaceIter:
iterate over all edge-neighboring faces.The circulators around an edge are:
EdgeVertexIter:
iterate over the edge's incident vertices. EdgeHalfedgeIter:
iterate over the edge's halfedges. EdgeFaceIter:
iterate over the edge's incident faces.Other circulators:
HalfedgeLoopIter:
iterate over a sequence of Halfedges. (all Halfedges over a face or a hole)All circulators provide the operations listed in CirculatorT<Mesh>, which are basically the same as the iterator funtions.
operator
bool()
, which returns true, as long as the circulator hasn't reached the end of the sequence, this function is deprecated. Use the function is_valid()
instead.OpenMesh provides the following functions (defined in OpenMesh::PolyConnectivity) to get circulators around a specified center item:
Additionally to the normal circulators there exists some for each direction (clock-wise, counterclock-wise). Those circulators might be slower than the normal one, but the direction of circulation is guaranteed. You can get these types of circulators by adding the infix "ccw" or "cw" to the function used to request the circulator of an item after the underscore. Example:
It is also possible to convert a cw circulator to a ccw circulator and vice versa. For this purpose, each circulator provides a constructor taking the other circulator as input. If a cw circulator is converted, the ccw circulator points on the same element as the cw circulator pointed on, but the direction for the increment and decrement changed.
The conversion is only valid for valid circulators. The resulting circulator from a invalid circulator is still invalid, but might behave in a fashion not expected by normal iterators. Example:
CW and CCW circulators requires that OpenMesh::Attributes::PrevHalfedge is available.
The following code example now shows how to enumerate the 1-ring of each vertex:
Enumerating all halfedges adjacent to a certain face (the inner halfedges) is accomplished as follows: