"""
导航网格管理器
负责导航网格的加载、生成、管理和查询
"""

import math
import json
import random
from typing import List, Tuple, Optional, Dict, Any, Set
from panda3d.core import Vec3, Point3, NodePath, GeomNode, Geom, GeomVertexFormat
from panda3d.core import GeomVertexData, GeomVertexWriter, GeomTriangles, GeomLines
from panda3d.core import LColor, Material, BitMask32
from direct.actor.Actor import Actor

class NavMeshPolygon:
    """
    导航网格多边形
    表示导航网格中的一个可行走区域
    """
    
    def __init__(self, polygon_id: int, vertices: List[Point3]):
        self.polygon_id = polygon_id
        self.vertices = vertices  # 多边形顶点列表
        self.neighbors: List[int] = []  # 相邻多边形ID列表
        self.center = self._calculate_center()  # 多边形中心点
        self.walkable = True  # 是否可行走
        self.portal_points: Dict[int, Tuple[Point3, Point3]] = {}  # 与其他多边形的门户点
        self.area = self._calculate_area()  # 多边形面积
        self.bounding_box = self._calculate_bounding_box()  # 边界框
        self.flags = 0  # 标志位，用于存储额外信息
        
    def _calculate_center(self) -> Point3:
        """计算多边形中心点"""
        if not self.vertices:
            return Point3(0, 0, 0)
            
        center = Point3(0, 0, 0)
        for vertex in self.vertices:
            center += vertex
        center /= len(self.vertices)
        return center
        
    def _calculate_area(self) -> float:
        """计算多边形面积（使用鞋带公式）"""
        if len(self.vertices) < 3:
            return 0.0
            
        area = 0.0
        n = len(self.vertices)
        for i in range(n):
            j = (i + 1) % n
            area += self.vertices[i].x * self.vertices[j].z
            area -= self.vertices[j].x * self.vertices[i].z
        return abs(area) / 2.0
        
    def _calculate_bounding_box(self) -> Tuple[Point3, Point3]:
        """计算边界框（最小点和最大点）"""
        if not self.vertices:
            return Point3(0, 0, 0), Point3(0, 0, 0)
            
        min_x = min(v.x for v in self.vertices)
        min_y = min(v.y for v in self.vertices)
        min_z = min(v.z for v in self.vertices)
        max_x = max(v.x for v in self.vertices)
        max_y = max(v.y for v in self.vertices)
        max_z = max(v.z for v in self.vertices)
        
        return Point3(min_x, min_y, min_z), Point3(max_x, max_y, max_z)
        
    def add_neighbor(self, neighbor_id: int):
        """添加相邻多边形"""
        if neighbor_id not in self.neighbors:
            self.neighbors.append(neighbor_id)
            
    def remove_neighbor(self, neighbor_id: int):
        """移除相邻多边形"""
        if neighbor_id in self.neighbors:
            self.neighbors.remove(neighbor_id)
            
    def set_portal_points(self, neighbor_id: int, left_point: Point3, right_point: Point3):
        """设置与邻居多边形的门户点"""
        self.portal_points[neighbor_id] = (left_point, right_point)
        
    def get_portal_points(self, neighbor_id: int) -> Optional[Tuple[Point3, Point3]]:
        """获取与邻居多边形的门户点"""
        return self.portal_points.get(neighbor_id)
        
    def is_point_inside(self, point: Point3) -> bool:
        """检查点是否在多边形内（射线投射算法）"""
        # 使用射线投射算法判断点是否在多边形内
        x, z = point.x, point.z
        n = len(self.vertices)
        inside = False
        
        p1x, p1z = self.vertices[0].x, self.vertices[0].z
        for i in range(1, n + 1):
            p2x, p2z = self.vertices[i % n].x, self.vertices[i % n].z
            if z > min(p1z, p2z):
                if z <= max(p1z, p2z):
                    if x <= max(p1x, p2x):
                        if p1z != p2z:
                            xinters = (z - p1z) * (p2x - p1x) / (p2z - p1z) + p1x
                        if p1x == p2x or x <= xinters:
                            inside = not inside
            p1x, p1z = p2x, p2z
            
        return inside
        
    def is_point_in_bounding_box(self, point: Point3) -> bool:
        """快速检查点是否在边界框内"""
        min_point, max_point = self.bounding_box
        return (min_point.x <= point.x <= max_point.x and
                min_point.y <= point.y <= max_point.y and
                min_point.z <= point.z <= max_point.z)
        
    def get_distance_to_point(self, point: Point3) -> float:
        """计算到点的距离"""
        return (self.center - point).length()
        
    def get_closest_point_on_boundary(self, point: Point3) -> Point3:
        """获取多边形边界上距离给定点最近的点"""
        if not self.vertices:
            return point
            
        closest_point = None
        min_distance = float('inf')
        
        # 检查每条边
        for i in range(len(self.vertices)):
            start = self.vertices[i]
            end = self.vertices[(i + 1) % len(self.vertices)]
            
            # 计算点到线段的最近点
            segment_vec = end - start
            point_vec = point - start
            segment_len_sq = segment_vec.lengthSquared()
            
            if segment_len_sq == 0:
                # 线段退化为点
                closest = start
            else:
                t = point_vec.dot(segment_vec) / segment_len_sq
                t = max(0, min(1, t))  # 限制在[0,1]范围内
                closest = start + segment_vec * t
                
            distance = (point - closest).length()
            if distance < min_distance:
                min_distance = distance
                closest_point = closest
                
        return closest_point if closest_point else self.center
        
    def get_closest_point(self, point: Point3) -> Point3:
        """获取多边形上距离给定点最近的点"""
        # 如果点在多边形内，返回该点
        if self.is_point_inside(point):
            return point
        # 否则返回边界上的最近点
        return self.get_closest_point_on_boundary(point)
        
    def intersects_with_ray(self, ray_origin: Point3, ray_direction: Vec3) -> Optional[Point3]:
        """检查与射线的交点"""
        # 简化实现：只检查与多边形平面的交点
        if len(self.vertices) < 3:
            return None
            
        # 计算法平面的法向量
        edge1 = self.vertices[1] - self.vertices[0]
        edge2 = self.vertices[2] - self.vertices[0]
        normal = edge1.cross(edge2)
        normal.normalize()
        
        # 计算射线与平面的交点
        denom = normal.dot(ray_direction)
        if abs(denom) < 1e-6:  # 射线与平面平行
            return None
            
        t = (normal.dot(Vec3(self.vertices[0] - ray_origin))) / denom
        if t < 0:  # 交点在射线起点后面
            return None
            
        intersection = ray_origin + ray_direction * t
        
        # 检查交点是否在多边形内
        if self.is_point_inside(intersection):
            return intersection
            
        return None
        
    def get_vertices(self) -> List[Point3]:
        """获取多边形顶点"""
        return self.vertices.copy()
        
    def get_neighbors(self) -> List[int]:
        """获取邻居列表"""
        return self.neighbors.copy()
        
    def get_portal_point_to_neighbor(self, neighbor_id: int) -> Optional[Tuple[Point3, Point3]]:
        """获取到指定邻居的门户点"""
        return self.portal_points.get(neighbor_id)

