根据上一篇文章介绍的方法进行匀速贝塞尔曲线运动时,实际使用时会发现两个问题。
计算失效问题
当\(A=0\),此时不能用\(L(t)\)计算二阶贝塞尔曲线的长度:
\[\begin{align}L(t) =& \frac{1}{8A^\frac{3}{2}} \big(T_1T_0-T_2ln(T_1+T_0) \\&- BT_3+T_2ln(B+T_3) \big) \\T_0 =& 2\sqrt{A}\sqrt{C+Bt+At^2} \\T_1 =& B+2At \\T_2 =& B^2-4AC \\T_3 =& 2\sqrt{AC}\end{align}\]
同时当\(P_0\) \(P_1\) \(P_2\)三点共线时,\(L(1.0)=Nan\),需要使用匀速直线运动方法进行计算。
加速度问题
当把Python代码中三个点的坐标替换为:- P0 = np.array([636.593750,684.976562]) # 起点
- P1 = np.array([636.593750,685.218750]) # 控制点
- P2 = np.array([672.511719,682.589844]) # 终点
复制代码 会得到如下结果:
通过打印\(t_n\)的值发现其部分\(>1\),通过回顾\(t_n\)的计算公式:
\[\begin{align}t_n=t_{n-1}+\frac{\frac{n}{N}L(1.0)-L(t_{n-1})}{s(t_{n-1})} \quad,\quad n\in[1, N]\end{align}\]
我们只考虑了速度\(s(t)\),并没有考虑加速度,通过对\(V(t)\)求导可以得到加速度:
\[\begin{align}F(t)=&V'(t) \\=&2\begin{bmatrix}x_0 \\y_0 \\\end{bmatrix}-4\begin{bmatrix}x_1 \\y_1 \\\end{bmatrix}+2\begin{bmatrix}x_2 \\y_2 \\\end{bmatrix}\end{align}\]
同样对其取模,舍弃方向:
\[\begin{align}f =& \Vert F(t) \Vert \\=& \sqrt{a_x^2+a_y^2} \\=& \sqrt{A}\end{align}\]
加速度为固定值,也就是恒加速度运动。最终\(t_n\)公式修改为:
\[\begin{align}t_n =& t_{n-1} + \Delta{t} \\\Delta{t} =& \frac{-s(t_{n-1})+\sqrt{s^2(t_{n-1})+2f\Big(\frac{n}{N}L(1.0)-L(t_{n-1})\Big)}}{f}\end{align}\]
将之前的Python进行修改如下:- import numpy as np
- import matplotlib.pyplot as plt
- import sys
- def bezier_length(A, B, C, t): # 二阶贝塞尔曲线长度
- T0 = 2 * np.sqrt(A) * np.sqrt(C + B * t + A * t * t)
- T1 = B + 2 * A * t
- T2 = B * B - 4 * A * C
- T3 = 2 * np.sqrt(A * C)
- return 1 / (8 * np.pow(A, 1.5)) * (T0 * T1 - T2 * np.log(T1 + T0) - B * T3 + T2 * np.log(B + T3))
- def bezier_velocity(A, B, C, t): # 二阶贝塞尔曲线速度
- return np.sqrt(C + B * t + A * t * t)
- def bezier_movement(p0, p1, p2, N): # 二阶贝塞尔曲线等距移动
- a = 2 * p0 - 4 * p1 + 2 * p2
- b = -2 * p0 + 2 * p1
- A = a[0] * a[0] + a[1] * a[1]
- B = 2 * a[0] * b[0] + 2 * a[1] * b[1]
- C = b[0] * b[0] + b[1] * b[1]
- f = np.sqrt(A)
- L1 = bezier_length(A, B, C, 1)
- print(A, B, C, L1)
- tn = 0
- res = np.zeros((N + 1, 2))
- for n in range(N + 1):
- print(tn)
- res[n] = (1 - tn) * (1 - tn) * p0 + 2 * tn * (1 - tn) * p1 + tn * tn * p2
- v = bezier_velocity(A, B, C, tn)
- l = ((n + 1) / N * L1 - bezier_length(A, B, C, tn))
- delta_t = (-v + np.sqrt(v * v + 2 * f * l)) / f
- tn = tn + delta_t
- return res
- P0 = np.array([636.593750, 684.976562]) # 起点
- P1 = np.array([636.593750, 685.218750]) # 控制点
- P2 = np.array([672.511719, 682.589844]) # 终点
- N = 10
- if len(sys.argv) > 1:
- N = int(sys.argv[1])
- curve = bezier_movement(P0, P1, P2, N)
- plt.figure(figsize=(10, 6))
- plt.plot([P0[0], P1[0], P2[0]], [P0[1], P1[1], P2[1]], 'ro--', label='Control-Line')
- plt.plot(curve[:, 0], curve[:, 1], 'o', linewidth=2, label='Bezier movement')
- plt.text(P0[0], P0[1], 'P0', fontsize=12, ha='right', va='top')
- plt.text(P1[0], P1[1], 'P1', fontsize=12, ha='center', va='bottom')
- plt.text(P2[0], P2[1], 'P2', fontsize=12, ha='left', va='top')
- plt.title('Bezier Curve(N=' + str(N) + ')', fontsize=14)
- plt.xlabel('X-axis', fontsize=12)
- plt.ylabel('Y-axis', fontsize=12)
- plt.grid(True, linestyle='--', alpha=0.7)
- plt.legend()
- plt.axis('equal')
- plt.show()
复制代码 最终运行结果如下图所示:
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |