# 坐标系动态适配设计方案(简化版)
## 问题背景
客户模型坐标系与插件默认坐标系不同:
- **插件默认**: Z-up (Z轴向上)
- **客户模型**: Y-up (Y轴向上,常见于Revit导出)
这导致网格生成、高度检测、路径规划等功能出现问题。
---
## 简化检测方案
### 核心原则
**单一检测源**: 使用 `Document.UpVector` 作为唯一检测依据
```csharp
var upVector = Application.ActiveDocument.UpVector;
if (!upVector.IsZero)
{
// 使用 Document.UpVector 判断坐标系
if (Math.Abs(upVector.Y) > 0.9)
return CoordinateSystemType.YUp;
else if (Math.Abs(upVector.Z) > 0.9)
return CoordinateSystemType.ZUp;
}
else
{
// 未定义,使用默认配置
return ConfigManager.Instance.Current.CoordinateSystem.Type;
}
```
---
## 实现架构
### 1. 坐标系类型枚举
```csharp
// src/Utils/CoordinateSystem/CoordinateSystemType.cs
public enum CoordinateSystemType
{
AutoDetect, // 自动检测(使用 Document.UpVector)
ZUp, // 强制 Z-Up
YUp // 强制 Y-Up
}
```
### 2. 简化坐标系管理器
```csharp
// src/Utils/CoordinateSystem/CoordinateSystemManager.cs
public class CoordinateSystemManager
{
public static CoordinateSystemManager Instance { get; } = new();
private ICoordinateSystem _current;
private CoordinateSystemType _configuredType;
///
/// 当前坐标系
///
public ICoordinateSystem Current => _current;
///
/// 初始化/重新检测坐标系
///
public void Initialize()
{
_configuredType = ConfigManager.Instance.Current.CoordinateSystem.Type;
switch (_configuredType)
{
case CoordinateSystemType.AutoDetect:
_current = AutoDetect();
break;
case CoordinateSystemType.ZUp:
_current = new ZUpCoordinateSystem();
break;
case CoordinateSystemType.YUp:
_current = new YUpCoordinateSystem();
break;
}
LogManager.Info($"[坐标系] 初始化完成: {_current.Type}");
}
///
/// 自动检测坐标系(基于 Document.UpVector)
///
private ICoordinateSystem AutoDetect()
{
try
{
var doc = Application.ActiveDocument;
if (doc == null) return new ZUpCoordinateSystem();
var upVector = doc.UpVector;
if (!upVector.IsZero)
{
if (Math.Abs(upVector.Y) > 0.9)
{
LogManager.Info("[坐标系检测] Document.UpVector 表明 Y-Up 坐标系");
return new YUpCoordinateSystem();
}
else if (Math.Abs(upVector.Z) > 0.9)
{
LogManager.Info("[坐标系检测] Document.UpVector 表明 Z-Up 坐标系");
return new ZUpCoordinateSystem();
}
}
LogManager.Warning("[坐标系检测] Document.UpVector 未定义,使用默认 Z-Up");
return new ZUpCoordinateSystem();
}
catch (Exception ex)
{
LogManager.Error($"[坐标系检测] 检测失败: {ex.Message}");
return new ZUpCoordinateSystem();
}
}
///
/// 手动切换坐标系(用于系统管理界面)
///
public void SetCoordinateSystem(CoordinateSystemType type)
{
switch (type)
{
case CoordinateSystemType.ZUp:
_current = new ZUpCoordinateSystem();
break;
case CoordinateSystemType.YUp:
_current = new YUpCoordinateSystem();
break;
default:
_current = AutoDetect();
break;
}
LogManager.Info($"[坐标系] 手动切换为: {_current.Type}");
}
}
```
---
## 配置文件
```toml
# default_config.toml
[coordinate_system]
# 坐标系类型: "AutoDetect"(推荐), "ZUp", "YUp"
# AutoDetect 将使用 Document.UpVector 自动检测
type = "AutoDetect"
```
---
## 系统管理界面
在系统管理页签添加坐标系设置:
```xml
```
**ViewModel 实现**:
```csharp
public ObservableCollection CoordinateSystemOptions { get; } =
new() { "AutoDetect", "ZUp", "YUp" };
public string SelectedCoordinateSystem
{
get => _selectedCoordinateSystem;
set
{
if (SetProperty(ref _selectedCoordinateSystem, value))
{
// 解析并应用新坐标系
if (Enum.TryParse(value, out var type))
{
CoordinateSystemManager.Instance.SetCoordinateSystem(type);
LogManager.Info($"坐标系已切换为: {value}");
}
}
}
}
```
---
## 使用流程
### 场景1: 自动检测成功
1. 打开模型
2. 插件自动检测 `Document.UpVector`
3. 检测到 `(0,1,0)` → 自动使用 Y-Up 坐标系
4. 用户无感知,功能正常工作
### 场景2: 自动检测失败(UpVector 为 Zero)
1. 打开模型
2. 插件检测到 `Document.UpVector.IsZero`
3. 回退到默认 Z-Up,记录警告日志
4. 用户发现功能异常
5. 打开系统管理 → 手动切换坐标系为 Y-Up
6. 功能恢复正常
### 场景3: 用户强制指定
1. 用户提前知道模型坐标系
2. 在系统管理中设置坐标系为 Y-Up
3. 打开模型,直接使用指定坐标系
---
## 需要修改的模块
| 模块 | 修改内容 | 优先级 |
|------|----------|--------|
| **CoordinateSystemManager** | 新建,实现简化检测逻辑 | P0 |
| **ICoordinateSystem** | 接口及 ZUp/YUp 实现 | P0 |
| **SystemManagementView** | 添加坐标系选择下拉框 | P0 |
| **GridMap** | 使用坐标系抽象 | P1 |
| **GridMapGenerator** | 垂直扫描方向适配 | P1 |
| **其他模块** | 逐步替换直接坐标访问 | P2 |
---
## 实施步骤
### 阶段1: 核心实现(1周)
1. 创建坐标系统抽象层
2. 实现简化检测逻辑
3. 添加系统管理界面配置
### 阶段2: 核心模块适配(1周)
1. 修改 GridMap 使用坐标系抽象
2. 修改 GridMapGenerator
3. 测试验证
### 阶段3: 全面适配(1周)
1. 逐步替换其他模块
2. 完善测试
3. 文档更新
---
## 关键代码示例
### 坐标系抽象接口
```csharp
public interface ICoordinateSystem
{
CoordinateSystemType Type { get; }
// 获取高度值(统一抽象)
double GetElevation(Point3D point);
// 设置高度值
Point3D SetElevation(Point3D point, double elevation);
// 获取水平面坐标
(double h1, double h2) GetHorizontalCoords(Point3D point);
// 创建3D点
Point3D CreatePoint(double h1, double h2, double elevation);
// 向上向量
Vector3D UpVector { get; }
// 垂直扫描方向(用于障碍物检测)
Vector3D VerticalScanDirection { get; }
}
```
### Z-Up 实现
```csharp
public class ZUpCoordinateSystem : ICoordinateSystem
{
public CoordinateSystemType Type => CoordinateSystemType.ZUp;
public Vector3D UpVector => new Vector3D(0, 0, 1);
public Vector3D VerticalScanDirection => new Vector3D(0, 0, -1);
public double GetElevation(Point3D point) => point.Z;
public Point3D SetElevation(Point3D point, double elevation) =>
new Point3D(point.X, point.Y, elevation);
public (double h1, double h2) GetHorizontalCoords(Point3D point) =>
(point.X, point.Y);
public Point3D CreatePoint(double h1, double h2, double elevation) =>
new Point3D(h1, h2, elevation);
}
```
### Y-Up 实现
```csharp
public class YUpCoordinateSystem : ICoordinateSystem
{
public CoordinateSystemType Type => CoordinateSystemType.YUp;
public Vector3D UpVector => new Vector3D(0, 1, 0);
public Vector3D VerticalScanDirection => new Vector3D(0, -1, 0);
public double GetElevation(Point3D point) => point.Y;
public Point3D SetElevation(Point3D point, double elevation) =>
new Point3D(point.X, elevation, point.Z);
public (double h1, double h2) GetHorizontalCoords(Point3D point) =>
(point.X, point.Z);
public Point3D CreatePoint(double h1, double h2, double elevation) =>
new Point3D(h1, elevation, h2);
}
```
---
## 优势
1. **简单可靠**: 基于 API 提供的 UpVector,无需猜测
2. **用户可控**: 自动检测失败时可手动干预
3. **向后兼容**: 默认行为不变,不影响现有用户
4. **易于维护**: 代码简洁,逻辑清晰
---
*文档更新时间: 2026-01-30*
*版本: 简化版*