如何画一条隐式曲线、一面隐式曲面: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 中,逻辑非常精炼:
- 计算当前值
val = f(pt)和梯度gradf - 用
-val / |∇f|²做后验误差估计,得到移动步长 - 沿梯度方向移动:
pt += posterr * nabla - 若偏移量小于容差
tol(默认 0.001,配置于 src/config.ts),判定收敛并返回 - 超过最大迭代次数(默认 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),仅供参考