# -*- 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()