简介:
在规划领域,表达path的方式有离散点,五次多项式,贝塞尔曲线,B样条曲线,螺旋线。作为从业者,掌握一种曲线,对于做轨迹优化是非常有必要的。如果自己想要做一些轨迹优化的项目,能够自己手写一个曲线,还是很有用的。因为搬轮子虽然也可以,但如果如果需要利用曲线特有的性质做一些事儿,就得很了解才行。
B样条曲线性质和代码示例
参考文献:
https://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/
1.B样条的优势
天然分段,分段之间是天然C2连续的,这对于运动规划是很好的性质,是分段多项式和分段贝塞尔不具备的性质。
二阶连续的特性,使得B样条在拼接处,只需保持控制点不变,就可达到曲率连续,而对于离散点,很难约束拼接处曲率连续,对于五次多项式,倒是可以,但不如b样条方便。
2.理论知识
C
(
u
)
=
∑
0
n
N
i
,
p
(
u
)
P
i
(
2.1
)
C(u) = \sum_0^nN_{i,p}(u)P_i\qquad \qquad \qquad(2.1)
C(u)=0∑nNi,p(u)Pi(2.1)
三大元素:基函数
N
i
,
p
N_{i,p}
Ni,p,控制点
P
i
P_i
Pi,节点向量knot vector
U
=
{
u
0
,
u
1
,
.
.
.
,
u
m
}
U = \{u_0,u_1,...,u_m\}
U={u0,u1,...,um}
数量关系:控制点个数n+1,节点个数m+1,阶数p,m = n + p + 1
三种类型:open, clamped, closed B-spline curve
曲线起点不过第一个控制点;曲线起点通过第一个控制点;曲线闭合。
2.1 节点向量和基函数
2.1.1 基本概念
有一些概念需要分清楚:
- p阶bezier曲线:共有p+1个控制点,只有一段轨迹
- p阶b-spline曲线:控制点不限,最少p+1个,多段C2连续的轨迹(段之间天然C2连续)
- 分段(peicewise)p阶bezier曲线:控制点不限,多段C2连续的轨迹(段之间C2连续需要边界约束)
这里需要搞清楚一个问题,每一小段曲线,由相应的p+1个控制点加相应的p+1个基函数确定,那b-样条曲线是如何自动分段,自动选取相应的相应的基函数和控制点的呢?如下图所示:
- 红色控制点生成红色曲线,蓝色控制点生成蓝色曲线,其中由p个控制点是重复使用的。
- N i , p ( u ) N_{i,p}(u) Ni,p(u)是一个关于的分段函数,对于指定的 i i i来说, N i , p N_{i,p} Ni,p仅在某一段u的取值范围内是非零的,其他都是0。
- 通过 N i , p N_{i,p} Ni,p是否为零,达到指定控制点的目的。根据不同的 u u u,假设3阶,得到3+1个非零的基函数 N i , p , N i + 1 , p , N i + 2 , p , N i + 3 , p N_{i,p},N_{i+1,p},N_{i+2,p},N_{i+3,p} Ni,p,Ni+1,p,Ni+2,p,Ni+3,p
- 对于红色曲线,其曲线方程可以看作:
C ( u ) = N 0 , 3 ( u ) P 0 + N 1 , 3 ( u ) P 1 + N 2 , 3 ( u ) P 3 + N 3 , 3 ( u ) P 3 + 0 ∗ P 4 + 0 ∗ P 5 + 0 ∗ P 6 + 0 ∗ P 7 . . . C(u)=N_{0,3}(u)P_0 + N_{1,3}(u)P_1+N_{2,3}(u)P3+N_{3,3}(u)P_3+0*P_4+0*P_5+0*P_6+0*P_7... C(u)=N0,3(u)P0+N1,3(u)P1+N2,3(u)P3+N3,3(u)P3+0∗P4+0∗P5+0∗P6+0∗P7... - 对于蓝色曲线,其曲线方程可以看作:
C ( u ) = 0 ∗ P 0 + N 1 , 3 ( u ) P 1 + N 2 , 3 ( u ) P 3 + N 3 , 3 ( u ) P 3 + N 4 , 3 P 4 + 0 ∗ P 5 + 0 ∗ P 6 + 0 ∗ P 7 . . . C(u)=0*P_0 + N_{1,3}(u)P_1+N_{2,3}(u)P3+N_{3,3}(u)P_3+N_{4,3}P_4+0*P_5+0*P_6+0*P_7... C(u)=0∗P0+N1,3(u)P1+N2,3(u)P3+N3,3(u)P3+N4,3P4+0∗P5+0∗P6+0∗P7...
2.1.2 节点向量knot vector
在上一节中提到,根据不同的u,可以确定哪几个基函数是非零的,哪些是0。可以直观感受到,
N
i
,
p
(
u
)
N_{i,p}(u)
Ni,p(u)是关于u的分段函数,这里的分段,其实就是不同的节点之间的分段。
一些基本名词:
- 节点向量knot vector: U = { u 0 , u 1 , u 2 , . . . u m } U=\{u_0, u_1, u_2, ... u_m\} U={u0,u1,u2,...um}
- 节点knot: u i u_i ui
- knot span: [ u i , u i + 1 ) [u_i, u_{i+1}) [ui,ui+1), 称为第i个knot span
- 均匀和非均匀: knot span间隔相等则为均匀b样条
- multiple knot: u i = u i + 1 = . . . u i + k − 1 , k > 1 u_i=u_{i+1}=...u_{i+k-1},k>1 ui=ui+1=...ui+k−1,k>1,即两个或以上重复knot,k称为multiplicity
- simple knot: 没有相同的knot,则该kont为simple knot
(1) 节点向量生成
本文讨论范围为均匀b样条,因此节点是均匀的,且 u 0 < = u 1 < = u 2 . . . < = u m u_0<=u_1<=u_2...<=u_m u0<=u1<=u2...<=um
节点个数:假设n+1个控制点,p阶, m = n + p + 1 m=n+p+1 m=n+p+1,节点个数为 m + 1 m+1 m+1
取值范围: [ u 0 , u m ] [u_0,u_m] [u0,um],常见的是取 u 0 = 0 , u m = 1 u_0=0,u_m=1 u0=0,um=1,当然也可以任意取值,[0,7],然后进行归一化即可
(2) open curve和clamped curve
根据knot vector是否满足 u 0 = u 1 = u 2 , . . . = u p = 0 u_0=u_1=u_2,...=u_p=0 u0=u1=u2,...=up=0且 u m − p = u m − p + 1 , . . . = u m = 1 u_{m-p}=u_{m-p+1},...=u_m=1 um−p=um−p+1,...=um=1区分,下边以p=3为例:
open curve
曲线的起点不经过第一个控制点,其节点向量如为 [ 0 , 0.1 , 0.2 , 0.3 , 0.4 , 0.5 , 0.6 , 0.7 , 0.8 , 0.9 , 1.0 ] [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
clampled curve
曲线起点经过第一个控制点,其节点向量为
[
0
,
0
,
0
,
0
,
0.4
,
0.5
,
0.6
,
1.0
,
1.0
,
1.0
,
1.0
]
[0, 0, 0, 0, 0.4, 0.5, 0.6, 1.0, 1.0, 1.0, 1.0]
[0,0,0,0,0.4,0.5,0.6,1.0,1.0,1.0,1.0]
原因在后边基函数三角形那里在讲 #三角形
2.1.3 基函数定义
b-spline的基函数,没有明确的公式可以直接计算,只有Cox-de Boor递推形式公式,通过0阶基函数,递推到p阶基函数.
(1) Cox-de Boor递推公式
假设节点向量 U = { 0 , 1 , 2 , 3 , 4 , 5 , 6... } , p = 3 U=\{0,1,2,3,4,5,6...\},p=3 U={0,1,2,3,4,5,6...},p=3
N i , 0 = { 1 if u i ≤ u < u i + 1 ( 2.3 ) 0 otherwise N_{i,0}= \begin{cases} 1 & \text{if } u_i \leq u < u_{i+1} \\ &&&&&&&&(2.3)\\ 0 & \text{otherwise} \end{cases} Ni,0=⎩ ⎨ ⎧10if ui≤u<ui+1otherwise(2.3)
N i , p ( u ) = ( 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 ) ( 2.4 ) N_{i,p}(u)= \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) \qquad \qquad(2.4) Ni,p(u)=ui+p−ui(u−ui)Ni,p−1(u)+ui+p+1−ui+1ui+p+1−uNi+1,p−1(u)(2.4)
0阶基函数 N i , 0 N_{i,0} Ni,0是已知的,是分段函数
N
0
,
0
N
0
,
1
N
1
,
0
N
0
,
2
N
1
,
1
N
0
,
3
N
2
,
0
N
1
,
2
N
0
,
4
N
2
,
1
N
1
,
3
N
0
,
5
(
2.6
)
N
3
,
0
N
2
,
2
N
1
,
4
N
3
,
1
N
2
,
3
N
4
,
0
N
3
,
2
N
4
,
1
N
5
,
0
\begin{aligned} N_{0,0} \\&& N_{0,1}\\ N_{1,0} &&&&N_{0,2} \\&& N_{1,1} &&&&N_{0,3} \\ N_{2,0} &&&&N_{1,2} &&&&N_{0,4} \\&& N_{2,1} &&&&N_{1,3} &&&&N_{0,5}&&&&&&&&(2.6)\\ N_{3,0} &&&&N_{2,2} &&&&N_{1,4} \\&& N_{3,1} &&&&N_{2,3} \\ N_{4,0} &&&&N_{3,2} \\&& N_{4,1}\\ N_{5,0} \end{aligned}
N0,0N1,0N2,0N3,0N4,0N5,0N0,1N1,1N2,1N3,1N4,1N0,2N1,2N2,2N3,2N0,3N1,3N2,3N0,4N1,4N0,5(2.6)
N
i
,
0
N_{i,0}
Ni,0的是0阶基函数,它是关于
u
u
u的分段函数,只有0阶基函数可以通过判断u所在的knot span来确定其值为1还是0。更高阶(1,2,3…)的基函数只能通过低阶基函数递推计算
- 0阶基函数计算
N
0
,
0
=
{
1
if
u
0
≤
u
<
u
1
0
if
u
1
≤
u
<
u
2
0
if
u
2
≤
u
<
u
3
0
otherwise
(
2.7
)
N_{0,0}= \begin{cases} 1 & \text{if } u_0 \leq u < u_1 \\ 0 & \text{if } u_1 \leq u < u_2 \\ 0 & \text{if } u_2 \leq u < u_3 \\ 0 & \text{otherwise} \end{cases} \quad (2.7)
N0,0=⎩
⎨
⎧1000if u0≤u<u1if u1≤u<u2if u2≤u<u3otherwise(2.7)
N
1
,
0
=
{
1
if
u
1
≤
u
<
u
2
0
otherwise
(
2.8
)
N_{1,0}= \begin{cases} 1 & \text{if } u_1 \leq u < u_2 \\ 0 & \text{otherwise} \quad (2.8) \end{cases}
N1,0={10if u1≤u<u2otherwise(2.8)
N 2 , 0 = { 1 if u 1 ≤ u < u 2 0 otherwise ( 2.9 ) N_{2,0}= \begin{cases} 1 & \text{if } u_1 \leq u < u_2 \\ 0 & \text{otherwise} \quad (2.9) \end{cases} N2,0={10if u1≤u<u2otherwise(2.9)
N 3 , 0 = { 1 if u 1 ≤ u < u 2 0 otherwise ( 2.10 ) N_{3,0}= \begin{cases} 1 & \text{if } u_1 \leq u < u_2 \\ 0 & \text{otherwise} \quad (2.10) \end{cases} N3,0={10if u1≤u<u2otherwise(2.10)
- 1阶基函数计算
由公式2.4,递推计算
N
i
,
1
N_i,1
Ni,1:
N
0
,
1
(
u
)
=
u
−
u
0
u
1
−
u
0
N
0
,
0
(
u
)
+
u
2
−
u
u
2
−
u
1
N
1
,
0
(
u
)
N_{0,1}(u)=\frac{u-u_0}{u_1-u_0}N_{0,0}(u)+\frac{u_2-u}{u_2-u_1}N_{1,0}(u)
N0,1(u)=u1−u0u−u0N0,0(u)+u2−u1u2−uN1,0(u)
将 u 0 = 0 , u 1 = 1 , u 2 = 2 u_0=0,u_1=1,u_2=2 u0=0,u1=1,u2=2带入上式,得到:
N 0 , 1 ( u ) = u N 0 , 0 ( u ) + ( 2 − u ) N 1 , 0 ( u ) N_{0,1}(u)=uN_{0,0}(u)+(2-u)N_{1,0}(u) N0,1(u)=uN0,0(u)+(2−u)N1,0(u)
当 u ∈ [ 0 , 1 ) 时, N 0 , 0 = 1 , 否则为 0 u\in[0,1)时,N_{0,0}=1,否则为0 u∈[0,1)时,N0,0=1,否则为0,当 u ∈ [ 1 , 2 ) 时, N 1 , 0 = 1 , 否则为 0 u\in[1,2)时,N_{1,0}=1,否则为0 u∈[1,2)时,N1,0=1,否则为0,因此可以得到 N 0 , 1 N_0,1 N0,1的分段函数为:
N
0
,
1
=
{
u
N
0
,
0
(
u
)
0
<
=
u
<
1
(
2
−
u
)
N
1
,
0
(
u
)
1
<
=
u
<
2
0
o
t
h
e
r
w
i
s
e
\begin{equation} N_{0,1}= \left\{ \begin{aligned} uN_{0,0}(u) & & 0<=u<1 \\ (2-u)N_{1,0}(u) & & 1<=u<2 \\ 0 & &otherwise \end{aligned} \right. \end{equation}
N0,1=⎩
⎨
⎧uN0,0(u)(2−u)N1,0(u)00<=u<11<=u<2otherwise
N
1
,
1
,
N
2
,
1
,
N
3
,
1
.
.
.
同理可得,不再赘述
N_{1,1},N_{2,1},N_{3,1}...同理可得,不再赘述
N1,1,N2,1,N3,1...同理可得,不再赘述
- 2阶基函数计算
同理可以推导出2阶基函数:
N
0
,
2
(
u
)
=
u
−
u
0
u
2
−
u
0
N
0
,
1
(
u
)
+
u
3
−
u
u
3
−
u
1
N
1
,
1
(
u
)
N_{0,2}(u)=\frac{u-u_0}{u_2-u_0}N_{0,1}(u)+\frac{u_3-u}{u_3-u_1}N_{1,1}(u)
N0,2(u)=u2−u0u−u0N0,1(u)+u3−u1u3−uN1,1(u)
N
0
,
2
(
u
)
=
0.5
u
N
0
,
1
(
u
)
+
0.5
(
3
−
u
)
N
1
,
1
(
u
)
N_{0,2}(u)=0.5uN_{0,1}(u)+0.5(3-u)N_{1,1}(u)
N0,2(u)=0.5uN0,1(u)+0.5(3−u)N1,1(u)
N
0
,
2
=
{
0.5
u
N
0
,
1
(
u
)
0
<
=
u
<
1
0.5
u
N
0
,
1
(
u
)
+
0.5
(
3
−
u
)
N
1
,
1
(
u
)
1
<
=
u
<
2
0.5
(
3
−
u
)
N
1
,
1
(
u
)
2
<
=
u
<
3
0
o
t
h
e
r
w
i
s
e
\begin{equation} N_{0,2}= \left\{ \begin{aligned} 0.5uN_{0,1}(u) & & 0<=u<1 \\ 0.5uN_{0,1}(u) + 0.5(3-u)N_{1,1}(u) & & 1<=u<2 \\ 0.5(3-u)N_{1,1}(u) & & 2<=u<3 \\ 0 & & otherwise \end{aligned} \right. \end{equation}
N0,2=⎩
⎨
⎧0.5uN0,1(u)0.5uN0,1(u)+0.5(3−u)N1,1(u)0.5(3−u)N1,1(u)00<=u<11<=u<22<=u<3otherwise
- 3阶基函数计算
https://www.ibiblio.org/e-notes/Splines/basis.html
N 0 , 3 ( u ) = u − u 0 u 3 − u 0 N 0 , 2 ( u ) + u 4 − u u 4 − u 1 N 1 , 2 ( u ) N_{0,3}(u)=\frac{u-u_0}{u_3-u_0}N_{0,2}(u)+\frac{u_4-u}{u_4-u_1}N_{1,2}(u) N0,3(u)=u3−u0u−u0N0,2(u)+u4−u1u4−uN1,2(u)
总结递推规律如下图所示。
需要注意一个特点,基函数的非零区间,随着阶数增加,逐步增加。
- 如0阶基函数 N i , 0 N_{i,0} Ni,0的非零区间为 [ u i , u i + 1 ) [u_i,u_{i+1}) [ui,ui+1)
- 1阶基函数 N i , 1 N_{i,1} Ni,1的非零区间为 [ u i , u i + 2 ) [u_i,u_{i+2}) [ui,ui+2)
- 即p阶基函数 N i , p N_{i,p} Ni,p的非零区间为 [ u i , u i + p + 1 ) [u_i,u_{i+p+1}) [ui,ui+p+1)
2.1.4 重要性质
下边性质是非常重要的,想要自己写一个b样条曲线,必须要明白,其中性质2和性质3是写出基函数的关键,必须要理解。
性质1: N i , p ( u ) N_{i,p}(u) Ni,p(u)关于u的是p阶多项式,准确说是分段多项式函数 #性质1
性质2: N i , p ( u ) N_{i,p}(u) Ni,p(u)的非零区间为 [ u i , u i + p + 1 ) [u_i,u_{i+p+1}) [ui,ui+p+1) #性质2
以三阶基函数为例,
N
1
,
3
N_{1,3}
N1,3是由
N
1
,
2
、
N
2
,
2
N_{1,2}、N_{2,2}
N1,2、N2,2递推得到,以此类推,
N
1
,
0
,
N
2
,
0
,
N
3
,
0
,
N
4
,
0
N_{1,0},N_{2,0},N_{3,0},N_{4,0}
N1,0,N2,0,N3,0,N4,0是递推的初始值,其u所在区间为
[
u
1
,
u
5
)
[u_1,u_5)
[u1,u5),该区间即为
N
1
,
3
N_{1,3}
N1,3的非零区间
#三角形1
性质3:任意span
[
u
i
,
u
i
+
1
)
[u_i,u_{i+1})
[ui,ui+1)的非零基函数是:
N
i
−
p
,
p
(
u
)
,
N
i
−
p
+
1
,
p
(
u
)
,
N
i
−
p
+
2
,
p
,
.
.
.
,
N
i
,
p
(
u
)
N_{i-p,p}(u),N_{i-p+1,p}(u),N_{i-p+2,p},...,N_{i,p}(u)
Ni−p,p(u),Ni−p+1,p(u),Ni−p+2,p,...,Ni,p(u) #性质3
#三角形2
以3次b样条为例,对于任意
u
u
u,如何确定该它属于哪一段b样条,即如何确定哪四个控制点和基函数控制着该段曲线呢,通过下边的三角形可以找到答案
C
(
u
)
=
∑
0
n
N
i
,
p
(
u
)
P
i
C(u) = \sum_0^nN_{i,p}(u)P_i\qquad \qquad \qquad
C(u)=0∑nNi,p(u)Pi
假设
u
∈
[
u
3
,
u
4
)
u\in[u_3,u_4)
u∈[u3,u4),向右做三角形,如橙色三角形,三角形包含的三阶基函数
N
0
,
3
,
N
1
,
3
,
N
2
,
3
,
N
3
,
3
N_{0,3},N_{1,3},N_{2,3},N_{3,3}
N0,3,N1,3,N2,3,N3,3,即
[
u
3
,
u
4
)
[u_3,u_4)
[u3,u4)上非零3阶基函数只有
N
0
,
3
,
N
1
,
3
,
N
2
,
3
,
N
3
,
3
N_{0,3},N_{1,3},N_{2,3},N_{3,3}
N0,3,N1,3,N2,3,N3,3。
性质4:open curve类型,b样条的有效knot为
[
u
p
,
u
m
−
p
]
[u_p,u_{m-p}]
[up,um−p] #性质4
假设p=3,knot个数为m+1,m=7,则有效knot为
[
u
3
,
u
4
)
[u_3,u_4)
[u3,u4),如下图所示。
思考一下,如果u取在
[
u
0
,
u
3
)
[u_0,u_3)
[u0,u3),意味着什么?
由 #三角形2 可知,在
[
u
2
,
u
3
)
[u_2,u_3)
[u2,u3)上,无法找到4个非零基函数,也就无法计算b样条;
另一个解释是,只有在
[
u
3
,
u
4
)
[u_3,u_4)
[u3,u4),才能使得b样条的二阶导数存在,这个求导性质后边会讲。
性质5:在span [ u i , u i + 1 ) [u_i,u_{i+1}) [ui,ui+1)上,所有非零基函数之和为1 #性质5
性质6:knots的个数为 m + 1 m+1 m+1,基函数个数=控制点个数= n + 1 n+1 n+1, p p p阶,则 m = n + p + 1 m=n+p+1 m=n+p+1 #性质6
性质7:在一个multiplicity为k的knot,基函数 N i , p ( u ) N_{i,p}(u) Ni,p(u)是 C p − k C^{p-k} Cp−k连续的 #性质7
-
对于simple knot,其multiplicity k = 1.
-
举个例子,二阶基函数 N 0 , 2 N_{0,2} N0,2是在 [ u 2 , u 3 ) [u_2,u3) [u2,u3)上是 C 1 C^1 C1连续的;
-
注意到,根据性质2,可知 N 0 , 2 ( u ) N_{0,2}(u) N0,2(u)在 [ u 0 , u 3 ) [u_0,u_3) [u0,u3)上都是非零的,为什么只有在 [ u 2 , u 3 ) [u_2,u_3) [u2,u3)上 C 1 C^1 C1连续呢?这个问题在后边讲完‘两个三角形’后就可以明白 #三角形 先说结论, N 0 , 2 , N 1 , 2 , N 2 , 2 N_{0,2},N_{1,2},N_{2,2} N0,2,N1,2,N2,2三个基函数加上 P 0 , P 1 , P 2 P_0,P_1,P_2 P0,P1,P2三个控制点,共同表示第一段曲线(假设为open curve)。该曲线的u区间为 [ u 2 , u 3 ) [u_2,u_3) [u2,u3)。即其实的u并不是 u 0 u_0 u0,而是 u 0 + p u_{0+p} u0+p。
2.2 求值方法(Evalute)
已知控制点和节点向量的情况下,给定u求b样条上的点,即求值(Evalute)操作。De boor算法是一种快速且数值稳定的方法。这里按我理解,b样条求值(Evalute)由三种方式。
2.2.1 de boor算法计算 C ( u ) C(u) C(u)
https://en.wikipedia.org/wiki/De_Boor%27s_algorithm#cite_note-4
de boor算法需要用到一个性质:knot的重复度增加,这个knot对应的非零基函数就会减少,当节点的重复度为
p
p
p时(p阶b样条),将只剩下一个非零基函数,那么
C
(
u
)
=
N
i
,
p
(
u
)
=
P
i
C(u)=N_{i,p}(u)=P_i
C(u)=Ni,p(u)=Pi。
通过不断插入u,使得u对应的非零基函数只有一个,那对应的控制点就是B样条曲线上的点。(注意这里的控制点,会随着插入knot u而重新生成)。
下边举例说明:
Eigen::Vector3d NonUniformBspline::evaluateDeBoor(double t)
{
if (t < this->u_(this->p_) || t > this->u_(this->m_ - this->p_))
{
if (t < this->u_(this->p_))
t = this->u_(this->p_);
if (t > this->u_(this->m_ - this->p_))
t = this->u_(this->m_ - this->p_);
}
// determine which [ui,ui+1] lay in
int k = this->p_;
while (true)
{
if (this->u_(k + 1) >= t)
break;
++k;
}
/* deBoor's alg */
vector<Eigen::Vector3d> d;
for (int i = 0; i <= p_; ++i)
{
d.push_back(control_points_.row(k - p_ + i));
}
for (int r = 1; r <= p_; ++r)
{
for (int i = p_; i >= r; --i)
{
double alpha = (t - u_[i + k - p_]) / (u_[i + 1 + k - r] - u_[i + k - p_]);
d[i] = (1 - alpha) * d[i - 1] + alpha * d[i];
}
}
return d[p_];
}
2.2.2 de boor递推公式,求出所有的非零基函数(重点掌握)
确定u所处的knot span,挑选相应的基函数和控制点,根据b样条表达式求出
C
(
u
)
C(u)
C(u)。这里需要用到的时基函数的递推公式。
下边举例说明:
2.2.3 计算矩阵表达形式
带入不同的u和控制点,计算 C ( u ) C(u) C(u)。这里需要推导b样条的矩阵表达形式。
本文讨论的是均匀B样条,即节点矢量沿参数轴均匀等距分布。
Δ
i
=
u
i
+
1
−
u
i
\Delta_i=u_{i+1}-u_i
Δi=ui+1−ui是一个常数。每一个节点区间
[
u
i
,
u
i
+
1
)
[u_i,u_{i+1})
[ui,ui+1)对应着一段b样条曲线,通过归一化将u归一化到
t
∈
[
0
,
1
]
t\in[0,1]
t∈[0,1],可以用整体的u来表示b样条。
1.归一化
u
=
u
(
t
)
=
(
1
−
t
)
u
i
+
t
u
i
+
1
,
t
∈
[
0
,
1
]
,
i
=
p
,
p
+
1
,
.
.
.
n
u=u(t)=(1-t)u_i+tu_{i+1}, \quad t\in[0,1],i=p,p+1,...n
u=u(t)=(1−t)ui+tui+1,t∈[0,1],i=p,p+1,...n
2.分段表达式
C
i
(
t
)
=
C
(
u
(
t
)
)
=
∑
j
=
i
−
k
i
P
j
N
j
,
p
(
u
(
t
)
)
,
t
∈
[
0
,
1
]
,
i
=
p
,
p
+
1
,
.
.
.
n
C_i(t)=C(u(t))=\sum_{j=i-k}^iP_jN_{j,p}(u(t)), \quad t\in[0,1],i=p,p+1,...n
Ci(t)=C(u(t))=j=i−k∑iPjNj,p(u(t)),t∈[0,1],i=p,p+1,...n
矩阵表达式如下:
C
i
(
t
)
=
[
1
t
t
2
.
.
.
t
p
]
M
p
[
p
i
−
p
p
i
−
p
+
1
⋮
p
i
]
,
t
∈
[
0
,
1
]
,
i
=
p
,
p
+
1
,
.
.
.
n
C_i(t)= \begin{bmatrix} 1 & t & t^2 & ... & t^p \end{bmatrix} M_p \begin{bmatrix} p_{i-p} \\ p_{i-p+1} \\ \vdots \\ p_i\end{bmatrix}, \quad t\in[0,1],i=p,p+1,...n
Ci(t)=[1tt2...tp]Mp
pi−ppi−p+1⋮pi
,t∈[0,1],i=p,p+1,...n
对于二次b样条,
p
=
2
p=2
p=2,系数矩阵为
M
2
=
[
1
1
0
−
2
2
0
1
−
2
1
]
M_2= \begin{bmatrix} 1 & 1 & 0 \\ -2 & 2 & 0 \\ 1 & -2 & 1 \end{bmatrix}
M2=
1−2112−2001
对于三次b样条,
p
=
3
p=3
p=3,系数矩阵为
M
3
=
[
1
4
1
0
−
3
0
3
0
3
−
6
3
0
−
1
3
−
3
1
]
M_3= \begin{bmatrix} 1 & 4 & 1 & 0\\ -3 & 0 & 3 & 0\\ 3 & -6 & 3 & 0\\ -1 & 3 & -3 & 1 \end{bmatrix}
M3=
1−33−140−63133−30001
三次均匀b样条曲线方程的矩阵形式为:
C
i
(
t
)
=
[
1
t
t
2
t
3
]
[
1
4
1
0
−
3
0
3
0
3
−
6
3
0
−
1
3
−
3
1
]
[
p
i
−
3
p
i
−
2
p
i
−
1
p
i
]
,
t
∈
[
0
,
1
]
,
i
=
p
,
p
+
1
,
.
.
.
n
C_i(t)= \begin{bmatrix} 1 & t & t^2 & t^3 \end{bmatrix} \begin{bmatrix} 1 & 4 & 1 & 0\\ -3 & 0 & 3 & 0\\ 3 & -6 & 3 & 0\\ -1 & 3 & -3 & 1 \end{bmatrix} \begin{bmatrix} p_{i-3} \\ p_{i-2} \\ p_{i-1} \\ p_i\end{bmatrix}, \quad t\in[0,1],i=p,p+1,...n
Ci(t)=[1tt2t3]
1−33−140−63133−30001
pi−3pi−2pi−1pi
,t∈[0,1],i=p,p+1,...n
下边举例说明:
Vector2d GetPos(int span_index){
MatrixXd M3(4,4);
M3 << -1, 3, -3, 1,
3, -6, 3, 0,
-3, 0, 3, 0,
1, 4, 1, 0;
MatrixXd tm(4,4);
tm << tf*tf*tf*tf, tf*tf, tf, 1;
MatrixXd control_points; //记录了所有控制点
MatrixXd pm(4,2);
pm = control_points.block(span_index,0,4,2);
//根据knot span, 从control_points中选取4个控制点
MatrixXd pos = tm*M3*pm;
return Vector2d(pos(0,0), pos(0,1));
}
2.3 曲率和求导
2.3.1 曲率计算公式:
k
=
∣
x
′
y
′
′
−
y
′
x
′
′
∣
(
x
′
2
+
y
′
2
)
3
2
k=\frac{|x^{'}y^{''}-y^{'}x^{''}|}{(x^{'2}+y^{'2})^{\frac{3}{2}}}
k=(x′2+y′2)23∣x′y′′−y′x′′∣
对于b样条来说,假设曲线为2维的,xy坐标系,则
C
(
u
)
C(u)
C(u)是一个二维的点(
C
(
u
)
.
x
,
C
(
u
)
.
y
C(u).x,C(u).y
C(u).x,C(u).y)。
为了求得曲率,需要求出曲线的一阶
C
′
(
u
)
C^{'}(u)
C′(u)和二阶导数
C
′
′
(
u
)
C^{''}(u)
C′′(u)
2.3.2 b样条求导
注:这里不讨论clamped curve,仅讨论open curve
p阶b样条的导数为p-1阶b样条。假设p阶b样条定义为:
C
(
u
)
=
∑
0
n
N
i
,
p
(
u
)
P
i
C(u) = \sum_0^nN_{i,p}(u)P_i
C(u)=0∑nNi,p(u)Pi
b样条的三大元素,节点向量,控制点,基函数,下边分别介绍求导后的b样条的三大元素。
新的基函数:
d
d
u
N
i
,
p
(
u
)
=
N
i
,
p
′
(
u
)
=
p
u
i
+
p
−
u
i
N
i
,
p
−
1
(
u
)
−
p
u
i
+
p
+
1
−
u
i
+
1
N
i
+
1
,
p
−
1
(
u
)
\frac{\mathrm{d}}{\mathrm{d}u}N_{i,p}(u) =N^{'}_{i,p}(u)=\frac{p}{u_{i+p}-u_i}N_{i,p-1}(u)-\frac{p}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u)
dudNi,p(u)=Ni,p′(u)=ui+p−uipNi,p−1(u)−ui+p+1−ui+1pNi+1,p−1(u)
曲线求导公式:
d
d
u
C
(
u
)
=
C
′
(
u
)
=
∑
i
=
0
n
−
1
N
i
+
1
,
p
−
1
(
u
)
Q
i
\frac{\mathrm{d}}{\mathrm{d}u}C(u)=C^{'}(u)=\sum^{n-1}_{i=0}N_{i+1,p-1}(u)Q_i
dudC(u)=C′(u)=i=0∑n−1Ni+1,p−1(u)Qi
新的控制点
Q
i
Q_i
Qi:
(新的控制点
Q
i
Q_i
Qi的个数会比旧的控制点
P
i
P_i
Pi的个数少一个)
Q
i
=
p
u
i
+
p
+
1
−
u
i
+
1
(
P
i
+
1
−
P
i
)
,
i
=
0
,
1
,
2
,
.
.
.
n
−
1
Q_i=\frac{p}{u_{i+p+1}-u_{i+1}}(P_{i+1}-P_i), \quad i=0,1,2,...n-1
Qi=ui+p+1−ui+1p(Pi+1−Pi),i=0,1,2,...n−1
新节点向量:
原始的节点向量去除首和尾的两个节点,得到新的节点向量。
原始的节点向量: { u 0 , u 1 , u 2 , . . . u m } \{u_0,u_1,u_2,...u_m\} {u0,u1,u2,...um}
新的节点向量: { u 1 , u 2 , . . . u m − 1 } \{u_1,u_2,...u_{m-1}\} {u1,u2,...um−1}
更多内容,请关注公众号 哎嗨人生