nx_dcc_slice_watertight_gate.nx source
↩ module page · 94 lines · 4932 B
1// nx_dcc_slice_watertight_gate.nx -- REGRESSION GATE for the two slicer fixes that
2// let DCC-authored slanted/curved geometry print:
3// (1) canonical edge-intersection rounding in nx_slice_edge_at_z (shared edges
4// compute the IDENTICAL crossing point regardless of traversal direction),
5// (2) the BVH right-child-adjacency fix in nx_bvh_fill_subtree (every triangle
6// is visited EXACTLY once -- no duplicate, no orphan).
7// Both bugs manifested as non-closing contours on non-axis-aligned meshes. This
8// gate asserts WATERTIGHT slicing (closed contours, exact segment counts) on a
9// pyramid, octahedron, and icosphere -- the shapes that exposed the bugs. A
10// 1-segment dup or a dropped face re-opens a contour and trips n_open. expect_exit: 0.
11
12import "nx_syscalls.nx"
13import "nx_mesh.nx"
14import "nx_mesh_edit.nx"
15import "nx_mesh_sculpt.nx"
16import "nx_bvh.nx"
17import "nx_slice_plane.nx"
18import "nx_slice_contour.nx"
19
20func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
21func wn(v: i64) -> i64 {
22 let b: *u8 = sys_mmap(28); var m: i64 = v
23 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
24 let t: *u8 = sys_mmap(28); var k: i64 = 0
25 if m == 0 { t[0] = 48 as u8; k = 1 }
26 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
27 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
28 sys_write(1, b, k); return 0
29}
30func chk(cond: i64, pass: *i64, fail: *i64, label: *u8) -> i64 {
31 if cond == 1 { pass[0] = pass[0] + 1; w(" ok " as *u8); w(label); w("\n" as *u8) }
32 else { fail[0] = fail[0] + 1; w(" XX " as *u8); w(label); w("\n" as *u8) }
33 return 0
34}
35func eqi(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
36
37// slice mesh at plane_z; write n_segments,n_polys,n_open into out3
38func slice_stats(model: *NxMesh, plane_z: i64, out3: *i64) -> i64 {
39 let bvh: *NxBvh = nx_bvh_build(model)
40 let soup: *NxSliceSoup = nx_slice_plane(model, bvh, plane_z)
41 let c: *NxSliceContours = nx_slice_contour_build(soup)
42 out3[0] = soup.n_segments
43 out3[1] = c.n_polys
44 out3[2] = c.n_open
45 return 0
46}
47
48func main() -> i64 {
49 let pass: *i64 = (sys_mmap(8)) as *i64
50 let fail: *i64 = (sys_mmap(8)) as *i64
51 pass[0] = 0
52 fail[0] = 0
53 let st: *i64 = (sys_mmap(32)) as *i64
54 w("=== nx_dcc_slice_watertight (slanted/curved geometry slices closed) ===\n" as *u8)
55
56 // PYRAMID: a horizontal cut is a 4-sided square -> exactly 4 segments, 1 closed loop.
57 let py: *NxMesh = nx_mesh_make_pyramid(163840, 327680, 0)
58 slice_stats(py, 81920, st)
59 w(" pyramid z=5mm: segs=" as *u8); wn(st[0]); w(" polys=" as *u8); wn(st[1]); w(" open=" as *u8); wn(st[2]); w("\n" as *u8)
60 chk(eqi(st[0], 4), pass, fail, "pyramid: exactly 4 segments (no dup, no drop)" as *u8)
61 chk(eqi(st[1], 1), pass, fail, "pyramid: exactly 1 contour" as *u8)
62 chk(eqi(st[2], 0), pass, fail, "pyramid: contour CLOSED (n_open=0)" as *u8)
63
64 // OCTAHEDRON near its apex -> a 4-sided cross-section, closed.
65 let oc: *NxMesh = nx_mesh_make_octahedron(163840, 0)
66 nx_mesh_translate(oc, 0, 0, 163840) // bottom apex -> z=0
67 slice_stats(oc, 81920, st)
68 w(" octahedron z=5mm: segs=" as *u8); wn(st[0]); w(" polys=" as *u8); wn(st[1]); w(" open=" as *u8); wn(st[2]); w("\n" as *u8)
69 chk(eqi(st[0], 4), pass, fail, "octahedron: exactly 4 segments" as *u8)
70 chk(eqi(st[2], 0), pass, fail, "octahedron: contour CLOSED" as *u8)
71
72 // ICOSPHERE subdiv=2: a dense curved mesh -- every layer must close.
73 let sp: *NxMesh = nx_mesh_make_icosphere(163840, 2, 0)
74 nx_mesh_translate(sp, 0, 0, 163840) // span 0..2R
75 slice_stats(sp, 81920, st) // lower band
76 w(" icosphere z=5mm: segs=" as *u8); wn(st[0]); w(" polys=" as *u8); wn(st[1]); w(" open=" as *u8); wn(st[2]); w("\n" as *u8)
77 chk(st[1] >= 1, pass, fail, "icosphere low band: >=1 contour" as *u8)
78 chk(eqi(st[2], 0), pass, fail, "icosphere low band: ALL contours CLOSED" as *u8)
79 slice_stats(sp, 163840, st) // equator (widest)
80 w(" icosphere z=10mm: segs=" as *u8); wn(st[0]); w(" polys=" as *u8); wn(st[1]); w(" open=" as *u8); wn(st[2]); w("\n" as *u8)
81 chk(eqi(st[2], 0), pass, fail, "icosphere equator: ALL contours CLOSED" as *u8)
82 slice_stats(sp, 245760, st) // upper band
83 chk(eqi(st[2], 0), pass, fail, "icosphere high band: ALL contours CLOSED" as *u8)
84
85 // CUBE: must still be watertight (regression guard for the BVH change).
86 let cu: *NxMesh = nx_mesh_make_cube(163840, 0)
87 nx_mesh_translate(cu, 0, 0, 163840)
88 slice_stats(cu, 81920, st)
89 chk(eqi(st[2], 0), pass, fail, "cube still watertight (BVH-change regression guard)" as *u8)
90
91 w("=== VERDICT pass=" as *u8); wn(pass[0]); w(" fail=" as *u8); wn(fail[0]); w(" ===\n" as *u8)
92 if fail[0] == 0 { return 0 }
93 return 1
94}