# -*- coding: utf-8 -*- """本地几何检查 + 推送到 EasyEDA。 用法: python .claude/build.py [--push] 不带 --push 只做本地检查。""" import importlib, json, os, shutil, sys, tempfile ROOT = os.path.dirname(os.path.abspath(__file__)) mod_name, pins_json, page = sys.argv[1], sys.argv[2], sys.argv[3] push = '--push' in sys.argv work = tempfile.mkdtemp(prefix='sch_') shutil.copy(os.path.abspath(pins_json), os.path.join(work, 'pins.json')) os.chdir(work) sys.path.insert(0, ROOT) sys.path.insert(0, os.path.join(ROOT, 'skills', 'easyeda-sch-geometry', 'scripts')) m = importlib.import_module(mod_name) import local_netcheck as N nc = getattr(m, 'NC', {}) _ncf = os.path.join(ROOT, mod_name.replace('_', '-') + '-nc.json') json.dump(nc, open(_ncf, 'w', encoding='utf-8'), ensure_ascii=False, indent=1) # 「网络被拆成 N 块」只有在**每一块都带同名旗/端口**时才合法(靠名字连)。 def _split_ok(name): segs = [(a, b) for a, b, net in N.SEGS if net == name] marks = [(x, y) for k, n, x, y, r in N.FLAGS if n == name] + [(x, y) for d, n, x, y, r in N.PORTS if n == name] par = list(range(len(segs))) def find(i): while par[i] != i: par[i] = par[par[i]]; i = par[i] return i for i in range(len(segs)): for j in range(i + 1, len(segs)): a1, a2 = segs[i]; b1, b2 = segs[j] if (N._on(a1, b1, b2) or N._on(a2, b1, b2) or N._on(b1, a1, a2) or N._on(b2, a1, a2)): par[find(i)] = find(j) blocks = {} for i in range(len(segs)): blocks.setdefault(find(i), []).append(segs[i]) for blk in blocks.values(): if not any(N._on(mk, s[0], s[1]) for mk in marks for s in blk): return False return True errs = [] for e in N.check(): if e.startswith('悬空引脚') and any( e.split(':')[1].strip().startswith(d + '.' + p + ' ') for d, ps in nc.items() for p in ps): continue if '被拆成' in e: name = e.split()[1] if _split_ok(name): continue errs.append(e) cross = N.crossings() print('导线段 %d 旗 %d 端口 %d 文字 %d' % (len(N.SEGS), len(N.FLAGS), len(N.PORTS), len(N.TEXTS))) print('有意不接的引脚: %d' % sum(len(v) for v in nc.values())) if errs: print('\n!! %d 个错误:' % len(errs)) for e in errs: print(' ', e) else: print('本地检查通过') print('\n交叉点 %d 处:' % len(cross)) for c in cross: print(' %s x %s @ (%d,%d)' % c) if errs or not push: sys.exit(1 if errs else 0) # ── 推送 ── from eda import run wires = [[a[0], a[1], b[0], b[1]] for a, b, _ in N.SEGS] flags = [[k, n, x, y, r] for k, n, x, y, r in N.FLAGS] ports = [[d, n, x, y, r] for d, n, x, y, r in N.PORTS] texts = [[s, x, y, sz] for s, x, y, sz in N.TEXTS] OPEN = "await eda.dmt_EditorControl.openDocument('%s');" % page def call(body, timeout=180): r = run(OPEN + body, timeout=timeout) if not r.get('success'): print('推送失败:', json.dumps(r, ensure_ascii=False)[:400]); sys.exit(1) return r['result'] # 桥接单次请求 30s 就超时,必须分批下发 print('') print('清空旧的导线/旗/端口/文字 ...') print(call(""" for (const x of await eda.sch_PrimitiveWire.getAll()) await eda.sch_PrimitiveWire.delete(x.getState_PrimitiveId()); for (const c of await eda.sch_PrimitiveComponent.getAll()) if (['netflag','netport'].includes(c.getState_ComponentType())) await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); for (const t of await eda.sch_PrimitiveText.getAll()) await eda.sch_PrimitiveText.delete(t.getState_PrimitiveId()); return (await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name; """)) def chunk(items, n): for k in range(0, len(items), n): yield items[k:k + n] total = 0 for part in chunk([[a[0], a[1], b[0], b[1]] for a, b, _ in N.SEGS], 40): total += call("for (const s of %s) await eda.sch_PrimitiveWire.create([s[0],s[1],s[2],s[3]]); return %d;" % (json.dumps(part), len(part))) print('导线 %d 段' % total) total = 0 for part in chunk([[k, n, x, y, r] for k, n, x, y, r in N.FLAGS], 25): total += call("for (const f of %s) await eda.sch_PrimitiveComponent.createNetFlag(f[0],f[1],f[2],f[3],f[4],false); return %d;" % (json.dumps(part), len(part))) print('旗 %d 个' % total) total = 0 for part in chunk([[d, n, x, y, r] for d, n, x, y, r in N.PORTS], 25): total += call("for (const p of %s) await eda.sch_PrimitiveComponent.createNetPort(p[0],p[1],p[2],p[3],p[4],false); return %d;" % (json.dumps(part), len(part))) print('端口 %d 个' % total) total = 0 for part in chunk([[s, x, y, sz] for s, x, y, sz in N.TEXTS], 20): total += call("for (const t of %s) await eda.sch_PrimitiveText.create(t[1],t[2],t[0],0,null,null,t[3]); return %d;" % (json.dumps(part), len(part))) print('文字 %d 条' % total)