# -*- coding: utf-8 -*- u"""合成焊盘表 vs 板上读回的焊盘表,逐脚对账(2026-09-11 晚,方案 §35)。 /c/Python314/python .claude/r2/pads_diff.py _blade_pads.synth.json _blade_pads.json 摆位下发之后 `pcb_route.py --dump` 重抓,和下发前 `synth_pads.py` 合成的那份比: 位置差 > TOL 或网名不同的脚全部列出来。**有一只对不上就不许拿合成表算出来的铜下发** (多半是底层旋转方向推错了,DRC 不一定报,读回焊盘才看得出来 —— 方案 §25.3 的教训)。 """ import io import json import math import sys sys.stdout.reconfigure(encoding='utf-8') TOL = 0.02 def group(path): u"""{(位号, 脚号): [盘...]},同一脚号的多块盘(U1.15 散热盘分 5 瓣)按坐标排序后逐块比。""" g = {} for r in json.load(io.open(path, encoding='utf-8')): g.setdefault((r[0], r[1]), []).append(r) return {k: sorted(v, key=lambda r: (round(r[2], 2), round(r[3], 2))) for k, v in g.items()} a, b = group(sys.argv[1]), group(sys.argv[2]) bad = [] n = 0 for k in sorted(set(a) | set(b)): if k not in a or k not in b or len(a[k]) != len(b[k]): bad.append(u'%s.%s 块数不同(合成 %d / 读回 %d)' % (k[0], k[1], len(a.get(k, [])), len(b.get(k, [])))) continue for p, q in zip(a[k], b[k]): n += 1 d = math.hypot(p[2] - q[2], p[3] - q[3]) if d > TOL or p[7] != q[7] or p[6] != q[6]: bad.append(u'%s.%s 合成 (%.3f,%.3f L%s %s) 读回 (%.3f,%.3f L%s %s) 差 %.3f' % (k[0], k[1], p[2], p[3], p[6], p[7], q[2], q[3], q[6], q[7], d)) print(u'比了 %d 块焊盘' % n) if bad: print(u'[X] %d 只对不上:' % len(bad)) for m in bad[:60]: print(u' ' + m) sys.exit(1) print(u'[OK] 位置 / 层 / 网名全部一致(容差 %.2f mm)' % TOL)