EG/plugins/user/terrain_editor/paths/path_system.py
2025-12-12 16:16:15 +08:00

1141 lines
42 KiB
Python

"""
地形路径和路网系统
提供完整的路径创建、编辑、导航、寻路算法和可视化功能
"""
from panda3d.core import NodePath, Vec3, Point3, BitMask32
from panda3d.core import CardMaker, LineSegs
from panda3d.core import Texture, TextureStage
from panda3d.ai import AIPathFinder, AIPath, AICharacter
import math
import json
import os
import heapq
class PathSystem:
"""
地形路径和路网系统类
提供路径创建、编辑、导航、寻路算法和可视化功能
"""
def __init__(self, world):
self.world = world
self.paths = [] # 存储路径
self.waypoints = [] # 存储路径点
self.roads = [] # 存储道路
self.navigation_mesh = None # 导航网格
self.pathfinding_enabled = True
self.graph = {} # 寻路图
self.traffic_system = {} # 交通系统
self.pathfinding_algorithm = 'a*' # 寻路算法 ('a*', 'dijkstra', 'rrt')
def create_path(self, name, points=None):
"""
创建路径
name: 路径名称
points: 路径点列表
"""
try:
# 创建路径节点
path_node = self.world.render.attachNewNode(f"path_{name}")
# 创建路径信息
path_info = {
'name': name,
'node': path_node,
'points': points if points else [],
'waypoints': [], # 路径点对象
'segments': [], # 路段信息
'properties': {
'width': 2.0,
'type': 'generic', # generic, road, trail, river, etc.
'speed_limit': 50.0, # km/h
'one_way': False,
'lanes': 1,
'difficulty': 1.0, # 通行难度系数
'traffic_density': 0.0 # 交通密度
}
}
# 如果提供了点,创建路径点
if points:
self._create_waypoints(path_info, points)
# 设置标签
path_node.setTag("path_name", name)
path_node.setTag("is_scene_element", "1")
path_node.setTag("tree_item_type", "PATH_NODE")
# 添加到路径列表
self.paths.append(path_info)
# 更新寻路图
self._update_pathfinding_graph()
print(f"创建路径: {name}")
return path_info
except Exception as e:
print(f"创建路径时出错: {e}")
return None
def _create_waypoints(self, path_info, points):
"""
创建路径点
"""
try:
waypoints = []
for i, point in enumerate(points):
# 创建路径点节点
waypoint_node = path_info['node'].attachNewNode(f"waypoint_{i}")
waypoint_node.setPos(point)
# 创建路径点信息
waypoint_info = {
'node': waypoint_node,
'position': point,
'index': i,
'connections': [], # 连接的其他路径点
'properties': {
'speed_limit': path_info['properties']['speed_limit'],
'stop_sign': False,
'traffic_light': False,
'priority': 1.0, # 路径点优先级
'wait_time': 0.0 # 等待时间
}
}
waypoints.append(waypoint_info)
self.waypoints.append(waypoint_info)
path_info['waypoints'] = waypoints
# 创建路径段
self._create_path_segments(path_info)
# 可视化路径
self._visualize_path(path_info)
except Exception as e:
print(f"创建路径点时出错: {e}")
def _create_path_segments(self, path_info):
"""
创建路径段
"""
try:
waypoints = path_info['waypoints']
segments = []
for i in range(len(waypoints) - 1):
start_waypoint = waypoints[i]
end_waypoint = waypoints[i + 1]
# 计算路段信息
segment_length = (end_waypoint['position'] - start_waypoint['position']).length()
segment_direction = (end_waypoint['position'] - start_waypoint['position']).normalized()
segment_slope = self._calculate_slope(start_waypoint['position'], end_waypoint['position'])
segment_info = {
'start': start_waypoint,
'end': end_waypoint,
'length': segment_length,
'direction': segment_direction,
'slope': segment_slope,
'difficulty': 1.0 + abs(segment_slope) * 0.1, # 坡度影响通行难度
'traffic_flow': 0.0, # 交通流量
'last_update': self.world.globalClock.getFrameTime()
}
segments.append(segment_info)
# 建立连接关系
start_waypoint['connections'].append(end_waypoint)
if not path_info['properties']['one_way']:
end_waypoint['connections'].append(start_waypoint)
path_info['segments'] = segments
except Exception as e:
print(f"创建路径段时出错: {e}")
def _calculate_slope(self, start_pos, end_pos):
"""
计算两点间的坡度
"""
try:
horizontal_distance = Vec3(end_pos.getX() - start_pos.getX(),
end_pos.getY() - start_pos.getY(), 0).length()
vertical_distance = end_pos.getZ() - start_pos.getZ()
if horizontal_distance > 0:
slope = math.degrees(math.atan(vertical_distance / horizontal_distance))
return slope
else:
return 0.0
except:
return 0.0
def _visualize_path(self, path_info):
"""
可视化路径
"""
try:
# 移除现有的可视化节点
if 'visualization' in path_info:
if path_info['visualization'] and not path_info['visualization'].isEmpty():
path_info['visualization'].removeNode()
# 创建线条段
ls = LineSegs()
ls.setThickness(3.0)
# 根据路径类型和交通状况设置颜色
path_type = path_info['properties']['type']
traffic_density = path_info['properties']['traffic_density']
# 基础颜色
if path_type == 'road':
base_color = Vec3(0.3, 0.3, 0.3) # 灰色
elif path_type == 'trail':
base_color = Vec3(0.5, 0.3, 0.1) # 棕色
elif path_type == 'river':
base_color = Vec3(0.0, 0.0, 1.0) # 蓝色
else:
base_color = Vec3(1.0, 1.0, 0.0) # 黄色
# 交通密度影响颜色
if traffic_density > 0.8:
color = Vec3(1.0, 0.0, 0.0) # 红色 - 拥堵
elif traffic_density > 0.5:
color = Vec3(1.0, 0.5, 0.0) # 橙色 - 繁忙
else:
color = base_color # 正常
ls.setColor(color[0], color[1], color[2], 1.0)
# 添加线条点
for waypoint in path_info['waypoints']:
ls.moveTo(waypoint['position'])
# 创建可视化节点
visualization_node = self.world.render.attachNewNode(ls.create())
visualization_node.reparentTo(path_info['node'])
# 保存可视化节点
path_info['visualization'] = visualization_node
except Exception as e:
print(f"可视化路径时出错: {e}")
def add_waypoint(self, path_info, position, index=None):
"""
添加路径点
"""
try:
waypoints = path_info['waypoints']
# 确定插入位置
if index is None:
index = len(waypoints)
# 创建路径点节点
waypoint_node = path_info['node'].attachNewNode(f"waypoint_{index}")
waypoint_node.setPos(position)
# 创建路径点信息
waypoint_info = {
'node': waypoint_node,
'position': position,
'index': index,
'connections': [],
'properties': {
'speed_limit': path_info['properties']['speed_limit'],
'stop_sign': False,
'traffic_light': False,
'priority': 1.0,
'wait_time': 0.0
}
}
# 插入到路径点列表
waypoints.insert(index, waypoint_info)
self.waypoints.append(waypoint_info)
# 更新索引
for i, wp in enumerate(waypoints):
wp['index'] = i
# 重新创建路径段
self._create_path_segments(path_info)
# 重新可视化路径
self._visualize_path(path_info)
# 更新寻路图
self._update_pathfinding_graph()
print(f"添加路径点到路径 {path_info['name']}")
return waypoint_info
except Exception as e:
print(f"添加路径点时出错: {e}")
return None
def remove_waypoint(self, path_info, waypoint_info):
"""
移除路径点
"""
try:
# 从路径中移除
if waypoint_info in path_info['waypoints']:
path_info['waypoints'].remove(waypoint_info)
# 从全局列表中移除
if waypoint_info in self.waypoints:
self.waypoints.remove(waypoint_info)
# 移除节点
if waypoint_info['node'] and not waypoint_info['node'].isEmpty():
waypoint_info['node'].removeNode()
# 重新创建路径段
self._create_path_segments(path_info)
# 重新可视化路径
self._visualize_path(path_info)
# 更新寻路图
self._update_pathfinding_graph()
print(f"从路径 {path_info['name']} 移除路径点")
return True
except Exception as e:
print(f"移除路径点时出错: {e}")
return False
def create_road(self, name, start_point, end_point, width=5.0, lanes=2):
"""
创建道路
"""
try:
# 创建道路节点
road_node = self.world.render.attachNewNode(f"road_{name}")
# 计算道路方向和长度
direction = (end_point - start_point).normalized()
length = (end_point - start_point).length()
# 创建道路几何体
cm = CardMaker('road_surface')
cm.setFrame(0, length, -width/2, width/2)
road_surface = road_node.attachNewNode(cm.generate())
# 设置道路方向和位置
road_node.setPos(start_point)
road_node.lookAt(end_point)
# 创建道路信息
road_info = {
'name': name,
'node': road_node,
'surface': road_surface,
'start_point': start_point,
'end_point': end_point,
'direction': direction,
'length': length,
'width': width,
'lanes': lanes,
'properties': {
'surface_type': 'asphalt', # asphalt, concrete, dirt, etc.
'speed_limit': 50.0,
'one_way': False,
'traffic_lights': [], # 交通灯列表
'road_markings': True # 道路标记
}
}
# 应用道路材质
self._setup_road_material(road_info)
# 设置标签
road_node.setTag("road_name", name)
road_node.setTag("is_scene_element", "1")
road_node.setTag("tree_item_type", "ROAD_NODE")
# 添加到道路列表
self.roads.append(road_info)
# 创建对应路径
path_points = [start_point, end_point]
path_info = self.create_path(f"path_for_{name}", path_points)
if path_info:
path_info['properties']['type'] = 'road'
path_info['properties']['width'] = width
path_info['properties']['lanes'] = lanes
road_info['path'] = path_info
print(f"创建道路: {name}")
return road_info
except Exception as e:
print(f"创建道路时出错: {e}")
return None
def _setup_road_material(self, road_info):
"""
设置道路材质
"""
try:
surface = road_info['surface']
# 创建道路材质
from panda3d.core import Material
road_material = Material()
road_material.setAmbient((0.3, 0.3, 0.3, 1.0))
road_material.setDiffuse((0.4, 0.4, 0.4, 1.0))
road_material.setSpecular((0.1, 0.1, 0.1, 1.0))
road_material.setShininess(10.0)
surface.setMaterial(road_material)
# 如果有纹理系统,应用道路纹理
# 这里可以集成纹理系统
except Exception as e:
print(f"设置道路材质时出错: {e}")
def generate_navigation_mesh(self, terrain_info):
"""
生成导航网格
"""
try:
# 基于地形生成导航网格
# 包括可行走区域、障碍物识别等
# 获取地形信息
heightfield = terrain_info['heightfield']
if not heightfield:
print("无法获取地形高度图数据")
return None
# 创建导航网格数据结构
nav_mesh = {
'triangles': [], # 三角形网格
'vertices': [], # 顶点
'obstacles': [], # 障碍物
'walkable_areas': [], # 可行走区域
'terrain_info': terrain_info
}
# 生成三角形网格(简化实现)
width = heightfield.getXSize()
height = heightfield.getYSize()
# 创建顶点
for y in range(0, height, 4): # 降低分辨率
for x in range(0, width, 4):
# 获取高度值
height_value = heightfield.getRed(x, y)
# 计算世界坐标
terrain_node = terrain_info['node']
terrain_pos = terrain_node.getPos()
terrain_scale = terrain_node.getScale()
center_offset = (width - 1) / 2
world_x = (x - center_offset) * terrain_scale.getX() + terrain_pos.getX()
world_y = (y - center_offset) * terrain_scale.getY() + terrain_pos.getY()
world_z = height_value * terrain_scale.getZ() + terrain_pos.getZ()
nav_mesh['vertices'].append(Point3(world_x, world_y, world_z))
# 创建三角形(简化实现)
vertex_count = len(nav_mesh['vertices'])
for i in range(0, vertex_count - 1, 2):
if i + 2 < vertex_count:
nav_mesh['triangles'].append([i, i + 1, i + 2])
# 识别可行走区域(基于坡度)
for i, vertex in enumerate(nav_mesh['vertices']):
# 检查周围点的坡度
if i + 1 < len(nav_mesh['vertices']):
next_vertex = nav_mesh['vertices'][i + 1]
slope = self._calculate_slope(vertex, next_vertex)
if slope < 30.0: # 坡度小于30度认为可行走
nav_mesh['walkable_areas'].append(i)
print(f"生成导航网格: {vertex_count} 个顶点, {len(nav_mesh['triangles'])} 个三角形")
self.navigation_mesh = nav_mesh
return nav_mesh
except Exception as e:
print(f"生成导航网格时出错: {e}")
return None
def find_path(self, start_pos, end_pos, algorithm=None):
"""
寻找路径
"""
try:
if not self.pathfinding_enabled:
print("路径寻找已禁用")
return None
# 选择寻路算法
if algorithm is None:
algorithm = self.pathfinding_algorithm
# 执行寻路
if algorithm == 'a*':
path = self._a_star_pathfinding(start_pos, end_pos)
elif algorithm == 'dijkstra':
path = self._dijkstra_pathfinding(start_pos, end_pos)
elif algorithm == 'rrt':
path = self._rrt_pathfinding(start_pos, end_pos)
else:
# 默认使用A*
path = self._a_star_pathfinding(start_pos, end_pos)
if path:
print(f"找到路径: {start_pos} -> {end_pos} (长度: {len(path)} 个点)")
return path
else:
print(f"无法找到路径: {start_pos} -> {end_pos}")
return None
except Exception as e:
print(f"寻找路径时出错: {e}")
return None
def _a_star_pathfinding(self, start_pos, end_pos):
"""
A*寻路算法
"""
try:
# 如果没有寻路图,使用路径点
if not self.graph or len(self.graph) == 0:
return self._simple_a_star(start_pos, end_pos)
# A*算法实现
open_set = []
closed_set = set()
came_from = {}
g_score = {start_pos: 0}
f_score = {start_pos: self._heuristic(start_pos, end_pos)}
heapq.heappush(open_set, (f_score[start_pos], start_pos))
while open_set:
current = heapq.heappop(open_set)[1]
if self._is_close(current, end_pos, 1.0):
# 重构路径
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start_pos)
path.reverse()
return path
closed_set.add(current)
# 检查邻居
for neighbor in self._get_neighbors(current):
if neighbor in closed_set:
continue
tentative_g_score = g_score[current] + (neighbor - current).length()
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = g_score[neighbor] + self._heuristic(neighbor, end_pos)
if neighbor not in [i[1] for i in open_set]:
heapq.heappush(open_set, (f_score[neighbor], neighbor))
return None # 未找到路径
except Exception as e:
print(f"A*寻路时出错: {e}")
return None
def _dijkstra_pathfinding(self, start_pos, end_pos):
"""
Dijkstra寻路算法
"""
try:
# Dijkstra算法实现
distances = {start_pos: 0}
previous = {}
unvisited = set()
# 初始化
for waypoint in self.waypoints:
pos = waypoint['position']
distances[pos] = float('inf')
unvisited.add(pos)
distances[start_pos] = 0
unvisited.add(start_pos)
while unvisited:
# 找到距离最小的节点
current = min(unvisited, key=lambda x: distances[x])
unvisited.remove(current)
if self._is_close(current, end_pos, 1.0):
# 重构路径
path = []
while current in previous:
path.append(current)
current = previous[current]
path.append(start_pos)
path.reverse()
return path
# 更新邻居距离
for neighbor in self._get_neighbors(current):
if neighbor in unvisited:
alt = distances[current] + (neighbor - current).length()
if alt < distances[neighbor]:
distances[neighbor] = alt
previous[neighbor] = current
return None # 未找到路径
except Exception as e:
print(f"Dijkstra寻路时出错: {e}")
return None
def _rrt_pathfinding(self, start_pos, end_pos):
"""
RRT (快速随机树) 寻路算法
"""
try:
# RRT算法简化实现
nodes = [start_pos]
parent = {start_pos: None}
max_iterations = 1000
step_size = 5.0
for i in range(max_iterations):
# 随机采样或偏向目标
if random.random() < 0.1:
random_point = end_pos
else:
# 随机点
random_point = Point3(
start_pos.getX() + random.uniform(-50, 50),
start_pos.getY() + random.uniform(-50, 50),
start_pos.getZ()
)
# 找到最近的节点
nearest_node = min(nodes, key=lambda x: (x - random_point).length())
# 向随机点延伸
direction = (random_point - nearest_node).normalized()
new_point = nearest_node + direction * step_size
# 检查是否与障碍物碰撞(简化检查)
if self._is_valid_point(new_point):
nodes.append(new_point)
parent[new_point] = nearest_node
# 检查是否到达目标附近
if (new_point - end_pos).length() < step_size:
# 重构路径
path = [end_pos]
current = new_point
while current is not None:
path.append(current)
current = parent.get(current)
path.reverse()
return path
return None # 未找到路径
except Exception as e:
print(f"RRT寻路时出错: {e}")
return None
def _simple_a_star(self, start_pos, end_pos):
"""
简化版A*(基于路径点)
"""
try:
if not self.waypoints:
return [start_pos, end_pos]
# 找到最近的路径点作为起点和终点
start_waypoint = min(self.waypoints, key=lambda x: (x['position'] - start_pos).length())
end_waypoint = min(self.waypoints, key=lambda x: (x['position'] - end_pos).length())
# 在路径点间寻路
waypoint_path = self._waypoint_a_star(start_waypoint, end_waypoint)
if not waypoint_path:
return None
# 构造完整路径
path = [start_pos]
for waypoint in waypoint_path:
path.append(waypoint['position'])
path.append(end_pos)
return path
except Exception as e:
print(f"简化A*寻路时出错: {e}")
return None
def _waypoint_a_star(self, start_waypoint, end_waypoint):
"""
路径点间的A*寻路
"""
try:
open_set = []
closed_set = set()
came_from = {}
g_score = {start_waypoint: 0}
f_score = {start_waypoint: self._waypoint_heuristic(start_waypoint, end_waypoint)}
heapq.heappush(open_set, (f_score[start_waypoint], id(start_waypoint), start_waypoint))
while open_set:
current = heapq.heappop(open_set)[2]
if current == end_waypoint:
# 重构路径
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.reverse()
return path
closed_set.add(current)
# 检查连接的路径点
for neighbor in current['connections']:
if neighbor in closed_set:
continue
# 计算通行成本
distance = (neighbor['position'] - current['position']).length()
difficulty = 1.0 # 可以从路径属性获取
tentative_g_score = g_score[current] + distance * difficulty
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = g_score[neighbor] + self._waypoint_heuristic(neighbor, end_waypoint)
if neighbor not in [item[2] for item in open_set]:
heapq.heappush(open_set, (f_score[neighbor], id(neighbor), neighbor))
return None # 未找到路径
except Exception as e:
print(f"路径点A*寻路时出错: {e}")
return None
def _heuristic(self, pos1, pos2):
"""
启发式函数(欧几里得距离)
"""
return (pos1 - pos2).length()
def _waypoint_heuristic(self, waypoint1, waypoint2):
"""
路径点启发式函数
"""
return (waypoint1['position'] - waypoint2['position']).length()
def _is_close(self, pos1, pos2, threshold):
"""
检查两点是否接近
"""
return (pos1 - pos2).length() <= threshold
def _get_neighbors(self, pos):
"""
获取位置的邻居点
"""
# 简化实现:返回附近的路径点
neighbors = []
for waypoint in self.waypoints:
distance = (waypoint['position'] - pos).length()
if 0.1 < distance < 10.0: # 距离阈值
neighbors.append(waypoint['position'])
return neighbors
def _is_valid_point(self, point):
"""
检查点是否有效(不与障碍物碰撞)
"""
# 简化实现:检查是否在合理高度范围内
return -10.0 <= point.getZ() <= 100.0
def create_ai_character(self, name, position, path=None):
"""
创建AI角色
"""
try:
# 创建AI角色
ai_char = AICharacter(name, position, 50, 0.05, 5)
# 如果提供了路径,设置路径跟随
if path:
ai_path = AIPath()
for point in path:
ai_path.addPoint(point)
ai_char.setAiPath(ai_path)
print(f"创建AI角色: {name}")
return ai_char
except Exception as e:
print(f"创建AI角色时出错: {e}")
return None
def _update_pathfinding_graph(self):
"""
更新寻路图
"""
try:
# 基于路径点构建寻路图
self.graph = {}
for waypoint in self.waypoints:
pos = waypoint['position']
self.graph[pos] = []
# 添加连接的邻居
for connection in waypoint['connections']:
neighbor_pos = connection['position']
self.graph[pos].append(neighbor_pos)
print(f"更新寻路图: {len(self.graph)} 个节点")
except Exception as e:
print(f"更新寻路图时出错: {e}")
def update_path_system(self, time_delta):
"""
更新路径系统
"""
try:
# 更新交通系统
self._update_traffic_system(time_delta)
# 更新路径可视化
self._update_path_visualization()
# 更新AI角色
# 这里可以更新所有AI角色的状态
except Exception as e:
print(f"更新路径系统时出错: {e}")
def _update_traffic_system(self, time_delta):
"""
更新交通系统
"""
try:
current_time = self.world.globalClock.getFrameTime()
# 更新每条路径的交通密度
for path_info in self.paths:
# 模拟交通流量变化
if 'traffic_density' in path_info['properties']:
# 简单的交通流量模拟
base_density = 0.3
time_factor = (math.sin(current_time * 0.1) + 1.0) * 0.5
path_info['properties']['traffic_density'] = base_density + time_factor * 0.4
except Exception as e:
print(f"更新交通系统时出错: {e}")
def _update_path_visualization(self):
"""
更新路径可视化
"""
try:
# 重新可视化所有路径以反映交通状况
for path_info in self.paths:
self._visualize_path(path_info)
except Exception as e:
print(f"更新路径可视化时出错: {e}")
def set_path_properties(self, path_info, properties):
"""
设置路径属性
"""
try:
# 更新路径属性
path_info['properties'].update(properties)
# 重新可视化路径
self._visualize_path(path_info)
# 更新寻路图(如果影响通行难度)
if 'difficulty' in properties or 'speed_limit' in properties:
self._update_pathfinding_graph()
print(f"更新路径 {path_info['name']} 属性")
return True
except Exception as e:
print(f"设置路径属性时出错: {e}")
return False
def get_path_stats(self):
"""
获取路径统计信息
"""
stats = {
'total_paths': len(self.paths),
'total_waypoints': len(self.waypoints),
'total_roads': len(self.roads),
'path_types': {},
'total_length': 0,
'algorithm': self.pathfinding_algorithm,
'traffic_stats': {
'total_density': 0.0,
'avg_density': 0.0
}
}
# 统计路径类型和总长度
total_density = 0.0
for path_info in self.paths:
path_type = path_info['properties']['type']
if path_type in stats['path_types']:
stats['path_types'][path_type] += 1
else:
stats['path_types'][path_type] = 1
# 计算路径长度
for segment in path_info['segments']:
stats['total_length'] += segment['length']
# 累计交通密度
total_density += path_info['properties'].get('traffic_density', 0.0)
# 计算平均交通密度
if len(self.paths) > 0:
stats['traffic_stats']['avg_density'] = total_density / len(self.paths)
stats['traffic_stats']['total_density'] = total_density
return stats
def save_path_data(self, output_path):
"""
保存路径数据
"""
try:
# 收集路径数据
path_data = {
'paths': [],
'roads': [],
'settings': {
'pathfinding_algorithm': self.pathfinding_algorithm,
'pathfinding_enabled': self.pathfinding_enabled
}
}
# 保存路径信息
for path_info in self.paths:
path_dict = {
'name': path_info['name'],
'points': [],
'properties': path_info['properties']
}
# 保存路径点
for waypoint in path_info['waypoints']:
point_dict = {
'position': [waypoint['position'].x,
waypoint['position'].y,
waypoint['position'].z],
'properties': waypoint['properties']
}
path_dict['points'].append(point_dict)
path_data['paths'].append(path_dict)
# 保存道路信息
for road_info in self.roads:
road_dict = {
'name': road_info['name'],
'start_point': [road_info['start_point'].x,
road_info['start_point'].y,
road_info['start_point'].z],
'end_point': [road_info['end_point'].x,
road_info['end_point'].y,
road_info['end_point'].z],
'width': road_info['width'],
'lanes': road_info['lanes'],
'properties': road_info['properties']
}
path_data['roads'].append(road_dict)
# 确保输出目录存在
output_dir = os.path.dirname(output_path)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 写入JSON文件
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(path_data, f, indent=2, ensure_ascii=False)
print(f"路径数据保存成功: {output_path}")
return True
except Exception as e:
print(f"保存路径数据时出错: {e}")
return False
def load_path_data(self, input_path):
"""
加载路径数据
"""
try:
if not os.path.exists(input_path):
print(f"路径数据文件不存在: {input_path}")
return False
# 读取JSON文件
with open(input_path, 'r', encoding='utf-8') as f:
path_data = json.load(f)
# 清除现有路径
self.clear_all_paths()
# 恢复设置
if 'settings' in path_data:
settings = path_data['settings']
self.pathfinding_algorithm = settings.get('pathfinding_algorithm', 'a*')
self.pathfinding_enabled = settings.get('pathfinding_enabled', True)
# 创建路径
for path_dict in path_data['paths']:
points = []
for point_dict in path_dict['points']:
position = Point3(point_dict['position'][0],
point_dict['position'][1],
point_dict['position'][2])
points.append(position)
path_info = self.create_path(path_dict['name'], points)
if path_info:
self.set_path_properties(path_info, path_dict['properties'])
# 创建道路
for road_dict in path_data['roads']:
start_point = Point3(road_dict['start_point'][0],
road_dict['start_point'][1],
road_dict['start_point'][2])
end_point = Point3(road_dict['end_point'][0],
road_dict['end_point'][1],
road_dict['end_point'][2])
self.create_road(road_dict['name'], start_point, end_point,
road_dict['width'], road_dict['lanes'])
print(f"路径数据加载成功: {input_path}")
return True
except Exception as e:
print(f"加载路径数据时出错: {e}")
return False
def clear_all_paths(self):
"""
清除所有路径
"""
try:
# 移除所有路径节点
for path_info in self.paths:
if path_info['node'] and not path_info['node'].isEmpty():
path_info['node'].removeNode()
# 移除所有道路节点
for road_info in self.roads:
if road_info['node'] and not road_info['node'].isEmpty():
road_info['node'].removeNode()
# 清空数据结构
self.paths = []
self.waypoints = []
self.roads = []
self.graph = {}
print("清除所有路径")
return True
except Exception as e:
print(f"清除所有路径时出错: {e}")
return False
def paint_path(self, start_point, end_point, path_type='generic', width=2.0):
"""
绘制路径(笔刷工具)
"""
try:
# 创建路径名称
path_name = f"painted_path_{len(self.paths)}"
# 创建路径点
points = [start_point, end_point]
# 创建路径
path_info = self.create_path(path_name, points)
if path_info:
# 设置路径属性
properties = {
'type': path_type,
'width': width
}
self.set_path_properties(path_info, properties)
print(f"绘制路径: {path_name}")
return path_info
except Exception as e:
print(f"绘制路径时出错: {e}")
return None
def set_pathfinding_algorithm(self, algorithm):
"""
设置寻路算法
"""
valid_algorithms = ['a*', 'dijkstra', 'rrt']
if algorithm in valid_algorithms:
self.pathfinding_algorithm = algorithm
print(f"寻路算法设置为: {algorithm}")
return True
else:
print(f"无效的寻路算法: {algorithm}")
return False
def get_navigation_mesh_stats(self):
"""
获取导航网格统计信息
"""
if not self.navigation_mesh:
return {'generated': False}
return {
'generated': True,
'vertices': len(self.navigation_mesh['vertices']),
'triangles': len(self.navigation_mesh['triangles']),
'obstacles': len(self.navigation_mesh['obstacles']),
'walkable_areas': len(self.navigation_mesh['walkable_areas'])
}