From 3aaa176ce63356a21aa01b2c3bea16f341cf1cdd Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 14 Oct 2025 16:29:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=92=E4=BB=B6=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=97=B6=E7=9A=84=E5=8A=A8=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/requirement/todo_features.md | 5 + src/Core/MainPlugin.cs | 2 +- src/Core/ModelSplitterManager.cs | 70 +----------- src/Core/PathPlanningManager.cs | 78 +++++++------- .../ViewModels/AnimationControlViewModel.cs | 12 ++- .../ViewModels/LayerManagementViewModel.cs | 13 +-- .../WPF/ViewModels/ModelSettingsViewModel.cs | 101 ++++++++++++++++-- .../WPF/ViewModels/PathAnalysisViewModel.cs | 2 +- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 21 +--- .../ViewModels/SystemManagementViewModel.cs | 72 ------------- 10 files changed, 156 insertions(+), 220 deletions(-) diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md index 18f3003..455a3d9 100644 --- a/doc/requirement/todo_features.md +++ b/doc/requirement/todo_features.md @@ -2,6 +2,11 @@ ## 功能点 +### [2025/10/14] + +1. [x] (功能优化)用空间索引优化碰撞路径预处理 +2. [x] (功能优化)规范文档打开前/后的初始化行为 + ### [2025/10/12] 1. [x] (实验性功能)用体素网格实现3D路径规划 diff --git a/src/Core/MainPlugin.cs b/src/Core/MainPlugin.cs index 2256d1e..e19e68f 100644 --- a/src/Core/MainPlugin.cs +++ b/src/Core/MainPlugin.cs @@ -484,7 +484,7 @@ namespace NavisworksTransport var pathManager = PathPlanningManager.GetActivePathManager(); if (pathManager != null) { - pathManager.EnsureDatabaseInitialized(); + pathManager.DatabaseInitialize(); LogManager.Info("[文档管理] 已触发PathDatabase初始化"); } }, "初始化PathDatabase"); diff --git a/src/Core/ModelSplitterManager.cs b/src/Core/ModelSplitterManager.cs index 53a6870..9513409 100644 --- a/src/Core/ModelSplitterManager.cs +++ b/src/Core/ModelSplitterManager.cs @@ -443,80 +443,16 @@ namespace NavisworksTransport { // 设置静态实例 Instance = this; - + _floorDetector = new FloorDetector(); - + // 初始化缓存 _floorCache = new Dictionary>(); _cacheLock = new object(); - // 验证Navisworks运行时环境 - ValidateNavisworksRuntime(); - - LogManager.Info("[SimplifiedModelSplitter] 简化分层管理器已初始化,包含缓存机制和运行时验证"); + LogManager.Debug("[ModelSplitterManager] 分层管理器已初始化"); } - /// - /// 验证Navisworks运行时环境 - 基于示例中的最佳实践 - /// - private void ValidateNavisworksRuntime() - { - try - { - LogManager.Info("[SimplifiedModelSplitter] 开始验证Navisworks运行时环境..."); - - // 1. 检查线程模型 - 必须在STA线程中 - var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState(); - LogManager.Info($"[分层管理器] 当前线程状态: {apartmentState}"); - if (apartmentState != System.Threading.ApartmentState.STA) - { - LogManager.Warning("[SimplifiedModelSplitter] 警告:当前不在STA线程中,这可能导致API调用失败"); - LogManager.Warning("[SimplifiedModelSplitter] 建议:确保主线程标记为[STAThread]"); - } - - // 2. 检查Navisworks API可用性 - 适用于Navisworks 2026 - try - { - // 尝试访问Navisworks Application来验证API是否可用 - var app = NavisApplication.ActiveDocument; - LogManager.Info("[SimplifiedModelSplitter] Navisworks API可用性检查通过"); - } - catch (Exception apiEx) - { - LogManager.Error($"[分层管理器] Navisworks API不可用: {apiEx.Message}"); - LogManager.Error("[SimplifiedModelSplitter] 解决方案:确保在Navisworks环境中运行此插件"); - } - - // 3. 检查文档状态 - try - { - var document = NavisApplication.ActiveDocument; - if (document != null) - { - LogManager.Info($"[分层管理器] 活动文档: {document.FileName ?? "未命名"}"); - LogManager.Info($"[分层管理器] 文档模型数量: {document.Models?.Count ?? 0}"); - } - else - { - LogManager.Warning("[SimplifiedModelSplitter] 当前没有活动文档"); - } - } - catch (Exception docEx) - { - LogManager.Warning($"[分层管理器] 检查文档状态时出错: {docEx.Message}"); - } - - // 4. 内存状态检查 - long memoryMB = GC.GetTotalMemory(false) / 1024 / 1024; - LogManager.Info($"[分层管理器] 当前内存使用: {memoryMB} MB"); - - LogManager.Info("[SimplifiedModelSplitter] Navisworks运行时环境验证完成"); - } - catch (Exception ex) - { - LogManager.Error($"[分层管理器] 运行时环境验证失败: {ex.Message}"); - } - } #endregion diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index 11655c2..a8e08cc 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -117,40 +117,6 @@ namespace NavisworksTransport _activePathManager = this; LogManager.Debug($"[路径管理] 设置_activePathManager静态引用, ManagerId: {_managerId}"); - // 尝试初始化路径分析数据库 - EnsureDatabaseInitialized(); - } - - /// - /// 确保路径分析数据库已初始化(支持延迟初始化) - /// - public void EnsureDatabaseInitialized() - { - if (_pathDatabase != null && _analysisService != null) - { - LogManager.Info("路径分析数据库已初始化,跳过"); - return; - } - - try - { - var documentPath = Autodesk.Navisworks.Api.Application.ActiveDocument?.FileName; - if (!string.IsNullOrEmpty(documentPath)) - { - _pathDatabase = new PathDatabase(documentPath); - _analysisService = new PathAnalysisService(_pathDatabase); - LogManager.Info($"路径分析数据库初始化成功,文档路径: {documentPath}"); - } - else - { - LogManager.Warning("文档路径为空,路径分析数据库初始化将延迟到文档加载后"); - } - } - catch (Exception ex) - { - LogManager.Error($"初始化路径分析数据库失败: {ex.Message}", ex); - } - // 获取已注册的圆形渲染插件实例 try { @@ -175,6 +141,7 @@ namespace NavisworksTransport _renderPlugin = null; } + // 初始化核心数据结构 _walkableAreas = new List(); _routes = new List(); _currentRoute = new PathRoute("默认路径"); @@ -182,10 +149,47 @@ namespace NavisworksTransport _coordinateConverter = null; // 将在需要时初始化 _pathPointMarkers = new List(); - // 从数据库加载历史路径到内存 - LoadHistoricalRoutesFromDatabase(); - LogManager.Info($"PathPlanningManager初始化完成,ManagerId: {_managerId}"); + + // 注意:数据库初始化延迟到文档加载完成后 + // 在 MainPlugin.OnModelsCollectionChanged 中会调用 DatabaseInitialize() + } + + /// + /// 路径分析数据库初始化 + /// 此方法应在文档加载完成后调用 + /// + public void DatabaseInitialize() + { + // 如果已经初始化,直接返回 + if (_pathDatabase != null && _analysisService != null) + { + LogManager.Debug("路径分析数据库已初始化,跳过"); + return; + } + + 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); + } } /// diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 0f7e86a..e3dc163 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -200,8 +200,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels return Math.Round(pathLength / (_animationFrameRate * _animationDuration), 3); } - // 无法计算时返回0,让问题暴露 - if (pathLength <= 0 || _animationFrameRate <= 0 || _animationDuration <= 0) + // 无法计算时返回0 + // 注意:如果路径为空(pathLength==0),这是正常的初始状态,不输出警告 + // 只有在配置参数异常时才输出警告 + if (pathLength > 0 && (_animationFrameRate <= 0 || _animationDuration <= 0)) { LogManager.Warning($"[AnimationControlViewModel] 无法计算碰撞检测精度 - 路径长度:{pathLength}m, 帧率:{_animationFrameRate}fps, 时长:{_animationDuration}s"); } @@ -224,8 +226,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels return Math.Round(pathLength / _animationDuration, 2); } - // 无法计算时返回0,让问题暴露 - if (pathLength <= 0 || _animationDuration <= 0) + // 无法计算时返回0 + // 注意:如果路径为空(pathLength==0),这是正常的初始状态,不输出警告 + // 只有在配置参数异常时才输出警告 + if (pathLength > 0 && _animationDuration <= 0) { LogManager.Warning($"[AnimationControlViewModel] 无法计算运动速度 - 路径长度:{pathLength}m, 时长:{_animationDuration}s"); } diff --git a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs index d687df7..36acf08 100644 --- a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs @@ -944,7 +944,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels async () => await ShowAllLayersAsync(), () => IsNotProcessing); - LogManager.Info("分层管理命令初始化完成 - 使用统一Command Pattern框架"); + LogManager.Info("分层管理命令初始化完成"); }, "初始化命令"); } @@ -2718,20 +2718,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels { // 设置默认输出目录 var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - + await _uiStateManager.ExecuteUIUpdateAsync(() => { OutputDirectory = Path.Combine(documentsPath, "NavisworksTransport", "分层输出"); }); - - // 刷新可用属性 - await RefreshAttributesAsync(); - - // 更新选择状态 - await UpdateCurrentSelectionAsync(); - - // 刷新楼层属性模型选择状态 - await RefreshSelectionAsync(); } catch (Exception ex) { diff --git a/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs b/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs index 220aad1..4cfbbae 100644 --- a/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs +++ b/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs @@ -33,10 +33,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels #region 私有字段和依赖注入 private readonly UIStateManager _uiStateManager; - + // 选择事件订阅管理器 private SelectionEventSubscription _selectionEventSubscription; - + + // 文档模型集合变化事件订阅标志 + private bool _modelsCollectionEventSubscribed; + // 资源释放状态标志 private bool _disposed; @@ -395,6 +398,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 订阅Navisworks选择变化事件 - 使用新的选择管理服务 SubscribeToSelectionEvents(); + // 订阅文档模型集合变化事件 + SubscribeToDocumentModelsEvents(); + // 异步初始化 InitializeAsync(); @@ -920,6 +926,83 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 选择状态格式化方法已移至NavisworksSelectionHelper中 + #region 文档模型集合事件处理 + + /// + /// 订阅文档模型集合变化事件 + /// + private void SubscribeToDocumentModelsEvents() + { + try + { + var document = NavisApplication.ActiveDocument; + if (document?.Models != null && !_modelsCollectionEventSubscribed) + { + document.Models.CollectionChanged += OnDocumentModelsCollectionChanged; + _modelsCollectionEventSubscribed = true; + LogManager.Info("[ModelSettingsViewModel] 已订阅文档Models.CollectionChanged事件"); + } + } + catch (Exception ex) + { + LogManager.Error($"[ModelSettingsViewModel] 订阅文档模型集合事件失败: {ex.Message}", ex); + } + } + + /// + /// 取消订阅文档模型集合变化事件 + /// + private void UnsubscribeFromDocumentModelsEvents() + { + try + { + if (_modelsCollectionEventSubscribed) + { + var document = NavisApplication.ActiveDocument; + if (document?.Models != null) + { + document.Models.CollectionChanged -= OnDocumentModelsCollectionChanged; + } + _modelsCollectionEventSubscribed = false; + LogManager.Info("[ModelSettingsViewModel] 已取消订阅文档Models.CollectionChanged事件"); + } + } + catch (Exception ex) + { + LogManager.Error($"[ModelSettingsViewModel] 取消订阅文档模型集合事件失败: {ex.Message}", ex); + } + } + + /// + /// 文档模型集合变化事件处理器 + /// + private async void OnDocumentModelsCollectionChanged(object sender, EventArgs e) + { + // 如果已经释放,直接返回 + if (_disposed) return; + + try + { + var document = NavisApplication.ActiveDocument; + var modelsCount = document?.Models?.Count ?? 0; + + LogManager.Info($"[ModelSettingsViewModel] 文档模型集合变化,当前模型数量: {modelsCount}"); + + // 只有在有模型的情况下才刷新物流模型列表 + if (modelsCount > 0) + { + LogManager.Info("[ModelSettingsViewModel] 检测到文档模型加载完成,自动刷新物流模型列表"); + await RefreshLogisticsModelsAsync(); + } + } + catch (Exception ex) + { + LogManager.Error($"[ModelSettingsViewModel] 处理文档模型集合变化事件异常: {ex.Message}", ex); + } + } + + #endregion + #region 选择事件处理 /// @@ -1053,17 +1136,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels } }); - // 刷新选择状态 - await RefreshSelectionAsync(); + // 注意:不在初始化时刷新选择状态和物流模型列表 + // 刷新会在以下情况自动触发: + // 1. 选择状态 - 通过 NavisworksSelectionHelper 的选择变化事件自动刷新 + // 2. 物流模型列表 - 通过 Models.CollectionChanged 事件在文档加载后自动刷新 - // 刷新物流模型列表 - await RefreshLogisticsModelsAsync(); - // 🔧 确保初始化完成后所有Command状态正确 await _uiStateManager.ExecuteUIUpdateAsync(() => { RefreshAllCommands(); - UpdateMainStatus("分层属性设置已就绪"); + UpdateMainStatus("类别设置已就绪"); }); } catch (Exception ex) @@ -1253,6 +1335,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 取消选择事件订阅 UnsubscribeFromSelectionEvents(); + // 取消文档模型集合事件订阅 + UnsubscribeFromDocumentModelsEvents(); + LogManager.Info("[ModelSettingsViewModel] 资源清理完成"); } catch (Exception ex) diff --git a/src/UI/WPF/ViewModels/PathAnalysisViewModel.cs b/src/UI/WPF/ViewModels/PathAnalysisViewModel.cs index 2a01fe0..a260737 100644 --- a/src/UI/WPF/ViewModels/PathAnalysisViewModel.cs +++ b/src/UI/WPF/ViewModels/PathAnalysisViewModel.cs @@ -174,7 +174,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels try { var manager = PathPlanningManager.Instance; - manager.EnsureDatabaseInitialized(); + manager.DatabaseInitialize(); } catch (Exception ex) { diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index cd0cd0c..98ccd16 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -2148,14 +2148,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels { if (_pathPlanningManager == null) { - LogManager.Info("PathPlanningManager为null,跳过事件订阅"); + LogManager.Debug("PathPlanningManager尚未设置,跳过事件订阅"); return; } try { - LogManager.Info($"*** 开始订阅PathPlanningManager事件,Manager实例: {_pathPlanningManager.GetType().Name} ***"); - // 订阅路径点操作事件(用于手工路径编辑) _pathPlanningManager.PathPointOperation += OnPathPointOperation; @@ -2174,22 +2172,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 添加错误事件订阅 - 用于处理自动路径规划失败等错误 _pathPlanningManager.ErrorOccurred += OnPathPlanningError; - LogManager.Info("*** PathEditingViewModel已成功订阅PathPlanningManager事件,包括RouteGenerated和ErrorOccurred ***"); - - // 验证事件订阅是否成功 - var routeGeneratedField = _pathPlanningManager.GetType().GetEvent("RouteGenerated"); - if (routeGeneratedField != null) - { - LogManager.Info($"*** RouteGenerated事件存在,事件类型: {routeGeneratedField.EventHandlerType?.Name} ***"); - } - else - { - LogManager.Error("*** RouteGenerated事件不存在!!! ***"); - } - - // 初始化加载现有路径(包括从数据库加载的历史路径) - RefreshPathRoutes(); - LogManager.Info("*** 已从PathPlanningManager加载现有路径到UI ***"); + LogManager.Debug("PathEditingViewModel已成功订阅PathPlanningManager事件"); } catch (Exception ex) { diff --git a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs index a05f1af..52d1e79 100644 --- a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs @@ -460,82 +460,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels UpdateMainStatus("系统管理初始化完成"); }); - // 启动性能监控 - StartPerformanceMonitoring(); - LogManager.Info("系统管理设置初始化完成"); }, "初始化系统管理设置"); } - /// - /// 启动性能监控 (已优化为Idle事件) - /// - private void StartPerformanceMonitoring() - { - // 如果已经释放,不启动监控 - if (_disposed) - { - LogManager.Info("SystemManagementViewModel已释放,跳过性能监控启动"); - return; - } - - _startTime = DateTime.Now; - _lastPerformanceUpdate = DateTime.MinValue; - - // 使用IdleEventManager注册性能监控任务,替代DispatcherTimer - const string taskId = "SystemManagement_PerformanceMonitor"; - - IdleEventManager.Instance.RegisterTask( - taskId, - UpdatePerformanceMetrics, // 要执行的操作 - 30000, // 30秒间隔 (毫秒) - 5 // 中等优先级 - ); - - LogManager.Info("SystemManagementViewModel性能监控已启动 (Idle事件模式)"); - } - - /// - /// 更新性能指标 (Idle事件回调方法) - /// - private void UpdatePerformanceMetrics() - { - try - { - // 检查释放状态,避免在释放后继续更新UI - if (_disposed) - { - LogManager.Info("SystemManagementViewModel已释放,停止性能监控更新"); - IdleEventManager.Instance.UnregisterTask("SystemManagement_PerformanceMonitor"); - return; - } - - // 更新内存使用 - var process = System.Diagnostics.Process.GetCurrentProcess(); - var memoryMB = process.WorkingSet64 / (1024 * 1024); - MemoryUsage = $"{memoryMB} MB"; - - // 更新运行时间 - var runTime = DateTime.Now - _startTime; - RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}"; - - // 记录上次更新时间 - _lastPerformanceUpdate = DateTime.Now; - - LogManager.Debug($"性能指标已更新: 内存={MemoryUsage}, 运行时间={RunningTime}"); - } - catch (Exception ex) - { - LogManager.Error($"性能监控更新失败: {ex.Message}"); - - // 发生异常时停止监控,避免持续错误 - if (!_disposed) - { - IdleEventManager.Instance.UnregisterTask("SystemManagement_PerformanceMonitor"); - } - } - } - #endregion #region 命令实现