# Navisworks API 坐标系检测文档

## 概述

本文档记录 Navisworks API 中关于坐标系获取的探索结果，包括已验证的方法和待验证的潜在方法。

---

## 已验证的 API

### 1. Viewpoint.WorldUpVector

**文件**: `src/Utils/ViewpointHelper.cs` (第119行)

```csharp
// 获取/设置视角的向上向量
newViewpoint.WorldUpVector = new UnitVector3D(0, 1, 0);
```

**说明**:
- 这是视图级别的向上向量，不是模型级别的坐标系定义
- 用于控制相机的朝向
- **局限性**: 可能不同于模型的实际坐标系

---

### 2. Model.Transform

**文件**: `src/Commands/ReadTransformTestCommand.cs` (第30行)

```csharp
// 获取模型项的变换矩阵
var transform = item.Transform;
var components = transform.Factor();
```

**说明**:
- 获取单个模型项的局部变换
- 包含 Translation, Rotation, Scale
- **局限性**: 这是模型项级别的变换，不是全局坐标系定义

---

### 3. COM API - GetLocalToWorldMatrix

**文件**: `src/Utils/GeometryHelper.cs` (第270行)

```csharp
// 从 COM API 获取局部到世界的变换矩阵
var transform = (ComApi.InwLTransform3f3)(object)fragment.GetLocalToWorldMatrix();
```

**说明**:
- 用于几何片段的世界坐标变换
- **局限性**: 几何级别的变换，不是坐标系定义

---

## 待验证的潜在方法

### 方法1: Document 级别的 Orientation 设置

Navisworks 界面中可以通过以下路径设置坐标系：
```
File Options → Orientation → Up Vector / North Vector
```

**可能的 API 路径**:

#### A. COM API 方式 (最有可能)
```csharp
// 伪代码 - 待验证
var comDocument = ComApiBridge.ToInwOpState(Application.ActiveDocument);
// 或
var fileOptions = comDocument.FileOptions;
var orientation = fileOptions.Orientation;
var upVector = orientation.UpVector;  // 可能是 Vector3D 或类似类型
var northVector = orientation.NorthVector;
```

#### B. .NET API 方式 (可能不存在)
```csharp
// 伪代码 - 待验证
var doc = Application.ActiveDocument;
// 可能的属性路径：
// doc.Options.Orientation.UpVector
// doc.FileOptions.Orientation.UpVector
// doc.Settings.Orientation.UpVector
```

**验证建议**:
1. 使用 Object Browser 查看 `Autodesk.Navisworks.Api` 中的相关类
2. 检查 `Document`, `DocumentOptions`, `FileOptions` 等类
3. 查看 COM API 的 `InwOpState` 或相关接口

---

### 方法2: Model 级别的 Transform

**可能的 API**:
```csharp
// 伪代码 - 待验证
foreach (Model model in Application.ActiveDocument.Models)
{
    // 模型可能有一个根级变换
    var modelTransform = model.Transform;
    var orientation = modelTransform.Factor().Rotation;
    // 从旋转矩阵推导坐标系
}
```

**验证建议**:
1. 检查 `Model` 类的属性
2. 对比不同坐标系模型的 `RootItem.Transform`

---

### 方法3: 通过场景包围盒分析

**思路**: 通过分析模型的包围盒特征推断坐标系

```csharp
// 启发式检测算法
public CoordinateSystemType DetectByBoundingBox()
{
    var sceneBounds = doc.Models[0].RootItem.BoundingBox();
    
    double xSpan = sceneBounds.Max.X - sceneBounds.Min.X;
    double ySpan = sceneBounds.Max.Y - sceneBounds.Min.Y;
    double zSpan = sceneBounds.Max.Z - sceneBounds.Min.Z;
    
    // 建筑通常更高而非更深
    if (ySpan > zSpan * 3 && ySpan > xSpan * 0.5)
    {
        return CoordinateSystemType.YUp;  // Y轴向上
    }
    
    return CoordinateSystemType.ZUp;  // 默认 Z轴向上
}
```

**局限性**:
- 不精确，只是启发式猜测
- 某些建筑可能不符合常规（如横向发展的建筑）

---

### 方法4: 通过典型元素分析

**思路**: 分析楼板、墙等建筑元素的法向量

```csharp
// 伪代码
var floorItems = FindItemsByCategory("楼板");
foreach (var floor in floorItems)
{
    // 获取几何并计算法向量
    var triangles = ExtractTriangles(floor);
    var normal = CalculateAverageNormal(triangles);
    
    // 如果法向量主要在 Y 方向，则是 Y-up
    if (Math.Abs(normal.Y) > 0.9)
    {
        return CoordinateSystemType.YUp;
    }
}
```

**局限性**:
- 需要解析几何，计算量大
- 需要正确识别楼板元素

---

## 推荐探索代码

创建一个测试命令来探索 API：

