一条
n
n
n 次贝塞尔曲线可以表示为
C
(
u
)
=
∑
i
=
0
n
B
i
,
n
(
u
)
P
i
,
0
≤
u
≤
1
(1)
\pmb C(u)=\sum_{i=0}^nB_{i,n}(u)\pmb{P_i},\quad 0\leq u\leq1\tag{1}
C(u)=i=0∑nBi,n(u)Pi,0≤u≤1(1)
其中,基函数(也称为混合函数)
{
B
i
,
n
(
u
)
}
\{B_{i,n}(u)\}
{Bi,n(u)} 是著名的
n
n
n 次 Bernstein 多项式,其定义为
B
i
,
n
(
u
)
=
n
!
i
!
(
n
−
i
)
!
u
i
(
1
−
u
)
n
−
i
(2)
B_{i,n}(u)=\frac{n!}{i!(n-i)!}u^i(1-u)^{n-i}\tag{2}
Bi,n(u)=i!(n−i)!n!ui(1−u)n−i(2)
式(1)中的几何系数 { P i } \{\pmb P_i\} {Pi} 称为控制点。
例1. 当 n = 1 n=1 n=1 时,由(2)式有 B 0 , 1 ( u ) = 1 − u B_{0,1}(u)=1-u B0,1(u)=1−u 和 B 1 , 1 ( u ) = u B_{1,1}(u)=u B1,1(u)=u,由(1)式可得 C ( u ) = ( 1 − u ) P 0 + u P 1 \pmb C(u)=(1-u)\pmb P_0+u\pmb P_1 C(u)=(1−u)P0+uP1,这是一段由 P 0 \pmb P_0 P0 到 P 1 \pmb P_1 P1 的直线段。
例2. 当 n = 2 n=2 n=2 时,由(1)式和(2)式可得 C ( u ) = ( 1 − u ) 2 P 0 + 2 u ( 1 − u ) P 1 + u 2 P 2 \pmb C(u)=(1-u)^2\pmb P_0+2u(1-u)\pmb P_1+u^2\pmb P_2 C(u)=(1−u)2P0+2u(1−u)P1+u2P2,这是一段由 P 0 \pmb P_0 P0 到 P 1 \pmb P_1 P1 的抛物线弧。
例3. 当
n
=
3
n=3
n=3 时,我们有
C
(
u
)
=
(
1
−
u
)
3
P
0
+
3
u
(
1
−
u
)
2
P
1
+
3
u
2
(
1
−
u
)
P
2
+
u
3
P
3
\pmb C(u)=(1-u)^3\pmb P_0+3u(1-u)^2\pmb P_1+3u^2(1-u)\pmb P_2+u^3\pmb P_3
C(u)=(1−u)3P0+3u(1−u)2P1+3u2(1−u)P2+u3P3
我们注意到:
- 由 { P 0 , P 1 , P 2 , P 3 } \{\pmb P_0,\pmb P_1,\pmb P_2,\pmb P_3\} {P0,P1,P2,P3} 形成的多边形,称为控制多边形,很好地逼近了曲线的形状。
- 曲线在两个端点处的切方向分别平行于控制多边形的始末两条直线。
基函数 { B i , n ( u ) } \{B_{i,n}(u)\} {Bi,n(u)} 的一条重要性质(递推定义): B i , n ( u ) = ( 1 − u ) B i , n − 1 ( u ) + u B i − 1 , n − 1 ( u ) (3) B_{i,n}(u)=(1-u)B_{i,n-1}(u)+uB_{i-1,n-1}(u)\tag{3} Bi,n(u)=(1−u)Bi,n−1(u)+uBi−1,n−1(u)(3)这里我们规定当 i < 0 i<0 i<0 或 i > n i>n i>n 时, B i , n ≡ 0 B_{i,n}\equiv0 Bi,n≡0。
例4. 由(2)式可得
B
0
,
0
(
0
)
=
1
B_{0,0}(0)=1
B0,0(0)=1。由(3)式,一次和二次 Bernstein 多项式是
B
0
,
1
(
u
)
=
(
1
−
u
)
B
0
,
0
(
u
)
+
u
B
−
1
,
0
(
u
)
=
1
−
u
B
1
,
1
(
u
)
=
(
1
−
u
)
B
1
,
0
(
u
)
+
u
B
0
,
0
(
u
)
=
u
B
0
,
2
(
u
)
=
(
1
−
u
)
B
0
,
1
(
u
)
+
u
B
−
1
,
1
(
u
)
=
(
1
−
u
)
2
B
1
,
2
(
u
)
=
(
1
−
u
)
B
1
,
1
(
u
)
+
u
B
0
,
1
(
u
)
=
2
u
(
1
−
u
)
B
2
,
2
(
u
)
=
(
1
−
u
)
B
2
,
1
(
u
)
+
u
B
1
,
1
(
u
)
=
u
2
\begin{aligned} B_{0,1}(u)&=(1-u)B_{0,0}(u)+uB_{-1,0}(u)=1-u\\[2ex] B_{1,1}(u)&=(1-u)B_{1,0}(u)+uB_{0,0}(u)=u\\[2ex] B_{0,2}(u)&=(1-u)B_{0,1}(u)+uB_{-1,1}(u)=(1-u)^2\\[2ex] B_{1,2}(u)&=(1-u)B_{1,1}(u)+uB_{0,1}(u)=2u(1-u)\\[2ex] B_{2,2}(u)&=(1-u)B_{2,1}(u)+uB_{1,1}(u)=u^2\\ \end{aligned}
B0,1(u)B1,1(u)B0,2(u)B1,2(u)B2,2(u)=(1−u)B0,0(u)+uB−1,0(u)=1−u=(1−u)B1,0(u)+uB0,0(u)=u=(1−u)B0,1(u)+uB−1,1(u)=(1−u)2=(1−u)B1,1(u)+uB0,1(u)=2u(1−u)=(1−u)B2,1(u)+uB1,1(u)=u2
由式(3)可以得到当 u u u 固定时计算 Bernstein 多项式值的算法 AllBernstein()
def AllBernstein(n, u):
"""
计算所有 n+1 个 n 次 Bernstein 多项式在固定点 u 处的值
输入:n, u
输出:B
"""
B = np.zeros(n + 1)
B[0] = 1.0
for i in range(1, n + 1):
saved = 0.0
for j in range(i):
temp = B[j]
B[j] = saved + (1.0 - u) * temp
saved = u * temp
B[i] = saved
return B
综合利用式(1)和算法 AllBernstein() 可以计算对某个固定的 u u u , n n n 次贝塞尔曲线上的点。
def PointOnBezierCurve(P, n, u):
"""
计算对某个固定的 u,n 次贝塞尔曲线上的点
输入:P, n, u
输出:C (一个点)
"""
B = AllBernstein(n, u)
C = 0.0
for i in range(n + 1):
C = C + B[i] * P[i]
return C
用
C
n
(
P
0
,
⋯
,
P
n
)
\pmb C_n(\pmb P_0,\cdots,\pmb P_n)
Cn(P0,⋯,Pn) 表示由控制点
P
0
,
⋯
,
P
n
\pmb P_0,\cdots,\pmb P_n
P0,⋯,Pn 定义的
n
n
n 次贝塞尔曲线,我们有
C
n
(
P
0
,
⋯
,
P
n
)
=
(
1
−
u
)
C
n
−
1
(
P
0
,
⋯
,
P
n
−
1
)
+
u
C
n
−
1
(
P
1
,
⋯
,
P
n
)
(4)
\pmb C_n(\pmb P_0,\cdots,\pmb P_n)=(1-u)\pmb C_{n-1}(\pmb P_0,\cdots,\pmb P_{n-1})+u\pmb C_{n-1}(\pmb P_1,\cdots,\pmb P_n)\tag{4}
Cn(P0,⋯,Pn)=(1−u)Cn−1(P0,⋯,Pn−1)+uCn−1(P1,⋯,Pn)(4)
固定
u
=
u
0
u=u_0
u=u0,并且记
P
0
,
i
=
P
i
\pmb P_{0,i}=\pmb P_i
P0,i=Pi,由(4)式可以得到计算
n
n
n 次贝塞尔曲线上的点
C
(
u
0
)
=
P
n
,
0
(
u
0
)
\pmb C(u_0)=P_{n,0}(u_0)
C(u0)=Pn,0(u0) 的一个递推算法,即
P
k
,
i
(
u
0
)
=
(
1
−
u
0
)
P
k
−
1
,
i
(
u
0
)
+
u
0
P
k
−
1
,
i
+
1
(
u
0
)
,
i
=
0
,
1
,
⋯
,
n
−
k
;
k
=
1
,
2
,
⋯
,
n
(5)
\pmb P_{k,i}(u_0)=(1-u_0)\pmb P_{k-1,i}(u_0)+u_0\pmb P_{k-1,i+1}(u_0),\quad i=0,1,\cdots,n-k;k=1,2,\cdots,n\tag{5}
Pk,i(u0)=(1−u0)Pk−1,i(u0)+u0Pk−1,i+1(u0),i=0,1,⋯,n−k;k=1,2,⋯,n(5)
式(5)称为 deCasteljau 算法
def deCasteljau(P, n, u):
"""
利用 deCasteljau 算法计算贝塞尔曲线上的点
输入:P, n, u
输出:C(一个点)
"""
Q = P.copy()
for i in range(1, n + 1):
for j in range(n - i + 1):
Q[j] = (1.0 - u) * Q[j] + u * Q[j + 1]
return Q[0]
贝塞尔曲线求导的一般公式
C
′
(
u
)
=
d
(
∑
i
=
0
n
B
i
,
n
(
u
)
P
i
)
d
u
=
∑
i
=
0
n
B
i
,
n
′
(
u
)
P
i
=
∑
i
=
0
n
n
(
B
i
−
1
,
n
−
1
(
u
)
−
B
i
,
n
−
1
(
u
)
P
i
)
=
n
∑
i
=
0
n
−
1
B
i
,
n
−
1
(
u
)
(
P
i
+
1
−
P
i
)
(6)
\begin{aligned} \pmb C^\prime(u)&=\frac{\mathrm{d}\Big(\sum_{i=0}^nB_{i,n}(u)\pmb P_i\Big)}{\mathrm{d}u}=\sum_{i=0}^nB^\prime_{i,n}(u)\pmb P_i\\[2ex] &=\sum_{i=0}^nn\Big(B_{i-1,n-1}(u)-B_{i,n-1}(u)\pmb P_i\Big)\\[2ex] &=n\sum_{i=0}^{n-1}B_{i,n-1}(u)\big(\pmb P_{i+1}-\pmb P_i\big) \end{aligned}\tag{6}
C′(u)=dud(∑i=0nBi,n(u)Pi)=i=0∑nBi,n′(u)Pi=i=0∑nn(Bi−1,n−1(u)−Bi,n−1(u)Pi)=ni=0∑n−1Bi,n−1(u)(Pi+1−Pi)(6)
由(6)式容易得到贝塞尔曲线在两个端点处导矢的公式
C
′
(
0
)
=
n
(
P
1
−
P
0
)
C
′
′
(
0
)
=
n
(
n
−
1
)
(
P
2
−
2
P
1
+
P
0
)
C
′
(
1
)
=
n
(
P
n
−
P
n
−
1
)
C
′
′
(
1
)
=
n
(
n
−
1
)
(
P
n
−
2
P
n
−
1
+
P
n
−
2
)
\begin{aligned} &\pmb C^\prime(0)=n\big(\pmb P_1-\pmb P_0\big)\quad\pmb C^{\prime\prime}(0)=n(n-1)\big(\pmb P_2-2\pmb P_1+\pmb P_0\big)\\[2ex] &\pmb C^\prime(1)=n\big(\pmb P_n-\pmb P_{n-1}\big)\quad\pmb C^{\prime\prime}(1)=n(n-1)\big(\pmb P_n-2\pmb P_{n-1}+\pmb P_{n-2}\big) \end{aligned}
C′(0)=n(P1−P0)C′′(0)=n(n−1)(P2−2P1+P0)C′(1)=n(Pn−Pn−1)C′′(1)=n(n−1)(Pn−2Pn−1+Pn−2)