对Bezier曲线的一些理解

本文介绍了Bezier曲线的几个核心问题!

普通Bezier曲线

普通 nn 次Bezier曲线定义为:

C(t)=i=0nBi,n(t)PiC(t)=\sum_{i=0}^{n} B_{i,n}(t)P_i

其中 Bernstein 基函数为:

Bi,n(t)=(ni)(1t)nitiB_{i,n}(t)=\binom{n}{i}(1-t)^{n-i}t^i

并且:

i=0nBi,n(t)=1\sum_{i=0}^{n}B_{i,n}(t)=1

所以普通Bezier曲线可以理解为: 在每个参数 tt 处,对所有控制点 PiP_i 做一次加权平均

有理Bezier曲线

有理Bezier曲线在每个控制点前增加了权重 wiw_i

C(t)=i=0nwiBi,n(t)Pii=0nwiBi,n(t)C(t)= \frac{ \sum_{i=0}^{n} w_i B_{i,n}(t)P_i }{ \sum_{i=0}^{n} w_i B_{i,n}(t) }

也可以写成:

C(t)=i=0nRi,n(t)PiC(t)=\sum_{i=0}^{n} R_{i,n}(t)P_i

其中:

Ri,n(t)=wiBi,n(t)j=0nwjBj,n(t)R_{i,n}(t)= \frac{ w_i B_{i,n}(t) }{ \sum_{j=0}^{n} w_j B_{j,n}(t) }

这里的 Ri,n(t)R_{i,n}(t) 叫做有理基函数

因此,权重并不是简单地把控制点坐标放大,而是改变控制点在加权平均中的比例。

权重的作用

在有理Bezier曲线中,控制点的权重 wiw_i 表示该控制点对曲线的吸引力强弱

  • wi>1w_i > 1:曲线更靠近控制点 PiP_i
  • wi=1w_i = 1:等同于普通Bezier曲线
  • 0<wi<10 < w_i < 1:曲线远离控制点 PiP_i
  • wi=0w_i = 0:该控制点基本失去影响
  • wi<0w_i < 0:数学上可以存在,但几何行为不直观,工程中通常避免

普通Bezier曲线不能精确表示圆、椭圆、双曲线等圆锥曲线,只能近似。

有理Bezier曲线通过权重可以精确表示这些曲线。

例如,用二次有理Bezier曲线表示一段圆弧时,中间控制点权重常取:

w=cosθ2w=\cos\frac{\theta}{2}

其中 θ\theta 是圆弧对应的圆心角。

例如 9090^\circ 圆弧:

w=cos45=220.7071w=\cos45^\circ=\frac{\sqrt{2}}{2}\approx0.7071

这就是 CAD、NURBS、OpenCASCADE 等几何系统大量使用有理曲线的原因。

二次有理Bezier曲线例子

对于三个控制点:

P0, P1, P2P_0,\ P_1,\ P_2

二次有理Bezier曲线为:

C(t)=(1t)2w0P0+2t(1t)w1P1+t2w2P2(1t)2w0+2t(1t)w1+t2w2C(t)= \frac{ (1-t)^2w_0P_0 + 2t(1-t)w_1P_1 + t^2w_2P_2 }{ (1-t)^2w_0 + 2t(1-t)w_1 + t^2w_2 }

通常令两端权重为:

w0=1,w2=1w_0 = 1,\quad w_2 = 1

只调节中间控制点的权重:

w1=ww_1 = w

则:

C(t)=(1t)2P0+2wt(1t)P1+t2P2(1t)2+2wt(1t)+t2C(t)= \frac{ (1-t)^2P_0 + 2wt(1-t)P_1 + t^2P_2 }{ (1-t)^2 + 2wt(1-t) + t^2 }

t=0.5t=0.5 时:

C(0.5)=0.25P0+0.5wP1+0.25P20.5+0.5wC(0.5)= \frac{ 0.25P_0+0.5wP_1+0.25P_2 }{ 0.5+0.5w }

可以看到,ww 越大,中间控制点 P1P_1 的影响越大,曲线越靠近 P1P_1

齐次坐标

有理Bezier曲线还可以理解为: 先在高一维空间中做普通Bezier曲线,然后再投影回来。

对于二维控制点:

Pi=(xi,yi)P_i=(x_i,y_i)

引入齐次坐标:

Pih=(wixi, wiyi, wi)P_i^h=(w_ix_i,\ w_iy_i,\ w_i)

