如何强制贝塞尔曲线首尾法向加速度(曲率)为零且保持平滑
解决方案
你需要的边界法向加速度为0(等价于曲率为0)有严格的解析实现方案,不需要调整权重做近似,只要满足贝塞尔曲线首尾控制点的共线条件即可,实现的是绝对零值效果,同时不破坏曲线本身的平滑性。
核心逻辑
对于你使用的4阶贝塞尔曲线(共5个控制点,记为$P_0$到$P_4$),曲率为0的充要条件是边界处的一阶导数(速度)与二阶导数(加速度)共线,对应到控制点的约束为:
- 起始点$t=0$处曲率为0:$P_0$、$P_1$、$P_2$三个控制点共线
- 终止点$t=1$处曲率为0:$P_2$、$P_3$、$P_4$三个控制点共线
贝塞尔曲线本身是无穷阶可导的,满足上述约束后曲线依然保持全程平滑。
修改后的代码示例
我们可以在生成控制点时直接加入上述共线约束,运行后可见首尾法向加速度为浮点数误差级别的接近零值:
import numpy as np from scipy.special import comb import matplotlib.pyplot as plt # 贝塞尔曲线对应控制点数量 N = 5 # 生成满足边界曲率为0的控制点 np.random.seed(2) # 仅随机生成3个关键控制点P0、P2、P4,其余控制点根据共线约束计算 key_points = np.random.rand(3, 2) P0, P2, P4 = key_points[0], key_points[1], key_points[2] # P1取P0到P2连线的中点,比例可按需调整,只要共线即可 P1 = P0 + 0.5 * (P2 - P0) # P3取P2到P4连线的中点,比例可按需调整,只要共线即可 P3 = P2 + 0.5 * (P4 - P2) points = np.array([P0, P1, P2, P3, P4]) ''' 计算贝塞尔曲线 ''' t = np.linspace(0, 1, 1000) polys = np.asarray([comb(N-1, i) * ((1-t)**(N-1-i)) * t**i for i in range(N)]) curve = points.T @ polys curve = curve.T ''' 计算法向加速度 ''' velocity = np.gradient(curve, axis=0) * t.shape[0] acceleration = np.gradient(velocity, axis=0) * t.shape[0] vel_sq = np.sum(velocity ** 2, axis=1, keepdims=True) + 1e-12 # 加小量避免除以零 a_tangent = (np.sum(acceleration * velocity, axis=1, keepdims=True) / vel_sq) * velocity a_normal = acceleration - a_tangent a_normal_mag = np.linalg.norm(a_normal, axis=1) # 输出首尾法向加速度验证结果 print(f"t=0处法向加速度: {a_normal_mag[0]:.16f}") print(f"t=1处法向加速度: {a_normal_mag[-1]:.16f}") ''' 可视化 ''' fig, axes = plt.subplots(1, 2, figsize=(10, 4)) axes[0].scatter(points[:, 0], points[:, 1], c='red', label='控制点') axes[0].plot(curve[:, 0], curve[:, 1], label='贝塞尔曲线') axes[0].set_xlabel('x(t)') axes[0].set_ylabel('y(t)') axes[0].legend() axes[1].plot(t, a_normal_mag) axes[1].set_xlabel('t') axes[1].set_ylabel('a_n(t)') plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Thomas Wagenaar
相关产品推荐
相关产品推荐

