muse/book-reading-clip-lamp
A tscircuit package created by muse.
- Version
- 0.4.6
- License
- unset
- Stars
- 0
repair-jlc-vias.py
exec(open('find-via-repair.py').read().split('obs=[]')[0].split("c=json.load")[0])
import json,math
c=json.load(open('dist/index/circuit.json'))
# Geometry helpers, independent of netlist labels.
text=open('find-via-repair.py').read();exec(text[text.index('def ds('):text.index('obs=[]')]);exec(text[text.index('def pointclear'):text.index('# Existing adjacent')])
patches=[]
for vid in ['pcb_via_31','pcb_via_32','pcb_via_94']:
v=next(e for e in c if e.get('type')=='pcb_via' and e['pcb_via_id']==vid);target=v['pcb_trace_id'];old=(v['x'],v['y'])
tr=next(e for e in c if e.get('type')=='pcb_trace' and e['pcb_trace_id']==target)
idx=next(i for i,p in enumerate(tr['route']) if p['route_type']=='via' and math.hypot(p['x']-old[0],p['y']-old[1])<1e-6)
a0=tr['route'][idx-2];b0=tr['route'][idx+2];a=(a0['x'],a0['y']);b=(b0['x'],b0['y']);la=a0['layer'];lb=b0['layer'];obs=[]
for e in c:
typ=e['type']
if typ=='pcb_trace' and e['pcb_trace_id']!=target:
for m,n in zip(e['route'],e['route'][1:]):
if m['route_type']==n['route_type']=='wire' and m['layer']==n['layer']:
obs.append(('seg',m['layer'],(m['x'],m['y']),(n['x'],n['y']),max(m['width'],n['width'])/2))
if typ=='pcb_via' and e.get('pcb_trace_id')!=target:obs.append(('point','all',(e['x'],e['y']),None,e['outer_diameter']/2))
if typ=='pcb_smtpad' and 'x' in e:
if e.get('shape')=='circle':obs.append(('point',e['layer'],(e['x'],e['y']),None,e.get('radius',e.get('diameter',0)/2)))
else:
x,y=e['x'],e['y'];w=e.get('width',0)/2;h=e.get('height',0)/2;obs.append(('rect',e['layer'],(x-w,y-h),(x+w,y+h),0))
# Restrict to neighborhood conservatively: anything intersecting candidate/connection bounds remains.
loX=min(old[0]-3,a[0],b[0])-1;hiX=max(old[0]+3,a[0],b[0])+1;loY=min(old[1]-3,a[1],b[1])-1;hiY=max(old[1]+3,a[1],b[1])+1
obs=[o for o in obs if not(max(o[2][0],(o[3] or o[2])[0])+o[4]<loX or min(o[2][0],(o[3] or o[2])[0])-o[4]>hiX or max(o[2][1],(o[3] or o[2])[1])+o[4]<loY or min(o[2][1],(o[3] or o[2])[1])-o[4]>hiY)]
choices=[]
diagnostics=[]
for xi in range(round((old[0]-3)*20),round((old[0]+3)*20)+1):
for yi in range(round((old[1]-3)*20),round((old[1]+3)*20)+1):
p=(xi/20,yi/20);vc=min(pointclear(p,o)-.3 for o in obs)
if vc<.17:continue
lc=min([lineclear(a,p,o)-.075 for o in obs if o[1] in ['all',la]]+[lineclear(p,b,o)-.075 for o in obs if o[1] in ['all',lb]])
diagnostics.append((lc,p,vc))
if lc>=.149:choices.append((math.dist(p,old),p,vc,lc))
if not choices:
print('NO CANDIDATES',vid,'best',sorted(diagnostics,reverse=True)[:3], 'anchor_clear',min(pointclear(a,o)-.075 for o in obs if o[1] in ['all',la]),min(pointclear(b,o)-.075 for o in obs if o[1] in ['all',lb]))
if diagnostics:
p=max(diagnostics)[1]; print('WORST',min([(lineclear(a,p,o)-.075,o,'A') for o in obs if o[1] in ['all',la]]+[(lineclear(p,b,o)-.075,o,'B') for o in obs if o[1] in ['all',lb]],key=lambda x:x[0]))
continue
best=min(choices);p=best[1];print(vid,target,'old',old,'new',p,'clearances',best[2:],'choices',len(choices))
patches.append({'traceId':target,'from':{'x':old[0],'y':old[1]},'to':{'x':p[0],'y':p[1]}})
for pt in tr['route'][idx-1:idx+2]:pt['x'],pt['y']=p
v['x'],v['y']=p
open('routing-corrections.json','w').write(json.dumps(patches,indent=2)+'\n')