文件

89 行
4.3 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""D16:把一个网里孤立的小块接到本网**已有的铜**上(不必落在某只焊盘上)—— 服务器跑。
DCDC_ROUTE_SERVER=1 /root/pypy/bin/pypy3 .claude/r2/d16_tap.py NET [--extra 结果文件 ...] [--w 0.2]
route_nets 每块只挑一只焊盘当代表,大块挑中的那只脚出不来就整网失败(2026-09-12 SDA:U13.4 出不来)。
这里小块照旧用焊盘;大块改用本网已有线段上每 0.5 mm 取的点当虚拟焊盘,按离小块由近到远逐个试,接上即停。
--extra:本机还没下发的结果(如刚布好的 SCL)一并当障碍。写 _d16_tap.out.json。
"""
import io
import json
import math
import os
import sys
if os.environ.get('DCDC_ROUTE_SERVER') != '1':
sys.exit(u'!! 布线运算只在服务器上跑(DCDC_ROUTE_SERVER=1),见 CLAUDE.md')
if '--grid' not in sys.argv:
sys.argv += ['--grid', '0.125']
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
import route_nets as N # noqa: E402
R = N.R
TRIES = 30
def main():
skip = {k + 1 for k, a in enumerate(sys.argv) if a in ('--extra', '--w', '--grid')}
net = [a for k, a in enumerate(sys.argv) if k >= 1 and k not in skip and not a.startswith('--')][0]
w = float(sys.argv[sys.argv.index('--w') + 1]) if '--w' in sys.argv else 0.2
b = json.load(io.open(os.path.join(HERE, '_board_for_nets.json'), encoding='utf-8'))
segs = [tuple(s[:7]) for s in b['segs']]
vias = [tuple(v[:3]) for v in b['vias']]
for k, a in enumerate(sys.argv):
if a == '--extra':
e = json.load(io.open(os.path.join(HERE, sys.argv[k + 1]), encoding='utf-8'))
segs += [tuple(s[:7]) for s in e['segs']]
vias += [tuple(v[:3]) for v in e['vias']]
pads = [p for p in R.load_pads() if not str(p[1]).endswith(R.TH_SUFFIX)]
groups = sorted(N.components(net, pads, segs, vias), key=len)
print(u'%s:%d 块,小块 %s' % (net, len(groups), ['%s.%s' % (q[0], q[1]) for q in groups[0]]))
if len(groups) < 2:
return
sp = groups[0][0]
cand = []
for s in segs:
if s[6] != net or s[0] not in (1, 2):
continue
n = max(1, int(math.hypot(s[3] - s[1], s[4] - s[2]) / 0.5))
for k in range(n + 1):
x, y = s[1] + (s[3] - s[1]) * k / n, s[2] + (s[4] - s[2]) * k / n
cand.append((math.hypot(x - sp[2], y - sp[3]), s[0], round(x, 3), round(y, 3), s[5]))
# 本网的过孔也当落点(两个外层各一块 0.6 焊盘):大块有的地方只靠内层线连着(EasyEDA 自动布线留在 L2/L3 的 SDA),
# 外层上一根本网的线都没有,只有孔 —— 2026-09-12 SDA 第一版只取外层线段上的点,候选全在 45 mm 外、全不通
for v in vias:
if v[2] == net:
for l in (1, 2):
cand.append((math.hypot(v[0] - sp[2], v[1] - sp[3]), l, round(v[0], 3), round(v[1], 3), 0.6))
cand.sort()
picked = []
for c in cand:
if all(math.hypot(c[2] - p[2], c[3] - p[3]) > 1.0 or c[1] != p[1] for p in picked):
picked.append(c)
if len(picked) >= TRIES:
break
out = {'net': net, 'segs': [], 'vias': [], 'tries': [], 'logs': []}
for d, l, x, y, ww in picked:
vp = ['#tap', '1', x, y, max(ww, 0.2), max(ww, 0.2), l, net, 'RECT']
N.INNER[:] = [s for s in segs if s[0] in (15, 16)]
obst = [s for s in segs if s[0] in (1, 2)]
lg = []
s2, v2 = R.route_one(net, [sp, vp], w, pads + [vp], obst, vias, [], lg)
after = N.components(net, pads, segs + [tuple(q) for q in s2], vias + [tuple(q) for q in v2])
ok = len(after) < len(groups)
out['tries'].append([round(d, 2), l, x, y, ok, len(s2), len(v2)])
print(u' 试 L%s (%.2f,%.2f) 距 %.1f:%s' % (l, x, y, d, u'接上(%d 段 / %d 孔)' % (len(s2), len(v2)) if ok else u'不通'))
if ok:
out['segs'] = [list(q) for q in s2]
out['vias'] = [list(q) for q in v2]
out['logs'] = lg
break
io.open(os.path.join(HERE, '_d16_tap.out.json'), 'w', encoding='utf-8').write(json.dumps(out, ensure_ascii=False))
if __name__ == '__main__':
main()