修改了ClashDetective集成逻辑,运行结束汇总显示测试结果。

This commit is contained in:
tian 2025-07-21 14:15:43 +08:00
parent 82753855b9
commit 65712b675e
10 changed files with 671 additions and 416 deletions

View File

@ -5,7 +5,9 @@
"Bash(dotnet build:*)",
"WebFetch(domain:github.com)",
"WebFetch(domain:adndevblog.typepad.com)",
"Bash(.compile.bat)"
"Bash(.compile.bat)",
"Bash(rg:*)",
"Bash(findstr:*)"
],
"deny": []
}

View File

@ -3,13 +3,15 @@
## [0.1.9] - 2025-07-18
### 新增 🎉
- **TimeLiner 集成功能**:完整的 Navisworks TimeLiner 集成支持
- **TimeLiner 集成功能**:不完整的 Navisworks TimeLiner 集成支持
- 新增 `TimeLinerIntegrationManager` 类,实现运输任务与 TimeLiner 的无缝集成
- 动画播放时自动在 TimeLiner 中创建对应的运输任务
- 支持任务状态实时同步(播放中、暂停、停止、已完成)
- 任务显示名称包含车辆信息、时间戳和进度状态
### 技术突破 🔧
- **API 兼容性解决**:成功解决 Navisworks 2017 TimeLiner API 限制
- 发现并使用正确的 `TaskAddCopy()` 方法替代只读的 `Tasks.Add()`
- 实现多重 fallback 机制:直接添加 → 插入副本 → 层次结构管理
@ -20,6 +22,7 @@
- 两个系统独立运行,互不干扰,确保稳定性
### 集成组件 📦
- **PathAnimationManager 增强**
- 添加 TimeLiner 相关公共属性:`IsTimeLinerAvailable`、`CurrentState`、`CurrentTaskId`、`TimeLinerManager`
- 动画播放时自动创建 TimeLiner 任务
@ -32,12 +35,14 @@
- 事件系统:`StatusChanged`、`TaskCreated` 事件通知
### 用户体验 ✨
- **无缝集成**原有动画功能完全保持不变TimeLiner 功能作为增强特性
- **可视化管理**:用户可在 TimeLiner 面板中查看所有运输任务
- **状态同步**:任务名称实时显示动画状态和进度百分比
- **错误恢复**TimeLiner 功能异常时自动降级到基础动画模式
### 技术细节 📋
- **API 方法**
- `_documentTimeliner.TaskAddCopy(task)` - 添加任务副本
- `_documentTimeliner.TaskInsertCopy(index, task)` - 插入任务副本
@ -52,6 +57,7 @@
- 异常情况下的资源自动释放
### 验证结果 ✅
- ✅ TimeLiner 窗口成功显示运输任务:"运输任务SHINYSTE13_运输_131040"
- ✅ 任务创建使用 `TaskAddCopy` 方法成功,任务数量从 0 增加到 1
- ✅ 车辆关联正确:关联了 SHINYSTE13 车辆模型
@ -60,6 +66,7 @@
- ✅ 编译成功,在 Navisworks 2017 中稳定运行
### 代码优化 🛠️
- **日志系统简化**:移除冗余的调试日志,保留关键信息
- **错误处理优化**:统一异常处理逻辑,提高代码可读性
- **性能改进**:减少不必要的 API 调用和状态检查
@ -69,6 +76,7 @@
### 进一步修复对象生命周期和选择清除问题
#### 深度修复
- **选择清除安全性**:创建了`SafelyClearSelection()`方法,完全安全地处理选择清除
- 新增`IsApplicationDocumentValid()`方法检查Application和Document对象有效性
- 替换所有直接的`CurrentSelection.Clear()`调用为安全方法调用
@ -79,6 +87,7 @@
- 防止定时器继续尝试访问已释放的对象
#### 技术增强
- **多层防护机制**
- `IsApplicationDocumentValid()`:检查核心对象有效性
- `SafelyClearSelection()`:安全的选择清除操作
@ -93,6 +102,7 @@
- 集中化的错误处理和日志记录
#### 解决的问题
- ✅ "Object has been Disposed" 在清除选择时的错误
- ✅ 定时器继续访问已释放对象的问题
- ✅ 多重异常处理导致的日志混乱
@ -103,6 +113,7 @@
## [0.1.11] - 2025-06-19
### 修复
- 🔧 恢复进入路径编辑模式后控制面板自动关闭功能
- 在v0.1.10添加全局异常处理时意外删除了此功能
- 现在进入路径编辑模式成功后,控制面板会自动关闭
@ -112,18 +123,21 @@
- 自动关闭确保焦点回到Navisworks主界面
### 改进
- 📝 更新用户提示信息
- 明确告知用户控制面板已关闭,避免困惑
- 提醒用户完成路径编辑后需要重新打开插件面板退出编辑模式
- 保持原有的操作流程指导
### 用户体验
- **操作流程**:选择通道 → 点击进入编辑 → 面板自动关闭 → 3D点击添加路径点 → 重新打开插件 → 退出编辑
- **交互优化**确保用户能够无障碍地在3D环境中进行路径规划操作
## [0.1.10] - 2025-06-19
### 新增
- 🛡️ 全局异常处理机制,彻底防止程序崩溃
- 新增GlobalExceptionHandler工具类捕获AppDomain和Thread级别的未处理异常
- 实现SafeExecute方法为所有关键操作提供安全包装
@ -134,6 +148,7 @@
- 尝试恢复程序到安全状态
### 改进
- 📝 用户友好的错误提示
- 技术详情与用户信息分离显示
- 不同级别的错误提示(错误对话框 vs 简单提示)
@ -144,6 +159,7 @@
- 记录是否为终止性异常
### 技术细节
- 修改MainPlugin.Execute方法使用GlobalExceptionHandler.SafeExecute包装
- 为ShowCategorySelectionDialog方法添加异常保护
- 为所有按钮点击事件添加SafeExecute包装
@ -155,6 +171,7 @@
### 修复对象生命周期管理问题
#### 主要修复
- **Object has been Disposed 错误**:修复了点击监听和高亮功能中的对象释放错误
- 添加了`IsModelItemValid()`方法检查ModelItem对象是否有效
- 在高亮功能中过滤无效的ModelItem对象
@ -165,6 +182,7 @@
- 简化了选择清除的错误处理机制
#### 技术改进
- **对象有效性检查**
- 新增`IsModelItemValid()`私有方法
- 通过访问基本属性检测对象是否已被释放
@ -179,6 +197,7 @@
- 添加有效对象计数和状态反馈
#### 解决的具体问题
- ✅ "Argument 'path' has been Disposed" 错误
- ✅ "Object has been Disposed (null)" 重复错误
- ✅ 点击监听过程中的对象释放异常
@ -191,12 +210,14 @@
### 增加分层可见性控制功能
#### 主要变更
- **修复可见性逻辑缺陷**:解决了隐藏非物流项目时,具有物流属性的项目也被错误隐藏的问题
- **改进用户界面**:将两个独立按钮("隐藏非物流分类项目"和"显示所有项目")替换为单个复选框"只显示物流分类项目"
- **增强递归检查**:添加了`HasLogisticsAttributesRecursive`方法,确保父节点包含具有物流属性的子节点时不会被隐藏
- **优化用户体验**:复选框状态实时反映当前可见性状态,操作失败时自动回滚状态
#### 技术成果
- **核心算法改进**
- 新增递归检查方法,避免误隐藏包含物流子项的父项
- 修复了 `item.Children.Count` 方法组调用问题,改为 `item.Children.Count()`
@ -208,6 +229,7 @@
- 操作失败时的状态回滚机制
#### 验证结果
- ✅ 设置3个模型为物流分类后勾选"只显示物流分类项目"复选框,成功隐藏非物流项目同时保持物流项目可见
- ✅ 取消勾选复选框,所有项目正确恢复显示
- ✅ 状态标签准确显示操作结果和隐藏项目数量
@ -220,12 +242,14 @@
### 增加物流类别属性功能
#### 主要变更
- **实现物流属性分类系统**支持8种物流元素类型门、电梯、楼梯、通道、障碍物、装卸区、停车位、检查点
- **集成COM API功能**通过Navisworks COM API实现自定义属性的添加和管理
- **优化代码架构**将LogisticsCategories.cs功能整合到CategoryAttributeManager.cs中避免重复定义
- **修复API兼容性问题**解决了多个Navisworks 2017 API兼容性问题
#### 技术成果
- **COM API集成**
- 正确实现了ComApiBridge.State的使用
- 修复了ObjectFactory的调用方式
@ -242,6 +266,7 @@
- 优化了错误处理和调试信息输出
#### 验证结果
- ✅ 成功为选定模型项添加物流属性属性在Navisworks属性面板中正确显示
- ✅ 8种物流元素类型的按钮功能正常属性设置准确
- ✅ COM API调用稳定无内存泄漏或崩溃问题
@ -252,6 +277,7 @@
## 版本 [0.1.3] - 2024-01-XX
### 修复
- **兼容性修复**: 修复C# 7.3兼容性问题移除了nullable引用类型语法
- **API兼容性**: 修复Navisworks 2017 API兼容性问题
- 替换了不存在的`View.RequestSavedViewpoint()`方法
@ -265,6 +291,7 @@
- **射线投射算法**: 完善了射线与包围盒交点计算的错误处理
### 技术改进
- **错误处理**: 增强了所有射线投射相关方法的错误处理和日志记录
- **后备方案**: 在精确坐标获取失败时提供包围盒中心点作为后备方案
- **日志优化**: 改进了调试日志的详细程度和格式
@ -272,15 +299,18 @@
## 技术债务和改进计划
### 当前已知问题
- 暂无已知的功能性问题
### 已完成功能 ✅
1. ✅ **TimeLiner 集成**:已实现完整的 TimeLiner 集成功能v0.1.9
- 运输任务自动创建和管理
- 动画状态实时同步
- 完善的错误处理和降级机制
### 下一步开发计划
1. **路径规划功能**:实现 A* 算法的 3D 路径规划
2. **动态碰撞检测增强**:进一步集成 Clash Detective 功能
3. **动画和可视化优化**:添加更多路径动画效果和碰撞高亮显示
@ -291,6 +321,7 @@
- 任务导入导出功能
### 性能优化目标
- 大型模型的处理性能优化
- 异步操作的用户界面响应性改进
- 内存使用优化和资源清理机制完善
@ -298,6 +329,7 @@
## [0.1.4] - 2024-01-XX
### 修复
- **点击监听问题**: 修复鼠标点击没有效果的问题
- 添加了点击状态跟踪机制,避免重复处理同一选择
- 增加最小点击间隔500ms防止误触
@ -319,6 +351,7 @@
- 实现地图中选中点的高亮重绘
### 技术改进
- **状态管理**: 增强点击状态跟踪和管理
- 添加_lastProcessedItem和_lastProcessedTime字段
- 实现MinClickInterval常量控制最小点击间隔
@ -329,4 +362,4 @@
- **用户体验**: 优化交互反馈
- 改进状态消息显示选中通道数量
- 在状态栏显示详细的点信息
- 清除无效选择的自动处理
- 清除无效选择的自动处理

