import numpy as np import pytest from env.graph import CreaseGraph, VERTEX_TOL def test_init_boundary(): g = CreaseGraph() assert len(g.vertices) == 4 assert len(g.edges) == 4 for eid, (v1, v2, assignment) in g.edges.items(): assert assignment == 'B' assert g.interior_vertices() == [] def test_add_vertex_dedup(): g = CreaseGraph() id1 = g.add_vertex(0.5, 0.5) id2 = g.add_vertex(0.5, 0.5) assert id1 == id2 def test_add_vertex_dedup_near(): g = CreaseGraph() id1 = g.add_vertex(0.5, 0.5) id2 = g.add_vertex(0.5 + VERTEX_TOL * 0.5, 0.5) assert id1 == id2 def test_cyclic_order(): g = CreaseGraph() center_id = g.add_vertex(0.5, 0.5) right_id = g.add_vertex(0.8, 0.5) # 0 degrees top_id = g.add_vertex(0.5, 0.8) # 90 degrees left_id = g.add_vertex(0.2, 0.5) # 180 degrees bottom_id = g.add_vertex(0.5, 0.2) # 270 degrees / -90 degrees e_right = g.add_edge(center_id, right_id, 'M') e_top = g.add_edge(center_id, top_id, 'M') e_left = g.add_edge(center_id, left_id, 'M') e_bottom = g.add_edge(center_id, bottom_id, 'M') cyclic = g.get_cyclic_edges(center_id) # Sorted by angle ascending: right(0), top(90), left(180), bottom(-90 → 270) # arctan2 for bottom gives -pi/2 which sorts before 0 in ascending order # So actual ascending order: bottom(-pi/2), right(0), top(pi/2), left(pi) assert len(cyclic) == 4 def edge_angle(eid): ev1, ev2, _ = g.edges[eid] other_id = ev2 if ev1 == center_id else ev1 ox, oy = g.vertices[other_id] cx, cy = g.vertices[center_id] return float(np.arctan2(oy - cy, ox - cx)) angles = [edge_angle(eid) for eid in cyclic] assert angles == sorted(angles), "Edges should be sorted by ascending angle" assert e_right in cyclic assert e_top in cyclic assert e_left in cyclic assert e_bottom in cyclic # Verify specific order: bottom < right < top < left in angle space pos = {eid: i for i, eid in enumerate(cyclic)} assert pos[e_bottom] < pos[e_right] < pos[e_top] < pos[e_left] def test_interior_vertices_empty(): g = CreaseGraph() assert g.interior_vertices() == [] def test_interior_vertices_with_crease_intersection(): g = CreaseGraph() center_id = g.add_vertex(0.5, 0.5) assert center_id in g.interior_vertices() def test_split_edge(): g = CreaseGraph() # Find the bottom boundary edge (0,0)-(1,0) which is edge 0: v0-v1 original_edge_id = None for eid, (v1, v2, assignment) in g.edges.items(): x1, y1 = g.vertices[v1] x2, y2 = g.vertices[v2] if {(x1, y1), (x2, y2)} == {(0.0, 0.0), (1.0, 0.0)}: original_edge_id = eid original_v1 = v1 original_v2 = v2 break assert original_edge_id is not None mid_id = g.add_vertex(0.5, 0.0) eid1, eid2 = g.split_edge(original_edge_id, mid_id) assert original_edge_id not in g.edges assert eid1 in g.edges assert eid2 in g.edges _, _, a1 = g.edges[eid1] _, _, a2 = g.edges[eid2] assert a1 == 'B' assert a2 == 'B' def edge_vertex_set(eid): v1, v2, _ = g.edges[eid] return {v1, v2} assert mid_id in edge_vertex_set(eid1) assert mid_id in edge_vertex_set(eid2) assert original_v1 in edge_vertex_set(eid1) or original_v1 in edge_vertex_set(eid2) assert original_v2 in edge_vertex_set(eid1) or original_v2 in edge_vertex_set(eid2)