using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Plugins; using NavisworksTransport.PathPlanning; using NavisworksTransport.Utils; using NavisworksTransport.Core; using NavisworksTransport.Core.Config; using NavisworksTransport.Commands; namespace NavisworksTransport { /// /// 路径规划管理器(重构版) /// 负责路径规划的核心业务逻辑,与UI完全解耦 /// public class PathPlanningManager : IPathPlanningManager, IDisposable { #region 私有字段 private readonly string _managerId; private readonly CategoryAttributeManager _categoryManager; private readonly UIStateManager _uiStateManager; private CoordinateConverter _coordinateConverter; private PathPointRenderPlugin _renderPlugin; // 路径分析相关 private PathDatabase _pathDatabase; private PathAnalysisService _analysisService; private List _walkableAreas; private List _routes; private PathRoute _currentRoute; private ChannelBounds _combinedChannelBounds; // 路径编辑状态管理 private PathEditState _pathEditState = PathEditState.Viewing; private PathPointType _currentPointType = PathPointType.WayPoint; private PathRoute _editingRoute = null; private PathHistoryManager _historyManager; // ToolPlugin 集成 private bool _isToolPluginActive = false; // 自动路径规划模式标志 private bool _isInAutoPathMode = false; // 路径点3D标记管理 private List _pathPointMarkers; // 预览点管理 private PathPoint _previewPoint = null; // 网格可视化设置 private bool _showWalkableGrid = false; private bool _showObstacleGrid = false; private bool _showUnknownGrid = false; private bool _showDoorGrid = false; private GridMap _currentGridMap = null; // 保存当前网格地图用于刷新 private double _currentVehicleHeight = 2.0; // 保存当前车辆高度(米)用于网格刷新 private bool _isPreviewMode = false; private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置 // 修改路径点管理 private int _editingPointIndex = -1; // 正在修改的路径点索引 private PathPoint _originalPoint = null; // 修改前的原始路径点 private PathPoint _editingPreviewPoint = null; // 修改时的预览路径点 /// /// ToolPlugin是否处于激活状态(供InputMonitor使用) /// public bool IsToolPluginActive => _isToolPluginActive; /// /// 获取当前是否在预览模式 /// public bool IsPreviewMode => _isPreviewMode; // 静态引用,用于处理ToolPlugin事件 private static PathPlanningManager _activePathManager; #endregion #region 构造函数 /// /// 构造函数 /// /// 类别属性管理器 /// UI状态管理器(可选) public PathPlanningManager(CategoryAttributeManager categoryManager, UIStateManager uiStateManager = null) { _managerId = Guid.NewGuid().ToString("N").Substring(0, 8); // 前8位作为ID _categoryManager = categoryManager ?? throw new ArgumentNullException(nameof(categoryManager)); _uiStateManager = uiStateManager ?? UIStateManager.Instance; InitializeManager(); } /// /// 无参构造函数(为向后兼容而保留) /// public PathPlanningManager() { _managerId = Guid.NewGuid().ToString("N").Substring(0, 8); _categoryManager = new CategoryAttributeManager(); _uiStateManager = UIStateManager.Instance; InitializeManager(); } private void InitializeManager() { // 设置静态引用,确保所有地方都使用同一个实例 _activePathManager = this; LogManager.Debug($"[路径管理] 设置_activePathManager静态引用, ManagerId: {_managerId}"); // 获取已注册的圆形渲染插件实例 try { _renderPlugin = PathPointRenderPlugin.Instance; if (_renderPlugin != null) { LogManager.Info("[路径管理] ✅ PathPointRenderPlugin实例获取成功"); LogManager.Debug($"[路径管理] 渲染插件状态 - 启用: {_renderPlugin.IsEnabled}, 标记数量: {_renderPlugin.MarkerCount}"); // 推送默认的网格大小和车辆参数,确保渲染插件有合理的初始值 InitializeRenderPluginDefaults(); } else { LogManager.Warning("[路径管理] ❌ PathPointRenderPlugin实例尚未就绪,将在后续尝试获取"); } } catch (Exception ex) { LogManager.Error($"[路径管理] PathPointRenderPlugin实例获取失败: {ex.Message}"); LogManager.Error($"[路径管理] 异常堆栈: {ex.StackTrace}"); _renderPlugin = null; } // 初始化核心数据结构 _walkableAreas = new List(); _routes = new List(); _currentRoute = new PathRoute("默认路径"); _historyManager = new PathHistoryManager(50); // 最多保存50个历史记录 _coordinateConverter = null; // 将在需要时初始化 _pathPointMarkers = new List(); LogManager.Info($"PathPlanningManager初始化完成,ManagerId: {_managerId}"); // 注意:数据库初始化延迟到文档加载完成后 // 在 MainPlugin.OnModelsCollectionChanged 中会调用 DatabaseInitialize() } /// /// 路径分析数据库初始化 /// 此方法应在文档加载完成后调用 /// public void DatabaseInitialize() { try { var documentPath = Application.ActiveDocument?.FileName; if (!string.IsNullOrEmpty(documentPath)) { _pathDatabase = new PathDatabase(documentPath); _analysisService = new PathAnalysisService(_pathDatabase); LogManager.Info($"路径分析数据库初始化成功,文档路径: {documentPath}"); // 从数据库加载历史路径到内存 LoadHistoricalRoutesFromDatabase(); } else { // 文档路径为空时,静默跳过(这种情况不应该发生,因为调用者应该确保文档已加载) LogManager.Debug("文档路径为空,跳过数据库初始化"); } } catch (Exception ex) { LogManager.Error($"初始化路径分析数据库失败: {ex.Message}", ex); } } /// /// 初始化渲染插件的默认值 /// 从配置文件读取网格大小和车辆参数,确保渲染插件在任何情况下都有正确的可视化效果 /// private void InitializeRenderPluginDefaults() { try { var config = ConfigManager.Instance.Current; // 从配置读取网格大小 double gridSizeInMeters = config.PathEditing.CellSizeMeters; _renderPlugin.SetGridSize(gridSizeInMeters); LogManager.Info($"[渲染插件初始化] 已设置网格大小: {gridSizeInMeters}米(来自配置)"); // 从配置读取车辆参数 double vehicleLength = config.PathEditing.VehicleLengthMeters; double vehicleWidth = config.PathEditing.VehicleWidthMeters; double vehicleHeight = config.PathEditing.VehicleHeightMeters; double safetyMargin = config.PathEditing.SafetyMarginMeters; _renderPlugin.SetVehicleParameters( vehicleLength, vehicleWidth, vehicleHeight, safetyMargin ); LogManager.Info($"[渲染插件初始化] 已设置车辆参数: 长={vehicleLength:F1}m, 宽={vehicleWidth:F1}m, 高={vehicleHeight:F1}m, 安全间隙={safetyMargin:F2}m(来自配置)"); } catch (Exception ex) { LogManager.Error($"[渲染插件初始化] 设置默认值失败: {ex.Message}", ex); // 即使失败也不抛出异常,避免影响PathPlanningManager的初始化 } } #endregion #region IPathPlanningManager接口实现 public string ManagerId => _managerId; public PathHistoryManager HistoryManager => _historyManager; public PathEditState PathEditState { get { return _pathEditState; } private set { var previousState = _pathEditState; _pathEditState = value; // 触发状态变更事件 RaiseEditStateChanged(previousState, value, _editingRoute); LogManager.Info($"路径编辑状态变更: {previousState} -> {value}"); } } public PathRoute EditingRoute { get { return _editingRoute; } private set { _editingRoute = value; } } public bool IsInEditableState { get { return _pathEditState == PathEditState.Creating || _pathEditState == PathEditState.Editing || _pathEditState == PathEditState.AddingPoints; } } public PathRoute CurrentRoute { get { return _currentRoute; } private set { var previousRoute = _currentRoute; _currentRoute = value; // 只有真正的业务操作才触发事件,UI同步不触发事件 RaiseCurrentRouteChanged(previousRoute, value, triggerEvent: true); } } public IReadOnlyList Routes => _routes.AsReadOnly(); /// /// 获取可修改的路线集合(内部使用) /// internal List ModifiableRoutes => _routes; public IReadOnlyList SelectedChannels => _walkableAreas.AsReadOnly(); public PathPointType CurrentPointType { get { return _currentPointType; } private set { _currentPointType = value; } } /// /// 是否在自动路径规划模式 /// public bool IsInAutoPathMode { get { return _isInAutoPathMode; } private set { _isInAutoPathMode = value; } } public ChannelBounds CombinedChannelBounds => _combinedChannelBounds; #endregion #region 事件定义 public event EventHandler StatusChanged; public event EventHandler ErrorOccurred; public event EventHandler EditStateChanged; public event EventHandler ChannelSelectionChanged; public event EventHandler PathPointOperation; public event EventHandler RouteGenerated; public event EventHandler CurrentRouteChanged; public event EventHandler PathPointsListUpdated; // 保留原有事件以保持向后兼容 [Obsolete("请使用新的强类型事件接口")] public event EventHandler> ChannelsSelected; [Obsolete("请使用新的强类型事件接口")] public event EventHandler CurrentRouteChanged_Legacy; [Obsolete("请使用新的强类型事件接口")] public event EventHandler RouteGenerated_Legacy; [Obsolete("请使用新的强类型事件接口")] public event EventHandler StatusChanged_Legacy; [Obsolete("请使用新的强类型事件接口")] public event EventHandler ErrorOccurred_Legacy; [Obsolete("请使用新的强类型事件接口")] public event EventHandler PathEditStateChanged; [Obsolete("请使用新的强类型事件接口")] public event EventHandler PathPointAddedIn3D; [Obsolete("请使用新的强类型事件接口")] public event EventHandler PathPointRemovedFrom3D; [Obsolete("请使用新的强类型事件接口")] public event EventHandler PathPointsListUpdated_Legacy; #endregion #region 事件触发方法 private void RaiseStatusChanged(string statusMessage, PathPlanningStatusType statusType = PathPlanningStatusType.Info, object additionalData = null) { try { var eventArgs = new PathPlanningStatusChangedEventArgs(statusMessage, statusType, additionalData, _managerId); // 使用UIStateManager安全地触发事件 if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { StatusChanged?.Invoke(this, eventArgs); // 向后兼容的事件 StatusChanged_Legacy?.Invoke(this, statusMessage); }); } else { StatusChanged?.Invoke(this, eventArgs); StatusChanged_Legacy?.Invoke(this, statusMessage); } LogManager.Info($"[状态变更] {statusMessage}"); } catch (Exception ex) { LogManager.Error($"[状态变更] 事件触发失败: {ex.Message}"); } } private void RaiseErrorOccurred(string errorMessage, Exception exception = null, PathPlanningErrorLevel errorLevel = PathPlanningErrorLevel.Error) { try { var eventArgs = new PathPlanningErrorOccurredEventArgs(errorMessage, exception, errorLevel, _managerId); // 使用UIStateManager安全地触发事件 if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { ErrorOccurred?.Invoke(this, eventArgs); // 向后兼容的事件 ErrorOccurred_Legacy?.Invoke(this, errorMessage); }); } else { ErrorOccurred?.Invoke(this, eventArgs); ErrorOccurred_Legacy?.Invoke(this, errorMessage); } LogManager.Error($"[错误发生] {errorMessage}"); if (exception != null) { LogManager.Error($"[错误详情] {exception}"); } } catch (Exception ex) { LogManager.Error($"[错误事件] 触发失败: {ex.Message}"); } } private void RaiseEditStateChanged(PathEditState previousState, PathEditState newState, PathRoute editingRoute) { try { var eventArgs = new PathEditStateChangedEventArgs(previousState, newState, editingRoute, _managerId); if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { EditStateChanged?.Invoke(this, eventArgs); // 向后兼容的事件 PathEditStateChanged?.Invoke(this, newState); }); } else { EditStateChanged?.Invoke(this, eventArgs); PathEditStateChanged?.Invoke(this, newState); } } catch (Exception ex) { LogManager.Error($"[编辑状态变更] 事件触发失败: {ex.Message}"); } } private void RaiseChannelSelectionChanged(List selectedChannels, string selectionMethod) { try { var eventArgs = new ChannelSelectionChangedEventArgs(selectedChannels, selectionMethod, _managerId); if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { ChannelSelectionChanged?.Invoke(this, eventArgs); // 向后兼容的事件 ChannelsSelected?.Invoke(this, selectedChannels); }); } else { ChannelSelectionChanged?.Invoke(this, eventArgs); ChannelsSelected?.Invoke(this, selectedChannels); } } catch (Exception ex) { LogManager.Error($"[通道选择变更] 事件触发失败: {ex.Message}"); } } private void RaisePathPointOperation(PathPointOperationType operationType, PathPoint pathPoint, PathRoute route) { try { var eventArgs = new PathPointOperationEventArgs(operationType, pathPoint, route, _managerId); if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { PathPointOperation?.Invoke(this, eventArgs); // 向后兼容的事件 if (operationType == PathPointOperationType.Added) { PathPointAddedIn3D?.Invoke(this, pathPoint); } else if (operationType == PathPointOperationType.Removed) { PathPointRemovedFrom3D?.Invoke(this, pathPoint); } }); } else { PathPointOperation?.Invoke(this, eventArgs); if (operationType == PathPointOperationType.Added) { PathPointAddedIn3D?.Invoke(this, pathPoint); } else if (operationType == PathPointOperationType.Removed) { PathPointRemovedFrom3D?.Invoke(this, pathPoint); } } } catch (Exception ex) { LogManager.Error($"[路径点操作] 事件触发失败: {ex.Message}"); } } private void RaiseRouteGenerated(PathRoute route, RouteGenerationMethod generationMethod, double gridSize = -1) { try { LogManager.Info($"*** RaiseRouteGenerated被调用: {route?.Name}, Method: {generationMethod}, GridSize: {gridSize} ***"); var eventArgs = new RouteGeneratedEventArgs(route, generationMethod, gridSize, _managerId); // 检查是否有订阅者 if (RouteGenerated != null) { var invocationList = RouteGenerated.GetInvocationList(); LogManager.Info($"*** RouteGenerated事件有 {invocationList.Length} 个订阅者 ***"); for (int i = 0; i < invocationList.Length; i++) { var handler = invocationList[i]; LogManager.Info($"*** 订阅者 {i}: {handler.Target?.GetType().Name}.{handler.Method.Name} ***"); } } else { LogManager.Warning("*** RouteGenerated事件没有订阅者!!! ***"); } // 测试强制同步处理:使用高优先级QueueUIUpdate代替立即执行 if (_uiStateManager != null) { LogManager.Info("*** 使用高优先级强制同步处理RouteGenerated事件 ***"); _uiStateManager.QueueUIUpdateWithForcedSync(() => { LogManager.Info($"*** 强制同步队列中执行RouteGenerated事件: {route?.Name} ***"); RouteGenerated?.Invoke(this, eventArgs); // 向后兼容的事件 RouteGenerated_Legacy?.Invoke(this, route); LogManager.Info($"*** RouteGenerated事件强制同步执行完成: {route?.Name} ***"); }, UIUpdatePriority.Critical, $"RouteGenerated强制同步事件({route?.Name})"); } else { LogManager.Info("*** 直接触发RouteGenerated事件(UIStateManager为null)***"); RouteGenerated?.Invoke(this, eventArgs); RouteGenerated_Legacy?.Invoke(this, route); LogManager.Info($"*** RouteGenerated事件直接调用完成: {route?.Name} ***"); } } catch (Exception ex) { LogManager.Error($"*** [路径生成] 事件触发失败: {ex.Message} ***"); } } private void RaiseCurrentRouteChanged(PathRoute previousRoute, PathRoute newRoute, bool triggerEvent) { try { var eventArgs = new CurrentRouteChangedEventArgs(previousRoute, newRoute, _managerId); // 只有需要触发事件时才执行事件触发逻辑 if (triggerEvent) { if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { CurrentRouteChanged?.Invoke(this, eventArgs); // 向后兼容的事件 CurrentRouteChanged_Legacy?.Invoke(this, newRoute); }); } else { CurrentRouteChanged?.Invoke(this, eventArgs); CurrentRouteChanged_Legacy?.Invoke(this, newRoute); } } } catch (Exception ex) { LogManager.Error($"[当前路径变更] 事件触发失败: {ex.Message}"); } } public void RaisePathPointsListUpdated(PathRoute route, string updateReason) { try { var eventArgs = new PathPointsListUpdatedEventArgs(route, updateReason, _managerId); if (_uiStateManager != null) { _uiStateManager.QueueUIUpdate(() => { PathPointsListUpdated?.Invoke(this, eventArgs); // 向后兼容的事件 PathPointsListUpdated_Legacy?.Invoke(this, route); }); } else { PathPointsListUpdated?.Invoke(this, eventArgs); PathPointsListUpdated_Legacy?.Invoke(this, route); } } catch (Exception ex) { LogManager.Error($"[路径点列表更新] 事件触发失败: {ex.Message}"); } } #endregion #region 核心业务方法 /// /// 切换到查看状态 /// public void SwitchToViewingState() { PathEditState = PathEditState.Viewing; EditingRoute = null; // 智能管理ToolPlugin状态 ManageToolPluginForEditState(); RaiseStatusChanged("已切换到查看状态", PathPlanningStatusType.Info); } /// /// 重置路径编辑状态 /// public void ResetPathEditState() { try { PathEditState = PathEditState.None; LogManager.Info("路径编辑状态已重置"); } catch (Exception ex) { LogManager.Error("重置路径编辑状态失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 清理无效的对象引用 /// public void ClearInvalidReferences() { try { LogManager.Info("[PathPlanningManager] 清理无效对象引用"); // 重置编辑状态 PathEditState = PathEditState.None; // 清空当前路径 if (_currentRoute != null) { _currentRoute.Points.Clear(); } // 清空通道引用 if (_walkableAreas != null) { _walkableAreas.Clear(); LogManager.Info("[PathPlanningManager] 已清空通道引用"); } // 清空组合边界 _combinedChannelBounds = null; LogManager.Info("[PathPlanningManager] 对象引用清理完成"); } catch (Exception ex) { LogManager.Error($"[PathPlanningManager] 清理对象引用失败: {ex.Message}"); } } /// /// 保存当前路线到历史记录 /// /// 保存描述 public void SaveCurrentRouteToHistory(string description = "手动保存") { try { if (CurrentRoute != null) { // 创建历史记录条目 var entry = new PathHistoryEntry(CurrentRoute.Id, PathHistoryOperationType.ManualSave, CurrentRoute, description); _historyManager?.AddHistoryEntry(entry); LogManager.Info($"路线 '{CurrentRoute.Name}' 已保存到历史记录: {description}"); } } catch (Exception ex) { LogManager.Error("保存路线到历史记录失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 清除3D路径标记(保留网格可视化) /// public void Clear3DPathMarkers() { try { _pathPointMarkers?.Clear(); // 清除路径标记但保留网格可视化 _renderPlugin?.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle", "grid_visualization_door"); LogManager.Info("3D路径标记已清除(保留网格可视化)"); } catch (Exception ex) { LogManager.Error("清除3D路径标记失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 删除路径点 /// /// 要删除的路径点 public void RemovePathPoint(PathPoint point) { try { if (point != null) { if (_pathPointMarkers != null) { // 找到对应的PathPointMarker var marker = _pathPointMarkers.FirstOrDefault(m => m.PathPoint?.Id == point.Id); if (marker != null) { _pathPointMarkers.Remove(marker); LogManager.Info($"已从3D中移除路径点标记: {point.Name}"); } } // 重新渲染当前路径以反映更改 if (_renderPlugin != null && CurrentRoute != null) { _renderPlugin.RenderPath(CurrentRoute); LogManager.Info($"已更新路径可视化: {point.Name}"); } // 触发路径点移除事件 RaisePathPointOperation(PathPointOperationType.Removed, point, CurrentRoute); // 保存到数据库 if (CurrentRoute != null) { SavePathToDatabase(CurrentRoute); } } } catch (Exception ex) { LogManager.Error("从3D中移除路径点失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 启动点击工具 /// /// 点击类型 public void StartClickTool(PathPointType pointType) { try { CurrentPointType = pointType; // 检查是否在自动路径模式 - 如果是,则不订阅PathPlanningManager的事件 bool shouldSubscribeToEvents = !IsInAutoPathMode; LogManager.Info($"StartClickTool - 自动路径模式: {IsInAutoPathMode}, 订阅事件: {shouldSubscribeToEvents}"); ActivateToolPlugin(shouldSubscribeToEvents); PathEditState = PathEditState.AddingPoints; LogManager.Info($"点击工具已启动,类型: {pointType},事件订阅: {shouldSubscribeToEvents}"); } catch (Exception ex) { LogManager.Error("启动点击工具失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 停止点击工具 /// public void StopClickTool() { try { LogManager.Debug("[事件清理] ===== 开始执行StopClickTool - 完整事件订阅清理 ====="); // 1. 停用ToolPlugin并清理事件订阅 DeactivateToolPlugin(); // 2. 简化的事件订阅清理 - 移除危险的反射操作 LogManager.Debug("[事件清理] 执行安全的事件订阅清理"); try { // 安全地移除事件订阅,多次取消订阅同一处理程序是安全的 PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; LogManager.Debug("[事件清理] 已安全移除PathPlanningManager.OnToolPluginMouseClicked订阅"); } catch (Exception cleanupEx) { LogManager.Error($"[事件清理] 事件清理过程异常: {cleanupEx.Message}"); } // 注意:移除了PathEditState设置,StopClickTool只管理工具插件状态,不修改业务逻辑状态 LogManager.Debug("[事件清理] ===== StopClickTool执行完成,所有事件订阅已清理 ====="); } catch (Exception ex) { LogManager.Error("停止点击工具失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 禁用鼠标处理(用于自动路径规划模式) /// public void DisableMouseHandling() { try { LogManager.Info("禁用PathPlanningManager鼠标处理,进入自动路径规划模式"); IsInAutoPathMode = true; // 取消PathPlanningManager的鼠标事件订阅 PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; LogManager.Info("已取消PathPlanningManager的鼠标事件订阅"); } catch (Exception ex) { LogManager.Error($"禁用鼠标处理失败: {ex.Message}", ex); } } /// /// 启用鼠标处理(用于手动路径编辑模式) /// public void EnableMouseHandling() { try { LogManager.Info("启用PathPlanningManager鼠标处理,退出自动路径规划模式"); IsInAutoPathMode = false; // 重新订阅PathPlanningManager的鼠标事件 PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; // 先取消避免重复 PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; LogManager.Info("已重新订阅PathPlanningManager的鼠标事件"); } catch (Exception ex) { LogManager.Error($"启用鼠标处理失败: {ex.Message}", ex); } } /// /// 自动路径规划(支持路径策略) /// /// 起点 /// 终点 /// 车辆尺寸(米) /// 安全间隙(米) /// 网格精度(米) /// 车辆高度(米) /// 路径规划策略 /// 规划结果 public Task AutoPlanPath(PathPoint startPoint, PathPoint endPoint, double vehicleRadius, double safetyMargin, double gridSize, double vehicleHeight, PathStrategy strategy) { try { if (startPoint == null || endPoint == null) { throw new ArgumentException("起点和终点不能为空"); } LogManager.Info($"开始自动路径规划: {startPoint.Name} -> {endPoint.Name}"); LogManager.Info($"起点坐标: ({startPoint.Position.X:F2}, {startPoint.Position.Y:F2}, {startPoint.Position.Z:F2})"); LogManager.Info($"终点坐标: ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})"); LogManager.Info($"车辆半径: {vehicleRadius}m, 安全间隙: {safetyMargin}m, 车辆高度: {vehicleHeight}m"); RaiseStatusChanged("正在进行自动路径规划...", PathPlanningStatusType.Info); // 1. 获取模型边界 var bounds = GetModelBounds() ?? throw new Exception("无法获取模型边界,请确保模型已加载"); LogManager.Info($"模型边界: Min({bounds.Min.X:F2}, {bounds.Min.Y:F2}), Max({bounds.Max.X:F2}, {bounds.Max.Y:F2})"); // 智能选择网格大小 if (gridSize <= 0) { gridSize = CalculateOptimalGridSize(bounds); LogManager.Info($"自动选择网格大小: {gridSize}米"); } else { LogManager.Info($"使用用户设置的网格大小: {gridSize}米"); } // 2. 生成网格地图 RaiseStatusChanged("正在生成网格地图...", PathPlanningStatusType.Info); var gridMapGenerator = new GridMapGenerator(); GridMap gridMap = null; try { var performanceStart = System.Diagnostics.Stopwatch.StartNew(); // 获取当前文档 var document = Application.ActiveDocument; LogManager.Info($"网格生成参数 - 边界: {bounds.Min.X:F2},{bounds.Min.Y:F2} -> {bounds.Max.X:F2},{bounds.Max.Y:F2}"); LogManager.Info($"网格生成参数 - 网格大小: {gridSize}m, 车辆半径: {vehicleRadius}m, 安全边距: {safetyMargin}m"); LogManager.Info($"网格生成参数 - 起点: ({startPoint.Position.X:F2}, {startPoint.Position.Y:F2}, {startPoint.Position.Z:F2})"); LogManager.Info($"网格生成参数 - 终点: ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})"); try { gridMap = gridMapGenerator.GenerateFromBIM( bounds, gridSize, vehicleRadius, safetyMargin, startPoint.Position, endPoint.Position, vehicleHeight ); LogManager.Info("✅ 网格地图生成成功"); } catch (Exception modeEx) { LogManager.Warning($"网格地图生成失败,{modeEx.Message}"); } performanceStart.Stop(); LogManager.Info($"GridMapGenerator.GenerateFromBIM 调用完成,耗时: {performanceStart.ElapsedMilliseconds}ms"); LogManager.Info($"生成的网格统计: {gridMap?.GetStatistics() ?? "NULL"}"); } catch (Exception ex) { LogManager.Error($"网格地图生成失败: {ex.Message}"); throw; // 直接抛出原始异常,不包装 } // 根据用户设置决定是否进行网格可视化 if (_showWalkableGrid || _showObstacleGrid || _showUnknownGrid || _showDoorGrid) { LogManager.Info("开始网格可视化,显示所有可通行网格单元"); VisualizeGridCells(gridMap, vehicleHeight); } // 3. 获取通道高度数据 var channelItems = GetChannelItemsForHeightCalculation(gridMap); LogManager.Info($"获取通道数据完成: {channelItems?.Count() ?? 0} 个通道项"); // 4. 创建ChannelCoverage对象(关键修复) ChannelCoverage channelCoverage = null; if (channelItems != null && channelItems.Any()) { LogManager.Info($"创建ChannelCoverage对象,包含 {channelItems.Count()} 个通道项"); channelCoverage = new ChannelCoverage { GridMap = gridMap, ChannelItems = channelItems.ToList(), TotalBounds = bounds }; LogManager.Info($"ChannelCoverage创建完成: {channelCoverage.GetStatistics()}"); } else { LogManager.Error("未找到通道数据,无法进行路径规划"); throw new Exception("路径规划需要通道数据,请先进行通道检测"); } // 5. 执行A*路径查找 RaiseStatusChanged("正在计算最优路径...", PathPlanningStatusType.Info); LogManager.Info("=== 开始执行A*路径查找 ==="); AutoPathFinder pathFinder = null; PathFindingResult pathResult = null; try { pathFinder = new AutoPathFinder(); double vehicleHeightInModelUnits = vehicleHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units); LogManager.Info($"使用2.5D模式进行路径查找,车辆高度: {vehicleHeight}m ({vehicleHeightInModelUnits:F2}模型单位),策略: {strategy}"); pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, vehicleHeightInModelUnits, strategy); LogManager.Info("FindPath方法调用完成"); } catch (Exception ex) { LogManager.Error($"路径查找失败: {ex.Message}"); throw; // 直接抛出原始异常,不包装 } // 1. 检查路径查找是否完全失败 if (pathResult == null) { throw new Exception("路径查找失败"); } // 2. 检查是否找到了可用的路径点(至少2个点才能构成路径) if (pathResult.PathPoints.Count < 2) { throw new Exception("未找到可行路径(起点或终点不可达)"); } // 3. 部分路径也是有效路径,不再抛出异常,继续正常处理 LogManager.Info($"A*算法找到路径,包含 {pathResult.PathPoints.Count} 个点,完成度: {pathResult.CompletionPercentage:F1}%"); // 6. 创建PathRoute对象并保存GridMap var routeName = $"自动路径_{DateTime.Now:HHmmss}"; // 🔥 关键修复:在创建路径前设置_currentGridMap,确保GetSpeedLimitAtPosition能正常工作 _currentGridMap = gridMap; var autoRoute = CreateAutoPathRoute(pathResult, routeName); // 保存GridMap和参数到PathRoute以便后续恢复网格可视化 autoRoute.AssociatedGridMap = gridMap; autoRoute.GridSize = gridSize; // 将vehicleRadius拆分为长宽(暂时使用相同值,后续可以传入更详细的参数) autoRoute.MaxVehicleLength = vehicleRadius * 2; // 车辆半径转换为长度 autoRoute.MaxVehicleWidth = vehicleRadius * 2; // 车辆半径转换为宽度 autoRoute.MaxVehicleHeight = vehicleHeight; autoRoute.SafetyMargin = safetyMargin; LogManager.Info($"已保存GridMap到路径: {routeName}, 网格大小: {gridSize}米"); // 7. 添加到路径集合 if (!_routes.Contains(autoRoute)) { _routes.Add(autoRoute); // 保存自动生成的路径到数据库 SavePathToDatabase(autoRoute); } SetCurrentRouteInternal(autoRoute, triggerEvent: true); // 8. 确保路径可视化使用正确的网格大小(修复尺寸自适应问题) var renderPlugin = PathPointRenderPlugin.Instance; if (renderPlugin != null && gridMap != null) { double gridSizeInMeters = UnitsConverter.ConvertToMeters(gridMap.CellSize); renderPlugin.SetGridSize(gridSizeInMeters); LogManager.Debug($"[路径可视化] 设置网格大小为 {gridSizeInMeters:F3}米,确保路径点尺寸正确"); } // 9. 自动绘制路径可视化 DrawRouteVisualization(autoRoute, isAutoPath: true); // 10. 强制设置路径编辑状态为查看状态(修复状态问题) // 在所有事件触发之前设置状态,确保不会被后续操作重置 LogManager.Info("自动路径规划完成,强制设置状态为Viewing"); PathEditState = PathEditState.Viewing; EditingRoute = null; // 确保没有编辑中的路径 // 11. 触发事件 RaiseRouteGenerated(autoRoute, RouteGenerationMethod.AutoPlanning, gridSize); var statusMessage = $"自动路径规划完成(2.5D模式): {routeName},使用网格大小 {gridSize:F2}米"; // 添加完成度信息 if (!autoRoute.IsComplete) { statusMessage += $" (完成度: {autoRoute.CompletionPercentage:F1}%)"; } RaiseStatusChanged(statusMessage, PathPlanningStatusType.Success); LogManager.Info($"自动路径规划成功完成: 路径长度 {autoRoute.TotalLength:F2}米,包含 {autoRoute.Points.Count} 个点,使用网格大小 {gridSize:F2}米"); return Task.FromResult(autoRoute); } catch (Exception ex) { LogManager.Error($"自动路径规划失败: {ex.Message}", ex); RaiseErrorOccurred(ex.Message, ex); // 使用原始异常消息,不再包装 return Task.FromResult(null); } } /// /// 设置当前路线(UI调用版本,不触发事件以避免循环) /// /// 要设置的路线 public void SetCurrentRoute(PathRoute route) { SetCurrentRouteInternal(route, triggerEvent: false); } /// /// 内部设置当前路线(可选择是否触发事件) /// /// 要设置的路线 /// 是否触发事件 private void SetCurrentRouteInternal(PathRoute route, bool triggerEvent) { try { // 直接设置字段,绕过事件触发 var previousRoute = _currentRoute; _currentRoute = route; // 如果需要触发事件(真正的业务操作) if (triggerEvent) { RaiseCurrentRouteChanged(previousRoute, route, triggerEvent: true); } // 如果路径有关联的GridMap,加载它用于网格可视化 if (route?.AssociatedGridMap != null) { _currentGridMap = route.AssociatedGridMap; LogManager.Info($"已加载路径 '{route.Name}' 的GridMap,网格大小: {route.GridSize}米"); // 如果网格可视化开启,立即刷新显示 if (IsAnyGridVisualizationEnabled) { LogManager.Info("检测到网格可视化已启用,自动刷新网格显示"); RefreshGridVisualization(); } } else { // 如果路径没有GridMap,清空当前缓存 _currentGridMap = null; if (route != null) { LogManager.Info($"路径 '{route.Name}' 没有关联的GridMap"); } } LogManager.Info($"当前路线已设置: {route?.Name ?? "null"}"); } catch (Exception ex) { LogManager.Error("设置当前路线失败", ex); RaiseErrorOccurred(ex.Message, ex); } } /// /// 切换到编辑状态 /// /// 要编辑的路径 public void SwitchToEditingState(PathRoute route) { PathEditState = PathEditState.Editing; EditingRoute = route ?? throw new ArgumentNullException(nameof(route)); SetCurrentRouteInternal(route, triggerEvent: true); // 智能管理ToolPlugin状态 ManageToolPluginForEditState(); RaiseStatusChanged($"已切换到编辑状态,正在编辑路径: {route.Name}", PathPlanningStatusType.Info); } /// /// 选择通道模型 /// /// 是否使用当前选择的模型 /// 选择的通道数量 public int SelectChannels(bool useCurrentSelection = true) { try { _walkableAreas.Clear(); if (useCurrentSelection) { // 使用当前选择的模型 var currentSelection = Application.ActiveDocument.CurrentSelection.SelectedItems; if (currentSelection.Any()) { _walkableAreas.AddRange(currentSelection); RaiseStatusChanged($"已选择 {_walkableAreas.Count} 个模型作为通道", PathPlanningStatusType.Success); } else { RaiseStatusChanged("未选择任何模型,请先选择通道模型", PathPlanningStatusType.Warning); return 0; } } else { // 直接使用 CategoryAttributeManager 的方法筛选通道,无需额外的包装方法 var document = Application.ActiveDocument; if (document != null) { var allLogisticsItems = CategoryAttributeManager.GetAllLogisticsItems(); var channelItems = CategoryAttributeManager.FilterByLogisticsType(allLogisticsItems, CategoryAttributeManager.LogisticsElementType.通道); _walkableAreas.AddRange(channelItems); LogManager.Info($"[SelectChannels] 通过CategoryAttributeManager直接筛选到 {channelItems.Count} 个通道"); } RaiseStatusChanged($"通过类别筛选到 {_walkableAreas.Count} 个通道", PathPlanningStatusType.Success); } if (_walkableAreas.Any()) { // 计算组合边界 CalculateCombinedBounds(); // 触发通道选择变更事件 RaiseChannelSelectionChanged(_walkableAreas, useCurrentSelection ? "手动选择" : "类别筛选"); } return _walkableAreas.Count; } catch (Exception ex) { RaiseErrorOccurred($"选择通道时发生错误: {ex.Message}", ex); return 0; } } /// /// 添加路径到管理器 /// /// 要添加的路径 /// 是否成功添加 public bool AddRoute(PathRoute route) { try { if (route == null) { RaiseErrorOccurred("无法添加空路径"); return false; } // 检查是否已存在同名路径 var existingRoute = _routes.FirstOrDefault(r => r.Name == route.Name); if (existingRoute != null) { // 如果存在同名路径,生成唯一名称 int counter = 1; string originalName = route.Name; while (_routes.Any(r => r.Name == route.Name)) { route.Name = $"{originalName}_{counter}"; counter++; } } _routes.Add(route); RaiseStatusChanged($"已添加路径: {route.Name}", PathPlanningStatusType.Success); // 保存到数据库 SavePathToDatabase(route); // AddRoute只负责添加路径到数据集合,不自动设置当前路径 // 路径选择应该通过专门的选择逻辑处理,而不是添加操作的副作用 // if (_currentRoute == null || _currentRoute.Points.Count == 0) // { // CurrentRoute = route; // } // 注释掉多余的路径生成事件调用,Manual类型路径通过UI层的RefreshPathRoutes()统一刷新 // RaiseRouteGenerated(route, RouteGenerationMethod.Manual); return true; } catch (Exception ex) { RaiseErrorOccurred($"添加路径失败: {ex.Message}", ex); return false; } } /// /// 创建新路径 /// /// 路径名称 /// 新创建的路径 public PathRoute CreateNewRoute(string routeName = null) { if (string.IsNullOrEmpty(routeName)) { routeName = $"路径_{_routes.Count + 1}"; } var newRoute = new PathRoute(routeName); _routes.Add(newRoute); SetCurrentRouteInternal(newRoute, triggerEvent: true); // 保存到数据库 SavePathToDatabase(newRoute); RaiseStatusChanged($"已创建新路径: {routeName}", PathPlanningStatusType.Success); return newRoute; } /// /// 删除路径 /// /// 要删除的路径 /// 是否成功删除 public bool DeleteRoute(PathRoute route) { if (route == null) return false; try { bool removed = _routes.Remove(route); if (removed) { // 从数据库删除 if (_pathDatabase != null) { try { _pathDatabase.DeletePathRoute(route.Id); LogManager.Info($"已从数据库删除路径: {route.Name}"); } catch (Exception dbEx) { LogManager.Error($"从数据库删除路径失败: {dbEx.Message}", dbEx); // 继续执行,不影响内存操作 } } if (_currentRoute == route) { var newRoute = _routes.FirstOrDefault() ?? new PathRoute("默认路径"); SetCurrentRouteInternal(newRoute, triggerEvent: true); } RaiseStatusChanged($"已删除路径: {route.Name}", PathPlanningStatusType.Success); } return removed; } catch (Exception ex) { RaiseErrorOccurred($"删除路径时发生错误: {ex.Message}", ex); return false; } } /// /// 生成路径 /// /// 要生成的路径,为null时使用当前路径 /// 是否成功生成 public bool GeneratePath(PathRoute route = null) { route = route ?? _currentRoute; if (route == null) return false; try { // 验证路径有效性 if (!route.IsValid()) { RaiseErrorOccurred("路径无效:必须包含至少一个起点和一个终点"); return false; } // 更新路径关联的通道ID route.AssociatedChannelIds.Clear(); foreach (var channel in _walkableAreas) { route.AssociatedChannelIds.Add(channel.InstanceGuid.ToString()); } // 计算预估时间(简单实现) CalculateEstimatedTime(route); RaiseStatusChanged($"路径生成成功: {route.Name}, 长度: {route.TotalLength:F2}米, 预估时间: {route.EstimatedTime:F1}秒", PathPlanningStatusType.Success); RaiseRouteGenerated(route, RouteGenerationMethod.Manual); return true; } catch (Exception ex) { RaiseErrorOccurred($"生成路径时发生错误: {ex.Message}", ex); return false; } } /// /// 开始新建路径 /// /// 路径名称 /// 创建的新路径 public PathRoute StartCreatingNewRoute(string routeName = null) { try { // 设置为创建状态 PathEditState = PathEditState.Creating; // 创建新路径 var newRoute = new PathRoute(routeName ?? $"路径{DateTime.Now:yyyyMMdd_HHmmss}"); _editingRoute = newRoute; SetCurrentRouteInternal(newRoute, triggerEvent: true); // 自动选择所有可通行的物流模型 AutoSelectLogisticsChannels(); // 检查是否有可通行的物流模型 if (_walkableAreas == null || _walkableAreas.Count == 0) { RaiseErrorOccurred("没有找到任何可通行的物流模型,请先为模型设置可通行的物流属性"); // 重置状态 SwitchToViewingState(); return null; } // 智能管理ToolPlugin状态 ManageToolPluginForEditState(); RaiseStatusChanged($"正在新建路径: {newRoute.Name} - 请在3D视图中可通行的物流模型上点击设置路径点", PathPlanningStatusType.Info); return newRoute; } catch (Exception ex) { RaiseErrorOccurred($"开始新建路径失败: {ex.Message}", ex); // 确保在出错时也重置状态 SwitchToViewingState(); return null; } } /// /// 完成当前编辑并保存 /// /// 是否成功完成编辑 public bool FinishEditing() { if (!IsInEditableState) { RaiseErrorOccurred("当前不在编辑状态,无法完成编辑"); return false; } try { // 自动设置最后一个点为终点 if (CurrentRoute != null && CurrentRoute.Points.Count > 1) { var lastPoint = CurrentRoute.Points.Last(); if (lastPoint.Type != PathPointType.StartPoint) // 起点不能是终点 { lastPoint.Type = PathPointType.EndPoint; lastPoint.Name = GeneratePointName(PathPointType.EndPoint); // 更新3D路径可视化 // 重新渲染整个路径以反映类型变更 _renderPlugin?.RenderPath(CurrentRoute); LogManager.Info($"已自动设置最后一个点为终点: {lastPoint.Name}"); } } // === 应用曲线化 === if (CurrentRoute != null) { double samplingStep = ConfigManager.Instance.Current.PathEditing.ArcSamplingStep; // 使用配置文件中的默认转弯半径 CurrentRoute.TurnRadius = ConfigManager.Instance.Current.PathEditing.DefaultPathTurnRadius; PathCurveEngine.ApplyCurvatureToRoute(CurrentRoute, samplingStep); LogManager.Info($"路径曲线化完成: {CurrentRoute.Name}, 转弯半径: {CurrentRoute.TurnRadius:F2}m, 边数: {CurrentRoute.Edges.Count}"); } // 如果是创建模式,将当前路径添加到路径集合 if (_pathEditState == PathEditState.Creating && CurrentRoute != null) { if (!_routes.Contains(CurrentRoute)) { _routes.Add(CurrentRoute); // 保存到数据库 SavePathToDatabase(CurrentRoute); // 添加历史记录 var historyEntry = new PathHistoryEntry( CurrentRoute.Id, PathHistoryOperationType.Created, CurrentRoute, $"创建新路径: {CurrentRoute.Name}"); _historyManager.AddHistoryEntry(historyEntry); } } // 如果是编辑模式,保存编辑历史 if (_pathEditState == PathEditState.Editing && EditingRoute != null) { // 更新数据库 SavePathToDatabase(EditingRoute); var historyEntry = new PathHistoryEntry( EditingRoute.Id, PathHistoryOperationType.Edited, EditingRoute, $"编辑路径: {EditingRoute.Name}"); _historyManager.AddHistoryEntry(historyEntry); } // 切换回查看状态 SwitchToViewingState(); // 触发路径点列表更新事件 RaisePathPointsListUpdated(CurrentRoute, "编辑完成"); // 触发路径生成事件 RaiseRouteGenerated(CurrentRoute, RouteGenerationMethod.Manual); RaiseStatusChanged("路径编辑已完成", PathPlanningStatusType.Success); return true; } catch (Exception ex) { RaiseErrorOccurred($"完成编辑失败: {ex.Message}", ex); return false; } } #region 修改路径点功能 /// /// 开始修改指定的路径点 /// /// 要修改的路径点索引 /// 是否成功开始修改 public bool StartEditingPoint(int pointIndex) { try { if (CurrentRoute == null || pointIndex < 0 || pointIndex >= CurrentRoute.Points.Count) { RaiseErrorOccurred("无效的路径点索引或当前没有路径"); return false; } // 保存原始点和索引 _editingPointIndex = pointIndex; var originalPoint = CurrentRoute.Points[pointIndex]; _originalPoint = new PathPoint { Id = originalPoint.Id, Name = originalPoint.Name, Position = originalPoint.Position, Type = originalPoint.Type }; // 切换到修改路径点状态 PathEditState = PathEditState.EditingPoint; // 激活ToolPlugin以接收3D点击 ActivateToolPlugin(); RaiseStatusChanged($"开始修改路径点: {_originalPoint.Name}", PathPlanningStatusType.Info); LogManager.Info($"开始修改路径点,索引: {pointIndex}, 名称: {_originalPoint.Name}"); return true; } catch (Exception ex) { RaiseErrorOccurred($"开始修改路径点失败: {ex.Message}", ex); return false; } } /// /// 设置修改路径点时的预览位置 /// /// 新的预览位置 public void SetEditingPreviewPoint(Point3D position) { try { if (PathEditState != PathEditState.EditingPoint || _editingPointIndex == -1) { return; } // 创建预览路径点 _editingPreviewPoint = new PathPoint { Position = position, Name = _originalPoint.Name + "_预览", Type = _originalPoint.Type }; // 更新预览可视化 UpdateEditingPreviewVisualization(); LogManager.Info($"设置修改预览点: ({position.X:F3}, {position.Y:F3}, {position.Z:F3})"); } catch (Exception ex) { LogManager.Error($"设置修改预览点失败: {ex.Message}"); } } /// /// 更新路径点位置(保存修改) /// /// 是否成功更新 public bool UpdatePointPosition() { try { if (PathEditState != PathEditState.EditingPoint || _editingPointIndex == -1 || _editingPreviewPoint == null || CurrentRoute == null) { RaiseErrorOccurred("当前不在修改路径点状态或没有预览点"); return false; } // 更新路径点位置 var pointToUpdate = CurrentRoute.Points[_editingPointIndex]; pointToUpdate.Position = _editingPreviewPoint.Position; // 添加历史记录 var historyEntry = new PathHistoryEntry( CurrentRoute.Id, PathHistoryOperationType.Edited, CurrentRoute, $"修改路径点 {pointToUpdate.Name} 位置"); _historyManager.AddHistoryEntry(historyEntry); // 清理修改预览可视化(会自动清除预览并重新渲染正常路径) ClearEditingPreviewVisualization(); // 清理修改状态 ClearEditingState(); // 切换回查看状态 PathEditState = PathEditState.Viewing; // 停用ToolPlugin DeactivateToolPlugin(); // 触发路径点列表更新事件 RaisePathPointsListUpdated(CurrentRoute, "路径点修改完成"); // 保存到数据库 SavePathToDatabase(CurrentRoute); RaiseStatusChanged($"路径点 {pointToUpdate.Name} 修改完成", PathPlanningStatusType.Success); LogManager.Info($"路径点修改完成: {pointToUpdate.Name}"); return true; } catch (Exception ex) { RaiseErrorOccurred($"确认修改路径点失败: {ex.Message}"); return false; } } /// /// 取消修改路径点 /// /// 是否成功取消修改 public bool CancelEditPoint() { try { if (PathEditState != PathEditState.EditingPoint) { return true; // 已经不在修改状态,认为成功 } // 清理修改状态 ClearEditingState(); // 切换回查看状态 PathEditState = PathEditState.Viewing; // 停用ToolPlugin DeactivateToolPlugin(); // 清理预览可视化 ClearEditingPreviewVisualization(); RaiseStatusChanged("已取消路径点修改", PathPlanningStatusType.Info); LogManager.Info("已取消路径点修改"); return true; } catch (Exception ex) { RaiseErrorOccurred($"取消修改路径点失败: {ex.Message}", ex); return false; } } /// /// 清理修改路径点的状态 /// private void ClearEditingState() { _editingPointIndex = -1; _originalPoint = null; _editingPreviewPoint = null; } /// /// 更新修改路径点时的预览可视化 /// private void UpdateEditingPreviewVisualization() { try { if (_renderPlugin == null || CurrentRoute == null || _editingPreviewPoint == null) { return; } // 创建预览路径,替换修改中的路径点 var previewRoute = CurrentRoute.Clone() as PathRoute; previewRoute.Points[_editingPointIndex] = _editingPreviewPoint; // 渲染预览路径(使用特殊的预览样式) _renderPlugin.RenderPreviewPath(previewRoute); } catch (Exception ex) { LogManager.Error($"更新修改预览可视化失败: {ex.Message}"); } } /// /// 清理修改路径点时的预览可视化 /// private void ClearEditingPreviewVisualization() { try { if (_renderPlugin == null) { return; } // 清理预览渲染,恢复原始路径渲染 _renderPlugin.ClearPreview(); if (CurrentRoute != null) { _renderPlugin.RenderPath(CurrentRoute); } } catch (Exception ex) { LogManager.Error($"清理修改预览可视化失败: {ex.Message}"); } } #endregion /// /// 取消当前编辑 /// /// 是否成功取消编辑 public bool CancelEditing() { if (!IsInEditableState) { RaiseErrorOccurred("当前不在编辑状态,无法取消编辑"); return false; } try { // 如果是创建模式,清理当前路径 if (_pathEditState == PathEditState.Creating && CurrentRoute != null) { CurrentRoute.Points.Clear(); LogManager.Info("已清理新建路径的临时数据"); } // 切换回查看状态 SwitchToViewingState(); RaiseStatusChanged("路径编辑已取消", PathPlanningStatusType.Info); return true; } catch (Exception ex) { RaiseErrorOccurred($"取消编辑失败: {ex.Message}", ex); return false; } } /// /// 在3D视图中添加路径点 /// /// 3D世界坐标 /// 路径点类型,为null时使用当前类型 /// 添加的路径点,失败时返回null public PathPoint AddPathPointIn3D(Point3D worldPoint, PathPointType? pointType = null) { // 确保在编辑状态下才能添加点 if (!IsInEditableState) { RaiseErrorOccurred("不在编辑状态,无法添加路径点"); return null; } // 如果没有当前路径,则无法添加 if (CurrentRoute == null) { RaiseErrorOccurred("内部错误:当前路径丢失"); return null; } try { // 确定路径点类型 PathPointType finalPointType; if (pointType.HasValue) { finalPointType = pointType.Value; } else { // 自动判断类型:第一个点为起点,其余为路径点 finalPointType = (CurrentRoute.Points.Count == 0) ? PathPointType.StartPoint : PathPointType.WayPoint; } // 创建路径点 var pathPoint = new PathPoint { Name = GeneratePointName(finalPointType), Position = worldPoint, Type = finalPointType }; CurrentRoute.Points.Add(pathPoint); LogManager.Info($"路径点已添加: {pathPoint.Name}, 位置: ({worldPoint.X:F2}, {worldPoint.Y:F2}, {worldPoint.Z:F2})"); // 绘制3D路径可视化(使用与自动路径规划相同的方法) try { DrawRouteVisualization(CurrentRoute, isAutoPath: false); LogManager.Info($"手工路径3D可视化已更新: {pathPoint.Name}"); } catch (Exception renderEx) { LogManager.Error($"绘制手工路径3D可视化失败: {renderEx.Message}"); } // 触发路径点添加事件 RaisePathPointOperation(PathPointOperationType.Added, pathPoint, CurrentRoute); // 触发路径列表更新事件 RaisePathPointsListUpdated(CurrentRoute, "添加路径点"); return pathPoint; } catch (Exception ex) { RaiseErrorOccurred($"添加路径点失败: {ex.Message}", ex); return null; } } /// /// 设置预览点位置(仅用于预览,不添加到路径中) /// /// 3D世界坐标 /// 点类型 /// 预览点对象 public PathPoint SetPreviewPoint(Point3D worldPoint, PathPointType? pointType = null) { // 确保在编辑状态下才能设置预览点 if (!IsInEditableState) { RaiseErrorOccurred("不在编辑状态,无法设置预览点"); return null; } // 如果没有当前路径,则无法设置预览点 if (CurrentRoute == null) { RaiseErrorOccurred("内部错误:当前路径丢失"); return null; } try { // 确定路径点类型 PathPointType finalPointType; if (pointType.HasValue) { finalPointType = pointType.Value; } else { // 自动判断类型:第一个点为起点,其余为路径点 finalPointType = (CurrentRoute.Points.Count == 0) ? PathPointType.StartPoint : PathPointType.WayPoint; } // 计算预览点应该插入的位置 _previewInsertIndex = -1; // 重置插入索引 if (CurrentRoute.Points.Count >= 2) { // 如果路径中有至少2个点,计算最佳插入位置 var nearestSegment = FindNearestLineSegmentWithIndex(worldPoint, CurrentRoute.Points.ToList()); if (nearestSegment.HasValue) { _previewInsertIndex = nearestSegment.Value.insertIndex; LogManager.Info($"预览点计算出插入索引: {_previewInsertIndex},位于 {nearestSegment.Value.prevPoint.Name} 和 {nearestSegment.Value.nextPoint.Name} 之间"); } } // 创建预览点(不添加到路径中) _previewPoint = new PathPoint { Name = $"预览-{GeneratePointName(finalPointType)}", Position = worldPoint, Type = finalPointType }; _isPreviewMode = true; LogManager.Info($"预览点已设置: {_previewPoint.Name}, 位置: ({worldPoint.X:F2}, {worldPoint.Y:F2}, {worldPoint.Z:F2}), 插入索引: {_previewInsertIndex}"); // 绘制预览点可视化(灰色) try { DrawPreviewPointVisualization(_previewPoint); LogManager.Info($"预览点3D可视化已更新: {_previewPoint.Name}"); // 如果路径中有足够的点,绘制预览连线 if (CurrentRoute.Points.Count >= 2) { DrawPreviewLinesVisualization(_previewPoint, CurrentRoute.Points.ToList()); LogManager.Info($"预览连线已绘制: {_previewPoint.Name}"); } } catch (Exception renderEx) { LogManager.Error($"绘制预览点3D可视化失败: {renderEx.Message}"); } return _previewPoint; } catch (Exception ex) { RaiseErrorOccurred($"设置预览点失败: {ex.Message}", ex); return null; } } /// /// 将预览点添加为正式路径点 /// /// 添加的路径点,如果失败返回null public PathPoint ConvertPreviewToPathPoint() { if (!_isPreviewMode || _previewPoint == null) { RaiseErrorOccurred("没有预览点可确认"); return null; } if (CurrentRoute == null) { RaiseErrorOccurred("内部错误:当前路径丢失"); return null; } try { // 创建正式的路径点 var confirmPoint = new PathPoint { Name = GeneratePointName(_previewPoint.Type), Position = _previewPoint.Position, Type = _previewPoint.Type }; // 根据保存的插入索引决定添加方式 if (_previewInsertIndex >= 0 && _previewInsertIndex <= CurrentRoute.Points.Count) { // 在指定位置插入路径点 CurrentRoute.Points.Insert(_previewInsertIndex, confirmPoint); LogManager.Info($"路径点已插入到索引 {_previewInsertIndex}: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})"); } else { // 如果没有有效的插入索引,添加到末尾(原来的行为) CurrentRoute.Points.Add(confirmPoint); LogManager.Info($"路径点已添加到末尾: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})"); } // 清除预览状态 ClearPreviewPoint(); // 绘制3D路径可视化 try { DrawRouteVisualization(CurrentRoute, isAutoPath: false); LogManager.Info($"手工路径3D可视化已更新: {confirmPoint.Name}"); } catch (Exception renderEx) { LogManager.Error($"绘制手工路径3D可视化失败: {renderEx.Message}"); } // 触发路径点添加事件 RaisePathPointOperation(PathPointOperationType.Added, confirmPoint, CurrentRoute); // 触发路径列表更新事件 RaisePathPointsListUpdated(CurrentRoute, "确认添加预览点"); // 保存到数据库 SavePathToDatabase(CurrentRoute); return confirmPoint; } catch (Exception ex) { RaiseErrorOccurred($"确认预览点失败: {ex.Message}"); return null; } } /// /// 清除预览点 /// public void ClearPreviewPoint() { if (_isPreviewMode && _previewPoint != null) { LogManager.Info($"清除预览点: {_previewPoint.Name}"); // 清除预览点可视化 try { ClearPreviewPointVisualization(); } catch (Exception ex) { LogManager.Error($"清除预览点可视化失败: {ex.Message}"); } } _previewPoint = null; _isPreviewMode = false; _previewInsertIndex = -1; // 清除保存的插入索引 } /// /// 绘制预览点可视化(灰色) /// /// 预览点 private void DrawPreviewPointVisualization(PathPoint previewPoint) { if (_renderPlugin != null && previewPoint != null) { // 先清除之前的预览点 _renderPlugin.ClearPreviewPoint(); // 绘制新的灰色预览点 _renderPlugin.RenderPreviewPoint(previewPoint); LogManager.Info($"预览点可视化已绘制: {previewPoint.Name}"); } } /// /// 绘制预览连线的3D可视化(灰色) /// /// 预览点 /// 当前路径点列表 private void DrawPreviewLinesVisualization(PathPoint previewPoint, List pathPoints) { if (_renderPlugin != null && previewPoint != null && pathPoints != null) { // 绘制预览连线 _renderPlugin.RenderPreviewLines(previewPoint, pathPoints); LogManager.Info($"预览连线可视化已绘制: {previewPoint.Name}"); } } /// /// 清除预览点可视化 /// private void ClearPreviewPointVisualization() { if (_renderPlugin != null) { _renderPlugin.ClearPreviewPoint(); LogManager.Info("预览点可视化已清除"); } } /// /// 获取路径统计信息 /// /// 统计信息字符串 public string GetStatistics() { var stats = $"通道数量: {_walkableAreas.Count}\n"; stats += $"路径数量: {_routes.Count}\n"; if (_currentRoute != null) { stats += $"当前路径: {_currentRoute.Name}\n"; stats += $"路径点数: {_currentRoute.Points.Count}\n"; stats += $"路径长度: {_currentRoute.TotalLength:F2}米\n"; stats += $"预估时间: {_currentRoute.EstimatedTime:F1}秒\n"; } if (_combinedChannelBounds != null) { double scaleX = 0, scaleY = 0; _coordinateConverter?.GetMapScale(out scaleX, out scaleY); stats += $"通道范围: {_combinedChannelBounds.MinPoint.X:F2},{_combinedChannelBounds.MinPoint.Y:F2} - {_combinedChannelBounds.MaxPoint.X:F2},{_combinedChannelBounds.MaxPoint.Y:F2}\n"; stats += $"地图缩放: {scaleX:F4}, {scaleY:F4}"; } return stats; } /// /// 验证路径管理器状态 /// /// 验证结果 public PathPlanningResult ValidateManagerState() { try { var errors = new List(); // 检查基础组件 if (_categoryManager == null) errors.Add("类别属性管理器未初始化"); if (_uiStateManager == null) errors.Add("UI状态管理器未初始化"); // 检查Navisworks环境 var document = Application.ActiveDocument; if (document == null) errors.Add("当前没有活动的Navisworks文档"); else if (document.Models == null || !document.Models.Any()) errors.Add("当前文档中没有加载的模型"); // 检查通道选择状态 if (_walkableAreas.Count == 0) errors.Add("没有选择任何通道模型"); if (errors.Count > 0) { return PathPlanningResult.ValidationFailure($"路径管理器状态验证失败: {string.Join("; ", errors)}"); } return PathPlanningResult.Success("路径管理器状态验证通过"); } catch (Exception ex) { LogManager.Error("验证路径管理器状态时发生异常", ex); return PathPlanningResult.ValidationFailure($"状态验证异常: {ex.Message}"); } } /// /// 验证路径有效性 /// /// 要验证的路径 /// 验证结果 public PathPlanningResult ValidateRoute(PathRoute route) { try { if (route == null) return PathPlanningResult.ValidationFailure("路径不能为空"); var errors = new List(); var warnings = new List(); // 基本验证 if (string.IsNullOrWhiteSpace(route.Name)) errors.Add("路径名称不能为空"); if (route.Points.Count < 2) errors.Add("路径至少需要包含2个点"); // 点类型验证 var startPoints = route.Points.Where(p => p.Type == PathPointType.StartPoint).ToList(); var endPoints = route.Points.Where(p => p.Type == PathPointType.EndPoint).ToList(); if (startPoints.Count == 0) errors.Add("路径必须包含至少一个起点"); else if (startPoints.Count > 1) warnings.Add($"路径包含多个起点({startPoints.Count}个)"); if (endPoints.Count == 0) errors.Add("路径必须包含至少一个终点"); else if (endPoints.Count > 1) warnings.Add($"路径包含多个终点({endPoints.Count}个)"); // 坐标验证 foreach (var point in route.Points) { if (point.Position == null) errors.Add($"路径点 '{point.Name}' 缺少位置信息"); } // 路径长度验证 if (route.TotalLength < 0.1) warnings.Add("路径长度过短,可能存在重复点"); else if (route.TotalLength > 10000) warnings.Add("路径长度过长,可能影响性能"); // 构建结果 if (errors.Count > 0) { return PathPlanningResult.ValidationFailure($"路径验证失败: {string.Join("; ", errors)}"); } var message = "路径验证通过"; if (warnings.Count > 0) { message += $" (警告: {string.Join("; ", warnings)})"; } return PathPlanningResult.Success(message); } catch (Exception ex) { LogManager.Error($"验证路径 '{route?.Name}' 时发生异常", ex); return PathPlanningResult.ValidationFailure($"路径验证异常: {ex.Message}"); } } #endregion #region 辅助方法(暂时保留原有实现,后续会重构) private void CalculateCombinedBounds() { // 保留原有实现,但移除UI相关调用 if (!_walkableAreas.Any()) { _combinedChannelBounds = null; return; } try { var conversionFactor = GetUnitsToMetersConversionFactor(); var units = Application.ActiveDocument.Units; var allBounds = new List(); foreach (var channel in _walkableAreas) { try { var originalBoundingBox = channel.BoundingBox(); if (originalBoundingBox != null) { var boundingBoxInMeters = ConvertBoundingBoxToMeters(originalBoundingBox, conversionFactor); allBounds.Add(boundingBoxInMeters); } } catch { continue; } } if (allBounds.Any()) { var minX = allBounds.Min(b => b.Min.X); var minY = allBounds.Min(b => b.Min.Y); var minZ = allBounds.Min(b => b.Min.Z); var maxX = allBounds.Max(b => b.Max.X); var maxY = allBounds.Max(b => b.Max.Y); var maxZ = allBounds.Max(b => b.Max.Z); var combinedBoundingBox = new BoundingBox3D( new Point3D(minX, minY, minZ), new Point3D(maxX, maxY, maxZ) ); _combinedChannelBounds = new ChannelBounds(combinedBoundingBox); RaiseStatusChanged($"已计算通道边界: {_combinedChannelBounds.MinPoint.X:F2},{_combinedChannelBounds.MinPoint.Y:F2} - {_combinedChannelBounds.MaxPoint.X:F2},{_combinedChannelBounds.MaxPoint.Y:F2}", PathPlanningStatusType.Info); } } catch (Exception ex) { RaiseErrorOccurred($"计算通道边界时发生错误: {ex.Message}", ex); } } /// /// 计算预估时间 /// private void CalculateEstimatedTime(PathRoute route) { // 简单的时间估算:假设平均速度1米/秒 const double averageSpeed = 1.0; // 米/秒 route.EstimatedTime = route.TotalLength / averageSpeed; } /// /// 生成路径点名称 /// private string GeneratePointName(PathPointType pointType) { var currentPoints = _currentRoute?.Points ?? new List(); var typeCount = currentPoints.Count(p => p.Type == pointType) + 1; switch (pointType) { case PathPointType.StartPoint: // 起点固定显示为"起点",不带编号 return "起点"; case PathPointType.EndPoint: // 终点固定显示为"终点",不带编号 return "终点"; case PathPointType.WayPoint: return $"路径点{typeCount}"; default: return $"点{typeCount}"; } } /// /// 自动选择所有可通行的物流模型 /// private void AutoSelectLogisticsChannels() { try { var document = Application.ActiveDocument; if (document?.Models == null) return; _walkableAreas.Clear(); LogManager.Info("[通道自动选择] 开始搜索可通行的物流模型"); // 使用CategoryAttributeManager统一接口获取物流项目 var allLogisticsItemsCollection = CategoryAttributeManager.GetAllLogisticsItems(); LogManager.Info($"[通道自动选择] CategoryAttributeManager找到 {allLogisticsItemsCollection.Count} 个具有物流属性的模型项"); // 筛选出可通行的物流模型 var traversableItems = CategoryAttributeManager.FilterTraversableItems(allLogisticsItemsCollection); LogManager.Info($"[通道自动选择] 筛选出 {traversableItems.Count} 个可通行的物流模型"); // 将可通行的物流模型添加到_selectedChannels foreach (ModelItem item in traversableItems) { _walkableAreas.Add(item); LogManager.Info($"[通道自动选择] 添加可通行模型: '{item.DisplayName}'"); } if (_walkableAreas.Count > 0) { // 计算组合边界 CalculateCombinedBounds(); // 触发通道选择变更事件 RaiseChannelSelectionChanged(_walkableAreas, "自动选择"); LogManager.Info($"[通道自动选择] ✅ 自动选择了 {_walkableAreas.Count} 个可通行的物流模型"); } else { LogManager.Warning("[通道自动选择] ❌ 未找到任何可通行的物流模型"); } } catch (Exception ex) { LogManager.Error($"[通道自动选择] 自动选择可通行物流模型失败: {ex.Message}"); RaiseErrorOccurred($"自动选择可通行物流模型失败: {ex.Message}", ex); } } /// /// 智能ToolPlugin管理:根据编辑状态自动激活或停用 /// private void ManageToolPluginForEditState() { try { if (IsInEditableState) { // 编辑状态:确保ToolPlugin已激活 if (!_isToolPluginActive) { ActivateToolPlugin(); } } else { // 查看状态:确保ToolPlugin已停用 if (_isToolPluginActive) { DeactivateToolPlugin(); } } } catch (Exception ex) { LogManager.Error($"管理ToolPlugin状态时发生错误: {ex.Message}"); RaiseErrorOccurred($"管理ToolPlugin状态失败: {ex.Message}", ex); } } /// /// 激活自定义ToolPlugin进行精确点击检测 /// /// 是否订阅鼠标事件 private bool ActivateToolPlugin(bool subscribeToEvents = true) { // 如果已经激活,检查是否需要订阅事件 if (_isToolPluginActive) { LogManager.Debug("[ToolPlugin] ToolPlugin已激活,检查事件订阅状态"); if (subscribeToEvents) { // 确保事件订阅(避免重复订阅) PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; LogManager.Debug("[ToolPlugin] 已确保PathPlanningManager事件订阅"); } return true; } try { LogManager.Debug("[ToolPlugin] ===== 开始激活ToolPlugin ====="); LogManager.Debug($"[ToolPlugin] 订阅事件: {subscribeToEvents}"); LogManager.Debug($"[ToolPlugin] 当前应用程序状态: {Application.IsAutomated}"); LogManager.Debug($"[ToolPlugin] 当前文档状态: {Application.ActiveDocument?.Title ?? "NULL"}"); // 1. 加载插件程序集 LogManager.Debug("[ToolPlugin] 步骤1: 加载插件程序集"); var assemblyPath = PathClickToolPlugin.AssemblyPath; LogManager.Debug($"[ToolPlugin] 程序集路径: {assemblyPath}"); LogManager.Debug($"[ToolPlugin] 程序集文件是否存在: {System.IO.File.Exists(assemblyPath)}"); Application.Plugins.AddPluginAssembly(assemblyPath); LogManager.Debug("[ToolPlugin] ✓ 程序集加载完成"); // 2. 查找插件 LogManager.Debug("[ToolPlugin] 步骤2: 查找插件"); ToolPluginRecord toolPluginRecord = (ToolPluginRecord)Application.Plugins.FindPlugin("PathClickTool.NavisworksTransport"); if (toolPluginRecord == null) { LogManager.Error("[ToolPlugin] ✗ 错误: 无法找到PathClickTool插件"); return false; } LogManager.Debug("[ToolPlugin] ✓ 插件查找成功"); // 3. 加载插件 LogManager.Debug("[ToolPlugin] 步骤3: 加载插件"); var loadedPlugin = toolPluginRecord.LoadPlugin(); if (loadedPlugin == null) { LogManager.Error("[ToolPlugin] ✗ 错误: 插件加载失败"); return false; } LogManager.Debug("[ToolPlugin] ✓ 插件加载成功"); // 4. 设置为活动工具 LogManager.Debug("[ToolPlugin] 步骤4: 设置为活动工具"); // 先重置工具状态,清除可能的导航工具 // 这一步很重要,确保从导航工具(如Pan、Orbit)切换回自定义工具 Application.MainDocument.Tool.Value = Tool.None; LogManager.Debug("[ToolPlugin] 已重置工具状态为None"); // 然后设置自定义工具插件 Application.MainDocument.Tool.SetCustomToolPlugin(loadedPlugin); LogManager.Debug("[ToolPlugin] ✓ 工具设置成功"); // 5. 根据参数决定是否订阅点击事件 if (subscribeToEvents) { LogManager.Debug("[ToolPlugin] 步骤5: 订阅点击事件"); PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; LogManager.Debug("[ToolPlugin] ✓ PathPlanningManager事件订阅成功"); } else { LogManager.Debug("[ToolPlugin] 步骤5: 跳过事件订阅(由外部组件管理)"); } _isToolPluginActive = true; LogManager.Info("[ToolPlugin] ===== ToolPlugin激活完成 ====="); return true; } catch (Exception ex) { LogManager.Error($"[ToolPlugin] 激活异常: {ex.Message}"); LogManager.Error($"[ToolPlugin] 堆栈: {ex.StackTrace}"); return false; } } /// /// 重新激活ToolPlugin(供InputMonitor调用) /// 用于在工具失活后快速恢复,不重复订阅事件 /// public void ReactivateToolPlugin() { try { // 检查当前状态和实际工具值 if ((PathEditState == PathEditState.Creating || PathEditState == PathEditState.AddingPoints || PathEditState == PathEditState.EditingPoint)) { // 检查当前工具是否为自定义工具,如果不是则需要重新激活 var currentTool = Application.MainDocument.Tool.Value; if (currentTool != Tool.CustomToolPlugin) { LogManager.Debug($"[ReactivateToolPlugin] 当前工具为{currentTool},开始重新激活ToolPlugin"); // 重要:先将激活标志设置为false,强制执行完整的激活流程 _isToolPluginActive = false; // 调用现有的激活方法,但不重复订阅事件 if (ActivateToolPlugin(false)) { LogManager.Info("[ReactivateToolPlugin] ToolPlugin重新激活成功"); RaiseStatusChanged("工具已重新激活", PathPlanningStatusType.Info); } else { LogManager.Warning("[ReactivateToolPlugin] ToolPlugin重新激活失败"); RaiseErrorOccurred("无法重新激活编辑工具"); } } else { LogManager.Debug("[ReactivateToolPlugin] 当前已是CustomToolPlugin,无需重新激活"); } } else { LogManager.Debug($"[ReactivateToolPlugin] 跳过重新激活 - PathEditState: {PathEditState}"); } } catch (Exception ex) { LogManager.Error($"[ReactivateToolPlugin] 重新激活失败: {ex.Message}"); RaiseErrorOccurred($"重新激活工具失败: {ex.Message}", ex); } } /// /// 处理ToolPlugin的鼠标点击事件 /// private void OnToolPluginMouseClicked(object sender, PickItemResult pickResult) { try { // 如果在自动路径规划模式,则跳过处理(应该由PathEditingViewModel处理) if (IsInAutoPathMode) { LogManager.Debug("[ToolPlugin事件] 当前在自动路径规划模式,跳过PathPlanningManager处理"); return; } // 手动路径编辑处理 ProcessManualPathEditing(pickResult); } catch (Exception ex) { LogManager.Error($"[ToolPlugin事件] 处理异常: {ex.Message}"); LogManager.Error($"[ToolPlugin事件] 堆栈: {ex.StackTrace}"); } } /// /// 处理手动路径编辑的鼠标点击 /// private void ProcessManualPathEditing(PickItemResult pickResult) { // 检查当前选中的通道状态 LogManager.Debug($"[手动编辑] 当前_selectedChannels状态: {(_walkableAreas == null ? "NULL" : $"包含{_walkableAreas.Count}个项目")}"); // 如果没有选中的通道,尝试实时搜索 if (_walkableAreas == null || _walkableAreas.Count == 0) { LogManager.Debug("[手动编辑] 没有预选通道,开始实时搜索可通行的物流模型"); SearchAndSetTraversableChannels(); } // 检查是否在可通行的物流模型内并处理点击 if (_walkableAreas != null && _walkableAreas.Any()) { bool isInTraversableLogisticsModel = IsItemInSelectedChannels(pickResult.ModelItem) || IsItemChildOfSelectedChannels(pickResult.ModelItem); LogManager.Debug($"[手动编辑] 在可通行的物流模型内: {isInTraversableLogisticsModel}"); if (isInTraversableLogisticsModel) { // 手动路径编辑 - 根据当前模式处理点击 if (PathEditState == PathEditState.AddingPoints) { // 添加路径点模式 - 使用预览点 LogManager.Debug("[手动编辑] 设置预览点位置"); var previewPoint = SetPreviewPoint(pickResult.Point); if (previewPoint != null) { LogManager.Debug($"[手动编辑] ✓ 预览点已设置: {previewPoint.Name}"); } else { LogManager.Warning("[手动编辑] ✗ 预览点设置失败"); } } else if (PathEditState == PathEditState.EditingPoint) { // 修改路径点模式 - 设置预览位置 LogManager.Debug("[手动编辑] 设置修改路径点预览位置"); SetEditingPreviewPoint(pickResult.Point); LogManager.Debug($"[手动编辑] ✓ 修改路径点预览位置已设置: ({pickResult.Point.X:F3}, {pickResult.Point.Y:F3}, {pickResult.Point.Z:F3})"); } else { // 其他编辑模式 - 保持原有逻辑 LogManager.Debug("[手动编辑] 调用AddPathPointIn3D添加路径点"); var pathPoint = AddPathPointIn3D(pickResult.Point); if (pathPoint != null) { LogManager.Debug($"[手动编辑] ✓ 路径点添加成功: {pathPoint.Name}"); } else { LogManager.Warning("[手动编辑] ✗ 路径点添加失败"); } } } else { LogManager.Debug("[手动编辑] ✗ 点击位置不在可通行的物流模型内"); RaiseErrorOccurred("点击位置不在物流通道内,请选择有效的物流路径位置"); } } else { LogManager.Warning("[手动编辑] ✗ 未找到可通行的物流模型"); RaiseErrorOccurred("未找到可通行的物流通道,请先选择或配置物流通道"); } } /// /// 搜索并设置可通行的通道 /// private void SearchAndSetTraversableChannels() { try { var document = Application.ActiveDocument; if (document?.Models != null) { // 使用CategoryAttributeManager统一接口获取物流项目 var logisticsItemsCollection = CategoryAttributeManager.GetAllLogisticsItems(); LogManager.Debug($"[搜索通道] CategoryAttributeManager找到 {logisticsItemsCollection.Count} 个物流模型"); if (logisticsItemsCollection.Count > 0) { // 筛选出可通行的物流模型 var traversableItems = CategoryAttributeManager.FilterTraversableItems(logisticsItemsCollection); LogManager.Debug($"[搜索通道] 筛选出 {traversableItems.Count} 个可通行的物流模型"); // 临时设置为选中通道 if (_walkableAreas == null) _walkableAreas = new List(); _walkableAreas.Clear(); foreach (ModelItem item in traversableItems) { _walkableAreas.Add(item); LogManager.Debug($"[搜索通道] 添加可通行模型: '{item.DisplayName}'"); } } } } catch (Exception searchEx) { LogManager.Error($"[搜索通道] 实时搜索失败: {searchEx.Message}"); } } /// /// 获取Navisworks文档单位并转换为米的系数 /// private double GetUnitsToMetersConversionFactor() { try { var units = Application.ActiveDocument.Units; switch (units) { case Units.Millimeters: return 0.001; case Units.Centimeters: return 0.01; case Units.Meters: return 1.0; case Units.Inches: return 0.0254; case Units.Feet: return 0.3048; case Units.Kilometers: return 1000.0; case Units.Micrometers: return 0.000001; case Units.Microinches: return 0.0000000254; case Units.Mils: return 0.0000254; case Units.Yards: return 0.9144; case Units.Miles: return 1609.43; default: return 1.0; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"获取文档单位失败: {ex.Message},默认为米"); return 1.0; } } /// /// 转换包围盒到米单位 /// private BoundingBox3D ConvertBoundingBoxToMeters(BoundingBox3D boundingBox, double conversionFactor) { var minPoint = new Point3D( boundingBox.Min.X * conversionFactor, boundingBox.Min.Y * conversionFactor, boundingBox.Min.Z * conversionFactor ); var maxPoint = new Point3D( boundingBox.Max.X * conversionFactor, boundingBox.Max.Y * conversionFactor, boundingBox.Max.Z * conversionFactor ); return new BoundingBox3D(minPoint, maxPoint); } #endregion #region IDisposable实现 public void Dispose() { try { // 清理资源 _renderPlugin?.ClearAllPaths(); _renderPlugin = null; // 停用ToolPlugin if (_isToolPluginActive) { DeactivateToolPlugin(); } } catch (Exception ex) { LogManager.Error($"PathPlanningManager释放时发生错误: {ex.Message}"); } } private bool DeactivateToolPlugin() { if (!_isToolPluginActive) { LogManager.Debug("[ToolPlugin] ToolPlugin未激活,无需停用"); return true; } try { // 1. 取消事件订阅 PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; // 2. 重置为无活动工具状态 try { // 使用Tool.None重置到无活动工具状态,让Navisworks处理默认导航 Application.MainDocument.Tool.Value = Tool.None; } catch (Exception ex) { LogManager.Warning($"[ToolPlugin] 重置工具状态失败: {ex.Message}"); } _isToolPluginActive = false; LogManager.Debug("[ToolPlugin] ===== ToolPlugin停用完成 ====="); return true; } catch (Exception ex) { LogManager.Error($"[ToolPlugin] 停用异常: {ex.Message}"); LogManager.Error($"[ToolPlugin] 堆栈: {ex.StackTrace}"); return false; } } /// /// 强制重新初始化ToolPlugin(公共接口,避免反射调用) /// /// 是否订阅事件 /// 初始化是否成功 public bool ForceReinitializeToolPlugin(bool subscribeToEvents = false) { try { LogManager.Debug($"[工具插件重初始化] 开始强制重新初始化ToolPlugin,订阅事件: {subscribeToEvents}"); // 1. 停用当前ToolPlugin bool deactivated = DeactivateToolPlugin(); LogManager.Debug($"[工具插件重初始化] 停用结果: {deactivated}"); // 2. 强制重置激活状态 _isToolPluginActive = false; LogManager.Debug("[工具插件重初始化] 已重置激活状态标志"); // 3. 重新激活ToolPlugin bool activated = ActivateToolPlugin(subscribeToEvents); LogManager.Debug($"[工具插件重初始化] 激活结果(事件订阅: {subscribeToEvents}): {activated}"); if (activated) { LogManager.Info("[工具插件重初始化] ToolPlugin重新初始化成功,已获得鼠标焦点"); } else { LogManager.Error("[工具插件重初始化] ToolPlugin激活失败"); } return activated; } catch (Exception ex) { LogManager.Error($"[工具插件重初始化] 重新初始化ToolPlugin失败: {ex.Message}", ex); return false; } } #endregion #region 公共访问方法 /// /// 获取PathDatabase实例 /// public PathDatabase GetPathDatabase() { return _pathDatabase; } /// /// 更新路径并保存到数据库 /// public void UpdateRoute(PathRoute route) { if (route == null) return; SavePathToDatabase(route); } #endregion #region 自动路径规划辅助方法 /// /// 获取当前模型的边界框 /// /// 模型边界框 private BoundingBox3D GetModelBounds() { try { // 如果没有选中的可通行区域,自动搜索 if (_walkableAreas == null || _walkableAreas.Count == 0) { LogManager.Info("未找到预定义的可通行区域,尝试自动搜索..."); AutoSelectLogisticsChannels(); } // 检查是否找到可通行区域 if (_walkableAreas == null || _walkableAreas.Count == 0) { LogManager.Error("没有找到任何可通行区域(通道、门、电梯、楼梯等)"); throw new InvalidOperationException("无法进行路径规划:模型中没有定义可通行的物流区域。请先设置物流属性。"); } // 使用可通行区域的边界作为路径规划范围 return CalculateChannelsBounds(_walkableAreas); } catch (Exception ex) { LogManager.Error($"获取模型边界失败: {ex.Message}"); throw; } } /// /// 计算选中通道的组合边界 /// private BoundingBox3D CalculateChannelsBounds(List channels) { var allBounds = new List(); foreach (var channel in channels) { var bounds = channel.BoundingBox(); if (bounds != null) { allBounds.Add(bounds); } } if (!allBounds.Any()) return null; var minX = allBounds.Min(b => b.Min.X); var minY = allBounds.Min(b => b.Min.Y); var minZ = allBounds.Min(b => b.Min.Z); var maxX = allBounds.Max(b => b.Max.X); var maxY = allBounds.Max(b => b.Max.Y); var maxZ = allBounds.Max(b => b.Max.Z); return new BoundingBox3D( new Point3D(minX, minY, minZ), new Point3D(maxX, maxY, maxZ) ); } /// /// 计算最优网格大小 /// private double CalculateOptimalGridSize(BoundingBox3D bounds) { try { var width = bounds.Max.X - bounds.Min.X; var height = bounds.Max.Y - bounds.Min.Y; var maxDimension = Math.Max(width, height); // 基于模型大小智能选择网格大小 if (maxDimension > 1000) return 5.0; // 大型模型:5米 if (maxDimension > 500) return 2.0; // 中型模型:2米 return 0.5; // 小型模型:0.5米 } catch { return 0.5; // 默认值改为0.5米,与UI默认设置保持一致 } } /// /// 获取通道模型项用于高度计算 /// private IEnumerable GetChannelItemsForHeightCalculation(GridMap gridMap = null) { var channelItems = new List(); try { // 🔥 关键修复:优先使用网格生成时已确定的通道数据 if (gridMap?.ChannelItems != null && gridMap.ChannelItems.Any()) { LogManager.Info($"[通道数据] 使用网格生成时的通道数据,数量: {gridMap.ChannelItems.Count()}"); channelItems.AddRange(gridMap.ChannelItems); return channelItems; } // 如果用户已选择通道,优先使用用户选择的通道 if (_walkableAreas != null && _walkableAreas.Count > 0) { LogManager.Info($"[通道数据] 使用用户选择的通道,数量: {_walkableAreas.Count}"); channelItems.AddRange(_walkableAreas); return channelItems; } // 否则使用CategoryAttributeManager搜索 LogManager.Info("[通道数据] 用户未选择通道且网格无通道数据,使用CategoryAttributeManager搜索"); var document = Application.ActiveDocument; if (document != null) { var foundChannelsCollection = CategoryAttributeManager.GetAllLogisticsItems(); foreach (ModelItem item in foundChannelsCollection) { channelItems.Add(item); } } LogManager.Info($"[通道数据] 找到 {channelItems.Count} 个通道模型项"); return channelItems; } catch (Exception ex) { LogManager.Error($"[通道数据] 获取通道项失败: {ex.Message}"); return channelItems; } } /// /// 从A*算法结果创建PathRoute对象 /// private PathRoute CreateAutoPathRoute(PathFindingResult pathResult, string routeName) { try { var route = new PathRoute(routeName); var pathPoints = pathResult.PathPoints; // 设置路径完成状态信息 route.IsComplete = pathResult.IsComplete; route.OriginalEndPoint = pathResult.OriginalEndPoint; route.ActualEndPoint = pathResult.ActualEndPoint; route.CompletionPercentage = pathResult.CompletionPercentage; for (int i = 0; i < pathPoints.Count; i++) { var point = pathPoints[i]; var pathPoint = new PathPoint { Name = GenerateAutoPathPointName(i, pathPoints.Count), Position = point, Type = DeterminePointType(i, pathPoints.Count), SpeedLimit = GetSpeedLimitAtPosition(point) }; route.Points.Add(pathPoint); } // 计算路径长度 route.RecalculateLength(); LogManager.Info($"创建自动路径: {routeName}, 点数: {pathPoints.Count}, 长度: {route.TotalLength:F2}米"); return route; } catch (Exception ex) { LogManager.Error($"创建自动路径失败: {ex.Message}"); return null; } } /// /// 根据世界坐标获取该位置的限速 /// /// 世界坐标 /// 限速值(米/秒),0表示未设置限速 private double GetSpeedLimitAtPosition(Point3D worldPosition) { try { // 如果没有当前网格地图,返回0 if (_currentGridMap == null) { return 0; } // 将世界坐标转换为网格坐标 var gridPos = _currentGridMap.WorldToGrid(worldPosition); // 检查网格坐标是否有效 if (!_currentGridMap.IsValidGridPosition(gridPos)) { return 0; } // 获取网格单元格 var cell = _currentGridMap.GetCell(gridPos); return cell?.SpeedLimit ?? 0; } catch (Exception ex) { LogManager.Error($"获取位置限速失败: {ex.Message}"); return 0; } } /// /// 生成自动路径点名称 /// private string GenerateAutoPathPointName(int index, int totalCount) { if (index == 0) return "自动起点"; if (index == totalCount - 1) return "自动终点"; return $"自动点{index}"; } /// /// 确定路径点类型 /// private PathPointType DeterminePointType(int index, int totalCount) { if (index == 0) return PathPointType.StartPoint; if (index == totalCount - 1) return PathPointType.EndPoint; return PathPointType.WayPoint; } /// /// 绘制路径可视化 /// public void DrawRouteVisualization(PathRoute route, bool isAutoPath = false) { if (route == null) return; try { var renderPlugin = PathPointRenderPlugin.Instance; if (renderPlugin == null) { LogManager.Warning("PathPointRenderPlugin实例为空,无法绘制路径"); return; } // 使用新的统一路径渲染API renderPlugin.RenderPath(route); LogManager.Info($"已渲染路径: {route.Name},包含 {route.Points.Count} 个路径点"); } catch (Exception ex) { LogManager.Warning($"路径可视化失败: {ex.Message}"); } } #endregion #region 辅助方法(检查项目关系) /// /// 检查项目是否在选定通道中 /// /// 要检查的项目 /// 是否在选定通道中 private bool IsItemInSelectedChannels(ModelItem item) { return _walkableAreas.Contains(item) || IsItemChildOfSelectedChannels(item); } /// /// 检查项目是否为选定通道的子项 /// /// 要检查的项目 /// 是否为子项 private bool IsItemChildOfSelectedChannels(ModelItem item) { foreach (var channel in _walkableAreas) { if (IsChildOf(item, channel)) { return true; } } return false; } /// /// 递归检查是否为子项 /// /// 子项 /// 父项 /// 是否为子项 private bool IsChildOf(ModelItem child, ModelItem parent) { var currentParent = child.Parent; while (currentParent != null) { if (currentParent == parent) { return true; } currentParent = currentParent.Parent; } return false; } /// /// 状态变更通知(向后兼容方法) /// /// 状态消息 private void OnStatusChanged(string status) { try { // 使用新的事件触发机制 RaiseStatusChanged(status, PathPlanningStatusType.Info); } catch (Exception ex) { LogManager.Error($"[PathManager] OnStatusChanged方法异常: {ex.Message}"); LogManager.Error($"[PathManager] 状态消息: {status}"); } } #endregion #region 预览插入位置计算方法 /// /// 查找预览点应该插入的最近线段和插入索引 /// /// 预览点位置 /// 路径点列表 /// 最近线段的前后两点以及插入索引,未找到时返回null private (PathPoint prevPoint, PathPoint nextPoint, int insertIndex)? FindNearestLineSegmentWithIndex(Point3D previewPosition, List pathPoints) { if (pathPoints == null || pathPoints.Count < 2) { return null; } // 对路径点进行排序(按添加顺序,即列表中的索引) var sortedPoints = pathPoints.ToList(); double minDistance = double.MaxValue; (PathPoint prevPoint, PathPoint nextPoint, int insertIndex)? nearestSegment = null; // 遍历相邻的路径点对,找到距离预览点最近的线段 for (int i = 0; i < sortedPoints.Count - 1; i++) { var currentPoint = sortedPoints[i]; var nextPoint = sortedPoints[i + 1]; // 计算预览点到线段的距离 var distance = CalculatePointToLineSegmentDistance(previewPosition, currentPoint.Position, nextPoint.Position); if (distance < minDistance) { minDistance = distance; // 插入索引应该是nextPoint的索引位置,这样新点会插入到currentPoint和nextPoint之间 nearestSegment = (currentPoint, nextPoint, i + 1); } } return nearestSegment; } /// /// 计算点到线段的最短距离 /// /// 目标点 /// 线段起点 /// 线段终点 /// 最短距离 private double CalculatePointToLineSegmentDistance(Point3D point, Point3D lineStart, Point3D lineEnd) { // 线段向量 var lineVector = new Point3D(lineEnd.X - lineStart.X, lineEnd.Y - lineStart.Y, lineEnd.Z - lineStart.Z); // 点到线段起点的向量 var pointVector = new Point3D(point.X - lineStart.X, point.Y - lineStart.Y, point.Z - lineStart.Z); // 计算线段长度的平方 var lineLengthSquared = lineVector.X * lineVector.X + lineVector.Y * lineVector.Y + lineVector.Z * lineVector.Z; if (lineLengthSquared == 0) { // 线段退化为点,返回点到点的距离 return CalculateDistance(point, lineStart); } // 计算投影参数t var t = (pointVector.X * lineVector.X + pointVector.Y * lineVector.Y + pointVector.Z * lineVector.Z) / lineLengthSquared; // 将t限制在[0,1]范围内 t = Math.Max(0, Math.Min(1, t)); // 计算线段上最近点 var closestPoint = new Point3D( lineStart.X + t * lineVector.X, lineStart.Y + t * lineVector.Y, lineStart.Z + t * lineVector.Z ); // 返回点到最近点的距离 return CalculateDistance(point, closestPoint); } /// /// 计算两点间距离 /// /// 第一个点 /// 第二个点 /// 两点间距离 private double CalculateDistance(Point3D point1, Point3D point2) { var dx = point1.X - point2.X; var dy = point1.Y - point2.Y; var dz = point1.Z - point2.Z; return Math.Sqrt(dx * dx + dy * dy + dz * dz); } #endregion #region 网格可视化方法 /// /// 更新网格可视化设置 /// /// 是否显示可通行网格点 /// 是否显示障碍物网格点 /// 是否显示未知区域网格点 /// 是否显示门网格点 public void UpdateGridVisualizationSettings(bool showWalkable, bool showObstacle, bool showUnknown, bool showDoor = false) { try { LogManager.Info($"[网格可视化设置] 更新设置: 通行={showWalkable}, 障碍物={showObstacle}, 未知={showUnknown}, 门={showDoor}"); _showWalkableGrid = showWalkable; _showObstacleGrid = showObstacle; _showUnknownGrid = showUnknown; _showDoorGrid = showDoor; // 如果当前有网格正在显示,重新应用可视化 RefreshGridVisualization(); LogManager.Info("[网格可视化设置] 设置更新完成"); } catch (Exception ex) { LogManager.Error($"[网格可视化设置] 更新设置失败: {ex.Message}", ex); } } /// /// 检查是否有任何网格可视化已启用 /// public bool IsAnyGridVisualizationEnabled { get { return _showWalkableGrid || _showObstacleGrid || _showUnknownGrid || _showDoorGrid; } } /// /// 刷新网格可视化(根据当前设置重新显示) /// private void RefreshGridVisualization() { try { // 清除当前网格可视化 ClearGridVisualization(); // 如果存在缓存的网格地图且有网格可视化设置启用,重新进行可视化 if (_currentGridMap != null && IsAnyGridVisualizationEnabled) { LogManager.Info("[网格可视化] 使用缓存的网格地图重新渲染"); VisualizeGridCells(_currentGridMap, _currentVehicleHeight); } else if (_currentGridMap == null) { LogManager.Info("[网格可视化] 无缓存网格地图,需要重新进行路径规划以查看网格"); } else { LogManager.Info("[网格可视化] 网格可视化设置已关闭,跳过渲染"); } } catch (Exception ex) { LogManager.Error($"[网格可视化] 刷新失败: {ex.Message}", ex); } } /// /// 在3D视图中可视化网格中的可通行单元格 /// 在每个可通行网格的中心绘制一个绿色小球 /// /// 要可视化的网格地图 /// 车辆高度(米),用于判断层高是否足够 public void VisualizeGridCells(GridMap gridMap, double vehicleHeight = 2.0) { if (gridMap == null) { LogManager.Warning("[网格可视化] 网格地图为null,无法进行可视化"); return; } try { // 保存当前网格地图和车辆高度用于后续刷新 _currentGridMap = gridMap; _currentVehicleHeight = vehicleHeight; LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}, 车辆高度:{vehicleHeight}m"); // 获取渲染插件 var renderPlugin = PathPointRenderPlugin.Instance; if (renderPlugin == null) { LogManager.Warning("[网格可视化] PathPointRenderPlugin实例为空,无法绘制网格"); return; } // 设置网格大小以实现自适应点大小 // gridMap.CellSize是模型单位,需要转换为米 double gridSizeInMeters = UnitsConverter.ConvertToMeters(gridMap.CellSize); renderPlugin.SetGridSize(gridSizeInMeters); // 清除之前的网格可视化 ClearGridVisualization(); // 创建四种独立的网格可视化路径 var channelRoute = new PathRoute("GridVisualization_Channel") { Id = "grid_visualization_channel" }; var unknownRoute = new PathRoute("GridVisualization_Unknown") { Id = "grid_visualization_unknown" }; var obstacleRoute = new PathRoute("GridVisualization_Obstacle") { Id = "grid_visualization_obstacle" }; var doorRoute = new PathRoute("GridVisualization_Door") { Id = "grid_visualization_door" }; // 统计变量 int channelCells = 0; int unknownCells = 0; int obstacleCells = 0; int doorCells = 0; int totalVisualized = 0; int multiLayerCells = 0; // 遍历所有网格单元格,根据类型分别收集 for (int x = 0; x < gridMap.Width; x++) { for (int y = 0; y < gridMap.Height; y++) { var cell = gridMap.Cells[x, y]; // 计算网格单元格的XY中心位置(Z坐标在多层逻辑中单独处理) var gridPos = new NavisworksTransport.PathPlanning.GridPoint2D(x, y); var gridCorner = gridMap.GridToWorld3D(gridPos); double centerX = gridCorner.X + gridMap.CellSize / 2; double centerY = gridCorner.Y + gridMap.CellSize / 2; // 所有网格都基于高度层,统一处理 if (cell.HeightLayers != null && cell.HeightLayers.Count > 0) { multiLayerCells++; foreach (var layer in cell.HeightLayers) { double layerZ = layer.Z; PathRoute targetRoute = null; string gridTypeName = ""; // 仅根据 layer.IsWalkable 决定渲染 if (layer.IsWalkable) { // 可通行层 - 门特殊处理,其他统一样式 if (cell.CellType == CategoryAttributeManager.LogisticsElementType.门) { if (_showDoorGrid) { targetRoute = doorRoute; gridTypeName = "门"; doorCells++; } } else { // 其他可通行类型统一为通道样式(绿色) if (_showWalkableGrid) { targetRoute = channelRoute; gridTypeName = "通道"; channelCells++; } } } else { // 不可通行层 - 渲染为障碍物(灰色) if (_showObstacleGrid) { targetRoute = obstacleRoute; gridTypeName = "障碍"; obstacleCells++; } } // 创建该层的可视化点 if (targetRoute != null) { var gridCenter = new Point3D(centerX, centerY, layerZ); var gridPoint = new PathPoint { Position = gridCenter, Name = $"网格_{gridTypeName}({x},{y})_Z{layerZ:F2}", Type = PathPointType.WayPoint, Index = totalVisualized, Notes = $"GridType:{cell.CellType}, LayerZ={layerZ:F2}, IsWalkable={layer.IsWalkable}" }; targetRoute.Points.Add(gridPoint); totalVisualized++; } } } else if (cell.CellType == CategoryAttributeManager.LogisticsElementType.Unknown) { // Unknown网格没有高度层,用于调试 if (_showUnknownGrid) { var gridCenter = new Point3D(centerX, centerY, gridCorner.Z); var gridPoint = new PathPoint { Position = gridCenter, Name = $"网格_空洞({x},{y})", Type = PathPointType.WayPoint, Index = totalVisualized, Notes = $"GridType:Unknown, NoLayers" }; unknownRoute.Points.Add(gridPoint); unknownCells++; totalVisualized++; } } } } // 分别渲染四种类型的网格点 if (channelRoute.Points.Count > 0) { renderPlugin.RenderPointOnly(channelRoute); LogManager.Info($"[网格可视化] 渲染可通行网格层: {channelRoute.Points.Count} 个(绿色)"); } if (doorRoute.Points.Count > 0) { renderPlugin.RenderPointOnly(doorRoute); LogManager.Info($"[网格可视化] 渲染门网格层: {doorRoute.Points.Count} 个(50%透明绿色)"); } if (unknownRoute.Points.Count > 0) { renderPlugin.RenderPointOnly(unknownRoute); LogManager.Info($"[网格可视化] 渲染Unknown网格: {unknownRoute.Points.Count} 个(红色,调试用)"); } if (obstacleRoute.Points.Count > 0) { renderPlugin.RenderPointOnly(obstacleRoute); LogManager.Info($"[网格可视化] 渲染障碍物网格层: {obstacleRoute.Points.Count} 个(灰色)"); } // 输出统计信息 LogManager.Info($"[网格可视化] 可视化完成:"); LogManager.Info($" - 总网格单元格数:{gridMap.Width * gridMap.Height}"); LogManager.Info($" - 多层网格数:{multiLayerCells}"); LogManager.Info($" - 可通行层数:{channelCells}"); LogManager.Info($" - 门层数:{doorCells}"); LogManager.Info($" - Unknown单元格数:{unknownCells}"); LogManager.Info($" - 障碍物层数:{obstacleCells}"); LogManager.Info($" - 已可视化点数:{totalVisualized}"); RaiseStatusChanged($"网格可视化完成:显示了 {totalVisualized} 个网格层 (多层网格:{multiLayerCells}, 可通行:{channelCells}, 门:{doorCells}, Unknown:{unknownCells}, 障碍:{obstacleCells})", PathPlanningStatusType.Success); } catch (Exception ex) { LogManager.Error($"[网格可视化] 可视化失败: {ex.Message}"); RaiseErrorOccurred($"网格可视化失败: {ex.Message}", ex); } } /// /// 清除网格可视化 /// public void ClearGridVisualization() { try { LogManager.Info("[网格可视化] 开始清除网格可视化"); var renderPlugin = PathPointRenderPlugin.Instance; if (renderPlugin != null) { // 清除所有网格可视化路径(包括旧的和新的) renderPlugin.RemovePath("grid_visualization_all"); // 旧的单一路径 renderPlugin.RemovePath("grid_visualization_channel"); // 新的通道路径 renderPlugin.RemovePath("grid_visualization_unknown"); // 新的Unknown路径 renderPlugin.RemovePath("grid_visualization_obstacle"); // 新的障碍物路径 renderPlugin.RemovePath("grid_visualization_door"); // 新的门路径 LogManager.Info("[网格可视化] 网格可视化已清除"); } else { LogManager.Warning("[网格可视化] PathPointRenderPlugin实例为空,无法清除可视化"); } } catch (Exception ex) { LogManager.Error($"[网格可视化] 清除可视化失败: {ex.Message}"); } } #endregion #region 路径分析方法 /// /// 获取所有路径(供分析使用) /// public List GetAllRoutes() { try { // 直接返回内存中的路径列表 // 因为所有路径操作都已同步到数据库,内存列表就是当前的完整列表 return _routes ?? new List(); } catch (Exception ex) { LogManager.Error($"获取所有路径失败: {ex.Message}", ex); return new List(); } } /// /// 分析多条路径并进行对比 /// /// 要分析的路径ID列表 /// 分析策略 /// 对比结果 public PathComparisonResult AnalyzePathsAndCompare(List routeIds, string strategy) { try { if (_analysisService == null) { LogManager.Error("路径分析服务未初始化"); return null; } // 获取要分析的路径 var routesToAnalyze = _routes?.Where(r => routeIds.Contains(r.Id)).ToList(); if (routesToAnalyze == null || routesToAnalyze.Count == 0) { LogManager.Warning("未找到要分析的路径"); return null; } // 执行分析和对比 var result = _analysisService.CompareRoutes(routesToAnalyze, strategy); return result; } catch (Exception ex) { LogManager.Error($"路径分析失败: {ex.Message}", ex); return null; } } /// /// 从数据库加载历史路径到内存 /// private void LoadHistoricalRoutesFromDatabase() { try { var historicalRoutes = _pathDatabase.GetAllPathRoutes(); if (historicalRoutes != null && historicalRoutes.Count > 0) { // 使用HashSet记录已存在的路径ID,避免重复 var existingIds = new HashSet(_routes.Select(r => r.Id)); int loadedCount = 0; // 加载历史路径(跳过已存在的) foreach (var route in historicalRoutes) { if (!existingIds.Contains(route.Id)) { _routes.Add(route); loadedCount++; //LogManager.Info($"加载历史路径: {route.Name}, ID={route.Id}, 长度={route.TotalLength:F2}米"); } } if (loadedCount > 0) { LogManager.Info($"成功从数据库加载 {loadedCount} 条历史路径(总计 {historicalRoutes.Count} 条)"); } else { LogManager.Info($"数据库中的 {historicalRoutes.Count} 条路径已全部在内存中"); } // 如果当前没有选中的路径,且路径列表不为空,选择第一条 if ((_currentRoute == null || string.IsNullOrEmpty(_currentRoute.Name) || _currentRoute.Name == "默认路径") && _routes.Count > 0) { _currentRoute = _routes[0]; LogManager.Info($"设置当前路径为: {_currentRoute.Name}"); } // 历史路径加载完成后,触发RouteGenerated事件通知UI刷新 // 使用特殊的生成方法标记这是数据库加载 foreach (var route in _routes) { RaiseRouteGenerated(route, RouteGenerationMethod.DatabaseLoad); } LogManager.Info($"已触发{_routes.Count}个RouteGenerated事件,通知UI刷新历史路径"); } else { LogManager.Info("数据库中没有历史路径记录"); } } catch (Exception ex) { LogManager.Error($"加载历史路径失败: {ex.Message}", ex); } } /// /// 保存路径时同时保存到数据库 /// private void SavePathToDatabase(PathRoute route) { try { if (_pathDatabase != null && route != null) { _pathDatabase.SavePathRoute(route); LogManager.Info($"路径已保存到数据库: {route.Name}"); } } catch (Exception ex) { LogManager.Error($"保存路径到数据库失败: {ex.Message}", ex); } } /// /// 获取Instance单例(为兼容现有代码) /// public static PathPlanningManager Instance { get { if (_activePathManager == null) { LogManager.Warning("PathPlanningManager未初始化,创建新实例"); _activePathManager = new PathPlanningManager(); } return _activePathManager; } } #endregion #region 静态方法 /// /// 静态方法:获取当前活动的路径管理器 /// /// 当前活动的路径管理器 public static PathPlanningManager GetActivePathManager() { return _activePathManager; } #endregion } }