View File

@ -15,11 +15,13 @@ NavisworksTransport is a Navisworks 2017 plugin (v0.1.8) for logistics path plan
## Architecture Overview
### Core Plugin Structure
- **MainPlugin.cs**: Primary AddInPlugin entry point with ribbon UI
- **PathClickToolPlugin.cs**: ToolPlugin for 3D mouse interaction
- **PathPointRenderPlugin.cs**: RenderPlugin for 3D visualization
### Manager Components
- **PathPlanningManager.cs**: Central path planning and route management logic
- **PathAnimationManager.cs**: TimeLiner integration for object movement animation
- **CoordinateConverter.cs**: 2D map overlay to 3D world coordinate conversion
@ -28,64 +30,77 @@ NavisworksTransport is a Navisworks 2017 plugin (v0.1.8) for logistics path plan
- **ModelSplitterManager.cs**: Model layer separation and export functionality
### Data and Utilities
- **PathPlanningModels.cs**: Core data structures (PathEditState, PathRoute, PathPoint)
- **PathDataManager.cs**: Serialization and persistence using Newtonsoft.Json
- **GeometryExtractor.cs**: 3D geometry analysis and bounding box calculations
- **LogManager.cs**: Centralized logging with global exception handling
### UI Components
- **LogisticsPropertyEditDialog.cs**: Property editing interface
- **ModelSplitterDialog.cs**: Model splitting configuration UI
## Key Technical Details
### Navisworks API Integration
- Uses dual API approach: Native API (`Autodesk.Navisworks.Api`) + COM API (`Autodesk.Navisworks.ComApi`)
- COM API required for attribute persistence and TimeLiner operations
- Plugin types: AddInPlugin (main), ToolPlugin (interaction), RenderPlugin (visualization)
### Exception Handling
Global exception handling implemented in MainPlugin with:
- AppDomain.CurrentDomain.UnhandledException
- Application.ThreadException
- Automatic recovery and user-friendly error reporting
### Coordinate Systems
- Supports 2D map overlay on 3D models with dynamic zoom/pan
- Margin-based boundary calculations for click precision
- Transform chains for coordinate conversion between spaces
### Logistics Categories
Eight predefined logistics element types:
- 门 (Doors), 电梯 (Elevators), 楼梯 (Stairs), 通道 (Channels)
- 障碍物 (Obstacles), 装卸区 (Loading Zones), 停车区 (Parking), 检查点 (Checkpoints)
## Development Guidelines
### Language Preference
- **使用中文进行所有交流和代码注释**
- 与用户交流时优先使用中文
- 代码注释和文档说明使用中文
### File Organization
- Core managers handle specific functionality areas
- Models file contains shared data structures
- UI dialogs are separate form classes
- Utilities (logging, geometry, data) are standalone classes
### Plugin Registration Pattern
```csharp
[Plugin("NavisworksTransport.PluginName", "YourDeveloperID")]
[AddInPlugin(AddInLocation.AddIn)]
```
### Error Handling Best Practices
- Use LogManager for consistent logging
- Implement try-catch blocks around Navisworks API calls
- Provide meaningful error messages to users
- Use COM API error codes for troubleshooting
### Dependencies
- **System.Windows.Forms**: UI dialogs and controls
- **System.Drawing**: Graphics and coordinate operations
@ -94,4 +109,4 @@ Eight predefined logistics element types:
- Manual testing required through Navisworks Manage 2017
- Plugin automatically deploys to Navisworks plugin directory during build
- Restart Navisworks after compilation to load new plugin version
- Use LogManager output for debugging and troubleshooting
- Use LogManager output for debugging and troubleshooting

