如何画一条隐式曲线、一面隐式曲面:Grafar vsolve 牛顿法求解实战指南
2026/8/22 14:33:10 网站建设 项目流程

如何画一条隐式曲线、一面隐式曲面:Grafar vsolve 牛顿法求解实战指南

【免费下载链接】grafarReactive multidimensional math & data visualization for the web.项目地址: https://gitcode.com/gh_mirrors/gr/grafar

Grafar是一个基于 WebGL 的 JavaScript 响应式数学可视化库,其中的vsolve方法内置牛顿法(Newton's method),让你用一行代码就能绘制任意隐式曲线隐式曲面——无需手动采样、无需网格剖分,只需写出方程 f(x, y, z) = 0。🎯

什么是隐式图形?

多数绘图库习惯用"参数方程"描述形状:给 t,算出 (x(t), y(t))。但很多漂亮的形状天然以"隐式方程"存在,比如:

  • 球面:x² + y² + z² = 2
  • 超椭圆(squircle):x⁴ + y⁴ = 3

它们的共同点是用方程定义零点集合(zero set),而不是用参数遍历。这正是 Grafar 的vsolve擅长处理的问题:给定一个函数 f,自动求出满足 f = 0 的点集。

核心实现位于两个文件中:

  • src/math/newton.ts—— 牛顿法迭代器
  • src/generators.ts中的vsolve函数(约第 120 行)

vsolve 的完整用法:三参数一行出图

vsolve的签名很简单,三个核心参数:

grafar.vsolve( v => Math.pow(v[0], 4) + Math.pow(v[1], 4) - 3, // 1. 隐式函数 f 5000, // 2. 要生成的点数 2 // 3. 维度(2=曲线,3=曲面) )
参数含义说明
f隐式函数接收一个坐标数组v,返回 f(v) 的值,求解目标为 f(v) = 0
size点数生成多少个点;曲面建议 3~5 万点,曲线 5 千点足够
dof自由度/维度2 维画平面曲线,3 维画空间曲面

⚠️ 注意:f接收的是单个数组参数v[0]v[1]…),这与 Grafar 中map()的多参数风格不同。

官方教程 docs/tutorial/5-implicit.md 中给出了这两个经典用例,完整可运行的 HTML 示例见 examples/implicit_3d.html。

实战一:绘制隐式曲线(二维)

画一条四阶超椭圆曲线,只需将点集select()后交给面板:

const curve = grafar.vsolve( v => Math.pow(v[0], 4) + Math.pow(v[1], 4) - 3, 5000, 2 ).select(); grafar.pin(curve, grafar.panel(document.getElementById('icurve')).setAxes(['x', 'y']));

.setAxes(['x', 'y'])会把面板固定为二维视图,适合绘制平面曲线。

实战二:绘制隐式曲面(三维)

把维度改为 3,方程换成x³ + y² + z² = 2,就得到一个有趣的非对称"水滴形"曲面:

const surf = grafar.vsolve( v => Math.pow(v[0], 3) + Math.pow(v[1], 2) + Math.pow(v[2], 2) - 2, 50000, 3 ).select(); grafar.pin(surf, grafar.panel(document.getElementById('isurf')));

曲面渲染为点云,配合 libs/OrbitControls.js 提供的轨道控制,可以用鼠标自由旋转、缩放观察。

揭秘:vsolve 内部如何用牛顿法求解?

vsolve并不暴力枚举网格,而是采用"随机探测 + 牛顿迭代"策略,整体分两步(见src/generators.ts第 134~200 行):

第一步:探测与估计(estimator)

随机撒 100 个点(范围约 [-10, 10]),对每个点执行牛顿迭代。成功收敛到 f ≈ 0 的点用于统计均值mean和散布spread——相当于先"侦察"零点大概在哪里、分布多广。

第二步:批量生成(constructor)

在统计出的分布范围内用随机化(src/math/randomize.ts)生成全部 size 个初始点,再逐点跑牛顿迭代,把每个点"吸附"到零点上。

牛顿迭代本体在 src/math/newton.ts 中,逻辑非常精炼:

  1. 计算当前值val = f(pt)和梯度gradf
  2. -val / |∇f|²后验误差估计,得到移动步长
  3. 沿梯度方向移动:pt += posterr * nabla
  4. 若偏移量小于容差tol(默认 0.001,配置于 src/config.ts),判定收敛并返回
  5. 超过最大迭代次数(默认 30 次)仍未收敛,则返回 0

梯度计算本身也很"轻量":src/math/grad.ts 用前向差分近似偏导,原地修改坐标数组以避免额外内存分配,对 5 万个点的批量求解性能很友好。

💡 小贴士:vsolve还支持{ neq: true }选项(acceptNeg),此时 f(pt) ≤ 0 即视为收敛——用于求解不等式、绘制区域填充。

最佳实践与常见坑

  • 对象要平滑、有界、靠近原点vsolve的点探测围绕零点展开,零点飘在很远处的方程(如 f = x - 1000)可能探测失败
  • 点数别吝啬:曲面至少 2~3 万点才够"密";但也不必上百万,渲染和求解都会变慢
  • 输出是点云:目前vsolve生成的是粒子点云(没有面片/边),追求实体感的场景请调小particleRadius并增加点数
  • 响应式友好vsolve生成的是标准 Generator,接入 Grafar 的响应式数据流后,改变方程参数即可动画化隐式曲面,可参考 examples/implicit_animation.html 与 examples/animated_levelset.html

小结

用 Grafar 画隐式图形只需三步:写出 f = 0 → 调用vsolve→ pin 到 panel。牛顿法的收敛细节、梯度差分、容差配置全部由库内部自动处理,你可以把精力集中在"想画什么方程"上,而不是"怎么采样"。

想继续深入,推荐阅读:

  • 完整教程:docs/tutorial/(从绘图基础到动画与交互)
  • API 参考:docs/api.md
  • 更多隐式示例:examples/implicit_intersection.html、examples/implicit_animation.html

【免费下载链接】grafarReactive multidimensional math & data visualization for the web.项目地址: https://gitcode.com/gh_mirrors/gr/grafar

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询