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-folded-panel-clearance.py
from pathlib import Path
import json,math,sys
from shapely.geometry import Polygon,box
from shapely.affinity import affine_transform
root=Path(__file__).resolve().parent.parent
source=root/(sys.argv[1] if len(sys.argv)>1 else 'dist/extracted/circuit.json')
c=json.loads(source.read_text());board=next(e for e in c if e['type']=='pcb_board')
poly=Polygon([(p['x'],p['y']) for p in board['outline']])
for cut in (e for e in c if e['type']=='pcb_cutout'):
assert cut['shape']=='polygon'
poly=poly.difference(Polygon([(p['x'],p['y']) for p in cut['points']]))
bends=sorted((e for e in c if e['type']=='pcb_bend'),key=lambda e:e['start']['y'])
assert len(bends)==2 and all(b['bend_radius']==3.9 and b['bend_angle']==-180 and b['bend_side']=='left' for b in bends)
frame_line,coil_line=[b['start']['y'] for b in bends]
half_arc=math.pi*3.9/2
frame_flat=poly.intersection(box(-100,-200,100,frame_line-half_arc))
coil_flat=poly.intersection(box(-100,coil_line+half_arc,100,200))
frame_folded=affine_transform(frame_flat,[1,0,0,-1,0,2*frame_line])
coil_folded=affine_transform(coil_flat,[1,0,0,-1,0,2*coil_line])
gap=frame_folded.distance(coil_folded)
overlap=frame_folded.intersection(coil_folded).area
r={'status':'PASS' if gap>=.199999 and overlap==0 else 'FAIL','sourceFile':str(source.relative_to(root)),'frameToCoilPanelMinimumGapMM':gap,'coplanarPanelOverlapAreaMM2':overlap,'method':'Exact Shapely polygons of the emitted outline minus cutouts. Transform both flat end panels through their actual parallel R3.9/180-degree folds into the same main-panel frame. Curved bands, components and solid envelopes are checked in separate mesh audits.'}
(root/'reports/folded-panel-clearance.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))
assert r['status']=='PASS'