使用De Boor递推算法求B样条曲线上的点
概括说明
de Boor 算法是一种递归算法,用于计算 B 样条曲线上给定参数 u 对应的点坐标。
算法的基本思路是:
- 首先确定参数 u 所在的节点区间
[u_k, u_k+1]
。 - 然后取出与该节点区间相关的
p + 1
个控制点,作为初始值。 - 通过
p
次迭代,每次将相邻的两个点合并为一个新的点,最终得到我们想要的点坐标。
其中 p
是 B 样条曲线的阶数。
B 样条曲线有一个重要性质:在任意一个节点区间 [u_k, u_k+1]
内,曲线段只与 p + 1
个控制点相关(参考下图)。 更具体地说,对于给定的参数 u,它所在的节点区间为 [u_k, u_k+1]
。根据 B 样条曲线的性质,在这个节点区间内,曲线段只与索引从 k - p
到 k
的 p + 1个控制点相关。
根据上图,需要强调的是,对于在节点区间 [u_k, u_k+1]
内的参数 u,p次B样条曲线只与索引从 k-p
到 k
的 p + 1个控制点相关,对应
N
k
−
p
,
p
N_{k-p,p}
Nk−p,p~
N
k
,
p
N_{k,p}
Nk,p非零。 同样,为了更加明确,其对应p-1次B样条曲线只与索引从 k-(p-1)
到 k
的 p 个控制点相关,对应
N
k
−
p
+
1
,
p
−
1
N_{k-p+1,p-1}
Nk−p+1,p−1~
N
k
,
p
−
1
N_{k,p-1}
Nk,p−1非零,比p次B样条曲线所对应的基函数个数刚好少一个。(这里理解的不够充分,可能有错误)
De Boor递推算法求B样条曲线上的点
在确定参数 u
所在的节点区间 [u_k, u_k+1]
后,根据B样条曲线定义可知
P
(
u
)
=
∑
i
=
0
n
N
i
,
p
(
u
)
Q
i
=
∑
i
=
k
−
p
k
N
i
,
p
(
u
)
Q
i
P(u) = \sum_{i=0}^n N_{i,p}(u)Q_i = \sum_{i=k-p}^k N_{i,p}(u)Q_i
P(u)=i=0∑nNi,p(u)Qi=i=k−p∑kNi,p(u)Qi
其中,
Q
i
Q_i
Qi为B样条轨迹控制点;
N
i
,
p
(
u
)
N_{i,p}(u)
Ni,p(u)为B样条轨迹p次基函数。
接下来,由以下Cox-de Boor递推公式
:
N
i
,
0
(
u
)
=
{
1
,
if
u
i
≤
u
<
u
i
+
1
0
,
otherwise
N
i
,
k
(
u
)
=
u
−
u
i
u
i
+
k
−
u
i
N
i
,
k
−
1
(
u
)
+
u
i
+
k
+
1
−
u
u
i
+
k
+
1
−
u
i
+
1
N
i
+
1
,
k
−
1
(
u
)
\begin{aligned} N_{i,0}(u) &= \begin{cases} 1, & \text{if } u_i \leq u < u_{i+1}\\ 0, & \text{otherwise} \end{cases} \\ N_{i,k}(u) &= \frac{u - u_i}{u_{i+k} - u_i} N_{i,k-1}(u) + \frac{u_{i+k+1} - u}{u_{i+k+1} - u_{i+1}} N_{i+1,k-1}(u) \end{aligned}
Ni,0(u)Ni,k(u)={1,0,if ui≤u<ui+1otherwise=ui+k−uiu−uiNi,k−1(u)+ui+k+1−ui+1ui+k+1−uNi+1,k−1(u)
带入之前的B样条曲线定义式可得:
P
(
u
)
=
∑
i
=
k
−
p
k
N
i
,
p
(
u
)
Q
i
=
∑
i
=
k
−
p
k
(
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
=
k
−
p
k
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
+
∑
i
=
k
−
p
k
u
i
+
p
+
1
−
u
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
Q
i
\begin{aligned} P(u) &= \sum_{i=k-p}^k N_{i,p}(u)Q_i \\ &= \sum_{i=k-p}^k \left( \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) \right) Q_i \\ &= \sum_{i=k-p}^k \frac{u - u_i}{u_{i+p} - u_i} N_{i,p-1}(u) Q_i + \sum_{i=k-p}^k \frac{u_{i+p+1} - u}{u_{i+p+1} - u_{i+1}} N_{i+1,p-1}(u) Q_i \end{aligned}
P(u)=i=k−p∑kNi,p(u)Qi=i=k−p∑k(ui+p−uiu−uiNi,p−1(u)+ui+p+1−ui+1ui+p+1−uNi+1,p−1(u))Qi=i=k−p∑kui+p−uiu−uiNi,p−1(u)Qi+i=k−p∑kui+p+1−ui+1ui+p+1−uNi+1,p−1(u)Qi
这里,由于B样条曲线基函数由p次变为p-1次,根据之前结论有
N
k
−
p
,
p
−
1
=
0
N
k
+
1
,
p
−
1
=
0
N_{k-p,p-1}=0 \\ N_{k+1,p-1}=0
Nk−p,p−1=0Nk+1,p−1=0
因此,对于上式结果的第一项,有
∑
i
=
k
−
p
k
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
=
∑
i
=
k
−
p
+
1
k
u
−
u
i
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
\sum_{i=k-p}^k \frac{u - u_i}{u_{i+p} - u_i} N_{i,p-1}(u) Q_i = \sum_{i=k-p+1}^k \frac{u - u_i}{u_{i+p} - u_i} N_{i,p-1}(u) Q_i
i=k−p∑kui+p−uiu−uiNi,p−1(u)Qi=i=k−p+1∑kui+p−uiu−uiNi,p−1(u)Qi
对于上式结果的第二项,有
∑
i
=
k
−
p
k
u
i
+
p
+
1
−
u
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
Q
i
=
∑
i
=
k
−
p
k
−
1
u
i
+
p
+
1
−
u
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
Q
i
=
∑
i
=
k
−
p
+
1
k
u
i
+
p
−
u
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
Q
i
−
1
\begin{aligned} &\sum_{i=k-p}^k \frac{u_{i+p+1} - u}{u_{i+p+1} - u_{i+1}} N_{i+1,p-1}(u) Q_i \\ = &\sum_{i=k-p}^{k-1} \frac{u_{i+p+1} - u}{u_{i+p+1} - u_{i+1}} N_{i+1,p-1}(u) Q_i \\ = &\sum_{i=k-p+1}^k \frac{u_{i+p} - u}{u_{i+p} - u_{i}} N_{i,p-1}(u) Q_{i-1} \end{aligned}
==i=k−p∑kui+p+1−ui+1ui+p+1−uNi+1,p−1(u)Qii=k−p∑k−1ui+p+1−ui+1ui+p+1−uNi+1,p−1(u)Qii=k−p+1∑kui+p−uiui+p−uNi,p−1(u)Qi−1
因此,
P
(
u
)
=
∑
i
=
k
−
p
+
1
k
(
u
−
u
i
u
i
+
p
−
u
i
Q
i
+
u
i
+
p
−
u
u
i
+
p
−
u
i
Q
i
−
1
)
N
i
,
p
−
1
(
u
)
\begin{aligned} P(u) &= \sum_{i=k-p+1}^k \bigg( \frac{u - u_i}{u_{i+p} - u_i} Q_i + \frac{u_{i+p} - u}{u_{i+p} - u_{i}} Q_{i-1} \bigg) N_{i,p-1}(u) \end{aligned}
P(u)=i=k−p+1∑k(ui+p−uiu−uiQi+ui+p−uiui+p−uQi−1)Ni,p−1(u)
记
Q
i
,
1
=
u
−
u
i
u
i
+
p
−
u
i
Q
i
+
u
i
+
p
−
u
u
i
+
p
−
u
i
Q
i
−
1
Q_{i,1} = \frac{u - u_i}{u_{i+p} - u_i} Q_i + \frac{u_{i+p} - u}{u_{i+p} - u_{i}} Q_{i-1}
Qi,1=ui+p−uiu−uiQi+ui+p−uiui+p−uQi−1
那么,
P
(
u
)
=
∑
i
=
k
−
p
+
1
k
N
i
,
p
−
1
(
u
)
Q
i
,
1
\begin{aligned} P(u) &= \sum_{i=k-p+1}^k N_{i,p-1}(u) Q_{i,1} \end{aligned}
P(u)=i=k−p+1∑kNi,p−1(u)Qi,1
依此递推,可得
P
(
u
)
=
∑
i
=
k
−
p
+
r
k
N
i
,
p
−
r
(
u
)
Q
i
,
r
\begin{aligned} P(u) &= \sum_{i=k-p+r}^k N_{i,p-r}(u) Q_{i,r} \end{aligned}
P(u)=i=k−p+r∑kNi,p−r(u)Qi,r
其中,
Q
i
,
r
=
u
−
u
i
u
i
+
p
+
1
−
r
−
u
i
Q
i
,
r
−
1
+
u
i
+
p
+
1
−
r
−
u
u
i
+
p
+
1
−
r
−
u
i
Q
i
−
1
,
r
−
1
Q_{i,r} = \frac{u - u_i}{u_{i+p+1-r} - u_i} Q_{i,r-1} + \frac{u_{i+p+1-r} - u}{u_{i+p+1-r} - u_{i}} Q_{i-1,r-1}
Qi,r=ui+p+1−r−uiu−uiQi,r−1+ui+p+1−r−uiui+p+1−r−uQi−1,r−1
如果我们记
α
=
u
−
u
i
u
i
+
p
+
1
−
r
−
u
i
\alpha = \frac{u - u_i}{u_{i+p+1-r} - u_i}
α=ui+p+1−r−uiu−ui,那么有
Q
i
,
r
=
α
Q
i
,
r
−
1
+
(
1
−
α
)
Q
i
−
1
,
r
−
1
Q_{i,r} = \alpha Q_{i,r-1} + (1-\alpha) Q_{i-1,r-1}
Qi,r=αQi,r−1+(1−α)Qi−1,r−1
De Boor递推算法实际上就是通过计算权重系数 alpha
进行线性插值,将相邻的两个控制点合并为一个新的控制点,通过 p
次迭代,最终即可得到我们想要的点坐标。