code wiki / _hdl_build / nx_meshdist.nx

nx_meshdist.nx source

↩ module page · 904 lines · 35829 B

1// nx_meshdist.nx -- THE METRIC GAP RULER (form ladder 1785935557; operator 2026-08-05: measure the gap 2// between two objects below the millimetre -- bodies today, screw-to-screw tomorrow). 3// Bidirectional point-to-surface distance between two NXMSH2 meshes, the METRO / DTU convention done 4// sovereignly: candidate->oracle = ACCURACY, oracle->candidate = COMPLETENESS (one direction alone is 5// gameable: a sphere inside the body has perfect accuracy and no completeness). Reported per direction: 6// mean / rms / p95 (the medical HD95) / max, in MICROMETRES, plus F-score-style fractions within 1mm and 7// 0.5mm (the Tanks-and-Temples F@tau shape). All integer math in 10um quanta -- products stay inside i64 8// by construction (coords <= ~2e5 q, near-cell evaluation bounds |p-a|), so the quantisation floor is 9// 10um, declared in the output. Screws and finer work pass a tighter unit via a future scale arg. 10// ALIGNMENT (declared, never silent): candidate is translated centroid-to-centroid and uniformly scaled 11// by the bbox-height ratio (permil printed). No rotation search in v1 -- both estates' bodies stand y-up. 12// Sampling v1: every k-th triangle CENTROID, k chosen to cap samples (bias declared; area-weighted 13// sampling is the named v2 rung). 14// nx_meshdist <cand.nxmesh> <oracle.nxmesh> [samples] | selftest 15// license_tier: ORIGINAL expect_exit: 0 16import "nx_syscalls.nx" 17 18const MD_CAP: i64 = 16777216 19const MD_MAXTRI: i64 = 400000 20const MD_GRID: i64 = 48 21const MD_MAXSAMP: i64 = 16384 22const MD_HISTMAX: i64 = 65536 23const MD_Q_PER_MM: i64 = 100 24const MD_UM_PER_Q: i64 = 10 25const MD_M8388607: i64 = 8388607 26const MD_M8388608: i64 = 8388608 27const MD_FARQ: i64 = 60000 28const MD_BIG: i64 = 4611686018427387903 29 30func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 31func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 32func md_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64) + ((b[o+1] as i64)<<8) + ((b[o+2] as i64)<<16) + ((b[o+3] as i64)<<24) } 33// IEEE754 f32 (millimetres) -> integer 10um quanta (value*100) 34func md_f32q(w: i64) -> i64 { 35 let sign: i64 = (w >> 31) & 1 36 let expo: i64 = (w >> 23) & 255 37 if expo == 0 { return 0 } 38 var mant: i64 = (w & MD_M8388607) | MD_M8388608 39 let sh: i64 = expo - 127 40 var v: i64 = 0 41 if sh >= 23 { if sh - 23 > 30 { return 0 } } 42 if sh >= 23 { v = mant * MD_Q_PER_MM * (1 << (sh - 23)) } 43 if sh < 23 { if 23 - sh > 62 { return 0 } } 44 if sh < 23 { v = (mant * MD_Q_PER_MM) >> (23 - sh) } 45 if sign == 1 { return 0 - v } 46 return v 47} 48func md_isqrt(x: i64) -> i64 { 49 if x <= 0 { return 0 } 50 var r: i64 = x 51 var q: i64 = (x/2) + 1 52 while q < r { r = q; q = (r + x/r)/2 } 53 return r 54} 55func md_refuse(reason: *u8) -> i64 { hw("MESHDIST REFUSED: " as *u8); hw(reason); hw("\n" as *u8); return 0 } 56 57// load an NXMSH2 into vx (9 coords per tri, q10um). returns ntris or -1. 58func md_load(path: *u8, vx: *i64) -> i64 { 59 let fd: i64 = sys_openat_rd(path) 60 if fd < 0 { return 0 - 1 } 61 let b: *u8 = sys_mmap(MD_CAP + 64) 62 var n: i64 = 0 63 var go: i64 = 1 64 while go == 1 { 65 let r: i64 = sys_read(fd, ((b as i64) + n) as *u8, MD_CAP - n) 66 if r <= 0 { go = 0 } else { n = n + r } 67 if n >= MD_CAP { go = 0 } 68 } 69 sys_close(fd) 70 if n < 44 { return 0 - 1 } 71 if b[0] != (78 as u8) { return 0 - 1 } 72 if b[5] != (50 as u8) { return 0 - 1 } 73 let nlay: i64 = md_u32(b, 8) 74 let nt: i64 = md_u32(b, 12) 75 if nt <= 0 { return 0 - 1 } 76 if nt > MD_MAXTRI { return 0 - 1 } 77 let hdr: i64 = 16 + nlay*24 78 if hdr + nt*84 > n { return 0 - 1 } 79 var t: i64 = 0 80 while t < nt { 81 var c: i64 = 0 82 while c < 9 { vx[t*9+c] = md_f32q(md_u32(b, hdr + t*84 + c*4)); c = c + 1 } 83 t = t + 1 84 } 85 return nt 86} 87 88// squared distance point->triangle, all q10um (Ericson clamp; t in 1/16384) 89func md_pt(px: i64, py: i64, pz: i64, v: *i64, o: i64) -> i64 { 90 let ax: i64 = v[o] 91 let ay: i64 = v[o+1] 92 let az: i64 = v[o+2] 93 var abx: i64 = v[o+3]-ax 94 var aby: i64 = v[o+4]-ay 95 var abz: i64 = v[o+5]-az 96 var acx: i64 = v[o+6]-ax 97 var acy: i64 = v[o+7]-ay 98 var acz: i64 = v[o+8]-az 99 var apx: i64 = px-ax 100 var apy: i64 = py-ay 101 var apz: i64 = pz-az 102 // far guard: beyond ~6m component the exact solve could overflow -- return a conservative vertex bound 103 if apx > MD_FARQ { return MD_BIG/4 } 104 if apx < 0-MD_FARQ { return MD_BIG/4 } 105 if apy > MD_FARQ { return MD_BIG/4 } 106 if apy < 0-MD_FARQ { return MD_BIG/4 } 107 if apz > MD_FARQ { return MD_BIG/4 } 108 if apz < 0-MD_FARQ { return MD_BIG/4 } 109 let d1: i64 = abx*apx + aby*apy + abz*apz 110 let d2: i64 = acx*apx + acy*apy + acz*apz 111 var cx: i64 = 0 112 var cy: i64 = 0 113 var cz: i64 = 0 114 var done: i64 = 0 115 if d1 <= 0 { if d2 <= 0 { cx = ax; cy = ay; cz = az; done = 1 } } 116 let bpx: i64 = px-v[o+3] 117 let bpy: i64 = py-v[o+4] 118 let bpz: i64 = pz-v[o+5] 119 let d3: i64 = abx*bpx + aby*bpy + abz*bpz 120 let d4: i64 = acx*bpx + acy*bpy + acz*bpz 121 if done == 0 { if d3 >= 0 { if d4 <= d3 { cx = v[o+3]; cy = v[o+4]; cz = v[o+5]; done = 1 } } } 122 if done == 0 { 123 let vc: i64 = d1*d4 - d3*d2 124 if vc <= 0 { if d1 >= 0 { if d3 <= 0 { 125 var den: i64 = d1 - d3 126 if den == 0 { den = 1 } 127 let t1: i64 = d1*16384/den 128 cx = ax + abx*t1/16384; cy = ay + aby*t1/16384; cz = az + abz*t1/16384; done = 1 129 } } } 130 } 131 let cpx: i64 = px-v[o+6] 132 let cpy: i64 = py-v[o+7] 133 let cpz: i64 = pz-v[o+8] 134 let d5: i64 = abx*cpx + aby*cpy + abz*cpz 135 let d6: i64 = acx*cpx + acy*cpy + acz*cpz 136 if done == 0 { if d6 >= 0 { if d5 <= d6 { cx = v[o+6]; cy = v[o+7]; cz = v[o+8]; done = 1 } } } 137 if done == 0 { 138 let vb: i64 = d5*d2 - d1*d6 139 if vb <= 0 { if d2 >= 0 { if d6 <= 0 { 140 var den2: i64 = d2 - d6 141 if den2 == 0 { den2 = 1 } 142 let t2: i64 = d2*16384/den2 143 cx = ax + acx*t2/16384; cy = ay + acy*t2/16384; cz = az + acz*t2/16384; done = 1 144 } } } 145 } 146 if done == 0 { 147 let va: i64 = d3*d6 - d5*d4 148 if va <= 0 { if d4 - d3 >= 0 { if d5 - d6 >= 0 { 149 var den3: i64 = (d4-d3) + (d5-d6) 150 if den3 == 0 { den3 = 1 } 151 let t3: i64 = (d4-d3)*16384/den3 152 cx = v[o+3] + (v[o+6]-v[o+3])*t3/16384 153 cy = v[o+4] + (v[o+7]-v[o+4])*t3/16384 154 cz = v[o+5] + (v[o+8]-v[o+5])*t3/16384 155 done = 1 156 } } } 157 if done == 0 { 158 // range-reduce before the fixed-point: on a 100mm tri va/vb/vc ~ 3e15 and *16384 overflows i64 159 // (caught by the selftest fixture 2026-08-05); shifting all three together preserves the ratio 160 var vbn: i64 = d5*d2 - d1*d6 161 var vcn: i64 = d1*d4 - d3*d2 162 var den4: i64 = va + vbn + vcn 163 if den4 == 0 { den4 = 1 } 164 while den4 > 549755813888 { vbn = vbn/1024; vcn = vcn/1024; den4 = den4/1024; if den4 == 0 { den4 = 1 } } 165 while den4 < 0-549755813888 { vbn = vbn/1024; vcn = vcn/1024; den4 = den4/1024; if den4 == 0 { den4 = 1 } } 166 let vv: i64 = vbn*16384/den4 167 let ww: i64 = vcn*16384/den4 168 cx = ax + abx*vv/16384 + acx*ww/16384 169 cy = ay + aby*vv/16384 + acy*ww/16384 170 cz = az + abz*vv/16384 + acz*ww/16384 171 done = 1 172 } 173 } 174 let dx: i64 = px-cx 175 let dy: i64 = py-cy 176 let dz: i64 = pz-cz 177 return dx*dx + dy*dy + dz*dz 178} 179 180// ---- grid over the target mesh ---- 181static MD_GX0: i64 182static MD_GY0: i64 183static MD_GZ0: i64 184static MD_CS: i64 185func md_cell(v: i64, g0: i64) -> i64 { 186 var c: i64 = (v - g0)/MD_CS 187 if c < 0 { c = 0 } 188 if c >= MD_GRID { c = MD_GRID-1 } 189 return c 190} 191// build cell lists: cnt/start (MD_GRID^3) + refs. returns nrefs. 192func md_grid(v: *i64, nt: i64, start: *i64, refs: *i64, maxrefs: i64) -> i64 { 193 var mnx: i64 = MD_BIG 194 var mny: i64 = MD_BIG 195 var mnz: i64 = MD_BIG 196 var mxx: i64 = 0-MD_BIG 197 var mxy: i64 = 0-MD_BIG 198 var mxz: i64 = 0-MD_BIG 199 var t: i64 = 0 200 while t < nt { 201 var c: i64 = 0 202 while c < 3 { 203 let x: i64 = v[t*9+c*3] 204 let y: i64 = v[t*9+c*3+1] 205 let z: i64 = v[t*9+c*3+2] 206 if x < mnx { mnx = x } 207 if x > mxx { mxx = x } 208 if y < mny { mny = y } 209 if y > mxy { mxy = y } 210 if z < mnz { mnz = z } 211 if z > mxz { mxz = z } 212 c = c + 1 213 } 214 t = t + 1 215 } 216 var ext: i64 = mxx - mnx 217 if mxy - mny > ext { ext = mxy - mny } 218 if mxz - mnz > ext { ext = mxz - mnz } 219 MD_CS = ext/MD_GRID + 1 220 MD_GX0 = mnx 221 MD_GY0 = mny 222 MD_GZ0 = mnz 223 let nc: i64 = MD_GRID*MD_GRID*MD_GRID 224 var i: i64 = 0 225 while i <= nc { start[i] = 0; i = i + 1 } 226 // pass 1: counts (into start[c+1]) 227 t = 0 228 while t < nt { 229 // full AABB of the tri, in cells 230 var ax2: i64 = md_cell(v[t*9], MD_GX0) 231 var bx2: i64 = ax2 232 var ay2: i64 = md_cell(v[t*9+1], MD_GY0) 233 var by2: i64 = ay2 234 var az2: i64 = md_cell(v[t*9+2], MD_GZ0) 235 var bz2: i64 = az2 236 var c2: i64 = 1 237 while c2 < 3 { 238 let qx: i64 = md_cell(v[t*9+c2*3], MD_GX0) 239 let qy: i64 = md_cell(v[t*9+c2*3+1], MD_GY0) 240 let qz: i64 = md_cell(v[t*9+c2*3+2], MD_GZ0) 241 if qx < ax2 { ax2 = qx } 242 if qx > bx2 { bx2 = qx } 243 if qy < ay2 { ay2 = qy } 244 if qy > by2 { by2 = qy } 245 if qz < az2 { az2 = qz } 246 if qz > bz2 { bz2 = qz } 247 c2 = c2 + 1 248 } 249 var gx: i64 = ax2 250 while gx <= bx2 { 251 var gy: i64 = ay2 252 while gy <= by2 { 253 var gz: i64 = az2 254 while gz <= bz2 { 255 let cell: i64 = (gx*MD_GRID + gy)*MD_GRID + gz 256 start[cell+1] = start[cell+1] + 1 257 gz = gz + 1 258 } 259 gy = gy + 1 260 } 261 gx = gx + 1 262 } 263 t = t + 1 264 } 265 // prefix 266 i = 0 267 while i < nc { start[i+1] = start[i+1] + start[i]; i = i + 1 } 268 let nrefs: i64 = start[nc] 269 if nrefs > maxrefs { return 0 - 1 } 270 // pass 2: fill (cursor array) 271 let cur: *i64 = sys_mmap((nc+1)*8) as *i64 272 i = 0 273 while i <= nc { cur[i] = start[i]; i = i + 1 } 274 t = 0 275 while t < nt { 276 var ax3: i64 = md_cell(v[t*9], MD_GX0) 277 var bx3: i64 = ax3 278 var ay3: i64 = md_cell(v[t*9+1], MD_GY0) 279 var by3: i64 = ay3 280 var az3: i64 = md_cell(v[t*9+2], MD_GZ0) 281 var bz3: i64 = az3 282 var c3: i64 = 1 283 while c3 < 3 { 284 let rx: i64 = md_cell(v[t*9+c3*3], MD_GX0) 285 let ry: i64 = md_cell(v[t*9+c3*3+1], MD_GY0) 286 let rz: i64 = md_cell(v[t*9+c3*3+2], MD_GZ0) 287 if rx < ax3 { ax3 = rx } 288 if rx > bx3 { bx3 = rx } 289 if ry < ay3 { ay3 = ry } 290 if ry > by3 { by3 = ry } 291 if rz < az3 { az3 = rz } 292 if rz > bz3 { bz3 = rz } 293 c3 = c3 + 1 294 } 295 var hx: i64 = ax3 296 while hx <= bx3 { 297 var hy: i64 = ay3 298 while hy <= by3 { 299 var hz: i64 = az3 300 while hz <= bz3 { 301 let cell2: i64 = (hx*MD_GRID + hy)*MD_GRID + hz 302 refs[cur[cell2]] = t 303 cur[cell2] = cur[cell2] + 1 304 hz = hz + 1 305 } 306 hy = hy + 1 307 } 308 hx = hx + 1 309 } 310 t = t + 1 311 } 312 return nrefs 313} 314 315// nearest squared distance from p to the gridded mesh (expanding shells) 316func md_near(px: i64, py: i64, pz: i64, v: *i64, start: *i64, refs: *i64) -> i64 { 317 let cx: i64 = md_cell(px, MD_GX0) 318 let cy: i64 = md_cell(py, MD_GY0) 319 let cz: i64 = md_cell(pz, MD_GZ0) 320 var best: i64 = MD_BIG 321 var r: i64 = 0 322 var go: i64 = 1 323 while go == 1 { 324 // if the closest possible point in shell r is farther than best -> stop 325 if r > 0 { 326 let ring: i64 = (r-1)*MD_CS 327 if ring*ring > best { go = 0 } 328 } 329 if r >= MD_GRID { go = 0 } 330 if go == 1 { 331 var gx: i64 = cx-r 332 while gx <= cx+r { 333 var gy: i64 = cy-r 334 while gy <= cy+r { 335 var gz: i64 = cz-r 336 while gz <= cz+r { 337 var onshell: i64 = 0 338 if gx == cx-r { onshell = 1 } 339 if gx == cx+r { onshell = 1 } 340 if gy == cy-r { onshell = 1 } 341 if gy == cy+r { onshell = 1 } 342 if gz == cz-r { onshell = 1 } 343 if gz == cz+r { onshell = 1 } 344 if onshell == 1 { if gx >= 0 { if gx < MD_GRID { if gy >= 0 { if gy < MD_GRID { if gz >= 0 { if gz < MD_GRID { 345 let cell: i64 = (gx*MD_GRID + gy)*MD_GRID + gz 346 var k: i64 = start[cell] 347 while k < start[cell+1] { 348 let d2v: i64 = md_pt(px, py, pz, v, refs[k]*9) 349 if d2v < best { best = d2v } 350 k = k + 1 351 } 352 } } } } } } } 353 gz = gz + 1 354 } 355 gy = gy + 1 356 } 357 gx = gx + 1 358 } 359 r = r + 1 360 } 361 } 362 return best 363} 364 365// one direction: samples from src tri centroids -> nearest on dst. prints a JSON fragment. 366func md_dir(label: *u8, src: *i64, ns: i64, dst: *i64, ndst: i64, start: *i64, refs: *i64, want: i64) -> i64 { 367 var stride: i64 = ns/want 368 if stride < 1 { stride = 1 } 369 let hist: *i64 = sys_mmap(MD_HISTMAX*8) as *i64 370 var i: i64 = 0 371 while i < MD_HISTMAX { hist[i] = 0; i = i + 1 } 372 var cnt: i64 = 0 373 var sum: i64 = 0 374 var sum2: i64 = 0 375 var mx: i64 = 0 376 var in1000: i64 = 0 377 var in500: i64 = 0 378 var t: i64 = 0 379 while t < ns { 380 let o: i64 = t*9 381 let px: i64 = (src[o] + src[o+3] + src[o+6])/3 382 let py: i64 = (src[o+1] + src[o+4] + src[o+7])/3 383 let pz: i64 = (src[o+2] + src[o+5] + src[o+8])/3 384 let d2v: i64 = md_near(px, py, pz, dst, start, refs) 385 let dum: i64 = md_isqrt(d2v) * MD_UM_PER_Q 386 cnt = cnt + 1 387 sum = sum + dum 388 sum2 = sum2 + (dum/10)*(dum/10) 389 if dum > mx { mx = dum } 390 if dum <= 1000 { in1000 = in1000 + 1 } 391 if dum <= 500 { in500 = in500 + 1 } 392 var hb: i64 = dum/MD_UM_PER_Q 393 if hb >= MD_HISTMAX { hb = MD_HISTMAX-1 } 394 hist[hb] = hist[hb] + 1 395 t = t + stride 396 } 397 if cnt == 0 { return 0 - 1 } 398 // p95 from histogram 399 var acc: i64 = 0 400 var p95: i64 = 0 401 var hb2: i64 = 0 402 while hb2 < MD_HISTMAX { 403 acc = acc + hist[hb2] 404 if p95 == 0 { if acc*100 >= cnt*95 { p95 = hb2*MD_UM_PER_Q } } 405 hb2 = hb2 + 1 406 } 407 hw("\x22" as *u8); hw(label); hw("\x22:{\x22samples\x22:" as *u8); pn(cnt) 408 hw(",\x22mean_um\x22:" as *u8); pn(sum/cnt) 409 hw(",\x22rms_um\x22:" as *u8); pn(md_isqrt(sum2/cnt)*10) 410 hw(",\x22p95_um\x22:" as *u8); pn(p95) 411 hw(",\x22max_um\x22:" as *u8); pn(mx) 412 hw(",\x22within_1mm_permil\x22:" as *u8); pn(in1000*1000/cnt) 413 hw(",\x22within_0p5mm_permil\x22:" as *u8); pn(in500*1000/cnt) 414 hw("}" as *u8) 415 return 0 416} 417 418func md_run(candp: *u8, oracp: *u8, want: i64) -> i64 { 419 let cv: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 420 let ov: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 421 let nc: i64 = md_load(candp, cv) 422 if nc < 0 { md_refuse("candidate unreadable or not NXMSH2" as *u8); return 3 } 423 let no: i64 = md_load(oracp, ov) 424 if no < 0 { md_refuse("oracle unreadable or not NXMSH2" as *u8); return 3 } 425 // centroid align + height scale (candidate -> oracle frame), declared 426 var csx: i64 = 0 427 var csy: i64 = 0 428 var csz: i64 = 0 429 var cmny: i64 = MD_BIG 430 var cmxy: i64 = 0-MD_BIG 431 var t: i64 = 0 432 while t < nc { 433 csx = csx + cv[t*9] 434 csy = csy + cv[t*9+1] 435 csz = csz + cv[t*9+2] 436 if cv[t*9+1] < cmny { cmny = cv[t*9+1] } 437 if cv[t*9+1] > cmxy { cmxy = cv[t*9+1] } 438 t = t + 1 439 } 440 csx = csx/nc 441 csy = csy/nc 442 csz = csz/nc 443 var osx: i64 = 0 444 var osy: i64 = 0 445 var osz: i64 = 0 446 var omny: i64 = MD_BIG 447 var omxy: i64 = 0-MD_BIG 448 t = 0 449 while t < no { 450 osx = osx + ov[t*9] 451 osy = osy + ov[t*9+1] 452 osz = osz + ov[t*9+2] 453 if ov[t*9+1] < omny { omny = ov[t*9+1] } 454 if ov[t*9+1] > omxy { omxy = ov[t*9+1] } 455 t = t + 1 456 } 457 osx = osx/no 458 osy = osy/no 459 osz = osz/no 460 var ch: i64 = cmxy - cmny 461 if ch < 1 { ch = 1 } 462 var oh: i64 = omxy - omny 463 if oh < 1 { oh = 1 } 464 let scl: i64 = oh*1000/ch 465 t = 0 466 while t < nc { 467 var c: i64 = 0 468 while c < 3 { 469 cv[t*9+c*3] = (cv[t*9+c*3]-csx)*scl/1000 + osx 470 cv[t*9+c*3+1] = (cv[t*9+c*3+1]-csy)*scl/1000 + osy 471 cv[t*9+c*3+2] = (cv[t*9+c*3+2]-csz)*scl/1000 + osz 472 c = c + 1 473 } 474 t = t + 1 475 } 476 let ncell: i64 = MD_GRID*MD_GRID*MD_GRID 477 let startO: *i64 = sys_mmap((ncell+2)*8) as *i64 478 let refsO: *i64 = sys_mmap(MD_MAXTRI*24*8) as *i64 479 if md_grid(ov, no, startO, refsO, MD_MAXTRI*24) < 0 { md_refuse("oracle grid overflow" as *u8); return 4 } 480 hw("{\x22organ\x22:\x22nx_meshdist\x22,\x22quant_um\x22:10,\x22align\x22:\x22centroid+height (no rotation, v1)\x22,\x22scale_permil\x22:" as *u8); pn(scl) 481 hw(",\x22cand_tris\x22:" as *u8); pn(nc) 482 hw(",\x22oracle_tris\x22:" as *u8); pn(no) 483 hw("," as *u8) 484 if md_dir("accuracy_cand_to_oracle" as *u8, cv, nc, ov, no, startO, refsO, want) < 0 { md_refuse("no samples" as *u8); return 5 } 485 hw("," as *u8) 486 let startC: *i64 = sys_mmap((ncell+2)*8) as *i64 487 let refsC: *i64 = sys_mmap(MD_MAXTRI*24*8) as *i64 488 if md_grid(cv, nc, startC, refsC, MD_MAXTRI*24) < 0 { md_refuse("cand grid overflow" as *u8); return 4 } 489 if md_dir("completeness_oracle_to_cand" as *u8, ov, no, cv, nc, startC, refsC, want) < 0 { md_refuse("no samples" as *u8); return 5 } 490 hw(",\x22note\x22:\x22METRO/DTU convention: accuracy+completeness both required; p95=HD95; centroid sampling v1 (area-weighted = named rung)\x22}\n" as *u8) 491 return 0 492} 493 494// integer/scale -> f32 bits (the estate encoder pattern; colours are PER-MILLE by NXMSH2 convention) 495func md_enc(v: i64, scale: i64) -> i64 { 496 if v == 0 { return 0 } 497 var neg: i64 = 0 498 var m: i64 = v 499 if m < 0 { neg = 1; m = 0-m } 500 var e: i64 = 0 501 var num: i64 = m 502 var den: i64 = scale 503 while num >= den*2 { den = den*2; e = e+1 } 504 while num < den { num = num*2; e = e-1 } 505 let frac: i64 = ((num - den)*MD_M8388608)/den 506 var bits: i64 = ((e+127) << 23) | (frac & MD_M8388607) 507 if neg == 1 { bits = bits | (1<<31) } 508 return bits 509} 510func md_w32(b: *u8, o: i64, v: i64) -> i64 { 511 b[o]=(v&255) as u8; b[o+1]=((v>>8)&255) as u8; b[o+2]=((v>>16)&255) as u8; b[o+3]=((v>>24)&255) as u8 512 return 0 513} 514// ---- DEVIATION HEATMAP (the ZEISS-Inspect capability, sovereign; operator research drop 2026-08-05): 515// paint each CANDIDATE triangle by its centroid distance to the oracle, banded green->magenta, into the 516// candidate file itself -- nx_meshview already renders per-tri colour, so the picture ships through the 517// existing viewer untouched. Alignment is used for the DISTANCE only; colours land on the ORIGINAL bytes. 518func md_paint(candp: *u8, oracp: *u8, outp: *u8, band_um: i64) -> i64 { 519 if band_um < 100 { md_refuse("band under 100um is below the quantisation floor -- a sub-quantum band lies" as *u8); return 2 } 520 let fd: i64 = sys_openat_rd(candp) 521 if fd < 0 { md_refuse("candidate unreadable" as *u8); return 3 } 522 let raw: *u8 = sys_mmap(MD_CAP + 64) 523 var n: i64 = 0 524 var go: i64 = 1 525 while go == 1 { 526 let r: i64 = sys_read(fd, ((raw as i64) + n) as *u8, MD_CAP - n) 527 if r <= 0 { go = 0 } else { n = n + r } 528 if n >= MD_CAP { go = 0 } 529 } 530 sys_close(fd) 531 if n < 44 { md_refuse("candidate too small" as *u8); return 3 } 532 if raw[0] != (78 as u8) { md_refuse("candidate not NXMSH2" as *u8); return 3 } 533 let nlay: i64 = md_u32(raw, 8) 534 let nc: i64 = md_u32(raw, 12) 535 if nc <= 0 { md_refuse("candidate empty" as *u8); return 3 } 536 if nc > MD_MAXTRI { md_refuse("candidate over tri cap" as *u8); return 3 } 537 let hdr: i64 = 16 + nlay*24 538 let cv: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 539 var t: i64 = 0 540 while t < nc { 541 var c: i64 = 0 542 while c < 9 { cv[t*9+c] = md_f32q(md_u32(raw, hdr + t*84 + c*4)); c = c + 1 } 543 t = t + 1 544 } 545 let ov: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 546 let no: i64 = md_load(oracp, ov) 547 if no < 0 { md_refuse("oracle unreadable or not NXMSH2" as *u8); return 3 } 548 // align candidate coords to the oracle frame (distance only) 549 var csx: i64 = 0 550 var csy: i64 = 0 551 var csz: i64 = 0 552 var cmny: i64 = MD_BIG 553 var cmxy: i64 = 0-MD_BIG 554 t = 0 555 while t < nc { 556 csx = csx + cv[t*9] 557 csy = csy + cv[t*9+1] 558 csz = csz + cv[t*9+2] 559 if cv[t*9+1] < cmny { cmny = cv[t*9+1] } 560 if cv[t*9+1] > cmxy { cmxy = cv[t*9+1] } 561 t = t + 1 562 } 563 csx = csx/nc 564 csy = csy/nc 565 csz = csz/nc 566 var osx: i64 = 0 567 var osy: i64 = 0 568 var osz: i64 = 0 569 var omny: i64 = MD_BIG 570 var omxy: i64 = 0-MD_BIG 571 t = 0 572 while t < no { 573 osx = osx + ov[t*9] 574 osy = osy + ov[t*9+1] 575 osz = osz + ov[t*9+2] 576 if ov[t*9+1] < omny { omny = ov[t*9+1] } 577 if ov[t*9+1] > omxy { omxy = ov[t*9+1] } 578 t = t + 1 579 } 580 osx = osx/no 581 osy = osy/no 582 osz = osz/no 583 var ch: i64 = cmxy - cmny 584 if ch < 1 { ch = 1 } 585 var oh: i64 = omxy - omny 586 if oh < 1 { oh = 1 } 587 let scl: i64 = oh*1000/ch 588 t = 0 589 while t < nc { 590 var c2: i64 = 0 591 while c2 < 3 { 592 cv[t*9+c2*3] = (cv[t*9+c2*3]-csx)*scl/1000 + osx 593 cv[t*9+c2*3+1] = (cv[t*9+c2*3+1]-csy)*scl/1000 + osy 594 cv[t*9+c2*3+2] = (cv[t*9+c2*3+2]-csz)*scl/1000 + osz 595 c2 = c2 + 1 596 } 597 t = t + 1 598 } 599 let ncell: i64 = MD_GRID*MD_GRID*MD_GRID 600 let startO: *i64 = sys_mmap((ncell+2)*8) as *i64 601 let refsO: *i64 = sys_mmap(MD_MAXTRI*24*8) as *i64 602 if md_grid(ov, no, startO, refsO, MD_MAXTRI*24) < 0 { md_refuse("oracle grid overflow" as *u8); return 4 } 603 let hist: *i64 = sys_mmap(8*8) as *i64 604 var hb: i64 = 0 605 while hb < 5 { hist[hb] = 0; hb = hb + 1 } 606 t = 0 607 while t < nc { 608 let o9: i64 = t*9 609 let px: i64 = (cv[o9] + cv[o9+3] + cv[o9+6])/3 610 let py: i64 = (cv[o9+1] + cv[o9+4] + cv[o9+7])/3 611 let pz: i64 = (cv[o9+2] + cv[o9+5] + cv[o9+8])/3 612 let d2v: i64 = md_near(px, py, pz, ov, startO, refsO) 613 let dum: i64 = md_isqrt(d2v) * MD_UM_PER_Q 614 var band: i64 = dum/band_um 615 if band > 4 { band = 4 } 616 hist[band] = hist[band] + 1 617 var r2: i64 = 100 618 var g2: i64 = 850 619 var b2: i64 = 150 620 if band == 1 { r2 = 900; g2 = 880; b2 = 100 } 621 if band == 2 { r2 = 950; g2 = 550; b2 = 80 } 622 if band == 3 { r2 = 920; g2 = 120; b2 = 80 } 623 if band == 4 { r2 = 850; g2 = 100; b2 = 850 } 624 let co: i64 = hdr + t*84 625 md_w32(raw, co+72, md_enc(r2, 1000)) 626 md_w32(raw, co+76, md_enc(g2, 1000)) 627 md_w32(raw, co+80, md_enc(b2, 1000)) 628 t = t + 1 629 } 630 let ofd: i64 = sys_openat_wr(outp, 420) 631 if ofd < 0 { md_refuse("output unwritable" as *u8); return 6 } 632 sys_write(ofd, raw, n) 633 sys_close(ofd) 634 hw("{\x22organ\x22:\x22nx_meshdist\x22,\x22verb\x22:\x22paint\x22,\x22band_um\x22:" as *u8); pn(band_um) 635 hw(",\x22tris\x22:" as *u8); pn(nc) 636 hw(",\x22bands\x22:{\x22b0_green\x22:" as *u8); pn(hist[0]) 637 hw(",\x22b1_yellow\x22:" as *u8); pn(hist[1]) 638 hw(",\x22b2_orange\x22:" as *u8); pn(hist[2]) 639 hw(",\x22b3_red\x22:" as *u8); pn(hist[3]) 640 hw(",\x22b4_magenta\x22:" as *u8); pn(hist[4]) 641 hw("},\x22permil\x22:[" as *u8); pn(hist[0]*1000/nc) 642 hw("," as *u8); pn(hist[1]*1000/nc) 643 hw("," as *u8); pn(hist[2]*1000/nc) 644 hw("," as *u8); pn(hist[3]*1000/nc) 645 hw("," as *u8); pn(hist[4]*1000/nc) 646 hw("],\x22note\x22:\x22ZEISS-Inspect-class deviation heatmap: candidate painted by distance-to-oracle; the histogram IS the picture in numbers so they can never disagree\x22}\n" as *u8) 647 return 0 648} 649 650// ---- PER-PART TABLE (debt 1785968584): oracle layers are the donor's own named parts, so 651// completeness can be reported PER PART -- 'her left forearm vs ours: N mm'. One candidate grid, 652// then each layer's contiguous tri range is sampled independently. 653func md_parts(candp: *u8, oracp: *u8, want: i64) -> i64 { 654 let cv: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 655 let ov: *i64 = sys_mmap(MD_MAXTRI*9*8 + 64) as *i64 656 let nc: i64 = md_load(candp, cv) 657 if nc < 0 { md_refuse("candidate unreadable or not NXMSH2" as *u8); return 3 } 658 let fd: i64 = sys_openat_rd(oracp) 659 if fd < 0 { md_refuse("oracle unreadable" as *u8); return 3 } 660 let b: *u8 = sys_mmap(MD_CAP + 64) 661 var n: i64 = 0 662 var go: i64 = 1 663 while go == 1 { 664 let r: i64 = sys_read(fd, ((b as i64) + n) as *u8, MD_CAP - n) 665 if r <= 0 { go = 0 } else { n = n + r } 666 if n >= MD_CAP { go = 0 } 667 } 668 sys_close(fd) 669 if n < 44 { md_refuse("oracle too small" as *u8); return 3 } 670 if b[0] != (78 as u8) { md_refuse("oracle not NXMSH2" as *u8); return 3 } 671 let nlay: i64 = md_u32(b, 8) 672 let no: i64 = md_u32(b, 12) 673 if no <= 0 { md_refuse("oracle empty" as *u8); return 3 } 674 if no > MD_MAXTRI { md_refuse("oracle over tri cap" as *u8); return 3 } 675 if nlay < 2 { md_refuse("oracle carries no named parts (single layer) -- run the converter with skinning" as *u8); return 6 } 676 let hdr: i64 = 16 + nlay*24 677 var t: i64 = 0 678 while t < no { 679 var c: i64 = 0 680 while c < 9 { ov[t*9+c] = md_f32q(md_u32(b, hdr + t*84 + c*4)); c = c + 1 } 681 t = t + 1 682 } 683 var csx: i64 = 0 684 var csy: i64 = 0 685 var csz: i64 = 0 686 var cmny: i64 = MD_BIG 687 var cmxy: i64 = 0-MD_BIG 688 t = 0 689 while t < nc { 690 csx = csx + cv[t*9] 691 csy = csy + cv[t*9+1] 692 csz = csz + cv[t*9+2] 693 if cv[t*9+1] < cmny { cmny = cv[t*9+1] } 694 if cv[t*9+1] > cmxy { cmxy = cv[t*9+1] } 695 t = t + 1 696 } 697 csx = csx/nc 698 csy = csy/nc 699 csz = csz/nc 700 var osx: i64 = 0 701 var osy: i64 = 0 702 var osz: i64 = 0 703 var omny: i64 = MD_BIG 704 var omxy: i64 = 0-MD_BIG 705 t = 0 706 while t < no { 707 osx = osx + ov[t*9] 708 osy = osy + ov[t*9+1] 709 osz = osz + ov[t*9+2] 710 if ov[t*9+1] < omny { omny = ov[t*9+1] } 711 if ov[t*9+1] > omxy { omxy = ov[t*9+1] } 712 t = t + 1 713 } 714 osx = osx/no 715 osy = osy/no 716 osz = osz/no 717 var ch: i64 = cmxy - cmny 718 if ch < 1 { ch = 1 } 719 var oh: i64 = omxy - omny 720 if oh < 1 { oh = 1 } 721 let scl: i64 = oh*1000/ch 722 t = 0 723 while t < nc { 724 var c2: i64 = 0 725 while c2 < 3 { 726 cv[t*9+c2*3] = (cv[t*9+c2*3]-csx)*scl/1000 + osx 727 cv[t*9+c2*3+1] = (cv[t*9+c2*3+1]-csy)*scl/1000 + osy 728 cv[t*9+c2*3+2] = (cv[t*9+c2*3+2]-csz)*scl/1000 + osz 729 c2 = c2 + 1 730 } 731 t = t + 1 732 } 733 let ncell: i64 = MD_GRID*MD_GRID*MD_GRID 734 let startC: *i64 = sys_mmap((ncell+2)*8) as *i64 735 let refsC: *i64 = sys_mmap(MD_MAXTRI*24*8) as *i64 736 if md_grid(cv, nc, startC, refsC, MD_MAXTRI*24) < 0 { md_refuse("cand grid overflow" as *u8); return 4 } 737 hw("{\x22organ\x22:\x22nx_meshdist\x22,\x22verb\x22:\x22parts\x22,\x22quant_um\x22:10,\x22scale_permil\x22:" as *u8); pn(scl) 738 hw(",\x22oracle_layers\x22:" as *u8); pn(nlay) 739 hw(",\x22parts\x22:[" as *u8) 740 var first: i64 = 1 741 var L: i64 = 0 742 while L < nlay { 743 let lb: i64 = 16 + L*24 744 let off: i64 = md_u32(b, lb+16) 745 let cnt: i64 = md_u32(b, lb+20) 746 if cnt >= 20 { if off + cnt <= no { 747 var stride: i64 = cnt/want 748 if stride < 1 { stride = 1 } 749 var sum: i64 = 0 750 var mx: i64 = 0 751 var scnt: i64 = 0 752 let hist: *i64 = sys_mmap(4096*8) as *i64 753 var hz: i64 = 0 754 while hz < 4096 { hist[hz] = 0; hz = hz + 1 } 755 var k: i64 = off 756 while k < off + cnt { 757 let o9: i64 = k*9 758 let px: i64 = (ov[o9] + ov[o9+3] + ov[o9+6])/3 759 let py: i64 = (ov[o9+1] + ov[o9+4] + ov[o9+7])/3 760 let pz: i64 = (ov[o9+2] + ov[o9+5] + ov[o9+8])/3 761 let d2v: i64 = md_near(px, py, pz, cv, startC, refsC) 762 let dum: i64 = md_isqrt(d2v) * MD_UM_PER_Q 763 sum = sum + dum 764 if dum > mx { mx = dum } 765 var hb: i64 = dum/1000 766 if hb >= 4096 { hb = 4095 } 767 hist[hb] = hist[hb] + 1 768 scnt = scnt + 1 769 k = k + stride 770 } 771 if scnt > 0 { 772 var acc: i64 = 0 773 var p95: i64 = 0 774 var hb2: i64 = 0 775 while hb2 < 4096 { 776 acc = acc + hist[hb2] 777 if p95 == 0 { if acc*100 >= scnt*95 { p95 = hb2*1000 } } 778 hb2 = hb2 + 1 779 } 780 if first == 0 { hw("," as *u8) } 781 first = 0 782 hw("{\x22part\x22:\x22" as *u8) 783 var q: i64 = 0 784 while q < 16 { let chq: i64 = b[lb+q] as i64; if chq >= 32 { if chq < 127 { sys_write(1, ((b as i64)+lb+q) as *u8, 1) } } q = q + 1 } 785 hw("\x22,\x22tris\x22:" as *u8); pn(cnt) 786 hw(",\x22samples\x22:" as *u8); pn(scnt) 787 hw(",\x22mean_um\x22:" as *u8); pn(sum/scnt) 788 hw(",\x22p95_um\x22:" as *u8); pn(p95) 789 hw(",\x22max_um\x22:" as *u8); pn(mx) 790 hw("}" as *u8) 791 } 792 } } 793 L = L + 1 794 } 795 hw("],\x22note\x22:\x22completeness per named oracle part: distance from HER part to OUR nearest surface; parts under 20 tris skipped\x22}\n" as *u8) 796 return 0 797} 798 799// ---- selftest: literal-only fixture writes (nx_cc wrong-slot bug 1785936860 workaround) ---- 800func md_fix(path: *u8, zoff_f32: i64) -> i64 { 801 let b: *u8 = sys_mmap(256) 802 b[0]=78 as u8; b[1]=88 as u8; b[2]=77 as u8; b[3]=83 as u8 803 b[4]=72 as u8; b[5]=50 as u8; b[6]=0 as u8; b[7]=0 as u8 804 b[8]=1 as u8; b[9]=0 as u8; b[10]=0 as u8; b[11]=0 as u8 805 b[12]=1 as u8; b[13]=0 as u8; b[14]=0 as u8; b[15]=0 as u8 806 var q: i64 = 0 807 while q < 16 { b[16+q] = 0 as u8; q = q + 1 } 808 b[16]=115 as u8; b[17]=107 as u8; b[18]=105 as u8; b[19]=110 as u8 809 b[32]=0 as u8; b[33]=0 as u8; b[34]=0 as u8; b[35]=0 as u8 810 b[36]=1 as u8; b[37]=0 as u8; b[38]=0 as u8; b[39]=0 as u8 811 // tri (0,0,0)(100,0,0)(0,100,v2z) mm; f32 100.0 = 0x42C80000; only v2's z comes from the arg 812 // (a TILTED PLANE survives centroid+height alignment; a pure translation or coplanar subset is nulled) 813 var o: i64 = 40 814 var k: i64 = 0 815 while k < 9 { b[o+k*4]=0 as u8; b[o+k*4+1]=0 as u8; b[o+k*4+2]=0 as u8; b[o+k*4+3]=0 as u8; k = k + 1 } 816 // v1 x=100f 817 b[o+12]=0 as u8; b[o+13]=0 as u8; b[o+14]=200 as u8; b[o+15]=66 as u8 818 // v2 y=100f, z=arg 819 b[o+28]=0 as u8; b[o+29]=0 as u8; b[o+30]=200 as u8; b[o+31]=66 as u8 820 b[o+32]=(zoff_f32&255) as u8; b[o+33]=((zoff_f32>>8)&255) as u8; b[o+34]=((zoff_f32>>16)&255) as u8; b[o+35]=((zoff_f32>>24)&255) as u8 821 // normals (0,0,1) f32 1.0=0x3F800000 x9... keep zeros (loader ignores), colors zeros 822 // layer id 823 b[o+84]=0 as u8; b[o+85]=0 as u8; b[o+86]=0 as u8; b[o+87]=0 as u8 824 let fd: i64 = sys_openat_wr(path, 420) 825 if fd < 0 { return 0 - 1 } 826 sys_write(fd, b, o+88) 827 sys_close(fd) 828 return 0 829} 830func md_selftest() -> i64 { 831 var fails: i64 = 0 832 md_fix("/tmp/md_a.nxmesh" as *u8, 0) 833 md_fix("/tmp/md_b.nxmesh" as *u8, 1112014848) 834 hw("T0 self-vs-self (expect mean ~0, floor = edge/16384 barycentric quantum):\n" as *u8) 835 if md_run("/tmp/md_a.nxmesh" as *u8, "/tmp/md_a.nxmesh" as *u8, 64) != 0 { fails = fails + 1 } 836 hw("T1 tilted plane, v2 lifted 50mm z (expect mean_um in the LOW THOUSANDS both directions):\n" as *u8) 837 if md_run("/tmp/md_a.nxmesh" as *u8, "/tmp/md_b.nxmesh" as *u8, 64) != 0 { fails = fails + 1 } 838 if md_run("/tmp/md_absent_zz.nxmesh" as *u8, "/tmp/md_a.nxmesh" as *u8, 64) == 0 { fails = fails + 1; hw("T2 FAIL absent accepted\n" as *u8) } else { hw("T2 PASS absent refused\n" as *u8) } 839 if fails == 0 { hw("MESHDIST-SELFTEST GREEN (verify T0 mean==0 and T1 mean~5000 above)\n" as *u8); return 0 } 840 hw("MESHDIST-SELFTEST RED fails=" as *u8); pn(fails); hw("\n" as *u8) 841 return 1 842} 843 844func main(argc: i64, argv: *i64) -> i64 { 845 if argc >= 2 { 846 let a1: *u8 = argv[1] as *u8 847 var m: i64 = 0 848 while a1[m] != (0 as u8) { m = m + 1 } 849 if m == 8 { 850 var ok: i64 = 1 851 let lit: *u8 = "selftest" as *u8 852 var i: i64 = 0 853 while i < 8 { if a1[i] != lit[i] { ok = 0; i = 8 } else { i = i + 1 } } 854 if ok == 1 { let rc: i64 = md_selftest(); sys_exit(rc); return rc } 855 } 856 } 857 // paint verb: deviation heatmap (chars: pa I nt vs pa R ts) 858 if a1[0] == (112 as u8) { if a1[1] == (97 as u8) { if a1[2] == (105 as u8) { 859 if argc < 5 { hw("usage: nx_meshdist paint <cand> <oracle> <out.nxmesh> [band_um=5000]\n" as *u8); sys_exit(2); return 2 } 860 var bu: i64 = 5000 861 if argc >= 6 { 862 let a5: *u8 = argv[5] as *u8 863 bu = 0 864 var q5: i64 = 0 865 while a5[q5] != (0 as u8) { bu = bu*10 + ((a5[q5] as i64) - 48); q5 = q5 + 1 } 866 } 867 let rcq: i64 = md_paint(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8, bu) 868 sys_exit(rcq) 869 return rcq 870 } } } 871 // parts verb: per-named-part completeness table 872 if a1[0] == (112 as u8) { if a1[1] == (97 as u8) { if a1[2] == (114 as u8) { if a1[3] == (116 as u8) { if a1[4] == (115 as u8) { if a1[5] == (0 as u8) { 873 if argc < 4 { hw("usage: nx_meshdist parts <cand.nxmesh> <oracle-with-layers.nxmesh> [samples-per-part]\n" as *u8); sys_exit(2); return 2 } 874 var pw: i64 = 256 875 if argc >= 5 { 876 let a4: *u8 = argv[4] as *u8 877 pw = 0 878 var q4: i64 = 0 879 while a4[q4] != (0 as u8) { pw = pw*10 + ((a4[q4] as i64) - 48); q4 = q4 + 1 } 880 if pw < 16 { pw = 16 } 881 if pw > 4096 { pw = 4096 } 882 } 883 let rcp: i64 = md_parts(argv[2] as *u8, argv[3] as *u8, pw) 884 sys_exit(rcp) 885 return rcp 886 } } } } } } 887 if argc < 3 { 888 hw("usage: nx_meshdist <cand.nxmesh> <oracle.nxmesh> [samples] | parts <cand> <oracle> [n] | selftest\n" as *u8) 889 sys_exit(2) 890 return 2 891 } 892 var want: i64 = 8192 893 if argc >= 4 { 894 let a3: *u8 = argv[3] as *u8 895 want = 0 896 var q: i64 = 0 897 while a3[q] != (0 as u8) { want = want*10 + ((a3[q] as i64) - 48); q = q + 1 } 898 if want < 16 { want = 16 } 899 if want > MD_MAXSAMP { want = MD_MAXSAMP } 900 } 901 let rc2: i64 = md_run(argv[1] as *u8, argv[2] as *u8, want) 902 sys_exit(rc2) 903 return rc2 904}