在三维中计算普通Bezier曲线:

Q(t)=i=0nBi,n(t)PihQ(t)=\sum_{i=0}^{n}B_{i,n}(t)P_i^h

得到:

Q(t)=(X(t),Y(t),W(t))Q(t)=(X(t),Y(t),W(t))

然后投影回二维:

C(t)=(X(t)W(t),Y(t)W(t))C(t)= \left( \frac{X(t)}{W(t)}, \frac{Y(t)}{W(t)} \right)

这正是有理Bezier曲线公式中“分子除以分母”的来源。

当w1=0.707时,曲线为什么是精确1/4圆弧

前提

w1=0.707122w_1=0.7071\approx \frac{\sqrt{2}}{2} 时,二次有理Bezier曲线是精确 1/41/4 圆弧,前提是控制点取成圆弧端点及其切线交点,例如单位圆第一象限:

P0=(1,0),P1=(1,1),P2=(0,1)P_0=(1,0),\quad P_1=(1,1),\quad P_2=(0,1)

权重为:

w0=1,w1=22,w2=1w_0=1,\quad w_1=\frac{\sqrt{2}}{2},\quad w_2=1

此时曲线就是单位圆

x2+y2=1x^2+y^2=1

上的第一象限圆弧。

二次有理Bezier曲线公式

C(t)=(1t)2P0+2wt(1t)P1+t2P2(1t)2+2wt(1t)+t2C(t)= \frac{ (1-t)^2P_0 + 2wt(1-t)P_1 + t^2P_2 }{ (1-t)^2 + 2wt(1-t) + t^2 }

证明

令:

a=(1t)2b=2wt(1t)c=t2a=(1-t)^2\\ b=2wt(1-t)\\ c=t^2

带入点坐标,则曲线点为:

C(t)=a(1,0)+b(1,1)+c(0,1)D=(a+bD,b+cD)C(t)= \frac{ a(1,0)+b(1,1)+c(0,1) }{ D }= \left( \frac{a+b}{D}, \frac{b+c}{D} \right)

也就是:

x(t)=a+bDy(t)=b+cDx(t)=\frac{a+b}{D},y(t)=\frac{b+c}{D}

我们要证明它在单位圆上,即:

x(t)2+y(t)2=1x2+y2=(a+bD)2+(b+cD)2=(a+b)2+(b+c)2D2x(t)^2+y(t)^2=1\\ x^2+y^2 = \left(\frac{a+b}{D}\right)^2 + \left(\frac{b+c}{D}\right)^2= \frac{(a+b)^2+(b+c)^2}{D^2}

因此只需要证明:

(a+b)2+(b+c)2=D2(a+b)^2+(b+c)^2=D^2

右式=D2=(a+b+c)2=a2+b2+c2+2ab+2ac+2bc左式=(a+b)2+(b+c)2=a2+2ab+b2+b2+2bc+c2右式=D^2=(a+b+c)^2=a^2+b^2+c^2+2ab+2ac+2bc\\ 左式=(a+b)^2+(b+c)^2=a^2+2ab+b^2+b^2+2bc+c^2

两者相等的条件是:

a2+b2+c2+2ab+2ac+2bc=a2+c2+2ab+2bc+2b2b2+2ac=2b2证明:2ac=b2a^2+b^2+c^2+2ab+2ac+2bc = a^2+c^2+2ab+2bc+2b^2\\ b^2+2ac=2b^2\\ 证明:2ac=b^2

前面定义:

a=(1t)2b=2wt(1t)c=t2a=(1-t)^2\\ b=2wt(1-t)\\ c=t^2

所以:

2ac=2(1t)2t22ac=2(1-t)^2t^2

而:

b2=(2wt(1t))2=4w2t2(1t)2b^2=\left(2wt(1-t)\right)^2=4w^2t^2(1-t)^2

要求:

2ac=b22ac=b^2

即:

2t2(1t)2=4w2t2(1t)2w2=12w=220.70712t^2(1-t)^2 = 4w^2t^2(1-t)^2\\ w^2=\frac{1}{2}\\ w=\frac{\sqrt{2}}{2}\approx 0.7071

更一般结论

对于一段圆心角为 θ\theta 的圆弧,二次有理Bezier曲线可以精确表示它。

