#!/usr/bin/env python3 """从页面源码 DSL 里取出每个元件的**位号 / 值标签的实际坐标**。 为什么需要:API 的 sch_PrimitiveAttribute.getAll() 返回空(属性挂在元件上,不是独立图元), 几何提取里拿不到标签位置。按固定偏移摆会在密集区叠成一团 —— 2026-09-07 第一版就是这样, P1B-5V 上 C731/C733 的位号糊在一起。 DSL 记录形如 {"type":"ATTR","ticket":N,"id":"..."}||{...,"parentId":"<元件 PrimitiveId>", "key":"Designator","x":575,"y":-620,...}| 注意 **DSL 的 Y = −API 的 Y**(实测:元件 API (600,600) 在 DSL 里是 (600,-600))。 parentId 与 API 的 PrimitiveId 同值,可以直接对上。 """ import json, os ROOT = os.path.dirname(os.path.abspath(__file__)) SRC = os.path.join(ROOT, "eda_src") def page_labels(board, page): """-> {componentPrimitiveId: {'Designator': (x, y, visible), 'Name': (x, y, visible)}} 坐标已转成 API 口径(Y 向上)。""" path = os.path.join(SRC, board, page + ".esrc") out = {} for line in open(path, encoding="utf-8"): line = line.strip() if not line.startswith('{"type":"ATTR"'): continue _, _, rest = line.partition("||") try: b = json.loads(rest.rstrip("|")) except Exception: continue k = b.get("key") if k not in ("Designator", "Name") or b.get("x") is None: continue pid = b.get("parentId") if not pid: continue out.setdefault(pid, {})[k] = (b["x"], -b["y"], bool(b.get("valueVisible"))) return out if __name__ == "__main__": tree = json.load(open(os.path.join(SRC, "_tree.json"), encoding="utf-8")) tot = 0 for b in tree["boards"]: for p in b["pages"]: d = page_labels(b["board"], p["name"]) n = sum(1 for v in d.values() if "Designator" in v) tot += n print(f" {b['board']}/{p['name']:12s} 带位号标签的元件 {n}") print(f"合计 {tot}(应为 508)")