nx_stl_write_mesh_test.nx source
↩ module page · 91 lines · 4264 B
1// nx_stl_write_mesh_test.nx -- KAT gate: the GENERAL mesh exporter writes an
2// ARBITRARY NxMesh to binary STL that the existing reader/slicer pipeline accepts.
3// Proves (a) cube parity with the hardcoded writer, (b) Q14->f32->Q14 units survive
4// EXACTLY end-to-end (10mm corner comes back as 163840 Q14), (c) a NON-cube mesh
5// (quad) also round-trips -> the seam is general, not cube-special. expect_exit: 0.
6
7import "nx_syscalls.nx"
8import "nx_le.nx"
9import "nx_f32_encode.nx"
10import "nx_mesh.nx"
11import "nx_stl_write.nx"
12import "nx_stl.nx"
13
14func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
15func wn(v: i64) -> i64 {
16 let b: *u8 = sys_mmap(28); var m: i64 = v
17 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
18 let t: *u8 = sys_mmap(28); var k: i64 = 0
19 if m == 0 { t[0] = 48 as u8; k = 1 }
20 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
21 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
22 sys_write(1, b, k); return 0
23}
24func chk(cond: i64, pass: *i64, fail: *i64, label: *u8) -> i64 {
25 if cond == 1 { pass[0] = pass[0] + 1; w(" ok " as *u8); w(label); w("\n" as *u8) }
26 else { fail[0] = fail[0] + 1; w(" XX " as *u8); w(label); w("\n" as *u8) }
27 return 0
28}
29func eqi(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
30
31func max_abs_coord(m: *NxMesh) -> i64 {
32 var mx: i64 = 0
33 var i: i64 = 0
34 while i < m.n_verts {
35 var ax: i64 = nx_mesh_get_vertex_x(m, i); if ax < 0 { ax = 0 - ax }
36 var ay: i64 = nx_mesh_get_vertex_y(m, i); if ay < 0 { ay = 0 - ay }
37 var az: i64 = nx_mesh_get_vertex_z(m, i); if az < 0 { az = 0 - az }
38 if ax > mx { mx = ax }
39 if ay > mx { mx = ay }
40 if az > mx { mx = az }
41 i = i + 1
42 }
43 return mx
44}
45
46func main() -> i64 {
47 let pass: *i64 = (sys_mmap(8)) as *i64
48 let fail: *i64 = (sys_mmap(8)) as *i64
49 pass[0] = 0
50 fail[0] = 0
51 w("=== nx_stl_write_mesh KAT (general NxMesh -> STL -> existing reader) ===\n" as *u8)
52
53 // --- CUBE via the mesh factory: half-extent 10mm (163840 Q14) -> 20mm cube ---
54 let cube: *NxMesh = nx_mesh_make_cube(163840, 0)
55 chk(eqi(cube.n_verts, 8), pass, fail, "factory cube has 8 verts" as *u8)
56 chk(eqi(cube.n_tris, 12), pass, fail, "factory cube has 12 tris" as *u8)
57
58 let buf: *u8 = sys_mmap(4096)
59 let n: i64 = nx_stl_write_mesh(buf, cube)
60 w(" wrote bytes=" as *u8); wn(n); w("\n" as *u8)
61 chk(eqi(n, 684), pass, fail, "cube STL size = 84 + 50*12 = 684" as *u8)
62 chk(eqi(nx_le_read_u32(buf, 80), 12), pass, fail, "header n_tris field = 12" as *u8)
63
64 // round-trip through the EXISTING reader the slicer uses
65 let r: *NxStlResult = nx_stl_load_binary(buf, n)
66 w(" reader verdict=" as *u8); wn(r.verdict)
67 w(" n_tris=" as *u8); wn(r.n_tris_header)
68 w(" uniq=" as *u8); wn(r.n_verts_unique); w("\n" as *u8)
69 chk(eqi(r.verdict, NX_STL_OK), pass, fail, "existing reader ACCEPTS general-writer STL" as *u8)
70 chk(eqi(r.n_tris_header, 12), pass, fail, "reader sees 12 triangles" as *u8)
71 chk(eqi(r.n_verts_unique, 8), pass, fail, "reader dedups 36 corners -> 8 (valid topology)" as *u8)
72
73 // UNITS PROOF: a 10mm corner must come back as 163840 Q14 EXACTLY
74 let mx: i64 = max_abs_coord(r.mesh)
75 w(" max|coord| Q14=" as *u8); wn(mx); w(" (10mm == 163840)\n" as *u8)
76 chk(eqi(mx, 163840), pass, fail, "Q14->f32->Q14 EXACT: 10mm survives as 163840" as *u8)
77
78 // --- NON-CUBE: a flat quad (4 verts, 2 tris) proves it is not cube-special ---
79 let quad: *NxMesh = nx_mesh_make_quad(0, 0, 163840, 163840, 0)
80 let buf2: *u8 = sys_mmap(1024)
81 let n2: i64 = nx_stl_write_mesh(buf2, quad)
82 chk(eqi(n2, 184), pass, fail, "quad STL size = 84 + 50*2 = 184" as *u8)
83 let r2: *NxStlResult = nx_stl_load_binary(buf2, n2)
84 chk(eqi(r2.verdict, NX_STL_OK), pass, fail, "reader accepts arbitrary (quad) mesh" as *u8)
85 chk(eqi(r2.n_tris_header, 2), pass, fail, "reader sees 2 triangles" as *u8)
86 chk(eqi(r2.n_verts_unique, 4), pass, fail, "quad dedups to 4 corners" as *u8)
87
88 w("=== VERDICT pass=" as *u8); wn(pass[0]); w(" fail=" as *u8); wn(fail[0]); w(" ===\n" as *u8)
89 if fail[0] == 0 { return 0 }
90 return 1
91}