网格点在设置时同步刷新
This commit is contained in:
parent
62349099aa
commit
8946873e32
@ -135,7 +135,8 @@
|
||||
"Bash(\"./compile.bat\")",
|
||||
"Bash(xcopy:*)",
|
||||
"Read(//c/ProgramData/Autodesk/Navisworks Manage 2026/NavisworksTransport/logs/**)",
|
||||
"Bash(sed:*)"
|
||||
"Bash(sed:*)",
|
||||
"Read(//c/ProgramData/Autodesk/**)"
|
||||
],
|
||||
"deny": [],
|
||||
"additionalDirectories": [
|
||||
|
||||
@ -186,4 +186,5 @@ public class PathClickToolPlugin : ToolPlugin { }
|
||||
- **Hot reload**: Restart Navisworks required after compilation to load new plugin version
|
||||
- **Debugging**: Use LogManager for centralized logging and the built-in log viewer dialog for log analysis
|
||||
- **2026 Features**: Test advanced animation capabilities, enhanced collision detection, and improved model handling
|
||||
- 在编码中,不要用回退或向后兼容的思路和步骤
|
||||
- 在编码中,不要用回退或向后兼容的思路和步骤
|
||||
- 程序的日志在:C:\ProgramData\Autodesk\Navisworks Manage 2026\NavisworksTransport\logs\debug.log
|
||||
@ -1871,3 +1871,29 @@ private static void SimpleProgressExample()
|
||||
Autodesk.Navisworks.Api.Application.EndProgress();
|
||||
}
|
||||
```
|
||||
|
||||
### Navisworks的Models.CollectionChanged事件模式
|
||||
|
||||
事件模式总结
|
||||
|
||||
场景1:第一次打开文件(2ND_FLOOR)
|
||||
- 事件#1 (6.6秒):Count=0,状态保持无模型(文档清空准备加载)
|
||||
- 事件#2 (6.7秒):Count=1,从无模型→有模型(文件加载完成)
|
||||
|
||||
场景2:重新打开新文件(4TH_FLOOR)
|
||||
- 事件#3 (25.6秒):Count=0,从有模型→无模型(旧文件被清空)
|
||||
- 事件#4 (25.6秒):Count=1,从无模型→有模型(新文件加载完成)
|
||||
|
||||
场景3:关闭程序
|
||||
- 事件#5 (39.8秒):Count=0,从有模型→无模型(程序关闭前清理)
|
||||
|
||||
关键发现
|
||||
|
||||
1. 每次文档操作都有两个事件:
|
||||
- 先清空Models(Count=0)
|
||||
- 再加载新Models(Count>0)
|
||||
2. 状态转换清晰:
|
||||
- 无模型→无模型:初始清理
|
||||
- 无模型→有模型:文档加载完成 ✅ 这是我们需要初始化的时机
|
||||
- 有模型→无模型:文档关闭/切换 ✅ 这是我们需要清理的时机
|
||||
3. 时间间隔很短:事件成对出现,间隔仅0.1秒左右
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
### [2025/09/14]
|
||||
|
||||
1. [x] (功能)增加两种路径连线方式:1、宽度路径,半透明,膨胀直径,10cm高立方体。2、和前面一样,高度为车高加安全距离
|
||||
1. [x] (功能)增加空间通道连线方式:1、宽度路径,半透明,膨胀直径高度为车高加安全距离
|
||||
|
||||
### [2025/09/12]
|
||||
|
||||
|
||||
331
doc/working/2025-09-14_文档切换三级处理机制设计.md
Normal file
331
doc/working/2025-09-14_文档切换三级处理机制设计.md
Normal file
@ -0,0 +1,331 @@
|
||||
# 文档切换三级处理机制设计方案
|
||||
|
||||
**日期**: 2025-09-14
|
||||
**作者**: Claude
|
||||
**背景**: 解决Navisworks插件在文档切换时的崩溃问题
|
||||
|
||||
## 一、问题分析
|
||||
|
||||
### 发现的问题
|
||||
|
||||
1. Navisworks是SDI(单文档界面)应用,ActiveDocument在整个生命周期中保持不变
|
||||
2. 文档内容变化通过`Models.CollectionChanged`事件通知
|
||||
3. 原代码在Models清空时调用了完整的CleanupManagers,导致IdleEventManager被Dispose,引发崩溃
|
||||
|
||||
### 测试观察结果
|
||||
|
||||
通过观察版本测试,发现Models.CollectionChanged事件的触发模式:
|
||||
|
||||
**场景1:第一次打开文件**
|
||||
|
||||
- 事件#1:Count=0,状态保持无模型(文档清空准备加载)
|
||||
- 事件#2:Count=1,从无模型→有模型(文件加载完成)
|
||||
|
||||
**场景2:重新打开新文件**
|
||||
|
||||
- 事件#3:Count=0,从有模型→无模型(旧文件被清空)
|
||||
- 事件#4:Count=1,从无模型→有模型(新文件加载完成)
|
||||
|
||||
**场景3:关闭程序**
|
||||
|
||||
- 事件#5:Count=0,从有模型→无模型(程序关闭前清理)
|
||||
|
||||
## 二、设计方案
|
||||
|
||||
### 整体架构
|
||||
|
||||
```
|
||||
插件生命周期:
|
||||
├── OnLoaded(插件启动)- 重量级初始化
|
||||
├── Models.CollectionChanged(文档切换)- 轻量级状态管理
|
||||
└── OnUnloading/DestroyControlPane(插件关闭)- 重量级清理
|
||||
```
|
||||
|
||||
### 三种处理级别
|
||||
|
||||
1. **插件初始化**(OnLoaded)
|
||||
- 创建所有管理器实例
|
||||
- 初始化UI组件
|
||||
- 订阅事件
|
||||
|
||||
2. **文档状态切换**(Models.CollectionChanged)
|
||||
- 轻量级操作
|
||||
- 清理/刷新ModelItem引用
|
||||
- 重置可视化状态
|
||||
- 保持管理器实例存活
|
||||
|
||||
3. **插件关闭**(OnUnloading + DestroyControlPane)
|
||||
- 重量级清理
|
||||
- 销毁所有管理器实例
|
||||
- 取消所有事件订阅
|
||||
- 释放所有资源
|
||||
|
||||
## 三、具体实现
|
||||
|
||||
### 1. 添加必要的成员变量
|
||||
|
||||
```csharp
|
||||
public class Main : DockPanePlugin
|
||||
{
|
||||
// 状态跟踪变量
|
||||
private bool _hasModels = false; // 跟踪模型状态
|
||||
private bool _isShuttingDown = false; // 插件关闭标志
|
||||
private int _eventCount = 0; // 事件计数(调试用)
|
||||
private DateTime _pluginStartTime; // 插件启动时间
|
||||
}
|
||||
```
|
||||
|
||||
### 2. OnLoaded - 插件初始化(一次性)
|
||||
|
||||
```csharp
|
||||
protected override void OnLoaded()
|
||||
{
|
||||
base.OnLoaded();
|
||||
|
||||
_pluginStartTime = DateTime.Now;
|
||||
_isShuttingDown = false;
|
||||
|
||||
LogManager.Info("[文档管理] 插件OnLoaded - 开始初始化");
|
||||
|
||||
// 订阅文档事件
|
||||
SubscribeToDocumentEvents();
|
||||
|
||||
// 一次性初始化管理器(创建实例)
|
||||
if (NavisApplication.ActiveDocument != null)
|
||||
{
|
||||
LogManager.Info("[文档管理] 插件加载时发现活动文档,初始化管理器");
|
||||
InitializeManagers(); // 创建管理器实例
|
||||
|
||||
// 检查文档是否有内容
|
||||
if (NavisApplication.ActiveDocument.Models?.Count > 0)
|
||||
{
|
||||
_hasModels = true;
|
||||
RefreshDocumentStates(); // 刷新状态
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. OnModelsCollectionChanged - 文档切换处理(频繁)
|
||||
|
||||
```csharp
|
||||
private void OnModelsCollectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
_eventCount++;
|
||||
|
||||
// 如果插件正在关闭,跳过所有处理
|
||||
if (_isShuttingDown)
|
||||
{
|
||||
LogManager.Info("[文档管理] 插件正在关闭,跳过Models.CollectionChanged处理");
|
||||
return;
|
||||
}
|
||||
|
||||
var activeDoc = NavisApplication.ActiveDocument;
|
||||
var modelCount = activeDoc?.Models?.Count ?? 0;
|
||||
bool currentHasModels = modelCount > 0;
|
||||
|
||||
LogManager.Info($"[文档管理] Models.CollectionChanged #{_eventCount}, Count={modelCount}, 状态: {(_hasModels ? "有" : "无")} -> {(currentHasModels ? "有" : "无")}");
|
||||
|
||||
// 状态转换:从有到无(文档被清空)
|
||||
if (_hasModels && !currentHasModels)
|
||||
{
|
||||
LogManager.Info("[文档管理] 文档已清空,执行轻量级清理");
|
||||
ClearDocumentStates();
|
||||
}
|
||||
// 状态转换:从无到有(文档加载完成)
|
||||
else if (!_hasModels && currentHasModels)
|
||||
{
|
||||
LogManager.Info("[文档管理] 文档已加载,刷新状态");
|
||||
RefreshDocumentStates();
|
||||
}
|
||||
// 状态未变化
|
||||
else
|
||||
{
|
||||
LogManager.Info("[文档管理] 模型集合更新但状态未变");
|
||||
}
|
||||
|
||||
_hasModels = currentHasModels;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 新增轻量级方法
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 轻量级清理 - 仅清理文档相关状态,不销毁管理器
|
||||
/// </summary>
|
||||
private void ClearDocumentStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[文档管理] 开始轻量级状态清理...");
|
||||
|
||||
// 1. 停止动画(如果正在播放)
|
||||
var animationManager = PathAnimationManager.GetInstance();
|
||||
if (animationManager?.IsAnimating == true)
|
||||
{
|
||||
animationManager.StopAnimation();
|
||||
}
|
||||
// 清理动画中的ModelItem引用
|
||||
animationManager?.ClearReferences();
|
||||
|
||||
// 2. 清理路径管理器状态
|
||||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||||
if (pathManager != null)
|
||||
{
|
||||
pathManager.ResetPathEditState();
|
||||
pathManager.ClearInvalidReferences(); // 清理ModelItem引用
|
||||
}
|
||||
|
||||
// 3. 清理路径可视化
|
||||
PathPointRenderPlugin.Instance?.ClearAllPaths();
|
||||
|
||||
// 4. 清理碰撞检测缓存
|
||||
ClashDetectiveIntegration.Instance?.ClearCollisionCache();
|
||||
ClashDetectiveIntegration.ClearAllCaches();
|
||||
|
||||
// 5. 清除临时材质
|
||||
if (NavisApplication.ActiveDocument?.Models != null)
|
||||
{
|
||||
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||||
}
|
||||
|
||||
// 6. 通知文档状态管理器
|
||||
DocumentStateManager.Instance.OnDocumentInvalidated();
|
||||
|
||||
LogManager.Info("[文档管理] 轻量级状态清理完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 状态清理时出现警告: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轻量级刷新 - 仅刷新状态,不重新创建管理器
|
||||
/// </summary>
|
||||
private void RefreshDocumentStates()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[文档管理] 开始刷新文档状态...");
|
||||
|
||||
// 1. 通知文档状态管理器
|
||||
DocumentStateManager.Instance.OnDocumentReady();
|
||||
|
||||
// 2. 清理旧缓存
|
||||
ClashDetectiveIntegration.ClearAllCaches();
|
||||
|
||||
// 3. 刷新路径管理器(如果需要)
|
||||
var pathManager = PathPlanningManager.GetActivePathManager();
|
||||
pathManager?.RefreshDocument();
|
||||
|
||||
LogManager.Info("[文档管理] 文档状态刷新完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 状态刷新时出现警告: {ex.Message}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. OnUnloading - 插件关闭(一次性)
|
||||
|
||||
```csharp
|
||||
protected override void OnUnloading()
|
||||
{
|
||||
LogManager.Info("[文档管理] 插件OnUnloading - 开始关闭");
|
||||
|
||||
// 设置关闭标志,阻止后续的Models事件处理
|
||||
_isShuttingDown = true;
|
||||
|
||||
// 取消订阅文档事件
|
||||
UnsubscribeFromDocumentEvents();
|
||||
|
||||
// 执行完整的管理器清理(销毁实例)
|
||||
CleanupManagers();
|
||||
|
||||
base.OnUnloading();
|
||||
}
|
||||
```
|
||||
|
||||
### 6. DestroyControlPane - 控件销毁
|
||||
|
||||
```csharp
|
||||
public override void DestroyControlPane(Control pane)
|
||||
{
|
||||
GlobalExceptionHandler.SafeExecute(() =>
|
||||
{
|
||||
LogManager.Info("开始销毁DockPane控制面板");
|
||||
|
||||
// 设置关闭标志(双重保险)
|
||||
_isShuttingDown = true;
|
||||
|
||||
// 清理WPF控件资源
|
||||
if (pane is ElementHost elementHost && elementHost.Child is UI.WPF.LogisticsControlPanel wpfControl)
|
||||
{
|
||||
wpfControl.Cleanup();
|
||||
elementHost.Child = null;
|
||||
}
|
||||
|
||||
// 释放控件资源
|
||||
pane?.Dispose();
|
||||
|
||||
LogManager.Info("DockPane控制面板销毁完成");
|
||||
}, "销毁控制面板");
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 保持不变的方法
|
||||
|
||||
- **InitializeManagers()** - 保持原样,用于创建管理器实例
|
||||
- **CleanupManagers()** - 保持原样,用于销毁管理器实例
|
||||
- **SubscribeToDocumentEvents()** - 保持原样
|
||||
- **UnsubscribeFromDocumentEvents()** - 保持原样
|
||||
|
||||
## 四、关键设计原则
|
||||
|
||||
### 1. 分离关注点
|
||||
|
||||
- 插件生命周期管理(OnLoaded/OnUnloading)
|
||||
- 文档状态管理(Models.CollectionChanged)
|
||||
- UI生命周期管理(CreateControlPane/DestroyControlPane)
|
||||
|
||||
### 2. 轻量级 vs 重量级
|
||||
|
||||
- **轻量级**:清理引用、重置状态、清空缓存
|
||||
- **重量级**:创建/销毁实例、订阅/取消事件
|
||||
|
||||
### 3. 防御性编程
|
||||
|
||||
- 使用`_isShuttingDown`标志防止关闭时的事件处理
|
||||
- 所有清理操作都包含try-catch
|
||||
- 使用GlobalExceptionHandler.SafeExecute
|
||||
|
||||
### 4. 性能优化
|
||||
|
||||
- 文档切换时不重新创建管理器
|
||||
- 只在必要时清理和刷新
|
||||
- 避免重复操作
|
||||
|
||||
## 五、预期效果
|
||||
|
||||
1. **启动时**:完整初始化,创建所有组件
|
||||
2. **文档切换时**:快速清理和刷新,保持响应性
|
||||
3. **关闭时**:干净退出,避免异常
|
||||
|
||||
## 六、实施计划
|
||||
|
||||
1. 先实现`_isShuttingDown`标志,防止关闭时的崩溃
|
||||
2. 实现`ClearDocumentStates()`和`RefreshDocumentStates()`方法
|
||||
3. 修改`OnModelsCollectionChanged`使用新的轻量级方法
|
||||
4. 测试各种场景确保稳定性
|
||||
|
||||
## 七、注意事项
|
||||
|
||||
1. PathPlanningManager可能需要添加`RefreshDocument()`方法
|
||||
2. 确保所有管理器都有适当的清理引用方法
|
||||
3. 考虑添加更多的日志来跟踪状态变化
|
||||
4. 可能需要在某些管理器中区分"清理状态"和"销毁实例"
|
||||
|
||||
这个方案清晰地分离了不同场景的处理逻辑,避免了混淆,确保了稳定性。
|
||||
@ -312,6 +312,11 @@ namespace NavisworksTransport
|
||||
/// <summary>
|
||||
/// 构造函数,提前初始化全局异常处理器
|
||||
/// </summary>
|
||||
// 状态跟踪变量(用于观察Models.CollectionChanged事件)
|
||||
private bool _hasModels = false;
|
||||
private int _eventCount = 0;
|
||||
private DateTime _pluginStartTime = DateTime.Now;
|
||||
|
||||
public Main()
|
||||
{
|
||||
// 在任何控件创建之前初始化全局异常处理器
|
||||
@ -325,6 +330,8 @@ namespace NavisworksTransport
|
||||
{
|
||||
base.OnLoaded();
|
||||
|
||||
_pluginStartTime = DateTime.Now; // 记录插件启动时间
|
||||
|
||||
LogManager.Info("[文档管理] 插件OnLoaded - 开始初始化");
|
||||
|
||||
// 订阅文档事件
|
||||
@ -365,10 +372,19 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
// 只订阅活动文档切换事件
|
||||
// 订阅文档切换前事件(保留用于未来兼容性)
|
||||
NavisApplication.ActiveDocumentChanging += OnActiveDocumentChanging;
|
||||
// 订阅文档切换后事件(保留用于未来兼容性)
|
||||
NavisApplication.ActiveDocumentChanged += OnActiveDocumentChanged;
|
||||
|
||||
LogManager.Info("[文档管理] 已订阅活动文档切换事件");
|
||||
|
||||
// 订阅模型集合变化事件(SDI架构下的真正文档变化事件)
|
||||
if (NavisApplication.ActiveDocument != null)
|
||||
{
|
||||
NavisApplication.ActiveDocument.Models.CollectionChanged += OnModelsCollectionChanged;
|
||||
LogManager.Info("[文档管理] 已订阅模型集合变化事件");
|
||||
}
|
||||
|
||||
LogManager.Info("[文档管理] 已订阅文档相关事件(Changing + Changed + Models.CollectionChanged)");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -376,34 +392,111 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 活动文档切换前事件处理
|
||||
/// </summary>
|
||||
private void OnActiveDocumentChanging(object sender, EventArgs e)
|
||||
{
|
||||
LogManager.Info($"[文档管理] 文档即将切换,当前文档: {NavisApplication.ActiveDocument?.FileName ?? "无"}");
|
||||
|
||||
// 取消订阅旧文档的Models.CollectionChanged事件
|
||||
if (NavisApplication.ActiveDocument != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged;
|
||||
LogManager.Info("[文档管理] 已取消订阅旧文档的模型集合变化事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 取消订阅旧文档事件时出现警告: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 清理旧文档的状态
|
||||
CleanupManagers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 活动文档切换事件处理
|
||||
/// </summary>
|
||||
private void OnActiveDocumentChanged(object sender, EventArgs e)
|
||||
{
|
||||
LogManager.Info($"[文档管理] 文档已切换到: {NavisApplication.ActiveDocument?.FileName ?? "无活动文档"}");
|
||||
|
||||
GlobalExceptionHandler.SafeExecute(() =>
|
||||
{
|
||||
var activeDoc = NavisApplication.ActiveDocument;
|
||||
var oldDocName = DocumentStateManager.Instance.CurrentDocumentPath ?? "无";
|
||||
var newDocName = activeDoc?.FileName ?? "无活动文档";
|
||||
|
||||
LogManager.Info($"[文档管理] 活动文档切换: {oldDocName} → {newDocName}");
|
||||
|
||||
// 先清理旧文档的状态
|
||||
CleanupManagers();
|
||||
|
||||
// 如果有新的活动文档,重新初始化
|
||||
|
||||
// 如果有新的活动文档,订阅其Models.CollectionChanged事件
|
||||
if (activeDoc != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
activeDoc.Models.CollectionChanged += OnModelsCollectionChanged;
|
||||
LogManager.Info("[文档管理] 已订阅新文档的模型集合变化事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 订阅新文档事件时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
InitializeManagers();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("[文档管理] 当前无活动文档");
|
||||
}
|
||||
|
||||
|
||||
}, "处理活动文档切换事件");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模型集合变化事件处理(SDI架构下的真正文档变化事件)
|
||||
/// </summary>
|
||||
private void OnModelsCollectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
_eventCount++;
|
||||
|
||||
var activeDoc = NavisApplication.ActiveDocument;
|
||||
var modelCount = activeDoc?.Models?.Count ?? 0;
|
||||
bool currentHasModels = modelCount > 0;
|
||||
var timeSinceStart = (DateTime.Now - _pluginStartTime).TotalSeconds;
|
||||
|
||||
LogManager.Info("========================================");
|
||||
LogManager.Info($"[文档管理] Models.CollectionChanged 事件 #{_eventCount}");
|
||||
LogManager.Info($"[文档管理] 触发时间: 插件启动后 {timeSinceStart:F1} 秒");
|
||||
LogManager.Info($"[文档管理] 当前Models.Count = {modelCount}");
|
||||
LogManager.Info($"[文档管理] 状态变化: {(_hasModels ? "有模型" : "无模型")} -> {(currentHasModels ? "有模型" : "无模型")}");
|
||||
LogManager.Info($"[文档管理] 文档文件名: {activeDoc?.FileName ?? "空"}");
|
||||
LogManager.Info($"[文档管理] 文档标题: {activeDoc?.Title ?? "空"}");
|
||||
|
||||
// 分析状态变化类型
|
||||
if (!_hasModels && currentHasModels)
|
||||
{
|
||||
LogManager.Info($"[文档管理] *** 状态分析: 从无到有(可能是打开文档)***");
|
||||
}
|
||||
else if (_hasModels && !currentHasModels)
|
||||
{
|
||||
LogManager.Info($"[文档管理] *** 状态分析: 从有到无(可能是关闭文档)***");
|
||||
}
|
||||
else if (!_hasModels && !currentHasModels)
|
||||
{
|
||||
LogManager.Info($"[文档管理] *** 状态分析: 保持无模型状态 ***");
|
||||
}
|
||||
else if (_hasModels && currentHasModels)
|
||||
{
|
||||
LogManager.Info($"[文档管理] *** 状态分析: 保持有模型状态(模型数量变化)***");
|
||||
}
|
||||
|
||||
LogManager.Info("========================================");
|
||||
|
||||
// 更新状态
|
||||
_hasModels = currentHasModels;
|
||||
|
||||
// 暂时不执行任何清理或初始化操作
|
||||
LogManager.Info("[文档管理] 观察模式:不执行清理或初始化操作");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化各个管理器
|
||||
@ -476,7 +569,22 @@ namespace NavisworksTransport
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 清理路径管理器时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
// 清理路径渲染插件的可视化
|
||||
try
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin != null)
|
||||
{
|
||||
renderPlugin.ClearAllPaths();
|
||||
LogManager.Info("[文档管理] 已清理路径可视化");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 清理路径可视化时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
// 清理碰撞检测缓存
|
||||
try
|
||||
{
|
||||
@ -585,10 +693,25 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
// 只取消订阅活动文档切换事件
|
||||
// 取消订阅文档切换事件
|
||||
NavisApplication.ActiveDocumentChanging -= OnActiveDocumentChanging;
|
||||
NavisApplication.ActiveDocumentChanged -= OnActiveDocumentChanged;
|
||||
|
||||
LogManager.Info("[文档管理] 已取消订阅文档事件");
|
||||
|
||||
// 取消订阅当前文档的Models.CollectionChanged事件
|
||||
if (NavisApplication.ActiveDocument != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged;
|
||||
LogManager.Info("[文档管理] 已取消订阅模型集合变化事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 取消订阅模型集合事件时出现警告: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.Info("[文档管理] 已取消订阅所有文档相关事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@ -53,6 +53,7 @@ namespace NavisworksTransport
|
||||
private bool _showObstacleGrid = false;
|
||||
private bool _showUnknownGrid = false;
|
||||
private bool _showDoorGrid = false;
|
||||
private GridMap _currentGridMap = null; // 保存当前网格地图用于刷新
|
||||
private bool _isPreviewMode = false;
|
||||
private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置
|
||||
|
||||
@ -578,7 +579,17 @@ namespace NavisworksTransport
|
||||
{
|
||||
_currentRoute.Points.Clear();
|
||||
}
|
||||
|
||||
|
||||
// 清空通道引用
|
||||
if (_walkableAreas != null)
|
||||
{
|
||||
_walkableAreas.Clear();
|
||||
LogManager.Info("[PathPlanningManager] 已清空通道引用");
|
||||
}
|
||||
|
||||
// 清空组合边界
|
||||
_combinedChannelBounds = null;
|
||||
|
||||
LogManager.Info("[PathPlanningManager] 对象引用清理完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -968,10 +979,18 @@ namespace NavisworksTransport
|
||||
|
||||
LogManager.Info($"A*算法找到路径,包含 {pathResult.PathPoints.Count} 个点,完成度: {pathResult.CompletionPercentage:F1}%");
|
||||
|
||||
// 6. 创建PathRoute对象
|
||||
// 6. 创建PathRoute对象并保存GridMap
|
||||
var routeName = $"自动路径_{DateTime.Now:HHmmss}";
|
||||
var autoRoute = CreateAutoPathRoute(pathResult, routeName);
|
||||
|
||||
// 保存GridMap和参数到PathRoute以便后续恢复网格可视化
|
||||
autoRoute.AssociatedGridMap = gridMap;
|
||||
autoRoute.GridSize = gridSize;
|
||||
autoRoute.VehicleSize = vehicleSize;
|
||||
autoRoute.SafetyMargin = safetyMargin;
|
||||
autoRoute.VehicleHeight = vehicleHeight;
|
||||
LogManager.Info($"已保存GridMap到路径: {routeName}, 网格大小: {gridSize}米");
|
||||
|
||||
// 7. 添加到路径集合
|
||||
if (!_routes.Contains(autoRoute))
|
||||
{
|
||||
@ -1049,6 +1068,30 @@ namespace NavisworksTransport
|
||||
try
|
||||
{
|
||||
CurrentRoute = route;
|
||||
|
||||
// 如果路径有关联的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)
|
||||
@ -3177,10 +3220,21 @@ namespace NavisworksTransport
|
||||
{
|
||||
// 清除当前网格可视化
|
||||
ClearGridVisualization();
|
||||
|
||||
// 如果存在当前网格地图,重新应用可视化
|
||||
// 这里需要保存对最后一个gridMap的引用,或者从当前路径规划状态中重新获取
|
||||
LogManager.Info("[网格可视化] 刷新完成 - 需要重新进行路径规划以查看网格");
|
||||
|
||||
// 如果存在缓存的网格地图且有网格可视化设置启用,重新进行可视化
|
||||
if (_currentGridMap != null && IsAnyGridVisualizationEnabled)
|
||||
{
|
||||
LogManager.Info("[网格可视化] 使用缓存的网格地图重新渲染");
|
||||
VisualizeGridCells(_currentGridMap);
|
||||
}
|
||||
else if (_currentGridMap == null)
|
||||
{
|
||||
LogManager.Info("[网格可视化] 无缓存网格地图,需要重新进行路径规划以查看网格");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("[网格可视化] 网格可视化设置已关闭,跳过渲染");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -3203,6 +3257,8 @@ namespace NavisworksTransport
|
||||
|
||||
try
|
||||
{
|
||||
// 保存当前网格地图用于后续刷新
|
||||
_currentGridMap = gridMap;
|
||||
LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}");
|
||||
|
||||
// 获取渲染插件
|
||||
|
||||
@ -376,6 +376,32 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
public double CompletionPercentage { get; set; } = 100.0;
|
||||
|
||||
/// <summary>
|
||||
/// 关联的网格地图(用于网格可视化)
|
||||
/// </summary>
|
||||
[XmlIgnore]
|
||||
public NavisworksTransport.PathPlanning.GridMap AssociatedGridMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 网格大小(米)
|
||||
/// </summary>
|
||||
public double GridSize { get; set; } = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// 车辆尺寸(米)
|
||||
/// </summary>
|
||||
public double VehicleSize { get; set; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// 安全间隙(米)
|
||||
/// </summary>
|
||||
public double SafetyMargin { get; set; } = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// 车辆高度(米)
|
||||
/// </summary>
|
||||
public double VehicleHeight { get; set; } = 2.0;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@ -557,7 +583,16 @@ namespace NavisworksTransport
|
||||
CreatedTime = CreatedTime,
|
||||
LastModified = DateTime.Now,
|
||||
Description = Description,
|
||||
AssociatedChannelIds = new List<string>(AssociatedChannelIds)
|
||||
AssociatedChannelIds = new List<string>(AssociatedChannelIds),
|
||||
IsComplete = IsComplete,
|
||||
OriginalEndPoint = OriginalEndPoint,
|
||||
ActualEndPoint = ActualEndPoint,
|
||||
CompletionPercentage = CompletionPercentage,
|
||||
AssociatedGridMap = AssociatedGridMap, // 共享引用,不深拷贝
|
||||
GridSize = GridSize,
|
||||
VehicleSize = VehicleSize,
|
||||
SafetyMargin = SafetyMargin,
|
||||
VehicleHeight = VehicleHeight
|
||||
};
|
||||
|
||||
// 克隆所有路径点
|
||||
|
||||
@ -240,8 +240,8 @@ namespace NavisworksTransport
|
||||
set
|
||||
{
|
||||
_visualizationMode = value;
|
||||
// 模式改变时刷新所有路径可视化
|
||||
RefreshAllPaths();
|
||||
// 模式改变时刷新所有普通路径(排除网格)
|
||||
RefreshNormalPaths();
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,8 +254,11 @@ namespace NavisworksTransport
|
||||
set
|
||||
{
|
||||
_vehicleHeightMode = value;
|
||||
// 高度模式改变时刷新所有路径可视化
|
||||
RefreshAllPaths();
|
||||
// 只有在车辆空间模式下才需要刷新
|
||||
if (_visualizationMode == PathVisualizationMode.VehicleSpace)
|
||||
{
|
||||
RefreshNormalPaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,14 +540,27 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新所有路径可视化(用于可视化模式改变时)
|
||||
/// 判断是否为网格可视化路径
|
||||
/// </summary>
|
||||
private void RefreshAllPaths()
|
||||
private bool IsGridVisualizationPath(string pathId)
|
||||
{
|
||||
return pathId != null && (
|
||||
pathId.StartsWith("grid_visualization_") ||
|
||||
pathId == "grid_visualization_all");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新所有普通路径(排除网格可视化)
|
||||
/// </summary>
|
||||
private void RefreshNormalPaths()
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
var pathIds = _pathVisualizations.Keys.ToList();
|
||||
foreach (var pathId in pathIds)
|
||||
var normalPathIds = _pathVisualizations.Keys
|
||||
.Where(id => !IsGridVisualizationPath(id))
|
||||
.ToList();
|
||||
|
||||
foreach (var pathId in normalPathIds)
|
||||
{
|
||||
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
|
||||
{
|
||||
@ -552,9 +568,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
if (pathIds.Count > 0)
|
||||
if (normalPathIds.Count > 0)
|
||||
{
|
||||
LogManager.WriteLog($"[路径刷新] 刷新所有路径: {pathIds.Count}个, 可视化模式: {_visualizationMode}");
|
||||
LogManager.WriteLog($"[路径刷新] 刷新普通路径: {normalPathIds.Count}个, 模式: {_visualizationMode}");
|
||||
RequestViewRefresh();
|
||||
}
|
||||
}
|
||||
@ -873,10 +889,10 @@ namespace NavisworksTransport
|
||||
|
||||
LogManager.WriteLog($"[车辆参数] 更新车辆参数: 长={vehicleLength:F2}m, 宽={vehicleWidth:F2}m, 高={vehicleHeight:F2}m, 安全间隙={safetyMargin:F2}m");
|
||||
|
||||
// 车辆参数改变时刷新所有路径可视化
|
||||
// 车辆参数改变时刷新所有普通路径
|
||||
if (_visualizationMode == PathVisualizationMode.VehicleSpace)
|
||||
{
|
||||
RefreshAllPaths();
|
||||
RefreshNormalPaths();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 1. 清理现有的路径可视化,但保留网格可视化
|
||||
PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle", "grid_visualization_door");
|
||||
LogManager.WriteLog("[路径可视化] 已清理现有路径显示(保留网格可视化)");
|
||||
|
||||
|
||||
// 2. 如果有选中的路径,则显示该路径
|
||||
if (_selectedPathRoute != null && _selectedPathRoute.Points.Count > 0)
|
||||
{
|
||||
@ -200,6 +200,35 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
LogManager.WriteLog("[路径可视化] 没有选中的路径,仅清理显示");
|
||||
}
|
||||
|
||||
// 3. 恢复网格可视化(如果网格可视化已启用且当前路径有关联的GridMap)
|
||||
if (_pathPlanningManager?.IsAnyGridVisualizationEnabled == true)
|
||||
{
|
||||
// 检查当前路径是否有关联的GridMap
|
||||
var currentRoute = _pathPlanningManager.CurrentRoute;
|
||||
if (currentRoute?.AssociatedGridMap != null)
|
||||
{
|
||||
LogManager.WriteLog("[路径可视化] 检测到网格可视化已启用且当前路径有GridMap,恢复网格显示");
|
||||
|
||||
// 通过PathPlanningManager的RefreshGridVisualization方法恢复网格
|
||||
// 这会使用当前路径的AssociatedGridMap来重新渲染网格
|
||||
var refreshMethod = typeof(PathPlanningManager).GetMethod("RefreshGridVisualization",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
if (refreshMethod != null)
|
||||
{
|
||||
refreshMethod.Invoke(_pathPlanningManager, null);
|
||||
LogManager.WriteLog("[路径可视化] 网格可视化已恢复");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning("[路径可视化] 无法找到RefreshGridVisualization方法");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.WriteLog("[路径可视化] 当前路径没有关联的GridMap,跳过网格恢复");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -1112,9 +1141,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
if (isEditingPoint)
|
||||
{
|
||||
// 修改路径点模式 - 确认修改
|
||||
// 修改路径点模式 - 尝试确认修改
|
||||
success = _pathPlanningManager.ConfirmEditPoint();
|
||||
operationMessage = success ? "路径点修改已确认" : "路径点修改确认失败";
|
||||
if (success)
|
||||
{
|
||||
operationMessage = "路径点修改已确认";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 确认失败(可能没有预览点),执行取消操作以安全退出
|
||||
success = _pathPlanningManager.CancelEditPoint();
|
||||
operationMessage = success ? "已取消路径点修改" : "取消路径点修改失败";
|
||||
}
|
||||
LogManager.Info($"[UI-修改路径点] {operationMessage}");
|
||||
}
|
||||
else
|
||||
|
||||
@ -88,6 +88,8 @@ NavisworksTransport 帮助对话框 - 采用与主界面一致的Navisworks 2026
|
||||
Style="{StaticResource DialogContentTextStyle}"/>
|
||||
<TextBlock Text="• 路径编辑:添加、删除、调整路径点位置"
|
||||
Style="{StaticResource DialogContentTextStyle}"/>
|
||||
<TextBlock Text="• 焦点恢复:编辑路径点时如使用导航工具丢失焦点,按空格键恢复取点状态"
|
||||
Style="{StaticResource DialogContentTextStyle}"/>
|
||||
|
||||
<!-- 检测动画 -->
|
||||
<Label Content="4. 检测动画" Style="{StaticResource SubSectionHeaderStyle}"/>
|
||||
|
||||
@ -170,11 +170,11 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
|
||||
Margin="0,0,20,0"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="显示标准圆柱形连线"/>
|
||||
<RadioButton Content="车辆通行空间"
|
||||
<RadioButton Content="通行空间"
|
||||
GroupName="PathVisualizationMode"
|
||||
IsChecked="{Binding IsVehicleSpaceMode}"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="显示车辆通行空间(矩形通道)"/>
|
||||
ToolTip="显示通行空间(矩形通道)"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 车辆高度模式选择 -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user