# 快速取面工具设计

创建时间：2026-06-02

## 目标

新增一个独立 ToolPlugin，通过单点+像素邻域法快速推断鼠标点击位置所在面的法向量。
和取点工具 `PathClickToolPlugin` 并列，互斥激活。

## 核心算法

单点+像素邻域法 —— 一次点击内做三次 `PickItemFromPoint`：

```
中心点: PickItemFromPoint(x, y)    → p0
右邻域: PickItemFromPoint(x+δ, y)  → p1
下邻域: PickItemFromPoint(x, y+δ)  → p2

v1 = p1 - p0
v2 = p2 - p0
normal = normalize(cross(v1, v2))
```

偏移量 δ 三级递进：2px → 5px → 10px，小偏移共线时自动退到更大偏移。

## 新增文件

| 文件 | 职责 |
|---|---|
| `src/Models/FaceInferResult.cs` | 结果数据类 |
| `src/Core/FaceInferToolPlugin.cs` | ToolPlugin 主体 |

不修改任何现有文件。

## 架构

```
FaceInferToolPlugin : ToolPlugin
│
├── Plugin("FaceInferTool", "NavisworksTransport")
│
├── Static 成员
│   ├── event FaceInferred          # 外部订阅事件
│   ├── AssemblyPath                # 用于动态加载
│   └── TriggerFaceInferred()       # 允许外部手动触发
│
├── GetCursor → Cursor.MarkupQuickPick
│
├── MouseDown(x, y)
│   ├── centerPick  = PickItemFromPoint(x, y)
│   ├── rightPick   = PickItemFromPoint(x + δ, y)
│   ├── downPick    = PickItemFromPoint(x, y + δ)
│   ├── 同构件校验 (ModelItem 比较)
│   ├── 共线校验 (cross.Length < 0.001 → 退到下一级 δ)
│   ├── 法向量归一化
│   ├── 朝向统一 (dot with viewDir, 始终指向相机)
│   └── 触发 FaceInferred 事件
│
└── MouseMove → 暂不处理（轻量原则）
```

## FaceInferResult 数据结构

```csharp
public class FaceInferResult
{
    public Point3D HitPoint { get; }    // 命中点（宿主坐标系）
    public Vector3D Normal { get; }      // 面法向量（已归一化，朝向相机）
    public ModelItem ModelItem { get; }  // 命中的 ModelItem
    public bool IsValid { get; }         // 推断是否成功
}
```

所有坐标均为**宿主坐标系**（`PickItemFromPoint` 原始输出）。

## 激活方式

与 `PathClickToolPlugin` 完全相同的流程，仅插件名不同：

```csharp
var assemblyPath = FaceInferToolPlugin.AssemblyPath;
Application.Plugins.AddPluginAssembly(assemblyPath);
var record = (ToolPluginRecord)Application.Plugins.FindPlugin("FaceInferTool.NavisworksTransport");
var plugin = record.LoadPlugin();
Application.MainDocument.Tool.SetCustomToolPlugin(plugin);
```

## 光标

使用 `Cursor.MarkupQuickPick`。Navisworks `Cursor` 枚举无平行四边形，此为最接近的选项。

## 与 PathClickToolPlugin 的关系

- 两者都是 `ToolPlugin`，同一时刻只有一个激活
- 互斥切换：取面时取点失活，取面结束切回取点
- 切换流程与项目中已有的「导航工具 ↔ ClickTool」切换模式一致

## 暂不实现

| 项目 | 原因 |
|---|---|
| 透视近大远小动态 δ 调整 | 先验证精度，不够再加 |
| 跨面距离检测 (maxDist) | 同构件判断已覆盖基本场景 |
| 曲面曲率分析 | 不同业务需求 |
| MouseMove 实时预览 | 保持轻量 |

## 下一步

1. 实现两个新文件
2. 在已知平面上验证法向量精度（误差应在 1° 以内）
3. 后续由调用方（ViewModel）按需集成激活/切换逻辑
