NavisworksTransport/doc/working/2026-02-08-human-in-the-loop-collision-optimization.md

321 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Human-in-the-Loop 碰撞优化功能 - 实现完成报告
## 当前状态2026-02-09
### 已完成功能
#### 第一阶段(基础分析)✅
1. **碰撞热点自动分析** - 预计算完成后自动分析碰撞结果
2. **自动高亮显示** - 自动高亮所有预计算碰撞结果(紫色 #9C27B0
3. **分析对话框** - 显示详细的碰撞统计和建议排除选项
4. **光标修复** - 对话框显示时光标恢复正常
#### 第二阶段(排除列表集成)✅
1. **排除列表数据结构** - `PathAnimationManager` 中使用 `HashSet<ModelItem>`
2. **管理方法** - `SetExcludedObjectsAndClearCache`、`AddExcludedObjects`、`ClearExcludedObjects`
3. **预计算过滤** - 在 `PrecomputeAnimationFrames()` 中应用排除列表过滤
4. **对话框集成** - 分析结果自动合并到排除列表
5. **UI区域** - 新增"检测排除对象"区域,支持手工添加和显示排除列表
#### 第三阶段UI优化
1. **碰撞分析对话框增强**
- 序号列显示
- 行点击自动高亮对应物体(紫色预计算风格)
- 候选碰撞数字黑色粗体显示
- 预计检测时间显示xxx秒/xx.x分钟
- 智能自动选中(碰撞>100次 或 占比>50%
- 单一"继续生成动画"按钮(自动判断是否有排除对象)
2. **排除列表UI完善**
- 添加"清除高亮"按钮
- 删除列表项时自动清除高亮
- 使用 `ModelItemEquals` 正确比较对象(修复 InstanceGuid 问题)
#### 第四阶段(数据库持久化)✅
1. **数据库表结构**
- `ExcludedObjects` - 存储排除对象PathId、DisplayName、ModelIndex等
- `CollisionReportExcludedObjects` - 碰撞报告与排除对象关联表
- `ClashDetectiveExcludedObjects` - ClashDetective结果与排除对象关联表
2. **数据持久化**
- 排除对象随碰撞报告一起保存到数据库
- 支持从数据库加载排除对象通过PathId查找
- 碰撞历史和报告中显示当时使用的排除对象列表
3. **核心方法**
- `SaveExcludedObjectsToDatabase()` - 保存排除对象到数据库
- `LoadExcludedObjectsFromDatabase()` - 从数据库加载排除对象
- `LinkExcludedObjectsToCollisionReport()` - 关联排除对象到碰撞报告
---
## 新增/修改文件
| 文件 | 说明 |
|------|------|
| `src/UI/WPF/Views/CollisionAnalysisDialog.xaml` | 分析对话框UI已统一项目风格 |
| `src/UI/WPF/Views/CollisionAnalysisDialog.xaml.cs` | 分析对话框逻辑(序号、高亮、智能选中) |
| `src/UI/WPF/ViewModels/AnimationControlViewModel.cs` | 添加分析逻辑、排除列表管理、数据库保存 |
| `src/Core/Animation/PathAnimationManager.cs` | 排除列表字段、预计算过滤、数据库加载/保存 |
| `src/UI/WPF/Views/AnimationControlView.xaml` | "检测排除对象"UI区域 |
| `src/Utils/ModelItemAnalysisHelper.cs` | 添加 `ModelItemEquals` 正确比较方法 |
| `src/Core/PathDatabase.cs` | 添加排除列表相关的数据库表和方法 |
---
## 技术实现细节
### 排除列表存储与比较
```csharp
// 使用 HashSet<ModelItem> 存储排除对象
private HashSet<ModelItem> _excludedObjects = new HashSet<ModelItem>();
// 正确的 ModelItem 比较(使用底层原生对象比较)
public static bool ModelItemEquals(ModelItem item1, ModelItem item2)
{
if (item1 == null && item2 == null) return true;
if (item1 == null || item2 == null) return false;
return item1.Equals(item2); // 使用 Navisworks API 的 Equals
}
```
**重要修复**:之前使用 `InstanceGuid` 比较会导致不同对象被误判为相同,现在统一使用 `ModelItemEquals`
### 预计算过滤点
```csharp
// 在 PrecomputeAnimationFrames 的循环中
var nearbyObjects = spatialIndexManager.FindInAABB(searchBounds, excludeObject: _animatedObject);
// 应用排除列表过滤
nearbyObjects = nearbyObjects.Where(obj => !_excludedObjects.Contains(obj));
```
### 智能自动选中逻辑
```csharp
// 碰撞分析对话框中的智能选中条件
IsExcluded = h.CollisionCount > 100 || h.Percentage > 50
```
### 行点击高亮
```csharp
// 使用预计算碰撞结果高亮类别(紫色 #9C27B0
private const string PrecomputedHighlightCategory = ModelHighlightHelper.PrecomputeCollisionResultsCategory;
// 点击行时高亮对应物体
ModelHighlightHelper.HighlightItems(PrecomputedHighlightCategory, items);
```
### UI 绑定
```csharp
// ViewModel 属性
public ThreadSafeObservableCollection<ExcludedObjectViewModel> ExcludedObjects { get; }
public string ExcludedObjectSummary { get; set; }
public bool HasExcludedObjects { get; }
// 命令
public ICommand AddExcludedObjectsFromSelectionCommand { get; }
public ICommand ClearExcludedObjectsCommand { get; }
public ICommand RemoveExcludedObjectCommand { get; }
public ICommand HighlightAllExcludedObjectsCommand { get; }
public ICommand ClearExcludedHighlightCommand { get; }
```
### 数据库持久化
#### 数据库表结构
```sql
-- 排除对象表
CREATE TABLE ExcludedObjects (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
RouteId TEXT, -- 关联路径ID可为空表示全局排除
ModelIndex INTEGER NOT NULL,
PathId TEXT NOT NULL, -- 格式: "模型索引:路径索引数组"
DisplayName TEXT,
ObjectName TEXT,
ExcludedTime DATETIME DEFAULT CURRENT_TIMESTAMP,
Reason TEXT,
IsGlobal INTEGER DEFAULT 0
);
-- 碰撞报告与排除对象关联表
CREATE TABLE CollisionReportExcludedObjects (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ReportId INTEGER NOT NULL,
ExcludedObjectId INTEGER NOT NULL
);
```
#### 保存排除对象到数据库
```csharp
// 在生成碰撞报告时保存排除对象
public void SaveExcludedObjectsToDatabase(PathDatabase database, string routeId)
{
var records = new List<ExcludedObjectRecord>();
foreach (var obj in _excludedObjects)
{
var record = new ExcludedObjectRecord
{
RouteId = routeId,
ModelIndex = GetModelIndex(obj),
PathId = GetModelItemPathId(obj), // 格式: "0:1,2,3"
DisplayName = obj.DisplayName,
ObjectName = GetModelItemObjectName(obj),
ExcludedTime = DateTime.Now,
Reason = "用户排除"
};
records.Add(record);
}
database.SaveExcludedObjects(records);
}
```
#### 从数据库加载排除对象
```csharp
// 根据PathId查找ModelItem
private ModelItem FindModelItemByPathId(Document doc, string pathId)
{
// PathId格式: "模型索引:路径索引数组"
// 例如: "0:1,2,3" 表示第0个模型的第1->2->3个节点
var parts = pathId.Split(':');
int modelIndex = int.Parse(parts[0]);
var pathIndices = parts[1].Split(',').Select(int.Parse).ToArray();
var model = doc.Models[modelIndex];
ModelItem current = model.RootItem;
foreach (var index in pathIndices)
{
var childrenList = current.Children.ToList();
current = childrenList[index];
}
return current;
}
```
---
## 工作流程
### 1. 动画生成流程
```
用户点击"生成动画"
预计算碰撞检测
分析碰撞热点(>5次或>10%
显示分析对话框(自动选中高频物体)
用户调整勾选/点击行查看高亮
点击"继续生成动画"
[如果有排除对象] 添加到排除列表 → 清除缓存 → 重新生成
[如果无排除对象] 直接继续
```
### 2. 排除列表管理流程
```
手工添加:选择物体 → 点击"从选择添加" → 添加到列表
分析添加:分析对话框勾选 → 点击"继续生成动画" → 合并到列表
删除单个:点击列表项的删除 → 清除高亮 → 同步到Manager
清除所有:点击"清除所有" → 清空列表 → 清除高亮
高亮显示:点击"全部高亮"/"清除高亮"
```
### 3. 数据库持久化流程
```
生成碰撞报告
保存排除对象到数据库ExcludedObjects表
关联排除对象到碰撞报告CollisionReportExcludedObjects表
查看碰撞历史时
加载碰撞报告关联的排除对象列表
显示"本次检测排除了X个对象"
```
---
## 使用指南
### 1. 通过分析对话框排除
1. 生成动画时自动触发预计算分析
2. 分析对话框显示高频碰撞物体(已自动选中>100次或>50%的)
3. 点击表格行可在3D视图中高亮对应物体紫色
4. 调整勾选状态后点击"继续生成动画"
5. 勾选的对象会被加入排除列表并重新生成
### 2. 手工管理排除列表
1. 在动画控制面板的"检测排除对象"区域
2. 在模型中选择要排除的物体
3. 点击"从选择添加"
4. 已排除物体在碰撞检测中会被忽略
5. 可随时"全部高亮"查看或"清除所有"清空
---
## 预期效果
### 减少 ClashDetective 测试数量
- 典型场景379 次碰撞 -> 排除地面后可能减少到 50 次以下
- 按每次测试 133ms 计算50s -> 6.6s,节省 86% 时间
### 提高结果质量
- 减少地面/楼板假阳性碰撞
- 让用户专注于真实障碍物
- 更准确的碰撞报告
---
## 后续可能的改进方向
### 智能建议增强
- [ ] 基于包围盒大小识别大型物体(>1000立方米
- [ ] 基于位置识别:位于路径下方的物体可能是地面
- [ ] 学习用户历史排除选择,优先建议
### 碰撞类型分类
- [ ] 区分"疑似假阳性"(地面/楼板接触)
- [ ] 区分"真实碰撞"(墙体/障碍物)
### 性能优化
- [ ] 增量预计算(仅重新计算受影响的帧)
- [ ] 分析结果持久化到数据库
---
## 注意事项
1. **排除列表生命周期**:当前为运行时管理,切换路径后保留,关闭文档后失效
2. **ModelItem比较**:必须使用 `ModelItemEquals` 方法,不能用 `InstanceGuid`
3. **缓存机制**:排除列表变更会触发 `SetExcludedObjectsAndClearCache` 清除动画缓存
4. **高亮颜色**
- 排除对象:绿色 (#4CAF50)
- 预计算碰撞:紫色 (#9C27B0)
- 手动目标:橙色 (#FFAA00)