新闻详情

新闻详情

首页 / 资讯中心 / 详情

用 Penrose 语言建模化学结构式:structural-formula 领域示例的开发日志复盘与源码解读

发布时间:2026/9/27 7:04:57来源:尧图网络
用 Penrose 语言建模化学结构式:structural-formula 领域示例的开发日志复盘与源码解读
开发工具数据可视化【免费下载链接】penroseCreate beautiful diagrams just by typing notation in plain text.项目地址https://gitcode.com/gh_mirrors/pe/penrose点击查看免费下载本文以 Penrose 仓库中packages/examples/src/structural-formula/目录及其开发日志DevLog为核心完整还原用领域专用语言DSL绘制化学结构式这一示例从 Domain 建模、Style 实现到 Substance 编写与性能调优的全过程并结合仓库中的实际源码、配置文件与运行脚本深入讲解 Penrose 三语言协作范式下的建模取舍、已知痛点与可行的工程化改进方向。读完本文你将掌握如何用 Penrose 的 Domain/Style/Substance 三件套搭建一个面向化学领域的图形 DSL并了解在真实开发中如何绕开匿名变量缺失、SVG 资源路径限制、布局引擎报错等关键坑。一、背景一个用纯文本描述化学结构的 Penrose 示例Penrose 的核心思想是用三种文本语言描述画什么Substance、长什么样Style、有哪些对象与关系Domain从而把画图从手工排版中解放出来。packages/examples/src/structural-formula/目录就是这个思想在化学领域的一次完整实践它希望仅凭诸如Hydrogen H1, H2 Oxygen O1 SingleBond( O1, H1 ) SingleBond( O1, H2 )这样的纯文本就能自动生成水分子water、咖啡因caffeine、葡萄糖glucose甚至甲烷燃烧反应methane-combustion的结构式图示。目录中除了一份记录开发过程的 DevLog.md还包含一套完整可运行的三语言文件与配套资源领域定义structural-formula.domain两套样式structural-formula.style平面结构式与 pseudo-3d.style伪 3D 效果分子 Substancemolecules/water、caffeine、glucose、methane、ethanol、photosynthesis 等化学反应 Substancereactions/methane-combustion、sodium-chlorine、photosynthesis组合清单trio.json如 caffeine.trio.json、glucose.trio.json、methane-combustion.trio.json运行脚本runSVG 视觉资源structural-formula-atom.svg、background.svg、node-shading.svg开发日志以第一人称记录了作者在建模过程中的真实决策、踩坑与下一步计划本文将其按建模决策 → 样式实现 → 内容编写 → 运行调优四步展开并结合源码逐一验证。二、Domain 建模为什么化学键必须是 predicate 而非 typeDevLog 的第一个核心决策是化学键bond到底应该建模成一种类型type还是建模成谓词predicate。作者最初倾向于把键做成显式类型再用构造器把原子粘在一起但最终放弃原因是 Penrose 中不存在匿名 substance 变量——如果键是一种类型那么每声明一个键都必须显式命名如Bond b1 ...而一个分子里有几十条键逐一命名既啰嗦又没必要。相比之下谓词方案可以直接写SingleBond(O1, H1)而无需为键本身起名。这一决策在 structural-formula.domain 中得到印证Domain 中只定义了Node、Atom、FunctionalGroup、Molecule、Reaction、Title六个类型而键全部以谓词形式出现predicate SingleBond(Node n1, Node n2) predicate DoubleBond(Node n1, Node n2) predicate IonicBond(Node n1, Node n2)作者也坦承这一取舍的代价如果键是类型就可以定义SingleBond、DoubleBond等子类型并在 Style 中分别定制绘制用谓词后每种键的绘制代码只能各自复制一份structural-formula.style中SingleBond与DoubleBond两段forall ... where ...规则即为明证。2.1 子类型声明的语法摩擦DevLog 还记录了一个影响面很大的语法细节子类型关系必须写在独立的行上而不能内联在类型声明里type BaseType type SubType SubType : BaseType作者希望写成type SubType : BaseType的单行形式。这在化学场景下尤其痛苦因为元素周期表上的每一种元素Carbon、Nitrogen、Oxygen…都需要是Atom的子类型。从仓库实际的 structural-formula.domain 可以看到这种三行一组的写法确实被大量使用type Atom : Node type Hydrogen : Atom type Carbon : Atom type Nitrogen : Atom type Oxygen : Atom type Sodium : Atom type Chlorine : Atom作者为这个语法问题在项目仓库提交了 Issue #722希望后续能在类型声明行内直接书写继承关系。2.2 领域模型的完整骨架综合 structural-formula.domain 全文该领域建模包含四层要素节点体系Node是抽象父类型Atom单个原子与FunctionalGroup官能团如羟基OH都是其子类型——两者在绘制时可统一用圆形图标 标签处理但官能团可额外绘制成圆角矩形框。键谓词SingleBond、DoubleBond、IonicBond参数均为Node不限于Atom因此官能团之间也可以成键。分子与反应标注Molecule类型 Contains谓词IsReactant/IsProduct谓词区分反应物与生成物Reaction类型 IsNetForward/IsStoichiometric/IsEquilibrium/IsBidirectional谓词描述反应类型。标题Title类型仅用于给整张图提供标签。这套模型既能表达分子结构咖啡因、葡萄糖也能表达化学反应方程式甲烷燃烧、钠与氯气反应是 DevLog 中Node 即图节点、键即图边这一图布局思想的领域层落点。三、Style 实现样式规则与四个真实踩坑点DevLog 的第二部分是 Style 编写过程中遇到的一系列可用性短板每一处都对应着真实的工程教训且都能在仓库源码中找到证据。3.1 局部变量匿名与类型标注的困惑作者表示很难理解局部变量的工作机制——是否需要类型、是否可匿名。他希望把一个形状与某个谓词关联时例如把一条线关联到一条SingleBond上不必为形状命名但 Penrose至少在当时的实现中似乎要求局部变量必须有名。作者为此提交了 Issue #720。从 structural-formula.style 看实际写法确实是给每个形状显式命名n.icon、line、line1、line2并以shape前缀声明shape line Line { start : x1 - 1.3*r*u end : x2 1.3*r*u strokeWidth : 4. strokeColor : Colors.black }3.2path与pathData的字段名陷阱DevLog 记录了一个让作者卡了很久的 Bug他设置的字段名是path:而不是pathData:导致Path形状始终没有被绘制而且系统既不报错也不警告。这是 Penrose 形状属性校验阶段静默吞掉未知字段的典型案例——用户把拼写错误当作配置了但没生效。该教训对任何 Penrose 开发者都有普适意义写形状字段时务必对照 shapes 类型定义 中的字段名避免Path用path、Text用string而非text这类隐性错误。3.3 SVG Image 资源的路径限制作者尝试在 Style 中直接引用与.style同目录下的 SVG 图片作为原子的外观结果什么都没显示。最终发现SVG 资源必须放到penrose/packages/core/assets/目录而不是示例自己的目录并且如何重新构建系统以识别新增 SVG 也不清晰。作者提交了 Issue #723。有趣的是示例代码的最终形态展示了两种规避路径限制的用法structural-formula.style 用Image { href: structural-formula-atom.svg }直接引用同目录资源而structural-formula-atom.svg确实与.style文件同处 structural-formula 目录——说明该问题在后续迭代中已得到缓解pseudo-3d.style 则引用background.svg与node-shading.svg并用preserveAspectRatio: none、ensureOnCanvas: false等字段控制背景图与节点高光贴图。3.4 SVG 特性未完全暴露以 linecap 为例作者需要圆头线帽rounded line caps这在 SVG 中早已是标准能力但 Penrose 当时并未在样式语法中暴露该属性。作者通过搜索-复制-粘贴-修改的方式在代码库中加入了 linecap 支持。从最终 pseudo-3d.style 看strokeLinecap: round已成为正式属性并被大量使用单键、双键、离子键的线条都显式声明了线帽离子键用butt平头加style: dashed虚线。这展示了 Penrose先按需在源码里加特性、再回填到 DSL 语法的演进模式。3.5 布局引擎的 no shape ordering possible from layering作者曾遇到布局阶段抛出的错误Error: no shape ordering possible from layering作者承认该错误技术上没错但遗憾的是系统没有优雅降级——他期望的是发出 warning 而不是 error并保留此前已经建立的局部偏序放弃寻找全局一致排序。这个反馈点明了 Penrose 布局管线的一个改进方向图层的偏序关系可能存在环此时应当降级而非中止整个布局。3.6 平面结构式的 Style 骨架综合 structural-formula.style平面结构式样式由五类规则构成画布与全局量canvas { width: 1066.5, height: 600 }Global块定义atomRadius 20、bondLength 60以及一个描边背景矩形bbox。原子基础外观forall Node n每个节点绘制白色圆形图标n.icon、以structural-formula-atom.svg为底的n.background、以及元素符号文本n.text并ensure contains( Global.bbox, n.icon, 0. )把节点约束在画布内。元素着色覆盖override对Hydrogen/Carbon/Nitrogen/Oxygen分别覆盖填充色、描边色与文本如氢原子红底白字H、碳原子黑底白字C。键绘制forall Node n1; Node n2 where SingleBond(...)等用unit(x1-x2)求方向向量把线段起点/终点各向内缩进1.3 * atomRadius避免线条穿入原子圆内单键一根粗线双键沿法向v (-u[1], u[0])平移出两根平行线同时encourage equal( norm(x1-x2), Global.bondLength )让键长趋向目标值。斥力与图层对所有节点对施加encourage equal( 200000./normsq(x1-x2), 0. )的类库仑斥力避免原子重叠并用layer语句固定键在图标下方、背景在最底层的绘制顺序。值得一提的是pseudo-3d.style在此基础上升级了视觉表现用Grouplistof shadow把全部节点阴影聚合成一个带opacity: .1与filter:blur(5px)的模糊阴影组用collect Node n into nodes收集节点还为官能团绘制带圆角的Rectangle框g.box并让氢原子缩小为0.75 * atomRadius。这些特性展示了 Penrose Style 在基础绘制之外的表达力。四、Substance 编写标签必须走 TeXDevLog 记录了内容层的一个重要发现Penrose 的标签必须用 TeX 书写不支持纯文本标签Issue #721。作者此前花了不少功夫才在文档中定位到 Labels 相关说明当时文档较为分散。这一约束在示例中体现得很明显简单分子用AutoLabel All自动生成标签例如 water.substance 只有三行声明与两行键需要自定义文本时一律使用 TeX 语法例如 glucose.substance 中的Label hydroxy_methyl $\mathrm{CH}_2\mathrm{OH}$methane-combustion.substance 中的Label methane $\text{methane}\ (\mathrm{CH}_4)$咖啡因 caffeine.substance 则用Title titleLabel title caffeine为整图提供标题。从结构上看一个分子的 Substance 文件通常分四段元素声明Carbon C1, C2, ...、键声明SingleBond(...)/DoubleBond(...)、标签声明AutoLabel All 显式Label、标题TitleLabel。化学反应文件在此基础上增加Molecule、Contains、IsReactant、IsProduct、Reaction、IsNetForward等声明把反应物/生成物的结构信息显式交给布局引擎。五、运行与性能从水分子到咖啡因的图布局之战DevLog 明确指出小分子水3 个原子运行毫无压力但大分子咖啡因24 个原子会让一切明显变慢——而且慢在编译阶段而非优化阶段一旦初始编译完成重新采样与优化反而很快。5.1 性能瓶颈全对 encourage 的成本作者将瓶颈归因于structural-formula.style中的全对斥力规则forall Node n1; Node n2 { vec2 x1 n1.center vec2 x2 n2.center encourage equal( 200000./normsq(x1-x2), 0. ) ... }这是一条所有节点对all-pairs的目标每个原子试图与其他所有原子保持距离。对 3 个原子只有 3 对对 24 个原子则有 C(24,2)276 对——目标函数项数随节点数平方增长这是编译期耗时爆炸的直接原因。对比可见pseudo-3d-reaction.style 在表达反应式时对同一斥力做了分域收紧只在IsReactant(m); Contains(m,n1); Contains(m,n2)、同侧分子之间等更小的作用域内施加斥力显著缩小配对规模。5.2 图布局的hack键长目标 全局斥力作者坦承这本质上是个图布局问题而我在尝试把它硬塞进 Penrose 优化器。其做法是双管齐下对有键相连的原子对encourage equal( norm(x1-x2), Global.bondLength )让键长趋于目标值相当于图的边约束对所有原子对无论是否成键encourage equal( 200000./normsq(x1-x2), 0. )让斥力能趋近于零相当于图的顶点分离约束。结果少于 10 个节点的分子通常能得到不错的布局更大分子则往往要靠反复点击resample并非常幸运地才能避免边交叉的杂乱布局。这说明纯靠键长 斥力两个标量目标无法系统性地解决大图的边交叉问题。5.3 下一步计划为边不重叠定义一个目标函数DevLog 收尾处给出了明确的改进方向作者想鼓励边不重叠方法是最小化由四条端点两条边共四个原子构成的有向面积的某种函数。但当时的 Penrose没有让某量取尽可能小值的原语——所有目标都形如encourage equal(expr, target)。因此下一步是自己定义一个新的 minimize 类目标函数。这实际上点出了一个可复用的设计思路在 Penrose 的 Objectives.ts 等目标函数库中新原语通常以把表达式与目标值之差压向零的形式接入优化器要实现最小化有向面积可以仿照equal把f(area)与 0 对齐。示例仓库虽然没有最终实现该原语但 DevLog 记录的这条探索路径恰好示范了遇到 DSL 能力缺口 → 溯源到核心库 → 扩展目标函数的标准动作。六、运行方式与文件索引6.1 如何运行这些示例run 脚本展示了最直接的运行方式基于仓库的 roger 工具其实现位于 packages/rogernpx roger watch reactions/sodium-chlorine.substance pseudo-3d-reaction.style structural-formula.domain参数依次为 Substance 文件、Style 文件、Domain 文件watch模式会在文件变化时自动重算布局。也可以借助 trio.json 组合清单如 caffeine.trio.json内含substance、style、domain三项路径与variation随机种子在编辑器或文档站中一键渲染。6.2 关键文件速查层次文件说明开发日志DevLog.md本文核心素材建模取舍、踩坑记录、性能分析与下一步计划Domainstructural-formula.domain节点/键/分子/反应的类型与谓词定义Style平面structural-formula.style基础结构式圆点原子、单/双键、全对斥力Style伪 3Dpseudo-3d.style阴影模糊、官能团圆角框、键角约束、水分子 104.5° 等Style反应式pseudo-3d-reaction.style反应物/生成物分区、箭头绘制、分域斥力Substancemolecules/、reactions/各分子与化学反应的文本描述资源structural-formula-atom.svg、background.svg、node-shading.svg原子纹理、背景、节点高光贴图七、小结这份 DevLog 带来的工程启示从 DevLog.md 与示例源码的对照中可以提炼出几条对任何用 Penrose 建新领域 DSL都适用的经验谓词优先于类型当某个概念化学键需要大量实例且实例本身无需被引用/命名时用 predicate 比用 type 省去海量样板命名代价是子类型化的多态绘制无法使用需要复制规则。形状字段名必须精确pathvspathData这类静默失败是 Penrose 早期版本的主要可用性痛点编码时务必对照核心库 Shapes.ts 中的字段定义。资源与标签有约束SVG 资源路径、TeX-only 标签、子类型声明语法都是作者实际踩过并提交 Issue 的坑#720、#721、#722、#723新用户在迁移到新版本前应留意这些约束是否已解除。性能要从配对规模入手all-pairsencourage会让编译期随节点数平方恶化分域按反应物/生成物分组施加约束是立竿见影的优化手段。能力缺口 → 核心库扩展当 DSL 缺少最小化某量的原语时正解是仿照现有目标函数在 Objectives.ts 中新增原语而非在样式层变相 hack。这份开发日志的价值正在于它没有只展示漂亮的成品而是把 DSL 在真实复杂领域落地时的摩擦、妥协与下一步构想完整留档是理解 Penrose 表达能力边界与其演进路线的一份珍贵的一手材料。赞分享开发工具数据可视化【免费下载链接】penroseCreate beautiful diagrams just by typing notation in plain text.项目地址https://gitcode.com/gh_mirrors/pe/penrose点击查看免费下载相关推荐vscode-pets错误排查与调试常见问题解决方案大全vscode pets错误排查与调试常见问题解决方案大全 vscode pets是一款能在VS Code窗口中添加可爱宠物的扩展让编程过程更加轻松有趣。本文i3lock-color实战案例5个惊艳的锁屏配置脚本分享i3lock color实战案例5个惊艳的锁屏配置脚本分享 i3lock color是一款功能强大的屏幕锁定工具它允许用户自定义锁屏的外观和行为打造个性化gocrawl最佳实践构建企业级网络爬虫的完整方案gocrawl最佳实践构建企业级网络爬虫的完整方案 gocrawl是一款用Go语言编写的礼貌、轻量且并发的网络爬虫工具专为企业级应用设计。它能够高效地抓取网后端上一篇APISIX 自定义 Nginx 配置指南snippet 注入机制与实战下一篇深入解析Ryujinx VP9解码器如何实现Switch游戏的高效视频处理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

