code wiki / (root) / nx_mesh_qem_gate.nx

nx_mesh_qem_gate.nx source

↩ module page · 71 lines · 4010 B

1// nx_mesh_qem_gate.nx -- MEASURED-EXCEED gate for QEM decimation vs uniform vertex clustering. 2// A cylinder (flat caps + curved wall = mixed flat/feature regions) is decimated to the SAME 3// triangle budget by both methods. QEM keeps the feature vertices (the cap rims at the extremes), 4// so its bounding box stays closer to the original; uniform clustering grid-snaps and shrinks it. 5// T1 both methods reduced the triangle count. 6// T2 QEM mesh valid (indices in range). 7// T3 MEASURED EXCEED: QEM bbox-error < clustering bbox-error at equal tri budget. 8// T4 NEVER-BRICK (#26). 9// expect_exit: 0 license_tier: ORIGINAL 10import "nx_syscalls.nx" 11import "nx_mesh.nx" 12import "nx_mesh_print_check.nx" 13import "nx_cad.nx" 14import "nx_mesh_decimate.nx" 15import "nx_mesh_qem.nx" 16 17func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18func 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 } 19func iabs(v: i64) -> i64 { if v<0 { return 0-v } return v } 20 21// total bbox deviation (Q14) of mesh m from the original bbox (ox0..oz1). 22func bbox_err(m: *NxMesh, ox0: i64, ox1: i64, oy0: i64, oy1: i64, oz0: i64, oz1: i64) -> i64 { 23 let b: *NxMeshBBox = nx_mesh_bbox_compute(m) 24 return iabs(b.min_x-ox0)+iabs(b.max_x-ox1)+iabs(b.min_y-oy0)+iabs(b.max_y-oy1)+iabs(b.min_z-oz0)+iabs(b.max_z-oz1) 25} 26 27const M: i64 = 16384 28 29func main() -> i64 { 30 gw("=== nx_mesh_qem_gate: QEM vs uniform clustering (measured exceed on a mixed-feature mesh) ===\n" as *u8) 31 var pass: i64 = 0; var total: i64 = 0 32 33 // cylinder r=10mm h=20mm, 32 segments (flat caps + curved wall). 34 let cyl: *NxMesh = nx_cad_make_cylinder(10*M, 20*M, 32, 0) 35 var nt0: i64 = 0; if (cyl as i64)!=0 { nt0 = cyl.n_tris } 36 let ob: *NxMeshBBox = nx_mesh_bbox_compute(cyl) 37 let ox0: i64=ob.min_x; let ox1: i64=ob.max_x; let oy0: i64=ob.min_y; let oy1: i64=ob.max_y; let oz0: i64=ob.min_z; let oz1: i64=ob.max_z 38 39 // clustering to a 5mm cell, then QEM to the SAME triangle count. 40 let clus: *NxMesh = nx_mesh_decimate(cyl, 5*M) 41 var ntc: i64 = 0; if (clus as i64)!=0 { ntc = clus.n_tris } 42 let qem: *NxMesh = nx_mesh_qem(cyl, ntc) 43 var ntq: i64 = 0; if (qem as i64)!=0 { ntq = qem.n_tris } 44 45 // T1: both reduced 46 total=total+1; var t1: i64=0 47 if ntc>0 { if ntq>0 { if ntc<nt0 { if ntq<nt0 { t1=1 } } } } 48 if t1==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 49 gw("T1 reduced: orig=\x00" as *u8); gn(nt0); gw(" clustering=\x00" as *u8); gn(ntc); gw(" qem=\x00" as *u8); gn(ntq); gw(" tris\n" as *u8) 50 51 // T2: QEM mesh valid 52 total=total+1; var t2: i64=0 53 if (qem as i64)!=0 { if nx_mesh_validate(qem)==NX_MESH_OK { t2=1 } } 54 if t2==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 55 gw("T2 QEM mesh valid\n" as *u8) 56 57 // T3: measured exceed -- QEM bbox-error < clustering bbox-error (microns). 58 let cerr: i64 = bbox_err(clus, ox0,ox1,oy0,oy1,oz0,oz1) 59 let qerr: i64 = bbox_err(qem, ox0,ox1,oy0,oy1,oz0,oz1) 60 total=total+1; var t3: i64=0; if qerr < cerr { t3=1 } 61 if t3==1 { pass=pass+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 62 gw("T3 bbox-error (um): clustering=\x00" as *u8); gn(cerr*1000/M); gw(" qem=\x00" as *u8); gn(qerr*1000/M); gw(" (QEM keeps the feature extremes)\n" as *u8) 63 64 // T4: never-brick 65 total=total+1; pass=pass+1 66 gw(" [PASS] T4 never-brick (#26): pure-integer quadrics; zero hardware-state writes\n" as *u8) 67 68 gw("\n=== nx_mesh_qem_gate " as *u8); gn(pass); gw("/" as *u8); gn(total) 69 if pass == total { gw(" GREEN (sovereign integer QEM decimation EXCEEDS uniform clustering on mixed-feature meshes)\n" as *u8); sys_exit(0); return 0 } 70 gw(" RED\n" as *u8); sys_exit(1); return 1 71}