code wiki / (root) / nx_polygon_test.nx

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}