文件
phonerail/.claude/k_esym.py
T

88 行
3.8 KiB
Python

#!/usr/bin/env python3
"""EasyEDA .esym 符号源码解析。
格式:每行一个 JSON 数组。实测出来的字段布局(2026-09-07,PhoneRail 工程 131 个符号):
["PART", name, {"BBOX":[x1,y1,x2,y2]}]
["PIN", id, ?, ?, x, y, length, rotation, color, ?, ?]
x,y 是**连接点**(外端),rotation 是「从连接点指向本体」的方向:0=向右(引脚在左边)
["ATTR", id, parentId, key, value, ?, visible, x, y, rot, fontStyle, ?]
挂在 PIN 上的 key 有 NAME / NUMBER / Pin Type
["RECT", id, x1, y1, x2, y2, rx, ry, rot, style, ?]
["POLY", id, [x1,y1,x2,y2,...], closed, style, ?]
["CIRCLE", id, cx, cy, r, style, ?]
["ELLIPSE", id, cx, cy, rx, ry, rot, style, ?]
["ARC", id, sx, sy, mx, my, ex, ey, style, ?] ← 实测 (mx,my) 是弧中点,和 KiCad 三点式同构
["TEXT", id, x, y, rot, text, style]
坐标单位 0.01 inch,**Y 轴向上**(和 KiCad .kicad_sym 同向,符号图形不需要翻 Y)。
"""
import json
MM = 0.254 # 1 EasyEDA 单位 = 0.01 inch = 0.254 mm
PIN_TYPE = { # EasyEDA "Pin Type" -> KiCad 电气类型
"Undefined": "unspecified",
"IN": "input",
"OUT": "output",
"BI": "bidirectional",
"POWER": "power_in",
}
def parse(path):
"""-> {'name':str, 'bbox':[x1,y1,x2,y2], 'pins':[...], 'shapes':[...], 'texts':[...]}"""
rows = []
for line in open(path, encoding="utf-8"):
line = line.strip()
if line:
rows.append(json.loads(line))
sym = {"name": None, "bbox": None, "pins": [], "shapes": [], "texts": [], "skipped": []}
pins = {} # pin id -> dict
for r in rows:
t = r[0]
if t == "PART":
sym["name"] = r[1]
if len(r) > 2 and isinstance(r[2], dict):
sym["bbox"] = r[2].get("BBOX")
elif t == "PIN":
p = {"id": r[1], "x": r[4], "y": r[5], "len": r[6], "rot": r[7],
"number": None, "name": None, "type": "Undefined",
"nameVisible": True, "numberVisible": True}
pins[r[1]] = p
sym["pins"].append(p)
elif t == "ATTR":
p = pins.get(r[2])
if not p:
continue
key, val, vis = r[3], r[4], (r[6] if len(r) > 6 else 1)
if key == "NAME":
p["name"] = val; p["nameVisible"] = bool(vis)
elif key == "NUMBER":
p["number"] = val; p["numberVisible"] = bool(vis)
elif key == "Pin Type":
p["type"] = val or "Undefined"
elif t == "RECT":
sym["shapes"].append({"k": "rect", "x1": r[2], "y1": r[3], "x2": r[4], "y2": r[5]})
elif t == "POLY":
pts = r[2]
sym["shapes"].append({"k": "poly", "pts": [(pts[i], pts[i + 1]) for i in range(0, len(pts) - 1, 2)],
"closed": bool(r[3]) if len(r) > 3 else False})
elif t == "CIRCLE":
sym["shapes"].append({"k": "circle", "cx": r[2], "cy": r[3], "r": r[4]})
elif t == "ELLIPSE":
# KiCad 没有椭圆图元;长短轴相等就是圆,否则退化成外接圆(本工程里全是小圆点)
sym["shapes"].append({"k": "circle", "cx": r[2], "cy": r[3], "r": max(r[4], r[5])})
elif t == "ARC":
sym["shapes"].append({"k": "arc", "sx": r[2], "sy": r[3],
"mx": r[4], "my": r[5], "ex": r[6], "ey": r[7]})
elif t == "TEXT":
sym["texts"].append({"x": r[2], "y": r[3], "rot": r[4], "s": r[5]})
elif t in ("DOCTYPE", "HEAD", "LINESTYLE", "FONTSTYLE"):
pass
else:
# TABLE / TABEL_CELL / OBJ / GROUP 只出现在图框符号里,不是元件
sym["skipped"].append(t)
return sym