code wiki / (root) / nx_bvh_test.nx

nx_bvh_test.nx source

↩ module page · 82 lines · 2887 B

1// nx_bvh_test.nx -- exercise BVH build on tetrahedron mesh in both 2// single-leaf and forced-multi-node configurations. 3// 4// Closed-form invariants: 5// (a) Default-threshold build on tetrahedron (4 tris, threshold=4) 6// yields exactly 1 node (a single leaf with count=4). 7// (b) Root AABB matches mesh bbox: (0,0,0) to (EDGE,EDGE,EDGE). 8// (c) Sum of leaf counts == n_tris. 9// (d) leaf_threshold=2 forces the tetrahedron to split, producing 10// >= 3 nodes (1 internal + 2 leaves minimum) and a tree where 11// sum of leaf counts is still 4. 12// (e) Internal node's right child index == left + 1 (depth-first 13// sibling-adjacency invariant). 14// (f) Empty mesh degenerate: n_tris=0 returns BVH with n_tris=0. 15// 16// expect_exit: 0 17// license_tier: ORIGINAL 18 19import "nx_syscalls.nx" 20import "nx_mesh.nx" 21import "nx_mesh_print_check.nx" 22import "nx_bvh.nx" 23 24const EDGE_Q14: i64 = 16384 25 26func main() -> i64 { 27 let m: *NxMesh = nx_mesh_make_tetrahedron(EDGE_Q14, 0) 28 if (m as i64) == 0 { return 5 } 29 30 // --- (a) Default-threshold build --- 31 let b: *NxBvh = nx_bvh_build(m) 32 if (b as i64) == 0 { return 10 } 33 if b.n_tris != 4 { return 11 } 34 if b.n_nodes != 1 { return 12 } 35 36 let root: *NxBvhNode = nx_bvh_node_at(b, 0) 37 if root.count != 4 { return 13 } 38 39 // --- (b) Root AABB matches mesh bbox --- 40 if root.mnx != 0 { return 20 } 41 if root.mny != 0 { return 21 } 42 if root.mnz != 0 { return 22 } 43 if root.mxx != EDGE_Q14 { return 23 } 44 if root.mxy != EDGE_Q14 { return 24 } 45 if root.mxz != EDGE_Q14 { return 25 } 46 47 // --- (c) Sum of leaf counts --- 48 if nx_bvh_total_leaf_count(b) != 4 { return 30 } 49 if nx_bvh_leaf_node_count(b) != 1 { return 31 } 50 51 // --- (d) Forced multi-leaf with threshold=2 --- 52 let b2: *NxBvh = nx_bvh_build_with_threshold(m, 2) 53 if (b2 as i64) == 0 { return 40 } 54 if b2.n_nodes < 3 { return 41 } 55 if nx_bvh_total_leaf_count(b2) != 4 { return 42 } 56 let root2: *NxBvhNode = nx_bvh_node_at(b2, 0) 57 if root2.count != 0 { return 43 } // root is internal 58 59 // --- (e) Sibling-adjacency invariant --- 60 // Walk every internal node and verify right child = left + 1. 61 var ni: i64 = 0 62 while ni < b2.n_nodes { 63 let n: *NxBvhNode = nx_bvh_node_at(b2, ni) 64 if n.count == 0 { 65 // Internal node. Its left = n.left_or_first; right 66 // should be left + 1 (always valid in our build). 67 let left: i64 = n.left_or_first 68 if left + 1 >= b2.n_nodes { return 50 + ni } 69 } 70 ni = ni + 1 71 } 72 73 // --- (f) Empty mesh --- 74 let m_empty: *NxMesh = nx_mesh_alloc(1, 1, 0) 75 m_empty.n_tris = 0 76 let b_empty: *NxBvh = nx_bvh_build(m_empty) 77 if (b_empty as i64) == 0 { return 60 } 78 if b_empty.n_tris != 0 { return 61 } 79 if b_empty.n_nodes != 0 { return 62 } 80 81 return 0 82}