R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""刀片布线缓存的**离线连通性**:按铜重叠做并查集(线段 / 过孔 / 焊盘,挨着就算连),纯几何校核。
|
||||
|
||||
/c/Python314/python .claude/r2/blade_conn.py # _blade_routes.json
|
||||
/c/Python314/python .claude/r2/blade_conn.py _blade_routes.var0.json _blade_routes.var1.json
|
||||
|
||||
为什么要有:`router.py` 自报的「[连通性] XXX: 铜分成 2 块」不可靠 —— 2026-09-11 第二轮服务器结果
|
||||
自报 8 条,按铜判只有 3 条是真断(+3V3 / VBUS / SCL / SDA / $1N136 都是误报)。比较变体、决定攻哪几个网,
|
||||
看这里的数。平面网 GND / VO_P 不判(靠铺铜 / L3 岛成网);+3V3 当普通网查。
|
||||
"""
|
||||
import json, math, sys
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
R2 = r'D:/DCDC/.claude/r2/'
|
||||
pads = json.load(open(R2 + '_blade_pads.json', encoding='utf-8'))
|
||||
VR, TOL = 0.3, 0.02
|
||||
PLANE = ('GND', 'VO_P', '+12V') # 2026-09-11 晚起 +12V 也靠 L3 岛成网(方案 §35)
|
||||
def pt_seg(px, py, ax, ay, bx, by):
|
||||
dx, dy = bx-ax, by-ay; L = dx*dx+dy*dy
|
||||
t = 0 if L == 0 else max(0, min(1, ((px-ax)*dx+(py-ay)*dy)/L))
|
||||
return math.hypot(px-(ax+t*dx), py-(ay+t*dy))
|
||||
def seg_seg(a, b):
|
||||
(x1,y1,x2,y2),(x3,y3,x4,y4) = a, b
|
||||
d = (x2-x1)*(y4-y3)-(y2-y1)*(x4-x3)
|
||||
if abs(d) > 1e-12:
|
||||
t = ((x3-x1)*(y4-y3)-(y3-y1)*(x4-x3))/d; u = ((x3-x1)*(y2-y1)-(y3-y1)*(x2-x1))/d
|
||||
if 0 <= t <= 1 and 0 <= u <= 1: return 0.0
|
||||
return min(pt_seg(x1,y1,x3,y3,x4,y4), pt_seg(x2,y2,x3,y3,x4,y4), pt_seg(x3,y3,x1,y1,x2,y2), pt_seg(x4,y4,x1,y1,x2,y2))
|
||||
def pt_rect(px, py, r):
|
||||
return math.hypot(max(r[0]-px, 0, px-r[2]), max(r[1]-py, 0, py-r[3]))
|
||||
def seg_rect(s, r):
|
||||
if pt_rect(s[0], s[1], r) == 0 or pt_rect(s[2], s[3], r) == 0: return 0.0
|
||||
e = [(r[0],r[1],r[2],r[1]),(r[2],r[1],r[2],r[3]),(r[2],r[3],r[0],r[3]),(r[0],r[3],r[0],r[1])]
|
||||
return min(seg_seg(s, x) for x in e)
|
||||
def check(path):
|
||||
c = json.load(open(path, encoding='utf-8'))
|
||||
bynet = {}
|
||||
for p in pads:
|
||||
if p[7]: bynet.setdefault(p[7], {'P': [], 'S': [], 'V': []})['P'].append(p)
|
||||
for s in c['segs']: bynet.setdefault(s[6], {'P': [], 'S': [], 'V': []})['S'].append(s)
|
||||
for v in c['vias']: bynet.setdefault(v[2], {'P': [], 'S': [], 'V': []})['V'].append(v)
|
||||
bad = {}
|
||||
for net, g in sorted(bynet.items()):
|
||||
if net in PLANE or len(g['P']) < 2: continue
|
||||
items = [('P', p) for p in g['P']] + [('S', s) for s in g['S']] + [('V', v) for v in g['V']]
|
||||
par = list(range(len(items)))
|
||||
def f(i):
|
||||
while par[i] != i: par[i] = par[par[i]]; i = par[i]
|
||||
return i
|
||||
def touch(a, b):
|
||||
ka, A = a; kb, B = b
|
||||
if ka == 'P' and kb == 'P': return False
|
||||
if ka == 'V' and kb == 'V': return math.hypot(A[0]-B[0], A[1]-B[1]) <= 2*VR + TOL
|
||||
if ka == 'S' and kb == 'S':
|
||||
return A[0] == B[0] and seg_seg(A[1:5], B[1:5]) <= (A[5]+B[5])/2 + TOL
|
||||
if {ka, kb} == {'S', 'P'}:
|
||||
s, p = (A, B) if ka == 'S' else (B, A)
|
||||
r = (p[2]-p[4]/2, p[3]-p[5]/2, p[2]+p[4]/2, p[3]+p[5]/2)
|
||||
return s[0] == p[6] and seg_rect(s[1:5], r) <= s[5]/2 + TOL
|
||||
if {ka, kb} == {'V', 'P'}:
|
||||
v, p = (A, B) if ka == 'V' else (B, A)
|
||||
r = (p[2]-p[4]/2, p[3]-p[5]/2, p[2]+p[4]/2, p[3]+p[5]/2)
|
||||
return pt_rect(v[0], v[1], r) <= VR + TOL
|
||||
v, s = (A, B) if ka == 'V' else (B, A)
|
||||
return pt_seg(v[0], v[1], *s[1:5]) <= VR + s[5]/2 + TOL
|
||||
for i in range(len(items)):
|
||||
for j in range(i+1, len(items)):
|
||||
if touch(items[i], items[j]):
|
||||
a, b = f(i), f(j)
|
||||
if a != b: par[a] = b
|
||||
grp = {}
|
||||
for i, (k, it) in enumerate(items):
|
||||
if k == 'P': grp.setdefault(f(i), []).append('%s.%s' % (it[0], it[1]))
|
||||
if len(grp) > 1:
|
||||
gs = sorted(grp.values(), key=len, reverse=True)
|
||||
bad[net] = gs
|
||||
return bad
|
||||
files = [a for a in sys.argv[1:]] or ['_blade_routes.json']
|
||||
for fn in files:
|
||||
b = check(fn if (':' in fn or fn.startswith('/')) else R2 + fn)
|
||||
print('===== %s:离线真断开 %d 个网' % (fn, len(b)))
|
||||
for n, gs in b.items():
|
||||
print(' %-10s %d 块:主块 %d 脚;其余 %s' % (n, len(gs), len(gs[0]), ' | '.join(' '.join(g) for g in gs[1:])[:160]))
|
||||
在新工单中引用
屏蔽一个用户