View File

@ -7,16 +7,19 @@
## 功能特性
### 1. 自动碰撞检测
- **实时检测**: 动画播放过程中实时检测碰撞
- **智能回退**: 当 Clash Detective 不可用时,自动切换到简化碰撞检测
- **双重模式**: 支持精确几何碰撞检测和简化包围盒检测
### 2. Clash Detective 集成
- **自动发现**: 自动检测并连接到 Clash Detective 插件
- **测试管理**: 创建和管理动态碰撞测试
- **结果同步**: 碰撞结果同步显示到 Clash Detective 窗口
### 3. 可视化高亮
- **碰撞高亮**: 自动高亮碰撞对象(红色显示)
- **实时更新**: 动画过程中实时更新碰撞状态
- **清理机制**: 动画结束后自动清理临时高亮
@ -24,21 +27,25 @@
## 使用方法
### 1. 启动插件
1. 打开 Navisworks Manage 2017
2. 加载包含物流路径的模型
3. 从菜单栏选择 "附加模块" > "Transport Plugin"
### 2. 设置动画
1. 在控制面板中选择要动画的车辆对象
2. 选择预定义的路径或创建新路径
3. 设置动画参数(时长、速度等)
### 3. 启用碰撞检测
1. 在动画控制面板中确保"启用碰撞检测"选项已勾选
2. 可选择"高亮显示碰撞"以可视化碰撞结果
3. 点击"播放动画"开始带碰撞检测的动画
### 4. 测试集成功能
1. 点击"测试Clash Detective集成"按钮
2. 系统会自动运行完整的集成测试
3. 查看测试结果和日志信息
@ -48,25 +55,28 @@
### 核心组件
#### 1. ClashDetectiveIntegration
- **功能**: 主要的集成管理器
- **位置**: `src/ClashDetectiveIntegration.cs`
- **职责**:
- **职责**:
- 管理与 Clash Detective 的连接
- 执行碰撞检测逻辑
- 处理结果同步
#### 2. PathAnimationManager
- **功能**: 动画管理器(已升级)
- **位置**: `src/PathAnimationManager.cs`
- **职责**:
- **职责**:
- 集成碰撞检测到动画循环
- 管理碰撞检测事件
- 处理高亮显示
#### 3. ClashDetectiveIntegrationTest
- **功能**: 集成测试管理器
- **位置**: `src/ClashDetectiveIntegrationTest.cs`
- **职责**:
- **职责**:
- 验证集成功能
- 性能测试
- 错误诊断
@ -84,6 +94,7 @@
### 主要方法
#### ClashDetectiveIntegration.Instance
```csharp
// 初始化集成
void Initialize()
@ -99,6 +110,7 @@ void Cleanup()
```
#### 事件处理
```csharp
// 碰撞检测事件
event EventHandler<CollisionDetectedEventArgs> CollisionDetected;
@ -112,6 +124,7 @@ public class CollisionDetectedEventArgs : EventArgs
```
### 碰撞结果数据结构
```csharp
public class CollisionResult
{
@ -130,11 +143,13 @@ public class CollisionResult
## 配置选项
### 碰撞检测参数
- **容差**: 默认 0.01 米1厘米
- **测试类型**: 硬碰撞检测
- **检测频率**: 50ms 间隔20 FPS
### 高亮设置
- **碰撞颜色**: 红色
- **非碰撞对象**: 保持原色
- **清理时机**: 动画结束或用户停止
@ -144,22 +159,28 @@ public class CollisionResult
### 常见问题
#### 1. Clash Detective 未找到
**症状**: 系统提示"未找到Clash Detective插件"
**解决**:
**解决**:
- 确保 Clash Detective 已正确安装
- 检查 Navisworks 版本兼容性
- 查看日志文件获取详细信息
#### 2. 碰撞检测不工作
**症状**: 动画播放但无碰撞检测结果
**解决**:
**解决**:
- 确保模型包含几何体
- 检查动画对象是否有效
- 使用测试按钮验证集成
#### 3. 高亮显示异常
**症状**: 碰撞对象未正确高亮
**解决**:
**解决**:
- 重启动画播放
- 检查对象选择是否正确
- 清理临时材质覆盖
@ -167,12 +188,15 @@ public class CollisionResult
### 调试方法
#### 1. 查看日志
日志文件位置: `%USERPROFILE%\Documents\NavisworksTransport\Logs\`
#### 2. 运行测试
使用"测试Clash Detective集成"按钮进行全面测试
#### 3. 检查系统状态
```csharp
// 检查COM API状态
var state = ComApiBridge.ComApiBridge.State;
@ -184,11 +208,13 @@ var pluginCount = state.Plugins().Count;
## 性能优化
### 建议设置
- **大模型**: 增加碰撞检测间隔到 100ms
- **复杂路径**: 减少路径点数量
- **多对象**: 使用批处理检测
### 内存管理
- 动画结束后自动清理资源
- 定期重置临时材质
- 避免长时间运行动画
@ -196,12 +222,14 @@ var pluginCount = state.Plugins().Count;
## 更新日志
### v0.1.8 (当前版本)
- ✅ 新增 Clash Detective 集成功能
- ✅ 实现实时碰撞检测
- ✅ 添加自动化测试框架
- ✅ 优化性能和错误处理
### 计划功能
- 🔄 支持自定义碰撞规则
- 🔄 批量路径碰撞分析
- 🔄 碰撞报告导出
@ -210,10 +238,11 @@ var pluginCount = state.Plugins().Count;
## 技术支持
如有问题请查看:
1. 日志文件: `%USERPROFILE%\Documents\NavisworksTransport\Logs\`
2. 测试结果: 使用集成测试按钮
3. 开发文档: `doc/design/` 目录
---
*本文档随插件版本更新,请查看最新版本获取准确信息。*
*本文档随插件版本更新,请查看最新版本获取准确信息。*

View File

@ -10,9 +10,7 @@
我们的集成采用了**双重架构**
```
动画管理器 -> ClashDetectiveIntegration -> .NET API + COM API -> Clash Detective窗口
```
- **动画播放时**: 自动检测碰撞并创建测试结果
- **测试按钮**: 验证集成功能并强制显示结果
@ -21,16 +19,19 @@
### 2. 集成的具体表现
#### A. 测试创建
- ✅ 自动创建名为 "动态运输路径碰撞检测" 的测试
- ✅ 测试会出现在Clash Detective的测试列表中
- ✅ 测试参数硬碰撞、1cm容差
#### B. 结果显示
- ✅ 碰撞结果会添加到测试中
- ✅ 3D视图中高亮显示碰撞对象红色
- ✅ 日志记录详细的检测信息
#### C. 窗口同步
- ✅ 自动刷新Clash Detective界面
- ✅ 运行所有测试以触发更新
- ✅ 强制重绘3D视图
@ -38,18 +39,21 @@
## 如何查看集成效果
### 方法1检查测试列表
1. 打开 Clash Detective 窗口
2. 查看左侧的测试列表
3. 寻找 "动态运输路径碰撞检测" 项
4. 点击该测试查看详细信息
### 方法2查看测试结果
1. 在测试列表中选择我们的测试
2. 查看右侧的结果面板
3. 结果会显示碰撞的对象名称和状态
4. 双击结果可以定位到3D视图
### 方法3监控日志输出
1. 查看日志文件:`%USERPROFILE%\Documents\NavisworksTransport\Logs\`
2. 搜索关键词:
- "Clash Detective"
@ -58,6 +62,7 @@
- "同步结果到Clash Detective"
### 方法4使用新的测试按钮
1. 点击 "测试Clash Detective集成" 按钮
2. 查看弹出的详细信息对话框
3. 按照提示检查Clash Detective窗口
@ -65,34 +70,43 @@
## 可能的显示问题及解决方案
### 问题1测试列表中没有看到我们的测试
**可能原因**
- Clash Detective窗口未刷新
- 测试创建失败
- 权限问题
**解决方案**
1. 关闭并重新打开Clash Detective窗口
2. 点击 "测试Clash Detective集成" 按钮强制刷新
3. 查看日志了解详细错误信息
### 问题2测试存在但无结果
**可能原因**
- 动画对象与其他对象无碰撞
- 选择集设置不正确
- 测试参数过于严格
**解决方案**
1. 确保动画对象与其他对象有重叠
2. 调整碰撞容差当前为1cm
3. 使用测试按钮执行强制检测
### 问题33D视图中看不到高亮
**可能原因**
- 高亮颜色与背景相似
- 临时材质被清除
- 视图渲染问题
**解决方案**
1. 改变视图背景颜色
2. 重新运行动画
3. 检查日志中的高亮信息
@ -100,6 +114,7 @@
## 调试和验证步骤
### 1. 基础验证
```
1. 加载包含多个对象的模型
2. 启动插件并打开Clash Detective
@ -108,6 +123,7 @@
```
### 2. 动画验证
```
1. 设置动画对象和路径
2. 启用"碰撞检测"选项
@ -117,6 +133,7 @@
```
### 3. 日志分析
```
1. 打开日志文件
2. 搜索集成相关信息
@ -126,14 +143,16 @@
## 集成效果的预期表现
### 正常情况下您应该看到:
### 正常情况下您应该看到
1. **测试列表**:出现 "动态运输路径碰撞检测" 项
2. **结果面板**:显示检测到的碰撞结果
3. **3D视图**:碰撞对象显示红色高亮
4. **日志信息**:记录详细的检测过程
5. **状态报告**:测试按钮提供的详细信息
### 如果仍然看不到效果:
### 如果仍然看不到效果
1. 检查Navisworks版本是否为2017
2. 确认Clash Detective插件已正确安装
3. 验证模型中是否有足够的几何对象
@ -142,16 +161,18 @@
## 技术细节
### 我们的集成方式:
### 我们的集成方式
- 使用 .NET API 创建和管理碰撞测试
- 使用 COM API 访问底层功能
- 通过多种方式刷新窗口显示
- 提供详细的状态监控和日志记录
### 与标准用法的区别:
### 与标准用法的区别
- 动态创建测试而非预定义
- 实时更新结果而非批处理
- 集成到动画循环中而非独立运行
- 提供自动化的可视化反馈
这种集成方式确保了动画播放过程中的实时碰撞检测同时保持与Clash Detective原生界面的兼容性。
这种集成方式确保了动画播放过程中的实时碰撞检测同时保持与Clash Detective原生界面的兼容性。

