code wiki / (root) / nx_supports_v2_test.nx

nx_supports_v2_test.nx source

↩ module page · 120 lines · 4593 B

1// nx_supports_v2_test.nx -- verify NxSupportPlan dedup + per-layer 2// G-code emission for support pillars. 3// 4// Closed-form invariants: 5// (a) plan_new returns plan with n=0 + correct capacity 6// (b) add_pillar at fresh XY returns 0 (added) + plan.n == 1 7// (c) add_pillar at identical XY returns 1 (merged) + plan.n unchanged 8// (d) merge extends top_z_q14 to max(old, new) 9// (e) add_pillar at proximity-close XY (within spacing) merges 10// (f) add_pillar at far XY adds new (plan.n == 2) 11// (g) emit_layer at z below all pillars' tops emits all 12// (h) emit_layer at z above all pillars' tops emits zero 13// (i) emit output contains ";SUPPORT_START" + ";SUPPORT_END" markers 14// (j) emit output contains "G1 X" perimeter moves 15// (k) capacity exhausted returns -1 16// 17// expect_exit: 0 18// license_tier: ORIGINAL 19 20import "nx_syscalls.nx" 21import "nx_polygon.nx" 22import "nx_machine_graph.nx" 23import "nx_material_profile.nx" 24import "nx_gcode_emit.nx" 25import "nx_supports.nx" 26 27const Q14: i64 = 16384 28 29func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 { 30 var nlen: i64 = 0 31 while needle[nlen] != 0 { nlen = nlen + 1 } 32 if len < nlen { return 0 } 33 var i: i64 = 0 34 let last: i64 = len - nlen 35 while i <= last { 36 var j: i64 = 0 37 var matched: i64 = 1 38 while j < nlen { 39 if buf[i + j] != needle[j] { matched = 0; j = nlen } 40 j = j + 1 41 } 42 if matched == 1 { return 1 } 43 i = i + 1 44 } 45 return 0 46} 47 48func main() -> i64 { 49 let footprint: i64 = 2 * Q14 // 2 mm pillar edge 50 let spacing: i64 = Q14 // 1 mm dedup tolerance 51 52 // --- (a) plan_new --- 53 let plan: *NxSupportPlan = nx_support_plan_new(8, footprint, spacing) 54 if (plan as i64) == 0 { return 10 } 55 if plan.n != 0 { return 11 } 56 if plan.capacity != 8 { return 12 } 57 if plan.footprint_q14 != footprint { return 13 } 58 if plan.spacing_q14 != spacing { return 14 } 59 60 // --- (b) add fresh pillar --- 61 let z_low: i64 = 5 * Q14 62 let z_mid: i64 = 10 * Q14 63 let z_high: i64 = 20 * Q14 64 65 if nx_support_plan_add_pillar(plan, 50 * Q14, 50 * Q14, z_mid) != 0 { return 20 } 66 if plan.n != 1 { return 21 } 67 68 // --- (c) add identical XY merges --- 69 if nx_support_plan_add_pillar(plan, 50 * Q14, 50 * Q14, z_low) != 1 { return 30 } 70 if plan.n != 1 { return 31 } 71 72 // --- (d) merge keeps MAX top_z (z_mid > z_low so unchanged) --- 73 let pp0_a: *NxSupportPillar = plan.pillars 74 if pp0_a.top_z_q14 != z_mid { return 40 } 75 76 // Now add same XY with z_high; should extend top_z to z_high. 77 if nx_support_plan_add_pillar(plan, 50 * Q14, 50 * Q14, z_high) != 1 { return 41 } 78 if pp0_a.top_z_q14 != z_high { return 42 } 79 80 // --- (e) proximity-close (within spacing) merges --- 81 let close_x: i64 = 50 * Q14 + spacing - 100 // slightly < spacing away 82 let close_y: i64 = 50 * Q14 83 if nx_support_plan_add_pillar(plan, close_x, close_y, z_mid) != 1 { return 50 } 84 if plan.n != 1 { return 51 } 85 86 // --- (f) far XY adds new --- 87 if nx_support_plan_add_pillar(plan, 100 * Q14, 100 * Q14, z_mid) != 0 { return 60 } 88 if plan.n != 2 { return 61 } 89 90 // ===== emit tests ===== 91 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 92 let pla: *NxMaterialProfile = nx_material_profile_generic_pla() 93 let lh: i64 = 3277 94 let lw: i64 = 6554 95 96 // --- (g) emit at z below all tops -> emits both pillars --- 97 let e_low: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 16384) 98 let n_emit_low: i64 = nx_support_plan_emit_layer(plan, e_low, 1 * Q14) 99 if n_emit_low != 2 { return 70 } 100 101 // --- (h) emit at z above all tops -> emits zero --- 102 let e_high: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 16384) 103 let n_emit_high: i64 = nx_support_plan_emit_layer(plan, e_high, 100 * Q14) 104 if n_emit_high != 0 { return 80 } 105 106 // --- (i) markers present in low-z output --- 107 if smoke_contains(e_low.buf, e_low.len, ";SUPPORT_START") != 1 { return 90 } 108 if smoke_contains(e_low.buf, e_low.len, ";SUPPORT_END") != 1 { return 91 } 109 110 // --- (j) perimeter moves present --- 111 if smoke_contains(e_low.buf, e_low.len, "G1 X") != 1 { return 100 } 112 113 // --- (k) capacity exhausted --- 114 let plan2: *NxSupportPlan = nx_support_plan_new(2, footprint, spacing) 115 nx_support_plan_add_pillar(plan2, 0, 0, z_mid) 116 nx_support_plan_add_pillar(plan2, 10 * Q14, 0, z_mid) 117 if nx_support_plan_add_pillar(plan2, 100 * Q14, 100 * Q14, z_mid) != -1 { return 110 } 118 119 return 0 120}