seveibar/pd-dual-stepper-controller

Bottom-side PCB silkscreen artwork consisting of embedded mirrored TS Circuit SVG logos, with via-clearance-aware lower-board placement.

Version
0.1.0
License
unset
Stars
0

scripts/reconstruct-repair-graph.py

"""Reconstruct required source paths from the current edited copper, without resurrecting ripped-up routes."""
import json,copy,subprocess,sys
from pathlib import Path
folder=Path('work/repair');plan=json.loads((folder/'route-plan.json').read_text())
j=[e for e in json.load(open('dist/dual/capture.json')) if not e['type'].endswith('_error') and e['type']!='pcb_copper_pour']
known={e['source_trace_id'] for e in j if e['type']=='source_trace'};nets={e['source_net_id'] for e in j if e['type']=='source_net'}
seen=set()
for t0 in plan['traces']:
 t=copy.deepcopy(t0);cn=next((c for c in t['connection_name'].split('__') if c in known or c in nets),None)
 if cn in known:t['source_trace_id']=cn
 elif cn in nets:t['source_net_id']=cn
 else:raise ValueError(t['connection_name'])
 j.append(t)
 for v in t['route']:
  if v['route_type']!='via':continue
  k=(v['x'],v['y'],cn)
  if k in seen:continue
  seen.add(k)
  j.append({'type':'pcb_via','pcb_via_id':f"edit_via_{len(seen)}",'x':v['x'],'y':v['y'],'outer_diameter':v.get('via_diameter',.5),'hole_diameter':v.get('via_hole_diameter',.3),'layers':['top','inner1','inner2','bottom'],**{k:t[k] for k in ['source_trace_id','source_net_id'] if k in t}})
Path('work/freerouting/placement.json').write_text(json.dumps(j))
Path('work/repair/empty.ses').write_text('(session edited (routes (resolution um 10) (network_out)))')
subprocess.run([sys.executable,'scripts/import-freerouting.py','work/repair/empty.ses','work/repair/reconstructed'],check=False)
(folder/'route-plan.json').write_text((folder/'reconstructed/route-plan.json').read_text())