From 3d358609bbebf66ae43996ec93f68b7f90b13d7b Mon Sep 17 00:00:00 2001 From: weixin_46229132 Date: Tue, 6 May 2025 09:43:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E8=88=AA=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- navigate_gui.py | 505 ++++++++++++++++++++++++++++++++++++++++++++++++ test.py | 289 --------------------------- 2 files changed, 505 insertions(+), 289 deletions(-) create mode 100644 navigate_gui.py delete mode 100644 test.py diff --git a/navigate_gui.py b/navigate_gui.py new file mode 100644 index 0000000..5efd9c3 --- /dev/null +++ b/navigate_gui.py @@ -0,0 +1,505 @@ +import heapq +import os +import random +import tkinter as tk +from collections import deque +from tkinter import messagebox + +import cv2 +import numpy as np + +# 停车场布局数据 +left_side = list(range(119, 132)) +right_side = list(range(99, 87, -1)) + +# 将右侧车位编号转换为三位数格式(例如:099, 098, ...) +right_side = [str(number).zfill(3) for number in right_side] + +entry_left = [117, 115, 113] +entry_right = [108, 106, 104, 102, 101, 100] +p_row1 = [118, 116, 114, 112, 111, 110, None, 109, 107, 105, 103] +middle_bottom_row1 = [292, 290, 288, 286, 284, 282, 280, 278, 276, 274, 272] +middle_top_row2 = [293, 291, 289, 287, 285, 283, 281, 279, 277, 275, 273, 271] +middle_bottom_row2 = list(range(259, 271)) +middle_top_row3 = [None] * 10 + [00] + [None] +middle_bottom_row3 = [258, 257, 256, None, None, + None, None, None, None, 255, 254, None] + +# 样式参数 +car_space_width = 40 +car_space_height = 80 +road_width = 40 +margin = 0 +canvas_width = 12 * car_space_width + road_width * \ + 2 + 2 * car_space_height + 11 * margin +canvas_height = 4 * road_width + 7 * car_space_height + 3 * margin +middle_area_offset_y = 100 # 中间区域整体下移 + +# 车位状态对应颜色 +status_color = { + "free": "lightgreen", + "occupied": "tomato", +} + +default_color = "white" +selected_color = "cyan" # 搜索高亮颜色 + +# 设置 YOLO 检测结果路径 +detection_folder = r"D:\car2\parking_folders" + + +# A*算法的启发式函数 +def heuristic(a, b): + return abs(a[0] - b[0]) + abs(a[1] - b[1]) # 曼哈顿距离 + + +class ParkingLot(tk.Tk): + def __init__(self): + super().__init__() + self.title("停车场平面图 🚗") + self.geometry(f"{canvas_width}x{canvas_height}") + self.canvas = tk.Canvas(self, width=canvas_width, + height=canvas_height, bg="#CCCCCC") + self.canvas.pack() + + # 搜索部分 + self.search_entry = tk.Entry(self) + self.search_entry.pack(pady=5) + self.search_button = tk.Button( + self, text="搜索车位", command=self.search_spot) + self.search_button.pack(pady=5) + + self.spots = {} # 存储车位信息 + self.path = [] # 存储路径 + self.parkpot = {} + self.grid = self.get_grid() + self.obstacles = [] # 存储障碍物坐标 + self.get_parkpot() + self.current_path = [] + self.draw_parking_lot() + + def get_grid(self): + row = int(canvas_height / 40) + column = int(canvas_width / 40) + grid = np.zeros((row, column), np.int64) + for i in range(4): + for j in range(14): + grid[2 + 5 * i][2 + j] = 1 + for i in range(2): + grid[3:, 2 + i * 13] = 1 + grid[:2, 8] = 1 + return grid + + def get_parkpot(self): + """获取车位入口坐标""" + for idx, name in enumerate(left_side): + self.parkpot[name] = (3 + idx, 2, "left") + for idx, name in enumerate(right_side): + self.parkpot[name] = (3 + idx, 15, "right") + for idx, name in enumerate(entry_left): + self.parkpot[name] = (2, 4 + idx, "up") + for idx, name in enumerate(entry_right): + self.parkpot[name] = (2, 10 + idx, "up") + for idx, name in enumerate(p_row1): + self.parkpot[name] = (2, 4 + idx, "down") + for idx, name in enumerate(middle_bottom_row1): + self.parkpot[name] = (7, 4 + idx, "up") + for idx, name in enumerate(middle_top_row2): + self.parkpot[name] = (7, 3 + idx, "down") + for idx, name in enumerate(middle_bottom_row2): + self.parkpot[name] = (12, 3 + idx, "up") + for idx, name in enumerate(middle_top_row3): + self.parkpot[name] = (12, 3 + idx, "down") + for idx, name in enumerate(middle_bottom_row3): + self.parkpot[name] = (17, 3 + idx, "up") + + def draw_parking_lot(self): + # 入口灰色路 + inx_start = 5 * car_space_width + road_width + car_space_height + 5 * margin + self.canvas.create_rectangle( + inx_start, 0, inx_start + road_width, car_space_height, fill="gray", outline="gray" + ) + self.canvas.create_text( + inx_start + road_width / 2, 20, text="入口", fill="red", font=("Arial", 16)) + self.canvas.create_rectangle( + car_space_height, + car_space_height, + canvas_width - car_space_height, + car_space_height + road_width, + fill="gray", + outline="gray", + ) + self.canvas.create_rectangle( + car_space_height, + car_space_height + road_width, + car_space_height + road_width, + canvas_height, + fill="gray", + outline="gray", + ) + self.canvas.create_rectangle( + canvas_width - car_space_height - road_width, + car_space_height + road_width, + canvas_width - car_space_height, + canvas_height, + fill="gray", + outline="gray", + ) + self.canvas.create_rectangle( + car_space_height, + 3 * car_space_height + margin + road_width, + canvas_width - car_space_height, + 3 * car_space_height + margin + road_width + road_width, + fill="gray", + outline="gray", + ) + self.canvas.create_rectangle( + car_space_height, + 5 * car_space_height + 2 * margin + 2 * road_width, + canvas_width - car_space_height, + 5 * car_space_height + 2 * margin + 2 * road_width + road_width, + fill="gray", + outline="gray", + ) + self.canvas.create_rectangle( + car_space_height, + canvas_height - road_width, + canvas_width - car_space_height, + canvas_height, + fill="gray", + outline="gray", + ) + self.canvas.create_line(inx_start + road_width / 2, 30, + inx_start + road_width / 2, 100, fill="blue", width=5) + + # 入口两边车位 + for idx, number in enumerate(entry_left): + x = car_space_height + road_width + car_space_width + \ + idx * (car_space_width + margin) + margin + y = 0 + self.draw_parking_spot(x, y, number, direction="down") + + for idx, number in enumerate(entry_right): + x = inx_start + road_width + car_space_width + \ + idx * (car_space_width + margin) + margin * 2 + y = 0 + self.draw_parking_spot(x, y, number, direction="down") + + # 左右两列 + for idx, number in enumerate(left_side): + x = 0 + y = car_space_height + road_width + \ + idx * (car_space_width + margin) + self.draw_parking_spot(x, y, number, direction="right") + + for idx, number in enumerate(right_side): + x = canvas_width - car_space_height + y = road_width + car_space_height + \ + idx * (car_space_width + margin) + self.draw_parking_spot(x, y, number, direction="left") + + # 中间区域 + start_y = car_space_height + road_width + start_x = car_space_height + road_width + margin + car_space_width + self.draw_middle_row(start_x, start_y, p_row1, up=True) + self.draw_middle_row( + start_x, + start_y + car_space_height + margin, + middle_bottom_row1, + up=False, + ) + + start_y += road_width + margin + 2 * car_space_height + start_x -= car_space_width + margin + self.draw_middle_row(start_x, start_y, middle_top_row2, up=True) + self.draw_middle_row( + start_x, start_y + car_space_height + margin, middle_bottom_row2, up=False) + + start_y += road_width + margin + 2 * car_space_height + self.draw_middle_row(start_x, start_y, middle_top_row3, up=True) + self.draw_middle_row( + start_x, start_y + car_space_height + margin, middle_bottom_row3, up=False) + + def draw_middle_row(self, start_x, start_y, row_data, up=True): + """ + 绘制中间行的停车位。 + :param start_y: 行起始的y坐标 + :param row_data: 行数据,包含停车位编号的列表 + :param up: 布尔值,指示停车位的头部方向,默认为True(向上) + """ + current_x = start_x + + for number in row_data: + # 绘制停车位矩形,去掉边框 + rect = self.canvas.create_rectangle( + current_x, + start_y, + current_x + car_space_width, + start_y + car_space_height, + fill=default_color, + # outline="#CCCCCC", # 修改:将边框颜色设置为与背景相同的颜色 + ) + + if number is not None: + # 初始随机给状态 + status = random.choice(["free", "occupied"]) + # 存储停车位信息 + self.spots[rect] = {"number": number, "status": status} + # 绘制指向停车位的箭头 + self.draw_arrow(current_x, start_y, "up" if up else "down") + # 绘制停车位编号 + self.canvas.create_text( + current_x + car_space_width / 2, + start_y + car_space_height / 2, + text=str(number), + font=("Arial", 8), + ) + # 绑定点击事件以切换停车位状态 + self.canvas.tag_bind(rect, "", self.toggle_spot) + # 按状态上色 + fill_color = status_color.get(status, default_color) + self.canvas.itemconfig(rect, fill=fill_color) + + # 添加障碍物坐标 + self.obstacles.append((current_x, start_y)) + + # 更新当前x坐标以绘制下一个停车位 + current_x += car_space_width + margin + + def draw_arrow(self, x, y, direction): + if direction == "up": + points = [ + x + car_space_width / 2, + y + 10, + x + 10, + y + 30, + x + car_space_width - 10, + y + 30, + ] + elif direction == "down": + points = [ + x + car_space_width / 2, + y + car_space_height - 10, + x + 10, + y + car_space_height - 30, + x + car_space_width - 10, + y + car_space_height - 30, + ] + elif direction == "right": + points = [ + x + car_space_height - 5, + y + car_space_width / 2, + x + car_space_height - 20, + y + 5, + x + car_space_height - 20, + y + car_space_width - 5, + ] + else: + points = [ + x + 5, + y + car_space_width / 2, + x + 20, + y + 5, + x + 20, + y + car_space_width - 5, + ] + self.canvas.create_polygon(points, fill="black") + + def draw_parking_spot(self, x, y, number, direction="up"): + if direction not in ["left", "right"]: + rect = self.canvas.create_rectangle( + x, y, x + car_space_width, y + car_space_height, fill=default_color, outline="black" + ) + elif direction == "left": + rect = self.canvas.create_rectangle( + x, y, x + car_space_height, y + car_space_width, fill=default_color, outline="black" + ) + else: + rect = self.canvas.create_rectangle( + x, y, x + car_space_height, y + car_space_width, fill=default_color, outline="black" + ) + # 获取车位编号对应的YOLO检测结果图像路径 + detection_image_path = os.path.join( + detection_folder, f"{number}.jpg") # 假设图像以车位编号命名 + + # 检查文件是否存在 + if os.path.exists(detection_image_path): + # 读取 YOLO 检测结果图像(假设是红绿图像,红色表示有车,绿色表示空位) + detection_image = cv2.imread(detection_image_path) + + # 检查图片是否为空 + if detection_image is not None: + # 假设检测图像中左上角是车位的检测状态,我们可以检查该区域的颜色 + # 获取车位区域的颜色 + region_color = detection_image[10, 10] # 假设检测图像左上角有车位状态信息 + + # 判断颜色,红色表示有车,绿色表示空位 + if np.array_equal(region_color, [0, 0, 255]): # 红色 + status = "occupied" + elif np.array_equal(region_color, [0, 255, 0]): # 绿色 + status = "free" + else: + status = "free" # 默认状态为免费 + else: + status = "free" # 默认状态为免费,如果读取失败 + else: + status = "free" # 默认状态为免费,如果没有检测结果 + + self.spots[rect] = {"number": number, "status": status} + + # 绘制箭头 + self.draw_arrow(x, y, direction) + + # 绘制车位编号 + if direction not in ["left", "right"]: + self.canvas.create_text( + x + car_space_width / 2, + y + car_space_height / 2, + text=str(number), + font=("Arial", 8), + ) + else: + self.canvas.create_text( + x + car_space_height / 2, + y + car_space_width / 2, + text=str(number), + font=("Arial", 8), + ) + # 绑定点击事件 + self.canvas.tag_bind(rect, "", self.toggle_spot) + + # 按状态设置颜色 + fill_color = status_color.get(status, default_color) + self.canvas.itemconfig(rect, fill=fill_color) + + def find_path(self, matrix): + # 定义起点和终点 + start = (0, 8) + end = None + for i in range(len(matrix)): + for j in range(len(matrix[0])): + if matrix[i][j] == 2: + end = (i, j) + break + if end: + break + + # 定义方向数组,表示上下左右四个方向 + directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + + # 初始化队列,存储当前坐标和路径 + queue = deque() + queue.append((start, [start])) + + # 初始化访问标记数组 + visited = [[False for _ in range(len(matrix[0]))] + for _ in range(len(matrix))] + visited[start[0]][start[1]] = True + + # 开始 BFS + while queue: + (x, y), path = queue.popleft() + + # 如果当前点是终点,返回路径 + if (x, y) == end: + return path # 返回找到的路径 + + # 检查四个方向 + for dx, dy in directions: + nx, ny = x + dx, y + dy + # 判断新坐标是否在矩阵范围内,并且是路径或目的地且未被访问过 + if 0 <= nx < len(matrix) and 0 <= ny < len(matrix[0]): + if matrix[nx][ny] in [1, 2] and not visited[nx][ny]: + visited[nx][ny] = True + queue.append(((nx, ny), path + [(nx, ny)])) + + return [] # 如果没有找到路径,返回空列表 + + def toggle_spot(self, event): + clicked = event.widget.find_withtag("current")[0] + spot = self.spots.get(clicked) + + if spot["status"] != "free": + messagebox.showinfo("提示", "该车位已满,请选择其他车位!") + else: + messagebox.showinfo( + "车位信息", + f"车位编号: {spot['number']}\n状态: {spot['status']}", + ) + coords = self.canvas.coords(clicked) + X1, Y1, X2, Y2 = coords + # X1 = X1*40+20 + # Y1 = Y1*40+20 + # X2=X2*40+20 + # Y2=Y2*40+20 + number = spot["number"] + parkspot = self.parkpot[number] + + # 清除之前的路径 + self.clear_previous_path() + + matrix = self.grid.copy() + matrix[parkspot[0]][parkspot[1]] = 2 + path = self.find_path(matrix) + direction = parkspot[2] + if path: + # 转换为像素坐标 + path_coords = [(x * 40 + 20, y * 40 + 20) for (x, y) in path] + if direction == 'left': + path_coords.append((X2, (Y1+Y2)/2)) + elif direction == 'right': + path_coords.append((X1, (Y1+Y2)/2)) + elif direction == 'up': + path_coords.append(((X1+X2)/2, Y2)) + else: + path_coords.append(((X1+X2)/2, Y1)) + # 保存路径图形项ID + self.current_path = [] + print(path_coords) + # 绘制路径并记录图形项ID + for i in range(len(path_coords) - 1): + y1, x1 = path_coords[i] + y2, x2 = path_coords[i + 1] + if i == len(path_coords) - 2: + line_id = self.canvas.create_line( + x1, y1, y2, x2, fill="blue", width=5, arrow=tk.LAST) + else: + line_id = self.canvas.create_line( + x1, y1, x2, y2, fill="blue", width=5) + self.current_path.append(line_id) + else: + messagebox.showinfo("提示", "未找到到达该车位的路径!") + + def clear_previous_path(self): + """清除之前绘制的路径""" + for item_id in self.current_path: + self.canvas.delete(item_id) + self.current_path.clear() + + def search_spot(self): + query = self.search_entry.get() + found = False + for rect, spot in self.spots.items(): + if str(spot["number"]) == query: + self.canvas.itemconfig(rect, fill=selected_color) + self.find_path(rect) + found = True + else: + # 恢复成状态颜色 + self.canvas.itemconfig(rect, fill=status_color.get( + spot["status"], default_color)) + + if not found: + messagebox.showwarning("提示", "未找到该车位编号!") + + def is_obstacle(self, coords): + # 判断当前位置是否为车位(障碍物) + for x, y in self.obstacles: + if x <= coords[0] <= x + car_space_width and y <= coords[1] <= y + car_space_height: + return True + return False + + +if __name__ == "__main__": + app = ParkingLot() + app.mainloop() diff --git a/test.py b/test.py deleted file mode 100644 index 5e0d588..0000000 --- a/test.py +++ /dev/null @@ -1,289 +0,0 @@ -import tkinter as tk -from tkinter import messagebox -import random -import heapq -import os -import cv2 -import numpy as np - -# 停车场布局数据 -left_side = list(range(119, 132)) -right_side = list(range(99, 87, -1)) - -# 将右侧车位编号转换为三位数格式(例如:099, 098, ...) -right_side = [str(number).zfill(3) for number in right_side] - -entry_left = [117, 115, 113] -entry_right = [108, 106, 104, 102, 101, 100] -p_row1 = [118, 116, 114, 112, 111, 110, None, 109, 107, 105, 103] -middle_bottom_row1 = [292, 290, 288, 286, 284, 282, 280, 278, 276, 274, 272] -middle_top_row2 = [293, 291, 289, 287, 285, 283, 281, 279, 277, 275, 273, 271] -middle_bottom_row2 = list(range(259, 271)) -middle_top_row3 = [None] * 10 + [00] + [None] -middle_bottom_row3 = [258, 257, 256, None, None, None, None, None, None, 255, 254, None] - -# 样式参数 -car_space_width = 50 -car_space_height = 80 -road_width = 40 -canvas_width = 1200 -canvas_height = 900 -middle_area_offset_y = 100 # 中间区域整体下移 - -# 车位状态对应颜色 -status_color = { - 'free': 'lightgreen', - 'occupied': 'tomato', -} - -default_color = 'white' -selected_color = 'cyan' # 搜索高亮颜色 - -# 设置 YOLO 检测结果路径 -detection_folder = r"D:\car2\parking_folders" - - -# A*算法的启发式函数 -def heuristic(a, b): - return abs(a[0] - b[0]) + abs(a[1] - b[1]) # 曼哈顿距离 - - -class ParkingLot(tk.Tk): - def __init__(self): - super().__init__() - self.title("停车场平面图 🚗") - self.geometry(f"{canvas_width}x{canvas_height}") - self.canvas = tk.Canvas(self, width=canvas_width, height=canvas_height, bg='#CCCCCC') - self.canvas.pack() - - # 搜索部分 - self.search_entry = tk.Entry(self) - self.search_entry.pack(pady=5) - self.search_button = tk.Button(self, text="搜索车位", command=self.search_spot) - self.search_button.pack(pady=5) - - self.spots = {} # 存储车位信息 - self.path = [] # 存储路径 - self.obstacles = [] # 存储障碍物坐标 - self.draw_parking_lot() - - def draw_parking_lot(self): - # 入口灰色路 - self.canvas.create_rectangle(400, 0, 800, road_width, fill='gray') - self.canvas.create_text(750, 20, text="入口", fill="red", font=('Arial', 16)) - - # 入口两边车位 - for idx, number in enumerate(entry_left): - x = 400 - (idx + 1) * (car_space_width + 5) - y = 0 - self.draw_parking_spot(x, y, number, direction='down') - - for idx, number in enumerate(entry_right): - x = 800 + idx * (car_space_width + 5) - y = 0 - self.draw_parking_spot(x, y, number, direction='down') - - # 左右两列 - for idx, number in enumerate(left_side): - x = 0 - y = road_width + idx * (car_space_height + 5) - self.draw_parking_spot(x, y, number, direction='right') - - for idx, number in enumerate(right_side): - x = canvas_width - 50 - y = road_width + idx * (car_space_height + 5) - self.draw_parking_spot(x, y, number, direction='left') - - # 中间区域 - start_y = road_width + 20 + middle_area_offset_y - self.draw_middle_row(start_y, p_row1, up=True) - self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row1, up=False) - - start_y += (car_space_height + 5) * 2 + road_width - self.draw_middle_row(start_y, middle_top_row2, up=True) - self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row2, up=False) - - start_y += (car_space_height + 5) * 2 + road_width - self.draw_middle_row(start_y, middle_top_row3, up=True) - self.draw_middle_row(start_y + car_space_height + 5, middle_bottom_row3, up=False) - - def draw_middle_row(self, start_y, row_data, up=True): - total_spots = len(row_data) - row_width = total_spots * (car_space_width + 5) - 5 - start_x = (canvas_width - row_width) / 2 - - current_x = start_x - for number in row_data: - rect = self.canvas.create_rectangle( - current_x, start_y, - current_x + car_space_width, - start_y + car_space_height, - fill=default_color, - outline='black' - ) - - if number is not None: - # 初始随机给状态 - status = random.choice(['free', 'occupied']) - self.spots[rect] = {'number': number, 'status': status} - self.draw_arrow(current_x, start_y, 'up' if up else 'down') - self.canvas.create_text(current_x + car_space_width / 2, start_y + car_space_height / 2, - text=str(number), font=('Arial', 8)) - self.canvas.tag_bind(rect, '', self.toggle_spot) - # 按状态上色 - fill_color = status_color.get(status, default_color) - self.canvas.itemconfig(rect, fill=fill_color) - - # 添加障碍物坐标 - self.obstacles.append((current_x, start_y)) - - current_x += car_space_width + 5 - - def draw_arrow(self, x, y, direction): - if direction == 'up': - points = [x + car_space_width / 2, y + 10, x + 10, y + 30, x + car_space_width - 10, y + 30] - elif direction == 'down': - points = [x + car_space_width / 2, y + car_space_height - 10, x + 10, y + car_space_height - 30, - x + car_space_width - 10, y + car_space_height - 30] - elif direction == 'left': - points = [x + 10, y + car_space_height / 2, x + 30, y + 10, x + 30, y + car_space_height - 10] - else: - points = [x + car_space_width - 10, y + car_space_height / 2, x + car_space_width - 30, y + 10, - x + car_space_width - 30, y + car_space_height - 10] - self.canvas.create_polygon(points, fill='black') - - def draw_parking_spot(self, x, y, number, direction='up'): - rect = self.canvas.create_rectangle(x, y, x + car_space_width, y + car_space_height, fill=default_color, - outline='black') - - # 获取车位编号对应的YOLO检测结果图像路径 - detection_image_path = os.path.join(detection_folder, f"{number}.jpg") # 假设图像以车位编号命名 - - # 检查文件是否存在 - if os.path.exists(detection_image_path): - # 读取 YOLO 检测结果图像(假设是红绿图像,红色表示有车,绿色表示空位) - detection_image = cv2.imread(detection_image_path) - - # 检查图片是否为空 - if detection_image is not None: - # 假设检测图像中左上角是车位的检测状态,我们可以检查该区域的颜色 - # 获取车位区域的颜色 - region_color = detection_image[10, 10] # 假设检测图像左上角有车位状态信息 - - # 判断颜色,红色表示有车,绿色表示空位 - if np.array_equal(region_color, [0, 0, 255]): # 红色 - status = 'occupied' - elif np.array_equal(region_color, [0, 255, 0]): # 绿色 - status = 'free' - else: - status = 'free' # 默认状态为免费 - else: - status = 'free' # 默认状态为免费,如果读取失败 - else: - status = 'free' # 默认状态为免费,如果没有检测结果 - - self.spots[rect] = {'number': number, 'status': status} - - # 绘制箭头 - self.draw_arrow(x, y, direction) - - # 绘制车位编号 - self.canvas.create_text(x + car_space_width / 2, y + car_space_height / 2, text=str(number), font=('Arial', 8)) - - # 绑定点击事件 - self.canvas.tag_bind(rect, '', self.toggle_spot) - - # 按状态设置颜色 - fill_color = status_color.get(status, default_color) - self.canvas.itemconfig(rect, fill=fill_color) - - def toggle_spot(self, event): - clicked = event.widget.find_withtag('current')[0] - spot = self.spots.get(clicked) - if spot: - messagebox.showinfo("车位信息", f"车位编号: {spot['number']}\n状态: {spot['status']}") - - def search_spot(self): - query = self.search_entry.get() - found = False - for rect, spot in self.spots.items(): - if str(spot['number']) == query: - self.canvas.itemconfig(rect, fill=selected_color) - self.find_path(rect) - found = True - else: - # 恢复成状态颜色 - self.canvas.itemconfig(rect, fill=status_color.get(spot['status'], default_color)) - - if not found: - messagebox.showwarning("提示", "未找到该车位编号!") - - def find_path(self, target_rect): - target_coords = self.canvas.coords(target_rect) - start_coords = (canvas_width // 2, 0) # 入口位置 - - # A*路径规划的实现,避免车位区域 - path = self.a_star(start_coords, target_coords) - - # 绘制路径 - for i in range(len(path) - 1): - self.canvas.create_line(path[i][0], path[i][1], path[i + 1][0], path[i + 1][1], fill="blue", width=4, - arrow=tk.LAST) - - def a_star(self, start, end): - open_list = [] - closed_list = set() - came_from = {} - - start_node = (start[0], start[1]) - end_node = (end[0], end[1]) - - # 计算G、H、F值 - def g_cost(node): - return abs(node[0] - start[0]) + abs(node[1] - start[1]) - - def h_cost(node): - return heuristic(node, end_node) - - def f_cost(node): - return g_cost(node) + h_cost(node) - - heapq.heappush(open_list, (f_cost(start_node), start_node)) - came_from[start_node] = None - - while open_list: - current_f, current_node = heapq.heappop(open_list) - if current_node == end_node: - path = [] - while current_node: - path.append(current_node) - current_node = came_from[current_node] - return path[::-1] - - closed_list.add(current_node) - - for direction in [(0, -car_space_height - 5), (0, car_space_height + 5), (-car_space_width - 5, 0), - (car_space_width + 5, 0)]: - neighbor = (current_node[0] + direction[0], current_node[1] + direction[1]) - - # Check if the neighbor is within bounds and not an obstacle - if 0 <= neighbor[0] < canvas_width and 0 <= neighbor[1] < canvas_height: - if self.is_obstacle(neighbor) or neighbor in closed_list: - continue - - heapq.heappush(open_list, (f_cost(neighbor), neighbor)) - came_from[neighbor] = current_node - - return [] # No path found - - def is_obstacle(self, coords): - # 判断当前位置是否为车位(障碍物) - for (x, y) in self.obstacles: - if x <= coords[0] <= x + car_space_width and y <= coords[1] <= y + car_space_height: - return True - return False - - -if __name__ == "__main__": - app = ParkingLot() - app.mainloop()