0hmX/mt41k512m8da-107-it-p-footprints

This code defines the mechanical and physical layout of a Micron digital ball grid array (FBGA) package with 78 balls, including pin positions, footprint geometry, PCB pads, and silkscreen outlines for surface-mount integration.

Version
0.1.1
License
unset
Stars
1

scripts/render-comparison.py

from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
import json,re,hashlib
p=Path(__file__).resolve().parents[1]; data=json.loads((p/'dist/examples/preview/circuit.json').read_text())
font='/System/Library/Fonts/Supplemental/Arial.ttf'
def f(n):return ImageFont.truetype(font,n)
ours=[(x['port_hints'][1],x['x'],x['y'],x['radius']*2) for x in data if x['type']=='pcb_smtpad']
ki=[(m[0],float(m[1]),-float(m[2]),float(m[3])) for m in re.findall(r'\(pad (\w+) smd circle \(at ([\d.-]+) ([\d.-]+)\) \(size ([\d.]+) [\d.]+\)',(p/'evidence/kicad-grid-reference.kicad_mod').read_text())]
raw=(p/'evidence/original-jlc-import.tsx').read_text()
old=[(ours[int(m[0])-1][0],float(m[1]),float(m[2]),float(m[3])*2) for m in re.findall(r'<smtpad portHints=\{\["pin(\d+)"\]\} pcbX="([\d.-]+)mm" pcbY="([\d.-]+)mm" radius="([\d.]+)mm"',raw)]
def panel(title,sub,pads,body,color,footer):
 im=Image.new('RGB',(650,1050),'#f8fafc');d=ImageDraw.Draw(im)
 d.text((32,24),title,font=f(29),fill='#12263a');d.text((32,70),sub,font=f(19),fill='#526174')
 cx,cy,scale=325,500,57
 def pt(x,y):return(cx+x*scale,cy-y*scale)
 d.rectangle([pt(-body[0]/2,body[1]/2),pt(body[0]/2,-body[1]/2)],outline='#748197',width=2)
 for name,x,y,diam in pads:
  px,py=pt(x,y);r=diam/2*scale
  d.ellipse((px-r,py-r,px+r,py+r),fill=color,outline=color)
  d.text((px,py-17),name,font=f(12),fill='#182b42',anchor='mm')
 d.line([pt(-4.4,4.85),pt(-4.4,5.65),pt(-3.6,5.65)],fill='#bf3f32',width=3)
 d.text((32,880),'TOP VIEW  |  A1 upper left',font=f(21),fill='#12263a')
 for i,t in enumerate(footer):d.text((32,920+30*i),t,font=f(19),fill='#526174')
 return im
oursim=panel('Our footprint','Rendered from compiled tscircuit pad geometry',ours,(8,10.5),'#047c85',['Body: 8 x 10.5 mm   |   Pads: 0.420 mm','78 balls   |   Pitch: 0.800 mm','Ball field: 6.4 x 9.6 mm'])
oursim.save(p/'images/our-footprint.png')
imgs=[panel('Original JLC import','C2888412 / EasyEDA geometry',old,(8.152384,10.652379),'#bc7528',['Shown outline: imported silkscreen','Pads: 0.383997 mm','Max center error: 0.000108 mm']),panel('KiCad grid reference','FBGA-78_7.5x11mm (different body)',ki,(7.5,11),'#536bae',['Body: 7.5 x 11 mm   |   Pads: 0.420 mm','Same grid; NOT an exact DA body','KiCad Y-down converted to top-view Y-up']),oursim]
canvas=Image.new('RGB',(1950,1050),'white')
for i,im in enumerate(imgs):canvas.paste(im,(650*i,0))
canvas.save(p/'images/three-way-comparison.png')
# Overlay generated directly from independent reference geometry vs compiled pads.
ov=Image.new('RGB',(650,1050),'#f8fafc');ov=oursim.copy();dr=ImageDraw.Draw(ov)
for _,x,y,diam in ki:
 xx=325+x*57; yy=500-y*57; rr=diam/2*57
 dr.ellipse((xx-rr,yy-rr,xx+rr,yy+rr),outline='#d13796',width=2)
ov.save(p/'images/kicad-overlay.png')
files=['src/index.tsx','src/balls.json','evidence/original-jlc-import.tsx','evidence/kicad-grid-reference.kicad_mod']
(p/'evidence/sha256.json').write_text(json.dumps({x:hashlib.sha256((p/x).read_bytes()).hexdigest() for x in files},indent=2))