Initializing 3D Canvas...

Manifold Geometry

3 min read1 page

In 3D geometry, a mesh is "Manifold" if it resembles a physically realizable surface. Specifically, a watertight manifold means the surface has no holes, no self-intersections, and encloses a solid volume.

Edge Rule:

1. Every edge in the mesh must be shared by exactly two faces. 2. If an edge is shared by 1 face, it is a boundary edge (a hole). 3. If an edge is shared by 3 or more faces, it is non-manifold (impossible in real life).
python
1# Checking for Manifold Edges
2def check_watertight(mesh):
3 """A mesh is watertight if EVERY edge is shared by exactly 2 faces."""
4 edge_counts = {}
5
6 for face in mesh.faces:
7 # Get the 3 edges of the triangle
8 edges = get_edges_from_face(face)
9 for e in edges:
10 # Sort vertex indices to ensure consistency (e.g. edge(1,2) == edge(2,1))
11 sorted_edge = tuple(sorted(e))
12 if sorted_edge in edge_counts:
13 edge_counts[sorted_edge] += 1
14 else:
15 edge_counts[sorted_edge] = 1
16
17 # Check if any edge has 1 or >2 faces
18 for edge, count in edge_counts.items():
19 if count == 1:
20 return False, "Hole found!"
21 if count > 2:
22 return False, "Non-manifold geometry found!"
23
24 return True, "Mesh is Watertight"
Mesh State (Watertight/Hole/NonManifold)
0.00
1 min read1 page

To efficiently analyze and repair topology, 3D software doesn't just store a raw list of triangles. It builds a Connectivity Graph (often using the Half-Edge data structure) which links vertices, edges, and faces together, allowing instant traversal across the surface.

Half-Edge Structure:

1. Every physical edge is split into two "Half-Edges", one for each face. 2. A Half-Edge points counter-clockwise around its face. 3. A Half-Edge knows its twin (the Half-Edge on the adjacent face). 4. If a Half-Edge has no twin, it's a boundary (hole).
python
1# Topology as a Graph
2class HalfEdge:
3 def __init__(self, vertex, face):
4 self.vertex = vertex # Pointing to vertex
5 self.face = face # Belonging to face
6 self.next = None # Next HalfEdge in face
7 self.twin = None # Opposite HalfEdge in adjacent face
Highlight Face Graph
0.00
3 min read1 page

To build the connectivity graph, algorithms scan through every triangle and create directed "Half-Edges". By using a hash map where the key is the ordered pair of vertices (v0, v1), it can instantly check if the opposite edge (v1, v0) already exists.

Twin Mapping:

1. For each triangle, generate 3 directed half-edges. 2. Store half-edge A->B in a dictionary. 3. If the dictionary already contains B->A, link them as Twins. 4. If A->B is already in the dictionary, the mesh is Non-Manifold!
python
1# Mapping Edges to Find Twins
2def build_half_edges(faces):
3 """Creates the Half-Edge graph from a list of faces."""
4 edge_map = {}
5
6 for face in faces:
7 for i in range(3):
8 v0 = face[i]
9 v1 = face[(i+1)%3]
10
11 # The directed edge (v0 -> v1)
12 edge = HalfEdge(vertex=v1, face=face)
13
14 # Look for the opposite edge (v1 -> v0)
15 twin_key = (v1, v0)
16 if twin_key in edge_map:
17 # We found its twin!
18 twin = edge_map[twin_key]
19 edge.twin = twin
20 twin.twin = edge
21 else:
22 # Store this edge so its twin can find it later
23 edge_map[(v0, v1)] = edge
24
25 return edge_map
Animation Step
0.00
3 min read1 page

Once the Half-Edge graph is built, identifying holes in the mesh becomes trivial: any Half-Edge that does not have a twin is a "Naked Edge" lying on a boundary.

Loop Traversal:

