文件
zhou yang和Claude Opus 5 efcba30a0c 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
2026-09-10 21:02:10 +08:00

90 行
3.8 KiB
Python

# -*- coding: utf-8 -*-
u"""把一页原理图的全部图元读回成 JSON(跨工程搬版图用)。
/c/Python314/python .claude/r2/dump_page.py <projectUuid> <pageUuid> <out.json>
读回的六类:
parts [位号, 器件名, 子部件, x, y, rot, mirror, uuid, libraryUuid, 引脚]
引脚 = [[脚号, 脚名, x, y], ...] ← 跨工程重放时的断言基准(§6c:方向表一张都别信)
wires [[x1,y1],[x2,y2]] ← **按 §5 的端点对解析**,不是折线
flags [种类, 网名, x, y, rot] 种类 = Power / Ground(按符号名判)
ports [dir, 网名, x, y, rot] dir 来自 getState_Component().name(§8b 尾)
texts [x, y, 内容, rot, 字号]
rects/polys 只数个数(本项目 P2 没有)
⚠️ 只读,不写。切工程会改变客户端的活动工程,跑完记得切回去。
"""
import io
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
# ⚠ `.claude` 下有和 r2 同名的 R1 脚本(pcb_pour / pcb_rules / pcb_place)。
# 只插父目录的话,**后面任何一个 `import pcb_rules` 都会拿到 R1 那一份**,
# 而且不报错,只在调到 R2 专有的函数时才炸(2026-09-08 踩过)。
# 规矩:两行都要写,HERE 后插(在 sys.path 最前)。
sys.path.insert(0, os.path.dirname(HERE))
sys.path.insert(0, HERE)
from eda import run # noqa: E402
JS = u"""
await eda.dmt_Project.openProject('%(proj)s');
await new Promise(r => setTimeout(r, 2500));
await eda.dmt_EditorControl.openDocument('%(page)s');
await new Promise(r => setTimeout(r, 2500));
const cur = await eda.dmt_Schematic.getCurrentSchematicPageInfo();
const parts = [], flags = [], ports = [];
for (const c of await eda.sch_PrimitiveComponent.getAll()) {
const t = c.getState_ComponentType();
const x = c.getState_X(), y = c.getState_Y(), r = c.getState_Rotation();
const comp = c.getState_Component() || {};
if (t === 'part') {
const pins = (await c.getAllPins()).map(p => [p.getState_PinNumber(),
(p.getState_PinName ? p.getState_PinName() : ''),
Math.round(p.getState_X()), Math.round(p.getState_Y())]);
parts.push([c.getState_Designator(), comp.name, c.getState_SubPartName(),
x, y, r, !!c.getState_Mirror(), comp.uuid, comp.libraryUuid, pins]);
} else if (t === 'netflag') {
flags.push([comp.name, c.getState_Net(), x, y, r]);
} else if (t === 'netport') {
ports.push([comp.name, c.getState_Net(), x, y, r]);
}
}
const wires = [];
for (const w of await eda.sch_PrimitiveWire.getAll()) {
const p = w.getState_Line();
for (let i = 0; i + 1 < p.length; i += 2) wires.push([p[i], p[i + 1]]);
}
const texts = [];
for (const t of await eda.sch_PrimitiveText.getAll()) {
texts.push([t.getState_X(), t.getState_Y(), t.getState_Content(),
t.getState_Rotation(), t.getState_FontSize()]);
}
return {page: cur && cur.name, parts, flags, ports, wires, texts,
nRect: (await eda.sch_PrimitiveRectangle.getAll()).length,
nPoly: (await eda.sch_PrimitivePolygon.getAll()).length};
"""
def main():
proj, page, out = sys.argv[1], sys.argv[2], sys.argv[3]
r = run(JS % {'proj': proj, 'page': page}, timeout=300)
if not r.get('success'):
raise SystemExit(json.dumps(r, ensure_ascii=False)[:600])
d = r['result']
io.open(out, 'w', encoding='utf-8').write(
json.dumps(d, ensure_ascii=False, indent=1))
print(u'页 %s:元件 %d / 导线段 %d / 旗 %d / 端口 %d / 文字 %d / 矩形 %d / 多边形 %d'
% (d['page'], len(d['parts']), len(d['wires']), len(d['flags']),
len(d['ports']), len(d['texts']), d['nRect'], d['nPoly']))
print(u'-> ' + out)
if __name__ == '__main__':
main()