Source code for ddg.halfedge._layout
from collections import deque
import numpy as np
import ddg
[docs]def integrate_one_form(
hds, start_vertex, start_vertex_co, co_attr, edge_attr, boundary_attr=None
):
"""
Lays out a surface using edge directions and lengths via breadth-first traversal.
I.e. integrates a discrete one-form with values stored on hds.edges.
Parameters
----------
hds : ddg.halfedge.Surface
Halfedge object with combinatorics and edge attributes.
start_vertex : hds.verts
Initial vertex to start from.
start_vertex_co : np.ndarray, shape (3,)
3D position of the start_vertex.
co_attr : str
Name of the vertex attribute to store the new coordinates.
edge_attr : str
Name of the edge attribute storing new edge vectors (shape (3,)).
The edge vectors must be scaled to desired length.
boundary_attr : str (default = None)
Vertex attribute with values True/False. If a string is given,
the BFS stops further traversal from that vertex.
Useful for example for vertices close to infinity.
Returns
-------
hds : ddg.halfedge.Surface
Same halfedge object with new vertex coordinates stored under co_attr.
"""
# Initialize BFS queue
queue = deque([start_vertex])
# Create a visited attribute to track traversed vertices
visited_attr = "visited_in_layout_fct"
visited = hds.verts.add_attribute(visited_attr, False)
visited[start_vertex] = True
# Initialize coordinate attribute if it doesn't exist
if not hasattr(hds.verts, co_attr):
hds.verts.add_attribute(co_attr)
setattr(start_vertex, co_attr, start_vertex_co)
# BFS traversal to lay out the surface
while queue:
current = queue.popleft()
for edge in ddg.halfedge.out_edges(current):
head = edge.head
if visited[head]:
continue
# Compute and assign head vertex coordinate
new_edge = getattr(edge, edge_attr)
new_coord = getattr(current, co_attr) + new_edge
setattr(head, co_attr, new_coord)
visited[head] = True
# Add to queue unless it's a boundary
if boundary_attr is None or not getattr(head, boundary_attr):
queue.append(head)
# Remove temporary visited attribute
delattr(hds.verts, visited_attr)
return hds
[docs]def verify_closure_one_form(hds, edge_attr, tol=1e-6):
"""
Verifies closure of a discrete one-form with edge lenths and
directions stored in an attribute called edge_attr.
Parameters
----------
hds : ddg.halfedge.Surface
Halfedge object.
edge_attr: str
Name of the edge attribute storing the new scaled edge vectors.
tol : float(default: 1e-6)
Tolerance for the error considered acceptable.
Returns
-------
int
Number of faces with large closure errors.
"""
broken_faces = 0
for f in hds.faces:
error = np.zeros(3)
for e in ddg.halfedge.edge_loop(f.edge):
error += getattr(e, edge_attr)
norm = np.linalg.norm(error)
if norm > tol:
print(f"❌ Face {f.index} error: {norm}")
broken_faces += 1
if broken_faces == 0:
print("✅ All faces pass the closure test within tolerance.")
else:
print(f"⚠️ {broken_faces} faces failed closure test (tol = {tol}).")
return broken_faces