本文仅作为学习记录。
贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。于1962年由法国工程师皮埃尔·贝塞尔( Pierre Bézier)发表,他运用贝塞尔曲线来为汽车的主体进行设计。
贝塞尔曲线是应用于二维图形应用程序的数学曲线,由一组称为控制点的向量来确定,给定的控制点按顺序连接构成控制多边形,贝塞尔曲线逼近这个多边形,进而通过调整控制点坐标改变曲线的形状。控制点的作用是控制曲线的弯曲程度
对于n阶贝塞尔曲线,只需要n+1个控制点即可生成。
该网址有一个贝塞尔曲线展示:贝塞尔曲线展示
参考文章:贝塞尔曲线法
参考文章:贝塞尔曲线性质
我关注到的博客中的一些点:
P 0 P_0 P0和 P n P_n Pn分别位于贝塞尔曲线的起点和终点。(所以,控制点的起点和终点可以是路径的起点和终点。)
起点和终点处的切线方向与和特征多边形的第一条边及最后一条边分别相切,换句话说,可根据曲线的起始点和终止点的切线方向确定车辆起始点姿态和目标点姿态;
至少需要三阶贝塞尔曲线(四个控制点)才能生成曲率连续的路径。
博客里特别提到:
城市环境下局部路径规划,如贝塞尔曲线能够拟合直道和弯道,在曲率变化较大的地方可以选用两个贝塞尔曲线来拟合。
无人驾驶车辆的运动规划,目标轨迹曲率是连续的且轨迹的曲率不超过车辆可行驶轨迹曲率的限制。
def BezierNormal(PointList, time):
"""
:param PointList: 控制点列表
:param time: 时间变量
:return: Pt 贝塞尔曲线点
"""
BezierOrder = len(PointList)
if BezierOrder == 1:
return PointList
BezierOrder = len(PointList) - 1
Pt = []
for t in np.arange(0.0, time, 0.01):
cur = np.array([0, 0])
for i in range(BezierOrder+1):
C_n_i = math.factorial(BezierOrder)/(math.factorial(i)*math.factorial(BezierOrder-i))
cur = cur + C_n_i * (1-t) ** (BezierOrder - i) * (t ** i) * PointList[i]
Pt.append(cur)
return Pt
def bezier_curve_res(PointList, time):
'''
Args:
PointList 控制点列表
time 时间变量
Returns:
_type_: 当前t时刻的贝塞尔点
'''
n = len(PointList)
if n == 1:
return PointList[0]
BezierOrder = n - 1
return (1-time) * bezier_curve_res(PointList[0:n-1], time) + (time) * bezier_curve_res(PointList[1:n], time)
def BezierCurveRes(PointsList, time):
'''
Args:
PointsList 控制点列表
time 时间变量
Returns:
Pos 贝塞尔曲线点
'''
Pos = []
for t in np.arange(0, time, 0.01):
Pos.append(bezier_curve_res(PointsList, t))
return Pos
def main():
Ps = np.array([[0, 0], [1, 1], [2, 1], [3, 0], [3, 1]])
pos = BezierNormal(Ps, 1.0)
plt.plot(Ps[:, 0], Ps[:, 1])
print(Ps[:, 0], Ps[:, 1], type(Ps))
pos = np.array(pos)
print(pos)
plt.scatter(pos[:, 0], pos[:, 1], c='r')
plt.show()
Pos = BezierCurveRes(Ps, 1)
print("Pos:",Pos)
Pos = np.array(Pos)
plt.plot(Ps[:, 0], Ps[:, 1])
plt.scatter(Pos[:, 0], Pos[:, 1], c='r')
plt.pause(0.001)
plt.show()
if __name__ == "__main__":
main()
包括了递归实现和常规实现。