news 2026/11/4 1:36:33

SolidCraft 参数化 CAD 内幕:改 24mm 到 32mm 背后的三层链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SolidCraft 参数化 CAD 内幕:改 24mm 到 32mm 背后的三层链路

SolidCraft 参数化 CAD 内幕:改 24mm 到 32mm 背后的三层链路

【免费下载链接】solidcraftSolidCraft: an open-source parametric 3D CAD application built in pure Rust. Desktop, web, and automation through MCP.项目地址: https://gitcode.com/gh_mirrors/so/solidcraft

把参数面板里一个尺寸从 24 改成 32,整机箱模型随即整体重建——这是 SolidCraft,一个用纯 Rust 写成的参数化 CAD,桌面端、浏览器与 MCP 自动化共用同一套代码。下文顺着源码拆解这次改动背后的三层链路:约束求解、参数驱动、增量重建。

全局图景:一次改动经过的三层链路

官方演示的收尾动作很固定:在 Parameters 面板把机箱高度从 24 mm 改成 32 mm,拉伸、立柱、通风槽全部跟着更新。这个动作不是"重画一遍模型",它按固定顺序穿过三层:

  1. 参数层:被改的数字先经过表达式求值(单位感知、可引用其他参数),得到新的参数值;
  2. 几何层:草图约束求解器以新的尺寸值为目标,把整套约束解算一遍,重新算出每个点的坐标;
  3. 重建层:特征时间线做增量评估,从第一个受影响的特征起,逐一走过几何内核(负责实体运算的底层引擎)生成新几何。

代码上每一层都有明确归属:crates/doc/src/params.rs与expr.rs管参数和表达式,crates/sketch/src/solver.rs管约束求解,crates/doc/src/eval.rs管时间线评估。下面逐层看。

参数层:从"数字"到模型参数 dN

在 SolidCraft 里,一个尺寸值或特征输入(拉伸距离、圆角半径)并不是以纯数字形式存进文件的。crates/doc/src/params.rs 的模块注释说清了这一点:

Parameters: user parameters, model parameters of sketch dimensions, and feature inputs (extrude distance, fillet radius…) which also appear as model parametersdNwithout being stored twice: the feature keeps its expression and the parameter name refers to it.

解读:特征保留的是表达式,参数值只存一份,特征按名字引用它。特征不存数字,存表达式;参数才是数值的唯一真源。所有草图尺寸和特征输入都会按遍历顺序拿到d1、d2这样的模型参数名,任意表达式都能按名字引用任意参数。

用户参数与模型参数的差别只在"命名"这一步:模型参数自动分配,用户参数是你自己起的名字。在输入框里敲height = 12就会创建(或重命名)一个参数,此后的表达式都引用它(docs/book/src/guide/parameters.md)。

表达式系统有三条纪律,都写进了文档与注释:

  • 单位感知。crates/doc/src/expr.rs 给出的例子是2 * width + 5 mm、angle / 2;指南明确:长度填到角度位置(或反过来)"is an error, not a silent conversion"——直接报错,不悄悄换算。
  • 循环依赖报路径。"Cycles are reported with their path (a → b → a)"——报圈不只是一个"存在循环",而是把路径列出来。
  • 重命名是全局操作。"renaming a parameter updates every expression, dimension and feature input that uses it, and a parameter in use can't be deleted"——重命名自动更新所有引用,使用中的参数禁止删除。

依赖图本身不用维护,它由表达式引用自动推出(params.rs 注释:the dependency graph and cycles come from the expression references)。给拉伸距离写height / 2时,联动关系就已经落在文件里了。

几何层:约束求解器如何把关系算成坐标

参数层只产出数字;数字要变成坐标,靠草图约束求解器。

约束全集在 crates/sketch/src/model.rs 的ConstraintKind枚举里,分两类:几何关系(Coincident、PointOnCurve、Horizontal/Vertical、Parallel、Perpendicular、Tangent、Equal、Concentric、Midpoint、Symmetric、Fix)和驱动尺寸(Distance、Length、Radius、Angle等)。值得注意:尺寸本身就是一种约束——它比几何关系多带一个value字段。无值的是关系,有值的才是驱动。

求解策略在 crates/sketch/src/solver.rs 的模块注释里:

Unknowns are the coordinates of every non-fixed point and the radius of every circle. Each constraint contributes residuals (zero when satisfied, in millimetres so that all rows have a comparable scale). The system is split into connected components and each is solved with a damped Gauss–Newton (Levenberg–Marquardt) iteration on a dense Jacobian built from local central differences.

拆成三步读:未知量是每个未固定点的 x/y 坐标、每个圆的半径;每条约束贡献一个以毫米计的残差,即"当前还不满足多少";系统按连通分量拆分(互不触及的约束互不相干,分开解),每个分量内做阻尼 Gauss–Newton 迭代——Gauss–Newton 是逐步线性化解非线性方程组的经典方法,"阻尼"指控制步长防止发散(Levenberg–Marquardt 就是它的标准实现),Jacobian(残差对每个未知量的偏导矩阵)用中心差分数值构造。

自由度分析是同一个 Jacobian 的直接副产品:

Afterwards the rank of the Jacobian gives the remaining degrees of freedom and which points are fully determined.

