fiziko.mkiv 详解:如何在 ConTeXt 与 LuaMPL 环境中集成使用 fiziko 库的完整指南
fiziko.mkiv 详解:如何在 ConTeXt 与 LuaMPL 环境中集成使用 fiziko 库的完整指南
fiziko 是一个专为物理教科书黑白插图自动化的 MetaPost 绘图库,而 fiziko.mkiv 正是它在 ConTeXt 生态中的文档与集成示例。本文将带你快速看懂 fiziko.mkiv 文件结构,并分别在 ConTeXt 和 LuaMPL(luamplib)两套环境中完成 fiziko 库的集成配置,让你几分钟内画出滑轮、弹簧、透镜等专业物理插图。
📦 项目概览:fiziko 是什么
fiziko 最初由 Sergey Slyusarev 为编写物理教材而开发,提供三类核心能力:
- 变宽线条绘制:
brush、offsetPath等宏,支持按函数控制线条粗细; - 带阴影的原语:
sphere.c(同心线球体)、tube.l/tube.t(纵向/横向线管)等,模拟经典黑白印刷质感; - 物理对象宏:
pulley(滑轮)、spring(弹簧)、lens(透镜)、weight.s(砝码)、globe(地球仪)等现成组件。
仓库结构非常精简,核心文件如下:
| 文件 | 作用 |
|---|---|
| fiziko.mp | 核心库源码,全部 2600+ 行 MetaPost 宏定义(v0.2.1,GPLv3) |
| fiziko.mkiv | ConTeXt 版 API 文档,演示库在 ConTeXt 中的集成方式 |
| fiziko.tex | LaTeX 版 API 文档,基于 luamplib(LuaMPL)演示集成方式 |
| README.md | 项目简介与使用效果展示 |
| LICENSE.md | GNU GPL v3 许可证 |
🔍 逐步拆解:fiziko.mkiv 文件结构
fiziko.mkiv 是一份 ConTeXt 文档,它本身就是一个"如何在 ConTeXt 里嵌入 MetaPost 绘图"的完整范例。按顺序看四个关键部分:
1. 全局引入库文件
fiziko.mkiv 开篇三行:
\startMPinclusions
input fiziko.mp;
\stopMPinclusions
\startMPinclusions 是 ConTeXt metapost 模块提供的全局作用域:在其中 input fiziko.mp; 一次,后续文档中所有 \startMP 环境都能直接使用库里定义的全部宏,无需重复引入。这是 ConTeXt 集成第三方 MetaPost 库的标准姿势。
2. 排版行为配置
fiziko.mkiv 通过 \setuptyping 设置了 option=mp(代码块按 MetaPost 语法高亮)、numbering=file(按文件而非按代码块连续编号)、keeptogether=yes(代码与配图不跨页分离),这些设置让代码示例和生成图片始终紧挨着,阅读体验更好。
3. 文档框架
fiziko.mkiv 的 \startdocument 声明了作者、标题、摘要与许可证(CC-BY-SA 4.0),正文从 \section{Introduction} 开始,逐宏讲解 API。
4. 宏定义 + 配图的标准写法
每个宏的演示都遵循"代码 + 实时渲染"的固定模式,例如 fiziko.mkiv:
\startMP[numbering=no]
defineMinStrokeWidth(1/2pt);
\stopMP
\startMP … \stopMP 环境把内部代码交给 MetaPost 引擎执行并直接输出图片,numbering=no 表示该块不参与行号。更复杂的示例(如 fiziko.mkiv 的 offsetPath 演示)则先用 \startbuffer 缓存代码,再用 \typebuffer 打印代码、\processMPbuffer 执行渲染,实现代码与图片的分离排版。
⚙️ 在 ConTeXt 环境中集成 fiziko 的 3 步配置
如果你要在自己的 ConTeXt 项目中使用 fiziko,只需照抄上述模式:
第 1 步:获取库文件
把 fiziko.mp 放入文档主文件所在目录,或者放入 MetaPost 可搜索的路径。
第 2 步:在文档开头声明全局引入
\startMPinclusions
input fiziko.mp;
\stopMPinclusions
第 3 步:用 \startMP 环境画图
\startMP
draw pulley(1cm, 0);
draw spring((0,1cm), (0,-2cm), 12);
\stopMP
编译命令为 context main.mkiv,即可得到嵌入文档的黑白插图。全局变量(如 fiziko.mp 的 defineMinStrokeWidth(1/5pt) 控制最小描边宽度、fiziko.mp 的 defineLightDirection 控制光源方向)也可以在 \startMPinclusions 中统一设置,作用于全文档所有图。
🧩 在 LuaMPL(luamplib)环境中加载 fiziko
不使用 ConTeXt 而选择 LaTeX 时, Luiz 推荐的组合是 luamplib 宏包(底层即 LuaMPL)。fiziko.tex 正是这套方案的官方示范,核心是 fiziko.tex 的三行配置:
\usepackage{luamplib}
\everymplib{verbatimtex \leavevmode etex; input fiziko.mp; beginfig(1);}
\everyendmplib{endfig;}
原理说明:
\everymplib:每个mplibcode环境开始时自动执行——插入换行、input fiziko.mp;加载库,并打开beginfig(1);\everyendmplib:每个环境结束时自动endfig;收尾。
这样写好的每个代码块都能免重复地使用全部 fiziko 宏:
\begin{mplibcode}
draw woodBlock(10cm, 1/2cm);
draw weight.s(1cm) shifted (5cm, 0.5cm);
\end{mplibcode}
若不想用自动钩子,也可以像常规 luamplib 用法那样,在每个 mplibcode 块首行手动写 input fiziko.mp; beginfig(1);,只是略显繁琐。使用 xelatex 或 lualatex 编译即可。
🧰 核心宏速览:画出你的第一张物理插图
集成完成后,最常用的宏可以按"原语 → 组件"两级来记:
底层原语
| 宏 | 用途 |
|---|---|
brush(p)(f) |
沿路径 p 按函数 f 绘制变宽线条 |
sphere.c(d) / sphere.s(d) |
同心线 / 点状阴影球体 |
tube.l(p)(f) / tube.t(p)(f) |
纵向 / 横向线阴影管 |
solidSurface(p) |
路径右侧的实体表面(地面、斜面) |
物理组件
| 宏 | 用途 |
|---|---|
pulley(d, a) |
带支架滑轮,pulleyOutline 可取轮廓 |
spring(a, b, n) |
两点间弹簧,springwidth 控制粗细 |
weight.h(h) / weight.s(h) |
悬挂 / 放置式砝码 |
lens((r1, r2), t, d, u) |
透镜截面(凸正凹负) |
refractionPath(ray, shape, n) |
光线在物体中的折射/全反射轨迹 |
globe(r, lon, lat) |
地球仪 |
addStrandToKnot + knotFromStrands |
多绳结绘制 |
一个组合示例(来自 fiziko.tex 的胡克定律插图):solidSurface 画天花板、spring 画弹簧、weight.h 挂砝码、drawdblarrow 标注伸长量 x,不到 20 行代码就是一张规范的实验示意图。
⚠️ 集成时的 3 个常见注意点
- 编译引擎必须支持 MetaPost:LaTeX 侧请用
xelatex或lualatex编译(luamplib 依赖 Lua 运行时);ConTeXt 原生支持 MetaPost,无此限制。 - 算法适用边界:官方文档明确提示,底层算法"只在某些简单场景下产生理想结果"(见 fiziko.mkiv),复杂 3D 造型目前仅支持平面(
flatSurface)。 - 全局变量相互耦合:
minStrokeWidth牵动笔宽、点划线、点阴影尺寸等多个派生量(见 fiziko.mp),修改时请用defineMinStrokeWidth宏而非直接赋值,保持派生量同步。
📌 总结
fiziko 把物理教科书插图里最繁琐的黑白阴影线条封装成了一批即取即用的 MetaPost 宏。fiziko.mkiv 展示了 ConTeXt 侧的完整集成链路:\startMPinclusions 一次引入 fiziko.mp,\startMP 环境即时渲染配图;而 LaTeX 用户只需三行 luamplib(LuaMPL)配置就能获得同样的能力。无论是 pulley 滑轮、spring 弹簧还是 refractionPath 光路,从集成到出图通常只需几分钟——这正是它"自动化教材插图"的初衷。