贝塞尔曲线 (Bézier Curve)
贝塞尔曲线是一种由控制点定义的参数多项式曲线,由 Pierre Bézier 与 Paul de Casteljau 在 20 世纪 60 年代分别提出。它不要求曲线经过所有控制点,而是通过控制点“拉动”曲线形状,因此适合描述平滑轮廓和路径。
定义
一条 n 次贝塞尔曲线由 n+1 个控制点 $P_0, P_1, \dots, P_n$ 定义,参数 $t$ 在 $[0, 1]$ 上变化:
$$B(t) = \sum_{i=0}^{n} \binom{n}{i} (1-t)^{n-i} t^i P_i$$
其中 $\binom{n}{i}$ 是二项式系数。$t=0$ 时曲线位于 $P_0$,$t=1$ 时位于 $P_n$;中间控制点一般不在曲线上。
低阶形式
- 一次(线段):$B(t) = (1-t)P_0 + tP_1$
- 二次:$B(t) = (1-t)^2 P_0 + 2(1-t)t P_1 + t^2 P_2$
- 三次:$B(t) = (1-t)^3 P_0 + 3(1-t)^2 t P_1 + 3(1-t)t^2 P_2 + t^3 P_3$
de Casteljau 算法
反复对相邻控制点做线性插值,可以得到曲线上任意一点。对于控制点 $P_0 \dots P_n$:
for k = 1 to n:
for i = 0 to n - k:
P_i = (1 - t) * P_i + t * P_{i+1}最终剩下的点就是 $B(t)$。该算法数值稳定,也常用于把曲线细分折线化。
性质
- 端点性质:曲线起点为 $P_0$,终点为 $P_n$。
- 切向:起点处切向指向 $P_1 - P_0$,终点处切向指向 $P_n - P_{n-1}$。
- 凸包性质:整条曲线位于所有控制点的凸包内。
- 仿射不变性:对控制点做仿射变换,等价于对曲线本身做同一变换。
- 次数:n 次曲线需要 n+1 个控制点;多段曲线拼接时可利用连续性约束。
在 Canvas 中的使用
Canvas 2D 提供二次与三次贝塞尔曲线绘制 API:
quadraticCurveTo(cpx, cpy, x, y)bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
示例:
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(20, 120);
ctx.bezierCurveTo(80, 20, 200, 220, 280, 120);
ctx.stroke();也可以先构造 Path2D,再交给 Canvas 绘制。详见 Canvas 绘图。
在 SVG 中的使用
SVG path 用命令描述贝塞尔曲线:
Q x1 y1, x y:二次贝塞尔曲线T x y:平滑二次贝塞尔曲线C x1 y1, x2 y2, x y:三次贝塞尔曲线S x2 y2, x y:平滑三次贝塞尔曲线
字体轮廓(TrueType 使用二次曲线,PostScript / OpenType 使用三次曲线)、SVG、Canvas 和矢量绘图工具都建立在贝塞尔曲线之上。相关笔记:矢量图。
应用
- 字体与图形轮廓。
- SVG path 与 Canvas path。
- 动画缓动曲线(easing curve)。
- 路径规划与轨迹插值。
参考资料
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Algorithms