code wiki / (root) / nx_slice_pipeline_test.nx

nx_slice_pipeline_test.nx source

↩ module page · 112 lines · 4074 B

1// nx_slice_pipeline_test.nx -- INTEGRATION TEST of every P0-P3.2 2// primitive. Tetrahedron mesh -> bvh -> multi-layer slice -> 3// contour -> perimeter + infill -> full Klipper G-code. 4// 5// Tetrahedron at unit-mm scale (Q14_ONE = 16384), layer_height 6// 0.2mm = 3277 Q14. Z range 0..16384, so ~5 layers fit 7// (3277, 6554, 9831, 13108, 16385/clip). 8// 9// Each layer's slice is a smaller right triangle (top of tetrahedron 10// shrinks toward apex). The pipeline produces: 11// - preamble (M104/M140/etc) 12// - per-layer: ;LAYER:N + M106 + G0/G1 travel + G1 extrude perimeter 13// + G0/G1 infill segments 14// - postamble (M104 S0 + M84) 15// 16// Closed-form invariants: 17// (a) Pipeline returns positive layer count (>= 4 layers). 18// (b) Final emitter buffer > 1000 bytes (enough for preamble + 19// layers + postamble). 20// (c) Output contains preamble markers (M104 S215, G28, M109). 21// (d) Output contains per-layer markers (";LAYER:0", ";LAYER:1"). 22// (e) Output contains perimeter print moves (G1 X with E value). 23// (f) Output contains postamble markers (M104 S0, M84). 24// (g) E_acc grew during printing (filament actually extruded). 25// 26// expect_exit: 0 27// license_tier: ORIGINAL 28 29import "nx_syscalls.nx" 30import "nx_mesh.nx" 31import "nx_mesh_print_check.nx" 32import "nx_bvh.nx" 33import "nx_machine_graph.nx" 34import "nx_material_profile.nx" 35import "nx_gcode_emit.nx" 36import "nx_slice_pipeline.nx" 37 38const Q14: i64 = 16384 39 40func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 { 41 var nlen: i64 = 0 42 while needle[nlen] != 0 { nlen = nlen + 1 } 43 if nlen == 0 { return 1 } 44 if len < nlen { return 0 } 45 var i: i64 = 0 46 while i <= len - nlen { 47 var j: i64 = 0 48 var matched: i64 = 1 49 while j < nlen { 50 if buf[i + j] != needle[j] { matched = 0; j = nlen } 51 j = j + 1 52 } 53 if matched == 1 { return 1 } 54 i = i + 1 55 } 56 return 0 57} 58 59func main() -> i64 { 60 let mesh: *NxMesh = nx_mesh_make_tetrahedron(Q14, 0) 61 if (mesh as i64) == 0 { return 5 } 62 63 let machine: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 64 let material: *NxMaterialProfile = nx_material_profile_generic_pla() 65 66 let layer_h_q14: i64 = 3277 // 0.2 mm 67 let line_w_q14: i64 = 6554 // 0.4 mm 68 69 let emitter: *NxGcodeEmitter = nx_gemit_new(machine, material, 70 layer_h_q14, line_w_q14, 71 65536) 72 if (emitter as i64) == 0 { return 10 } 73 74 // Preamble is the caller's responsibility (per primitive contract). 75 nx_gemit_preamble(emitter) 76 if emitter.verdict != NX_GEMIT_OK { return 11 } 77 78 let E_before: i64 = emitter.E_acc_q14 79 80 // Run the full slicer pipeline at 20% infill density. 81 let n_layers: i64 = nx_slice_pipe_run(emitter, mesh, 20) 82 83 // --- (a) Layer count --- 84 if n_layers < 4 { return 20 } 85 86 // --- (b) Buffer size --- 87 // Per layer for tetrahedron: ~200 bytes (3-vert perimeter + 1 88 // infill segment at this density). 4 layers + preamble + postamble 89 // = ~900-1000 bytes total. Threshold 500 is a generous floor. 90 if emitter.len < 500 { return 30 } 91 92 // --- (c) Preamble markers --- 93 if smoke_contains(emitter.buf, emitter.len, "M104 S215") != 1 { return 40 } 94 if smoke_contains(emitter.buf, emitter.len, "G28") != 1 { return 41 } 95 if smoke_contains(emitter.buf, emitter.len, "M109 S215") != 1 { return 42 } 96 97 // --- (d) Per-layer markers --- 98 if smoke_contains(emitter.buf, emitter.len, ";LAYER:0") != 1 { return 50 } 99 if smoke_contains(emitter.buf, emitter.len, ";LAYER:1") != 1 { return 51 } 100 101 // --- (e) Print moves --- 102 if smoke_contains(emitter.buf, emitter.len, "G1 X") != 1 { return 60 } 103 104 // --- (f) Postamble --- 105 if smoke_contains(emitter.buf, emitter.len, "M104 S0") != 1 { return 70 } 106 if smoke_contains(emitter.buf, emitter.len, "M84") != 1 { return 71 } 107 108 // --- (g) E accumulated --- 109 if emitter.E_acc_q14 <= E_before { return 80 } 110 111 return 0 112}