资讯动态

Penrose 图形约束中的包含关系判定:从 BBox 预筛到 Level Set 精判的设计与实现

发布时间:2026/9/27 5:42:10 来源:尧图企业网站定制
开发工具数据可视化【免费下载链接】penroseCreate beautiful diagrams just by typing notation in plain text.项目地址https://gitcode.com/gh_mirrors/pe/penrose点击查看免费下载导读本文以 Penrose 仓库中 docs/graphical-api.md 这份设计笔记为核心完整展开其中记录的contains图形约束算法设计——从“BBox 粗判 Level Set水平集精判”的两阶段伪代码到坐标系统与变换、运行时优化构想以及intersects、overlap等关联目标函数。文章同时结合仓库源码Constraints.ts、BBox.ts、Minkowski.ts印证这些设计在当前实现中的落点帮助读者理解 Penrose 如何在可微优化框架内表达“A 包含 B”这类空间关系。一、设计笔记的背景为什么需要专门的contains约束Penrose 的核心工作方式是把“画图”编码为一个数值优化问题所有约束constraint和优化目标objective都被实现为可微的能量函数优化器不断降低总能量直到得到一个满足语义的布局。这一点在 docs-site/docs/ref/constraints.md 中有系统说明约束必须写成零基不等式p(x) 0的形式Penrose 会惩罚违反程度且所有数值运算都要通过自动微分autodiff算子完成。contains正是这样一类约束它要求形状s1包含形状s2可选一个padding作为两者尺寸之间的安全边距。这个约束看似简单但对任意形状对圆、多边形、矩形、Group 等都要给出一个可微的、且不引入过多性能开销的能量值因此需要认真设计算法——这正是 docs/graphical-api.md 记录这份设计笔记的动机。从当前源码看contains已在 Constraints.ts 中落地为按形状类型分派dispatch的通用函数Circle–Circle 走containsCirclesPolygon–Polygon 走containsPolys矩形类走containsRectsGroup 走containsGroupShape无法精确处理时退回 BBox 近似并给出BBoxApproximationWarning。设计笔记中“先粗判、后精判”的思路正是为了减少这些分派在通用情形下的计算量。二、两阶段判定算法BBox 粗筛 Level Set 精判设计笔记的核心是一段针对通用对象contains A B的伪代码其总体策略是第一阶段BBox 粗判先看A与B的包围盒bounding box简称 BBox是否满足包含关系短路返回如果 BBox 层面就能判定结果d ! 0直接返回该距离值第二阶段Level Set 精判仅当 BBox 判定不充分结果为 0即边界上无法确定时才进入 Level Set 的逐像素精确比较。笔记给出的原始伪代码如下-- Top-level function on two generic objects contains A B let d contains (bbox A) (bbox B) if d ! 0 then d else contains (levelSet A) (levelSet B) contains (BBox a) (BBox b) if ! ( a.L b. L .... ) return dist( a.center, b.center) - Epsilon else 0 contains (LevelSet a) (LevelSet b) -- Assuming we have globally uniform grid resolution for x in width that they overlap for y in height that they overlap if ( b.grid[ x,y ] 0 ) if ( a.grid[ x,y ] 0 ) -- return farthest “worst” pixel distance function -- average or handle points return 0逐段解读其中的关键设计决策BBox 阶段返回距离值当A的包围盒在某个维度上不能覆盖B的包围盒时直接用dist(a.center, b.center) - Epsilon作为能量值。这保证了约束值在“明显不满足”时是一个正数即被惩罚并且是连续可微的——距离中心差是位置坐标的平滑函数。Epsilon是一个容差项避免把“刚好相切”误判为满足或违反。BBox 阶段返回 0 表示“无法确定”当两个包围盒在所有维度上都满足包含关系时BBox 判定只能说明“B在盒层面位于A内”但A的真实形状可能是凹陷的、非凸的边界附近的点是否真的在A内无法从盒得出。此时返回 0 作为哨兵值触发第二阶段。Level Set 阶段逐像素比较在全局统一网格分辨率globally uniform grid resolution的假设下遍历两个网格重叠区域内的每个像素(x, y)如果b.grid[x, y] 0B的网格值非正说明该像素在B内或边界上而a.grid[x, y] 0A的网格值为正说明该像素在A外则说明存在B的点落到了A之外即包含关系被违反。返回值应体现“最坏”像素的距离函数值或者做平均处理。与当前源码实现的关系设计笔记中的两阶段思想在当前仓库中体现为两个层面BBox 是实际的降级路径contains的通用分支两个形状都非 Circle/Polygon/Rect 等已知组合会退回containsRects(bboxFromShape(s1), bboxFromShape(s2), padding)同时返回一个BBoxApproximationWarning提示“当前结果只是包围盒近似”见 Constraints.ts。BBox 的数据结构在 BBox.ts 中定义由width、height、center组成并提供角点corners、区间intervals、边edges等辅助接口。精确判定按形状类型特化仓库并没有用统一的 Level Set 网格而是为每种形状组合给出精确的解析能量函数例如containsCirclesd - (r1 - r2 - padding)即“圆心距减去半径差”完全对应 docs-site/docs/ref/constraints.md 中推导的圆包含能量表达式Constraints.tscontainsPolys/containsPolyCircle/containsCirclePoly把“多边形包含”转化为“每个关键点都被包含”的能量maxN取最坏点对应笔记中“return farthest worst pixel distance”的取最大惩罚思想Constraints.tscontainsGroupShape对 Group 先判断成员形状是否包含目标再结合裁剪形状clip path共同判定采用minN成员满足其一即可与andConstraint裁剪必须同时满足的组合Constraints.ts。换句话说笔记中“BBox 粗判短路、Level Set 精判兜底”的分层策略在实现上被等价地落实为“已知形状组合走精确解析式、未知组合退回 BBox 并告警”的分派策略。三、坐标系统与变换grid / math / screen 三套坐标设计笔记明确指出系统内同时存在三套坐标系统任何涉及 Level Set 网格的运算都必须清楚自己在哪套坐标系下网格坐标grid coordinatesLevel Set 的离散像素坐标即grid[x, y]中的x, y数学坐标math coordinates系统默认的连续坐标所有形状属性圆心、半径、顶点等都以它为准屏幕坐标screen coordinates前端渲染使用的坐标与 Canvas 画布相关。笔记给出了两组变换关系变换涉及参数math ↔ screen平移由 CANVAS 尺寸决定grid ↔ math平移 缩放由 Level Set 分辨率、网格左上角在数学坐标中的位置决定这两条变换关系在实践中意味着网格与数学坐标之间不是简单平移网格分辨率每单位距离多少个像素决定了缩放因子而网格左上角top-left corner的数学坐标决定了平移偏移。任何“把形状的连续坐标换算成网格下标”的操作都需要offset (mathCoord - gridTopLeft) * resolution这类换算。屏幕坐标与数学坐标之间在 Penrose 的渲染链路中由画布尺寸决定平移量。当前渲染器实现在 packages/core/src/renderer 目录下各形状的 SVG 属性如cx、cy、r均从数学坐标经画布变换映射而来。笔记还提到一个与此相关的开放问题对齐Alignment。当两个 Level Set 网格分辨率或原点不一致时“用像素分辨率重算重叠区域”是最直接的思路Idea 1但这会带来性能开销还可能要求用户一开始就按像素分辨率输入 SDF并可能在上/下采样与插值中引入误差。该问题在笔记中列为待决项说明它属于设计考量而非最终实现。四、性能优化构想按需细化 Level Set由于 Level Set 的逐像素比较是 O(重叠像素数) 的操作笔记专门记录了解决慢运行时的构想Idea 1compute finer levelset on demand—— 如果只需 BBox 即可完成空间查询就先在较粗的分辨率上计算 Level Set只有当 BBox 测试结果不确定not deterministic时才在局部细化到更精细的 Level Set。这是一种典型的**渐进式精度progressive refinement**策略先以粗网格快速排除大量无需精确判定的情况再对少数边界情况投入精细计算。它与第二节伪代码中的短路逻辑一脉相承——两阶段设计的目的正是让“绝大多数情况”停留在廉价的第一阶段。从当前实现看仓库选择了另一种等价工程路径来规避这一性能问题contains为每种已知形状组合提供解析的、O(1) 或 O(顶点数) 的精确能量如containsCircles只有一次ops.vdist从而完全避免了网格化的逐像素开销只有未知组合才退回 BBox。这与笔记“用 Level Set 兜底”的初衷一致但用解析式替代了网格扫描从源码结构看这是设计笔记落地时做出的关键简化。五、关联目标intersects与overlap笔记末尾列出了其他相关目标函数intersects与overlap。这两者与contains共同构成 Penrose 中形状间空间关系的基础集合overlapping(s1, s2, overlap)要求两个形状以一定的重叠量相交overlap参数控制最小重叠量默认 0其能量由形状距离shapeDistance与重叠量的组合构成Constraints.ts在形状距离计算触发 BBox 近似时会改写告警信息为overlapping(s1, s2)签名便于用户定位问题Constraints.ts。disjoint(s1, s2, padding)要求两形状不相交语义上等价于“overlapping取负”即把overlapping的能量取反Constraints.ts。touching则取其绝对值表示相切状态。圆与椭圆的解析实现overlappingEllipses、overlappingCircleEllipse通过隐式椭圆函数ImplicitShapes.ts实现在 Constraints.ts 中注册。intersects在设计笔记中作为待实现目标列出当前源码中intersects更多以函数查询形式出现如 Functions.ts 中“射线与形状求交”的rayIntersect系列见 Functions.ts用于几何查询而非约束能量。这些约束都在 constrDict 中统一注册随后作为 Style 语言的内建约束builtin constraints暴露给用户可在.style文件中直接书写例如contains s1 s2 padding: 10.0 overlapping s1 s2 overlap: 5.0 disjoint s1 s2 padding: 3.0其中padding/overlap参数均有默认值 0见 constrDictGeneral 中各个条目的params声明表示“恰好包含 / 恰好重叠”。六、设计笔记中的开放问题与后续演进从笔记行文可以推断这份文档是contains图形约束开发早期的设计备忘其中明确标记的开放问题包括Level Set 对齐问题重叠区域的重算、初始 SDF 的分辨率输入要求、上下采样与插值误差——这些决定了“网格化方案”能否落地性能路径是否按需细化 Level Set取决于 BBox 测试的判定确定性determinism程度目标函数集合的补全intersects、overlap与contains的最终统一语义。对照当前仓库上述问题的大部分已在源码层面得到工程化解法contains的精确能量按形状组合特化Constraints.tsMinkowski 和Minkowski.ts为凸多边形提供解析的有符号距离函数 SDFrectangleDifference为包围盒差提供解析解——这些都让“逐像素 Level Set”不再是唯一选择。因此设计笔记与当前实现构成了一个完整的演进脉络从“两阶段网格算法”的构想到“BBox 兜底 解析特化”的落地读者可以通过对照这两份材料深入理解 Penrose 图形约束系统的设计取舍。延伸阅读约束与目标函数的系统讲解Writing Constraints Objectivescontains/overlapping/disjoint的实现Constraints.tsBBox 数据结构与辅助函数BBox.tsMinkowski 和与 SDF 实现Minkowski.ts函数库与射线求交等几何查询Functions.ts隐式形状椭圆、半平面定义ImplicitShapes.ts赞分享开发工具数据可视化【免费下载链接】penroseCreate beautiful diagrams just by typing notation in plain text.项目地址https://gitcode.com/gh_mirrors/pe/penrose点击查看免费下载相关推荐Penrose 实战教程用 predicate 声明关系、用 ensure 约束绘制子集包含图Penrose 实战教程用 predicate 声明关系、用 ensure 约束绘制子集包含图 本文是 Penrose 系列教程的第二篇围绕仓库文档 pre开发工具数据可视化cytoscape.js 集合包含关系判定eles.contains() / eles.has() 的用法与源码原理cytoscape.js 集合包含关系判定eles.contains / eles.has 的用法与源码原理 eles.contains eles 是 cyt数据可视化Penrose约束系统从几何关系到优化目标的转换Penrose约束系统从几何关系到优化目标的转换 Penrose作为一个通过文本符号生成精美 diagrams 的开源项目其核心在于将用户定义的几何关系转化开发工具数据可视化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