如果:

  • P0P_0P2P_2 是圆弧两端点
  • P1P_1 是两端点切线的交点
  • w0=1w_0=1
  • w2=1w_2=1

那么中间控制点权重应取:

w1=cosθ2w_1=\cos\frac{\theta}{2}

最大可以表示多大弧度的圆弧

一段二次有理Bezier曲线精确表示圆弧时,通常最大表示:

θ<180\boxed{\theta < 180^\circ}

也就是:

θ<π\boxed{\theta < \pi}

工程上一般不用一段表示正好 180180^\circ,而是把圆弧拆成多段。

为什么要求小于180°

二次有理Bezier圆弧的中间权重为:

w1=cosθ2w_1=\cos\frac{\theta}{2}

其中 θ\theta 是圆弧对应的圆心角。

当:

0<θ<1800 < \theta < 180^\circ

有:

0<θ2<900 < \frac{\theta}{2} < 90^\circ

所以:

cosθ2>0\cos\frac{\theta}{2} > 0

权重是正数,曲线行为稳定、直观。


等于180°

如果是半圆:

θ=180w1=cos90=0w1=0\theta=180^\circ\\ w_1=\cos90^\circ=0\\ w_1=0

这时中间控制点的权重为零。

从几何上看,半圆两端点的切线是平行的,不会相交于有限点,因此中间控制点 P1P_1 会跑到无穷远。

所以一段普通有限控制点的二次有理Bezier曲线不能稳定表示半圆


大于180°

如果圆弧超过半圆:

θ>180θ2>90w1=cosθ2<0\theta > 180^\circ\\ \frac{\theta}{2} > 90^\circ\\ w_1=\cos\frac{\theta}{2}<0

中间权重变成负数。

负权重在数学上可以讨论,但在 CAD/NURBS 建模中通常不推荐:

  • 曲线可能出现不直观的形状
  • 参数化可能不稳定
  • 分母可能接近或经过零
  • 几何解释变差
  • 许多几何内核更偏好正权重

因此工程中通常不使用一段二次有理Bezier表示超过 180180^\circ 的圆弧。

结论

一段二次有理Bezier曲线精确表示圆弧时:

w1=cosθ2w_1=\cos\frac{\theta}{2}

因此:

  • 0<θ<1800^\circ < \theta < 180^\circ:权重为正,可稳定表示
  • θ=180\theta = 180^\circ:权重为 00,控制点在无穷远,工程中不用
  • θ>180\theta > 180^\circ:权重为负,通常不推荐

所以通常说:

一段二次有理贝塞尔曲线最大稳定表示小于 180 的圆弧\boxed{\text{一段二次有理贝塞尔曲线最大稳定表示小于 }180^\circ\text{ 的圆弧}}

实际工程中更推荐:

90 一段,整圆拆成 4 段\boxed{90^\circ\text{ 一段,整圆拆成 4 段}}

Bezier曲线的计算

理论公式的局限性

普通Bezier曲线理论公式是:

C(t)=i=0nBi,n(t)PiC(t)=\sum_{i=0}^{n}B_{i,n}(t)P_i

其中:

Bi,n(t)=(ni)(1t)nitiB_{i,n}(t)=\binom{n}{i}(1-t)^{n-i}t^i

这个公式当然可以直接计算,特别是阶数较低时,比如二次、三次Bezier曲线。

例如三次Bezier:

C(t)=(1t)3P0+3(1t)2tP1+3(1t)t2P2+t3P3C(t)=(1-t)^3P_0+3(1-t)^2tP_1+3(1-t)t^2P_2+t^3P_3

但在实际计算中,直接公式有几个问题:

  • 需要计算组合数
  • 需要计算多次幂
  • 高阶时数值误差更明显
  • 阶数变化时实现不够统一
  • 不方便做曲线分割、细分、求点构造

所以 CAD、图形学、字体、曲线编辑器中,通常更喜欢 de Casteljau 算法。

de Casteljau 算法

de Casteljau 算法的核心思想是:不断对相邻控制点做线性插值,最后得到曲线上的点。

两个点 AABB 之间按参数 tt 插值:

L(A,B,t)=(1t)A+tBL(A,B,t)=(1-t)A+tB

对于三次Bezier,控制点为:

P0,P1,P2,P3P_0,P_1,P_2,P_3

第一层插值:

P01=(1t)P0+tP1P_{0}^{1}=(1-t)P_0+tP_1

