Files
skills-win/kicad-flow/scripts/schgen/root.py
T
2026-10-15 01:59:40 +08:00

118 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""根图(第 1 页):左栏层次页符号 + 右侧内嵌 drawio 框图 PNG。
跨页连接一律用全局标签,层次页不需要 sheet pin。子页的 sheet_uuid 由 uid("sh", 文件名)
推出,与 page.Page 的约定一致,所以根图和子图可以各自单独重生成。
from schgen.root import write_root
write_root(prj, [("02_Power.kicad_sch", "02 电源"), ...], png=r"...\\diagram.png",
title="MyBoard", note="一段说明文字")
插图:KiCad 对没有 pHYs 的 PNG 按 300DPI 解释,scale=1 时宽 = 像素/300*25.4mm(G-0022),
据此反算 scale;(image (at 中心)) 给的是中心不是左上角;base64 每行 76 字符。
"""
import base64
import io
import os
import struct
from .kicad_lib import uid, esc
from .layout import PAPER
KICAD_BITMAP_DPI = 300.0
def image_block(png, x0, y0, max_w, max_h, key="img"):
raw = io.open(png, "rb").read()
px, py = struct.unpack(">II", raw[16:24])
nat_w, nat_h = px / KICAD_BITMAP_DPI * 25.4, py / KICAD_BITMAP_DPI * 25.4
scale = min(max_w / nat_w, max_h / nat_h)
w, h = nat_w * scale, nat_h * scale
cx, cy = x0 + w / 2.0, y0 + h / 2.0
b64 = base64.b64encode(raw).decode("ascii")
body = "\n\t\t\t".join('"%s"' % b64[i:i + 76] for i in range(0, len(b64), 76))
blk = ('\t(image\n\t\t(at %.3f %.3f)\n\t\t(scale %.6f)\n\t\t(uuid "%s")\n'
'\t\t(data %s\n\t\t)\n\t)' % (cx, cy, scale, uid("root", key, os.path.basename(png)), body)) # 只用文件名:工程搬目录后重生成结果不变
return blk, (x0, y0, w, h)
def write_root(prj, sheets, png=None, title=None, note="", paper="A2",
col_w=110.0, sheet_h=18.0, gap=10.0, img_note=None):
"""sheets: [(文件名, 显示名), ...],按顺序排在左栏(页码 2、3…)。"""
PW, PH = PAPER[paper]
title = title or prj.name
root_u = uid("root", prj.name)
out = ['(kicad_sch (version 20231120) (generator "kicad_flow_schgen") (generator_version "8.0")',
' (uuid "%s")' % root_u,
' (paper "%s")' % paper,
' (title_block (title "%s") (rev "%s") (company "%s"))'
% (esc(title), prj.rev, esc(prj.company)),
' (lib_symbols)']
x = 26.0
y = 24.0
if note:
out.append(' (text "%s" (at %.1f %.1f 0) (effects (font (size 1.8 1.8)) (justify left top))'
' (uuid "%s"))' % (esc(note), x, y, uid("root", "note")))
y += 6.0 + 2.6 * (note.count("\n") + 1)
for i, (fn, name) in enumerate(sheets):
sy = y + 6.0 + i * (sheet_h + gap)
out.append(
' (sheet (at %.1f %.1f) (size %.1f %.1f) (fields_autoplaced yes)\n'
' (stroke (width 0.1524) (type solid)) (fill (color 0 0 0 0.0))\n'
' (uuid "%s")\n'
' (property "Sheetname" "%s" (at %.1f %.2f 0)\n'
' (effects (font (size 1.8 1.8)) (justify left bottom)))\n'
' (property "Sheetfile" "%s" (at %.1f %.2f 0)\n'
' (effects (font (size 1.4 1.4)) (justify left top)))\n'
' (instances (project "%s" (path "/%s" (page "%d"))))\n'
' )' % (x, sy, col_w, sheet_h, uid("sh", fn), esc(name), x, sy - 1.0,
fn, x, sy + sheet_h + 1.0, prj.name, root_u, i + 2))
info = None
if png:
ix0 = x + col_w + 14.0
iy0 = 24.0
blk, info = image_block(png, ix0, iy0, PW - 14.0 - ix0, PH - 40.0 - iy0 - 8.0)
out.append(blk)
if img_note:
out.append(' (text "%s" (at %.1f %.1f 0) (effects (font (size 1.6 1.6)) (justify left top))'
' (uuid "%s"))' % (esc(img_note), ix0, iy0 + info[3] + 3.0,
uid("root", "imgnote")))
out.append(' (sheet_instances (path "/" (page "1")))')
out.append(')')
p = os.path.join(prj.out_dir, prj.name + ".kicad_sch")
io.open(p, "w", encoding="utf-8").write("\n".join(out) + "\n")
print("根图 %s (%.0f KB)%s" % (p, os.path.getsize(p) / 1024.0,
" 框图 %.0fx%.0f mm" % (info[2], info[3]) if info else ""))
return p
def write_project(prj):
"""最小 .kicad_pro(没有它 KiCad 打不开工程);已存在就不动。"""
p = os.path.join(prj.out_dir, prj.name + ".kicad_pro")
if not os.path.exists(p):
io.open(p, "w", encoding="utf-8").write(
'{\n "meta": {"filename": "%s.kicad_pro", "version": 1},\n'
' "schematic": {"legacy_lib_dir": "", "legacy_lib_list": []},\n'
' "sheets": [],\n "boards": [],\n "libraries": {"pinned_footprint_libs": [],'
' "pinned_symbol_libs": []}\n}\n' % prj.name)
return p
def write_lib_tables(prj, sym_libs=(), fp_libs=()):
"""工程级 sym-lib-table / fp-lib-table,用 ${KIPRJMOD} 相对路径。
改完必须**整个退出 KiCad 再重启**才生效(G-0020)。"""
def table(kind, libs):
rows = ['(%s_lib_table' % kind, ' (version 7)']
for name, rel in libs:
# 绝对路径原样写;ipots 工程里 ${KIPRJMOD} 版 fp-lib-table 曾没被认到(多半是没重启)
uri = rel if os.path.isabs(rel) else "${KIPRJMOD}/" + rel
rows.append(' (lib (name "%s") (type "KiCad") (uri "%s") (options "")'
' (descr ""))' % (name, uri.replace("\\", "/")))
rows.append(')')
return "\n".join(rows) + "\n"
if sym_libs:
io.open(os.path.join(prj.out_dir, "sym-lib-table"), "w", encoding="utf-8").write(
table("sym", sym_libs))
if fp_libs:
io.open(os.path.join(prj.out_dir, "fp-lib-table"), "w", encoding="utf-8").write(
table("fp", fp_libs))