即Jacobian 的秩直接给出剩余自由度——几何还能自由移动的方向数。SolveReport里对应dof(0 即完全约束)、未满足约束failing、以及逐点/逐曲线的point_determined/curve_determined。UI 表现见 docs/book/src/guide/sketching.md:

Under-constrained geometry is blue and fully constrained geometry turns dark… A constraint or dimension that would over-constrain the sketch is refused rather than applied.

欠约束的几何显示为蓝色、仍可拖动;dof 归零后变深色;会造成过约束的新约束会被拒绝,而不是强行套用。

还有一处工程取舍:并非所有未知量都进迭代器。求解器注释写道,那些能从常数一步步"逐个钉出来"的未知量——比如两条已知轨迹(loci,已确定的几何元素集合)的交点——"are eliminated exactly, without the dense matrices":crates/sketch/src/decompose.rs的注释引用 Owen 1991 与 Fudos–Hoffmann 1997 的构造分解,把这类点先精确消去,剩下的才交给 LM 迭代。能算出精确解的就不走稠密矩阵,这是求解器既快又稳的来源。

重建层:特征时间线的增量评估

草图只是第一步。拉伸、旋转、扫掠、圆角、抽壳、阵列、镜像等全部特征挂在一条时间线上。crates/doc/src/lib.rs 顶部一句话定了评估规则:

Evaluation is incremental: a feature is recomputed only when it, a parameter it uses, or an earlier feature changed.

eval.rs 的主评估函数注释更直白:Re-evaluate the document, reusing results up to the first changed feature——找到第一个变化的特征,它之前的结果原样复用,从它开始往后重走。50 步的历史里改第 3 步的尺寸,前 2 步不参与重算。

"重走"要可靠,靠一套持久化命名兜底。docs/book/src/dev/naming.md 先讲原因:如果圆角存的是边的下标,上游一改、面多了一个,圆角就会挪到别的边上。"SolidCraft stores names, and finds them again every time the timeline evaluates."——名字不是几何猜测:内核对每次运算报告每个面/边的来历,名字沿历史传递(crates/doc/src/lineage.rs合成,crates/doc/src/name_lookup.rs查找);引用确实找不到了,特征会明说,而不是默默选错对象。

时间线本身也完全可交互:每个特征可编辑、抑制、重命名、重排(docs/book/src/guide/features.md:Each one can be edited, suppressed, renamed, reordered),底部还有逐步回滚的历史回放条。下面示例设计的浏览器面板列出了 Sketches 与 Features 层级,底栏即时间线:

源码速查:哪个文件对应哪一节

文件职责对应章节
crates/doc/src/params.rsdN 模型参数、用户参数、依赖与循环检测参数层
crates/doc/src/expr.rs单位感知表达式求值参数层
crates/sketch/src/model.rsConstraintKind:几何关系与驱动尺寸几何层
crates/sketch/src/solver.rsLM 迭代求解器、Jacobian 秩与 dof 报告几何层
crates/sketch/src/decompose.rsOwen/Fudos–Hoffmann 解析分解与精确消元几何层
crates/doc/src/lib.rs文档模型与增量评估规则重建层
crates/doc/src/eval.rs时间线评估、结果复用重建层
crates/doc/src/name_lookup.rs持久命名查找与降级重建层

动手验证:两条 JSON 命令检查并驱动一个特征

时间线还有一整套命令接口,最小复现路径是timeline.inspect与timeline.edit(见 docs/book/src/guide/features.md)。前者查一个特征的定义与输入参数,后者写入新值:

{"command": "timeline.inspect", "params": {"feature": "Slab"}} → {"type": "extrude", "definition": {"extent": {"distance": "10", "direction": "positive"}, …}, "inputs": [{"label": "Distance", "param": "d1", "expression": "10", "unit": "mm"}]} {"command": "timeline.edit", "params": {"feature": "Slab", "set": {"extent": {"distance": "12"}}}}

inputs字段是两层机制的交汇点:它把特征输入映射到参数名和当前表达式(d1→10)。timeline.edit合并新字段后触发重建,响应里报告哪些特征被recomputed、哪些被restored(复用)。演示 GIF 结尾的"高度 24 → 32 mm"走的正是同一条通路。

收尾:参数化模型为什么天然可脚本化

回头看这套机制,"改 24 为 32、全模型重建"之所以能被脚本驱动,是因为模型不是一份几何结果,而是一段可重放的描述——参数表、约束系统、特征序列,全部可序列化。同一套命令既可供 UI 使用,也可以经 JSON 控制通道(docs/book/src/dev/control-protocol.md)和 MCP 服务器(crates/mcp/)暴露给 AI 代理。当模型天生就是"描述 + 重放",自动化就不是附加功能,而是表示方式的直接推论。

【免费下载链接】solidcraftSolidCraft: an open-source parametric 3D CAD application built in pure Rust. Desktop, web, and automation through MCP.项目地址: https://gitcode.com/gh_mirrors/so/solidcraft

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

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

优化Hermes Agent的API缓存实现:Redis与Memcached比较

优化Hermes Agent的API缓存实现:Redis与Memcached比较 在现代AI应用开发中,高效的API缓存机制是提升性能和降低成本的关键因素。Hermes Agent作为一款强大的AI代理框架,其缓存策略直接影响系统响应速度和资源利用率。本文将深入探讨如何优化…

作者头像 李华
网站建设 2026/11/4 1:34:09

ruoyi登录功能后端代码调用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华