class NavMeshManager:
    """
    导航网格管理器
    负责整个导航网格系统的管理
    """
    
    def __init__(self, world):
        """
        初始化导航网格管理器
        
        Args:
            world: 3D世界对象
        """
        self.world = world
        self.enabled = False
        
        # 导航网格数据
        self.polygons: Dict[int, NavMeshPolygon] = {}  # 多边形字典
        self.polygon_counter = 0
        self.navmesh_node = None  # 可视化节点
        self.path_visualization_node = None  # 路径可视化节点
        self.obstacles_node = None  # 障碍物可视化节点
        
        # 导航网格设置
        self.cell_size = 0.5  # 网格单元大小
        self.cell_height = 0.2  # 网格高度
        self.agent_height = 1.8  # 代理高度
        self.agent_radius = 0.3  # 代理半径
        self.max_slope = 45.0  # 最大坡度（度）
        self.max_climb = 0.2  # 最大可爬升高度
        self.min_region_area = 3  # 最小区域面积
        self.merge_region_area = 20  # 合并区域面积阈值
        self.edge_max_len = 12.0  # 边最大长度
        self.edge_max_error = 1.3  # 边最大误差
        self.verts_per_poly = 6  # 每个多边形最大顶点数
        self.walkable = True  # 是否启用
        
        # 可视化设置
        self.visualization_enabled = True
        self.navmesh_visible = False
        self.path_visualization_enabled = True
        self.show_portals = False  # 显示门户点
        self.show_normals = False  # 显示法向量
        
        # 性能优化
        self.spatial_hash_grid = {}  # 空间哈希网格，用于快速查找
        self.spatial_hash_cell_size = 5.0  # 空间哈希网格单元大小
        self.use_spatial_hashing = True  # 是否使用空间哈希
        
        # 导航网格统计
        self.stats = {
            'polygons': 0,
            'vertices': 0,
            'edges': 0,
            'portals': 0,
            'obstacles': 0,
            'last_generation_time': 0.0
        }
        
        # 障碍物管理
        self.obstacles: Dict[int, Dict[str, Any]] = {}  # 动态障碍物
        self.obstacle_counter = 0
        
        # 导航网格版本和元数据
        self.version = "1.0.0"
        self.generator = "EG Navigation Mesh System"
        self.created_time = ""
        self.modified_time = ""
        
        print("✓ 导航网格管理器初始化完成")
        
    def enable(self):
        """启用导航网格管理器"""
        if self.enabled:
            return
            
        self.enabled = True
        
        # 创建可视化节点
        self._create_visualization_nodes()
        
        print("✓ 导航网格管理器已启用")
        
    def disable(self):
        """禁用导航网格管理器"""
        if not self.enabled:
            return
            
        self.enabled = False
        
        # 清理可视化节点
        self._cleanup_visualization_nodes()
        
        print("✓ 导航网格管理器已禁用")
        
    def cleanup(self):
        """清理资源"""
        self.disable()
        self.polygons.clear()
        self.obstacles.clear()
        self.spatial_hash_grid.clear()
        
    def _create_visualization_nodes(self):
        """创建可视化节点"""
        if not self.world or not self.world.render:
            return
            
        # 导航网格可视化节点
        self.navmesh_node = self.world.render.attachNewNode("navmesh_visualization")
        self.navmesh_node.setTransparency(True)
        self.navmesh_node.setColor(LColor(0.0, 0.8, 0.0, 0.3))  # 半透明绿色
        
        # 路径可视化节点
        self.path_visualization_node = self.world.render.attachNewNode("path_visualization")
        self.path_visualization_node.setTransparency(True)
        
        # 障碍物可视化节点
        self.obstacles_node = self.world.render.attachNewNode("obstacles_visualization")
        self.obstacles_node.setTransparency(True)
        self.obstacles_node.setColor(LColor(1.0, 0.0, 0.0, 0.5))  # 半透明红色
        
        # 默认隐藏
        self.navmesh_node.hide()
        self.path_visualization_node.hide()
        self.obstacles_node.hide()
        
    def _cleanup_visualization_nodes(self):
        """清理可视化节点"""
        if self.navmesh_node:
            self.navmesh_node.removeNode()
            self.navmesh_node = None
            
        if self.path_visualization_node:
            self.path_visualization_node.removeNode()
            self.path_visualization_node = None
            
        if self.obstacles_node:
            self.obstacles_node.removeNode()
            self.obstacles_node = None
            
    def toggle_visibility(self):
        """切换导航网格可见性"""
        if not self.navmesh_node:
            return
            
        if self.navmesh_visible:
            self.navmesh_node.hide()
            self.navmesh_visible = False
            print("✓ 导航网格已隐藏")
        else:
            self.navmesh_node.show()
            self.navmesh_visible = True
            print("✓ 导航网格已显示")
            
        # 更新可视化
        self._update_navmesh_visualization()
        
    def _update_spatial_hash(self):
        """更新空间哈希网格"""
        if not self.use_spatial_hashing:
            return
            
        # 清空现有哈希网格
        self.spatial_hash_grid.clear()
        
        # 为每个多边形计算哈希键
        for polygon_id, polygon in self.polygons.items():
            if not polygon.vertices:
                continue
                
            # 计算多边形的边界框
            min_point, max_point = polygon.bounding_box
            
            # 计算覆盖的哈希网格单元
            min_x = int(min_point.x / self.spatial_hash_cell_size)
            min_z = int(min_point.z / self.spatial_hash_cell_size)
            max_x = int(max_point.x / self.spatial_hash_cell_size)
            max_z = int(max_point.z / self.spatial_hash_cell_size)
            
            # 将多边形添加到所有覆盖的单元格中
            for x in range(min_x, max_x + 1):
                for z in range(min_z, max_z + 1):
                    key = (x, z)
                    if key not in self.spatial_hash_grid:
                        self.spatial_hash_grid[key] = []
                    self.spatial_hash_grid[key].append(polygon_id)
                    
    def _get_polygons_in_radius(self, center: Point3, radius: float) -> List[int]:
        """获取指定半径内的多边形"""
        if self.use_spatial_hashing:
            # 使用空间哈希加速查找
            result = set()
            
            # 计算覆盖的哈希网格单元
            min_x = int((center.x - radius) / self.spatial_hash_cell_size)
            min_z = int((center.z - radius) / self.spatial_hash_cell_size)
            max_x = int((center.x + radius) / self.spatial_hash_cell_size)
            max_z = int((center.z + radius) / self.spatial_hash_cell_size)
            
            # 检查所有覆盖的单元格
            for x in range(min_x, max_x + 1):
                for z in range(min_z, max_z + 1):
                    key = (x, z)
                    if key in self.spatial_hash_grid:
                        for polygon_id in self.spatial_hash_grid[key]:
                            polygon = self.polygons[polygon_id]
                            # 精确检查距离
                            if polygon.get_distance_to_point(center) <= radius:
                                result.add(polygon_id)
                                
            return list(result)
        else:
            # 暴力查找
            result = []
            radius_sq = radius * radius
            for polygon_id, polygon in self.polygons.items():
                dist_sq = (polygon.center - center).lengthSquared()
                if dist_sq <= radius_sq:
                    result.append(polygon_id)
            return result
            
    def _update_navmesh_visualization(self):
        """更新导航网格可视化"""
        if not self.navmesh_node or not self.navmesh_visible:
            return
            
        # 清除现有几何体
        self.navmesh_node.node().removeAllGeoms()
        
        if not self.polygons:
            return
            
        # 创建新的几何体
        self._create_navmesh_geometry()
        
        # 如果需要，创建门户点可视化
        if self.show_portals:
            self._create_portals_geometry()
            
        # 如果需要，创建法向量可视化
        if self.show_normals:
            self._create_normals_geometry()
            
    def _create_navmesh_geometry(self):
        """创建导航网格几何体"""
        if not self.navmesh_node or not self.polygons:
            return
            
        # 创建顶点格式
        vertex_format = GeomVertexFormat.getV3n3c4()
        vertex_data = GeomVertexData("navmesh", vertex_format, Geom.UHStatic)
        
        # 计算总顶点数（每个三角形3个顶点）
        total_vertices = 0
        for polygon in self.polygons.values():
            if len(polygon.vertices) >= 3:
                # 简单三角剖分（假设多边形是凸的）
                total_vertices += (len(polygon.vertices) - 2) * 3
                
        if total_vertices == 0:
            return
            
        vertex_data.setNumRows(total_vertices)
        
        # 创建顶点写入器
        vertex_writer = GeomVertexWriter(vertex_data, "vertex")
        normal_writer = GeomVertexWriter(vertex_data, "normal")
        color_writer = GeomVertexWriter(vertex_data, "color")
        
        # 创建几何体
        geom = Geom(vertex_data)
        triangles = GeomTriangles(Geom.UHStatic)
        
        vertex_index = 0
        for polygon in self.polygons.values():
            if len(polygon.vertices) < 3:
                continue
                
            # 计算法平面的法向量
            if len(polygon.vertices) >= 3:
                edge1 = polygon.vertices[1] - polygon.vertices[0]
                edge2 = polygon.vertices[2] - polygon.vertices[0]
                normal = edge1.cross(edge2)
                if normal.length() > 0:
                    normal.normalize()
                else:
                    normal = Vec3(0, 1, 0)
            else:
                normal = Vec3(0, 1, 0)
                
            # 简单三角剖分（扇形剖分）
            for i in range(1, len(polygon.vertices) - 1):
                # 三角形顶点索引
                indices = [0, i, i + 1]
                
                # 写入顶点数据
                for idx in indices:
                    vertex = polygon.vertices[idx]
                    vertex_writer.addData3f(vertex.x, vertex.y, vertex.z)
                    normal_writer.addData3f(normal.x, normal.y, normal.z)
                    color_writer.addData4f(0.0, 0.8, 0.0, 0.3)  # 绿色半透明
                    
                # 添加三角形索引
                triangles.addVertex(vertex_index)
                triangles.addVertex(vertex_index + 1)
                triangles.addVertex(vertex_index + 2)
                triangles.closePrimitive()
                
                vertex_index += 3
                
        geom.addPrimitive(triangles)
        self.navmesh_node.node().addGeom(geom)
        
    def _create_portals_geometry(self):
        """创建门户点几何体"""
        if not self.navmesh_node or not self.polygons:
            return
            
        # 创建顶点格式
        vertex_format = GeomVertexFormat.getV3c4()
        vertex_data = GeomVertexData("portals", vertex_format, Geom.UHStatic)
        
        # 计算总顶点数
        total_vertices = 0
        for polygon in self.polygons.values():
            total_vertices += len(polygon.portal_points) * 2  # 每个门户2个点
            
        if total_vertices == 0:
            return
            
        vertex_data.setNumRows(total_vertices)
        
        # 创建顶点写入器
        vertex_writer = GeomVertexWriter(vertex_data, "vertex")
        color_writer = GeomVertexWriter(vertex_data, "color")
        
        # 写入门户点数据
        vertex_index = 0
        for polygon in self.polygons.values():
            for neighbor_id, (left_point, right_point) in polygon.portal_points.items():
                # 左点
                vertex_writer.addData3f(left_point.x, left_point.y + 0.1, left_point.z)
                color_writer.addData4f(1.0, 1.0, 0.0, 1.0)  # 黄色
                
                # 右点
                vertex_writer.addData3f(right_point.x, right_point.y + 0.1, right_point.z)
                color_writer.addData4f(1.0, 1.0, 0.0, 1.0)  # 黄色
                
                vertex_index += 2
                
        # 创建几何体
        geom = Geom(vertex_data)
        lines = GeomLines(Geom.UHStatic)
        
        # 添加线段
        vertex_index = 0
        for polygon in self.polygons.values():
            for _ in polygon.portal_points:
                lines.addVertex(vertex_index)
                lines.addVertex(vertex_index + 1)
                lines.closePrimitive()
                vertex_index += 2
                
        geom.addPrimitive(lines)
        self.navmesh_node.node().addGeom(geom)
        
        # 设置线宽
        portal_node = self.navmesh_node.attachNewNode("portals")
        portal_node.node().addGeom(geom)
        portal_node.setRenderModeThickness(2.0)
        
    def _create_normals_geometry(self):
        """创建法向量几何体"""
        if not self.navmesh_node or not self.polygons:
            return
            
        # 创建顶点格式
        vertex_format = GeomVertexFormat.getV3c4()
        vertex_data = GeomVertexData("normals", vertex_format, Geom.UHStatic)
        
        # 计算总顶点数
        total_vertices = 0
        for polygon in self.polygons.values():
            if polygon.vertices:
                total_vertices += 2  # 每个多边形中心点和法向量终点
                
        if total_vertices == 0:
            return
            
        vertex_data.setNumRows(total_vertices)
        
        # 创建顶点写入器
        vertex_writer = GeomVertexWriter(vertex_data, "vertex")
        color_writer = GeomVertexWriter(vertex_data, "color")
        
        # 写入法向量数据
        vertex_index = 0
        normal_length = 0.5
        for polygon in self.polygons.values():
            if not polygon.vertices or len(polygon.vertices) < 3:
                continue
                
            # 计算法向量
            edge1 = polygon.vertices[1] - polygon.vertices[0]
            edge2 = polygon.vertices[2] - polygon.vertices[0]
            normal = edge1.cross(edge2)
            if normal.length() > 0:
                normal.normalize()
                normal *= normal_length
                
            # 起点（中心点）
            vertex_writer.addData3f(polygon.center.x, polygon.center.y, polygon.center.z)
            color_writer.addData4f(0.0, 0.0, 1.0, 1.0)  # 蓝色
            
            # 终点（法向量方向）
            end_point = polygon.center + normal
            vertex_writer.addData3f(end_point.x, end_point.y, end_point.z)
            color_writer.addData4f(0.0, 0.0, 1.0, 1.0)  # 蓝色
            
            vertex_index += 2
            
        # 创建几何体
        geom = Geom(vertex_data)
        lines = GeomLines(Geom.UHStatic)
        
        # 添加线段
        for i in range(0, total_vertices, 2):
            lines.addVertex(i)
            lines.addVertex(i + 1)
            lines.closePrimitive()
            
        geom.addPrimitive(lines)
        self.navmesh_node.node().addGeom(geom)
        
        # 设置线宽
        normals_node = self.navmesh_node.attachNewNode("normals")
        normals_node.node().addGeom(geom)
        normals_node.setRenderModeThickness(1.5)
        
    def load_from_file(self, filepath: str) -> bool:
        """
        从文件加载导航网格
        
        Args:
            filepath: 导航网格文件路径
            
        Returns:
            是否加载成功
        """
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            # 解析导航网格数据
            self._parse_navmesh_data(data)
            
            # 更新可视化
            self._update_navmesh_visualization()
            
            print(f"✓ 导航网格加载成功: {filepath}")
            return True
            
        except Exception as e:
            print(f"✗ 导航网格加载失败: {e}")
            return False
            
    def _parse_navmesh_data(self, data: Dict[str, Any]):
        """解析导航网格数据"""
        # 清除现有数据
        self.polygons.clear()
        self.obstacles.clear()
        
        # 解析元数据
        if 'metadata' in data:
            metadata = data['metadata']
            self.version = metadata.get('version', self.version)
            self.generator = metadata.get('generator', self.generator)
            self.created_time = metadata.get('created', '')
            self.modified_time = metadata.get('modified', '')
            
        # 解析设置
        if 'settings' in data:
            settings = data['settings']
            self.cell_size = settings.get('cell_size', self.cell_size)
            self.cell_height = settings.get('cell_height', self.cell_height)
            self.agent_height = settings.get('agent_height', self.agent_height)
            self.agent_radius = settings.get('agent_radius', self.agent_radius)
            self.max_slope = settings.get('max_slope', self.max_slope)
            self.max_climb = settings.get('max_climb', self.max_climb)
            self.min_region_area = settings.get('min_region_area', self.min_region_area)
            self.merge_region_area = settings.get('merge_region_area', self.merge_region_area)
            self.edge_max_len = settings.get('edge_max_len', self.edge_max_len)
            self.edge_max_error = settings.get('edge_max_error', self.edge_max_error)
            self.verts_per_poly = settings.get('verts_per_poly', self.verts_per_poly)
                
        # 解析多边形
        if 'polygons' in data:
            for poly_data in data['polygons']:
                polygon_id = poly_data['id']
                vertices = [Point3(v[0], v[1], v[2]) for v in poly_data['vertices']]
                
                polygon = NavMeshPolygon(polygon_id, vertices)
                
                # 添加邻居信息
                if 'neighbors' in poly_data:
                    for neighbor_id in poly_data['neighbors']:
                        polygon.add_neighbor(neighbor_id)
                        
                # 添加门户点信息
                if 'portal_points' in poly_data:
                    for neighbor_id, portal_data in poly_data['portal_points'].items():
                        left_point = Point3(portal_data[0][0], portal_data[0][1], portal_data[0][2])
                        right_point = Point3(portal_data[1][0], portal_data[1][1], portal_data[1][2])
                        polygon.set_portal_points(int(neighbor_id), left_point, right_point)
                        
                # 设置标志位
                if 'flags' in poly_data:
                    polygon.flags = poly_data['flags']
                    
                self.polygons[polygon_id] = polygon
                
        # 解析障碍物
        if 'obstacles' in data:
            for obs_data in data['obstacles']:
                obstacle_id = obs_data['id']
                self.obstacles[obstacle_id] = {
                    'position': Point3(obs_data['position'][0], obs_data['position'][1], obs_data['position'][2]),
                    'radius': obs_data['radius'],
                    'height': obs_data['height'],
                    'type': obs_data.get('type', 'cylinder')
                }
                
        # 更新统计信息
        self._update_stats()
        
        # 更新空间哈希
        self._update_spatial_hash()
        
        print(f"✓ 解析了 {len(self.polygons)} 个多边形和 {len(self.obstacles)} 个障碍物")
        
    def save_to_file(self, filepath: str) -> bool:
        """
        保存导航网格到文件
        
        Args:
            filepath: 保存文件路径
            
        Returns:
            是否保存成功
        """
        try:
            import time
            current_time = time.strftime("%Y-%m-%d %H:%M:%S")
            
            # 构建导航网格数据
            data = {
                "metadata": {
                    "version": self.version,
                    "generator": self.generator,
                    "created": self.created_time if self.created_time else current_time,
                    "modified": current_time
                },
                "settings": {
                    "cell_size": self.cell_size,
                    "cell_height": self.cell_height,
                    "agent_height": self.agent_height,
                    "agent_radius": self.agent_radius,
                    "max_slope": self.max_slope,
                    "max_climb": self.max_climb,
                    "min_region_area": self.min_region_area,
                    "merge_region_area": self.merge_region_area,
                    "edge_max_len": self.edge_max_len,
                    "edge_max_error": self.edge_max_error,
                    "verts_per_poly": self.verts_per_poly
                },
                "polygons": [],
                "obstacles": []
            }
            
            # 添加多边形数据
            for polygon_id, polygon in self.polygons.items():
                poly_data = {
                    "id": polygon_id,
                    "vertices": [[v.x, v.y, v.z] for v in polygon.vertices],
                    "neighbors": polygon.neighbors,
                    "portal_points": {},
                    "flags": polygon.flags
                }
                
                # 添加门户点数据
                for neighbor_id, (left_point, right_point) in polygon.portal_points.items():
                    poly_data['portal_points'][str(neighbor_id)] = [
                        [left_point.x, left_point.y, left_point.z],
                        [right_point.x, right_point.y, right_point.z]
                    ]
                    
                data["polygons"].append(poly_data)
                
            # 添加障碍物数据
            for obstacle_id, obstacle in self.obstacles.items():
                obs_data = {
                    "id": obstacle_id,
                    "position": [obstacle['position'].x, obstacle['position'].y, obstacle['position'].z],
                    "radius": obstacle['radius'],
                    "height": obstacle['height'],
                    "type": obstacle['type']
                }
                data["obstacles"].append(obs_data)
                
            # 保存到文件
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
                
            print(f"✓ 导航网格保存成功: {filepath}")
            return True
            
        except Exception as e:
            print(f"✗ 导航网格保存失败: {e}")
            return False
            
    def generate_from_scene(self) -> bool:
        """
        从当前场景生成导航网格
        
        Returns:
            是否生成成功
        """
        try:
            import time
            start_time = time.time()
            
            print("✓ 开始从场景生成导航网格...")
            
            # 这里应该实现实际的导航网格生成算法
            # 为演示目的，我们创建一个更复杂的测试网格
            self._create_complex_test_navmesh()
            
            # 计算多边形之间的连接关系
            self._calculate_polygon_connections()
            
            # 计算门户点
            self._calculate_portal_points()
            
            # 更新可视化
            self._update_navmesh_visualization()
            
            # 更新统计信息
            self._update_stats()
            
            # 更新空间哈希
            self._update_spatial_hash()
            
            end_time = time.time()
            self.stats['last_generation_time'] = end_time - start_time
            
            print(f"✓ 导航网格生成完成，耗时 {end_time - start_time:.2f} 秒")
            return True
            
        except Exception as e:
            print(f"✗ 导航网格生成失败: {e}")
            return False
            
    def _create_complex_test_navmesh(self):
        """创建复杂测试导航网格"""
        # 清除现有数据
        self.polygons.clear()
        
        # 创建一个更复杂的测试网格（10x10的区域，包含一些障碍物）
        size = 20.0
        step = 2.0
        obstacle_positions = [
            Point3(5, 0, 5),
            Point3(10, 0, 10),
            Point3(15, 0, 5),
            Point3(5, 0, 15)
        ]
        
        # 创建网格多边形
        polygon_id = 0
        for x in range(0, int(size/step)):
            for z in range(0, int(size/step)):
                # 检查是否与障碍物重叠
                x_pos = x * step - size/2
                z_pos = z * step - size/2
                center = Point3(x_pos + step/2, 0, z_pos + step/2)
                
                # 检查是否与障碍物重叠
                overlap = False
                for obstacle_pos in obstacle_positions:
                    distance = (center - obstacle_pos).length()
                    if distance < step * 1.5:  # 避开障碍物
                        overlap = True
                        break
                        
                if overlap:
                    continue
                    
                # 创建正方形多边形
                vertices = [
                    Point3(x_pos, 0, z_pos),
                    Point3(x_pos + step, 0, z_pos),
                    Point3(x_pos + step, 0, z_pos + step),
                    Point3(x_pos, 0, z_pos + step)
                ]
                
                polygon = NavMeshPolygon(polygon_id, vertices)
                self.polygons[polygon_id] = polygon
                polygon_id += 1
                
        # 创建一些不规则多边形
        irregular_polygons = [
            # L形多边形
            [
                Point3(-8, 0, -8),
                Point3(-6, 0, -8),
                Point3(-6, 0, -6),
                Point3(-4, 0, -6),
                Point3(-4, 0, -4),
                Point3(-8, 0, -4)
            ],
            # 三角形
            [
                Point3(8, 0, -8),
                Point3(10, 0, -6),
                Point3(6, 0, -6)
            ],
            # 六边形
            [
                Point3(-8, 0, 8),
                Point3(-7, 0, 9),
                Point3(-5, 0, 9),
                Point3(-4, 0, 8),
                Point3(-5, 0, 7),
                Point3(-7, 0, 7)
            ]
        ]
        
        for vertices in irregular_polygons:
            polygon = NavMeshPolygon(polygon_id, vertices)
            self.polygons[polygon_id] = polygon
            polygon_id += 1
            
        print(f"✓ 创建了 {len(self.polygons)} 个复杂测试多边形")
        
    def _calculate_polygon_connections(self):
        """计算多边形之间的连接关系"""
        # 为每个多边形找到相邻的多边形
        polygon_list = list(self.polygons.values())
        
        for i, polygon in enumerate(polygon_list):
            polygon.neighbors.clear()  # 清除现有邻居
            
            # 检查与其他多边形的共享边
            for j, other_polygon in enumerate(polygon_list):
                if i == j:
                    continue
                    
                # 检查是否有共享边
                if self._polygons_share_edge(polygon, other_polygon):
                    polygon.add_neighbor(other_polygon.polygon_id)
                    
    def _polygons_share_edge(self, poly1: NavMeshPolygon, poly2: NavMeshPolygon) -> bool:
        """检查两个多边形是否共享边"""
        # 简化实现：检查是否有两个顶点非常接近
        threshold = 0.1  # 距离阈值
        
        for i, v1 in enumerate(poly1.vertices):
            next_i = (i + 1) % len(poly1.vertices)
            edge1_start = v1
            edge1_end = poly1.vertices[next_i]
            
            for j, v2 in enumerate(poly2.vertices):
                next_j = (j + 1) % len(poly2.vertices)
                edge2_start = v2
                edge2_end = poly2.vertices[next_j]
                
                # 检查边是否重合（方向相同或相反）
                if (self._points_equal(edge1_start, edge2_end, threshold) and 
                    self._points_equal(edge1_end, edge2_start, threshold)):
                    return True  # 方向相反的共享边
                    
                if (self._points_equal(edge1_start, edge2_start, threshold) and 
                    self._points_equal(edge1_end, edge2_end, threshold)):
                    return True  # 方向相同的共享边
                    
        return False
        
    def _points_equal(self, p1: Point3, p2: Point3, threshold: float) -> bool:
        """检查两点是否相等（在阈值范围内）"""
        return (p1 - p2).length() < threshold
        
    def _calculate_portal_points(self):
        """计算多边形之间的门户点"""
        for polygon in self.polygons.values():
            polygon.portal_points.clear()  # 清除现有门户点
            
            for neighbor_id in polygon.neighbors:
                if neighbor_id in self.polygons:
                    neighbor_polygon = self.polygons[neighbor_id]
                    portal_points = self._calculate_portal_between_polygons(polygon, neighbor_polygon)
                    if portal_points:
                        left_point, right_point = portal_points
                        polygon.set_portal_points(neighbor_id, left_point, right_point)
                        # 同时在邻居多边形上设置反向门户点
                        neighbor_polygon.set_portal_points(polygon.polygon_id, right_point, left_point)
                        
    def _calculate_portal_between_polygons(self, poly1: NavMeshPolygon, poly2: NavMeshPolygon) -> Optional[Tuple[Point3, Point3]]:
        """计算两个多边形之间的门户点"""
        # 简化实现：找到两个多边形共享边的两个端点
        threshold = 0.1
        
        for i, v1 in enumerate(poly1.vertices):
            next_i = (i + 1) % len(poly1.vertices)
            edge1_start = v1
            edge1_end = poly1.vertices[next_i]
            
            for j, v2 in enumerate(poly2.vertices):
                next_j = (j + 1) % len(poly2.vertices)
                edge2_start = v2
                edge2_end = poly2.vertices[next_j]
                
                # 检查边是否重合（方向相同）
                if (self._points_equal(edge1_start, edge2_start, threshold) and 
                    self._points_equal(edge1_end, edge2_end, threshold)):
                    return (edge1_start, edge1_end)
                    
                # 检查边是否重合（方向相反）
                if (self._points_equal(edge1_start, edge2_end, threshold) and 
                    self._points_equal(edge1_end, edge2_start, threshold)):
                    return (edge1_end, edge1_start)  # 保持poly1到poly2的方向
                    
        return None
        
    def is_point_walkable(self, point: Point3) -> bool:
        """
        检查点是否可行走
        
        Args:
            point: 检查的点
            
        Returns:
            是否可行走
        """
        if not self.polygons:
            return False
            
        # 首先检查是否有动态障碍物阻挡
        for obstacle in self.obstacles.values():
            obstacle_pos = obstacle['position']
            distance = (Point3(point.x, 0, point.z) - Point3(obstacle_pos.x, 0, obstacle_pos.z)).length()
            if distance < obstacle['radius']:
                # 检查高度
                if obstacle_pos.y <= point.y <= obstacle_pos.y + obstacle['height']:
                    return False  # 被障碍物阻挡
                    
        # 检查点是否在任何多边形内
        if self.use_spatial_hashing:
            # 使用空间哈希加速查找
            x_key = int(point.x / self.spatial_hash_cell_size)
            z_key = int(point.z / self.spatial_hash_cell_size)
            key = (x_key, z_key)
            
            if key in self.spatial_hash_grid:
                for polygon_id in self.spatial_hash_grid[key]:
                    if polygon_id in self.polygons:
                        polygon = self.polygons[polygon_id]
                        if polygon.is_point_in_bounding_box(point) and polygon.is_point_inside(point):
                            return polygon.walkable
        else:
            # 暴力查找
            for polygon in self.polygons.values():
                if polygon.is_point_in_bounding_box(point) and polygon.is_point_inside(point):
                    return polygon.walkable
                    
        return False
        
    def get_closest_point(self, point: Point3) -> Optional[Point3]:
        """
        获取导航网格上最近的点
        
        Args:
            point: 目标点
            
        Returns:
            最近的可行走点，如果找不到则返回None
        """
        if not self.polygons:
            return None
            
        closest_point = None
        min_distance = float('inf')
        
        # 使用空间哈希加速查找附近的多边形
        search_radius = 5.0  # 初始搜索半径
        polygons_to_check = self._get_polygons_in_radius(point, search_radius)
        
        # 如果没找到，扩大搜索范围
        if not polygons_to_check:
            search_radius = 20.0
            polygons_to_check = self._get_polygons_in_radius(point, search_radius)
            
        # 如果仍然没找到，检查所有多边形
        if not polygons_to_check:
            polygons_to_check = list(self.polygons.keys())
            
        # 遍历相关多边形找到最近的点
        for polygon_id in polygons_to_check:
            if polygon_id in self.polygons:
                polygon = self.polygons[polygon_id]
                poly_point = polygon.get_closest_point(point)
                distance = (poly_point - point).length()
                
                if distance < min_distance:
                    min_distance = distance
                    closest_point = poly_point
                    
        return closest_point
        
    def get_random_point(self) -> Optional[Point3]:
        """
        获取导航网格上的随机点
        
        Returns:
            随机可行走点，如果导航网格为空则返回None
        """
        if not self.polygons:
            return None
            
        # 随机选择一个多边形
        polygon = random.choice(list(self.polygons.values()))
        
        # 在多边形内生成随机点
        if len(polygon.vertices) >= 3:
            # 使用重心坐标生成多边形内的随机点
            # 选择三个随机顶点
            indices = random.sample(range(len(polygon.vertices)), 
                                  min(3, len(polygon.vertices)))
            
            if len(indices) == 3:
                v1 = polygon.vertices[indices[0]]
                v2 = polygon.vertices[indices[1]]
                v3 = polygon.vertices[indices[2]]
                
                # 生成重心坐标
                r1 = random.random()
                r2 = random.random()
                if r1 + r2 > 1:
                    r1 = 1 - r1
                    r2 = 1 - r2
                    
                r3 = 1 - r1 - r2
                
                # 计算随机点
                random_point = v1 * r1 + v2 * r2 + v3 * r3
                return random_point
                
        # 如果无法生成重心坐标，返回中心点
        return polygon.center
        
    def get_polygon_containing_point(self, point: Point3) -> Optional[NavMeshPolygon]:
        """
        获取包含指定点的多边形
        
        Args:
            point: 目标点
            
        Returns:
            包含点的多边形，如果找不到则返回None
        """
        # 使用空间哈希加速查找
        if self.use_spatial_hashing:
            x_key = int(point.x / self.spatial_hash_cell_size)
            z_key = int(point.z / self.spatial_hash_cell_size)
            key = (x_key, z_key)
            
            if key in self.spatial_hash_grid:
                for polygon_id in self.spatial_hash_grid[key]:
                    if polygon_id in self.polygons:
                        polygon = self.polygons[polygon_id]
                        if polygon.is_point_in_bounding_box(point) and polygon.is_point_inside(point):
                            return polygon
        else:
            # 暴力查找
            for polygon in self.polygons.values():
                if polygon.is_point_in_bounding_box(point) and polygon.is_point_inside(point):
                    return polygon
                    
        return None
        
    def get_adjacent_polygons(self, polygon_id: int) -> List[NavMeshPolygon]:
        """
        获取相邻多边形列表
        
        Args:
            polygon_id: 多边形ID
            
        Returns:
            相邻多边形列表
        """
        if polygon_id not in self.polygons:
            return []
            
        polygon = self.polygons[polygon_id]
        adjacent_polygons = []
        
        for neighbor_id in polygon.neighbors:
            if neighbor_id in self.polygons:
                adjacent_polygons.append(self.polygons[neighbor_id])
                
        return adjacent_polygons
        
    def visualize_path(self, path: List[Point3]):
        """
        可视化路径
        
        Args:
            path: 路径点列表
        """
        if not self.path_visualization_node or not path:
            return
            
        # 清除现有路径可视化
        self.path_visualization_node.node().removeAllGeoms()
        
        if len(path) < 2:
            return
            
        # 创建路径几何体
        self._create_path_geometry(path)
        
        # 显示路径
        self.path_visualization_node.show()
        
    def _create_path_geometry(self, path: List[Point3]):
        """创建路径几何体"""
        if not self.path_visualization_node or len(path) < 2:
            return
            
        # 创建顶点格式
        vertex_format = GeomVertexFormat.getV3c4()
        vertex_data = GeomVertexData("path", vertex_format, Geom.UHStatic)
        vertex_data.setNumRows(len(path))
        
        # 创建顶点写入器
        vertex_writer = GeomVertexWriter(vertex_data, "vertex")
        color_writer = GeomVertexWriter(vertex_data, "color")
        
        # 写入路径点
        for point in path:
            vertex_writer.addData3f(point.x, point.y + 0.1, point.z)  # 稍微抬高避免与地面重叠
            color_writer.addData4f(1.0, 0.0, 0.0, 1.0)  # 红色
                
        # 创建几何体
        geom = Geom(vertex_data)
        lines = GeomLines(Geom.UHStatic)
        
        # 添加线段
        for i in range(len(path) - 1):
            lines.addVertex(i)
            lines.addVertex(i + 1)
            lines.closePrimitive()
            
        geom.addPrimitive(lines)
        self.path_visualization_node.node().addGeom(geom)
        
        # 设置线宽
        self.path_visualization_node.setRenderModeThickness(3.0)
        
        # 添加路径点标记
        self._create_path_point_markers(path)
        
    def _create_path_point_markers(self, path: List[Point3]):
        """创建路径点标记"""
        if not self.path_visualization_node or not path:
            return
            
        marker_node = self.path_visualization_node.attachNewNode("path_markers")
        
        for i, point in enumerate(path):
            # 创建标记球体
            marker = self.world.render.attachNewNode(f"path_marker_{i}")
            marker.setPos(point.x, point.y + 0.2, point.z)
            
            # 可以在这里添加可视化标记（比如一个小球）
            # 为简化，我们只添加位置信息
            
    def clear_path_visualization(self):
        """清除路径可视化"""
        if self.path_visualization_node:
            self.path_visualization_node.node().removeAllGeoms()
            self.path_visualization_node.hide()
            
    def is_navmesh_loaded(self) -> bool:
        """检查导航网格是否已加载"""
        return len(self.polygons) > 0
        
    def get_polygon_count(self) -> int:
        """获取多边形数量"""
        return len(self.polygons)
        
    def add_polygon(self, vertices: List[Point3]) -> int:
        """
        添加多边形
        
        Args:
            vertices: 多边形顶点列表
            
        Returns:
            新多边形的ID
        """
        polygon_id = self.polygon_counter
        self.polygon_counter += 1
        
        polygon = NavMeshPolygon(polygon_id, vertices)
        self.polygons[polygon_id] = polygon
        
        # 更新空间哈希
        self._update_spatial_hash()
        
        # 更新可视化
        self._update_navmesh_visualization()
        
        # 更新统计信息
        self._update_stats()
        
        return polygon_id
        
    def remove_polygon(self, polygon_id: int) -> bool:
        """
        移除多边形
        
        Args:
            polygon_id: 多边形ID
            
        Returns:
            是否移除成功
        """
        if polygon_id in self.polygons:
            # 从邻居多边形中移除这个多边形的引用
            polygon = self.polygons[polygon_id]
            for neighbor_id in polygon.neighbors:
                if neighbor_id in self.polygons:
                    self.polygons[neighbor_id].remove_neighbor(polygon_id)
                    
            # 移除多边形
            del self.polygons[polygon_id]
            
            # 更新空间哈希
            self._update_spatial_hash()
            
            # 更新可视化
            self._update_navmesh_visualization()
            
            # 更新统计信息
            self._update_stats()
            
            return True
        return False
        
    def add_obstacle(self, position: Point3, radius: float, height: float, obstacle_type: str = "cylinder") -> int:
        """
        添加动态障碍物
        
        Args:
            position: 障碍物位置
            radius: 障碍物半径
            height: 障碍物高度
            obstacle_type: 障碍物类型
            
        Returns:
            新障碍物的ID
        """
        obstacle_id = self.obstacle_counter
        self.obstacle_counter += 1
        
        self.obstacles[obstacle_id] = {
            'position': position,
            'radius': radius,
            'height': height,
            'type': obstacle_type
        }
        
        # 更新统计信息
        self._update_stats()
        
        # 更新可视化
        self._update_obstacles_visualization()
        
        return obstacle_id
        
    def remove_obstacle(self, obstacle_id: int) -> bool:
        """
        移除动态障碍物
        
        Args:
            obstacle_id: 障碍物ID
            
        Returns:
            是否移除成功
        """
        if obstacle_id in self.obstacles:
            del self.obstacles[obstacle_id]
            
            # 更新统计信息
            self._update_stats()
            
            # 更新可视化
            self._update_obstacles_visualization()
            
            return True
        return False
        
    def _update_obstacles_visualization(self):
        """更新障碍物可视化"""
        if not self.obstacles_node:
            return
            
        # 清除现有障碍物可视化
        self.obstacles_node.node().removeAllGeoms()
        
        if not self.obstacles or not self.navmesh_visible:
            return
            
        # 创建障碍物几何体
        self._create_obstacles_geometry()
        
        # 显示障碍物
        self.obstacles_node.show()
        
    def _create_obstacles_geometry(self):
        """创建障碍物几何体"""
        if not self.obstacles_node or not self.obstacles:
            return
            
        # 为每个障碍物创建可视化表示
        for obstacle_id, obstacle in self.obstacles.items():
            # 创建圆柱体表示障碍物
            # 这里简化处理，实际应用中可能需要更复杂的几何体
            
            # 创建顶点格式
            vertex_format = GeomVertexFormat.getV3c4()
            vertex_data = GeomVertexData(f"obstacle_{obstacle_id}", vertex_format, Geom.UHStatic)
            
            # 简化：创建一个正方形表示障碍物
            pos = obstacle['position']
            radius = obstacle['radius']
            
            vertices = [
                Point3(pos.x - radius, pos.y, pos.z - radius),
                Point3(pos.x + radius, pos.y, pos.z - radius),
                Point3(pos.x + radius, pos.y, pos.z + radius),
                Point3(pos.x - radius, pos.y, pos.z + radius),
                Point3(pos.x - radius, pos.y + obstacle['height'], pos.z - radius),
                Point3(pos.x + radius, pos.y + obstacle['height'], pos.z - radius),
                Point3(pos.x + radius, pos.y + obstacle['height'], pos.z + radius),
                Point3(pos.x - radius, pos.y + obstacle['height'], pos.z + radius)
            ]
            
            vertex_data.setNumRows(len(vertices))
            
            # 创建顶点写入器
            vertex_writer = GeomVertexWriter(vertex_data, "vertex")
            color_writer = GeomVertexWriter(vertex_data, "color")
            
            # 写入顶点
            for vertex in vertices:
                vertex_writer.addData3f(vertex.x, vertex.y, vertex.z)
                color_writer.addData4f(1.0, 0.0, 0.0, 0.5)  # 红色半透明
                
            # 创建几何体
            geom = Geom(vertex_data)
            
            # 创建面（简化为立方体）
            # 底面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(0, 1, 2)
            triangles.addVertices(0, 2, 3)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            # 顶面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(4, 6, 5)
            triangles.addVertices(4, 7, 6)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            # 前面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(0, 4, 5)
            triangles.addVertices(0, 5, 1)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            # 后面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(2, 6, 7)
            triangles.addVertices(2, 7, 3)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            # 左面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(0, 3, 7)
            triangles.addVertices(0, 7, 4)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            # 右面
            triangles = GeomTriangles(Geom.UHStatic)
            triangles.addVertices(1, 5, 6)
            triangles.addVertices(1, 6, 2)
            triangles.closePrimitive()
            geom.addPrimitive(triangles)
            
            obstacle_node = self.obstacles_node.attachNewNode(f"obstacle_geom_{obstacle_id}")
            obstacle_node.node().addGeom(geom)
            
    def _update_stats(self):
        """更新统计信息"""
        total_vertices = sum(len(polygon.vertices) for polygon in self.polygons.values())
        total_edges = sum(len(polygon.vertices) for polygon in self.polygons.values())  # 简化处理
        total_portals = sum(len(polygon.portal_points) for polygon in self.polygons.values())
        
        self.stats.update({
            'polygons': len(self.polygons),
            'vertices': total_vertices,
            'edges': total_edges,
            'portals': total_portals,
            'obstacles': len(self.obstacles)
        })
        
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        return self.stats.copy()
        
    def set_cell_size(self, size: float):
        """设置网格单元大小"""
        self.cell_size = max(0.1, size)
        
    def set_agent_height(self, height: float):
        """设置代理高度"""
        self.agent_height = max(0.1, height)
        
    def set_agent_radius(self, radius: float):
        """设置代理半径"""
        self.agent_radius = max(0.1, radius)
        
    def set_max_slope(self, slope: float):
        """设置最大坡度"""
        self.max_slope = max(0.0, min(89.0, slope))
        
    def set_max_climb(self, climb: float):
        """设置最大可爬升高度"""
        self.max_climb = max(0.0, climb)
        
    def set_min_region_area(self, area: float):
        """设置最小区域面积"""
        self.min_region_area = max(1, area)
        
    def set_merge_region_area(self, area: float):
        """设置合并区域面积阈值"""
        self.merge_region_area = max(1, area)
        
    def set_edge_max_len(self, length: float):
        """设置边最大长度"""
        self.edge_max_len = max(0.1, length)
        
    def set_edge_max_error(self, error: float):
        """设置边最大误差"""
        self.edge_max_error = max(0.1, error)
        
    def set_verts_per_poly(self, count: int):
        """设置每个多边形最大顶点数"""
        self.verts_per_poly = max(3, count)
        
    def enable_spatial_hashing(self, enabled: bool):
        """启用/禁用空间哈希"""
        self.use_spatial_hashing = enabled
        if enabled:
            self._update_spatial_hash()
            
    def set_spatial_hash_cell_size(self, size: float):
        """设置空间哈希网格单元大小"""
        self.spatial_hash_cell_size = max(0.1, size)
        if self.use_spatial_hashing:
            self._update_spatial_hash()
            
    def rebuild_navmesh(self):
        """重新构建导航网格"""
        print("✓ 重新构建导航网格...")
        return self.generate_from_scene()
        
    def optimize_navmesh(self):
        """优化导航网格"""
        print("✓ 优化导航网格...")
        # 这里可以实现多边形合并、简化等优化算法
        # 为简化，我们只更新连接关系
        self._calculate_polygon_connections()
        self._calculate_portal_points()
        self._update_navmesh_visualization()
        print("✓ 导航网格优化完成")
        
    def validate_navmesh(self) -> bool:
        """验证导航网格的完整性"""
        print("✓ 验证导航网格完整性...")
        
        issues = []
        
        # 检查多边形数据
        for polygon_id, polygon in self.polygons.items():
            if len(polygon.vertices) < 3:
                issues.append(f"多边形 {polygon_id} 顶点数不足")
                
            # 检查邻居关系一致性
            for neighbor_id in polygon.neighbors:
                if neighbor_id not in self.polygons:
                    issues.append(f"多边形 {polygon_id} 的邻居 {neighbor_id} 不存在")
                else:
                    # 检查双向连接
                    neighbor = self.polygons[neighbor_id]
                    if polygon_id not in neighbor.neighbors:
                        issues.append(f"多边形 {polygon_id} 和 {neighbor_id} 的连接关系不一致")
                        
        # 检查门户点数据
        for polygon_id, polygon in self.polygons.items():
            for neighbor_id, (left_point, right_point) in polygon.portal_points.items():
                if neighbor_id not in polygon.neighbors:
                    issues.append(f"多边形 {polygon_id} 存在未连接邻居 {neighbor_id} 的门户点")
                    
        if issues:
            print(f"✗ 发现 {len(issues)} 个问题:")
            for issue in issues:
                print(f"  - {issue}")
            return False
        else:
            print("✓ 导航网格验证通过")
            return True