code wiki / (root) / nx_cad_test.nx

nx_cad_test.nx source

↩ module page · 121 lines · 5963 B

1// nx_cad_test.nx -- KAT gate for parametric sketch->extrude solid modeling. 2// Closed-form invariants (vert/tri counts, validity, AABB) for box / triangular 3// prism / faceted cylinder, watertight slicing of the solids, and a full 4// CAD->print proof: a parametric cylinder -> STL -> existing QIDI slicer -> real 5// G-code. Ties the AutoCAD-class tools into the same proven fabrication pipeline 6// the DCC tools use. expect_exit: 0. 7 8import "nx_syscalls.nx" 9import "nx_mesh.nx" 10import "nx_mesh_edit.nx" 11import "nx_cad.nx" 12import "nx_bvh.nx" 13import "nx_slice_plane.nx" 14import "nx_slice_contour.nx" 15import "nx_stl_write.nx" 16import "nx_stl.nx" 17import "nx_machine_graph.nx" 18import "nx_material_profile.nx" 19import "nx_gcode_emit.nx" 20import "nx_slice_pipeline.nx" 21 22func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 23func wn(v: i64) -> i64 { 24 let b: *u8 = sys_mmap(28); var m: i64 = v 25 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 26 let t: *u8 = sys_mmap(28); var k: i64 = 0 27 if m == 0 { t[0] = 48 as u8; k = 1 } 28 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 29 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 30 sys_write(1, b, k); return 0 31} 32func smoke_count(buf: *u8, len: i64, needle: *u8) -> i64 { 33 var nlen: i64 = 0; while needle[nlen] != 0 { nlen = nlen + 1 } 34 if len < nlen { return 0 } 35 var count: i64 = 0; var i: i64 = 0; let last: i64 = len - nlen 36 while i <= last { 37 var j: i64 = 0; var matched: i64 = 1 38 while j < nlen { if buf[i + j] != needle[j] { matched = 0; j = nlen } j = j + 1 } 39 if matched == 1 { count = count + 1 } 40 i = i + 1 41 } 42 return count 43} 44func chk(cond: i64, pass: *i64, fail: *i64, label: *u8) -> i64 { 45 if cond == 1 { pass[0] = pass[0] + 1; w(" ok " as *u8); w(label); w("\n" as *u8) } 46 else { fail[0] = fail[0] + 1; w(" XX " as *u8); w(label); w("\n" as *u8) } 47 return 0 48} 49func eqi(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 } 50 51func slice_open(model: *NxMesh, plane_z: i64) -> i64 { 52 let bvh: *NxBvh = nx_bvh_build(model) 53 let soup: *NxSliceSoup = nx_slice_plane(model, bvh, plane_z) 54 let c: *NxSliceContours = nx_slice_contour_build(soup) 55 return c.n_open 56} 57 58func main() -> i64 { 59 let pass: *i64 = (sys_mmap(8)) as *i64 60 let fail: *i64 = (sys_mmap(8)) as *i64 61 pass[0] = 0 62 fail[0] = 0 63 let bb: *i64 = (sys_mmap(48)) as *i64 64 w("=== nx_cad KAT (parametric sketch->extrude solid modeling) ===\n" as *u8) 65 66 // --- BOX 20x20x20mm: rectangle sketch extruded -> 8 verts, 12 tris --- 67 let box: *NxMesh = nx_cad_make_box(327680, 327680, 327680, 0) 68 chk(eqi(box.n_verts, 8), pass, fail, "box: 2*4 = 8 verts" as *u8) 69 chk(eqi(box.n_tris, 12), pass, fail, "box: 4*4-4 = 12 tris" as *u8) 70 chk(eqi(nx_mesh_validate(box), NX_MESH_OK), pass, fail, "box valid" as *u8) 71 nx_mesh_aabb(box, bb) 72 chk(eqi(bb[2], 0), pass, fail, "box base on z=0" as *u8) 73 chk(eqi(bb[5], 327680), pass, fail, "box height = 20mm" as *u8) 74 chk(eqi(bb[3], 163840), pass, fail, "box half-width = 10mm" as *u8) 75 76 // --- TRIANGULAR PRISM: arbitrary 3-vert convex sketch -> 6 verts, 8 tris --- 77 let tx: *i64 = (sys_mmap(3 * 8)) as *i64 78 let ty: *i64 = (sys_mmap(3 * 8)) as *i64 79 tx[0] = 0; ty[0] = 0 80 tx[1] = 327680; ty[1] = 0 81 tx[2] = 0; ty[2] = 327680 82 let prism: *NxMesh = nx_cad_extrude(tx, ty, 3, 163840, 0) 83 chk(eqi(prism.n_verts, 6), pass, fail, "tri prism: 2*3 = 6 verts" as *u8) 84 chk(eqi(prism.n_tris, 8), pass, fail, "tri prism: 4*3-4 = 8 tris" as *u8) 85 chk(eqi(nx_mesh_validate(prism), NX_MESH_OK), pass, fail, "tri prism valid" as *u8) 86 87 // --- CYLINDER r=10mm h=20mm, 16 facets -> 32 verts, 60 tris --- 88 let cyl: *NxMesh = nx_cad_make_cylinder(163840, 327680, 16, 0) 89 chk(eqi(cyl.n_verts, 32), pass, fail, "cylinder(16): 2*16 = 32 verts" as *u8) 90 chk(eqi(cyl.n_tris, 60), pass, fail, "cylinder(16): 4*16-4 = 60 tris" as *u8) 91 chk(eqi(nx_mesh_validate(cyl), NX_MESH_OK), pass, fail, "cylinder valid" as *u8) 92 nx_mesh_aabb(cyl, bb) 93 w(" cylinder AABB x[" as *u8); wn(bb[0]); w("," as *u8); wn(bb[3]); w("] z[" as *u8); wn(bb[2]); w("," as *u8); wn(bb[5]); w("]\n" as *u8) 94 chk(bb[3] <= 163840, pass, fail, "cylinder radius <= 10mm (verts on/inside circle)" as *u8) 95 chk(bb[3] >= 150000, pass, fail, "cylinder radius ~10mm (facets close to circle)" as *u8) 96 97 // --- WATERTIGHT slicing of the solids --- 98 chk(eqi(slice_open(box, 163840), 0), pass, fail, "box slices CLOSED" as *u8) 99 chk(eqi(slice_open(cyl, 163840), 0), pass, fail, "cylinder slices CLOSED" as *u8) 100 101 // --- CAD -> PRINT: parametric cylinder -> STL -> QIDI slicer -> G-code --- 102 let model: *NxMesh = nx_cad_make_cylinder(163840, 327680, 32, 0) // smoother 32-facet 103 let stl: *u8 = sys_mmap(32768) 104 let n: i64 = nx_stl_write_mesh(stl, model) 105 let r: *NxStlResult = nx_stl_load_binary(stl, n) 106 chk(eqi(r.verdict, NX_STL_OK), pass, fail, "cylinder STL read OK" as *u8) 107 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 108 let pla: *NxMaterialProfile = nx_material_profile_generic_pla() 109 let e: *NxGcodeEmitter = nx_gemit_new(qidi, pla, 3277, 6554, 4194304) 110 nx_gemit_preamble(e) 111 let nl: i64 = nx_slice_pipe_run_v2(e, r.mesh, 20, 3277) 112 let g1: i64 = smoke_count(e.buf, e.len, "G1 X" as *u8) 113 w(" CAD->print cylinder: layers=" as *u8); wn(nl); w(" G1=" as *u8); wn(g1); w(" bytes=" as *u8); wn(e.len); w("\n" as *u8) 114 chk(nl >= 50, pass, fail, "cylinder sliced >= 50 layers" as *u8) 115 chk(g1 >= 1000, pass, fail, "cylinder: many real extrusion moves" as *u8) 116 chk(smoke_count(e.buf, e.len, "M84" as *u8) >= 1, pass, fail, "cylinder G-code has motors-off (complete)" as *u8) 117 118 w("=== VERDICT pass=" as *u8); wn(pass[0]); w(" fail=" as *u8); wn(fail[0]); w(" ===\n" as *u8) 119 if fail[0] == 0 { return 0 } 120 return 1 121}