P11=(1t)P1+tP2P_{1}^{1}=(1-t)P_1+tP_2

P21=(1t)P2+tP3P_{2}^{1}=(1-t)P_2+tP_3

第二层插值:

P02=(1t)P01+tP11P_{0}^{2}=(1-t)P_{0}^{1}+tP_{1}^{1}

P12=(1t)P11+tP21P_{1}^{2}=(1-t)P_{1}^{1}+tP_{2}^{1}

第三层插值:

P03=(1t)P02+tP12P_{0}^{3}=(1-t)P_{0}^{2}+tP_{1}^{2}

最后:

C(t)=P03C(t)=P_{0}^{3}

这和理论 Bernstein 公式是等价的,但数值稳定性更好。

二次Bezier的直观例子

二次Bezier有三个控制点:

P0,P1,P2P_0,P_1,P_2

先插值:

Q0=(1t)P0+tP1Q_0=(1-t)P_0+tP_1

Q1=(1t)P1+tP2Q_1=(1-t)P_1+tP_2

再插值:

C(t)=(1t)Q0+tQ1C(t)=(1-t)Q_0+tQ_1

这就是曲线上的点。

展开后会得到:

C(t)=(1t)2P0+2(1t)tP1+t2P2C(t)=(1-t)^2P_0+2(1-t)tP_1+t^2P_2

所以 de Casteljau 算法不是近似,而是和公式完全等价。

有理Bezier怎么计算

有理Bezier曲线通常有两种实际计算方式。

方式一:直接用有理公式

有理Bezier曲线为:

C(t)=i=0nwiBi,n(t)Pii=0nwiBi,n(t)C(t)= \frac{ \sum_{i=0}^{n} w_iB_{i,n}(t)P_i }{ \sum_{i=0}^{n} w_iB_{i,n}(t) }

低阶曲线时直接算很方便。

例如二次有理Bezier:

C(t)=(1t)2w0P0+2t(1t)w1P1+t2w2P2(1t)2w0+2t(1t)w1+t2w2C(t)= \frac{ (1-t)^2w_0P_0+2t(1-t)w_1P_1+t^2w_2P_2 }{ (1-t)^2w_0+2t(1-t)w_1+t^2w_2 }

如果你的程序只是计算二次或三次曲线上的点,这种方法完全可以接受。

方式二:用齐次坐标 + de Casteljau

工程中更统一的方式是使用齐次坐标。

二维点:

Pi=(xi,yi)P_i=(x_i,y_i)

转换为三维齐次点:

Pih=(wixi,wiyi,wi)P_i^h=(w_ix_i,w_iy_i,w_i)

然后对这些齐次点使用普通 de Casteljau 算法,得到:

Q(t)=(X(t),Y(t),W(t))Q(t)=(X(t),Y(t),W(t))

最后投影回二维:

C(t)=(X(t)W(t),Y(t)W(t))C(t)= \left( \frac{X(t)}{W(t)}, \frac{Y(t)}{W(t)} \right)

三维点也是类似:

Pi=(xi,yi,zi)P_i=(x_i,y_i,z_i)

转换为四维齐次点:

Pih=(wixi,wiyi,wizi,wi)P_i^h=(w_ix_i,w_iy_i,w_iz_i,w_i)

计算后再投影:

C(t)=(X(t)W(t),Y(t)W(t),Z(t)W(t))C(t)= \left( \frac{X(t)}{W(t)}, \frac{Y(t)}{W(t)}, \frac{Z(t)}{W(t)} \right)

这种方法的优点是:

  • 普通Bezier和有理Bezier处理方式统一
  • 数值稳定
  • 适合任意阶数
  • 方便做曲线分割
  • 和 NURBS/CAD 内核的思想一致

实际工程的做法

低阶曲线,比如二次、三次

可以直接用公式:

C(t)=wiBi(t)PiwiBi(t)C(t)= \frac{ \sum w_iB_i(t)P_i }{ \sum w_iB_i(t) }

优点:

  • 代码短
  • 性能好
  • 容易调试
  • 对二次、三次足够稳定

任意阶曲线

更推荐 de Casteljau 或其变体,原因:

  • 不需要手写不同阶数公式
  • 更适合动态控制点数量
  • 细分曲线非常方便
  • 数值稳定性更好
  • 更符合几何算法实现习惯

(转载本站文章请注明作者和出处lihaohello.top,请勿用于任何商业用途)