1. Collect all Half-Edges where twin == None. 2. Pick a naked edge, and look at the vertex it points to. 3. Find the next naked edge that originates from that vertex. 4. Repeat until you return to the start, forming a continuous Boundary Loop.
python
1# Finding Boundary Loops
2def extract_boundary_loops(half_edges):
3 """Finds all closed loops of naked edges (holes)."""
4 loops = []
5 visited = set()
6
7 # 1. Find all naked edges (no twin)
8 naked_edges = [e for e in half_edges if e.twin is None]
9
10 for edge in naked_edges:
11 if edge in visited:
12 continue
13
14 # 2. Walk the loop
15 current = edge
16 loop = []
17
18 while current not in visited:
19 visited.add(current)
20 loop.append(current)
21
22 # To find the next naked edge in the loop, we find the next
23 # outgoing edge from current.vertex that is also naked.
24 # In a valid manifold, there is exactly 1 such edge.
25 next_naked = find_next_naked_edge(current.vertex, naked_edges)
26 current = next_naked
27
28 loops.append(loop)
29
30 return loops
Traversal Step
0.00
2 min read1 page

A mesh can pass the "Watertight Edge Rule" but still be non-manifold! If two distinct parts of a mesh touch only at a single vertex (like two pyramids meeting point-to-point), that vertex is Non-Manifold.

Vertex Rule:

1. Look at all the faces connected to a single vertex. 2. Those faces must form a single continuous "fan" or "disk". 3. If the faces form two or more disconnected groups that only meet at the vertex (the "Hourglass" or "Bowtie" configuration), the vertex is invalid.
python
1# Checking Vertex Manifoldness
2def is_vertex_manifold(vertex, connected_faces):
3 """A vertex is manifold if its connected faces form a single continuous strip/fan."""
4
5 # 1. Build a local graph of the faces sharing this vertex
6 # 2. Start at one face, and walk to adjacent faces that share an edge AND this vertex
7 # 3. Count how many distinct "fans" or "components" you find
8
9 components = count_connected_components(connected_faces, shared_vertex=vertex)
10
11 # If the faces touch ONLY at the vertex (forming an hourglass shape),
12 # there will be >1 component, meaning it is Non-Manifold.
13 return components == 1
Topology (Manifold/Bowtie)
0.00
2 min read1 page

One of the most profound mathematical laws governing 3D topology is the Euler Characteristic. For any closed, watertight manifold mesh without holes or tunnels (topologically equivalent to a sphere), the number of Vertices minus Edges plus Faces will always equal 2.

Euler Formula: V - E + F = 2:

1. V: Total Vertices. 2. E: Total Unique Edges. 3. F: Total Faces. 4. If X != 2, the mesh either has boundaries (holes), tunnels (like a donut/torus), or is non-manifold.
python
1# Euler-Poincaré Characteristic
2def calculate_euler_characteristic(mesh):
3 """Calculates the Euler characteristic (X) of a mesh."""
4
5 V = len(mesh.vertices)
6 E = len(mesh.get_unique_edges())
7 F = len(mesh.faces)
8
9 # X = V - E + F
10 euler_chi = V - E + F
11
12 # For a closed surface (sphere topology), X should equal 2
13 # For a surface with 'g' holes (torus), X = 2 - 2g
14 # If the mesh has 'b' boundary loops, X = 2 - 2g - b
15
16 return euler_chi, V, E, F
Geometry (Tetra/Box/Sphere)
0.00
2 min read1 page

Before running computationally expensive boolean operations (like intersecting two meshes) or sending a file to a 3D printer, software must run a full diagnostic pass to ensure the geometry is a perfectly watertight manifold.

Diagnostic Pass:

1. Build half-edge connectivity graph. 2. Highlight naked edges in Red (holes to be filled). 3. Highlight non-manifold edges in Yellow (bad topology to be deleted). 4. Verify Euler Characteristic matches expected topology genus.
python
1# Diagnostics & Repair Workflow
2def diagnose_mesh(mesh):
3 """Checks all manifold conditions and reports errors."""
4
5 # 1. Build Graph
6 edges = build_half_edges(mesh.faces)
7
8 # 2. Find Naked Edges (Holes)
9 naked = [e for e in edges if e.twin is None]
10 if len(naked) > 0:
11 print(f"Mesh has {len(naked)} naked edges. Requires Hole Filling.")
12
13 # 3. Find Non-Manifold Edges
14 nm_edges = find_non_manifold_edges(mesh)
15 if len(nm_edges) > 0:
16 print("Mesh has non-manifold edges. Requires topological repair.")
17
18 # 4. Check Euler
19 X, V, E, F = calculate_euler_characteristic(mesh)
20 print(f"Euler Characteristic: {X}")
21
22 return len(naked) == 0 and len(nm_edges) == 0
Auto-Rotate
1.00