原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。 这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。 纳入: - 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本 - .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、 pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源) - 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾) - firmware/ 的 A1 骨架与 site/ 文档站源码 .gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、 site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。 .gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存, 不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
95 行
3.6 KiB
Python
95 行
3.6 KiB
Python
# -*- 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()
|