Files
Robot_Arm/arm/viewer/build_viewer.py
T

99 lines
4.0 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
"""把生成物落到 webapp/,并打一份单文件分发版。
单文件时代这里做 8 路字符串替换再写 3 份 16MB 副本;现在前端本身就是 webapp/ 下的
文件,本脚本只剩两件事:
write_data() 网格/工程图/行程/碰撞/螺钉 -> generated/00_data.js(普通脚本 const)
build_single() 把 webapp/ 的 css/js 原样内联成 dist/机器人手臂3D查看器.html(分发用)
S5 数据改 fetch() 后 write_data() 的 00_data.js 退役;S8 由 pack.py 的受限 ESM 内联器
接管 build_single()。
"""
import io
import json
import os
import re
import sys
import time
try:
sys.stdout.reconfigure(encoding="utf-8")
except Exception:
pass
from arm.paths import DATA, DIST, DOCS, GEN, WEBAPP
# 与 SHEET_METAS 的顺序一致;工程图读 draw_sheet 写出的真 SVG,
# 不再维护第二份 sheets.jsdata(单文件时代的内联载体,内容与 SVG 完全重复)。
SHEET_ORDER = ["sheet_front", "sheet_joint", "sheet_exploded", "sheet_side"]
def _read(path, dflt=None):
if os.path.exists(path):
return io.open(path, encoding="utf-8").read()
if dflt is None:
raise SystemExit("缺少查看器数据文件: %s(先跑 python -m arm.build_model)" % path)
return dflt
def write_data():
t0 = time.time()
print("【数据】汇总查看器数据 -> webapp/generated/00_data.js", flush=True)
os.makedirs(GEN, exist_ok=True)
mesh = _read(DATA + "/mesh_arm.json")
svgs = [_read(DOCS + "/%s.svg" % n) for n in SHEET_ORDER]
trv = _read(DOCS + "/travel.json", "[]")
col = _read(DOCS + "/collide.json", '{"caps":[],"parts":{}}')
scr = _read(DOCS + "/screws.json", "[]")
print(" - 网格 %d KB / 工程图 %d 张 / travel %d B / collide %d KB / screws %d B"
% (len(mesh) // 1024, len(svgs), len(trv), len(col) // 1024, len(scr)), flush=True)
out = ["/* 生成物,勿手改:由 python -m arm.viewer.build_viewer 写入。",
" 普通脚本顶层 const —— 经典脚本共享全局词法作用域,后续脚本直接可见。 */"]
for name, raw in (("DATA", mesh), ("TRAVEL", trv), ("COLLIDE", col), ("SCREWS", scr)):
out.append("const %s = %s;" % (name, raw.strip()))
out.append("const SHEETS = %s;" % json.dumps(svgs, ensure_ascii=False))
text = "\n".join(out) + "\n"
tmp = GEN + "/00_data.js.tmp"
io.open(tmp, "w", encoding="utf-8").write(text)
os.replace(tmp, GEN + "/00_data.js")
print(" 完成:%d KB, %.2fs ✓" % (len(text) // 1024, time.time() - t0), flush=True)
def build_single():
"""分发用单文件:仍是普通脚本,所以内联是平凡的(S5 变 ESM 后交给 pack.py)。"""
t0 = time.time()
os.makedirs(DIST, exist_ok=True)
html = _read(WEBAPP + "/index.html")
total = len(html)
def sub(m, kind):
nonlocal total
body = _read(WEBAPP + "/" + m.group(1))
total += len(body)
return ("<style>\n" + body + "\n</style>") if kind == "css" \
else ("<script>\n" + body + "\n</script>")
out = re.sub(r'<link rel="stylesheet" href="([^"]+)">', lambda m: sub(m, "css"), html)
out = re.sub(r'<script src="([^"]+)"></script>', lambda m: sub(m, "js"), out)
left = re.findall(r'(?:src|href)="(?!data:)([^"]+)"', out)
assert not left, "单文件里仍有外部引用: %s" % left[:5]
assert len(out) >= total * 0.95, "内联后 %d 远小于各部之和 %d,疑似漏文件" % (len(out), total)
dst = DIST + "/机器人手臂3D查看器.html"
# Windows 上被浏览器打开的 html 是独占锁;写不进去就直接报,不要静默留旧版。
io.open(dst, "w", encoding="utf-8").write(out)
print(" - 单文件分发版 %.2f MB, %.2fs ✓ %s"
% (os.path.getsize(dst) / 1e6, time.time() - t0, dst), flush=True)
def rebuild_viewer():
"""build_model 流水线的最后一步(沿用旧函数名,调用点不改)。"""
write_data()
build_single()
if __name__ == "__main__":
rebuild_viewer()