"""
Created on Fri May 24 09:04:23 2024
"""
import os
import sys
import math
import heapq
import matplotlib.pyplot as plt
import time
'''
传统A*算法
'''
class Astar:
'''
AStar set the cost + heuristics as the priority
AStar将成本+启发式设置为优先级
'''
def __init__(self, s_start, s_goal, heuristic_type, xI, xG):
self.s_start = s_start
self.s_goal = s_goal
self.heuristic_type = heuristic_type
self.u_set = [(-1, 0), (0, 1), (1, 0), (0, -1)]
self.Open = []
self.Closed = []
self.parent = dict()
self.g = dict()
self.x_range = 51
self.y_range = 51
self.xI, self.xG = xI, xG
self.obs = self.obs_map()
def animation(self, path_l, visited_l, name, path_color='g'):
obs_x = [x[0] for x in self.obs]
obs_y = [x[1] for x in self.obs]
plt.plot(self.xI[0], self.xI[1], "bs")
plt.plot(self.xG[0], self.xG[1], "gs")
plt.plot(obs_x, obs_y, "sk")
plt.title(name)
plt.axis("equal")
visited_l = [node for node in visited_l if node != self.xI and node != self.xG]
for x in visited_l:
plt.plot(x[0], x[1], color='gray', marker='o')
path_x = [point[0] for point in path_l]
path_y = [point[1] for point in path_l]
plt.plot(path_x, path_y, linewidth=3, color=path_color)
plt.show(block=True)
def obs_map(self):
"""
Initialize obstacles' positions
:return: map of obstacles
初始化障碍物位置
返回:障碍物
"""
x = 51
y = 31
self.obs = set()
self.obs.update((i, 0) for i in range(x))
self.obs.update((i, y - 1) for i in range(x))
self.obs.update((0, i) for i in range(y))
self.obs.update((x - 1, i) for i in range(y))
self.obs.update((i, 15) for i in range(10, 21))
self.obs.update((20, i) for i in range(15))
self.obs.update((30, i) for i in range(15, 30))
self.obs.update((40, i) for i in range(16))
return self.obs
def searching(self):
"""
A_star Searching.
:return: path, visited order
Astart搜索,返回路径、访问集,
"""
self.parent[self.s_start] = self.s_start
self.g[self.s_start] = 0
self.g[self.s_goal] = math.inf
heapq.heappush(self.Open, (self.f_value(self.s_start), self.s_start))
while self.Open:
_, s_current = heapq.heappop(self.Open)
self.Closed.append(s_current)
if s_current == self.s_goal:
break
for s_next in self.get_neighbor(s_current):
new_cost = self.g[s_current] + self.cost(s_current, s_next)
if s_next not in self.g:
self.g[s_next] = math.inf
if new_cost < self.g[s_next]:
self.g[s_next] = new_cost
self.parent[s_next] = s_current
heapq.heappush(self.Open, (self.f_value(s_next), s_next))
return self.extract_path(self.parent), self.Closed
def get_neighbor(self, s_current):
"""
:param s_current:
:return: 相邻点集合
"""
return [(s_current[0] + u[0], s_current[1] + u[1]) for u in self.u_set]
def cost(self, s_current, s_next):
"""
:param s_current 表示当前点
:param s_next 表示相邻点
:return 若与障碍物无冲突,则范围欧式距离成本,否则为无穷大成本
计算当前点与相邻点的距离成本
"""
if self.is_collision(s_current, s_next):
return math.inf
return math.hypot(s_next[0] - s_current[0], s_next[1] - s_current[1])
def is_collision(self, s_current, s_next):
"""
check if the line segment (s_start, s_end) is collision.
:param s_current: start node
:param s_next: end node
:return: True: is collision / False: not collision
检查起终点线段与障碍物是否冲突
如果线段的起点或终点之一位于障碍物集合 self.obs 内,则直接判定为碰撞,返回 True。
若线段不垂直也不水平(即斜线段),则分为两种情况检查:
若线段为45度线(斜率为1:1或-1),则检查线段的端点形成的矩形框内是否有障碍物。
否则检查线段端点形成的另一矩形框内是否有障碍物。
若上述任一矩形框内有障碍,则判定为碰撞,返回 True
若无碰撞情况,则返回 False
"""
if s_current in self.obs or s_next in self.obs:
return True
''''''
if s_current[0] != s_next[0] and s_current[1] != s_next[1]:
if s_next[0] - s_current[0] == s_current[1] - s_next[1]:
s1 = (min(s_current[0], s_next[0]), min(s_current[1], s_next[1]))
s2 = (max(s_current[0], s_next[0]), max(s_current[1], s_next[1]))
else:
s1 = (min(s_current[0], s_next[0]), max(s_current[1], s_next[1]))
s2 = (max(s_current[0], s_next[0]), min(s_current[1], s_next[1]))
if s1 in self.obs or s2 in self.obs:
return True
return False
def f_value(self, s_currrent):
"""
f = g + h. (g: Cost to come, h: heuristic value)
:param s: current state
:return: f
"""
return self.g[s_currrent] + self.heuristic(s_currrent)
def extract_path(self, parent):
path = [self.s_goal]
s = self.s_goal
while True:
s = parent[s]
path.append(s)
if s == self.s_start:
break
return list(path)
def heuristic(self, s_current):
heuristic_type = self.heuristic_type
goal = self.s_goal
if heuristic_type == "manhattan":
return abs(goal[0] - s_current[0]) + abs(goal[1] - s_current[1])
else:
return math.hypot(goal[0] - s_current[0], goal[1] - s_current[1])
if __name__ == '__main__':
time_start = time.time()
s_start = (5, 5)
s_goal = (45, 26)
star_m = Astar(s_start, s_goal, "ee", s_start, s_goal)
path, visited = star_m.searching()
star_m.animation(path, visited, "A*")
time_end = time.time()
print("程序运行时间:", time_end - time_start)