R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,87 @@
|
||||
#!/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
|
||||
在新工单中引用
屏蔽一个用户