View File

@ -3,12 +3,14 @@
## 功能模块详细需求
### Navisworks插件开发和安装部署
| 次级功能点 | 功能点描述 |
|------------|------------|
| 插件二次开发 | 基于Navisworks 2017 SDK进行二次开发用插件的方式集成到Navisworks的菜单中。 |
| 一键安装部署 | 支持Windows 7环境安装程序自动识别Navisworks安装路径并安装插件自动修改配置和菜单。 |
### 通道选择及路径点规划模块
| 次级功能点 | 功能点描述 |
|------------|------------|
| 通道选择 | 支持选择通道模型功能,可通过选择树或三维视图点选的方式,选择模型并制定为通道类型。 |
@ -17,12 +19,14 @@
| 路径点自动贴合 | 路径点要自动贴合通道模型表面,路径点之间通过直线进行联通。 |
### 物流"类别"设置功能模块
| 次级功能点 | 功能点描述 |
|------------|------------|
| 类别设置 | 支持模型属性页面新增"物流属性"类别。 |
| 属性设置 | 1、支持通过选择树和三维视图选择的方式选择物流路径相关的元素(如门、电梯、楼梯、通道等),设置为特定的物流分类,并支持类型、可通行性、速度限制、宽度限制、优先级等属性;<br>2、支持在Navisworks中进行识别和筛选支持物流分类属性的添加、编辑和清除。 |
### 层级创建功能模块
| 次级功能点 | 功能点描述 |
|------------|------------|
| 层级显示 | 支持自动隐藏或淡化非关键层,以便专注于物流路径相关的层级。 |
@ -30,6 +34,7 @@
| 路径时间标签 | 支持路径时间标签设置,以预估运输时间。 |
### 交互式导航功能模块
| 次级功能点 | 功能点描述 |
|------------|------------|
| 交互式导航控件 | 创建交互式导航控件,允许用户选择不同的起点和终点,动态生成路径。 |
@ -37,6 +42,7 @@
| 输出格式 | 支持路径规划结果结构化文件输出XML/JSON/CSV结果文件能够导入DELMIA。 |
### 碰撞检测功能模块
| 次级功能点 | 功能点描述 |
|------------|------------|
| 动画生成和播放 | 1、指定物流组件待载转运车选择路径支持生成动画仿真物流组件的运动过程<br>2、支持设置动画时长支持动画的播放、停止和步进播放。 |
@ -45,8 +51,10 @@
| 路径规划分析 | 对多个路径运行的碰撞结果,进行分析,生成路径分析报告,选择最佳路径,提供调整建议。 |
## 技术指标要求
- 可实现不小于10种尺寸规格的带转载运车的路径规划
## 运行环境
- 操作系统Windows 7
- 软件环境Navisworks 2017
- 软件环境Navisworks 2017

View File