FastAPI + PostgreSQL 实战:做一个重启后还能继续的审批流程 2026/9/27 7:57:36

FastAPI + PostgreSQL 实战:做一个重启后还能继续的审批流程

FastAPI PostgreSQL 实战:做一个重启后还能继续的审批流程 《企业级 Workflow 实战:从审批流到 AI Agent》|第 03 篇 / 共 24 篇 本篇成果:提交客户服务申请、创建运营待办、完成审批、查询流程历史,并实测应用进程重…

阅读更多 →
LeetCode 1096.花括号展开 II:一个一百行的解题方法(DFS) 2026/9/27 7:57:30

LeetCode 1096.花括号展开 II:一个一百行的解题方法(DFS)

【LetMeFly】1096.花括号展开 II:一个一百行的解题方法(DFS) 力扣题目链接:https://leetcode.cn/problems/brace-expansion-ii/ 如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符…

阅读更多 →
5步搞定html5网站检测,从零搭建避开90%的坑 2026/9/27 7:57:30

5步搞定html5网站检测,从零搭建避开90%的坑

5步搞定html5网站检测,从零搭建避开90%的坑 网站做好了没人访问,这不仅仅是流量玄学,很多时候是底子没打牢。很多新手朋友问,明明页面挺好看,为什么百度搜不到,甚至打开速度还慢?问题往往出在代码结构和标准兼容性上。今天不聊虚的,直接拿一…

