code wiki / (root) / nx_meshthick.nx

nx_meshthick.nx source

↩ module page · 160 lines · 6811 B

1// nx_meshthick.nx -- R5 of the CAD car-twin ladder (cadtwin P6a): MESH WALL-THICKNESS by ray-casting (the 2// GOM/ZEISS-INSPECT "ray method"), the GEOMETRIC half of "identify underbuilt parts when flipping cars" 3// (R6 nx_underbuilt_board is the DATA half). For each triangle face: from its centroid, cast a ray along the 4// INWARD normal and find the nearest OTHER face -> that hit distance is the local wall thickness. The MIN over 5// all faces = the thinnest wall = the underbuilt candidate. A data-driven THRESHOLD (passed in, never 6// hardcoded) classifies a part OK vs UNDERBUILT. All fixed-point fx256 (256 = 1.0), deterministic. Composes 7// nx_mesh3 (real tri-mesh + STL interchange). Ray-triangle = Moller-Trumbore, KAT-gated. license_tier: ORIGINAL 8import "nx_mesh3.nx" 9 10const MTK_ONE: i64 = 256 // 1.0 in fx256 11const MTK_EPS: i64 = 64 // 0.25 real: skip self/coplanar hits (t must exceed this) 12const MTK_BIG: i64 = 4611686018427387904 // "no hit" sentinel thickness 13 14func mtk_fxmul(a: i64, b: i64) -> i64 { return (a * b) / MTK_ONE } 15func mtk_fxdiv(a: i64, b: i64) -> i64 { if b == 0 { return 0 } return (a * MTK_ONE) / b } 16func mtk_abs(a: i64) -> i64 { if a < 0 { return 0 - a } return a } 17 18// integer sqrt (Newton) on a plain (non-fx) magnitude 19func mtk_isqrt(n: i64) -> i64 { 20 if n <= 0 { return 0 } 21 var x: i64 = n 22 var y: i64 = (x + 1) / 2 23 while y < x { x = y; y = (x + n / x) / 2 } 24 return x 25} 26 27// Moller-Trumbore ray/triangle. orig/dir + tri verts all fx256; dir is a UNIT fx256 vector (|dir|=256). 28// Returns hit distance t in fx256 (>0), or -1 on miss/parallel/behind. u,v barycentric checked in [0,256]. 29func mtk_ray_tri(ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, 30 ax: i64, ay: i64, az: i64, bx: i64, by: i64, bz: i64, cx: i64, cy: i64, cz: i64) -> i64 { 31 let e1x: i64 = bx - ax 32 let e1y: i64 = by - ay 33 let e1z: i64 = bz - az 34 let e2x: i64 = cx - ax 35 let e2y: i64 = cy - ay 36 let e2z: i64 = cz - az 37 // h = dir x e2 38 let hx: i64 = mtk_fxmul(dy, e2z) - mtk_fxmul(dz, e2y) 39 let hy: i64 = mtk_fxmul(dz, e2x) - mtk_fxmul(dx, e2z) 40 let hz: i64 = mtk_fxmul(dx, e2y) - mtk_fxmul(dy, e2x) 41 // a = e1 . h (determinant) 42 let det: i64 = mtk_fxmul(e1x, hx) + mtk_fxmul(e1y, hy) + mtk_fxmul(e1z, hz) 43 if mtk_abs(det) < 1 { return 0 - 1 } // ray parallel to triangle 44 // s = orig - a 45 let sx: i64 = ox - ax 46 let sy: i64 = oy - ay 47 let sz: i64 = oz - az 48 // u = (s . h) / det -> barycentric in fx256 [0,256] 49 let su: i64 = mtk_fxmul(sx, hx) + mtk_fxmul(sy, hy) + mtk_fxmul(sz, hz) 50 let u: i64 = mtk_fxdiv(su, det) 51 if u < 0 { return 0 - 1 } 52 if u > MTK_ONE { return 0 - 1 } 53 // q = s x e1 54 let qx: i64 = mtk_fxmul(sy, e1z) - mtk_fxmul(sz, e1y) 55 let qy: i64 = mtk_fxmul(sz, e1x) - mtk_fxmul(sx, e1z) 56 let qz: i64 = mtk_fxmul(sx, e1y) - mtk_fxmul(sy, e1x) 57 // v = (dir . q) / det 58 let sv: i64 = mtk_fxmul(dx, qx) + mtk_fxmul(dy, qy) + mtk_fxmul(dz, qz) 59 let v: i64 = mtk_fxdiv(sv, det) 60 if v < 0 { return 0 - 1 } 61 if u + v > MTK_ONE { return 0 - 1 } 62 // t = (e2 . q) / det 63 let st: i64 = mtk_fxmul(e2x, qx) + mtk_fxmul(e2y, qy) + mtk_fxmul(e2z, qz) 64 let t: i64 = mtk_fxdiv(st, det) 65 if t < MTK_EPS { return 0 - 1 } 66 return t 67} 68 69// nearest hit of ray (orig,dir) against every mesh triangle EXCEPT skip_tri; -1 if none. dir is UNIT fx256. 70func mtk_cast(base: i64, ox: i64, oy: i64, oz: i64, dx: i64, dy: i64, dz: i64, skip_tri: i64) -> i64 { 71 let h: *i64 = m3_hdr(base) 72 var best: i64 = 0 - 1 73 var ti: i64 = 0 74 while ti < h[1] { 75 if ti != skip_tri { 76 let t: *i64 = m3_tri(base, ti) 77 let va: *i64 = m3_vert(base, t[0]) 78 let vb: *i64 = m3_vert(base, t[1]) 79 let vc: *i64 = m3_vert(base, t[2]) 80 let hit: i64 = mtk_ray_tri(ox, oy, oz, dx, dy, dz, 81 va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]) 82 if hit > 0 { 83 if best < 0 { best = hit } else { if hit < best { best = hit } } 84 } 85 } 86 ti = ti + 1 87 } 88 return best 89} 90 91// unit fx256 outward normal of triangle ti into out3 (from winding v0->v1->v2, right-handed) 92func mtk_face_normal(base: i64, ti: i64, out3: *i64) -> i64 { 93 let t: *i64 = m3_tri(base, ti) 94 let va: *i64 = m3_vert(base, t[0]) 95 let vb: *i64 = m3_vert(base, t[1]) 96 let vc: *i64 = m3_vert(base, t[2]) 97 let e1x: i64 = vb[0] - va[0] 98 let e1y: i64 = vb[1] - va[1] 99 let e1z: i64 = vb[2] - va[2] 100 let e2x: i64 = vc[0] - va[0] 101 let e2y: i64 = vc[1] - va[1] 102 let e2z: i64 = vc[2] - va[2] 103 let nx: i64 = e1y * e2z - e1z * e2y 104 let ny: i64 = e1z * e2x - e1x * e2z 105 let nz: i64 = e1x * e2y - e1y * e2x 106 let mag: i64 = mtk_isqrt(nx * nx + ny * ny + nz * nz) 107 if mag == 0 { out3[0] = 0; out3[1] = 0; out3[2] = 0; return 0 - 1 } 108 out3[0] = (nx * MTK_ONE) / mag 109 out3[1] = (ny * MTK_ONE) / mag 110 out3[2] = (nz * MTK_ONE) / mag 111 return 0 112} 113 114// centroid (fx256) of triangle ti into out3 115func mtk_centroid(base: i64, ti: i64, out3: *i64) -> i64 { 116 let t: *i64 = m3_tri(base, ti) 117 let va: *i64 = m3_vert(base, t[0]) 118 let vb: *i64 = m3_vert(base, t[1]) 119 let vc: *i64 = m3_vert(base, t[2]) 120 out3[0] = (va[0] + vb[0] + vc[0]) / 3 121 out3[1] = (va[1] + vb[1] + vc[1]) / 3 122 out3[2] = (va[2] + vb[2] + vc[2]) / 3 123 return 0 124} 125 126// local wall thickness at face ti: cast INWARD (-normal); if no hit, try +normal (winding-robust). fx256, -1 none. 127func mtk_face_thickness(base: i64, ti: i64) -> i64 { 128 let n3: *i64 = sys_mmap(32) as *i64 129 let c3: *i64 = sys_mmap(32) as *i64 130 if mtk_face_normal(base, ti, n3) < 0 { return 0 - 1 } 131 mtk_centroid(base, ti, c3) 132 // inward = -normal 133 let t1: i64 = mtk_cast(base, c3[0], c3[1], c3[2], 0 - n3[0], 0 - n3[1], 0 - n3[2], ti) 134 if t1 > 0 { return t1 } 135 let t2: i64 = mtk_cast(base, c3[0], c3[1], c3[2], n3[0], n3[1], n3[2], ti) 136 return t2 137} 138 139// MIN wall thickness over all faces (fx256); argmin face index into out_face[0]; -1 if unmeasurable 140func mtk_min_thickness(base: i64, out_face: *i64) -> i64 { 141 let h: *i64 = m3_hdr(base) 142 var best: i64 = MTK_BIG 143 var bestf: i64 = 0 - 1 144 var ti: i64 = 0 145 while ti < h[1] { 146 let th: i64 = mtk_face_thickness(base, ti) 147 if th > 0 { if th < best { best = th; bestf = ti } } 148 ti = ti + 1 149 } 150 out_face[0] = bestf 151 if bestf < 0 { return 0 - 1 } 152 return best 153} 154 155// data-driven underbuilt classification: 1 = UNDERBUILT (thinner than threshold), 0 = OK. threshold fx256. 156func mtk_is_underbuilt(min_thick: i64, threshold_fx: i64) -> i64 { 157 if min_thick < 0 { return 0 - 1 } // unmeasurable 158 if min_thick < threshold_fx { return 1 } 159 return 0 160}