news 2026/9/27 9:28:58

Penrose 实战:用 Domain / Substance / Style 三文件实现 Mobius 圆反演(Inversion)可视化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Penrose 实战:用 Domain / Substance / Style 三文件实现 Mobius 圆反演(Inversion)可视化
  • 开发工具
  • 数据可视化

【免费下载链接】penrose

Create beautiful diagrams just by typing notation in plain text.

项目地址:https://gitcode.com/gh_mirrors/pe/penrose
点击查看免费下载

本文围绕 packages/examples/src/mobius 示例展开,讲解 Penrose 如何通过.domain、.substance、.style三个声明式文件完整刻画"圆与点的反演变换"(circle inversion,Möbius 变换的一种)并渲染出带渐变光影质感的矢量图。读完本文,你将掌握 Penrose 三段式建模中构造函数(constructor)、条件式样式匹配(forall ... where)与数值约束(ensure)的配合方法,并能独立读懂并复刻一个含自定义数学推导的完整示例。

示例定位与文件结构

该目录的 README.md 只有一句话点明主题:这是一个用于**演示反演变换(inversion transformation)**的 Domain,当前仅支持圆(circles)和点(points),直线、圆弧等其他形状可能在后续加入。围绕这一简短描述,目录内还配套了四个关键文件,共同构成一个可直接运行的 Penrose 示例:

文件作用
mobius.domain类型系统:定义Center、Shape、Point、Circle及反演构造函数Inversion
mobius.substance程序声明:实例化一个反演中心、三个圆及其反演结果,并附加 LaTeX 标签
mobius.style样式与数学:把反演公式写成可优化的数值计算,同时定义画布、图像纹理、约束与图层
mobius.trio.json运行清单:关联三份文件并固定随机种子variation

在示例注册表 registry.json 中,该示例登记名为"Mobius Transformation of Circles",且"gallery": true,意味着它会被收录进在线画廊,属于官方推荐展示的示例之一。

Domain 层:用类型与构造函数声明"反演"这一数学对象

mobius.domain 全文仅 10 行,却完整定义了本示例的全部抽象:

type Center type Shape type Point type Circle Point <: Shape Circle <: Shape constructor Inversion( Shape original, Center center ) -> Shape

关键点逐条拆解:

  • 类型层级:Point与Circle都继承自Shape,因此凡是对Shape编写的样式规则,会自动作用于点和圆,这是 Penrose 面向对象式类型继承的典型用法。
  • Center独立成类:反演中心(即变换圆心与半径所在)被单独建模,不并入Shape,便于在样式层为其单独绘制虚线参考圆与中心点。
  • 构造函数Inversion( Shape original, Center center ) -> Shape:这是整个示例的核心抽象。它声明"对一个 Shape 施加以 Center 为参考的反演,结果仍是一个 Shape"。注意其结果类型是抽象父类Shape,意味着既可以反演Point,也可以反演Circle——Substance 中恰好同时使用了这两种用法,而 Style 层则通过匹配s := Inversion(p, r)与s := Inversion(c, r)两条规则分别给出不同的几何算法。

这种"用构造函数承载数学运算"的建模方式,是 Penrose 把数学概念翻译成可视化程序的典型路径:Domain 只描述"有什么对象和关系",具体怎么算、怎么画,全部留给 Style 层。

Substance 层:声明对象并调用构造函数

mobius.substance 声明了一个反演中心与三个待反演的圆:

Center r Circle c1, c2, c3 Shape ic1 := Inversion(c1, r) Shape ic2 := Inversion(c2, r) Shape ic3 := Inversion(c3, r)
  • 语法Shape ic1 := Inversion(c1, r)表示用构造函数创建对象并命名,ic1、ic2、ic3即三个圆的反演像。
  • 三组Label语句为对象绑定数学排版标签,标签内容使用 LaTeX 书写(Penrose 会将它们渲染为排版公式):
Label r $S^1$ Label c1 $c_1$ Label c2 $c_2$ Label c3 $c_3$ Label ic1 $c'_1$ Label ic2 $c'_2$ Label ic3 $c'_3$

