R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发
- 规则:铜层 2→4,差分 0.28/0.18,间距 0.15,过孔 0.3/0.2(rules_base) - 几何:98×98 板框 + 4×M3,槽阵居中,L1 12V 大铜 + 指头(pcb_base) - 摆位:五插槽留 L1,其余 133 件翻到 L4;背面镜像规则实测;Hub 放走廊 2、 东移 2.5 mm;扇出圈 / 小件间距 1.5(去耦例外)/ 9 A 过孔阵禁区(place_base) - 叠层按用户决定改为 L1 槽面 / L2 整层 +3V3 / L3 整层 GND / L4 器件面 - 布线:D± 七对按构造布通(USB3 掉头、USB1/2 北去掉头、USB4/5 东绕、 J23 桥),+3V3 / GND / +12V 平面网每脚一孔,0.125 网格 + PathFinder 开关(route_base、remote_route.ps1);剩 37 个网待手工补 - 铺铜:4 层重写,入口链自南向北切段 + 断面校核(pour_base); 已下发布线 / 缝合孔 / 铜面轮廓,填铜未成功(待查) - 工具:plot_base / plot_routes / shot_base,board_check 通孔两层都算 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
+94
-94
@@ -1,94 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""删掉指定矩形框里的**某个网络**的走线与过孔(板坐标或站内坐标)。
|
||||
|
||||
/c/Python314/python .claude/pcb2_del_box.py GND --site 54.9 36.8 56.5 37.5
|
||||
/c/Python314/python .claude/pcb2_del_box.py GND --board 100 60 102 62
|
||||
加 `--push` 才真删,不加只列出来。
|
||||
|
||||
## 为什么需要它
|
||||
|
||||
板上的铜是好几个脚本各画各的(`pcb2_dp_long` / `pcb2_fanout` / `pcb2_vo_vias` / `pcb2_route_sig`),
|
||||
每个脚本的 `--push` 只删**自己上一轮**画的东西。挪了一个元件之后,
|
||||
它那颗扇出孔就成了没人认领的孤儿 —— 谁的删除逻辑都不管,DRC 只报一条
|
||||
「过孔没连上任何东西」,很容易被当成噪声放过去。
|
||||
|
||||
## 判据
|
||||
|
||||
- **完全落在框里**才删(导线两端都在框内、过孔中心在框内)。半进半出的一律不动,
|
||||
免得把一条长线截断一半留在板上 —— 那比不删还糟。
|
||||
- `--site` 是站内坐标,会自动展开到五个手机位(`pcb2_place.to_board`,4/5 站镜像)。
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
from eda import run
|
||||
from pcb2_place import SITES, to_board
|
||||
|
||||
PCB = 'f126ffb29c92f9b2'
|
||||
MIL = 39.3700787401575
|
||||
|
||||
|
||||
def boxes_from_argv():
|
||||
if '--site' in sys.argv:
|
||||
i = sys.argv.index('--site')
|
||||
u0, v0, u1, v1 = [float(v) for v in sys.argv[i + 1:i + 5]]
|
||||
out = []
|
||||
for n in SITES:
|
||||
ax, ay, _ = to_board(n, u0, v0)
|
||||
bx, by, _ = to_board(n, u1, v1)
|
||||
out.append((min(ax, bx), min(ay, by), max(ax, bx), max(ay, by)))
|
||||
return out
|
||||
i = sys.argv.index('--board')
|
||||
x0, y0, x1, y1 = [float(v) for v in sys.argv[i + 1:i + 5]]
|
||||
return [(min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1))]
|
||||
|
||||
|
||||
JS = u"""
|
||||
await eda.dmt_EditorControl.openDocument('%s');
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
const M = 39.3700787401575, q = v => Math.round(v / M * 1e4) / 1e4;
|
||||
const NET = %s, B = %s, DO = %s;
|
||||
const inB = (x, y) => B.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
|
||||
const lines = [], vias = [];
|
||||
for (const l of await eda.pcb_PrimitiveLine.getAll()) {
|
||||
if ((l.net || '') !== NET) continue;
|
||||
if (l.layer !== 1 && l.layer !== 2) continue;
|
||||
if (inB(q(l.startX), q(l.startY)) && inB(q(l.endX), q(l.endY)))
|
||||
lines.push([l.primitiveId, q(l.startX), q(l.startY), q(l.endX), q(l.endY), l.layer]);
|
||||
}
|
||||
for (const v of await eda.pcb_PrimitiveVia.getAll()) {
|
||||
if ((v.net || '') !== NET) continue;
|
||||
if (inB(q(v.x), q(v.y))) vias.push([v.primitiveId, q(v.x), q(v.y)]);
|
||||
}
|
||||
if (DO) {
|
||||
if (lines.length) await eda.pcb_PrimitiveLine.delete(lines.map(l => l[0]));
|
||||
if (vias.length) await eda.pcb_PrimitiveVia.delete(vias.map(v => v[0]));
|
||||
await eda.pcb_Document.save();
|
||||
}
|
||||
return {lines: lines.map(l => l.slice(1)), vias: vias.map(v => v.slice(1)), did: DO};
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
net = sys.argv[1]
|
||||
boxes = boxes_from_argv()
|
||||
do = '--push' in sys.argv
|
||||
r = run(JS % (PCB, json.dumps(net), json.dumps(boxes), 'true' if do else 'false'),
|
||||
timeout=600)
|
||||
if not r.get('success'):
|
||||
sys.exit(u'失败: ' + json.dumps(r, ensure_ascii=False)[:400])
|
||||
x = r['result']
|
||||
print(u'%s:%d 个框里有 %s 的导线 %d 条 / 过孔 %d 个'
|
||||
% (u'已删' if do else u'(预览,加 --push 才删)', len(boxes), net,
|
||||
len(x['lines']), len(x['vias'])))
|
||||
for l in x['lines'][:20]:
|
||||
print(u' 线 L%d (%.3f, %.3f) -> (%.3f, %.3f)' % (l[4], l[0], l[1], l[2], l[3]))
|
||||
for v in x['vias'][:20]:
|
||||
print(u' 孔 (%.3f, %.3f)' % (v[0], v[1]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""删掉指定矩形框里的**某个网络**的走线与过孔(板坐标或站内坐标)。
|
||||
|
||||
/c/Python314/python .claude/pcb2_del_box.py GND --site 54.9 36.8 56.5 37.5
|
||||
/c/Python314/python .claude/pcb2_del_box.py GND --board 100 60 102 62
|
||||
加 `--push` 才真删,不加只列出来。
|
||||
|
||||
## 为什么需要它
|
||||
|
||||
板上的铜是好几个脚本各画各的(`pcb2_dp_long` / `pcb2_fanout` / `pcb2_vo_vias` / `pcb2_route_sig`),
|
||||
每个脚本的 `--push` 只删**自己上一轮**画的东西。挪了一个元件之后,
|
||||
它那颗扇出孔就成了没人认领的孤儿 —— 谁的删除逻辑都不管,DRC 只报一条
|
||||
「过孔没连上任何东西」,很容易被当成噪声放过去。
|
||||
|
||||
## 判据
|
||||
|
||||
- **完全落在框里**才删(导线两端都在框内、过孔中心在框内)。半进半出的一律不动,
|
||||
免得把一条长线截断一半留在板上 —— 那比不删还糟。
|
||||
- `--site` 是站内坐标,会自动展开到五个手机位(`pcb2_place.to_board`,4/5 站镜像)。
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
from eda import run
|
||||
from pcb2_place import SITES, to_board
|
||||
|
||||
PCB = '942ed1560d81c1e7'
|
||||
MIL = 39.3700787401575
|
||||
|
||||
|
||||
def boxes_from_argv():
|
||||
if '--site' in sys.argv:
|
||||
i = sys.argv.index('--site')
|
||||
u0, v0, u1, v1 = [float(v) for v in sys.argv[i + 1:i + 5]]
|
||||
out = []
|
||||
for n in SITES:
|
||||
ax, ay, _ = to_board(n, u0, v0)
|
||||
bx, by, _ = to_board(n, u1, v1)
|
||||
out.append((min(ax, bx), min(ay, by), max(ax, bx), max(ay, by)))
|
||||
return out
|
||||
i = sys.argv.index('--board')
|
||||
x0, y0, x1, y1 = [float(v) for v in sys.argv[i + 1:i + 5]]
|
||||
return [(min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1))]
|
||||
|
||||
|
||||
JS = u"""
|
||||
await eda.dmt_EditorControl.openDocument('%s');
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
const M = 39.3700787401575, q = v => Math.round(v / M * 1e4) / 1e4;
|
||||
const NET = %s, B = %s, DO = %s;
|
||||
const inB = (x, y) => B.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
|
||||
const lines = [], vias = [];
|
||||
for (const l of await eda.pcb_PrimitiveLine.getAll()) {
|
||||
if ((l.net || '') !== NET) continue;
|
||||
if (l.layer !== 1 && l.layer !== 2) continue;
|
||||
if (inB(q(l.startX), q(l.startY)) && inB(q(l.endX), q(l.endY)))
|
||||
lines.push([l.primitiveId, q(l.startX), q(l.startY), q(l.endX), q(l.endY), l.layer]);
|
||||
}
|
||||
for (const v of await eda.pcb_PrimitiveVia.getAll()) {
|
||||
if ((v.net || '') !== NET) continue;
|
||||
if (inB(q(v.x), q(v.y))) vias.push([v.primitiveId, q(v.x), q(v.y)]);
|
||||
}
|
||||
if (DO) {
|
||||
if (lines.length) await eda.pcb_PrimitiveLine.delete(lines.map(l => l[0]));
|
||||
if (vias.length) await eda.pcb_PrimitiveVia.delete(vias.map(v => v[0]));
|
||||
await eda.pcb_Document.save();
|
||||
}
|
||||
return {lines: lines.map(l => l.slice(1)), vias: vias.map(v => v.slice(1)), did: DO};
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
net = sys.argv[1]
|
||||
boxes = boxes_from_argv()
|
||||
do = '--push' in sys.argv
|
||||
r = run(JS % (PCB, json.dumps(net), json.dumps(boxes), 'true' if do else 'false'),
|
||||
timeout=600)
|
||||
if not r.get('success'):
|
||||
sys.exit(u'失败: ' + json.dumps(r, ensure_ascii=False)[:400])
|
||||
x = r['result']
|
||||
print(u'%s:%d 个框里有 %s 的导线 %d 条 / 过孔 %d 个'
|
||||
% (u'已删' if do else u'(预览,加 --push 才删)', len(boxes), net,
|
||||
len(x['lines']), len(x['vias'])))
|
||||
for l in x['lines'][:20]:
|
||||
print(u' 线 L%d (%.3f, %.3f) -> (%.3f, %.3f)' % (l[4], l[0], l[1], l[2], l[3]))
|
||||
for v in x['vias'][:20]:
|
||||
print(u' 孔 (%.3f, %.3f)' % (v[0], v[1]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
在新工单中引用
屏蔽一个用户