文件

127 行
6.4 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""在现有铜之上**只重布几根绕远的慢速信号**(2026-09-15,BLADE-PCB_1 新摆位)。
# 本机:先把要重布的网从缓存里拆掉(保留 ESC 逃逸孔 / 金手指引出),写成 _blade_routes.json
# 服务器(搜索只在服务器跑):
DCDC_ROUTE_SERVER=1 pypy3 .claude/r2/opt_blade1.py <网,网,...> [<网,网,...> ...]
# 每个参数 = 一种布线顺序,结果写 _blade_routes.opt<k>.json(合并后的完整缓存)
和 `repair_route.py` 的区别:
· 起止点用 **ESC 逃逸孔**(router.ESC_VIAS)当虚拟焊盘,不从被围住的原焊盘起步(repair 在 U3/U4 上一直「没布通」);
· 线宽强制 0.15(规则默认值;repair 按 rule_width 走出了 0.30,同样的走廊少一半通道)。
"""
import io
import json
import math
import os
import sys
sys.stdout.reconfigure(encoding='utf-8')
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
if not os.environ.get('DCDC_ROUTE_SERVER'):
sys.exit(u'⛔ 搜索只在 10.5.5.13 上跑(CLAUDE.md)')
import router as RT # noqa: E402
import pcb_rules as R # noqa: E402
W = 0.15
def main():
base = json.load(io.open(os.path.join(HERE, '_blade_routes.json'), encoding='utf-8'))
pads = RT.load_pads()
auto = R.resolve_auto()
_fs, _fv, launch = RT.finger_escape()
esc = {k: v for k, v in RT.ESC_VIAS.items()}
vp = os.path.join(HERE, '_opt_virt.json')
VIRT = json.load(io.open(vp, encoding='utf-8')) if os.path.exists(vp) else {}
for k_, order in enumerate(sys.argv[1:]):
nets = [n.replace('@', '$') for n in order.split(',') if n]
segs = [tuple(s) for s in base['segs']]
vias = [tuple(v) for v in base['vias']]
board_vias = [(v[0], v[1], v[2], RT.VIA_D) for v in vias]
# U2 的 QFN 预扇出(被拆掉了就补回来):扇出段落铜,焊盘换成扇出端点的虚拟焊盘
qs, qv, qvirt = RT.qfn_fan(pads)
have = set(tuple(round(c, 3) for c in s[1:5]) for s in segs)
qmap = {}
for sg in qs:
if sg[6] in nets and tuple(round(c, 3) for c in sg[1:5]) not in have:
segs.append(tuple(sg))
for (x, y, n) in qv:
if n in nets:
vias.append((x, y, n))
for p, (ex, ey), lay in qvirt:
qmap[(p[0], p[1])] = (ex, ey, lay)
# 手算过的出口(在 BLADE-PCB_1 定稿缓存上核过净距):U2.2 扇出端点 → R15.1;R40.1 西出打孔
# 2026-09-15 晚:上拉电阻 R13/R15/R40/R41 挪到 U4 东南之后,原来的 R15.1 / R40.1 / R41.1 手算出口作废
FIX = {}
fixdrop, fixvirt = set(), {}
for net, (fs_, fv_, fd_, fvp) in FIX.items():
if net in nets:
segs += [tuple(x) for x in fs_]
vias += [tuple(x) for x in fv_]
fixdrop |= set(fd_)
if fvp:
fixvirt[net] = fvp
_es, _ev, _evirt, edrop = RT.esc_fan(pads)
have = set(tuple(round(c, 3) for c in sg[1:5]) for sg in segs)
for sg in _es: # ESC_PATHS 的折线(被拆掉了就补回来)
if sg[6] in nets and tuple(round(c, 3) for c in sg[1:5]) not in have:
segs.append(tuple(sg))
for p, (ex, ey), lay in _evirt:
if (p[0], p[1]) in RT.ESC_PATHS:
qmap[(p[0], p[1])] = (ex, ey, lay)
dropk = set((p[0], p[1]) for p in edrop) | fixdrop
bypad = {}
for net in nets:
ps = []
for p in pads:
if p[7] != net or p[0] == 'J1':
continue
if (p[0], p[1]) in dropk:
continue
if (p[0], p[1]) in qmap:
ex, ey, lay = qmap[(p[0], p[1])]
ps.append([p[0], 'qfan:%s' % p[1], ex, ey, 0.3, 0.3, lay, net, 'RECT'])
continue
e = esc.get((p[0], p[1]))
if e:
lay = RT.LAY[1] if p[6] == RT.LAY[0] else RT.LAY[0]
ps.append([p[0], 'qfan:%s' % p[1], e[0], e[1], 0.3, 0.3, lay, net, 'RECT'])
else:
ps.append(p)
for (lay, x, y) in launch.get(net, []):
ps.append(['J1', 'launch', x, y, 0.3, 0.3, lay, net, 'RECT'])
if net in fixvirt:
ps.append(fixvirt[net])
# `_opt_virt.json`(可选):{网: {"drop": [[位号, 脚], ...], "add": [[x, y, 层], ...]}}
# drop = 已由手定短线接好的焊盘;add = 那些短线的端点,当虚拟焊盘
if net in VIRT:
dk = set(tuple(x) for x in VIRT[net].get('drop', []))
ps = [q for q in ps if (q[0], str(q[1]).split(':')[-1]) not in dk]
ps += [['VIRT', 'v%d' % n_, x, y, 0.3, 0.3, l, net, 'RECT'] for n_, (x, y, l) in enumerate(VIRT[net].get('add', []))]
bypad[net] = ps
RT.rule_width = lambda net, a, _n=set(nets): W if net in _n else RT.W_DEFAULT
RT.rule_min = lambda net, a: W
n0, v0 = len(segs), len(vias)
# 逐网调用 route_groups:顺序真正按参数走(一次传全部时它自己按「出口数 / 跨度」重排,顺序参数不起作用)
logs = []
for net in nets:
logs += RT.route_groups({net: bypad[net]}, pads, segs, vias, board_vias, auto,
priority=(net,), only={net})
board_vias = [(v[0], v[1], v[2], RT.VIA_D) for v in vias]
L = {}
for s in segs[n0:]:
L[s[6]] = L.get(s[6], 0.0) + math.hypot(s[3] - s[1], s[4] - s[2])
print(u'[%d] %s:新增 %d 段 / %d 孔,总长 %.1f,长度 %s,未通 %s'
% (k_, order, len(segs) - n0, len(vias) - v0, sum(L.values()),
' '.join('%s=%.1f' % kv for kv in sorted(L.items())), logs))
json.dump({'segs': [list(s) for s in segs], 'vias': [list(v) for v in vias], 'logs': logs},
io.open(os.path.join(HERE, '_blade_routes.opt%d.json' % k_), 'w', encoding='utf-8'),
ensure_ascii=False)
if __name__ == '__main__':
main()