网格点在设置时同步刷新

This commit is contained in:
tian 2025-09-14 21:24:51 +08:00
parent 62349099aa
commit 8946873e32
12 changed files with 673 additions and 44 deletions

View File

@ -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": [

View File

@ -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

View File

@ -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. 每次文档操作都有两个事件:
- 先清空ModelsCount=0
- 再加载新ModelsCount>0
2. 状态转换清晰:
- 无模型→无模型:初始清理
- 无模型→有模型:文档加载完成 ✅ 这是我们需要初始化的时机
- 有模型→无模型:文档关闭/切换 ✅ 这是我们需要清理的时机
3. 时间间隔很短事件成对出现间隔仅0.1秒左右

View File

@ -4,7 +4,7 @@
### [2025/09/14]
1. [x] (功能)增加两种路径连线方式1、宽度路径半透明膨胀直径10cm高立方体。2、和前面一样高度为车高加安全距离
1. [x] (功能)增加空间通道连线方式1、宽度路径半透明膨胀直径高度为车高加安全距离
### [2025/09/12]

View 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第一次打开文件**
- 事件#1Count=0状态保持无模型文档清空准备加载
- 事件#2Count=1从无模型→有模型文件加载完成
**场景2重新打开新文件**
- 事件#3Count=0从有模型→无模型旧文件被清空
- 事件#4Count=1从无模型→有模型新文件加载完成
**场景3关闭程序**
- 事件#5Count=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. 可能需要在某些管理器中区分"清理状态"和"销毁实例"
这个方案清晰地分离了不同场景的处理逻辑,避免了混淆,确保了稳定性。

View File

@ -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)
{

View File

@ -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}");
// 获取渲染插件

View File

@ -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
};
// 克隆所有路径点

View File

@ -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();
}
}

View File

@ -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

View File

@ -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}"/>

View File

@ -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>
<!-- 车辆高度模式选择 -->