# -*- coding: utf-8 -*- u"""BLADE-PCB_1 **2026-09-15 新摆位** 的手工收尾(服务器布线 + MODE=repair 之后)。 /c/Python314/python .claude/r2/hand_blade1b.py <基础缓存> <输出> <补丁名...> 只做确定几何(本机不搜索,CLAUDE.md)。每个补丁 = (DROP 判据, 新段, 新孔),按基础缓存挑着用: 每段都用 scratchpad 的 probe 核过净距(≥0.15),但**只对当时那份基础缓存成立**,换基础要重核。 上一版(09-14 老摆位)的手工收尾是 `hand_blade1.py`,两者互不相干。 """ import io import json import os import sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.stdout.reconfigure(encoding='utf-8') FIXES = { # $1N131(U1.8 COMP → R6.1 → C11.1):repair 绕了 96 mm;只留 U1.8→R6.1 那三段,C11.1 改从 R6/C10 西侧 x 28.26 直下 'N131': ([('$1N131', lambda k, it: not (k == 'seg' and it[0] == 2 and 21.3 < min(it[2], it[4]) and max(it[2], it[4]) < 23.1 and min(it[1], it[3]) > 28.85))], [(2, 28.81, 26.31, 28.26, 26.31, 0.15, '$1N131'), (2, 28.26, 26.31, 28.26, 23.04, 0.15, '$1N131'), (2, 28.26, 23.04, 28.89, 23.04, 0.15, '$1N131')], []), # $1N135(U1.9 → C9.1):U1.9 焊盘内 x 30.1 直上到 C9.1 'N135': ([], [(2, 30.1, 20.67, 30.1, 22.80, 0.15, '$1N135')], []), # +12V_F → R4.1(EN 分压上端,µA 级):L4 北上 → 西到 (28.55,27.3) 打孔 → L1 西南到 U1 旁的 +12V_F 孔 (26.25,20.75) 'R4': ([], [(2, 31.43, 24.92, 31.43, 27.3, 0.28, '+12V_F'), (2, 31.43, 27.3, 28.55, 27.3, 0.28, '+12V_F'), (1, 28.55, 27.3, 28.55, 22.5, 0.28, '+12V_F'), (1, 28.55, 22.5, 26.25, 20.75, 0.28, '+12V_F')], [(28.55, 27.3, '+12V_F')]), # SDA 上拉 R40.1:被 +3V3 / SCL 的孔围住 —— 西出打孔 → L1 东去 → (44.15,20.6) 下 L4 → 北上接 SDA 在 (47.75,29.0) 的孔 'R40': ([], [(2, 41.13, 18.27, 40.2, 18.4, 0.15, 'SDA'), (1, 40.2, 18.4, 40.2, 18.6, 0.15, 'SDA'), (1, 40.2, 18.6, 44.0, 18.6, 0.15, 'SDA'), (1, 44.0, 18.6, 44.15, 20.6, 0.15, 'SDA'), (2, 44.15, 20.6, 44.15, 28.8, 0.15, 'SDA'), (2, 44.15, 28.8, 47.75, 29.0, 0.15, 'SDA')], [(40.2, 18.4, 'SDA'), (44.15, 20.6, 'SDA')]), # ── 以下三个补丁对 `_blade_routes.r15.json`(服务器 `--pf --first $1N137,$1N165,$1N173,$1N147,$1N177,BUCK_PG`)核过 ── # +12V_F → R4.1:L4 北上 → 斜到 (30.4,26.4) 打孔 → L1 北上绕过 $1N131 孔 → 西到 x 27.0 → 南下 → (26.8,21.6) 打孔 → L4 接 U1.6 'R4b': ([], [(2, 31.43, 24.92, 31.43, 25.9, 0.28, '+12V_F'), (2, 31.43, 25.9, 30.4, 26.4, 0.28, '+12V_F'), (1, 30.4, 26.4, 30.4, 28.0, 0.28, '+12V_F'), (1, 30.4, 28.0, 27.0, 28.0, 0.28, '+12V_F'), (1, 27.0, 28.0, 27.0, 21.8, 0.28, '+12V_F'), (1, 27.0, 21.8, 26.8, 21.6, 0.28, '+12V_F'), (2, 26.8, 21.6, 26.825, 20.673, 0.28, '+12V_F')], [(30.4, 26.4, '+12V_F'), (26.8, 21.6, '+12V_F')]), # SDA 上拉 R40.1:西出 (40.0,18.62) 打孔 → L1 东去 → (44.15,20.6) 下 L4 → 北上接 SDA 孔 (47.5,29.25) 'R40b': ([], [(2, 41.13, 18.27, 40.0, 18.62, 0.15, 'SDA'), (1, 40.0, 18.62, 44.0, 18.62, 0.15, 'SDA'), (1, 44.0, 18.62, 44.15, 20.6, 0.15, 'SDA'), (2, 44.15, 20.6, 44.15, 28.8, 0.15, 'SDA'), (2, 44.15, 28.8, 47.5, 29.25, 0.15, 'SDA')], [(40.0, 18.62, 'SDA'), (44.15, 20.6, 'SDA')]), # U4.23 (SDA):逃逸孔 (69.75,32.64) → L1 沿板东沿南下到 y 28.625(INT# y28 / SCL y29.25 两线之间的缝)→ 西穿 Kelvin 两线上方 → SDA 孔 (56.25,29.0) 'SDA23': ([], [(1, 69.75, 32.636, 69.4, 32.3, 0.15, 'SDA'), (1, 69.4, 32.3, 69.4, 28.625, 0.15, 'SDA'), (1, 69.4, 28.625, 57.0, 28.625, 0.15, 'SDA'), (1, 57.0, 28.625, 56.25, 29.0, 0.15, 'SDA')], []), # EFUSE_EN:U2.14 的 QFN 扇出斜线擦过 R14.2(GND),净距 0.035 ⇒ 斜线换成先西后南的折线(离 R14.2 0.194、离 $1N147 斜线 0.227) # 金手指地母线:B32 那段对排是 +5V,母线往外伸 1 mm 伸出了舌头((53,7) 孔在板外 −0.05)⇒ 改成竖上再斜到台阶以上 (53.2,11.0) 打孔; # B12/B13 那段 (32,7.0) 的孔离防呆缺口 0.25(< 0.3),同段 (33,7.0) 还有孔 ⇒ 删掉 'FING': ([('GND', lambda k, it: (k == 'via' and ((abs(it[0] - 53.0) < 0.02 and abs(it[1] - 7.0) < 0.02) or (abs(it[0] - 32.0) < 0.02 and abs(it[1] - 7.0) < 0.02))) or (k == 'seg' and it[0] == 1 and abs(it[1] - 52.0) < 0.02 and abs(it[3] - 53.0) < 0.02 and abs(it[2] - 7.0) < 0.02))], [(1, 52.0, 7.0, 52.0, 9.5, 0.2, 'GND'), (1, 52.0, 9.5, 53.2, 11.0, 0.2, 'GND')], [(53.2, 11.0, 'GND')]), # GND:MODE=gndtie 找不到位置的 6 只 J4 地脚(两排之间错开打孔,孔边到焊盘 ≥0.40)+ U2 散热盘经 U2.16 / U2.1 引脚短接 # (gndtie 的 20 段 / 17 孔在 `_blade_routes.gndtie.json`,按 'GNDTIE' 并入) 'GNDJ4': ([], [(2, 18.151, 39.807, 18.151, 40.95, 0.15, 'GND'), (2, 16.749, 39.807, 16.749, 40.75, 0.15, 'GND'), (2, 15.349, 39.807, 15.349, 41.928, 0.15, 'GND'), (2, 12.901, 41.928, 12.901, 40.75, 0.15, 'GND'), (2, 11.151, 41.928, 11.151, 40.75, 0.15, 'GND'), (2, 49.22, 21.643, 49.22, 22.6, 0.15, 'GND'), (2, 49.22, 24.643, 49.22, 23.7, 0.15, 'GND')], [(18.151, 40.95, 'GND'), (16.749, 40.75, 'GND'), (15.349, 40.75, 'GND'), (12.901, 40.75, 'GND'), (11.151, 40.75, 'GND')]), # U1 散热盘(U1.15)和 U1.3:DRC 连接性报断开 ⇒ U1.3 焊盘内横接到散热盘(U1.3 已由 gndtie 接到 (26.075,18.874) 地孔) 'U1EP': ([], [(2, 26.825, 19.174, 27.8, 19.174, 0.2, 'GND')], []), 'EN14': ([('EFUSE_EN', lambda k, it: k == 'seg' and abs(it[1] - 50.221) < 0.02 and abs(it[2] - 20.143) < 0.02 and abs(it[3] - 49.471) < 0.02 and abs(it[4] - 19.393) < 0.02)], [(2, 50.221, 20.143, 49.75, 20.143, 0.15, 'EFUSE_EN'), (2, 49.75, 20.143, 49.75, 19.6, 0.15, 'EFUSE_EN'), (2, 49.75, 19.6, 49.471, 19.393, 0.15, 'EFUSE_EN')], []), } def main(): src, dst = sys.argv[1], sys.argv[2] d = json.load(io.open(src, encoding='utf-8')) segs, vias = [list(s) for s in d['segs']], [list(v) for v in d['vias']] for name in sys.argv[3:]: if name == 'GNDTIE': g = json.load(io.open(os.path.join(HERE, '_blade_routes.gndtie.json'), encoding='utf-8')) segs += [list(x) for x in g['segs']] vias += [list(x) for x in g['vias']] continue drop, add_s, add_v = FIXES[name] for net, f in drop: n0, v0 = len(segs), len(vias) segs = [s for s in segs if not (s[6] == net and f('seg', s))] vias = [v for v in vias if not (v[2] == net and f('via', v))] print(u'%s / %s: 删 %d 段 / %d 孔' % (name, net, n0 - len(segs), v0 - len(vias))) segs += [list(s) for s in add_s] vias += [list(v) for v in add_v] json.dump({'segs': segs, 'vias': vias, 'logs': []}, io.open(dst, 'w', encoding='utf-8'), ensure_ascii=False) print(u'写 %s:%d 段 / %d 孔' % (dst, len(segs), len(vias))) if __name__ == '__main__': main()