NavisworksTransport/doc/design/2026/face-infer-tool-design.md
tian c7a1eeebb8 feat: add FaceInferToolPlugin - single-click face normal inference tool
- New FaceInferToolPlugin: pixel-neighborhood method with {2,5,10}px offsets
- New FaceInferResult data class
- Test button in SystemManagement page
- Cursor: MarkupAutoPoly (arrow + dashed box)
- Uses project-standard tools: FindNamedParentContainer, viewpoint.Position
- Design doc at doc/design/2026/face-infer-tool-design.md
2026-06-02 23:11:11 +08:00

112 lines
3.4 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.

# 快速取面工具设计
创建时间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按需集成激活/切换逻辑