# 2025-12-10 手工指定碰撞检测对象方案

## 背景与目标

- **用户痛点**：默认碰撞检测会遍历全部非通道构件，难以及时聚焦某些高风险设备；在超大模型上，构建几何体缓存与空间索引会耗时数分钟。
- **目标**：在“检测动画”页签中提供“指定被检测对象”能力，让用户先选定构件集合再生成动画，并以特殊颜色提示这些对象已被纳入检测范围；**一旦启用该模式，直接绕过几何体缓存/空间索引的构建，以达到“只检测我选的对象”这一性能诉求**。
- **约束**：
  - 遵循既有 WPF 风格（参考路径编辑页“高级设置”区）；
  - 仅在开启新开关时生效，关闭后恢复现有流程；
  - 方案阶段不改动后端数据存储，优先复用现有选择/高亮/碰撞管线。

> **模式切换总览**
>
> | 模式 | 默认行为 | 手工指定开启后 |
> | --- | --- | --- |
> | 碰撞对象来源 | 空间索引 + 通道过滤后的全集 | 仅使用手工列表（最多几十个） |
> | 预处理 | 构建几何体缓存、通道缓存、空间索引 | **全部跳过**，即刻进入动画帧预计算 |
> | 高亮颜色 | 红/绿（碰撞结果） | 琥珀色（手工目标） + 红色（真实碰撞） |

## 影响面

| 层级 | 受影响组件 | 改动点 |
| --- | --- | --- |
| UI | `AnimationControlView.xaml` | 在“生成动画”之前插入一个新的 Border 区块，包含开关、说明文本、选择按钮和列表 |
| ViewModel | `AnimationControlViewModel` | 新增状态、集合、命令以及与 PathAnimationManager/ClashDetectiveIntegration 的桥接逻辑 |
| 动画核心 | `PathAnimationManager` | 允许外部传入“手工指定碰撞对象”列表并在预计算阶段使用 |
| 碰撞集成 | `ClashDetectiveIntegration` | 复用高亮能力，新建类别（如 `manualTargets`）和辅助方法支持直接高亮 ModelItem 集合 |

## 方案概述（最小改动路径）

1. **UI 区块**：使用 `Border + StackPanel + Expander` 布局，结构仿照路径编辑页“高级设置”。包含：
   - “指定碰撞检测对象”`CheckBox`（开关），描述文本说明高亮颜色及生效时机；
   - `TextBox`（只读）展示已选数量/最近一次同步时间；
   - “选择对象”“清除”按钮，复用移动物体选择的按钮样式；
   - `ListView` 展示选中项（序号、名称、模型路径摘要），并提供每行“移除”按钮。
2. **ViewModel 状态**：
   - `bool IsManualCollisionTargetEnabled`：绑定开关；
   - `ObservableCollection<ManualCollisionTargetViewModel> ManualCollisionTargets`：存储条目；
   - `string ManualCollisionTargetSummary`：供只读文本框显示，例如“3 个对象 • 来自当前选择”。
3. **命令**：
   - `ApplyManualTargetsFromSelectionCommand`：读取 Navisworks 当前选中集合（支持多选），过滤无几何体项，生成/更新条目；
   - `ClearManualTargetsCommand`、`RemoveManualTargetCommand`：维护列表；
   - 所有命令触发时都更新 PathAnimationManager 和高亮状态。
4. **高亮实现**：
   - 在 `ClashDetectiveIntegration` 增加 `HighlightModelItems(string category, IEnumerable<ModelItem> items, Color color)`；
   - ViewModel 在以下场景调用：开启开关、列表变化、清除/关闭时调用 `ClearHighlightCategory("manualTargets")`；
   - 颜色建议使用 `Color.FromArgb(255, 255, 170, 0)`（琥珀色），区别于红/绿等现有语义。
5. **碰撞管线改动**：
   - `PathAnimationManager` 中新增字段 `_manualCollisionTargets` 与 `_isManualTargetOverride`，提供 `SetManualCollisionTargets(IEnumerable<ModelItem> targets, bool enabled)`；
   - `PrecomputeAnimationFrames` 内判断：
     - 若启用且集合不为空，**不再构建/访问 `SpatialIndexManager`，直接遍历 `_manualCollisionTargets` 并按需要套用检测间隙**；
     - 若禁用或集合为空，保持原流程（空间索引 + 通道过滤）。
   - 在 `CreateAnimation`/`SetupAnimation` 入口调用 `SetManualCollisionTargets`，确保每次生成动画采用当前配置；若处于手工模式，`PathAnimationManager` 可以跳过 `_pathAnimationManager.PrecomputeCollisionExclusions` 等额外缓存。
