在曲线拟合问题中,通常需要根据已知曲线上的离散点,估算出曲线在端点处的导数(严格来说是导矢),常用的一种导数估计方法称为“Bessel Tangent”方法。
已知点P_{i-1},P_i,P_{i+1},求一种导数(矢)估算算法,计算P_{i-1}^\prime,P_i^\prime,P_{i+1}^\prime。Bessel tangent 算法的主要思路是,插值一条通过三点的二次曲线,然后通过计算曲线上三点的导数的方式给出三点的估计导数。
令 P_{i-1},P_{i},P_{i+1} 的参数分别为 t_{i-1},t_{i},t_{i+1}
插值的曲线的表达式如下:
P(t)=\frac{(t-t_i)(t-t_{i+1})}{(t_{i-1}-t_i)(t_{i-1}-t_{i+1})}(P_{i-1}-P_{i})+\frac{(t-t_{i-1})(t-t_{i})}{(t_{i+1}-t_{i-1})(t_{i+1}-t_{i})}(P_{i+1}-P_{i})+P_{i}\tag1
1) P_i导数
P(t_i)^\prime=\frac{t_i-t_{i+1}}{(t_{i-1}-t_i)(t_{i-1}-t_{i+1})}(P_{i-1}-P_{i})+\frac{t_i-t_{i-1}}{(t_{i+1}-t_{i-1})(t_{i+1}-t_{i})}(P_{i+1}-P_{i})
令 \triangle t_i = t_{i+1}-t_i;\triangle P_i=\frac{P_{i+1}-P_i}{\triangle t_i}
\begin{align} P(t_i)^\prime&=\frac{t_i-t_{i+1}}{t_{i-1}-t_{i+1}}\triangle P_{i-1}+\frac{t_i-t_{i-1}}{t_{i+1}-t_{i-1}}\triangle P_{i}\\ &= \frac{t_i-t_{i+1}}{t_{i-1}-t_{i+1}}\triangle P_{i-1}+\frac{t_i-t_{i-1}}{t_{i+1}-t_{i-1}}\triangle P_{i} \\ &= \frac{\triangle t_{i}}{t_{i+1}-t_{i}+t_{i}-t_{i-1}}\triangle P_{i-1} + \frac{\triangle t_{i-1}}{t_{i+1}-t_{i}+t_{i}-t_{i-1}}\triangle P_{i}\\ &=\frac{\triangle t_{i}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i-1}+\frac{\triangle t_{i-1}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i} \tag2 \end{align}即P_i^\prime是\triangle P_{i-1},\triangle P_{i}的加权平均。
2)P_{i-1},P_{i+1}导数
根据公式(1)
\begin{align} P(t_{i-1})^\prime&=\frac{2t_{i-1}-2t_{i+1}+t_{i+1}-t_{i}}{t_{i-1}-t_{i+1}}\triangle P_{i-1}+\frac{t_{i-1}-t_{i}}{t_{i+1}-t_{i-1}}\triangle P_{i}\\ &=2\triangle P_{i-1}-(\frac{\triangle t_{i}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i-1}+\frac{\triangle t_{i-1}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i})\\ &=2\triangle P_{i-1}-P(t_i)^\prime \tag3 \end{align}
\begin{align} P(t_{i+1})^\prime&=-(\frac{\triangle t_{i}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i-1}+\frac{\triangle t_{i-1}}{\triangle t_{i}+\triangle t_{i-1}}\triangle P_{i} )+2\triangle P_i \\ &=2\triangle P_i-P(t_{i})^\prime \tag4 \end{align}
参数化的选择
对于三点的参数可以按照累计弦长化确定参数 \left\{ \begin{aligned} t_{i-1} & = 0 \\ t_{i} & = t_0+|P_{i-1}P_i| \\ t_{i+1} & = t_1+|P_iP_{i+1}| \end{aligned} \right.
我对算法的C++实现是:
/*! *\brief Bessel Tangent 方法估算导数 *\ param const Point & p0,p1,p2 待求点 *\ param Vec3d & p0deriv,p1deriv,p2deriv 三点上导数的估计值 *\ Returns: */ void BesselTanget(const Point& p0,const Point& p1,const Point& p2, Vec3d& p0deriv,Vec3d& p1deriv,Vec3d& p2deriv) { double delta_t1 =PointDistance(p2,p1); double delta_t0 = PointDistance(p1,p0); Vec3d delta_p0 = (p1-p0)/delta_t0; Vec3d delta_p1 = (p2-p1)/delta_t1; double sum = delta_t0+delta_t1; p1deriv = delta_t1/sum * delta_p0 + delta_t0/sum * delta_p1; p0deriv = 2*delta_p0 - p1deriv; p2deriv = 2*delta_p1 - p1deriv; }
参考资料:
The Essentials of CAGD : Chapter 11 Working with B Spline Curves
于谦. 基于切向约束的二次B样条插值曲线的研究[D]. 山东大学, 2009.
即P_i^\prime是\triangle P_{i-1},\triangle P_{i-1}的加权平均
应为
即P_i^\prime是\triangle P_{i-1},\triangle P_{i}的加权平均
谢谢,已经改正。
P′i−1+P′i=2△Pi−1 这个是怎么来的,推导不出来。 能推导一下么。
你好,现在已经对文章内容进行了增补,推导过程在公式(3)(4)中,就是对公式(1)求导后进行一些变换后得出的结果,供您参考