sync: HP_BOWEI 2026-10-15

This commit is contained in:
Myfro9
2026-10-15 01:59:40 +08:00
parent 771acd4171
commit a0a3445bfd
21 changed files with 3042 additions and 16 deletions
+117
View File
@@ -0,0 +1,117 @@
"""根图(第 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))