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}