nx_polygon_test.nx source
↩ module page · 111 lines · 5062 B
1// nx_polygon_test.nx -- exercise foundational polygon ops + offset
2// on a CCW unit-mm square.
3//
4// Closed-form invariants on a unit-mm square at (0,0)-(Q14,Q14):
5// (a) Factory yields 4 verts in CCW order.
6// (b) Signed 2*area = 2 * Q14 * Q14 = 2^29 (positive = CCW).
7// (c) is_ccw returns 1.
8// (d) bbox = (0, 0, Q14, Q14).
9// (e) Point inside (8192, 8192) -> 1; outside (-100, 8192) -> 0;
10// outside (32768, 8192) -> 0; outside (8192, -100) -> 0.
11// (f) Orientation predicate:
12// - orient(0,0, Q14,0, 0,Q14) = +1 (CCW)
13// - orient(0,0, 0,Q14, Q14,0) = -1 (CW)
14// - orient(0,0, Q14,0, 2*Q14,0) = 0 (collinear)
15// (g) Segment intersection:
16// - (0,0)-(10K,10K) crosses (0,10K)-(10K,0) -> 1
17// - (0,0)-(5K,5K) and (6K,6K)-(10K,10K) non-overlapping -> 0
18// - (0,0)-(Q14,0) and (Q14,0)-(2*Q14,0) touching endpoint -> 0
19// - parallel non-collinear -> 0
20// (h) Offset OUTWARD by 0.1mm (1638 Q14): corner (0,0) moves to
21// (-1638,-1638); resulting bbox is (-1638,-1638,18022,18022);
22// polygon remains CCW and area grew.
23// (i) Offset INWARD by 0.1mm (-1638 Q14): corner (0,0) moves to
24// (1638,1638); bbox is (1638,1638,14746,14746); area shrunk.
25//
26// expect_exit: 0
27// license_tier: ORIGINAL
28
29import "nx_syscalls.nx"
30import "nx_abs.nx"
31import "nx_polygon.nx"
32
33const Q14_ONE: i64 = 16384
34
35func main() -> i64 {
36 let sq: *NxPolygon = nx_polygon_make_square(0, 0, Q14_ONE, Q14_ONE)
37 if (sq as i64) == 0 { return 5 }
38
39 // --- (a) Factory ---
40 if sq.n_verts != 4 { return 10 }
41 if nx_polygon_get_x(sq, 0) != 0 { return 11 }
42 if nx_polygon_get_y(sq, 0) != 0 { return 12 }
43 if nx_polygon_get_x(sq, 1) != Q14_ONE { return 13 }
44 if nx_polygon_get_y(sq, 1) != 0 { return 14 }
45 if nx_polygon_get_x(sq, 2) != Q14_ONE { return 15 }
46 if nx_polygon_get_y(sq, 2) != Q14_ONE { return 16 }
47 if nx_polygon_get_x(sq, 3) != 0 { return 17 }
48 if nx_polygon_get_y(sq, 3) != Q14_ONE { return 18 }
49
50 // --- (b)(c) Signed area + CCW ---
51 let area2: i64 = nx_polygon_signed_2area_q28(sq)
52 let expected_2area: i64 = 2 * Q14_ONE * Q14_ONE
53 if area2 != expected_2area { return 20 }
54 if nx_polygon_is_ccw(sq) != 1 { return 21 }
55
56 // --- (d) Bbox ---
57 let bb: *i64 = (sys_mmap(32)) as *i64
58 if nx_polygon_bbox(sq, bb) != NX_POLYGON_OK { return 30 }
59 if bb[0] != 0 { return 31 }
60 if bb[1] != 0 { return 32 }
61 if bb[2] != Q14_ONE { return 33 }
62 if bb[3] != Q14_ONE { return 34 }
63
64 // --- (e) Point inside ---
65 if nx_polygon_point_inside(sq, 8192, 8192) != 1 { return 40 }
66 if nx_polygon_point_inside(sq, -100, 8192) != 0 { return 41 }
67 if nx_polygon_point_inside(sq, 32768, 8192) != 0 { return 42 }
68 if nx_polygon_point_inside(sq, 8192, -100) != 0 { return 43 }
69 if nx_polygon_point_inside(sq, 8192, 32768) != 0 { return 44 }
70
71 // --- (f) Orientation ---
72 if nx_polygon_orient(0, 0, Q14_ONE, 0, 0, Q14_ONE) != 1 { return 50 }
73 if nx_polygon_orient(0, 0, 0, Q14_ONE, Q14_ONE, 0) != -1 { return 51 }
74 if nx_polygon_orient(0, 0, Q14_ONE, 0, 2 * Q14_ONE, 0) != 0 { return 52 }
75
76 // --- (g) Segment intersection ---
77 if nx_polygon_segments_cross(0, 0, 10000, 10000, 0, 10000, 10000, 0) != 1 { return 60 }
78 if nx_polygon_segments_cross(0, 0, 5000, 5000, 6000, 6000, 10000, 10000) != 0 { return 61 }
79 if nx_polygon_segments_cross(0, 0, Q14_ONE, 0, Q14_ONE, 0, 2 * Q14_ONE, 0) != 0 { return 62 }
80 if nx_polygon_segments_cross(0, 0, 100, 0, 0, 50, 100, 50) != 0 { return 63 } // parallel
81
82 // --- (h) Outward offset by 0.1mm (1638 Q14) ---
83 let out_grow: *NxPolygon = nx_polygon_offset(sq, 1638)
84 if (out_grow as i64) == 0 { return 70 }
85 if out_grow.n_verts != 4 { return 71 }
86 // Bottom-left corner should land at (-1638, -1638)
87 if nx_polygon_get_x(out_grow, 0) != -1638 { return 72 }
88 if nx_polygon_get_y(out_grow, 0) != -1638 { return 73 }
89 // Top-right corner should land at (Q14+1638, Q14+1638) = (18022, 18022)
90 if nx_polygon_get_x(out_grow, 2) != 18022 { return 74 }
91 if nx_polygon_get_y(out_grow, 2) != 18022 { return 75 }
92 let bb2: *i64 = (sys_mmap(32)) as *i64
93 nx_polygon_bbox(out_grow, bb2)
94 if bb2[0] != -1638 { return 76 }
95 if bb2[2] != 18022 { return 77 }
96 // Outward offset should grow area
97 if nx_polygon_signed_2area_q28(out_grow) <= expected_2area { return 78 }
98 if nx_polygon_is_ccw(out_grow) != 1 { return 79 }
99
100 // --- (i) Inward offset by 0.1mm (-1638 Q14) ---
101 let out_shrink: *NxPolygon = nx_polygon_offset(sq, -1638)
102 if (out_shrink as i64) == 0 { return 80 }
103 if nx_polygon_get_x(out_shrink, 0) != 1638 { return 81 }
104 if nx_polygon_get_y(out_shrink, 0) != 1638 { return 82 }
105 if nx_polygon_get_x(out_shrink, 2) != 14746 { return 83 }
106 if nx_polygon_get_y(out_shrink, 2) != 14746 { return 84 }
107 if nx_polygon_signed_2area_q28(out_shrink) >= expected_2area { return 85 }
108 if nx_polygon_is_ccw(out_shrink) != 1 { return 86 }
109
110 return 0
111}