阅读更多 →
Amethyst 瓦片地图实战:从 Tile 特征实现到 TileMap 组件创建完整指南 2026/9/27 7:57:23

Amethyst 瓦片地图实战:从 Tile 特征实现到 TileMap 组件创建完整指南

【免费下载链接】amethyst Data-oriented and data-driven game engine written in Rust 项目地址: https://gitcode.com/gh_mirrors/ame/amethyst 点击查看 免费下载 本篇技术指南围绕 Amethyst 游戏引擎(Rust 编写的数据驱动游戏引擎)的 a…

阅读更多 →
AutoBangumi 解析器配置指南:RSS 标题解析引擎、语言与全局过滤规则 2026/9/27 7:57:23

AutoBangumi 解析器配置指南:RSS 标题解析引擎、语言与全局过滤规则

后端前端音视频 【免费下载链接】Auto_Bangumi AutoBangumi - 全自动追番工具 项目地址: https://gitcode.com/gh_mirrors/au/Auto_Bangumi 点击查看 免费下载 AutoBangumi 的解析器(Parser)负责从 RSS 条目标题中抽取结构化的番剧元数据&am…

阅读更多 →
换机照片怎么迁移才靠谱?6种方案对比,原图与备份一次讲清 2026/9/27 7:57:23

换机照片怎么迁移才靠谱?6种方案对比,原图与备份一次讲清

换手机时,照片迁移最需要关注的不是单纯的“速度”,而是文件有没有完整过去、原始信息有没有变化,以及迁移完成后有没有备用副本。如果只有几百张照片,手机直连通常就能解决;但面对几千甚至上万张照片,尤其…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