文件
zhou yang和Claude Opus 5 312089326e R2 底板:按用户布局重布风扇窗口 + L1 走廊重开 + 位号丝印重排
布线(窗口整体重布,已下发):
- 拆窗口内 43 段(用户手布的那批,用户选「拆掉重来」),补 139 段 / 7 孔,
  GND 回流孔 10 个;fan_check 对板上真实快照逐项净距达标(含「新孔 vs 内层线」)。
- ⛔ 根因:pcb_base.PD_L1 里的 L1 走廊是按**旧摆位**开的(注释坐标全是旧的),
  用户重摆后与件对不上 ⇒ 四条长途网必然布不通。重开六条走廊后未完成 4 → 2。
  走廊必须盖住焊盘正上方,只盖沿途不行。断面:几何 11.80 / 铺铜后实测 9.82(要 8.0)。
- 与拆线前逐网对比:没引入任何新的连通性问题(GND 未接 58→48、+3V3 2→0、
  两路 TACH 2/1→0、+12V 一字不差)。

定版:板上铜以**用户自己布好的那版**为准,不再改动。

丝印(silk_base.py,已下发并读回核对 150/150):
- 压焊盘 128→4、压过孔 48→8、越框 8→3、互相重叠 34 对→0;字号不变。
- 三条坑:rotation 是度且不归一化(900=180°);别拿「本体≥5mm」当保留白名单
  (会豁免掉 R9A/D3/U13 这些该重排的件);「离本体」必须设硬上限 + 降级策略。

新工具:silk_base.py(丝印重排)、l1_section.py(L1 12V 主块逐 y 断面核算)、
fan_rip.py(按窗口拆线,拆前后比对全板线/孔总数防连带删除)。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
2026-09-12 12:02:32 +08:00

98 行
4.0 KiB
Python

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""按坐标**拆掉窗口内待布网的旧铜**(下发新布线之前的第一步)。
/c/Python314/python .claude/r2/fan_rip.py # 只列清单,不动板
/c/Python314/python .claude/r2/fan_rip.py --push # 真删
⛔ 2026-09-12 实测:**删外层段会连带清掉过孔和它在内层的延续** —— 点名删 6 段,读回发现线少 12 段、
孔少 8 个,多掉的全在 L15/L16。⇒ 拆前后都要比对**全板**线 / 孔总数,不能只数自己点名的那几段。
这里每次都先读回全板、删完再读回,逐项打印差值。
判据与 `repair_window` 同口径:`_base_window.json` 的窗口 + 网名,**两个端点都在窗口内**才算窗口内的铜
(跨窗边界的段是主干接口,必须留着)。
"""
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)
from eda import run # noqa: E402
import pcb_base as B # noqa: E402
MIL = 0.0254
CFG = json.load(io.open(os.path.join(HERE, '_base_window.json'), encoding='utf-8'))
WIN = CFG['window']
NETS = set(n.replace('@', '$') for n in CFG['nets'])
OPEN = ("await eda.dmt_EditorControl.openDocument('%s');"
"await new Promise(r=>setTimeout(r,2500));" % B.PCB)
READ = OPEN + """
const L=(await eda.pcb_PrimitiveLine.getAll()||[]).filter(l=>[1,2,15,16].includes(l.layer))
.map(l=>[l.primitiveId,l.net,l.layer,l.startX,l.startY,l.endX,l.endY,l.lineWidth]);
const V=(await eda.pcb_PrimitiveVia.getAll()||[]).map(v=>[v.primitiveId,v.net,v.x,v.y]);
return {L, V};
"""
def inw(x, y):
return WIN[0] <= x <= WIN[2] and WIN[1] <= y <= WIN[3]
def read():
r = run(READ, timeout=300)
assert r.get('success'), json.dumps(r, ensure_ascii=False)[:400]
return r['result']
def main():
d = read()
L, V = d['L'], d['V']
outer = [l for l in L if l[2] in (1, 2)]
inner = [l for l in L if l[2] in (15, 16)]
print(u'板上:外层 %d 段 / 内层 %d 段 / 过孔 %d' % (len(outer), len(inner), len(V)))
kill = []
for pid, net, lay, x1, y1, x2, y2, w in outer:
if net not in NETS:
continue
if inw(x1 * MIL, y1 * MIL) and inw(x2 * MIL, y2 * MIL):
kill.append((pid, net, lay, x1 * MIL, y1 * MIL, x2 * MIL, y2 * MIL))
killv = [(v[0], v[1]) for v in V if v[1] in NETS and inw(v[2] * MIL, v[3] * MIL)]
print(u'要拆:%d 段 / %d 孔' % (len(kill), len(killv)))
by = {}
for k in kill:
by[k[1]] = by.get(k[1], 0) + 1
for n in sorted(by):
print(u' %-18s %d 段' % (n, by[n]))
io.open(os.path.join(HERE, '_base_fan_ripped.json'), 'w', encoding='utf-8').write(
json.dumps({'segs': [[k[2], k[3], k[4], k[5], k[6], 0, k[1]] for k in kill],
'vias': []}, ensure_ascii=False))
if '--push' not in sys.argv:
print(u'(只列清单;加 --push 才真删)')
return
ids = [k[0] for k in kill] + [v[0] for v in killv]
r = run(OPEN + """
const ids = %s;
let n = 0;
for (const id of ids) { try { await eda.pcb_PrimitiveLine.delete(id); n++; } catch (e) {
try { await eda.pcb_PrimitiveVia.delete(id); n++; } catch (e2) {} } }
await eda.pcb_Document.save();
return n;
""" % json.dumps(ids), timeout=600)
print(u'删除返回:%s' % json.dumps(r.get('result'), ensure_ascii=False))
d2 = read()
o2 = [l for l in d2['L'] if l[2] in (1, 2)]
i2 = [l for l in d2['L'] if l[2] in (15, 16)]
print(u'拆后:外层 %d 段(−%d,点名 %d)/ 内层 %d 段(−%d)/ 过孔 %d(−%d)'
% (len(o2), len(outer) - len(o2), len(kill), len(i2), len(inner) - len(i2),
len(d2['V']), len(V) - len(d2['V'])))
if len(outer) - len(o2) != len(kill) or len(inner) != len(i2):
print(u'⛔ 连带删除!实际掉的和点名的对不上,检查内层 / 过孔')
if __name__ == '__main__':
main()