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-rendered-bends.py

from pathlib import Path
import sys,json,hashlib,numpy as np,trimesh
root=Path(__file__).resolve().parent.parent
candidate=root/(sys.argv[1] if len(sys.argv)>1 else 'mechanical/upright-pcb.glb')
source=root/(sys.argv[2] if len(sys.argv)>2 else 'dist/index/circuit.json')
c=json.loads(source.read_text());board=next(e for e in c if e['type']=='pcb_board');bends=[e for e in c if e['type']=='pcb_bend']
assert len(bends)==2 and all(b['bend_angle']==-180 and b['bend_side']=='left' and b['bend_radius']==3.9 for b in bends)
s=trimesh.load(candidate,force='scene');surfaces=[m for n,m in s.geometry.items() if n.startswith('Box0_') and len(m.vertices)==444]
assert len(surfaces)==2,'Both native board skin surfaces must be present'
results=[]
for bend,xlo,xhi,sign in [('FRAME_FOLD',12.2,14.8,-1),('COIL_FOLD',0,1.6,1)]:
    fits=[]
    for mesh in surfaces:
        v=mesh.vertices;p=v[(abs(v[:,0])>=xlo)&(abs(v[:,0])<=xhi)&(v[:,2]>-7.25)&(v[:,2]<.25)]
        p=p[(p[:,1]*sign)>15];assert len(p)>=30
        yz=np.unique(np.round(p[:,1:3],5),axis=0)
        A=np.c_[2*yz,np.ones(len(yz))];coef=np.linalg.lstsq(A,(yz*yz).sum(1),rcond=None)[0]
        center=coef[:2];radius=float(np.sqrt(coef[2]+(center*center).sum()))
        residual=float(abs(np.linalg.norm(yz-center,axis=1)-radius).max())
        assert residual<.00003 and abs(center[1]+3.5)<.00003
        fits.append({'surfaceVertices':len(p),'centerYZMM':center.tolist(),'radiusMM':radius,'maxCircleResidualMM':residual})
    radii=sorted(f['radiusMM'] for f in fits)
    assert abs(sum(radii)/2-3.9)<.00003 and abs(radii[1]-radii[0]-.2)<.00003
    results.append({'name':bend,'fittedNativeBoardSkins':fits,'neutralRadiusMM':sum(radii)/2})
r={'status':'PASS','candidateFile':str(candidate.relative_to(root)),'candidateSha256':hashlib.sha256(candidate.read_bytes()).hexdigest(),'sourceFile':str(source.relative_to(root)),'sourceSha256':hashlib.sha256(source.read_bytes()).hexdigest(),'actualCurvedBands':2,'bends':results,'method':'Fit circles independently to both actual exported board skin meshes at each distinct bend. Require two opposite-end curves, 3.9mm neutral radius, 0.2mm skin separation and less than 0.03um fit residual.'}
(root/'reports/rendered-bends.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))