bezier_path.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. """
  2. bezier path
  3. author: Atsushi Sakai(@Atsushi_twi)
  4. modified: huiming zhou
  5. """
  6. import numpy as np
  7. import matplotlib.pyplot as plt
  8. from scipy.special import comb
  9. import draw
  10. def calc_4points_bezier_path(sx, sy, syaw, gx, gy, gyaw, offset):
  11. dist = np.hypot(sx - gx, sy - gy) / offset
  12. control_points = np.array(
  13. [[sx, sy],
  14. [sx + dist * np.cos(syaw), sy + dist * np.sin(syaw)],
  15. [gx - dist * np.cos(gyaw), gy - dist * np.sin(gyaw)],
  16. [gx, gy]])
  17. path = calc_bezier_path(control_points, n_points=100)
  18. return path, control_points
  19. def calc_bezier_path(control_points, n_points=100):
  20. traj = []
  21. for t in np.linspace(0, 1, n_points):
  22. traj.append(bezier(t, control_points))
  23. return np.array(traj)
  24. def Comb(n, i, t):
  25. return comb(n, i) * t ** i * (1 - t) ** (n - i)
  26. def bezier(t, control_points):
  27. n = len(control_points) - 1
  28. return np.sum([Comb(n, i, t) * control_points[i] for i in range(n + 1)], axis=0)
  29. def bezier_derivatives_control_points(control_points, n_derivatives):
  30. w = {0: control_points}
  31. for i in range(n_derivatives):
  32. n = len(w[i])
  33. w[i + 1] = np.array([(n - 1) * (w[i][j + 1] - w[i][j])
  34. for j in range(n - 1)])
  35. return w
  36. def curvature(dx, dy, ddx, ddy):
  37. return (dx * ddy - dy * ddx) / (dx ** 2 + dy ** 2) ** (3 / 2)
  38. def simulation():
  39. sx = [-3, 0, 4, 6]
  40. sy = [2, 0, 1.5, 6]
  41. ratio = np.linspace(0, 1, 100)
  42. pathx, pathy = [], []
  43. for t in ratio:
  44. x, y = [], []
  45. for i in range(len(sx) - 1):
  46. x.append(sx[i + 1] * t + sx[i] * (1 - t))
  47. y.append(sy[i + 1] * t + sy[i] * (1 - t))
  48. xx, yy = [], []
  49. for i in range(len(x) - 1):
  50. xx.append(x[i + 1] * t + x[i] * (1 - t))
  51. yy.append(y[i + 1] * t + y[i] * (1 - t))
  52. px = xx[1] * t + xx[0] * (1 - t)
  53. py = yy[1] * t + yy[0] * (1 - t)
  54. pathx.append(px)
  55. pathy.append(py)
  56. plt.cla()
  57. plt.plot(sx, sy, linestyle='-', marker='o', color='dimgray', label="Control Points")
  58. plt.plot(x, y, color='dodgerblue')
  59. plt.plot(xx, yy, color='cyan')
  60. plt.plot(pathx, pathy, color='darkorange', linewidth=2, label="Bezier Path")
  61. plt.plot(px, py, marker='o')
  62. plt.axis("equal")
  63. plt.legend()
  64. plt.title("Cubic Bezier Curve demo")
  65. plt.grid(True)
  66. plt.pause(0.001)
  67. plt.show()
  68. def main():
  69. sx, sy, syaw = 10.0, 1.0, np.deg2rad(180.0)
  70. gx, gy, gyaw = 0.0, -3.0, np.deg2rad(-45.0)
  71. offset = 3.0
  72. path, control_points = calc_4points_bezier_path(sx, sy, syaw, gx, gy, gyaw, offset)
  73. t = 0.8 # Number in [0, 1]
  74. x_target, y_target = bezier(t, control_points)
  75. derivatives_cp = bezier_derivatives_control_points(control_points, 2)
  76. point = bezier(t, control_points)
  77. dt = bezier(t, derivatives_cp[1])
  78. ddt = bezier(t, derivatives_cp[2])
  79. # Radius of curv
  80. radius = 1 / curvature(dt[0], dt[1], ddt[0], ddt[1])
  81. # Normalize derivative
  82. dt /= np.linalg.norm(dt, 2)
  83. tangent = np.array([point, point + dt])
  84. normal = np.array([point, point + [- dt[1], dt[0]]])
  85. curvature_center = point + np.array([- dt[1], dt[0]]) * radius
  86. circle = plt.Circle(tuple(curvature_center), radius,
  87. color=(0, 0.8, 0.8), fill=False, linewidth=1)
  88. assert path.T[0][0] == sx, "path is invalid"
  89. assert path.T[1][0] == sy, "path is invalid"
  90. assert path.T[0][-1] == gx, "path is invalid"
  91. assert path.T[1][-1] == gy, "path is invalid"
  92. fig, ax = plt.subplots()
  93. ax.plot(path.T[0], path.T[1], label="Bezier Path")
  94. ax.plot(control_points.T[0], control_points.T[1],
  95. '--o', label="Control Points")
  96. ax.plot(x_target, y_target)
  97. ax.plot(tangent[:, 0], tangent[:, 1], label="Tangent")
  98. ax.plot(normal[:, 0], normal[:, 1], label="Normal")
  99. ax.add_artist(circle)
  100. draw.Arrow(sx, sy, syaw, 1, "darkorange")
  101. draw.Arrow(gx, gy, gyaw, 1, "darkorange")
  102. plt.grid(True)
  103. plt.title("Bezier Path: from Atsushi's work")
  104. ax.axis("equal")
  105. plt.show()
  106. if __name__ == '__main__':
  107. main()
  108. # simulation()