欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。
问题描述
- 对besier曲线在u处打断,生成两条besier曲线
- 对besier曲线升阶处理
bezier高阶性质
求导推导
P ( t ) = ∑ i = 0 n B i n ( t ) b i \boldsymbol P(t) = \displaystyle \sum_{i=0}^nB_i^n(t)\boldsymbol b_i P(t)=i=0∑nBin(t)bi
B i n ( t ) = ( n i ) t i ( 1 − t ) n − i B_i^n(t)=\left (\begin{array}{l}n \\i \end{array} \right)t^i(1-t)^{n-i} Bin(t)=(ni)ti(1−t)n−i
矩阵表示
P ( t ) = [ B 0 n B 1 n ⋯ B n n ] [ b 0 b 1 ⋮ b n ] P(t) = \begin {bmatrix} B_0^n & B_1^n &\cdots& B_n^n \end{bmatrix} \begin {bmatrix} \boldsymbol b_0\\\boldsymbol b_1\\\vdots\\\boldsymbol b_n\end{bmatrix} P(t)=[B0nB1n⋯Bnn] b0b1⋮bn
只要对每个系数求导即可
B i n ( t ) ′ = i ( n i ) t i − 1 ( 1 − t ) n − i − ( n − i ) ( n i ) t i ( 1 − t ) n − i − 1 ⋯ ( 1 ) B_i^n(t)'=i\left (\begin{array}{l}n \\i \end{array} \right)t^{i-1}(1-t)^{n-i}-(n-i)\left (\begin{array}{l}n \\i \end{array} \right)t^i(1-t)^{n-i-1} \cdots (1) Bin(t)′=i(ni)ti−1(1−t)n−i−(n−i)(ni)ti(1−t)n−i−1⋯(1)
对组合数展开可以发现
B i n ( t ) ′ = n ( n − 1 i − 1 ) t i − 1 ( 1 − t ) n − i − n ( n − 1 i ) t i ( 1 − t ) n − i − 1 = n B i − 1 n − 1 ( t ) − n B i n − 1 ( t ) B_i^n(t)'=n\left (\begin{array}{cl}n-1 \\i-1 \end{array} \right)t^{i-1}(1-t)^{n-i}-n\left (\begin{array}{cl}n-1 \\i \end{array} \right)t^i(1-t)^{n-i-1}=nB_{i-1}^{n-1}(t)-nB_i^{n-1}(t) Bin(t)′=n(n−1i−1)ti−1(1−t)n−i−n(n−1i)ti(1−t)n−i−1=nBi−1n−1(t)−nBin−1(t)
从(1)式可知,当i=0时, B i − 1 n − 1 ( t ) = 0 B_{i-1}^{n-1}(t)=0 Bi−1n−1(t)=0
设 q i = B i n − 1 ( t ) 设q_i = B_{i}^{n-1}(t) 设qi=Bin−1(t)
P ′ ( t ) = n [ q 0 ⋯ q n − 1 ] [ b 1 ⋮ b n ] + n [ q 0 ⋯ q n − 1 ] [ − b 0 ⋮ − b n − 1 ] \boldsymbol P'(t)=n[q_0\ \cdots \ q_{n-1}] \begin {bmatrix} \boldsymbol b_1\\\vdots\\\boldsymbol b_n\end{bmatrix}+n[q_0\ \cdots \ q_{n-1}] \begin {bmatrix} -\boldsymbol b_0\\\vdots\\-\boldsymbol b_{n-1}\end{bmatrix} P′(t)=n[q0 ⋯ qn−1] b1⋮bn +n[q0 ⋯ qn−1] −b0⋮−bn−1
= ∑ i = 0 n − 1 B i n − 1 ( t ) ( b i + 1 − b i ) = \displaystyle \sum_{i=0}^{n-1}B_i^{n-1}(t)(\boldsymbol b_{i+1}-\boldsymbol b_i) =i=0∑n−1Bin−1(t)(bi+1−bi)
上式一共是n项,所以n阶bezier曲线的导数可以由n-1阶bezier曲线得到
控制点如下
D i = n ( b i + 1 − b i ) , i ∈ [ 0 , n − 1 ] D_i = n(b_{i+1}-b_i), i\in[0, n-1] Di=n(bi+1−bi),i∈[0,n−1]
导数的计算也可以由De Casteljau algorithm 来算
端点导数
将t=0, t=1代入公式,发现首末端的导数刚好是初始两点和末端两点连线的n倍。
高阶导数
参数曲线的d阶导为在d-1阶导数基础上再求一次导。
P ′ ′ ( t ) = ∑ i = 0 n − 2 B i n − 2 ( t ) ( ( n − 1 ) ( D i + 1 − D i ) ) \boldsymbol P''(t)= \displaystyle \sum_{i=0}^{n-2}B_i^{n-2}(t)((n-1)(\boldsymbol D_{i+1}-\boldsymbol D_i)) P′′(t)=i=0∑n−2Bin−2(t)((n−1)(Di+1−Di))
= n ( n − 1 ) ∑ i = 0 n − 2 B i n − 2 ( t ) ( b i + 2 − 2 b i + 1 + b i ) =n(n-1) \displaystyle \sum_{i=0}^{n-2}B_i^{n-2}(t)(\boldsymbol b_{i+2} -2\boldsymbol b_{i+1}+\boldsymbol b_i) =n(n−1)i=0∑n−2Bin−2(t)(bi+2−2bi+1+bi)
从u处打断
根据 De Casteljau algorithm 的过程可以观察到。
每次迭代后,数组中的第1个点和最后一个点,分别是左右子段的控制点。
/*!
*\brief Bezier曲线的打断
*\ param const std::vector<Point> & A 控制点序列
*\ param double u 打断处的参数 (0,1)
*\ param std::vector<Point> & cv_left 打断后前半部分的控制点
*\ param std::vector<Point> & cv_right 打断后后半部分的控制点
*\ Returns: std::pair<List2f, List2f>
*/
std::pair<List2f, List2f> subDevide(const std::vector<Eigen::Vector2f> &A, float u)
{
List2f cv_left = A;
List2f cv_right = A;
if(A.size()<2)return {cv_left, cv_right};
int p = A.size()-1;
//p次迭代
for (int i = 0;i<p;++i)
{
for (int j = 0;j<p - i;++j)
cv_right[j] = (1.0 - u)*cv_right[j] + u*cv_right[j + 1];
//左侧控制点为每次迭代的首点
cv_left[i + 1] = cv_right[0];
}
return {cv_left, cv_right};
}
升阶
设原来曲线控制点为b0, b1, … bn n+1个控制点,
升阶后的点为c0, c1, … cn, cn+1 n+2个控制点
c0=b0, cn+1=bn
中间控制点
c i = i n + 1 b i − 1 + ( 1 + i n + 1 ) b i , i ∈ [ 1 , n ] c_i = \frac {i}{n+1}b_{i-1} + (1+\frac{i}{n+1})b_i, i \in[1,n] ci=n+1ibi−1+(1+n+1i)bi,i∈[1,n]
List2f degreeElevation(const std::vector<Eigen::Vector2f> &A)
{
int n=A.size(); // 为公式中的n+1
List2f res (n+1);
res.front() = A[0];
res.back() = A.back();
for(int i=1;i<n;++i) {
float ratio = 1.0*i/n;
res[i] = ratio *A[i-1] + (1-ratio)*A[i];
}
return res;
}
实现
代码:
https://gitcode.com/chenbb1989/geometric_model/tree/master/gohw4-3
演示视频
besier 打断与升阶
打断
升阶
本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接,帮忙转发,感激不尽。