Half-edge data structure
computational geometry
3D modeling
mesh initialization
data structures

Initializing Half-edge data structure from vertices

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

You cannot build a useful half-edge data structure from vertices alone. A half-edge mesh is a topological structure, so it needs connectivity information such as faces or indexed polygons in addition to the vertex coordinates. Vertices tell you where points are; faces tell you which points are connected and in what order.

What the Half-Edge Structure Needs

A typical half-edge representation stores relationships among four kinds of objects:

  • vertices
  • half-edges
  • faces
  • twin relationships between opposite half-edges

That means the real input to construction is usually:

  • a list of vertex positions
  • a list of faces, where each face is an ordered list of vertex indices

Example input for a single quad split into two triangles:

python
1vertices = [
2    (0.0, 0.0, 0.0),
3    (1.0, 0.0, 0.0),
4    (1.0, 1.0, 0.0),
5    (0.0, 1.0, 0.0),
6]
7
8faces = [
9    [0, 1, 2],
10    [0, 2, 3],
11]

Without the faces list, there is no way to know which edges should exist.

A Minimal Construction Strategy

The usual construction algorithm is:

  1. create vertex objects
  2. loop through each face
  3. create one half-edge per directed face edge
  4. connect each half-edge to its next half-edge within the face
  5. map directed edge pairs so twins can be found later
  6. assign an outgoing half-edge to each vertex

A small Python sketch makes the idea concrete:

python
1class Vertex:
2    def __init__(self, position):
3        self.position = position
4        self.halfedge = None
5
6
7class HalfEdge:
8    def __init__(self):
9        self.origin = None
10        self.next = None
11        self.twin = None
12        self.face = None
13
14
15class Face:
16    def __init__(self):
17        self.halfedge = None

This is not yet the full builder, but it shows the core references each object usually needs.

Building Face Loops

For each face, create the half-edges in cyclic order.

python
1def build_face(vertices, face_indices):
2    face = Face()
3    edges = [HalfEdge() for _ in face_indices]
4
5    for i, edge in enumerate(edges):
6        edge.origin = vertices[face_indices[i]]
7        edge.next = edges[(i + 1) % len(edges)]
8        edge.face = face
9        if edge.origin.halfedge is None:
10            edge.origin.halfedge = edge
11
12    face.halfedge = edges[0]
13    return face, edges

This step builds the directed cycle around each polygon.

Assigning Twins

Twin links are found by matching opposite directed edges. A common pattern is to keep a dictionary keyed by (start, end) index pairs.

python
1def assign_twins(all_face_edges, face_index_lists):
2    edge_map = {}
3
4    for edges, indices in zip(all_face_edges, face_index_lists):
5        for i, edge in enumerate(edges):
6            start_idx = indices[i]
7            end_idx = indices[(i + 1) % len(indices)]
8            edge_map[(start_idx, end_idx)] = edge
9
10    for (start_idx, end_idx), edge in list(edge_map.items()):
11        twin = edge_map.get((end_idx, start_idx))
12        if twin is not None:
13            edge.twin = twin

This is the key step that turns disconnected face loops into a navigable mesh topology.

Why Vertices Alone Are Not Enough

If all you have is a cloud of points, you first need a separate reconstruction or triangulation step. The half-edge structure is not responsible for guessing topology from geometry.

For example, points lying on a plane could represent:

  • one polygon
  • several polygons
  • a triangulated mesh
  • a point cloud with no faces at all

The half-edge builder cannot infer which one you intended.

Practical Input Assumptions

Half-edge construction is easiest when the mesh input is already well-formed.

Helpful assumptions include:

  • consistent face winding
  • no duplicated directed edges within the same manifold surface
  • valid vertex indices
  • clear boundary behavior for edges without twins

If those assumptions are violated, construction becomes a mesh-cleaning problem rather than a simple initialization problem.

Common Pitfalls

  • Trying to build a half-edge mesh from vertices only, without faces or edge connectivity.
  • Ignoring face winding, which can make twin assignment inconsistent.
  • Forgetting to assign boundary edges that have no twin in an open mesh.
  • Using unordered face vertex lists, which destroys the cyclic topology needed for next pointers.
  • Treating mesh reconstruction from points as the same problem as half-edge initialization.

Summary

  • A half-edge data structure cannot be initialized from vertex positions alone.
  • You also need connectivity information, usually in the form of ordered face index lists.
  • Construction typically creates face loops first and twin links second.
  • A dictionary of directed edges is a common way to assign twins efficiently.
  • If you only have a point cloud, topology reconstruction must happen before half-edge initialization.

Course illustration
Course illustration

All Rights Reserved.