nx_slice_plane_test.nx source
↩ module page · 86 lines · 3194 B
1// nx_slice_plane_test.nx -- slice a unit tetrahedron at its midplane
2// and verify the resulting segment soup describes the expected
3// right-triangle cross-section.
4//
5// Tetrahedron at unit-mm scale:
6// v0=(0,0,0), v1=(1,0,0), v2=(0,1,0), v3=(0,0,1) (in Q14: 0 vs 16384)
7// Sliced at z = 0.5 mm (8192 Q14):
8// T0 (v1,v2,v3): produces segment (8192,0) -- (0,8192)
9// T1 (v0,v3,v2): produces segment (0,0) -- (0,8192)
10// T2 (v0,v1,v3): produces segment (8192,0) -- (0,0)
11// T3 (v0,v2,v1): all z=0, plane at 8192 -> all below -> no segment
12//
13// Result: 3 segments whose 6 endpoints cover the set
14// {(0,0), (8192,0), (0,8192)}, each appearing exactly twice.
15// This is the boundary of a right triangle in 2D.
16//
17// Closed-form invariants:
18// (a) Soup verdict == OK.
19// (b) Exactly 3 segments at z=8192.
20// (c) Each of the 3 corner points appears exactly twice in the
21// segment-endpoint multiset.
22// (d) Slicing at z above tetrahedron (z = 2 * Q14) -> 0 segments.
23// (e) Slicing at z below tetrahedron (z = -1) -> 0 segments.
24// (f) Slicing at the bottom face (z = 0) yields 3 segments
25// (the three coplanar tri edges of the bottom face's
26// neighbours; T3 itself coplanar -> no segment).
27//
28// expect_exit: 0
29// license_tier: ORIGINAL
30
31import "nx_syscalls.nx"
32import "nx_mesh.nx"
33import "nx_mesh_print_check.nx"
34import "nx_bvh.nx"
35import "nx_slice_plane.nx"
36
37const Q14_ONE: i64 = 16384
38const Q14_HALF: i64 = 8192
39
40// Count occurrences of (px, py) in the segment endpoints.
41func smoke_count_endpoint(s: *NxSliceSoup, px: i64, py: i64) -> i64 {
42 var count: i64 = 0
43 var i: i64 = 0
44 while i < s.n_segments {
45 let p: *i64 = nx_slice_soup_seg_ptr(s, i)
46 if p[0] == px { if p[1] == py { count = count + 1 } }
47 if p[2] == px { if p[3] == py { count = count + 1 } }
48 i = i + 1
49 }
50 return count
51}
52
53func main() -> i64 {
54 let m: *NxMesh = nx_mesh_make_tetrahedron(Q14_ONE, 0)
55 if (m as i64) == 0 { return 5 }
56 let b: *NxBvh = nx_bvh_build(m)
57 if (b as i64) == 0 { return 6 }
58
59 // --- (a)(b) Slice at mid-plane ---
60 let s: *NxSliceSoup = nx_slice_plane(m, b, Q14_HALF)
61 if s.verdict != NX_SLICE_OK { return 10 }
62 if s.n_segments != 3 { return 11 }
63
64 // --- (c) Endpoint multiset ---
65 if smoke_count_endpoint(s, 0, 0) != 2 { return 20 }
66 if smoke_count_endpoint(s, Q14_HALF, 0) != 2 { return 21 }
67 if smoke_count_endpoint(s, 0, Q14_HALF) != 2 { return 22 }
68
69 // --- (d) Slice above tetrahedron ---
70 let s_above: *NxSliceSoup = nx_slice_plane(m, b, 2 * Q14_ONE)
71 if s_above.n_segments != 0 { return 30 }
72
73 // --- (e) Slice below tetrahedron ---
74 let s_below: *NxSliceSoup = nx_slice_plane(m, b, -1)
75 if s_below.n_segments != 0 { return 40 }
76
77 // --- (f) Slice at bottom face z=0 ---
78 // T3 (v0,v2,v1) all coplanar -> no segment.
79 // T0(v1,v2,v3), T1(v0,v3,v2), T2(v0,v1,v3) each have 2 zeros
80 // -> each emits the on-plane edge as segment. 3 segments.
81 let s_bottom: *NxSliceSoup = nx_slice_plane(m, b, 0)
82 if s_bottom.verdict != NX_SLICE_OK { return 50 }
83 if s_bottom.n_segments != 3 { return 51 }
84
85 return 0
86}