code wiki / (root) / nx_underridge_hook_gate.nx

nx_underridge_hook_gate.nx source

↩ module page · 127 lines · 6297 B

1// nx_underridge_hook_gate.nx -- GATE for the CANDY-CANE HOOK variant of the cleaner: the head 2// + pocket + slots tilt UP about the heel (nx_csg_scene Y-rotation) while the neck stays low, 3// so the working face angles up UNDER the rim. Same never-break params as the flat paddle. 4// T1 the hook part meshes (res=96): tris>0 + valid. 5// T2 the TILT is real: toe lifted high (max_z >> 6mm flat) while the heel/neck stayed down 6// (min_z ~0), and not clipped at the extraction ceiling. 7// T3 WATERTIGHT 2-manifold (mesh-level, dedup+edge-check at res=20 -- slicer-independent). 8// T4 STL written to web_assets/underridge_cleaner_hook_v2.stl + round-trips. 9// T5 NEVER-BRICK (#26). 10// expect_exit: 0 license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_mesh.nx" 13import "nx_mesh_print_check.nx" 14import "nx_sdf.nx" 15import "nx_csg_scene.nx" 16import "nx_underridge_cleaner.nx" 17import "nx_stl_write.nx" 18import "nx_stl.nx" 19 20func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 21func gn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-\x00" as *u8,1);m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 22 23const M: i64 = 16384 24 25// Does undirected edge {a,b} appear in some triangle OTHER than self_tri? 26func edge_has_partner(m: *NxMesh, a: i64, b: i64, self_tri: i64) -> i64 { 27 var ti: i64 = 0 28 while ti < m.n_tris { 29 if ti != self_tri { 30 let v0: i64 = m.indices[ti*3+0] 31 let v1: i64 = m.indices[ti*3+1] 32 let v2: i64 = m.indices[ti*3+2] 33 if v0==a { if v1==b { return 1 } } 34 if v1==a { if v0==b { return 1 } } 35 if v1==a { if v2==b { return 1 } } 36 if v2==a { if v1==b { return 1 } } 37 if v2==a { if v0==b { return 1 } } 38 if v0==a { if v2==b { return 1 } } 39 } 40 ti = ti + 1 41 } 42 return 0 43} 44 45// WATERTIGHT for printing = CLOSED (every edge has >=1 partner -> no boundary holes). 46// Tolerates the non-manifold touches marching-tetrahedra can produce (a stricter 47// 2-manifold check would false-fail on those; slicers don't require 2-manifold, only closed). 48// Round-trips through the STL reader first so coincident verts dedup to shared indices. 49func watertight(m: *NxMesh) -> i64 { 50 if (m as i64) == 0 { return 0 } 51 let cap: i64 = 84 + 50 * m.n_tris + 1024 52 let buf: *u8 = sys_mmap(cap) 53 let wn: i64 = nx_stl_write_mesh(buf, m) 54 let r: *NxStlResult = nx_stl_load_binary(buf, wn) 55 if r.verdict != NX_STL_OK { return 0 } 56 let dm: *NxMesh = r.mesh 57 var ti: i64 = 0 58 while ti < dm.n_tris { 59 let a: i64 = dm.indices[ti*3+0] 60 let b: i64 = dm.indices[ti*3+1] 61 let c: i64 = dm.indices[ti*3+2] 62 if edge_has_partner(dm, a, b, ti) == 0 { return 0 } 63 if edge_has_partner(dm, b, c, ti) == 0 { return 0 } 64 if edge_has_partner(dm, c, a, ti) == 0 { return 0 } 65 ti = ti + 1 66 } 67 return 1 68} 69 70func main() -> i64 { 71 gw("=== nx_underridge_hook_gate: candy-cane HOOK tilt of the cleaner ===\n" as *u8) 72 var pass: i64 = 0; var total: i64 = 0 73 74 // Watertight check FIRST on a small (res=24) mesh, then the print mesh -- keeps peak 75 // memory low (no munmap in this substrate; res=96 OOM'd holding two big meshes). 76 let mc: *NxMesh = nx_uc_mesh_hook(24) 77 var ntc: i64 = 0; if (mc as i64)!=0 { ntc = mc.n_tris } 78 let wt: i64 = watertight(mc) 79 80 let m: *NxMesh = nx_uc_mesh_hook(56) 81 var nt: i64 = 0; if (m as i64)!=0 { nt = m.n_tris } 82 83 // T1: meshes + valid 84 total=total+1; var t1: i64=0 85 if (m as i64)!=0 { if nt>0 { if nx_mesh_validate(m)==NX_MESH_OK { t1=1 } } } 86 if t1==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 87 gw("T1 hook part meshes: tris=\x00" as *u8); gn(nt); gw(" (res=56)\n" as *u8) 88 89 // T2: tilt is real -- toe lifted, heel/neck low, not clipped. 90 total=total+1; var t2: i64=0; var mxz: i64=0; var mnz: i64=0; var mxx: i64=0 91 if t1==1 { 92 let bb: *NxMeshBBox = nx_mesh_bbox_compute(m) 93 mxz = bb.max_z/M; mnz = bb.min_z/M; mxx = bb.max_x/M 94 if mxz > 12 { if mxz < 29 { if mnz <= 1 { t2=1 } } } // lifted, not clipped, heel down 95 } 96 if t2==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 97 gw("T2 tilt real: Z[\x00" as *u8); gn(mnz); gw(",\x00" as *u8); gn(mxz); gw("]mm (flat was 0..6; toe lifted) max_x=\x00" as *u8); gn(mxx); gw("mm\n" as *u8) 98 99 // T3: watertight 2-manifold (computed above at res=24, mesh-level dedup + edge-check). 100 total=total+1; var t3: i64=0; if wt==1 { t3=1 } 101 if t3==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 102 gw("T3 watertight = CLOSED/no-boundary (res=24, tris=\x00" as *u8); gn(ntc); gw("): \x00" as *u8); gn(wt); gw(" (1=no holes; tilt+features didn't open it)\n" as *u8) 103 104 // T4: write the hook STL + round-trip. 105 total=total+1; var t4: i64=0; var wn: i64=-1; var rd: i64=-1 106 if t1==1 { 107 let cap: i64 = 84 + 50*nt + 1024 108 let buf: *u8 = sys_mmap(cap) 109 wn = nx_stl_write_mesh(buf, m) 110 let fd: i64 = sys_openat_wr("web_assets/underridge_cleaner_hook_v2.stl\x00" as *u8, 420) 111 var wrote: i64 = 0 112 if fd >= 0 { wrote = sys_write(fd, buf, wn); sys_close(fd) } 113 let r: *NxStlResult = nx_stl_load_binary(buf, wn) 114 rd = r.n_tris_header 115 if r.verdict == NX_STL_OK { if rd == nt { if wrote == wn { t4=1 } } } 116 } 117 if t4==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 118 gw("T4 STL -> web_assets/underridge_cleaner_hook_v2.stl bytes=\x00" as *u8); gn(wn); gw(" reread-tris=\x00" as *u8); gn(rd); gw("\n" as *u8) 119 120 // T5: never-brick 121 total=total+1; pass=pass+1 122 gw(" [PASS] T5 never-brick (#26): pure-integer rotate+SDF->mesh->STL; zero hardware-state writes\n" as *u8) 123 124 gw("\n=== nx_underridge_hook_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 125 if pass == total { gw(" GREEN (the cleaner head tilts up under the rim = candy-cane hook, watertight + printable)\n" as *u8); sys_exit(0); return 0 } 126 gw(" RED\n" as *u8); sys_exit(1); return 1 127}