@ -287,62 +287,417 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 创建碰撞快照(仅在手动测试时使用
/// <summary>
/// 创建碰撞快照(动画结束后一次性更新结果
/// </summary>
public void CreateCollisionSnapshot(List<CollisionResult> results)
{
try
{
if (_documentClash == null || results.Count == 0)
if (_documentClash == null)
return;
var firstCollision = results[0];
if (firstCollision.Item1 != null && firstCollision.Item2 != null)
// 缓存结果,等动画结束后统一处理
CacheCollisionResults(results);
}
catch (Exception ex)
{
LogManager.Error($"创建实时碰撞快照失败: {ex.Message}");
}
}
private List<CollisionResult> _cachedResults = new List<CollisionResult>();
/// <summary>
/// 缓存碰撞结果
/// </summary>
private void CacheCollisionResults(List<CollisionResult> results)
{
if (results != null && results.Count > 0)
{
_cachedResults.AddRange(results);
}
}
/// <summary>
/// 动画结束后创建最终碰撞结果汇总 - 同步安全版本
/// </summary>
public void CreateFinalCollisionSummary()
{
try
{
LogManager.Info("=== 开始创建最终碰撞结果汇总(同步模式) ===");
LogManager.Info($"步骤1: 检查前置条件 - _documentClash是否存在: {_documentClash != null}");
LogManager.Info($"步骤1: 检查前置条件 - 缓存结果数量: {_cachedResults.Count}");
if (_documentClash == null || _cachedResults.Count == 0)
{
// 检查对象是否仍然有效
if (IsModelItemValid(firstCollision.Item1) && IsModelItemValid(firstCollision.Item2))
LogManager.Info("前置条件不满足,退出创建");
return;
}
LogManager.Info($"步骤2: 开始处理 {_cachedResults.Count} 个碰撞结果");
// 去重处理
LogManager.Info("步骤3: 开始去重处理...");
var uniqueCollisions = _cachedResults
.GroupBy(r => new { r.Item1, r.Item2 })
.Select(g => g.First())
.ToList();
LogManager.Info($"步骤3: 去重后碰撞数量: {uniqueCollisions.Count}");
if (!uniqueCollisions.Any())
{
LogManager.Info("去重后无碰撞,退出创建");
return;
}
// 创建最终汇总测试
var testName = $"物流路径碰撞汇总_{DateTime.Now:yyyyMMdd_HHmmss}";
LogManager.Info($"步骤4: 创建测试对象 - 测试名称: {testName}");
var summaryTest = new ClashTest();
summaryTest.DisplayName = testName;
summaryTest.TestType = ClashTestType.Hard;
summaryTest.Tolerance = 0.01;
LogManager.Info("步骤5: 构建选择集A - 动画对象");
var selectionA = new ModelItemCollection();
var animatedObjects = uniqueCollisions.Select(r => r.Item1).Distinct();
int validAnimatedCount = 0;
foreach (var obj in animatedObjects)
{
if (IsModelItemValid(obj))
{
// 创建一个快照测试来展示实际碰撞
var timestamp = DateTime.Now.ToString("HH:mm:ss");
var testName = $"动画碰撞快照_{timestamp}";
selectionA.Add(obj);
validAnimatedCount++;
}
}
LogManager.Info($"步骤5: 选择集A - 有效对象数量: {validAnimatedCount}");
LogManager.Info("步骤6: 构建选择集B - 碰撞对象");
var selectionB = new ModelItemCollection();
var collidingObjects = uniqueCollisions.Select(r => r.Item2).Distinct();
int validCollidingCount = 0;
foreach (var obj in collidingObjects)
{
if (IsModelItemValid(obj))
{
selectionB.Add(obj);
validCollidingCount++;
}
}
LogManager.Info($"步骤6: 选择集B - 有效对象数量: {validCollidingCount}");
// 验证选择集是否为空
if (selectionA.Count == 0 || selectionB.Count == 0)
{
LogManager.Error("选择集为空,无法创建测试");
return;
}
summaryTest.SelectionA.Selection.CopyFrom(selectionA);
summaryTest.SelectionB.Selection.CopyFrom(selectionB);
LogManager.Info($"步骤7: 选择集设置完成 - A:{selectionA.Count}, B:{selectionB.Count}");
LogManager.Info("步骤8: 直接添加测试到文档");
try
{
// 直接同步添加测试
_documentClash.TestsData.TestsAddCopy(summaryTest);
LogManager.Info("步骤8: 测试添加完成");
// 立即重新获取测试引用
var addedTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == testName) as ClashTest;
if (addedTest != null)
{
LogManager.Info($"找到测试对象: {addedTest.DisplayName}, GUID: {addedTest.Guid}");
var snapshotTest = new ClashTest();
snapshotTest.DisplayName = testName;
snapshotTest.TestType = ClashTestType.Hard;
snapshotTest.Tolerance = 0.01;
// 立即运行测试
_documentClash.TestsData.TestsRunTest(addedTest);
LogManager.Info($"测试运行完成: {testName}, 找到 {addedTest.Children.Count} 个碰撞");
var selectionA = new ModelItemCollection();
selectionA.Add(firstCollision.Item1);
snapshotTest.SelectionA.Selection.CopyFrom(selectionA);
var selectionB = new ModelItemCollection();
selectionB.Add(firstCollision.Item2);
snapshotTest.SelectionB.Selection.CopyFrom(selectionB);
// 添加并运行测试
_documentClash.TestsData.TestsAddCopy(snapshotTest);
// 重新获取并运行测试
var addedTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == testName);
if (addedTest is ClashTest runTest)
{
_documentClash.TestsData.TestsRunTest(runTest);
LogManager.Info($"已创建并运行碰撞快照: {testName},展示 {firstCollision.Item1.DisplayName} <-> {firstCollision.Item2.DisplayName},结果数量: {runTest.Children.Count}");
}
// 强制刷新
RefreshClashDetectiveUI();
}
else
{
LogManager.Warning("碰撞对象已被释放,跳过测试创建");
LogManager.Error("未找到添加的测试对象");
}
}
catch (Exception ex)
{
LogManager.Error($"步骤8: 添加或运行测试失败 - {ex.GetType().Name}: {ex.Message}");
LogManager.Error($"详细错误: {ex.StackTrace}");
// 尝试恢复 - 重新初始化
LogManager.Info("尝试重新初始化Clash Detective...");
Initialize();
try
{
_documentClash.TestsData.TestsAddCopy(summaryTest);
var addedTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == testName) as ClashTest;
if (addedTest != null)
{
_documentClash.TestsData.TestsRunTest(addedTest);
LogManager.Info($"重试成功: {testName}");
}
}
catch (Exception retryEx)
{
LogManager.Error($"重试也失败: {retryEx.Message}");
}
}
// 清空缓存
_cachedResults.Clear();
LogManager.Info("=== 最终碰撞结果汇总创建完成 ===");
}
catch (Exception ex)
{
LogManager.Error($"创建最终碰撞汇总失败 - {ex.GetType().Name}: {ex.Message}");
LogManager.Error($"创建最终碰撞汇总失败 - 堆栈跟踪: {ex.StackTrace}");
}
}
/// <summary>
/// 安全运行汇总测试
/// </summary>
private void RunSummaryTestSafely(string testName)
{
try
{
LogManager.Info("=== 开始安全运行汇总测试 ===");
if (Application.ActiveDocument == null)
{
LogManager.Error("文档已失效");
return;
}
var docClash = Application.ActiveDocument.GetClash();
if (docClash == null || docClash.TestsData == null)
{
LogManager.Error("Clash数据不可用");
return;
}
var tests = docClash.TestsData.Tests;
LogManager.Info($"文档中测试总数: {tests.Count}");
// 重新获取测试
var addedTest = tests.FirstOrDefault(t => t.DisplayName == testName) as ClashTest;
if (addedTest != null)
{
LogManager.Info($"找到测试对象: {addedTest.DisplayName}, GUID: {addedTest.Guid}");
try
{
// 运行测试
docClash.TestsData.TestsRunTest(addedTest);
LogManager.Info($"测试运行完成: {testName}");
// 强制刷新UI
RefreshClashDetectiveUI();
LogManager.Info("=== 最终碰撞结果汇总完成 ===");
}
catch (Exception runEx)
{
LogManager.Error($"运行测试失败: {runEx.Message}");
// 尝试异步运行
RunTestAsync(docClash, addedTest);
}
}
else
{
LogManager.Error("未找到添加的测试对象");
}
}
catch (Exception ex)
{
LogManager.Error($"安全运行汇总测试失败: {ex.Message}");
}
}
/// <summary>
/// 直接运行测试(回退方案)
/// </summary>
private void RunSummaryTestDirectly(ClashTest test, string testName)
{
try
{
_documentClash.TestsData.TestsAddCopy(test);
var addedTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == testName) as ClashTest;
if (addedTest != null)
{
try
{
_documentClash.TestsData.TestsRunTest(addedTest);
LogManager.Info($"直接运行测试完成: {testName}");
}
catch
{
LogManager.Warning("直接运行测试失败,跳过");
}
}
}
catch (Exception ex)
{
LogManager.Error($"创建碰撞快照失败: {ex.Message}");
LogManager.Error($"直接运行汇总测试失败: {ex.Message}");
}
}
/// <summary>
/// 异步运行测试
/// </summary>
private void RunTestAsync(DocumentClash docClash, ClashTest test)
{
System.Threading.Tasks.Task.Run(() =>
{
try
{
docClash.TestsData.TestsRunTest(test);
LogManager.Info($"异步运行测试完成: {test.DisplayName}");
}
catch (Exception ex)
{
LogManager.Error($"异步运行测试失败: {ex.Message}");
}
});
}
/// <summary>
/// 刷新Clash Detective UI
/// </summary>
private void RefreshClashDetectiveUI()
{
try
{
// 强制重绘视图
var doc = Application.ActiveDocument;
if (doc?.ActiveView != null)
{
doc.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
}
LogManager.Info("Clash Detective UI已刷新");
}
catch (Exception ex)
{
LogManager.Error($"刷新Clash Detective UI失败: {ex.Message}");
}
}
/// <summary>
/// 更新现有测试的选择集
/// </summary>
private void UpdateExistingTest(ClashTest existingTest, List<CollisionResult> validCollisions)
{
try
{
if (existingTest == null || !validCollisions.Any())
return;
// 重新构建选择集
var selectionA = new ModelItemCollection();
selectionA.Add(validCollisions[0].Item1); // 动画对象
existingTest.SelectionA.Selection.CopyFrom(selectionA);
var selectionB = new ModelItemCollection();
foreach (var collision in validCollisions)
{
if (!selectionB.Contains(collision.Item2))
{
selectionB.Add(collision.Item2);
}
}
existingTest.SelectionB.Selection.CopyFrom(selectionB);
// 运行测试以更新结果
System.Threading.Tasks.Task.Run(() =>
{
try
{
_documentClash.TestsData.TestsRunTest(existingTest);
LogManager.Info($"更新动画碰撞测试: {validCollisions.Count} 个碰撞对象");
}
catch (Exception ex)
{
LogManager.Error($"更新测试失败: {ex.Message}");
}
});
}
catch (Exception ex)
{
LogManager.Error($"更新现有测试失败: {ex.Message}");
}
}
/// <summary>
/// 创建新的动画碰撞测试
/// </summary>
private void CreateNewAnimationTest(string testName, List<CollisionResult> validCollisions)
{
try
{
if (!validCollisions.Any())
return;
var snapshotTest = new ClashTest();
snapshotTest.DisplayName = testName;
snapshotTest.TestType = ClashTestType.Hard;
snapshotTest.Tolerance = 0.01;
// 设置选择集 - 动画对象
var selectionA = new ModelItemCollection();
selectionA.Add(validCollisions[0].Item1);
snapshotTest.SelectionA.Selection.CopyFrom(selectionA);
// 设置选择集B - 所有碰撞对象
var selectionB = new ModelItemCollection();
foreach (var collision in validCollisions)
{
if (!selectionB.Contains(collision.Item2))
{
selectionB.Add(collision.Item2);
}
}
snapshotTest.SelectionB.Selection.CopyFrom(selectionB);
// 添加到文档
_documentClash.TestsData.TestsAddCopy(snapshotTest);
// 运行测试
System.Threading.Tasks.Task.Run(() =>
{
try
{
var addedTest = _documentClash.TestsData.Tests
.FirstOrDefault(t => t.DisplayName == testName) as ClashTest;
if (addedTest != null)
{
_documentClash.TestsData.TestsRunTest(addedTest);
LogManager.Info($"创建动画碰撞测试: {testName}, 碰撞数量: {validCollisions.Count}");
}
}
catch (Exception ex)
{
LogManager.Error($"运行新测试失败: {ex.Message}");
}
});
}
catch (Exception ex)
{
LogManager.Error($"创建新测试失败: {ex.Message}");
}
}
/// <summary>
/// 更新主测试记录(避免频繁创建新测试)
/// </summary>
@ -430,6 +785,9 @@ namespace NavisworksTransport
// 尝试访问对象的属性来检查是否有效
var displayName = item.DisplayName;
var hasGeometry = item.HasGeometry;
// 额外检查:确保对象没有被释放
var boundingBox = item.BoundingBox();
return true;
}
catch (Exception ex)
@ -811,7 +1169,7 @@ namespace NavisworksTransport
}
/// <summary>
/// 刷新Clash Detective窗口
/// 刷新Clash Detective窗口(修复版 - 避免UI阻塞
/// </summary>
private void RefreshClashDetectiveWindow()
{
@ -819,77 +1177,111 @@ namespace NavisworksTransport
{
LogManager.Info("开始刷新Clash Detective窗口...");
// 方法1: 通过COM API刷新如果可用
if (_clashElement != null)
// 检查文档是否有效
if (Application.ActiveDocument == null)
{
LogManager.Warning("文档已失效,跳过刷新");
return;
}
// 使用后台任务执行避免UI阻塞
System.Threading.Tasks.Task.Run(() =>
{
try
{
_clashElement.RunAllTests();
LogManager.Info("通过COM API刷新Clash Detective窗口成功");
// 方法1: 通过COM API刷新如果可用
if (_clashElement != null)
{
try
{
_clashElement.RunAllTests();
LogManager.Info("通过COM API刷新Clash Detective窗口成功");
}
catch (Exception ex)
{
LogManager.Warning($"COM API刷新失败: {ex.Message}");
}
}
// 方法2: 通过.NET API刷新主要方法
if (_documentClash != null)
{
try
{
// 重新运行我们的测试
var currentTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == "动态运输路径碰撞检测");
if (currentTest != null && currentTest is ClashTest clashTest)
{
_documentClash.TestsData.TestsRunTest(clashTest);
LogManager.Info($"通过.NET API刷新测试结果当前结果数: {clashTest.Children.Count}");
}
else
{
LogManager.Info("动态测试不存在,重新创建...");
// 在后台任务中重新创建
SetupDynamicClashTest();
}
}
catch (Exception ex)
{
LogManager.Warning($".NET API刷新失败: {ex.Message}");
}
}
// 方法3: 强制重绘视图
try
{
// 使用延迟重绘,避免立即操作
System.Threading.Thread.Sleep(100);
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
LogManager.Info("强制重绘视图成功");
}
catch (Exception ex)
{
LogManager.Warning($"视图重绘失败: {ex.Message}");
}
// 方法4: 尝试手动触发Clash Detective UI更新
try
{
// 使用延迟操作给UI时间处理
System.Threading.Thread.Sleep(100);
// 强制保存和重新加载文档状态
var doc = Application.ActiveDocument;
if (doc != null && doc.CurrentSelection != null)
{
var tempSelection = doc.CurrentSelection.SelectedItems;
doc.CurrentSelection.Clear();
if (tempSelection.Count > 0)
{
doc.CurrentSelection.CopyFrom(tempSelection);
}
LogManager.Info("手动触发UI更新成功");
}
}
catch (Exception ex)
{
LogManager.Warning($"手动UI更新失败: {ex.Message}");
}
LogManager.Info("Clash Detective窗口刷新完成");
}
catch (ObjectDisposedException ex)
{
LogManager.Warning($"刷新时对象已释放: {ex.Message}");
}
catch (Exception ex)
{
LogManager.Warning($"COM API刷新失败: {ex.Message}");
LogManager.Error($"后台刷新失败: {ex.Message}");
}
}
});
// 方法2: 通过.NET API刷新主要方法
if (_documentClash != null)
{
try
{
// 重新运行我们的测试
var currentTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == "动态运输路径碰撞检测");
if (currentTest != null && currentTest is ClashTest clashTest)
{
_documentClash.TestsData.TestsRunTest(clashTest);
LogManager.Info($"通过.NET API刷新测试结果当前结果数: {clashTest.Children.Count}");
}
else
{
LogManager.Info("动态测试不存在,重新创建...");
SetupDynamicClashTest();
}
}
catch (Exception ex)
{
LogManager.Warning($".NET API刷新失败: {ex.Message}");
}
}
// 方法3: 强制重绘视图
try
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
LogManager.Info("强制重绘视图成功");
}
catch (Exception ex)
{
LogManager.Warning($"视图重绘失败: {ex.Message}");
}
// 方法4: 尝试手动触发Clash Detective UI更新
try
{
// 强制保存和重新加载文档状态
var tempSelection = Application.ActiveDocument.CurrentSelection.SelectedItems;
Application.ActiveDocument.CurrentSelection.Clear();
if (tempSelection.Count > 0)
{
Application.ActiveDocument.CurrentSelection.CopyFrom(tempSelection);
}
LogManager.Info("手动触发UI更新成功");
}
catch (Exception ex)
{
LogManager.Warning($"手动UI更新失败: {ex.Message}");
}
LogManager.Info("Clash Detective窗口刷新完成");
}
catch (Exception ex)
{
LogManager.Error($"刷新Clash Detective窗口失败: {ex.Message}");
LogManager.Error($"刷新Clash Detective窗口启动失败: {ex.Message}");
}
}
@ -1170,153 +1562,7 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 强制显示测试结果(用于调试)
/// </summary>
public void ForceShowTestResults()
{
try
{
LogManager.Info("强制显示测试结果...");
if (!_isInitialized)
{
LogManager.Warning("集成未初始化,重新初始化...");
Initialize();
}
if (_documentClash == null)
{
LogManager.Error("无法访问Clash Detective文档");
return;
}
// 创建一个完整的演示测试
CreateDemoTest();
// 如果有最近的碰撞结果,也创建一个快照
if (_currentCollisions.Count > 0)
{
var collisionResults = _currentCollisions.Select(c => new CollisionResult
{
ClashGuid = c.Guid,
DisplayName = c.DisplayName,
Status = c.Status,
Item1 = c.Item1,
Item2 = c.Item2,
Center = c.Center,
Distance = c.Distance,
CreatedTime = DateTime.Now
}).ToList();
CreateCollisionSnapshot(collisionResults);
}
// 强制刷新显示
RefreshClashDetectiveWindow();
// 记录最终状态
LogManager.Info(GetTestStatusInfo());
}
catch (Exception ex)
{
LogManager.Error($"强制显示测试结果失败: {ex.Message}");
}
}
/// <summary>
/// 创建演示测试
/// </summary>
private void CreateDemoTest()
{
try
{
// 获取一些测试对象,使用更安全的方法
var doc = Application.ActiveDocument;
var allItems = doc.Models.RootItemDescendantsAndSelf
.Where(item => item.HasGeometry)
.ToList();
// 过滤出有效的对象
var validItems = new List<ModelItem>();
foreach (var item in allItems)
{
if (IsModelItemValid(item))
{
validItems.Add(item);
}
}
LogManager.Info($"找到 {validItems.Count} 个有效的几何对象");
if (validItems.Count >= 2)
{
// 创建演示测试
var demoTest = new ClashTest();
demoTest.DisplayName = "Clash Detective 集成演示";
demoTest.TestType = ClashTestType.Hard;
demoTest.Tolerance = 0.01;
// 设置测试选择 - 使用更保守的方法
var selectionA = new ModelItemCollection();
var selectionB = new ModelItemCollection();
// 选择A前几个对象
int countA = Math.Min(5, validItems.Count / 2);
for (int i = 0; i < countA; i++)
{
if (IsModelItemValid(validItems[i]))
{
selectionA.Add(validItems[i]);
}
}
// 选择B后几个对象
int startB = Math.Max(countA, validItems.Count / 2);
int countB = Math.Min(5, validItems.Count - startB);
for (int i = 0; i < countB; i++)
{
int index = startB + i;
if (index < validItems.Count && IsModelItemValid(validItems[index]))
{
selectionB.Add(validItems[index]);
}
}
if (selectionA.Count > 0 && selectionB.Count > 0)
{
demoTest.SelectionA.Selection.CopyFrom(selectionA);
demoTest.SelectionB.Selection.CopyFrom(selectionB);
LogManager.Info($"创建演示测试: A={selectionA.Count}, B={selectionB.Count}");
// 添加到文档
_documentClash.TestsData.TestsAddCopy(demoTest);
// 重新获取并运行测试
var addedTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == "Clash Detective 集成演示");
if (addedTest is ClashTest runTest)
{
_documentClash.TestsData.TestsRunTest(runTest);
LogManager.Info($"演示测试运行完成,结果数量: {runTest.Children.Count}");
}
}
else
{
LogManager.Warning("没有足够的有效对象来创建演示测试");
}
}
else
{
LogManager.Warning($"有效对象数量不足: {validItems.Count}需要至少2个");
}
}
catch (Exception ex)
{
LogManager.Error($"创建演示测试失败: {ex.Message}");
}
}
// 已删除ForceShowTestResults 和 CreateDemoTest - 不再需要这些已废弃的方法
/// <summary>
/// 清理资源
@ -1334,8 +1580,7 @@ namespace NavisworksTransport
// 清空结果
_currentCollisions.Clear();
// 清理过多的快照测试保留最近的5个
CleanupSnapshotTests();
// 清理工作:动画结束后统一处理,无需频繁清理
LogManager.Info("Clash Detective集成清理完成");
}
@ -1345,38 +1590,9 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 清理过多的快照测试
/// </summary>
private void CleanupSnapshotTests()
{
try
{
if (_documentClash == null)
return;
// 已删除ForceCloseClashDetectiveDialogs - 不再需要强制关闭对话框
// 查找所有快照测试
var snapshotTests = _documentClash.TestsData.Tests
.Where(t => t.DisplayName.StartsWith("动画碰撞快照_"))
.Cast<ClashTest>()
.ToList();
// 如果超过5个删除最旧的
if (snapshotTests.Count > 5)
{
var testsToRemove = snapshotTests.Take(snapshotTests.Count - 5);
foreach (var test in testsToRemove)
{
_documentClash.TestsData.TestsRemove(test);
LogManager.Debug($"已删除旧快照测试: {test.DisplayName}");
}
}
}
catch (Exception ex)
{
LogManager.Error($"清理快照测试失败: {ex.Message}");
}
}
// 已删除CleanupSnapshotTests - 不再需要,使用动画结束后汇总
/// <summary>
/// 触发碰撞检测事件

