nx_infill_test.nx source
↩ module page · 131 lines · 4681 B
1// nx_infill_test.nx -- scan-line infill on a unit-mm CCW square at
2// multiple densities, hand-computed expected counts and endpoints.
3//
4// Unit square (0,0) - (1mm, 1mm) in Q14: (0,0) - (16384, 16384).
5// Line width = 0.4mm = 6554 Q14.
6//
7// Density 100% -> spacing = 6554 Q14. Scan lines at y = 0, 6554,
8// 13108 (next 19662 > 16384 = out of bbox). 3 segments.
9// Density 50% -> spacing = 13108 Q14. Scan lines at y = 0, 13108.
10// 2 segments.
11// Density 25% -> spacing = 26216 Q14. Scan line at y = 0 only.
12// 1 segment.
13//
14// At each scan line, the square produces ONE crossing pair from
15// x = 0 to x = 16384 (left and right vertical edges of the square).
16// Horizontal edges of the square (top and bottom) are skipped by
17// the straddle test, which is the right behaviour.
18//
19// Closed-form invariants:
20// (a) 100% density horizontal scan -> exactly 3 segments.
21// (b) 50% density horizontal scan -> exactly 2 segments.
22// (c) 25% density horizontal scan -> exactly 1 segment.
23// (d) Every emitted segment is horizontal (y1 == y2).
24// (e) Every emitted segment spans full width (x1=0, x2=16384).
25// (f) Vertical scan (vertical=1) at 50% density -> 2 vertical
26// segments (x1==x2, span full height).
27// (g) density_pct = 0 returns BAD_DENSITY verdict.
28// (h) density_pct = 101 returns BAD_DENSITY verdict.
29// (i) 3-vert polygon (triangle) at 100% density yields > 0 segments.
30//
31// expect_exit: 0
32// license_tier: ORIGINAL
33
34import "nx_syscalls.nx"
35import "nx_polygon.nx"
36import "nx_slice_plane.nx"
37import "nx_infill.nx"
38
39const Q14: i64 = 16384
40const LINE_WIDTH: i64 = 6554
41
42func smoke_seg_x1(s: *NxSliceSoup, i: i64) -> i64 {
43 let p: *i64 = nx_slice_soup_seg_ptr(s, i)
44 return p[0]
45}
46func smoke_seg_y1(s: *NxSliceSoup, i: i64) -> i64 {
47 let p: *i64 = nx_slice_soup_seg_ptr(s, i)
48 return p[1]
49}
50func smoke_seg_x2(s: *NxSliceSoup, i: i64) -> i64 {
51 let p: *i64 = nx_slice_soup_seg_ptr(s, i)
52 return p[2]
53}
54func smoke_seg_y2(s: *NxSliceSoup, i: i64) -> i64 {
55 let p: *i64 = nx_slice_soup_seg_ptr(s, i)
56 return p[3]
57}
58
59func main() -> i64 {
60 let sq: *NxPolygon = nx_polygon_make_square(0, 0, Q14, Q14)
61
62 // --- (a) 100% horizontal ---
63 let s100: *NxSliceSoup = nx_slice_soup_new(64)
64 let v100: i64 = nx_infill_lines(sq, 100, LINE_WIDTH, 0, s100)
65 if v100 != NX_INFILL_OK { return 10 }
66 if s100.n_segments != 3 { return 11 }
67
68 // --- (b) 50% horizontal ---
69 let s50: *NxSliceSoup = nx_slice_soup_new(64)
70 let v50: i64 = nx_infill_lines(sq, 50, LINE_WIDTH, 0, s50)
71 if v50 != NX_INFILL_OK { return 20 }
72 if s50.n_segments != 2 { return 21 }
73
74 // --- (c) 25% horizontal ---
75 let s25: *NxSliceSoup = nx_slice_soup_new(64)
76 let v25: i64 = nx_infill_lines(sq, 25, LINE_WIDTH, 0, s25)
77 if v25 != NX_INFILL_OK { return 30 }
78 if s25.n_segments != 1 { return 31 }
79
80 // --- (d) Horizontal segments: y1 == y2 ---
81 var i: i64 = 0
82 while i < s50.n_segments {
83 if smoke_seg_y1(s50, i) != smoke_seg_y2(s50, i) { return 40 }
84 i = i + 1
85 }
86
87 // --- (e) Full-width span: x1 == 0, x2 == Q14 ---
88 i = 0
89 while i < s50.n_segments {
90 let a: i64 = smoke_seg_x1(s50, i)
91 let b: i64 = smoke_seg_x2(s50, i)
92 // qsort orders them; a should be 0, b should be Q14
93 if a != 0 { return 50 }
94 if b != Q14 { return 51 }
95 i = i + 1
96 }
97
98 // --- (f) Vertical scan ---
99 let sV: *NxSliceSoup = nx_slice_soup_new(64)
100 let vV: i64 = nx_infill_lines(sq, 50, LINE_WIDTH, 1, sV)
101 if vV != NX_INFILL_OK { return 60 }
102 if sV.n_segments != 2 { return 61 }
103 i = 0
104 while i < sV.n_segments {
105 // Vertical: x1 == x2
106 if smoke_seg_x1(sV, i) != smoke_seg_x2(sV, i) { return 62 }
107 // Spans full height
108 let ay: i64 = smoke_seg_y1(sV, i)
109 let by: i64 = smoke_seg_y2(sV, i)
110 if ay != 0 { return 63 }
111 if by != Q14 { return 64 }
112 i = i + 1
113 }
114
115 // --- (g)(h) Bad density ---
116 let sBad: *NxSliceSoup = nx_slice_soup_new(64)
117 if nx_infill_lines(sq, 0, LINE_WIDTH, 0, sBad) != NX_INFILL_ERR_BAD_DENSITY { return 70 }
118 if nx_infill_lines(sq, 101, LINE_WIDTH, 0, sBad) != NX_INFILL_ERR_BAD_DENSITY { return 71 }
119
120 // --- (i) Triangle infill produces segments ---
121 let tri: *NxPolygon = nx_polygon_alloc(3)
122 nx_polygon_add_vert(tri, 0, 0)
123 nx_polygon_add_vert(tri, Q14, 0)
124 nx_polygon_add_vert(tri, 0, Q14)
125 let sTri: *NxSliceSoup = nx_slice_soup_new(64)
126 let vTri: i64 = nx_infill_lines(tri, 100, LINE_WIDTH, 0, sTri)
127 if vTri != NX_INFILL_OK { return 80 }
128 if sTri.n_segments <= 0 { return 81 }
129
130 return 0
131}