这里$S^1$表明反演参考圆是单位圆,c'_i与c_i的撇号记法清晰区分了原圆与其反演像,正好呼应"反演圆"的主题语义。

Style 层:把反演公式写成可优化计算

mobius.style 是本示例最富技术含量的部分,它包含画布设置、图像纹理、几何算法、布局约束与图层管理五类内容。

画布与背景纹理

canvas { width = 800 height = 700 } global { shape background = Image { href: "background.svg" center: (0,0) width: canvas.width height: canvas.height opacity: .6 preserveAspectRatio: "none" } }

画布固定为 800×700,背景直接引用同目录下的 background.svg(一段木纹色渐变矩形)作为整幅图的底层纹理,opacity: .6降低饱和度以避免干扰前景图形。

通用规则:给所有带标签的形状绘制公式

forall Shape s where s has label { shape s.eq = Equation { center: s.center string: s.label fontSize: "25px" } }

forall ... where ...是 Penrose 的条件匹配语法:任何"拥有标签的 Shape"都会生成一个Equation形状,把 LaTeX 标签渲染在自身中心。由于Point <: Shape、Circle <: Shape,这条规则自动覆盖圆及其反演像,一处声明、处处生效。

反演中心Center的绘制

forall Center c { vec2 c.center = (?, ?) scalar c.r = ? shape c.circle = Circle { center: c.center r: c.r fillColor: rgba(0, 0, 0, 0) strokeWidth: 2 strokeStyle: "dashed" strokeColor: rgba(0, 0, 0, 1) } shape c.point = Circle { center: c.center fillColor: rgba(0, 0, 0, 1) r: 3 } ensure lessThan(100, c.r) }

(?, ?)表示该数值由 Penrose 的优化求解器(基于自动微分的能量优化)在布局阶段自动求解,这正是 Penrose 区别于普通绘图库的核心机制。参考圆以透明填充 + 黑色虚线描边呈现,圆心以半径 3 的实心小黑点标出,并施加约束ensure lessThan(100, c.r)保证参考圆半径足够大。

原圆的绘制与球面光影

forall Circle c { vec2 c.center = (?, ?) scalar c.r = ? shape c.circle = Circle { center: c.center r: c.r } ensure lessThan(30, c.r) shape c.shading = Image { href: "sphere-shading.svg" center: c.center width: 2*c.r height: 2*c.r ensureOnCanvas: false opacity: .5 } layer c.circle above c.shading }

除了常规圆,这里给每个原圆叠加了同目录 sphere-shading.svg(一幅径向黑白渐变)作为球体光影贴图,尺寸跟随圆的直径2*c.r,透明度 0.5,并通过layer c.circle above c.shading让圆轮廓位于光影之上。ensureOnCanvas: false允许贴图超出画布边界而不触发约束。

点反演公式(核心数学之一)

forall Shape s; Point p; Center r where s := Inversion( p, r ) { scalar s.d2 = vdistsq(p.pos, r.center) scalar s.coef = r.r * r.r / s.d2 vec2 s.pos = r.center + s.coef * (p.pos - r.center) shape s.point = Circle { r: 5 fillColor: p.point.fillColor center: s.pos } }

这里完整实现了反演的标准解析公式。对参考圆半径r.r、圆心r.center,点p.pos的反演像为:

s.pos = r.center + (r.r² / |p.pos − r.center|²) · (p.pos − r.center)
  • vdistsq计算两点距离平方(避免开方),s.d2即分母|P − C|²;
  • s.coef = r.r * r.r / s.d2即缩放系数r²/d²;
  • 结果点s.pos用半径 5 的小圆绘制,并继承原点的填充色。

vdistsq与vdist都是 Penrose 内置的自动微分运算原语,见 Autodiff.ts——它们不仅计算数值,还会为优化求解器提供可微的梯度信息,这是"用约束反推布局"的底层保障。

圆反演公式(核心数学之二)

圆的反演不像点那样能一步到位,mobius.style 采用了"取两端点、分别反演、再求中点和半径"的标准算法:

