abse/smartwatch-flex-top-only
Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.
- Version
- 0.2.20
- License
- unset
- Stars
- 0
scripts/audit-optical-paths.py
from pathlib import Path
import json,numpy as np,trimesh
root=Path(__file__).resolve().parent.parent
cx=-.02509520000035;cy=-8.99159126281738
opaque=[]
for f in ['case-body','optical-light-seal']:
s=trimesh.load(root/f'mechanical/{f}.glb',force='scene')
for n in s.graph.nodes_geometry:
T,k=s.graph[n];m=s.geometry[k].copy();m.apply_transform(T);opaque.append((f+'/'+n,m))
def intersections(mesh,x,y):
tri=mesh.triangles;a=tri[:,0];u=tri[:,1]-a;v=tri[:,2]-a
det=u[:,0]*v[:,1]-u[:,1]*v[:,0];keep=np.abs(det)>1e-10
a=a[keep];u=u[keep];v=v[keep];det=det[keep]
dx=x-a[:,0];dy=y-a[:,1];b=(dx*v[:,1]-dy*v[:,0])/det;c=(u[:,0]*dy-u[:,1]*dx)/det
keep=(b>=-1e-8)&(c>=-1e-8)&(b+c<=1+1e-8)
z=a[keep,2]+b[keep]*u[keep,2]+c[keep]*v[keep,2]
zs=sorted(float(z) for z in z);unique=[]
for z in zs:
if not unique or z-unique[-1]>1e-5:unique.append(z)
return unique
points=[]
for name,x,y in [('LED0',-2.55,-.875),('LED1',-1.675,0),('LED2',-2.55,.875)]:
for dx,dy in [(0,0),(-.2,-.2),(-.2,.2),(.2,-.2),(.2,.2)]:points.append((name,cx+x+dx,cy+y+dy))
for x in np.linspace(-.3,3.1,5):
for y in np.linspace(-1.4,1.4,5):points.append(('PHOTODIODE_APERTURE',cx+x,cy+y))
blocked=[]
for name,x,y in points:
for body,m in opaque:
hits=[z for z in intersections(m,x,y) if -9.41999<z<-8.41004]
if hits:blocked.append({'field':name,'xyMM':[x,y],'body':body,'hitZMM':hits})
assert not blocked,blocked[:3]
# The opaque divider spans from the external floor up to the gasket face.
intervals=[]
for body,m in opaque:
zs=intersections(m,cx-.675,cy)
assert len(zs)%2==0,(body,zs)
intervals.extend(zip(zs[::2],zs[1::2]))
intervals.sort();end=-9.42
for lo,hi in intervals:
if hi<end:continue
assert lo<=end+.000005,('Gap in black optical divider',end,lo)
end=max(end,hi)
assert end>=-8.410025,end
out={'status':'PASS','raysChecked':len(points),'blockedOpticalRays':blocked,
'continuousOpaqueDividerFromZMM':-9.42,'continuousOpaqueDividerToZMM':end,
'method':'Exact triangle intersections along skin-facing optical rays through three LED fields and a 5x5 photodiode aperture grid; exclude transparent inserts. Check solid vertical intervals along the black divider through case and gasket.',
'qualification':'Geometric optical clearance and baffle continuity only; sensor signal quality, material transmission and seal compression need physical verification.'}
(root/'reports/optical-paths.json').write_text(json.dumps(out,indent=2)+'\n');print(json.dumps(out,indent=2))