main
John Lauer Publish independent Astra ESC source and full-pad Kelvin review lesson d057af8 23d ago
from geometry import *
from shapely.ops import nearest_points
s=json.load(open('evidence/after-routing-state.json'));plans=json.load(open('stitching.json'));zs=json.load(open('outer-pours.json'));keep=unary_union([Polygon(z['polygon']) for z in zs if z.get('type')=='keepout']);out=[]
for plan in plans:
 net=plan['net'];foreign=[p['g'] for p in pads if p['net']!=net]
 foreign += [LineString([(t['start']['x'],t['start']['y']),(t['end']['x'],t['end']['y'])]).buffer(t['width']/2) for t in s['segments'] if t['net_name']!=net and t['layer']=='F.Cu']
 foreign += [Point(v['position']['x'],v['position']['y']).buffer(v['size']/2) for v in s['vias'] if v['net_name']!=net]
 obstacles=unary_union(foreign).buffer(.451).union(keep)
 paths=[]
 for path in plan['paths']:
  pt=Point(path[0]['x'],path[0]['y']);candidates=[]
  for p in pads:
   if p['net']!=net or p['name'].startswith('U6.'):continue
   inner=p['g'].buffer(-.15)
   if inner.is_empty:continue
   a=nearest_points(inner,pt)[0]
   if a.is_empty:continue
   line=LineString([a,pt])
   if line.length<4 and not line.intersects(obstacles):candidates.append((line.length,a))
  if candidates:
   a=min(candidates,key=lambda q:q[0])[1];paths.append([{'x':round(a.x,6),'y':round(a.y,6),'layer':'F.Cu'}]+path)
 if paths:out.append(dict(plan,paths=paths))
 print(net,len(paths))
Path('stitching-unanchored-rejected.json').write_text(json.dumps(plans,indent=2));Path('stitching.json').write_text(json.dumps(out,indent=2))