scalar s.d = vdist( c.center, r.center ) scalar s.coef1 = ( s.d - c.r ) / s.d vec2 s.p1 = r.center + s.coef1 * (c.center - r.center) scalar s.i1coef = r.r * r.r / vdistsq( r.center, s.p1 ) vec2 s.ip1 = r.center + s.i1coef * ( s.p1 - r.center) scalar s.coef2 = (s.d + c.r) / s.d vec2 s.p2 = r.center + s.coef2 * (c.center - r.center) scalar s.i2coef = r.r * r.r / vdistsq( r.center, s.p2 ) vec2 s.ip2 = r.center + s.i2coef * ( s.p2 - r.center ) scalar s.r = vdist(s.ip1, s.ip2) / 2 vec2 s.center = 0.5 * (s.ip1 + s.ip2)

算法逻辑分四步:

  1. 取直径两端点:沿两圆心连线方向,取原圆上距参考圆心最近的点p1与最远的点p2(系数(d−r)/d与(d+r)/d);
  2. 分别反演两端点:对p1、p2各自套用点反演公式,得到ip1、ip2;
  3. 反演圆的圆心:为两端点反演像的中点0.5 * (ip1 + ip2);
  4. 反演圆的半径:为两端点反演像距离的一半vdist(ip1, ip2) / 2。

随后把算出的圆绘制出来,同样叠加球面光影贴图、以layer控制层级,并施加ensure lessThan(30, s.r)防止反演圆过大。这套推导正是"圆在反演下的像仍是圆(圆心在参考圆上时退化为直线)"这一几何性质的数值实现。

布局约束与图层管理

示例末尾集中声明了几组约束与图层规则:

forall Circle c1; Circle c2 { ensure touching(c1.circle, c2.circle) } forall Center r; Circle c { ensure contains(r.circle, c.circle, 30) } forall Shape s1; Shape s2 { s1.eq above s2.circle s1.eq above s1.circle s2.eq above s1.circle s2.eq above s2.circle }
  • ensure touching(c1.circle, c2.circle):任意两个原圆彼此相切,让画面紧凑有序;
  • ensure contains(r.circle, c.circle, 30):参考圆以 30 像素余量包住每个原圆,保证反演几何关系在视觉上成立;
  • 四条above规则统一确保所有公式标签始终绘制在圆之上,避免文字被图形遮挡。

这些touching、contains、lessThan都是 Penrose 内置的几何约束函数,其实现位于 Constraints.ts(lessThan见 L72、touching见 L291、contains见 L315)。它们会被编译成能量项交给优化器最小化,最终同时满足全部约束的布局即为渲染结果。

运行配置:trio.json 与随机种子

mobius.trio.json 把三段式程序串成一个可运行单元:

{ "substance": "./mobius.substance", "style": ["./mobius.style"], "domain": "./mobius.domain", "variation": "HibernationPony6425" }
  • style是数组,说明一个示例可以叠加多个样式文件(本示例只用了一个);
  • variation固定随机种子"HibernationPony6425",保证每次运行得到确定性的初始布局——这对示例复现与画廊截图尤为重要。

该示例位于packages/examples/src下,因此会被示例构建流程扫描进 registry.json,并以 "Mobius Transformation of Circles" 的名称出现在在线示例集中。如需本地运行,可按仓库根目录 package.json 中约定的脚本在packages/examples下执行相应的示例编译命令,产出 SVG 渲染结果。

从源码理解:ensureOnCanvas与自动微分如何支撑本示例

本示例大量使用"数值未知、由约束求解"的写法((?, ?)与scalar c.r = ?),其底层依赖两点:

  1. ensureOnCanvas属性:样式里对两张 SVG 贴图显式设置了ensureOnCanvas: false。在编译器端,该布尔属性由 Style.ts 读取并决定是否为形状生成"必须在画布内"的约束;同时 AttrHelper.ts 将其列入"不自动映射为 SVG 属性"的白名单,避免该配置泄漏到最终 SVG 标签中。默认值则在 Circle.ts 等处定义为true——因此示例中主动关掉它,是让贴图可以自由超出画布的刻意设计。

  2. vdist/vdistsq的自动微分:点反演与圆反演公式中的所有vdist、vdistsq调用,最终都会经过 Autodiff.ts 注册的可微运算。Penrose 据此把"反演结果应满足的几何关系"翻译为连续可导的能量函数,由优化器(如 Lbfgs.ts)迭代求解出c.center、c.r等所有自由变量。这也解释了为什么 Substance 中从未指定任何坐标——位置与大小全部是"被约束出来的"。

