diff --git a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl index 9e66a01..1843f7c 100644 Binary files a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl and b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl differ diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 74d8d48..8f11b5d 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -184,11 +184,21 @@ namespace NavisworksTransport.Core.Animation var doc = NavisApplication.ActiveDocument; var modelItems = new ModelItemCollection { _animatedObject }; - // 计算从部件原始中心到路径起点的偏移 + // 获取物体的包围盒 + var boundingBox = _animatedObject.BoundingBox(); + + // 计算物体底面中心点(而不是整体中心点) + var objectBottomCenter = new Point3D( + _originalCenter.X, + _originalCenter.Y, + boundingBox.Min.Z // 使用包围盒的最小Z值作为底面 + ); + + // 计算从物体底面中心到路径起点的偏移 var startOffset = new Vector3D( - _pathPoints[0].X - _originalCenter.X, - _pathPoints[0].Y - _originalCenter.Y, - _pathPoints[0].Z - _originalCenter.Z + _pathPoints[0].X - objectBottomCenter.X, + _pathPoints[0].Y - objectBottomCenter.Y, + _pathPoints[0].Z - objectBottomCenter.Z ); // 创建变换并应用 @@ -198,9 +208,12 @@ namespace NavisworksTransport.Core.Animation // 更新当前位置为路径起点 _currentPosition = _pathPoints[0]; - LogManager.Info($"部件已移动到路径起点,偏移: ({startOffset.X:F2},{startOffset.Y:F2},{startOffset.Z:F2})"); + LogManager.Info($"物体已移动到路径起点,底面对齐地面"); + LogManager.Info($"物体包围盒: Min=({boundingBox.Min.X:F2},{boundingBox.Min.Y:F2},{boundingBox.Min.Z:F2}), Max=({boundingBox.Max.X:F2},{boundingBox.Max.Y:F2},{boundingBox.Max.Z:F2})"); + LogManager.Info($"物体原始中心: ({_originalCenter.X:F2},{_originalCenter.Y:F2},{_originalCenter.Z:F2})"); + LogManager.Info($"物体底面中心: ({objectBottomCenter.X:F2},{objectBottomCenter.Y:F2},{objectBottomCenter.Z:F2})"); LogManager.Info($"路径起点坐标: ({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2})"); - LogManager.Info($"原始中心坐标: ({_originalCenter.X:F2},{_originalCenter.Y:F2},{_originalCenter.Z:F2})"); + LogManager.Info($"应用的偏移量: ({startOffset.X:F2},{startOffset.Y:F2},{startOffset.Z:F2})"); } catch (Exception ex) { diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index aa964f1..249f037 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -40,6 +40,9 @@ namespace NavisworksTransport // ToolPlugin 集成 private bool _isToolPluginActive = false; + // 自动路径规划模式标志 + private bool _isInAutoPathMode = false; + // 路径点3D标记管理 private List _pathPointMarkers; @@ -147,7 +150,7 @@ namespace NavisworksTransport public bool IsInEditableState { - get { return _pathEditState == PathEditState.Creating || _pathEditState == PathEditState.Editing; } + get { return _pathEditState == PathEditState.Creating || _pathEditState == PathEditState.Editing || _pathEditState == PathEditState.AddingPoints; } } public PathRoute CurrentRoute @@ -177,6 +180,14 @@ namespace NavisworksTransport get { return _currentPointType; } private set { _currentPointType = value; } } + /// + /// 是否在自动路径规划模式 + /// + public bool IsInAutoPathMode + { + get { return _isInAutoPathMode; } + private set { _isInAutoPathMode = value; } + } public ChannelBounds CombinedChannelBounds => _combinedChannelBounds; @@ -618,9 +629,14 @@ namespace NavisworksTransport try { CurrentPointType = pointType; - ActivateToolPlugin(); + + // 检查是否在自动路径模式 - 如果是,则不订阅PathPlanningManager的事件 + bool shouldSubscribeToEvents = !IsInAutoPathMode; + LogManager.Info($"StartClickTool - 自动路径模式: {IsInAutoPathMode}, 订阅事件: {shouldSubscribeToEvents}"); + + ActivateToolPlugin(shouldSubscribeToEvents); PathEditState = PathEditState.AddingPoints; - LogManager.Info($"点击工具已启动,类型: {pointType}"); + LogManager.Info($"点击工具已启动,类型: {pointType},事件订阅: {shouldSubscribeToEvents}"); } catch (Exception ex) { @@ -676,8 +692,7 @@ namespace NavisworksTransport LogManager.WriteLog($"[事件清理] 额外清理过程异常: {cleanupEx.Message}"); } - // 3. 更新状态 - PathEditState = PathEditState.None; + // 注意:移除了PathEditState设置,StopClickTool只管理工具插件状态,不修改业务逻辑状态 LogManager.WriteLog("[事件清理] ===== StopClickTool执行完成,所有事件订阅已清理 ====="); } catch (Exception ex) @@ -687,6 +702,47 @@ namespace NavisworksTransport } } + /// + /// 禁用鼠标处理(用于自动路径规划模式) + /// + 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); + } + } + /// /// 自动路径规划(完整实现) /// @@ -1631,18 +1687,27 @@ namespace NavisworksTransport /// /// 激活自定义ToolPlugin进行精确点击检测 /// - private bool ActivateToolPlugin() + /// 是否订阅鼠标事件 + private bool ActivateToolPlugin(bool subscribeToEvents = true) { - // 如果已经激活,直接返回成功 + // 如果已经激活,检查是否需要订阅事件 if (_isToolPluginActive) { - LogManager.WriteLog("[ToolPlugin] ToolPlugin已激活,无需重复激活"); + LogManager.WriteLog("[ToolPlugin] ToolPlugin已激活,检查事件订阅状态"); + if (subscribeToEvents) + { + // 确保事件订阅(避免重复订阅) + PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; + PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; + LogManager.WriteLog("[ToolPlugin] 已确保PathPlanningManager事件订阅"); + } return true; } try { LogManager.WriteLog("[ToolPlugin] ===== 开始激活ToolPlugin ====="); + LogManager.WriteLog($"[ToolPlugin] 订阅事件: {subscribeToEvents}"); LogManager.WriteLog($"[ToolPlugin] 当前应用程序状态: {Application.IsAutomated}"); LogManager.WriteLog($"[ToolPlugin] 当前文档状态: {Application.ActiveDocument?.Title ?? "NULL"}"); @@ -1681,10 +1746,17 @@ namespace NavisworksTransport Application.MainDocument.Tool.SetCustomToolPlugin(loadedPlugin); LogManager.WriteLog("[ToolPlugin] ✓ 工具设置成功"); - // 5. 订阅点击事件 - LogManager.WriteLog("[ToolPlugin] 步骤5: 订阅点击事件"); - PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; - LogManager.WriteLog("[ToolPlugin] ✓ 事件订阅成功"); + // 5. 根据参数决定是否订阅点击事件 + if (subscribeToEvents) + { + LogManager.WriteLog("[ToolPlugin] 步骤5: 订阅点击事件"); + PathClickToolPlugin.MouseClicked += OnToolPluginMouseClicked; + LogManager.WriteLog("[ToolPlugin] ✓ PathPlanningManager事件订阅成功"); + } + else + { + LogManager.WriteLog("[ToolPlugin] 步骤5: 跳过事件订阅(由外部组件管理)"); + } _isToolPluginActive = true; LogManager.WriteLog("[ToolPlugin] ===== ToolPlugin激活完成 ====="); @@ -1708,85 +1780,17 @@ namespace NavisworksTransport LogManager.WriteLog("[ToolPlugin事件-V2] ===== 收到精确点击坐标 ====="); LogManager.WriteLog($"[ToolPlugin事件-V2] 精确坐标: ({pickResult.Point.X:F3}, {pickResult.Point.Y:F3}, {pickResult.Point.Z:F3})"); LogManager.WriteLog($"[ToolPlugin事件-V2] 选中对象: {pickResult.ModelItem?.DisplayName ?? "NULL"}"); + LogManager.WriteLog($"[ToolPlugin事件-V2] 当前点类型: {CurrentPointType}"); - // 检查当前选中的通道状态 - LogManager.WriteLog($"[ToolPlugin事件-V2] 当前_selectedChannels状态: {(_selectedChannels == null ? "NULL" : $"包含{_selectedChannels.Count}个项目")}"); - - // 如果没有选中的通道,尝试实时搜索 - if (_selectedChannels == null || _selectedChannels.Count == 0) + // 如果在自动路径规划模式,则跳过处理(应该由PathEditingViewModel处理) + if (IsInAutoPathMode) { - LogManager.WriteLog("[ToolPlugin事件] 没有预选通道,开始实时搜索可通行的物流模型"); - - try - { - var document = Application.ActiveDocument; - if (document?.Models != null) - { - // 使用Search API实时搜索 - var logisticsItems = SearchLogisticsItemsUsingSearchAPI(); - LogManager.WriteLog($"[ToolPlugin事件] 实时搜索找到 {logisticsItems.Count} 个物流模型"); - - if (logisticsItems.Count > 0) - { - // 筛选出可通行的物流模型 - var modelCollection = new ModelItemCollection(); - modelCollection.AddRange(logisticsItems); - var traversableItems = CategoryAttributeManager.FilterTraversableItems(modelCollection); - LogManager.WriteLog($"[ToolPlugin事件] 筛选出 {traversableItems.Count} 个可通行的物流模型"); - - // 临时设置为选中通道 - if (_selectedChannels == null) _selectedChannels = new List(); - _selectedChannels.Clear(); - - foreach (ModelItem item in traversableItems) - { - _selectedChannels.Add(item); - LogManager.WriteLog($"[ToolPlugin事件] 添加可通行模型: '{item.DisplayName}'"); - } - } - } - } - catch (Exception searchEx) - { - LogManager.WriteLog($"[ToolPlugin事件] 实时搜索失败: {searchEx.Message}"); - } + LogManager.WriteLog("[ToolPlugin事件] 当前在自动路径规划模式,跳过PathPlanningManager处理"); + return; } - // 检查是否在可通行的物流模型内 - if (_selectedChannels != null && _selectedChannels.Any()) - { - bool isInTraversableLogisticsModel = IsItemInSelectedChannels(pickResult.ModelItem) || - IsItemChildOfSelectedChannels(pickResult.ModelItem); - - LogManager.WriteLog($"[ToolPlugin事件] 在可通行的物流模型内: {isInTraversableLogisticsModel}"); - - if (isInTraversableLogisticsModel) - { - // 不再传递点类型,让AddPathPointIn3D方法内部自动判断 - LogManager.WriteLog("[ToolPlugin事件] 调用AddPathPointIn3D添加路径点"); - var pathPoint = AddPathPointIn3D(pickResult.Point); - - if (pathPoint != null) - { - LogManager.WriteLog($"[ToolPlugin事件] ✓ 路径点添加成功: {pathPoint.Name}"); - } - else - { - LogManager.WriteLog("[ToolPlugin事件] ✗ 路径点添加失败"); - } - } - else - { - LogManager.WriteLog("[ToolPlugin事件] ✗ 点击位置不在可通行的物流模型内"); - // 可以考虑给用户一个提示 - OnStatusChanged("点击位置不是可通行的物流模型,请在可通行的物流模型上点击"); - } - } - else - { - LogManager.WriteLog("[ToolPlugin事件] ✗ 没有可通行的物流模型"); - OnStatusChanged("没有找到任何可通行的物流模型,请先为模型设置可通行的物流属性"); - } + // 手动路径编辑处理 + ProcessManualPathEditing(pickResult); } catch (Exception ex) { @@ -1795,6 +1799,98 @@ namespace NavisworksTransport } } + /// + /// 处理手动路径编辑的鼠标点击 + /// + private void ProcessManualPathEditing(PickItemResult pickResult) + { + // 检查当前选中的通道状态 + LogManager.WriteLog($"[手动编辑] 当前_selectedChannels状态: {(_selectedChannels == null ? "NULL" : $"包含{_selectedChannels.Count}个项目")}"); + + // 如果没有选中的通道,尝试实时搜索 + if (_selectedChannels == null || _selectedChannels.Count == 0) + { + LogManager.WriteLog("[手动编辑] 没有预选通道,开始实时搜索可通行的物流模型"); + SearchAndSetTraversableChannels(); + } + + // 检查是否在可通行的物流模型内并添加路径点 + if (_selectedChannels != null && _selectedChannels.Any()) + { + bool isInTraversableLogisticsModel = IsItemInSelectedChannels(pickResult.ModelItem) || + IsItemChildOfSelectedChannels(pickResult.ModelItem); + + LogManager.WriteLog($"[手动编辑] 在可通行的物流模型内: {isInTraversableLogisticsModel}"); + + if (isInTraversableLogisticsModel) + { + // 手动路径编辑 - 添加路径点并绘制 + LogManager.WriteLog("[手动编辑] 调用AddPathPointIn3D添加路径点"); + var pathPoint = AddPathPointIn3D(pickResult.Point); + + if (pathPoint != null) + { + LogManager.WriteLog($"[手动编辑] ✓ 路径点添加成功: {pathPoint.Name}"); + } + else + { + LogManager.WriteLog("[手动编辑] ✗ 路径点添加失败"); + } + } + else + { + LogManager.WriteLog("[手动编辑] ✗ 点击位置不在可通行的物流模型内"); + OnStatusChanged("点击位置不是可通行的物流模型,请在可通行的物流模型上点击"); + } + } + else + { + LogManager.WriteLog("[手动编辑] ✗ 没有可通行的物流模型"); + OnStatusChanged("没有找到任何可通行的物流模型,请先为模型设置可通行的物流属性"); + } + } + + /// + /// 搜索并设置可通行的通道 + /// + private void SearchAndSetTraversableChannels() + { + try + { + var document = Application.ActiveDocument; + if (document?.Models != null) + { + // 使用Search API实时搜索 + var logisticsItems = SearchLogisticsItemsUsingSearchAPI(); + LogManager.WriteLog($"[搜索通道] 实时搜索找到 {logisticsItems.Count} 个物流模型"); + + if (logisticsItems.Count > 0) + { + // 筛选出可通行的物流模型 + var modelCollection = new ModelItemCollection(); + modelCollection.AddRange(logisticsItems); + var traversableItems = CategoryAttributeManager.FilterTraversableItems(modelCollection); + LogManager.WriteLog($"[搜索通道] 筛选出 {traversableItems.Count} 个可通行的物流模型"); + + // 临时设置为选中通道 + if (_selectedChannels == null) _selectedChannels = new List(); + _selectedChannels.Clear(); + + foreach (ModelItem item in traversableItems) + { + _selectedChannels.Add(item); + LogManager.WriteLog($"[搜索通道] 添加可通行模型: '{item.DisplayName}'"); + } + } + } + } + catch (Exception searchEx) + { + LogManager.WriteLog($"[搜索通道] 实时搜索失败: {searchEx.Message}"); + } + } + + /// /// 使用Navisworks Search API高效搜索具有物流属性的模型项 /// diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index 557b009..3f7bcd5 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -268,6 +268,68 @@ namespace NavisworksTransport } } + /// + /// 只渲染点标记,不绘制连线(用于自动路径规划的起终点显示) + /// + public void RenderPointOnly(PathRoute pathRoute) + { + if (pathRoute == null) + { + LogManager.WriteLog("[点标记渲染] 路径数据为空"); + return; + } + + try + { + var visualization = new PathVisualization + { + PathId = pathRoute.Id, + PathRoute = pathRoute + }; + + // 只构建点标记,不构建连线 + BuildPointMarkersOnly(visualization); + + lock (_lockObject) + { + _pathVisualizations[pathRoute.Id] = visualization; + } + + LogManager.WriteLog($"[点标记渲染] 渲染点标记: {pathRoute.Name}, 点数: {pathRoute.Points.Count}"); + RequestViewRefresh(); + } + catch (Exception ex) + { + LogManager.WriteLog($"[点标记渲染] 渲染点标记失败: {ex.Message}"); + } + } + + /// + /// 只构建点标记,不构建连线 + /// + private void BuildPointMarkersOnly(PathVisualization visualization) + { + // 清空现有标记 + visualization.PointMarkers.Clear(); + visualization.LineMarkers.Clear(); // 确保没有连线 + + var points = visualization.PathRoute.Points; + if (points.Count == 0) return; + + // 按索引排序点 + var sortedPoints = points.OrderBy(p => p.Index).ToList(); + + // 只构建点标记,不构建连线 + foreach (var point in sortedPoints) + { + var pointMarker = CreatePointMarker(point); + visualization.PointMarkers.Add(pointMarker); + } + + visualization.LastUpdated = DateTime.Now; + LogManager.WriteLog($"[点标记构建] 已构建 {visualization.PointMarkers.Count} 个点标记,无连线"); + } + /// /// 刷新路径可视化 /// diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 0ad1e78..e83b400 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -357,8 +357,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels PathRoutes.Add(newPathViewModel); SelectedPathRoute = newPathViewModel; + // 强制重新初始化ToolPlugin以确保获得鼠标焦点,新建路径需要订阅事件 + if (!ForceReinitializeToolPlugin(subscribeToEvents: true)) + { + AutoPathStatus = "ToolPlugin初始化失败,请重试"; + LogManager.Error("新建路径:ToolPlugin初始化失败"); + return; + } + AutoPathStatus = $"已进入新建路径模式: {newRoute.Name} - 请在3D视图中点击设置路径点"; - LogManager.Info($"开始新建路径: {newRoute.Name}"); + LogManager.Info($"开始新建路径: {newRoute.Name},已强制重新初始化ToolPlugin获取鼠标焦点"); // 不再显示对话框,状态文本已提供足够的反馈 } @@ -458,21 +466,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels IsSelectingEndPoint = false; AutoPathStatus = "请在3D视图中点击选择起点..."; - // 强制重新初始化ToolPlugin以确保获得鼠标焦点 - if (!ForceReinitializeToolPlugin()) + // 进入自动路径规划模式 - 动态事件订阅 + LogManager.Info("进入自动路径规划模式,启用动态事件订阅"); + + // 1. 禁用PathPlanningManager的鼠标处理 + _pathPlanningManager.DisableMouseHandling(); + + // 2. 启用PathEditingViewModel的事件订阅 + PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; // 先取消避免重复 + PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked; + LogManager.Info("已启用PathEditingViewModel的鼠标事件订阅"); + + // 强制重新初始化ToolPlugin以确保获得鼠标焦点,自动路径不需要PathPlanningManager订阅事件 + if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) { AutoPathStatus = "ToolPlugin初始化失败,请重试"; return; } - // 订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的起点 - LogManager.Info("订阅PathClickToolPlugin.MouseClicked事件"); - PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; - PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked; - // 在STA线程中调用Navisworks API _pathPlanningManager.StartClickTool(PathPointType.StartPoint); - LogManager.Info("=== 选择起点命令设置完成,ToolPlugin已重新激活并获得鼠标焦点,等待用户点击 ==="); + LogManager.Info("=== 选择起点命令设置完成,已启用动态事件订阅,等待用户点击 ==="); }, "选择起点"); } @@ -494,21 +508,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels IsSelectingEndPoint = true; AutoPathStatus = "请在3D视图中点击选择终点..."; - // 强制重新初始化ToolPlugin以确保获得鼠标焦点 - if (!ForceReinitializeToolPlugin()) + // 进入自动路径规划模式 - 动态事件订阅 + LogManager.Info("进入自动路径规划模式,启用动态事件订阅"); + + // 1. 禁用PathPlanningManager的鼠标处理 + _pathPlanningManager.DisableMouseHandling(); + + // 2. 启用PathEditingViewModel的事件订阅 + PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; // 先取消避免重复 + PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked; + LogManager.Info("已启用PathEditingViewModel的鼠标事件订阅"); + + // 强制重新初始化ToolPlugin以确保获得鼠标焦点,自动路径不需要PathPlanningManager订阅事件 + if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) { AutoPathStatus = "ToolPlugin初始化失败,请重试"; return; } - // 订阅PathClickToolPlugin的鼠标点击事件来获取自动路径规划的终点 - LogManager.Info("订阅PathClickToolPlugin.MouseClicked事件"); - PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; - PathClickToolPlugin.MouseClicked += OnAutoPathMouseClicked; - // 在STA线程中调用Navisworks API _pathPlanningManager.StartClickTool(PathPointType.EndPoint); - LogManager.Info("=== 选择终点命令设置完成,ToolPlugin已重新激活并获得鼠标焦点,等待用户点击 ==="); + LogManager.Info("=== 选择终点命令设置完成,已启用动态事件订阅,等待用户点击 ==="); }, "选择终点"); } @@ -568,6 +588,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels _pathPlanningManager.StopClickTool(); } + // 清理临时的起点和终点标记 + ClearTemporaryAutoPathMarkers(); + // 不在这里直接操作UI,让RouteGenerated事件处理UI更新 // 这避免了重复的路径添加和UI更新冲突 @@ -576,15 +599,28 @@ namespace NavisworksTransport.UI.WPF.ViewModels } else { - AutoPathStatus = "❌ 路径规划失败,未找到可行路径"; - LogManager.Warning("自动路径规划失败:未找到可行路径"); + // 检查是否已经通过ErrorOccurred事件设置了详细错误信息 + if (!AutoPathStatus.Contains("❌ 自动路径规划失败")) + { + // 如果没有详细错误信息,则设置通用错误提示 + AutoPathStatus = "❌ 路径规划失败,未找到可行路径"; + LogManager.Warning("自动路径规划失败:未找到可行路径"); + } + else + { + // 如果已有详细错误信息,保留不覆盖 + LogManager.Info("保留ErrorOccurred事件设置的详细错误信息,不覆盖AutoPathStatus"); + } - // 失败情况下也要清理事件订阅 + // 失败情况下也要清理事件订阅和临时标记 CleanupAutoPathEventSubscriptions(); if (_pathPlanningManager != null) { _pathPlanningManager.StopClickTool(); } + + // 清理临时的起点和终点标记 + ClearTemporaryAutoPathMarkers(); } }, "自动路径规划"); } @@ -603,25 +639,26 @@ namespace NavisworksTransport.UI.WPF.ViewModels PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked; } - // 清除所有路径可视化(使用新的统一API) + // 清除所有路径的可视化显示(与新建路径按钮保持一致) if (PathPointRenderPlugin.Instance != null) { try { + // 清除所有路径可视化,包括自动路径和手动路径 PathPointRenderPlugin.Instance.ClearAllPaths(); LogManager.Info("重置参数:已清除所有路径可视化显示"); } catch (Exception ex) { LogManager.Error($"重置参数:清除路径可视化失败: {ex.Message}", ex); - throw; // 重新抛出异常,让上层处理 + // 不抛出异常,继续执行状态重置 } } - // 强制重新初始化ToolPlugin以重新获得鼠标焦点 + // 强制重新初始化ToolPlugin以重新获得鼠标焦点,重置时不需要订阅事件 if (_pathPlanningManager != null) { - ForceReinitializeToolPlugin(); + ForceReinitializeToolPlugin(subscribeToEvents: false); } // 重置所有状态 @@ -638,7 +675,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 通知Can Execute属性更改 OnPropertyChanged(nameof(CanExecuteAutoPlanPath)); - LogManager.Info("自动路径规划参数和3D标记已完全重置,ToolPlugin已重新初始化"); + LogManager.Info("自动路径规划参数和起终点标记已完全重置,ToolPlugin已重新初始化"); }, "重置自动路径规划"); } @@ -820,7 +857,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels SetAutoPathStartPoint(point3D); await SafeExecuteAsync(() => { + // 退出自动路径规划模式 - 恢复事件订阅 + LogManager.Info("起点选择完成,恢复正常事件订阅状态"); CleanupAutoPathEventSubscriptions(); + _pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理 _pathPlanningManager?.StopClickTool(); }, "停止起点选择工具"); } @@ -830,7 +870,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels SetAutoPathEndPoint(point3D); await SafeExecuteAsync(() => { + // 退出自动路径规划模式 - 恢复事件订阅 + LogManager.Info("终点选择完成,恢复正常事件订阅状态"); CleanupAutoPathEventSubscriptions(); + _pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理 _pathPlanningManager?.StopClickTool(); }, "停止终点选择工具"); } @@ -838,6 +881,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { LogManager.WriteLog("[自动路径事件] 非选择状态,直接清理事件订阅"); CleanupAutoPathEventSubscriptions(); + _pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理 } } catch (Exception ex) @@ -848,10 +892,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels IsSelectingStartPoint = false; IsSelectingEndPoint = false; - // 异常情况下也要清理事件订阅 + // 异常情况下也要清理事件订阅并恢复状态 try { CleanupAutoPathEventSubscriptions(); + _pathPlanningManager?.EnableMouseHandling(); // 恢复PathPlanningManager的鼠标处理 _pathPlanningManager?.StopClickTool(); } catch (Exception cleanupEx) @@ -868,9 +913,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels { await SafeExecuteAsync(() => { + // 如果已有起点,先移除之前的可视化 if (_hasStartPoint && PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.RemoveMarkerAt(_startPoint3D, 2.0); + // 移除之前的起点路径可视化 + PathPointRenderPlugin.Instance.RemovePath("AutoPathStartPoint"); } _startPoint3D = point; @@ -881,9 +928,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 通知Can Execute属性更改 OnPropertyChanged(nameof(CanExecuteAutoPlanPath)); + // 使用新的RenderPointOnly API只渲染起点标记 if (PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.AddCircleMarker(point, PathPointType.StartPoint, -100); + // 创建临时路径只包含起点 + var startPointPathRoute = new PathRoute("AutoPathStartPoint") + { + Description = "自动路径规划起点" + }; + var startPathPoint = new PathPoint + { + Name = "起点", + Position = point, + Type = PathPointType.StartPoint + }; + startPointPathRoute.AddPoint(startPathPoint); + + // 使用新的只渲染点的API,不绘制连线 + PathPointRenderPlugin.Instance.RenderPointOnly(startPointPathRoute); } if (_hasEndPoint) @@ -906,9 +968,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels { await SafeExecuteAsync(() => { + // 如果已有终点,先移除之前的可视化 if (_hasEndPoint && PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.RemoveMarkerAt(_endPoint3D, 2.0); + // 移除之前的终点路径可视化 + PathPointRenderPlugin.Instance.RemovePath("AutoPathEndPoint"); } _endPoint3D = point; @@ -919,9 +983,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 通知Can Execute属性更改 OnPropertyChanged(nameof(CanExecuteAutoPlanPath)); + // 使用新的RenderPointOnly API只渲染终点标记 if (PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.AddCircleMarker(point, PathPointType.EndPoint, -200); + // 创建临时路径只包含终点 + var endPointPathRoute = new PathRoute("AutoPathEndPoint") + { + Description = "自动路径规划终点" + }; + var endPathPoint = new PathPoint + { + Name = "终点", + Position = point, + Type = PathPointType.EndPoint + }; + endPointPathRoute.AddPoint(endPathPoint); + + // 使用新的只渲染点的API,不绘制连线 + PathPointRenderPlugin.Instance.RenderPointOnly(endPointPathRoute); } if (_hasStartPoint) @@ -1003,6 +1082,33 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 清理临时的自动路径起点和终点标记 + /// + private void ClearTemporaryAutoPathMarkers() + { + try + { + LogManager.WriteLog("[临时标记清理] 开始清理自动路径临时标记"); + + if (PathPointRenderPlugin.Instance != null) + { + // 清除临时的起点和终点标记 + PathPointRenderPlugin.Instance.RemovePath("AutoPathStartPoint"); + PathPointRenderPlugin.Instance.RemovePath("AutoPathEndPoint"); + LogManager.WriteLog("[临时标记清理] 已清除AutoPathStartPoint和AutoPathEndPoint临时标记"); + } + else + { + LogManager.WriteLog("[临时标记清理] PathPointRenderPlugin实例为null,无法清理标记"); + } + } + catch (Exception ex) + { + LogManager.Error($"[临时标记清理] 清理临时标记失败: {ex.Message}"); + } + } + #endregion #region PathPlanningManager事件处理 @@ -1037,7 +1143,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 订阅路径生成事件(用于处理自动路径) _pathPlanningManager.RouteGenerated += OnRouteGenerated; - LogManager.Info("*** PathEditingViewModel已成功订阅PathPlanningManager事件,包括RouteGenerated ***"); + // 添加错误事件订阅 - 用于处理自动路径规划失败等错误 + _pathPlanningManager.ErrorOccurred += OnPathPlanningError; + + LogManager.Info("*** PathEditingViewModel已成功订阅PathPlanningManager事件,包括RouteGenerated和ErrorOccurred ***"); // 验证事件订阅是否成功 var routeGeneratedField = _pathPlanningManager.GetType().GetEvent("RouteGenerated"); @@ -1070,8 +1179,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels _pathPlanningManager.CurrentRouteChanged -= OnCurrentRouteChanged; _pathPlanningManager.EditStateChanged -= OnEditStateChanged; _pathPlanningManager.RouteGenerated -= OnRouteGenerated; + _pathPlanningManager.ErrorOccurred -= OnPathPlanningError; - LogManager.Info("PathEditingViewModel已取消订阅PathPlanningManager事件"); + LogManager.Info("PathEditingViewModel已取消订阅PathPlanningManager事件,包括ErrorOccurred"); } catch (Exception ex) { @@ -1337,6 +1447,41 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 处理路径规划错误事件 + /// + /// + /// 处理路径规划错误事件 + /// + /// + /// 处理路径规划错误事件 + /// + private async void OnPathPlanningError(object sender, PathPlanningErrorOccurredEventArgs e) + { + LogManager.Info($"*** OnPathPlanningError被调用!Sender: {sender?.GetType().Name}, Error: {e?.ErrorMessage} ***"); + + try + { + await SafeExecuteAsync(async () => + { + LogManager.Error($"自动路径规划失败: {e.ErrorMessage}"); + + // 使用UIStateManager确保UI更新在主线程执行 + await _uiStateManager.ExecuteUIUpdateAsync(() => + { + // 更新自动路径状态显示错误信息 + AutoPathStatus = $"❌ 自动路径规划失败: {e.ErrorMessage}"; + LogManager.Info($"*** AutoPathStatus已更新为: {AutoPathStatus} ***"); + }); + + }, "处理路径规划错误事件"); + } + catch (Exception ex) + { + LogManager.Error($"*** OnPathPlanningError异常: {ex.Message} ***", ex); + } + } + #endregion #region 清理资源 @@ -1344,10 +1489,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// /// 强制重新初始化ToolPlugin以确保获得鼠标焦点 /// + /// 是否订阅鼠标事件,新建路径需要true,自动路径选点需要false /// 初始化是否成功 - private bool ForceReinitializeToolPlugin() + private bool ForceReinitializeToolPlugin(bool subscribeToEvents = false) { - LogManager.Info("开始强制重新初始化ToolPlugin以确保获得鼠标焦点"); + LogManager.Info($"开始强制重新初始化ToolPlugin以确保获得鼠标焦点,订阅事件: {subscribeToEvents}"); try { // 使用反射调用私有方法强制重新激活ToolPlugin @@ -1368,13 +1514,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels LogManager.Info("已重置ToolPlugin激活状态标志"); } - // 重新激活ToolPlugin + // 重新激活ToolPlugin,根据参数决定是否订阅事件 var activateMethod = _pathPlanningManager.GetType().GetMethod("ActivateToolPlugin", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (activateMethod != null) { - var result = activateMethod.Invoke(_pathPlanningManager, null); - LogManager.Info($"ToolPlugin重新激活结果: {result}"); + // 调用带参数的方法,传递subscribeToEvents参数 + var result = activateMethod.Invoke(_pathPlanningManager, new object[] { subscribeToEvents }); + LogManager.Info($"ToolPlugin重新激活结果(事件订阅: {subscribeToEvents}): {result}"); if (!(bool)result) { LogManager.Error("ToolPlugin激活失败");