skill
EDA Skillpack
Public Made by Adomby adom
All skills for all EDA capabilities across the Adom ecosystem.
main
import re,json,math
from pathlib import Path
from shapely.geometry import Point,box,Polygon,LineString
from shapely import affinity
from shapely.ops import unary_union
def parse(s):
toks=re.findall(r'"(?:\\.|[^"\\])*"|[()]|[^\s()]+',s); stack=[];root=None
for t in toks:
if t=='(':stack.append([])
elif t==')':
v=stack.pop()
if stack:stack[-1].append(v)
else:root=v
else:
try:v=json.loads(t) if t.startswith('"') else float(t)
except:v=t
stack[-1].append(v)
return root
def allof(x,k):return [v for v in x if isinstance(v,list) and v and v[0]==k]
def one(x,k,d=None):return next(iter(allof(x,k)),d)
def val(x,k,d=None):
a=one(x,k);return a[1] if a else d
root=parse(Path('route-input.kicad_pcb').read_text())
pads=[];keepouts=[]
for f in allof(root,'footprint'):
ref=next(p[2] for p in allof(f,'property') if p[1]=='Reference'); fa=one(f,'at');fx,fy=fa[1:3];ang=fa[3] if len(fa)>3 else 0
for p in allof(f,'pad'):
a=one(p,'at');px,py=a[1:3];pa=a[3] if len(a)>3 else 0;sz=one(p,'size');w,h=sz[1:3];shape=p[3]
if shape=='circle':g=Point(0,0).buffer(w/2,quad_segs=16)
elif shape=='oval':
g=LineString([(-(w-h)/2,0),((w-h)/2,0)]).buffer(h/2) if w>h else LineString([(0,-(h-w)/2),(0,(h-w)/2)]).buffer(w/2)
elif shape=='roundrect':
r=min(w,h)*val(p,'roundrect_rratio',.25);g=box(-w/2+r,-h/2+r,w/2-r,h/2-r).buffer(r)
else:g=box(-w/2,-h/2,w/2,h/2)
if shape=='custom':
shapes=[g]; prim=one(p,'primitives',[])
for q in allof(prim,'gr_poly'):
pts=[v[1:3] for v in one(q,'pts')[1:]];pg=Polygon(pts);shapes.append(pg.buffer(val(q,'width',0)/2))
g=unary_union(shapes)
# pad angle stored board absolute angle, coordinates footprint local
g=affinity.rotate(g,-pa,origin=(0,0));cx=fx+px*math.cos(math.radians(ang))+py*math.sin(math.radians(ang));cy=fy-px*math.sin(math.radians(ang))+py*math.cos(math.radians(ang));g=affinity.translate(g,cx,cy)
n=one(p,'net');net=n[-1] if n else ''; layers=one(p,'layers')[1:];dr=one(p,'drill');hole=0
if dr:
hole=max([v for v in dr[1:] if isinstance(v,(int,float))],default=0)
pads.append(dict(name=ref+'.'+str(int(p[1]) if isinstance(p[1],float) else p[1]),net=net,x=cx,y=cy,g=g,layers=layers,type=p[2],clearance=max(val(p,'clearance',0),val(f,'clearance',0)),hole=hole))
if __name__=='__main__':
print(len(pads));print('shapes',[(p['name'],p['g'].bounds,p['clearance']) for p in pads if p['clearance']]);print('zones',[(val(z,'net_name'),val(z,'layer')) for z in allof(root,'zone')]);print('edges',[(a[0],one(a,'start'),one(a,'end')) for a in root if isinstance(a,list) and val(a,'layer')=='Edge.Cuts'])
st=json.load(open('evidence/initial-state.json'));live={p['name']:p for p in st['pads']};print('maxcoorderror',max(math.hypot(p['x']-live[p['name']]['x'],p['y']-live[p['name']]['y']) for p in pads))