众所周知,B样条曲线的通用表达式为:
C
(
u
)
=
∑
i
=
0
n
N
i
,
p
(
u
)
Q
i
C(u)=\sum_{i=0}^n N_{i,p}(u)Q_i
C(u)=i=0∑nNi,p(u)Qi
其中
N
i
,
p
(
u
)
N_{i,p}(u)
Ni,p(u)为基函数,
Q
i
Q_i
Qi为控制点。且基函数由下式递推算出:
在实际使用中,如果已知所有的控制点
Q
i
Q_i
Qi,我们希望求出参数u处的B样条值来。这种给定参数u,计算参数曲线上对应点的运算称为求值(Evaluate)操作。为了方便后续讨论,我们这里设B样条曲线有n+1个控制点,阶数为p。
由B样条曲线的表达式可以看出来,最简单的Evaluate方法就是先由
N
0
,
0
,
⋯
,
N
n
+
p
,
0
N_{0,0},\cdots,N_{n+p,0}
N0,0,⋯,Nn+p,0递推地求出基函数
N
0
,
p
,
⋯
,
N
n
,
p
N_{0,p},\cdots,N_{n,p}
N0,p,⋯,Nn,p,然后再用公式
C
(
u
j
)
=
∑
i
=
0
n
N
i
,
p
(
u
)
Q
i
C(u_j)=\sum_{i=0}^n N_{i,p}(u)Q_i
C(uj)=∑i=0nNi,p(u)Qi把
C
(
u
)
C(u)
C(u)的值算出来,这个计算过程可以用下图理解,计算复杂度为O(n*(n+n+1))=O(np)。程序可以参考B样条值的公式计算方法。
由公式直接算值虽然简单直观,但是程序复杂度太高,所以有人又提出了一种更快速的Evaluate方法-deboor计算方法。推导过程如下((假设我们已经提前找到了要求的参数
u
∈
[
u
j
,
u
j
+
1
u\in[u_j,u_{j+1}
u∈[uj,uj+1):
C
(
u
)
=
∑
i
=
0
n
N
i
,
p
(
u
)
Q
i
=
∑
i
=
j
−
p
j
N
i
,
p
(
u
)
Q
i
=
∑
i
=
j
−
p
j
(
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
+
u
i
+
p
+
1
−
u
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
)
Q
i
=
∑
i
=
j
−
p
j
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
+
∑
i
=
j
−
p
j
u
i
+
p
+
1
−
u
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
Q
i
=
∑
i
=
j
−
p
+
1
j
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
+
u
−
u
j
−
p
u
j
−
p
+
p
−
u
j
−
p
N
j
−
p
,
p
−
1
(
u
)
Q
j
+
∑
i
=
j
−
p
+
1
j
u
i
+
p
−
u
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
−
1
+
u
j
+
p
+
1
−
u
u
j
+
p
+
1
−
u
j
+
1
N
j
+
1
,
p
−
1
(
u
)
Q
j
=
∑
i
=
j
−
p
+
1
j
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
+
∑
i
=
j
−
p
+
1
j
u
i
+
p
−
u
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
−
1
(
因为
N
j
−
p
,
p
−
1
(
u
)
只在
[
u
j
−
p
,
u
j
−
p
+
p
−
1
+
1
)
不为
0
,
N
j
+
1
,
p
−
1
(
u
)
只在
[
u
j
+
1
,
u
j
+
1
+
p
−
1
+
1
)
不为
0
,而
u
j
∈
[
u
j
,
u
j
+
1
)
)
=
∑
i
=
j
−
p
+
1
j
N
i
,
p
−
1
(
u
)
(
u
−
u
i
u
i
+
p
−
u
i
Q
i
+
u
i
+
p
−
u
u
i
+
p
−
u
i
Q
i
−
1
)
\begin{equation}\nonumber \begin{split} C(u)&=\sum_{i=0}^n N_{i,p}(u)Q_i \\ &=\sum_{i=j-p}^{j} N_{i,p}(u)Q_i \\ &= \sum_{i=j-p}^{j} (\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)+\frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u))Q_i \\ &= \sum_{i=j-p}^{j}\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)Q_i + \sum_{i=j-p}^{j}\frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u)Q_i \\ &= \sum_{i=j-p+1}^{j}\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)Q_i + \frac{u-u_{j-p}}{u_{j-p+p}-u_{j-p}}N_{j-p,p-1}(u)Q_j \\ &+ \sum_{i=j-p+1}^{j}\frac{u_{i+p}-u}{u_{i+p}-u_{i}}N_{i,p-1}(u)Q_{i-1} + \frac{u_{j+p+1}-u}{u_{j+p+1}-u_{j+1}}N_{j+1,p-1}(u)Q_j \\ &= \sum_{i=j-p+1}^{j}\frac{u-u_i}{u_{i+p}-u_i}N_{i,p-1}(u)Q_i + \sum_{i=j-p+1}^{j}\frac{u_{i+p}-u}{u_{i+p}-u_{i}}N_{i,p-1}(u)Q_{i-1}\\ &(因为N_{j-p,p-1}(u)只在[u_{j-p},u_{j-p+p-1+1})不为0,\\ &N_{j+1,p-1}(u)只在[u_{j+1},u_{j+1+p-1+1})不为0,而u_j\in[u_j,u_{j+1})) \\ &=\sum_{i=j-p+1}^{j} N_{i,p-1}(u)(\frac{u-u_i}{u_{i+p}-u_i}Q_i + \frac{u_{i+p}-u}{u_{i+p}-u_{i}}Q_{i-1}) \end{split} \end{equation}
C(u)=i=0∑nNi,p(u)Qi=i=j−p∑jNi,p(u)Qi=i=j−p∑j(ui+p−uiu−uiNi,p−1(u)+ui+p+1−ui+1ui+p+1−uNi+1,p−1(u))Qi=i=j−p∑jui+p−uiu−uiNi,p−1(u)Qi+i=j−p∑jui+p+1−ui+1ui+p+1−uNi+1,p−1(u)Qi=i=j−p+1∑jui+p−uiu−uiNi,p−1(u)Qi+uj−p+p−uj−pu−uj−pNj−p,p−1(u)Qj+i=j−p+1∑jui+p−uiui+p−uNi,p−1(u)Qi−1+uj+p+1−uj+1uj+p+1−uNj+1,p−1(u)Qj=i=j−p+1∑jui+p−uiu−uiNi,p−1(u)Qi+i=j−p+1∑jui+p−uiui+p−uNi,p−1(u)Qi−1(因为Nj−p,p−1(u)只在[uj−p,uj−p+p−1+1)不为0,Nj+1,p−1(u)只在[uj+1,uj+1+p−1+1)不为0,而uj∈[uj,uj+1))=i=j−p+1∑jNi,p−1(u)(ui+p−uiu−uiQi+ui+p−uiui+p−uQi−1)
令:
Q
i
,
k
(
u
)
=
{
Q
i
k
=
0
u
−
u
i
u
i
+
p
+
1
−
k
−
u
i
Q
i
,
k
−
1
(
u
)
+
u
i
+
p
+
1
−
k
−
u
u
i
+
p
+
1
−
k
−
u
i
Q
i
−
1
,
k
−
1
(
u
)
k
=
1
,
⋯
,
p
\begin{equation}\nonumber Q_{i,k}(u)=\left\{ \begin{aligned} & Q_i \ \ &k=0 \\ & \frac{u-u_i}{u_{i+p+1-k}-u_i}Q_{i,k-1}(u) + \frac{u_{i+p+1-k}-u}{u_{i+p+1-k}-u_{i}}Q_{i-1,k-1}(u) \ \ &k=1,\cdots,p \\ \end{aligned} \right. \end{equation}
Qi,k(u)=⎩
⎨
⎧Qi ui+p+1−k−uiu−uiQi,k−1(u)+ui+p+1−k−uiui+p+1−k−uQi−1,k−1(u) k=0k=1,⋯,p
则上式可以写为:
C
(
u
)
=
∑
i
=
j
−
p
+
1
j
N
i
,
p
−
1
(
u
)
Q
i
,
1
(
u
)
=
∑
i
=
j
−
p
+
1
j
(
u
−
u
i
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
+
u
i
+
p
−
u
u
i
+
p
−
u
i
+
1
N
i
+
1
,
p
−
2
(
u
)
)
Q
i
,
1
(
u
)
=
∑
i
=
j
−
p
+
1
j
u
−
u
i
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
Q
i
,
1
(
u
)
+
∑
i
=
j
−
p
+
1
j
u
i
+
p
−
u
u
i
+
p
−
u
i
+
1
N
i
+
1
,
p
−
2
(
u
)
)
Q
i
,
1
(
u
)
=
∑
i
=
j
−
p
+
2
j
u
−
u
i
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
Q
i
,
1
(
u
)
+
u
−
u
j
−
p
+
1
u
j
−
p
+
1
+
p
−
1
−
u
j
−
p
+
1
N
j
−
p
+
1
,
p
−
2
(
u
)
Q
j
−
p
+
1
,
1
(
u
)
+
∑
i
=
j
−
p
+
2
j
u
i
+
p
−
1
−
u
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
Q
i
−
1
,
1
(
u
)
+
u
j
+
p
−
u
u
j
+
p
−
u
j
+
1
N
j
+
1
,
p
−
2
(
u
)
Q
j
,
1
(
u
)
=
∑
i
=
j
−
p
+
2
j
u
−
u
i
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
Q
i
,
1
(
u
)
+
∑
i
=
j
−
p
+
2
j
u
i
+
p
−
1
−
u
u
i
+
p
−
1
−
u
i
N
i
,
p
−
2
(
u
)
Q
i
−
1
,
1
(
u
)
(
因为
N
j
−
p
+
1
,
p
−
2
(
u
)
只在
[
u
j
−
p
+
1
,
u
j
−
p
+
1
+
p
−
2
+
1
)
不为
0
,
N
j
+
1
,
p
−
2
(
u
)
只在
[
u
j
+
1
,
u
j
+
1
+
p
−
2
+
1
)
不为
0
,而
u
j
∈
[
u
j
,
u
j
+
1
)
)
=
∑
i
=
j
−
p
+
2
j
N
i
,
p
−
2
(
u
)
(
u
−
u
i
u
i
+
p
−
1
−
u
i
Q
i
,
1
(
u
)
+
u
i
+
p
−
1
−
u
u
i
+
p
−
1
−
u
i
Q
i
−
1
,
1
(
u
)
)
=
∑
i
=
j
−
p
+
2
j
N
i
,
p
−
2
(
u
)
Q
i
,
2
(
u
)
=
⋯
=
∑
i
=
j
−
p
+
k
j
N
i
,
p
−
k
(
u
)
Q
i
,
k
(
u
)
=
⋯
=
∑
i
=
j
−
p
+
p
j
N
i
,
p
−
p
(
u
)
Q
i
,
p
(
u
)
=
N
j
,
0
(
u
)
Q
j
,
p
(
u
)
=
Q
j
,
p
(
u
)
\begin{equation}\nonumber \begin{split} C(u) &= \sum_{i=j-p+1}^{j} N_{i,p-1}(u)Q_{i,1}(u) \\ &= \sum_{i=j-p+1}^{j} (\frac{u-u_i}{u_{i+p-1}-u_i}N_{i,p-2}(u)+\frac{u_{i+p}-u}{u_{i+p}-u_{i+1}}N_{i+1,p-2}(u))Q_{i,1}(u) \\ &= \sum_{i=j-p+1}^{j} \frac{u-u_i}{u_{i+p-1}-u_i}N_{i,p-2}(u)Q_{i,1}(u) + \sum_{i=j-p+1}^{j}\frac{u_{i+p}-u}{u_{i+p}-u_{i+1}}N_{i+1,p-2}(u))Q_{i,1}(u) \\ &= \sum_{i=j-p+2}^{j}\frac{u-u_i}{u_{i+p-1}-u_i}N_{i,p-2}(u)Q_{i,1}(u) \\ &+ \frac{u-u_{j-p+1}}{u_{j-p+1+p-1}-u_{j-p+1}}N_{j-p+1,p-2}(u)Q_{j-p+1,1}(u) \\ &+ \sum_{i=j-p+2}^{j}\frac{u_{i+p-1}-u}{u_{i+p-1}-u_{i}}N_{i,p-2}(u)Q_{i-1,1}(u)\\ &+ \frac{u_{j+p}-u}{u_{j+p}-u_{j+1}}N_{j+1,p-2}(u)Q_{j,1}(u) \\ &= \sum_{i=j-p+2}^{j}\frac{u-u_i}{u_{i+p-1}-u_i}N_{i,p-2}(u)Q_{i,1}(u) \\ &+ \sum_{i=j-p+2}^{j}\frac{u_{i+p-1}-u}{u_{i+p-1}-u_{i}}N_{i,p-2}(u)Q_{i-1,1}(u)\\ &(因为N_{j-p+1,p-2}(u)只在[u_{j-p+1},u_{j-p+1+p-2+1})不为0,\\ &N_{j+1,p-2}(u)只在[u_{j+1},u_{j+1+p-2+1})不为0,而u_j\in[u_j,u_{j+1})) \\ &=\sum_{i=j-p+2}^{j} N_{i,p-2}(u)(\frac{u-u_i}{u_{i+p-1}-u_i}Q_{i,1}(u) + \frac{u_{i+p-1}-u}{u_{i+p-1}-u_{i}}Q_{i-1,1}(u)) \\ &= \sum_{i=j-p+2}^{j} N_{i,p-2}(u)Q_{i,2}(u) \\ &=\cdots\\ &= \sum_{i=j-p+k}^{j} N_{i,p-k}(u)Q_{i,k}(u) \\ &=\cdots \\ &=\sum_{i=j-p+p}^{j} N_{i,p-p}(u)Q_{i,p}(u) \\ &= N_{j,0}(u)Q_{j,p}(u) \\ &= Q_{j,p}(u) \end{split} \end{equation}
C(u)=i=j−p+1∑jNi,p−1(u)Qi,1(u)=i=j−p+1∑j(ui+p−1−uiu−uiNi,p−2(u)+ui+p−ui+1ui+p−uNi+1,p−2(u))Qi,1(u)=i=j−p+1∑jui+p−1−uiu−uiNi,p−2(u)Qi,1(u)+i=j−p+1∑jui+p−ui+1ui+p−uNi+1,p−2(u))Qi,1(u)=i=j−p+2∑jui+p−1−uiu−uiNi,p−2(u)Qi,1(u)+uj−p+1+p−1−uj−p+1u−uj−p+1Nj−p+1,p−2(u)Qj−p+1,1(u)+i=j−p+2∑jui+p−1−uiui+p−1−uNi,p−2(u)Qi−1,1(u)+uj+p−uj+1uj+p−uNj+1,p−2(u)Qj,1(u)=i=j−p+2∑jui+p−1−uiu−uiNi,p−2(u)Qi,1(u)+i=j−p+2∑jui+p−1−uiui+p−1−uNi,p−2(u)Qi−1,1(u)(因为Nj−p+1,p−2(u)只在[uj−p+1,uj−p+1+p−2+1)不为0,Nj+1,p−2(u)只在[uj+1,uj+1+p−2+1)不为0,而uj∈[uj,uj+1))=i=j−p+2∑jNi,p−2(u)(ui+p−1−uiu−uiQi,1(u)+ui+p−1−uiui+p−1−uQi−1,1(u))=i=j−p+2∑jNi,p−2(u)Qi,2(u)=⋯=i=j−p+k∑jNi,p−k(u)Qi,k(u)=⋯=i=j−p+p∑jNi,p−p(u)Qi,p(u)=Nj,0(u)Qj,p(u)=Qj,p(u)
综上所述,
C
(
u
)
=
Q
j
,
p
(
u
)
,
u
∈
[
u
j
,
u
j
+
1
)
C(u)=Q_{j,p}(u),u\in[u_j,u_{j+1})
C(u)=Qj,p(u),u∈[uj,uj+1),我们只需要算出
Q
j
,
p
(
u
)
Q_{j,p}(u)
Qj,p(u)就可以了,而
Q
j
,
p
(
u
)
Q_{j,p}(u)
Qj,p(u)的递推计算公式我们已经在上面给出了,这里再写一遍:
Q
i
,
k
(
u
)
=
{
Q
i
k
=
0
u
−
u
i
u
i
+
p
+
1
−
k
−
u
i
Q
i
,
k
−
1
(
u
)
+
u
i
+
p
+
1
−
k
−
u
u
i
+
p
+
1
−
k
−
u
i
Q
i
−
1
,
k
−
1
(
u
)
k
=
1
,
⋯
,
p
\begin{equation}\nonumber Q_{i,k}(u)=\left\{ \begin{aligned} & Q_i \ \ &k=0 \\ & \frac{u-u_i}{u_{i+p+1-k}-u_i}Q_{i,k-1}(u) + \frac{u_{i+p+1-k}-u}{u_{i+p+1-k}-u_{i}}Q_{i-1,k-1}(u) \ \ &k=1,\cdots,p \\ \end{aligned} \right. \end{equation}
Qi,k(u)=⎩
⎨
⎧Qi ui+p+1−k−uiu−uiQi,k−1(u)+ui+p+1−k−uiui+p+1−k−uQi−1,k−1(u) k=0k=1,⋯,p
递推计算方法如下图所示,复杂度为
O
(
p
2
)
O(p^2)
O(p2),代码参考EvaluateDeboor。
(由于网站要梯子,所以这里附EvaluateDeboor的代码:)
def deBoor(k: int, x: int, t, c, p: int):
"""Evaluates S(x).
Arguments
---------
k: Index of knot interval that contains x.
x: Position.
t: Array of knot positions, needs to be padded as described above.
c: Array of control points.
p: Degree of B-spline.
"""
d = [c[j + k - p] for j in range(0, p + 1)]
for r in range(1, p + 1):
for j in range(p, r - 1, -1):
alpha = (x - t[j + k - p]) / (t[j + 1 + k - r] - t[j + k - p])
d[j] = (1.0 - alpha) * d[j - 1] + alpha * d[j]
return d[p]
参考文献:
- https://en.wikipedia.org/wiki/De_Boor%27s_algorithm
- http://www.whudj.cn/?p=535