8.9 KiB
8.9 KiB
坐标系动态适配设计方案(简化版)
问题背景
客户模型坐标系与插件默认坐标系不同:
- 插件默认: Z-up (Z轴向上)
- 客户模型: Y-up (Y轴向上,常见于Revit导出)
这导致网格生成、高度检测、路径规划等功能出现问题。
简化检测方案
核心原则
单一检测源: 使用 Document.UpVector 作为唯一检测依据
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. 坐标系类型枚举
// src/Utils/CoordinateSystem/CoordinateSystemType.cs
public enum CoordinateSystemType
{
AutoDetect, // 自动检测(使用 Document.UpVector)
ZUp, // 强制 Z-Up
YUp // 强制 Y-Up
}
2. 简化坐标系管理器
// src/Utils/CoordinateSystem/CoordinateSystemManager.cs
public class CoordinateSystemManager
{
public static CoordinateSystemManager Instance { get; } = new();
private ICoordinateSystem _current;
private CoordinateSystemType _configuredType;
/// <summary>
/// 当前坐标系
/// </summary>
public ICoordinateSystem Current => _current;
/// <summary>
/// 初始化/重新检测坐标系
/// </summary>
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}");
}
/// <summary>
/// 自动检测坐标系(基于 Document.UpVector)
/// </summary>
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();
}
}
/// <summary>
/// 手动切换坐标系(用于系统管理界面)
/// </summary>
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}");
}
}
配置文件
# default_config.toml
[coordinate_system]
# 坐标系类型: "AutoDetect"(推荐), "ZUp", "YUp"
# AutoDetect 将使用 Document.UpVector 自动检测
type = "AutoDetect"
系统管理界面
在系统管理页签添加坐标系设置:
<!-- 添加到 SystemManagementView.xaml -->
<ComboBox ItemsSource="{Binding CoordinateSystemOptions}"
SelectedItem="{Binding SelectedCoordinateSystem}"
ToolTip="选择坐标系,AutoDetect 将自动检测"/>
ViewModel 实现:
public ObservableCollection<string> CoordinateSystemOptions { get; } =
new() { "AutoDetect", "ZUp", "YUp" };
public string SelectedCoordinateSystem
{
get => _selectedCoordinateSystem;
set
{
if (SetProperty(ref _selectedCoordinateSystem, value))
{
// 解析并应用新坐标系
if (Enum.TryParse<CoordinateSystemType>(value, out var type))
{
CoordinateSystemManager.Instance.SetCoordinateSystem(type);
LogManager.Info($"坐标系已切换为: {value}");
}
}
}
}
使用流程
场景1: 自动检测成功
- 打开模型
- 插件自动检测
Document.UpVector - 检测到
(0,1,0)→ 自动使用 Y-Up 坐标系 - 用户无感知,功能正常工作
场景2: 自动检测失败(UpVector 为 Zero)
- 打开模型
- 插件检测到
Document.UpVector.IsZero - 回退到默认 Z-Up,记录警告日志
- 用户发现功能异常
- 打开系统管理 → 手动切换坐标系为 Y-Up
- 功能恢复正常
场景3: 用户强制指定
- 用户提前知道模型坐标系
- 在系统管理中设置坐标系为 Y-Up
- 打开模型,直接使用指定坐标系
需要修改的模块
| 模块 | 修改内容 | 优先级 |
|---|---|---|
| CoordinateSystemManager | 新建,实现简化检测逻辑 | P0 |
| ICoordinateSystem | 接口及 ZUp/YUp 实现 | P0 |
| SystemManagementView | 添加坐标系选择下拉框 | P0 |
| GridMap | 使用坐标系抽象 | P1 |
| GridMapGenerator | 垂直扫描方向适配 | P1 |
| 其他模块 | 逐步替换直接坐标访问 | P2 |
实施步骤
阶段1: 核心实现(1周)
- 创建坐标系统抽象层
- 实现简化检测逻辑
- 添加系统管理界面配置
阶段2: 核心模块适配(1周)
- 修改 GridMap 使用坐标系抽象
- 修改 GridMapGenerator
- 测试验证
阶段3: 全面适配(1周)
- 逐步替换其他模块
- 完善测试
- 文档更新
关键代码示例
坐标系抽象接口
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 实现
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 实现
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);
}
优势
- 简单可靠: 基于 API 提供的 UpVector,无需猜测
- 用户可控: 自动检测失败时可手动干预
- 向后兼容: 默认行为不变,不影响现有用户
- 易于维护: 代码简洁,逻辑清晰
文档更新时间: 2026-01-30 版本: 简化版