# -*- coding: utf-8 -*- """把 p2gen.py 生成的 CHn 内容推到指定图页。 用法: python .claude/p2push.py [--rename] [--push] --rename 按坐标把元件位号改成 CHn 的(复制出来的页会被 EasyEDA 自动改号,必须做) --push 清空并重画导线 / 旗 / 端口 / 文字 位号改名分两趟(先改成临时名再改成目标名),因为目标名可能正被同工程别的页占着, 一趟改会撞号被 EasyEDA 悄悄改成别的。 """ import json, os, sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from eda import run import p2gen n = int(sys.argv[1]) page = sys.argv[2] do_temp = '--temp' in sys.argv or '--rename' in sys.argv do_final = '--final' in sys.argv or '--rename' in sys.argv do_push = '--push' in sys.argv ch = p2gen.channel(n) POS2DES = {} for des, _mfr, _sub, x, y, _r, _m in p2gen.SNAP['parts']: key = '%d,%d' % (round(x), round(y)) # 回读的坐标有 179.99999999999997 这种浮点误差 assert key not in POS2DES, '坐标撞车: %s' % key POS2DES[key] = ch['des'][des] 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)[:500]) sys.exit(1) return r['result'] cur = call("return (await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;") print('当前页:', cur) if do_temp or do_final: res = call(""" const want = %s, doTemp = %s, doFinal = %s, chn = %d; const parts = (await eda.sch_PrimitiveComponent.getAll()).filter(c=>c.getState_ComponentType()==='part'); const miss = []; let i = 0, done = []; if (doTemp) { // 第一趟:改成本页唯一的临时名,把目标名腾出来 for (const c of parts) { const k = Math.round(c.getState_X()) + ',' + Math.round(c.getState_Y()); if (!want[k]) { miss.push(k); continue; } await c.toAsync().setState_Designator('Z' + chn + 'T' + (i++)).done(); } } if (doFinal) { // 第二趟:改成目标名 for (const c of (await eda.sch_PrimitiveComponent.getAll()).filter(c=>c.getState_ComponentType()==='part')) { const k = Math.round(c.getState_X()) + ',' + Math.round(c.getState_Y()); if (!want[k]) continue; await c.toAsync().setState_Designator(want[k]).done(); done.push(want[k]); } } const now = (await eda.sch_PrimitiveComponent.getAll()) .filter(c=>c.getState_ComponentType()==='part').map(c=>c.getState_Designator()).sort(); return {renamed: done.length, missed: miss, bad: doFinal ? now.filter(d=>/^Z[0-9]+T/.test(d)) : [], now}; """ % (json.dumps(POS2DES), 'true' if do_temp else 'false', 'true' if do_final else 'false', n)) print('改名 %d 个,未匹配 %d 个,残留临时名 %d 个' % (res['renamed'], len(res['missed']), len(res['bad']))) if res['missed'] or res['bad']: print(' 未匹配坐标:', res['missed'], ' 残留:', res['bad']) sys.exit(1) wrong = sorted(set(res['now']) ^ set(POS2DES.values())) if do_final else [] if wrong: print(' ⚠️ 位号与预期不一致:', wrong) sys.exit(1) print(' 位号:', ' '.join(sorted(set(res['now']))[:8]), '...') if not do_push: sys.exit(0) 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 1; """) def chunk(items, k): for i in range(0, len(items), k): yield items[i:i + k] total = 0 for part in chunk([[a[0], a[1], b[0], b[1]] for a, b in ch['wires']], 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([['Ground' if net == 'GND' else 'Power', net, x, y, r] for net, x, y, r in ch['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, net, x, y, r] for net, x, y, r, d in ch['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 ch['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)