Description of HMesh
The half-edge data structure modelized by HMesh is composed of a collection of faces, a collection of half-edges and a collection of vertices.
A face is modelized by the Java interface HFace
An half-edge is modelized by the Java interface HEdge
A vertex is modelized by the Java interface HVertex
Streams on each collection are provided by HMesh:
HMesh mesh = ...
// Get streams over the collections of faces, half-edges and vertices
Stream<HFace> faces = mesh.faces();
Stream<HEdge> edges = mesh.edges();
Stream<HFace> vertices = mesh.vertices();
A HFace consists of a cycle of HEdge forming a polygon boundary. Each HEdge connects two HVertex
HFace provides getters on its HEdge and on its HVertex:
HFace face = ...
// Get the sequence of half-edges forming the face / polygon's boundary
Sequence<HEdge> edges = face.edges();
// Get the sequence of vertices on the face / polygon's boundary
Sequence<HVertice> vertices = face.vertices();
HFace also provides a getter on its adjacent neighbors:
HFace face = ...
// Get the sequence of adjacent faces
Sequence<HFace> neighbors = face.neighbors();
An HEdge modelizes an oriented link between 2 HVertex. It is an element of a cycle forming the boundary of a polygon. It always has a twin / opposite half-edge
Various getters are provided by HEdge:
HEdge edge = ...
// Get the face to which the half-edge belongs
HFace face = edge.face();
// Get the vertex the edge points at
HVertex head = edge.head();
// Get the vertex the edge starts from
HVertex tail = edge.tail();
// Get the next edge on the edge's cycle
HEdge next = edge.next();
// Get the previous edge on the edge's cycle
HEdge previous = edge.previous();
// Get the opposite / twin half-edge
HEdge opposite = edge.opposite();
// Get the cycle the edge is part of
Sequence<HEdge> cycle = edge.cycle();
// Get all edges going out of the edge's head
Sequence<HEdge> outgoingEdges = edge.outgoingEdges()
// Get all edges starting from the edge's tail
Sequence<HEdge> incomingEdges = edge.incomingEdges()
An HVertex modelizes a vertex. A HVertex is both the tail of several HEdge and the head of several others HEdge
HVertex vertex = ...
// Get one of the half-edge pointing at the vertex
HEdge edge = vertex.edge();
// Get all half-edges going out of the vertex
Sequence<HEdge> outgoingEdges = vertex.outgoingEdges()
// Get all half-edges pointing at the vertex
Sequence<HEdge> incomingEdges = vertex.incomingEdges()
// Get all vertices neighbors of the vertex (in connection via a half-edge)
Sequence<HVertex> neighbors = vertex.neighbors();
Some of the getters of HFace, HEdge and HVertex are returning a Sequence. A Sequence is a kind of simplified stream providing several basic streaming operations:
HVertex vertex = ...
HEdge edge = ...
// Collect all vertex neighbors whose degree is 5 into a list
List<HVertex> neighbors = vertex.neighbors().
filter(v -> v.degree() == 5).toList();
// Iterate on the vertices of a cycle
for (HVertex vertex : edge.cycle().map(HEdge::head)) {
...
}
// Tell if a vertex is a neighbor of a half-edge's head
boolean isNeighbor = edge.outgoingEdges().anyMatch(e -> e.head() == vertex);
Topological operations on HMesh
Several topological operations are provided by HMesh:
- Splitting a face into two parts
HMesh mesh = ...
HFace face = ...
HVertex vertex1 = ...
HVertex vertex2 = ...
// Split a face along the line formed by 2 of its vertices
Optional<HFace> newFace = mesh.splitFace(face, vertex1, vertex2);
- Merging two faces
HMesh mesh = ...
HFace face1 = ...
HFace face2 = ...
// Merge 2 adjacent faces
boolean success = mesh.mergeFaces(face1, face2);
- Splitting an edge by inserting a new vertex
HMesh mesh = ...
HEdge edge = ...
// Split a half-edge (and its opposite) and return the newly vertex
HVertex vertex = mesh.splitEdge(edge);
- Collapsing an edge
HMesh mesh = ...
HEdge edge = ...
// Collapse a half-edge (and its opposite) by merging its head and its tail
boolean success = mesh.collapseEdge(edge);
- Removing a vertex
HMesh mesh = ...
HVertex vertex = ...
// Remove a vertex
boolean success = mesh.removeVertex(vertex);
Data association with a HMesh
Faces, half-edges and vertices of a HMesh can be associated with data. HMesh provides several methods to do that
For instance, to associate a double value to each of the vertices of a HMesh:
HMesh mesh = ...
// Create a collection of double values associated with the mesh's vertices
HDData<HVertex> vertexDoubleValues = mesh.createVertexDoubleData();
// Associate a value to a vertex
HVertex vertex = ...
vertexDoubleValues.set(vertex, 2.3);
// Get the value associated to a vertex
double value = vertexDoubleValues.get(vertex);
// set all double values associated with the mesh's vertices using a function
// to compute the values
vertexDoubleValues.setAll(v -> {
...
});
Or to associate boolean values to the collection of edges:
// Create a set of boolean values associated with the mesh's half-edges
HBData<HEdge> edgeFlags = mesh.createEdgeBooleanData();
Or to associate Java objects to the collection of faces:
// Create a set of data associated with the mesh's faces
HData<HFace, Color> faceColors = mesh.createFaceData();
These sets of data (HData for Java objects, HDData for double values, HIData for integer values, HBData for boolean values) are synchronized with their associated mesh and are updated whenever a topological change occurs. For instance, if a vertex is removed from the mesh, all values attached to this vertex will automatically be removed from all sets of data
Consistency of HMesh
An HMesh is always consistent during its lifetime whatever operations performed on it:
- HMesh never contains orphan HVertex or HEdge: an HEdge is always connecting 2 HVertex. A HVertex is always the origin and the end of several HEdge
- An HEdge is always associated with an opposite/twin HEdge. The relationship is always symmetric : edge.opposite().opposite() == edge
- An HEdge is always part of one and only one polygonal cycle
- All HEdge of a polygonal cycle are always distinct
- No collapsed faces: each HFace always contains a cycle of at least 3 half-edges