NavisworksTransport/doc/working/coordinate-system-adaptation-design-simplified.md

8.9 KiB
Raw Blame History

坐标系动态适配设计方案(简化版)

问题背景

客户模型坐标系与插件默认坐标系不同:

  • 插件默认: 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: 自动检测成功

  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. 文档更新

关键代码示例

坐标系抽象接口

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);
}

优势

  1. 简单可靠: 基于 API 提供的 UpVector无需猜测
  2. 用户可控: 自动检测失败时可手动干预
  3. 向后兼容: 默认行为不变,不影响现有用户
  4. 易于维护: 代码简洁,逻辑清晰

文档更新时间: 2026-01-30 版本: 简化版