64 lines
3.0 KiB
Python
64 lines
3.0 KiB
Python
import re, sys
|
|
from PIL import Image, ImageDraw
|
|
import numpy as np
|
|
from scipy import ndimage
|
|
def regions(path):
|
|
inreg=False; regs=[]; cur=[]; x=y=0; pol="D"
|
|
for line in open(path, errors="replace"):
|
|
s=line.strip()
|
|
if s=="%LPC*%": pol="C"
|
|
if s=="%LPD*%": pol="D"
|
|
if s=="G36*": inreg=True; cur=[]; continue
|
|
if s=="G37*": inreg=False; regs.append((pol,cur)); continue
|
|
m=re.match(r"(?:X(-?\d+))?(?:Y(-?\d+))?D0([123])\*$",s)
|
|
if m:
|
|
nx=int(m.group(1)) if m.group(1) is not None else x; ny=int(m.group(2)) if m.group(2) is not None else y
|
|
if inreg: cur.append((nx,ny))
|
|
x,y=nx,ny
|
|
return regs
|
|
def prims(path):
|
|
ap=None; inreg=False; x=y=0; flashes=set(); draws=set(); apdefs={}
|
|
for line in open(path, errors="replace"):
|
|
s=line.strip()
|
|
if s.startswith("G04") or s.startswith("%T"): continue
|
|
m=re.match(r"%ADD(\d+)(.*)\*%",s)
|
|
if m: apdefs[m.group(1)]=m.group(2); continue
|
|
if s=="G36*": inreg=True; continue
|
|
if s=="G37*": inreg=False; continue
|
|
m=re.match(r"D(\d+)\*$",s)
|
|
if m and int(m.group(1))>=10: ap=apdefs.get(m.group(1)); continue
|
|
m=re.match(r"(?:X(-?\d+))?(?:Y(-?\d+))?D0([123])\*$",s)
|
|
if m:
|
|
nx=int(m.group(1)) if m.group(1) is not None else x; ny=int(m.group(2)) if m.group(2) is not None else y
|
|
if not inreg:
|
|
if m.group(3)=="3": flashes.add((ap,nx,ny))
|
|
elif m.group(3)=="1": draws.add((ap,x,y,nx,ny))
|
|
x,y=nx,ny
|
|
return flashes,draws
|
|
SC=50; W,H=int(141*SC),int(101*SC)
|
|
def raster_regs(regs):
|
|
im=Image.new("1",(W,H),0); d=ImageDraw.Draw(im)
|
|
for pol,pts in regs:
|
|
d.polygon([((x/1e6-60)*SC,(-y/1e6-40)*SC) for x,y in pts], fill=1 if pol=="D" else 0)
|
|
return np.array(im)
|
|
def compare(a,b):
|
|
fa,da=prims(a); fb,db=prims(b)
|
|
ra=raster_regs(regions(a)); rb=raster_regs(regions(b))
|
|
x=ra^rb
|
|
er=ndimage.binary_erosion(x, structure=np.ones((3,3)))
|
|
lab,n=ndimage.label(er)
|
|
blobs=[]
|
|
for i in range(1,n+1):
|
|
ys,xs=np.nonzero(lab==i)
|
|
if len(xs)<9: continue
|
|
blobs.append((len(xs)/SC/SC, round(xs.min()/SC+60,1),round(ys.min()/SC+40,1),round(xs.max()/SC+60,1),round(ys.max()/SC+40,1), "A-only" if ra[ys[0],xs[0]] else "B-only"))
|
|
blobs.sort(reverse=True)
|
|
return fa==fb, da==db, x.sum()/SC/SC, blobs
|
|
if __name__=="__main__":
|
|
base="../in/03-Architecture-Hardware/kicad"
|
|
for v,b,prod in (("v56","v5","HBOX_v5_Rev6_PROD"),("v57","v57","HBOX_v5_Rev7_PROD")):
|
|
print("=====",v)
|
|
for lay,e1 in (("F_Cu","gtl"),("In1_Cu","g1"),("In2_Cu","g2"),("B_Cu","gbl")):
|
|
fs,ds,xa,blobs=compare(f"{base}/production/{prod}/hbox-watchdog-{b}-{lay}.{e1}", f"{base}/_to_delete/audit-20261022/{v}/rf/gerber/hbox-watchdog-{b}-{lay}.gbr")
|
|
print(f" {lay:7s} flashes={fs} draws={ds} fill-xor={xa:.3f} mm2 blobs={len(blobs)}", [f"{a:.2f}@({x1},{y1})-({x2},{y2}){t}" for a,x1,y1,x2,y2,t in blobs[:5]])
|