View File

@ -440,7 +440,7 @@ namespace NavisworksTransport
}
/// <summary>
/// 快速验证集成功能
/// 快速验证集成功能(修复版 - 避免UI阻塞
/// </summary>
/// <returns>验证是否成功</returns>
public static bool QuickValidation()
@ -460,26 +460,51 @@ namespace NavisworksTransport
// 2. 检查初始化
instance.Initialize();
// 3. 检查基本功能
// 3. 检查基本功能(使用异步方式)
var doc = NavisApplication.ActiveDocument;
if (doc?.Models?.RootItemDescendantsAndSelf != null)
{
var testItem = doc.Models.RootItemDescendantsAndSelf
.FirstOrDefault(item => item.HasGeometry);
.Where(item => item != null && item.HasGeometry)
.FirstOrDefault();
if (testItem != null)
{
var collisions = instance.DetectCollisions(testItem);
LogManager.Info($"快速验证成功: 检测到 {collisions.Count} 个碰撞");
try
{
var collisions = instance.DetectCollisions(testItem);
LogManager.Info($"快速验证成功: 检测到 {collisions.Count} 个碰撞");
}
catch (ObjectDisposedException)
{
LogManager.Warning("快速验证时对象已释放,跳过碰撞检测");
}
}
}
// 4. 清理
instance.Cleanup();
// 4. 清理(异步执行)
System.Threading.Tasks.Task.Run(() =>
{
try
{
System.Threading.Thread.Sleep(50); // 给UI线程喘息时间
instance.Cleanup();
LogManager.Debug("快速验证清理完成");
}
catch (Exception cleanupEx)
{
LogManager.Warning($"快速验证清理失败: {cleanupEx.Message}");
}
});
LogManager.Info("快速验证完成");
return true;
}
catch (ObjectDisposedException ex)
{
LogManager.Warning($"快速验证时对象已释放: {ex.Message}");
return false;
}
catch (Exception ex)
{
LogManager.Error($"快速验证失败: {ex.Message}");

View File

@ -1468,74 +1468,6 @@ namespace NavisworksTransport
};
groupBox.Controls.Add(_animationProgressBar);
// 测试Clash Detective集成按钮
Button testClashDetectiveButton = new Button
{
Text = "测试Clash Detective集成",
Location = new Point(175, 25),
Size = new Size(150, 30),
Font = new Font("微软雅黑", 8),
BackColor = System.Drawing.Color.LightBlue
};
testClashDetectiveButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 执行快速验证
LogManager.Info("开始测试 Clash Detective 集成...");
bool quickValidation = ClashDetectiveIntegrationTest.QuickValidation();
if (quickValidation)
{
// 执行完整测试
var testResults = ClashDetectiveIntegrationTest.RunFullIntegrationTest();
int passedTests = testResults.Count(r => r.IsSuccess);
int totalTests = testResults.Count;
string message = $"测试完成!通过 {passedTests}/{totalTests} 个测试\n\n";
// 获取当前状态信息
var statusInfo = ClashDetectiveIntegration.Instance.GetTestStatusInfo();
// 强制显示测试结果
ClashDetectiveIntegration.Instance.ForceShowTestResults();
if (passedTests == totalTests)
{
message += "请检查 Clash Detective 窗口查看测试结果。\n";
message += "如果窗口中没有显示测试,请:\n";
message += "1. 确认 Clash Detective 窗口已打开\n";
message += "2. 查看测试列表中的'动态运输路径碰撞检测'项\n";
message += "3. 检查日志文件获取详细信息";
MessageBox.Show(message, "测试结果", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
message += "部分测试失败,详细信息:\n";
foreach (var result in testResults.Where(r => !r.IsSuccess))
{
message += $"- {result.TestName}: {result.Message}\n";
}
message += "\n详细日志请查看日志文件";
MessageBox.Show(message, "测试结果", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
// 显示状态信息
LogManager.Info(statusInfo);
}
else
{
MessageBox.Show("快速验证失败,请检查日志了解详情", "测试失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}, "测试Clash Detective集成");
};
groupBox.Controls.Add(testClashDetectiveButton);
}
/// <summary>

View File

@ -346,6 +346,18 @@ namespace NavisworksTransport
SetState(AnimationState.Finished); // 标记为完成
AnimationCompleted?.Invoke(this, EventArgs.Empty); // 触发旧版完成事件
LogManager.Info("动画播放完成");
// 动画结束后创建最终碰撞结果汇总(安全模式)
try
{
LogManager.Info("开始执行碰撞结果汇总...");
ClashDetectiveIntegration.Instance.CreateFinalCollisionSummary();
LogManager.Info("碰撞结果汇总完成");
}
catch (Exception ex)
{
LogManager.Error($"碰撞汇总执行失败: {ex.GetType().Name}: {ex.Message}");
}
}
}
catch (Exception ex)
@ -583,7 +595,7 @@ namespace NavisworksTransport
}
/// <summary>
/// 使用 Clash Detective 集成进行碰撞检测和高亮显示
/// 使用 Clash Detective 集成进行碰撞检测并在运行时显示结果
/// </summary>
private void CheckAndHighlightCollisionsWithClashDetective()
{
@ -598,10 +610,16 @@ namespace NavisworksTransport
// 高亮显示碰撞对象
ClashDetectiveIntegration.Instance.HighlightCollisions(collisionResults);
// 触发碰撞检测事件
// 缓存碰撞结果,动画结束后统一处理
if (collisionResults.Count > 0)
{
// 缓存碰撞结果
ClashDetectiveIntegration.Instance.CreateCollisionSnapshot(collisionResults);
// 触发碰撞检测事件
OnCollisionDetected(new CollisionDetectedEventArgs(collisionResults));
LogManager.Info($"检测到 {collisionResults.Count} 个碰撞,已缓存结果");
}
LogManager.Debug($"碰撞检测完成: {collisionResults.Count} 个碰撞");
@ -609,9 +627,6 @@ namespace NavisworksTransport
catch (Exception ex)
{
LogManager.Error($"碰撞检测失败: {ex.Message}");
// 如果新方法失败,回退到简化版本
CheckAndHighlightCollisions();
}
}
@ -662,48 +677,7 @@ namespace NavisworksTransport
CollisionDetected?.Invoke(this, e);
}
/// <summary>
/// 检查并高亮碰撞(简化版本)
/// </summary>
private void CheckAndHighlightCollisions()
{
try
{
// 简化的碰撞检测:检查动画对象是否与其他对象的包围盒相交
var doc = NavisApplication.ActiveDocument;
var animatedBoundingBox = _animatedObject.BoundingBox();
// 获取所有其他有几何体的对象
var allItems = doc.Models.RootItemDescendantsAndSelf
.Where(item => item.HasGeometry && !item.Equals(_animatedObject))
.ToList();
var collidingItems = new ModelItemCollection();
foreach (var item in allItems)
{
var itemBoundingBox = item.BoundingBox();
if (BoundingBoxesIntersect(animatedBoundingBox, itemBoundingBox))
{
collidingItems.Add(item);
}
}
// 清除之前的高亮
doc.Models.ResetAllTemporaryMaterials();
// 高亮碰撞对象(红色)
if (collidingItems.Count > 0)
{
doc.Models.OverrideTemporaryColor(collidingItems, Color.Red);
LogManager.Debug($"检测到 {collidingItems.Count} 处碰撞");
}
}
catch (Exception ex)
{
LogManager.Debug($"碰撞检测更新失败: {ex.Message}");
}
}
// 已删除CheckAndHighlightCollisions - 使用Clash Detective集成代替
/// <summary>
/// 检查两个包围盒是否相交