扩展方向:从圆与点到直线与圆弧

README 末尾提到"直线、圆弧或其他形状可能后续加入"(lines/arcs or other shapes may be added later)。从现有代码结构看,接入新形状的路径相当清晰:

  • 在 mobius.domain 中新增type Line/type Arc并继承Shape;
  • 在 Substance 中创建反演实例Shape il := Inversion(line, r);
  • 在 mobius.style 中新增forall Shape s; Line l; Center r where s := Inversion(l, r)规则块,利用"过参考圆心的直线反演为自身、不过圆心的直线反演为圆"等性质补充对应算法。

这一"类型 + 构造函数 + 条件样式"的三层扩展模式,正是 Penrose 将任意数学变换可视化的通用方法论,也是该示例作为教学范例的价值所在。

  • 开发工具
  • 数据可视化

【免费下载链接】penrose

Create beautiful diagrams just by typing notation in plain text.

项目地址:https://gitcode.com/gh_mirrors/pe/penrose
点击查看免费下载

相关推荐

上一篇:samvit_large_patch16.sa1b在SA-1B数据集上的预训练秘籍:性能与局限终极指南
下一篇:cann/asc-devkit:Reg数据搬出Store接口

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 9:28:53

做pc端网站行情揭秘:改需求拖一周?这份报价避坑指南必看

做pc端网站行情揭秘:改需求拖一周?这份报价避坑指南必看 改个需求建站公司拖一周,这是多少老板心中的痛?我见过太多湖南中小企业的官网,刚上线时看着挺漂亮,结果后台改个Banner图、调个产品参数,沟通群里的消息发出去,对面已读不回,或者回复一句“排期满了,下个月再说”。这种体验,不仅耽误业务,更暴露…

作者头像 李华
网站建设 2026/9/27 9:28:51

isomorphic-git 的 deleteRemote 指南:从配置层面安全移除远端仓库

开发工具 【免费下载链接】isomorphic-git A pure JavaScript implementation of git for node and browsers! 项目地址&#xff1a; https://gitcode.com/gh_mirrors/is/isomorphic-git 点击查看 免费下载 本篇文章围绕 isomorphic-git 公开 API 中的 deleteRemote 命令展开&…

作者头像 李华
网站建设 2026/9/27 9:28:42

避坑指南:中企动力销售是做什么的及建站服务商怎么选

避坑指南:中企动力销售是做什么的及建站服务商怎么选 找建站公司怕被坑高价?别急,先搞清楚 中企动力销售是做什么的 。很多老板在预算里留了坑位,结果一接触销售,话术满天飞,最后账单比预期高出30%。今天不聊虚的,直接拆解这家头部服务商的业务逻辑,教你 怎么选…

作者头像 李华
网站建设 2026/9/27 9:28:28

英文网站外链查询实操:从零搭建监测体系只需3天

英文网站外链查询实操:从零搭建监测体系只需3天 改个需求建站公司拖一周,这种憋屈事谁没遇到过?你改个按钮颜色,对方说要排期;你加个联系表单,对方要重新评估架构。等到网站上线,发现SEO数据惨不忍睹,回头一看,外链全是垃圾站或者失效链接。别急,今天咱们不扯虚的,直接上干货。我花了三年时间,从设计师转行…

作者头像 李华
网站建设 2026/9/27 9:28:14

梧州红豆网梧州论坛SEO实战:域名服务器与性能优化全解

梧州红豆网梧州论坛SEO实战:域名服务器与性能优化全解 域名服务器配置一塌糊涂,页面加载慢如蜗牛,这才是网站做不起来的核心死因。很多老板盯着梧州红豆网梧州论坛的流量数据焦虑,却忽略了底层的 性能优化 才是根基。…

作者头像 李华