main
John Lauer Publish independent Astra ESC source and full-pad Kelvin review lesson d057af8 23d ago
from geometry import *
from collections import defaultdict
s=json.load(open('evidence/after-routing-state.json'));zones=json.load(open('outer-pours.json'))
cu=[]
for p in pads:cu.append((p['net'],p['g']))
for t in s['segments']:cu.append((t['net_name'],LineString([(t['start']['x'],t['start']['y']),(t['end']['x'],t['end']['y'])]).buffer(t['width']/2)))
for v in s['vias']:cu.append((v['net_name'],Point(v['position']['x'],v['position']['y']).buffer(v['size']/2)))
keep=unary_union([Polygon(z['polygon']) for z in zones if z.get('type')=='keepout'])
result=[];chosen=[]
for net in ['+VBAT','GND_OUT','/DRV_SHA','/DRV_SHB','/DRV_SHC','GND']:
 own=[z for z in zones if z.get('net')==net];region=unary_union([Polygon(z['polygon']) for z in own]);prio=max(z['priority'] for z in own)
 if net=='GND':region=unary_union([Polygon(z['polygon']) for z in own if z['priority']==1])
 else:region=region.difference(unary_union([Polygon(z['polygon']) for z in zones if z.get('net') not in [net,None] and z.get('priority',0)>=prio]))
 foreign=unary_union([g for n,g in cu if n!=net]).buffer(.601)
 occupied=unary_union([g for n,g in cu if n==net]).buffer(.15).union(unary_union([p['g'] for p in pads]).buffer(.45))
 allowed=region.buffer(-.6).difference(foreign).difference(keep.buffer(.4)).difference(occupied)
 anchors=[p for p in pads if p['net']==net and p['name'].split('.')[0] in ['Q1','Q2','Q3','Q4','Q5','Q6','R32','C2','C3']]
 paths=[]
 for p in anchors:
  cand=[]
  for dx in range(-16,17):
   for dy in range(-16,17):
    x=round(p['x']+dx*.25,4);y=round(p['y']+dy*.25,4);pt=Point(x,y)
    if allowed.contains(pt):cand.append(((x-p['x'])**2+(y-p['y'])**2,x,y))
  count=0
  for _,x,y in sorted(cand):
   if any(math.hypot(x-a,y-b)<1.2 for a,b in chosen):continue
   chosen.append((x,y));paths.append([{'x':x,'y':y,'layer':'F.Cu'},{'x':x,'y':y,'layer':'B.Cu'}]);count+=1
   if count==3:break
 if paths:result.append(dict(net=net,width=.5,viaSize=.8,viaDrill=.4,paths=paths))
 print(net,len(paths))
Path('stitching.json').write_text(json.dumps(result,indent=2))