130 行
5.3 KiB
Python
130 行
5.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""按**连线闭包**整块删掉一页上的一个子电路(元件 + 与之相连的导线 / 旗 / 端口)。
|
||
|
||
/c/Python314/python .claude/sch_cut.py <pageUuid> Q103 Q104 ... # 干跑:打印闭包
|
||
/c/Python314/python .claude/sch_cut.py <pageUuid> Q103 Q104 ... --push # 真删并存盘
|
||
|
||
判据(skill §5 / §10):导线按「端点对」解析;一段导线和一个引脚相连 = 引脚落在该段的
|
||
端点或中段;两个导线图元相连 = 一方的某个端点落在另一方的某一段上。
|
||
从待删元件的全部引脚出发做闭包,闭包里的导线段上如果站着**不在删除清单里的元件引脚**,
|
||
直接终止 —— 说明这块电路和别的电路是连着的,不能整块删。
|
||
旗 / 端口的引脚只要落在闭包导线的任意一段上就一起删(它们本来就只是这段线的名字)。
|
||
|
||
2026-09-06 为「74HC595 那一窝挪到载板」写的:P2×5 的按键 MOS 块、P3B 的 U21/U22、P6 的 U33。
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, HERE)
|
||
from eda import run # noqa: E402
|
||
|
||
JS_READ = u"""
|
||
await eda.dmt_EditorControl.openDocument('%s');
|
||
await new Promise(r => setTimeout(r, 1200));
|
||
const cur = (await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;
|
||
const parts = [], flags = [];
|
||
for (const c of await eda.sch_PrimitiveComponent.getAll()) {
|
||
const t = c.getState_ComponentType();
|
||
if (t === 'part') {
|
||
const ps = await c.getAllPins();
|
||
parts.push([c.getState_PrimitiveId(), c.getState_Designator(),
|
||
ps.map(p => [p.getState_PinNumber(), Math.round(p.getState_X()), Math.round(p.getState_Y())])]);
|
||
} else if (t === 'netport' || t === 'netflag') {
|
||
flags.push([c.getState_PrimitiveId(), t, c.getState_Net(), Math.round(c.getState_X()), Math.round(c.getState_Y())]);
|
||
}
|
||
}
|
||
const wires = (await eda.sch_PrimitiveWire.getAll()).map(w => [w.getState_PrimitiveId(), w.getState_Line().map(Math.round)]);
|
||
return {cur, parts, flags, wires};
|
||
"""
|
||
|
||
JS_DEL = u"""
|
||
await eda.dmt_EditorControl.openDocument('%s');
|
||
await new Promise(r => setTimeout(r, 1200));
|
||
const C = %s, W = %s;
|
||
if (C.length) await eda.sch_PrimitiveComponent.delete(C);
|
||
if (W.length) await eda.sch_PrimitiveWire.delete(W);
|
||
await eda.sch_Document.save();
|
||
await new Promise(r => setTimeout(r, 800));
|
||
return {c: C.length, w: W.length};
|
||
"""
|
||
|
||
|
||
def on_seg(p, a, b):
|
||
u"""点 p 是否落在线段 ab 上(横平竖直,含端点)。"""
|
||
(x, y), (x1, y1), (x2, y2) = p, a, b
|
||
if x1 == x2 == x:
|
||
return min(y1, y2) <= y <= max(y1, y2)
|
||
if y1 == y2 == y:
|
||
return min(x1, x2) <= x <= max(x1, x2)
|
||
return False
|
||
|
||
|
||
def segs_of(line):
|
||
pts = list(zip(line[0::2], line[1::2]))
|
||
return [(pts[i], pts[i + 1]) for i in range(0, len(pts) - 1, 2)]
|
||
|
||
|
||
def read(page):
|
||
r = run(JS_READ % page, timeout=300)
|
||
assert r.get('success'), json.dumps(r, ensure_ascii=False)[:500]
|
||
return r['result']
|
||
|
||
|
||
def closure(st, victims):
|
||
parts = {d: (pid, pins) for pid, d, pins in st['parts']}
|
||
missing = [d for d in victims if d not in parts]
|
||
if missing:
|
||
raise SystemExit(u'页 %s 上找不到元件: %s' % (st['cur'], missing))
|
||
seed = [(x, y) for d in victims for _n, x, y in parts[d][1]]
|
||
wires = {pid: segs_of(line) for pid, line in st['wires']}
|
||
keep = set()
|
||
frontier = list(seed)
|
||
while frontier:
|
||
pts, frontier = frontier, []
|
||
for pid, segs in wires.items():
|
||
if pid in keep:
|
||
continue
|
||
if any(on_seg(p, a, b) for p in pts for a, b in segs):
|
||
keep.add(pid)
|
||
frontier += [q for a, b in segs for q in (a, b)]
|
||
segs_all = [s for pid in keep for s in wires[pid]]
|
||
# 闭包导线上不许站着别的元件的引脚
|
||
foreign = []
|
||
for d, (pid, pins) in parts.items():
|
||
if d in victims:
|
||
continue
|
||
for n, x, y in pins:
|
||
if any(on_seg((x, y), a, b) for a, b in segs_all):
|
||
foreign.append(u'%s.%s@(%d,%d)' % (d, n, x, y))
|
||
# 落在闭包导线上的旗 / 端口
|
||
fl = [f for f in st['flags'] if any(on_seg((f[3], f[4]), a, b) for a, b in segs_all)]
|
||
return {'wires': sorted(keep), 'flags': fl, 'foreign': foreign,
|
||
'parts': [parts[d][0] for d in victims], 'nseg': len(segs_all)}
|
||
|
||
|
||
def main():
|
||
args = [a for a in sys.argv[1:] if not a.startswith('--')]
|
||
page, victims = args[0], args[1:]
|
||
push = '--push' in sys.argv
|
||
st = read(page)
|
||
c = closure(st, victims)
|
||
print(u'页 %s:删元件 %d / 导线图元 %d(%d 段)/ 旗端口 %d'
|
||
% (st['cur'], len(c['parts']), len(c['wires']), c['nseg'], len(c['flags'])))
|
||
for f in c['flags']:
|
||
print(u' %-8s %-12s (%d,%d)' % (f[1], f[2], f[3], f[4]))
|
||
if c['foreign']:
|
||
raise SystemExit(u'⛔ 闭包碰到了别的元件的引脚,不能整块删:%s' % c['foreign'])
|
||
if not push:
|
||
print(u'(未加 --push,没有改动)')
|
||
return
|
||
ids = c['parts'] + [f[0] for f in c['flags']]
|
||
r = run(JS_DEL % (page, json.dumps(ids), json.dumps(c['wires'])), timeout=300)
|
||
assert r.get('success'), json.dumps(r, ensure_ascii=False)[:500]
|
||
print(u' 已删:元件+旗端口 %d,导线 %d,已存盘' % (r['result']['c'], r['result']['w']))
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|