```csharp
using System;
using System.Windows;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;

namespace NavisworksTransport.Commands
{
    [Plugin("CoordinateSystemExplorer", "NavisworksTransport", DisplayName = "坐标系检测")]
    [AddInPlugin(AddInLocation.AddIn)]
    public class CoordinateSystemExplorerCommand : AddInPlugin
    {
        public override int Execute(params string[] parameters)
        {
            var doc = Application.ActiveDocument;
            var sb = new System.Text.StringBuilder();
            
            sb.AppendLine("=== 坐标系检测 ===\n");
            
            // 1. 检查 Document 级别的选项
            sb.AppendLine("1. Document 级别信息:");
            sb.AppendLine($"   文档名称: {doc.FileName}");
            sb.AppendLine($"   模型数量: {doc.Models.Count}");
            sb.AppendLine();
            
            // 2. 检查每个模型的信息
            sb.AppendLine("2. Model 级别信息:");
            foreach (Model model in doc.Models)
            {
                sb.AppendLine($"   模型: {model.Title}");
                sb.AppendLine($"   - RootItem.Name: {model.RootItem.DisplayName}");
                sb.AppendLine($"   - RootItem.Transform: {model.RootItem.Transform}");
                
                var bbox = model.RootItem.BoundingBox();
                sb.AppendLine($"   - 包围盒: [{bbox.Min.X:F2}, {bbox.Min.Y:F2}, {bbox.Min.Z:F2}] - [{bbox.Max.X:F2}, {bbox.Max.Y:F2}, {bbox.Max.Z:F2}]");
                sb.AppendLine();
            }
            
            // 3. 检查 COM API
            sb.AppendLine("3. COM API 探索:");
            try
            {
                var comState = ComApiBridge.ToInwOpState(doc);
                // 尝试访问 FileOptions 或 Orientation
                // 注意：这部分需要根据实际 COM API 结构调整
                sb.AppendLine($"   COM State 类型: {comState.GetType().Name}");
            }
            catch (Exception ex)
            {
                sb.AppendLine($"   COM API 访问失败: {ex.Message}");
            }
            sb.AppendLine();
            
            // 4. 检查 Viewpoint
            sb.AppendLine("4. Viewpoint 信息:");
            var vp = doc.CurrentViewpoint.Value;
            sb.AppendLine($"   WorldUpVector: ({vp.WorldUpVector.X}, {vp.WorldUpVector.Y}, {vp.WorldUpVector.Z})");
            sb.AppendLine($"   Position: ({vp.Position.X:F2}, {vp.Position.Y:F2}, {vp.Position.Z:F2})");
            sb.AppendLine();
            
            // 5. 包围盒分析
            sb.AppendLine("5. 包围盒分析:");
            var sceneBounds = doc.Models[0].RootItem.BoundingBox();
            double xSpan = sceneBounds.Max.X - sceneBounds.Min.X;
            double ySpan = sceneBounds.Max.Y - sceneBounds.Min.Y;
            double zSpan = sceneBounds.Max.Z - sceneBounds.Min.Z;
            sb.AppendLine($"   X 跨度: {xSpan:F2}");
            sb.AppendLine($"   Y 跨度: {ySpan:F2}");
            sb.AppendLine($"   Z 跨度: {zSpan:F2}");
            sb.AppendLine($"   检测建议: {(ySpan > zSpan * 3 ? "可能是 Y-Up" : "可能是 Z-Up")}");
            
            // 显示结果
            MessageBox.Show(sb.ToString(), "坐标系检测结果");
            LogManager.Info(sb.ToString());
            
            return 0;
        }
    }
}
```

---

## 下一步行动建议

### 立即行动

1. **创建探索命令**
   - 实现上面的 `CoordinateSystemExplorerCommand`
   - 在客户模型上运行，记录结果
   - 在标准 Z-up 模型上运行，对比结果

2. **Object Browser 检查**
   - 打开 Visual Studio 的 Object Browser
   - 查看 `Autodesk.Navisworks.Api` 程序集
   - 搜索关键词: `Orientation`, `FileOptions`, `UpVector`, `North`

3. **COM API 文档检查**
   - 打开 `doc\navisworks_api\COM\documentation\NavisWorksCOM.chm`
   - 搜索 `FileOptions`, `Orientation`

### 短期行动

1. **如果找到 API**
   - 更新 `CoordinateSystemManager` 使用官方 API
   - 简化自动检测逻辑

2. **如果没有找到 API**
   - 完善启发式检测算法
   - 增加用户手动配置选项
   - 考虑通过 UI 提示用户确认检测到的坐标系

---

## 相关资源

### 内部文档
- `doc\navisworks_api\NET\documentation\NET API.chm`
- `doc\navisworks_api\COM\documentation\NavisWorksCOM.chm`

### 外部链接
- [Autodesk Forum: Setting File Options Up- and North-orientation](https://forums.autodesk.com/t5/navisworks-api-forum/setting-file-options-up-and-north-orientation-using-navisworks/td-p/11795216)
- [How to change model orientation in Navisworks](https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-change-model-orientation-in-Navisworks.html)

### 参考文件
- `src/Utils/ViewpointHelper.cs` - Viewpoint.WorldUpVector 使用示例
- `src/Commands/ReadTransformTestCommand.cs` - Transform 读取示例
- `src/Utils/GeometryHelper.cs` - COM API Transform 使用示例

---

*文档创建时间: 2026-01-30*
*状态: 探索中*