6. **校验 & 兜底**：
   - 开启开关但集合为空时，`GenerateAnimation` 给出提示并阻止执行；
   - 任何时候如果传入的 `ModelItem` 已无效，自动在 ViewModel 层剔除并提示用户重新选择；
   - 关闭开关或清空集合后，恢复默认检测路径并清除高亮。

## 详细流程

1. 用户在 Navisworks 选中若干对象 → 点击“选择对象”。
2. ViewModel 读取 `Application.ActiveDocument.CurrentSelection.SelectedItems`：
   - 过滤无几何体项（复用 `HasGeometryRecursive` 或 `ModelItemAnalysisHelper.IsModelItemValid`）；
   - 构建 `ManualCollisionTargetViewModel`（含 `ModelItem Reference`、`string DisplayName`、`string ModelPath`）。
3. 若开启开关，立即：
   - `ClashDetectiveIntegration.HighlightModelItems("manualTargets", targets, amberColor)`；
   - `_pathAnimationManager.SetManualCollisionTargets(targets, true)`；
   - 更新 summary、列表 UI、按钮可用状态。
4. `ExecuteGenerateAnimation` 中：
   - **先判断模式**：
     - 手工模式 → 只校验列表有效性，`_pathAnimationManager.SetManualCollisionTargets(validTargets, true)`，然后**跳过** `ClashDetectiveIntegration.BuildAllGeometryItemsCache()`、`BuildChannelObjectsCache()`、`SpatialIndexManager.BuildGlobalIndex()` 等耗时步骤；
     - 默认模式 → 保持既有缓存流程，完成后执行 `_pathAnimationManager.SetManualCollisionTargets(null, false)`。
   - 如此可以把“选择对象 → 生成动画”链路缩短到秒级（仅需复制列表和生成动画帧）。
5. `PathAnimationManager.PrecomputeAnimationFrames` 中：
   - `var nearbyObjects = _isManualTargetOverride ? _manualCollisionTargets : spatialIndexManager.FindNearbyObjects(...);`
   - 若 `_isManualTargetOverride` 为 true：
     - 不访问空间索引，也不构建搜索半径网格；
     - 仅对列表中对象执行包围盒碰撞判断，可选地基于位置快速剔除远离路径起点的对象；
   - 若为 false：继续沿用空间索引路径。
   - 其余碰撞计算逻辑保持不变，确保报告与动画输出流程无需额外改动。

## 风险与缓解

| 风险 | 影响 | 措施 |
| --- | --- | --- |
| `ModelItem` 在动画周期内失效 | 碰撞计算异常或高亮失败 | 在 ViewModel 选择/生成阶段调用 `ModelItemAnalysisHelper.IsModelItemValid`，无效条目自动剔除并提示 |
| 与空间索引缓存互斥 | 可能遗漏非手工对象 | 开关明确声明“限制检测范围”，代码层面启用后完全绕过空间索引，避免混合逻辑产生重复过滤 |
| 高亮颜色覆盖已有类别 | UI 混淆 | 使用 `manualTargets` 独立类别，调用 `ManageHighlightsByCategory`，只在关闭/清空时清除此类别 |

## 验证计划

1. **功能验证**：
   - 默认关闭 → 生成动画 → 碰撞流程与当前版本一致；
   - 开启 + 选择 2 个对象 → 生成动画 → 仅对这 2 个对象触发碰撞 & 高亮为琥珀色；
   - 开启但未选择 → 生成动画应被阻止并提示；
   - 清除或关闭开关后再次生成动画 → 恢复全局检测。
2. **回归验证**：`./compile.bat`，重点关注 `AnimationControlView`/ViewModel 编译；若需要，运行 `run-unit-tests.bat` 保证基础用例通过。

## 后续可选项（非本次范围）

- 将手工对象集合持久化到路径/配置文件；
- 在碰撞报告中标注“手工检测对象”标签用于审计；
- 在 TimeLiner 中同步这些对象的可见性以便演示。
