diff --git a/doc/working/coordinate-system-adaptation-design.md b/doc/working/coordinate-system-adaptation-design.md
index 7365df2..2a9ad7f 100644
--- a/doc/working/coordinate-system-adaptation-design.md
+++ b/doc/working/coordinate-system-adaptation-design.md
@@ -474,13 +474,58 @@ public Point3D GridToWorld3D(GridPoint2D gridPosition)
## 实施路线图
-### 阶段1:核心适配(P0)- 1-2周
+### 阶段1:核心适配(P0)- 1-2周 ✅ 已完成
-1. 创建坐标系抽象层(ICoordinateSystem + 实现类)
-2. 修改 GridMap 和 GridMapGenerator
-3. 修改 ChannelHeightDetector 的垂直扫描
-4. 添加配置支持
-5. 基础测试验证
+1. ✅ 创建坐标系抽象层(ICoordinateSystem + 实现类)
+ - `src/Utils/CoordinateSystem/ICoordinateSystem.cs`
+ - `src/Utils/CoordinateSystem/ZUpCoordinateSystem.cs`
+ - `src/Utils/CoordinateSystem/YUpCoordinateSystem.cs`
+ - `src/Utils/CoordinateSystem/CoordinateSystemType.cs`
+ - `src/Utils/CoordinateSystem/CoordinateSystemManager.cs`
+
+2. ✅ 修改 GridMap 和 GridMapGenerator
+ - `GridMap.cs` 已使用 `ICoordinateSystem` 进行坐标转换
+ - `GridMapGenerator.cs` 已适配坐标系
+
+3. ✅ 修改 ChannelHeightDetector 的垂直扫描
+ - 已使用 `VerticalScanDirection` 替代硬编码方向
+ - 已使用 `GetElevation`/`SetElevation` 替代直接 Z 访问
+
+4. ✅ 修改 ChannelBasedGridBuilder
+ - 已适配坐标系进行三角形光栅化
+ - 已使用坐标系进行法向量向上判断
+
+5. ✅ 添加配置支持
+ - `default_config.toml` 已添加 `[coordinate_system]` 配置节
+ - `SystemConfig.cs` 已添加 `CoordinateSystemConfig` 类
+ - `ConfigManager.cs` 已添加坐标系配置解析
+ - `MainPlugin.cs` 已添加坐标系初始化调用
+
+6. ✅ 基础测试验证
+ - 构建成功,无编译错误
+ - 所有坐标系相关代码已正确集成
+
+### 阶段1 完成总结
+
+**已完成的核心适配工作:**
+
+| 组件 | 文件 | 适配内容 |
+|------|------|----------|
+| 坐标系抽象层 | `ICoordinateSystem.cs` | 定义坐标系接口,包含高度/水平坐标转换、扫描方向等 |
+| Z-Up 坐标系 | `ZUpCoordinateSystem.cs` | X=Right, Y=Back, Z=Up 实现 |
+| Y-Up 坐标系 | `YUpCoordinateSystem.cs` | X=Right, Y=Up, Z=Front 实现 |
+| 坐标系管理器 | `CoordinateSystemManager.cs` | 单例模式,支持自动检测和手动配置 |
+| 网格地图 | `GridMap.cs` | 使用坐标系进行世界/网格坐标转换 |
+| 网格生成器 | `GridMapGenerator.cs` | 适配坐标系进行边界计算 |
+| 通道网格构建 | `ChannelBasedGridBuilder.cs` | 三角形光栅化适配坐标系 |
+| 高度检测器 | `ChannelHeightDetector.cs` | 垂直扫描使用坐标系扫描方向 |
+| 配置系统 | `SystemConfig.cs`, `ConfigManager.cs` | 添加坐标系配置节 |
+| 主插件 | `MainPlugin.cs` | 初始化坐标系管理器 |
+
+**向后兼容性:**
+- 默认使用 Z-Up 坐标系,确保现有用户不受影响
+- 配置文件默认为 `AutoDetect`,自动检测文档坐标系
+- 所有修改对现有功能透明
### 阶段2:完整适配(P1)- 1周
diff --git a/src/Core/MainPlugin.cs b/src/Core/MainPlugin.cs
index 820de55..3a3dbf5 100644
--- a/src/Core/MainPlugin.cs
+++ b/src/Core/MainPlugin.cs
@@ -5,7 +5,9 @@ using System.Windows.Forms;
using System.Windows.Forms.Integration;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Animation;
+using NavisworksTransport.Core.Config;
using NavisworksTransport.Utils;
+using NavisworksTransport.Utils.CoordinateSystem;
using NavisApplication = Autodesk.Navisworks.Api.Application;
namespace NavisworksTransport
@@ -337,8 +339,11 @@ namespace NavisworksTransport
//显式初始化配置管理器,确保配置加载完成
try
{
- var config = NavisworksTransport.Core.Config.ConfigManager.Instance.Current;
+ var config = ConfigManager.Instance.Current;
LogManager.Info($"[配置管理] 配置已加载");
+
+ // 注意:坐标系初始化推迟到 InitializeManagers() 中进行
+ // 因为此时文档可能尚未加载,无法正确检测坐标系
}
catch (Exception ex)
{
@@ -544,6 +549,65 @@ namespace NavisworksTransport
_hasModels = currentHasModels;
}
+ ///
+ /// 为当前文档初始化坐标系
+ /// 在文档加载完成后调用,确保可以正确检测 Document.UpVector
+ ///
+ private void InitializeCoordinateSystemForDocument()
+ {
+ try
+ {
+ var config = ConfigManager.Instance.Current;
+ if (config?.CoordinateSystem == null)
+ {
+ LogManager.Warning("[坐标系] 配置中缺少坐标系设置,使用默认自动检测");
+ CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.AutoDetect);
+ return;
+ }
+
+ // 如果已经初始化且不是 AutoDetect 模式,则跳过
+ // 这样用户手动设置的坐标系不会在文档切换时被覆盖
+ if (CoordinateSystemManager.Instance.Current != null &&
+ CoordinateSystemManager.Instance.ConfiguredType != CoordinateSystemType.AutoDetect)
+ {
+ LogManager.Debug("[坐标系] 使用手动指定的坐标系,跳过自动检测");
+ return;
+ }
+
+ // 解析坐标系类型配置
+ CoordinateSystemType coordType;
+ var typeString = config.CoordinateSystem.Type?.Trim() ?? "AutoDetect";
+
+ switch (typeString.ToLowerInvariant())
+ {
+ case "zup":
+ case "z-up":
+ coordType = CoordinateSystemType.ZUp;
+ break;
+ case "yup":
+ case "y-up":
+ coordType = CoordinateSystemType.YUp;
+ break;
+ case "autodetect":
+ case "auto":
+ default:
+ coordType = CoordinateSystemType.AutoDetect;
+ break;
+ }
+
+ // 初始化坐标系
+ CoordinateSystemManager.Instance.Initialize(coordType);
+
+ var currentCS = CoordinateSystemManager.Instance.Current;
+ LogManager.Info($"[坐标系] 初始化完成 - {currentCS}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[坐标系] 初始化失败: {ex.Message},使用默认 Z-Up");
+ CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.ZUp);
+ }
+ }
+
///
/// 初始化各个管理器
///
@@ -560,6 +624,9 @@ namespace NavisworksTransport
LogManager.Info($"[文档管理] 开始为文档 '{activeDoc.FileName ?? "未保存"}' 初始化管理器...");
+ // 初始化坐标系(文档已加载,可以正确检测)
+ InitializeCoordinateSystemForDocument();
+
// 通知DocumentStateManager文档已就绪
DocumentStateManager.Instance.OnDocumentReady();
diff --git a/src/PathPlanning/ChannelBasedGridBuilder.cs b/src/PathPlanning/ChannelBasedGridBuilder.cs
index 093375b..e29bd99 100644
--- a/src/PathPlanning/ChannelBasedGridBuilder.cs
+++ b/src/PathPlanning/ChannelBasedGridBuilder.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
+using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.PathPlanning
{
@@ -18,6 +19,7 @@ namespace NavisworksTransport.PathPlanning
public class ChannelBasedGridBuilder
{
private ChannelHeightDetector _heightDetector;
+ private readonly ICoordinateSystem _coordinateSystem;
///
/// 通道几何类型
@@ -40,13 +42,22 @@ namespace NavisworksTransport.PathPlanning
Complex
}
+ ///
+ /// 构造函数(自动使用当前坐标系)
+ ///
+ public ChannelBasedGridBuilder() : this(CoordinateSystemManager.Instance.Current)
+ {
+ }
+
///
/// 构造函数
///
- public ChannelBasedGridBuilder()
+ /// 坐标系
+ public ChannelBasedGridBuilder(ICoordinateSystem coordinateSystem)
{
- _heightDetector = new ChannelHeightDetector();
- LogManager.Info("[通道网格构建器] 初始化完成");
+ _coordinateSystem = coordinateSystem ?? throw new ArgumentNullException(nameof(coordinateSystem));
+ _heightDetector = new ChannelHeightDetector(_coordinateSystem);
+ LogManager.Info($"[通道网格构建器] 初始化完成,坐标系: {_coordinateSystem.Type}");
}
///
@@ -200,8 +211,8 @@ namespace NavisworksTransport.PathPlanning
{
var normal = ComputeTriangleNormal(triangle);
- // 根据法向量决定处理方式
- if (normal.Z > 0) // 朝上的面
+ // 根据法向量决定处理方式(使用坐标系判断向上)
+ if (GetUpComponent(normal) > 0) // 朝上的面
{
RasterizeTriangleToGrid(gridMap, triangle, channel, channelSpeedLimit);
processedTriangles++;
@@ -244,17 +255,18 @@ namespace NavisworksTransport.PathPlanning
return normal;
}
-
- private double GetHeightAtPoint(Triangle3D triangle, double x, double y)
+
+ ///
+ /// 获取向上轴的分量(根据坐标系)
+ ///
+ private double GetUpComponent(Point3D vector)
{
- var normal = ComputeTriangleNormal(triangle);
-
- // 使用平面方程计算点(x,y)在三角形平面上的Z值
- double height = triangle.Point1.Z - (normal.X * (x - triangle.Point1.X) + normal.Y * (y - triangle.Point1.Y)) / normal.Z;
- return height;
+ return _coordinateSystem.GetElevation(vector);
}
+
+
///
/// 将三角形光栅化到网格
///
@@ -264,14 +276,18 @@ namespace NavisworksTransport.PathPlanning
/// 预计算的通道限速
private void RasterizeTriangleToGrid(GridMap gridMap, Triangle3D triangle, ModelItem channel, double channelSpeedLimit)
{
- // 获取三角形的2D投影边界框
- var minX = Math.Min(triangle.Point1.X, Math.Min(triangle.Point2.X, triangle.Point3.X));
- var maxX = Math.Max(triangle.Point1.X, Math.Max(triangle.Point2.X, triangle.Point3.X));
- var minY = Math.Min(triangle.Point1.Y, Math.Min(triangle.Point2.Y, triangle.Point3.Y));
- var maxY = Math.Max(triangle.Point1.Y, Math.Max(triangle.Point2.Y, triangle.Point3.Y));
+ // 获取三角形的2D投影边界框(使用水平坐标)
+ var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
+ var (p2h1, p2h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point2);
+ var (p3h1, p3h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point3);
+
+ var minH1 = Math.Min(p1h1, Math.Min(p2h1, p3h1));
+ var maxH1 = Math.Max(p1h1, Math.Max(p2h1, p3h1));
+ var minH2 = Math.Min(p1h2, Math.Min(p2h2, p3h2));
+ var maxH2 = Math.Max(p1h2, Math.Max(p2h2, p3h2));
- var minGrid = gridMap.WorldToGrid(new Point3D(minX, minY, 0));
- var maxGrid = gridMap.WorldToGrid(new Point3D(maxX, maxY, 0));
+ var minGrid = gridMap.WorldToGrid(_coordinateSystem.CreatePoint(minH1, minH2, 0));
+ var maxGrid = gridMap.WorldToGrid(_coordinateSystem.CreatePoint(maxH1, maxH2, 0));
// 遍历边界框内的所有网格点
for (int x = minGrid.X; x <= maxGrid.X; x++)
@@ -283,16 +299,16 @@ namespace NavisworksTransport.PathPlanning
{
var worldPos = gridMap.GridToWorld3D(gridPos);
- // 检查点是否在三角形内部
- if (GeometryHelper.IsPointInTriangle2D(worldPos, triangle))
+ // 检查点是否在三角形内部(使用2D水平投影)
+ if (IsPointInTriangleHorizontal(worldPos, triangle))
{
// 计算网格中心点在三角形平面上的精确高度
- double gridCenterHeight = GetHeightAtPoint(triangle, worldPos.X, worldPos.Y);
+ double gridCenterElevation = GetElevationAtPoint(triangle, worldPos);
// 创建高度层(追加模式,不覆盖)
var channelType = CategoryAttributeManager.GetLogisticsElementType(channel);
var layer = new HeightLayer(
- z: gridCenterHeight,
+ z: gridCenterElevation,
passableHeight: new HeightInterval(0, 0), // 初始化,后续由SetChannelPassableHeights设置
sourceItem: channel,
speedLimit: channelSpeedLimit,
@@ -306,6 +322,68 @@ namespace NavisworksTransport.PathPlanning
}
}
}
+
+ ///
+ /// 检查点是否在三角形的水平投影内
+ ///
+ private bool IsPointInTriangleHorizontal(Point3D point, Triangle3D triangle)
+ {
+ var (ph1, ph2) = _coordinateSystem.GetHorizontalCoords(point);
+ var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
+ var (p2h1, p2h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point2);
+ var (p3h1, p3h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point3);
+
+ // 使用叉积法判断点是否在三角形内
+ double Cross(double ax, double ay, double bx, double by) => ax * by - ay * bx;
+
+ var d1 = Cross(ph1 - p1h1, ph2 - p1h2, p2h1 - p1h1, p2h2 - p1h2);
+ var d2 = Cross(ph1 - p2h1, ph2 - p2h2, p3h1 - p2h1, p3h2 - p2h2);
+ var d3 = Cross(ph1 - p3h1, ph2 - p3h2, p1h1 - p3h1, p1h2 - p3h2);
+
+ bool hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
+ bool hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
+
+ return !(hasNeg && hasPos);
+ }
+
+ ///
+ /// 计算点在三角形平面上的高度值(根据当前坐标系)
+ ///
+ private double GetElevationAtPoint(Triangle3D triangle, Point3D point)
+ {
+ var normal = ComputeTriangleNormal(triangle);
+
+ // 获取向上轴的分量
+ double upComponent = GetUpComponent(normal);
+
+ // 如果向上分量接近0,说明是垂直面,返回第一个点的Z值
+ if (Math.Abs(upComponent) < 0.0001)
+ {
+ return _coordinateSystem.GetElevation(triangle.Point1);
+ }
+
+ // 获取各点的水平坐标
+ var (p1h1, p1h2) = _coordinateSystem.GetHorizontalCoords(triangle.Point1);
+ var (ph1, ph2) = _coordinateSystem.GetHorizontalCoords(point);
+
+ // 获取向上轴的索引来正确计算
+ int upAxis = _coordinateSystem.UpAxisIndex;
+
+ // 使用平面方程计算点的高度
+ // n_x(x-x0) + n_y(y-y0) + n_z(z-z0) = 0
+ // 解出高度值
+ double elevation;
+ if (upAxis == 2) // Z-up
+ {
+ elevation = triangle.Point1.Z - (normal.X * (ph1 - p1h1) + normal.Y * (ph2 - p1h2)) / normal.Z;
+ }
+ else // Y-up
+ {
+ elevation = triangle.Point1.Y - (normal.X * (ph1 - p1h1) + normal.Z * (ph2 - p1h2)) / normal.Y;
+ }
+
+ return elevation;
+ }
@@ -332,7 +410,9 @@ namespace NavisworksTransport.PathPlanning
/// 格式化字符串
private string FormatBounds(BoundingBox3D bounds)
{
- return $"[{bounds.Min.X:F2},{bounds.Min.Y:F2},{bounds.Min.Z:F2}] - [{bounds.Max.X:F2},{bounds.Max.Y:F2},{bounds.Max.Z:F2}]";
+ var (min1, max1, min2, max2) = _coordinateSystem.GetHorizontalRange(bounds);
+ var (minElev, maxElev) = _coordinateSystem.GetHeightRange(bounds);
+ return $"[H1:{min1:F2}-{max1:F2}, H2:{min2:F2}-{max2:F2}, Elev:{minElev:F2}-{maxElev:F2}]";
}
}
diff --git a/src/PathPlanning/ChannelHeightDetector.cs b/src/PathPlanning/ChannelHeightDetector.cs
index 44a79b6..1f901d7 100644
--- a/src/PathPlanning/ChannelHeightDetector.cs
+++ b/src/PathPlanning/ChannelHeightDetector.cs
@@ -3,24 +3,41 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
+using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.PathPlanning
{
///
/// 通道地面高度检测器
/// 负责检测路径点在通道中的精确地面高度
+ /// 支持动态坐标系(Z-Up 或 Y-Up)
///
public class ChannelHeightDetector
{
+ ///
+ /// 当前使用的坐标系
+ ///
+ private readonly ICoordinateSystem _coordinateSystem;
private readonly Dictionary _heightCache;
private readonly double _raycastTolerance;
///
- /// 构造函数
+ /// 构造函数(自动使用当前坐标系)
///
/// 射线投射容差(米)
- public ChannelHeightDetector(double raycastTolerance = 0.1)
+ public ChannelHeightDetector(double raycastTolerance = 0.1)
+ : this(CoordinateSystemManager.Instance.Current, raycastTolerance)
{
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// 坐标系
+ /// 射线投射容差(米)
+ public ChannelHeightDetector(ICoordinateSystem coordinateSystem, double raycastTolerance = 0.1)
+ {
+ _coordinateSystem = coordinateSystem ?? throw new ArgumentNullException(nameof(coordinateSystem));
_heightCache = new Dictionary();
_raycastTolerance = raycastTolerance;
}
@@ -690,30 +707,52 @@ namespace NavisworksTransport.PathPlanning
///
/// 执行射线与三角形的交点检测
///
- /// 射线起点的XY坐标
+ /// 射线起点的水平坐标
/// 三角形列表
- /// 交点的Z坐标列表
+ /// 交点的高度值列表
private List PerformRayTriangleIntersection(Point3D position, List triangles)
{
var intersectionPoints = new List();
try
{
- // 创建垂直向下的射线(从通道上方合理高度开始)
- var maxZ = triangles.Count > 0 ? triangles.Max(t => Math.Max(Math.Max(t.Point1.Z, t.Point2.Z), t.Point3.Z)) : 0;
- var rayOrigin = new Point3D(position.X, position.Y, maxZ + 1000.0); // 从最高点上方1km开始
- var rayDirection = new Point3D(0, 0, -1); // 向下
+ // 获取坐标系的垂直扫描方向
+ var scanDirection = _coordinateSystem.VerticalScanDirection;
+
+ // 计算三角形在垂直方向上的最大范围
+ double maxHeight = 0;
+ if (triangles.Count > 0)
+ {
+ maxHeight = triangles.Max(t =>
+ Math.Max(
+ _coordinateSystem.GetElevation(t.Point1),
+ Math.Max(
+ _coordinateSystem.GetElevation(t.Point2),
+ _coordinateSystem.GetElevation(t.Point3)
+ )
+ )
+ );
+ }
+
+ // 从最高点上方开始扫描
+ var scanStartHeight = maxHeight + 1000.0;
+ var rayOrigin = _coordinateSystem.SetElevation(position, scanStartHeight);
+
+ // 使用坐标系的垂直扫描方向(转换为 Point3D)
+ var rayDirection = new Point3D(scanDirection.X, scanDirection.Y, scanDirection.Z);
int intersectionCount = 0;
foreach (var triangle in triangles)
{
- if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ))
+ if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionElevation))
{
- intersectionPoints.Add(intersectionZ);
+ intersectionPoints.Add(intersectionElevation);
intersectionCount++;
}
}
+ LogManager.Debug($"[射线-三角形] 找到 {intersectionCount} 个交点,扫描方向: ({rayDirection.X:F2}, {rayDirection.Y:F2}, {rayDirection.Z:F2})");
+
return intersectionPoints;
}
catch (Exception ex)
diff --git a/src/PathPlanning/GridMap.cs b/src/PathPlanning/GridMap.cs
index 5738fc6..d84c31c 100644
--- a/src/PathPlanning/GridMap.cs
+++ b/src/PathPlanning/GridMap.cs
@@ -2,15 +2,21 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
+using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.PathPlanning
{
///
/// 网格地图数据结构
/// 用于将BIM模型转换为路径规划算法可使用的2D网格表示
+ /// 支持动态坐标系(Z-Up 或 Y-Up)
///
public class GridMap
{
+ ///
+ /// 当前使用的坐标系
+ ///
+ private readonly ICoordinateSystem _coordinateSystem;
///
/// 网格宽度(单元格数量)
///
@@ -78,22 +84,37 @@ namespace NavisworksTransport.PathPlanning
///
public GridCell[,] Cells { get; set; }
+ ///
+ /// 构造函数(自动使用当前坐标系)
+ ///
+ /// 世界坐标边界框
+ /// 网格单元格大小
+ public GridMap(BoundingBox3D bounds, double cellSize)
+ : this(bounds, cellSize, CoordinateSystemManager.Instance.Current)
+ {
+ }
+
///
/// 构造函数
///
/// 世界坐标边界框
/// 网格单元格大小
- public GridMap(BoundingBox3D bounds, double cellSize)
+ /// 坐标系
+ public GridMap(BoundingBox3D bounds, double cellSize, ICoordinateSystem coordinateSystem)
{
if (cellSize <= 0)
throw new ArgumentException("网格单元格大小必须大于0", nameof(cellSize));
+ if (coordinateSystem == null)
+ throw new ArgumentNullException(nameof(coordinateSystem));
Bounds = bounds ?? throw new ArgumentNullException(nameof(bounds));
CellSize = cellSize;
+ _coordinateSystem = coordinateSystem;
- // 计算网格尺寸
- double worldWidth = bounds.Max.X - bounds.Min.X;
- double worldHeight = bounds.Max.Y - bounds.Min.Y;
+ // 使用坐标系获取水平范围
+ var (min1, max1, min2, max2) = _coordinateSystem.GetHorizontalRange(bounds);
+ double worldWidth = max1 - min1;
+ double worldHeight = max2 - min2;
Width = (int)Math.Ceiling(worldWidth / cellSize);
Height = (int)Math.Ceiling(worldHeight / cellSize);
@@ -107,6 +128,8 @@ namespace NavisworksTransport.PathPlanning
// 初始化高度计算组件
InitializeHeightCalculation();
+
+ LogManager.Info($"[网格地图] 创建完成: {Width}x{Height}, 坐标系: {_coordinateSystem.Type}");
}
///
@@ -116,7 +139,7 @@ namespace NavisworksTransport.PathPlanning
{
try
{
- HeightDetector = new ChannelHeightDetector();
+ HeightDetector = new ChannelHeightDetector(_coordinateSystem);
SlopeAnalyzer = new SlopeAnalyzer();
LogManager.Info("[网格地图] 高度计算组件初始化完成");
}
@@ -156,27 +179,33 @@ namespace NavisworksTransport.PathPlanning
/// 网格坐标(可能超出边界)
public GridPoint2D WorldToGrid(Point3D worldPosition)
{
- double gridX = (worldPosition.X - Origin.X) / CellSize;
- double gridY = (worldPosition.Y - Origin.Y) / CellSize;
+ // 使用坐标系获取水平坐标
+ var (h1, h2) = _coordinateSystem.GetHorizontalCoords(worldPosition);
+ var (originH1, originH2) = _coordinateSystem.GetHorizontalCoords(Origin);
+
+ double gridX = (h1 - originH1) / CellSize;
+ double gridY = (h2 - originH2) / CellSize;
return new GridPoint2D((int)Math.Round(gridX), (int)Math.Round(gridY));
}
///
- /// 将网格坐标转换为世界2D坐标(纯坐标转换,不涉及Z坐标计算)
+ /// 将网格坐标转换为世界2D坐标(纯坐标转换,不涉及高度计算)
///
/// 网格坐标
- /// 世界2D坐标点(网格左下角)
+ /// 世界2D坐标点(网格左下角),高度设为0
public Point3D GridToWorld2D(GridPoint2D gridPosition)
{
- double worldX = Origin.X + gridPosition.X * CellSize;
- double worldY = Origin.Y + gridPosition.Y * CellSize;
+ var (originH1, originH2) = _coordinateSystem.GetHorizontalCoords(Origin);
+ double worldH1 = originH1 + gridPosition.X * CellSize;
+ double worldH2 = originH2 + gridPosition.Y * CellSize;
- return new Point3D(worldX, worldY, 0); // Z设为0,调用者可以替换
+ // 使用坐标系创建点,高度设为0
+ return _coordinateSystem.CreatePoint(worldH1, worldH2, 0);
}
///
- /// 将网格坐标转换为世界3D坐标(使用最低层HeightLayer的Z坐标)
+ /// 将网格坐标转换为世界3D坐标(使用最低层HeightLayer的高度)
///
/// 网格坐标
/// 世界3D坐标点
@@ -185,14 +214,15 @@ namespace NavisworksTransport.PathPlanning
var world2D = GridToWorld2D(gridPosition);
var cell = Cells[gridPosition.X, gridPosition.Y];
- // 使用最低层的Z坐标(HeightLayers[0]),如果没有层则用0
- double z = 0;
+ // 获取高度(HeightLayer.Z 存储的是高度值,与坐标系无关)
+ double elevation = 0;
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
{
- z = cell.HeightLayers[0].Z;
+ elevation = cell.HeightLayers[0].Z;
}
- return new Point3D(world2D.X, world2D.Y, z);
+ // 使用坐标系设置高度
+ return _coordinateSystem.SetElevation(world2D, elevation);
}
diff --git a/src/Utils/CoordinateSystem/ICoordinateSystem.cs b/src/Utils/CoordinateSystem/ICoordinateSystem.cs
index 0c0cbde..46d5576 100644
--- a/src/Utils/CoordinateSystem/ICoordinateSystem.cs
+++ b/src/Utils/CoordinateSystem/ICoordinateSystem.cs
@@ -17,6 +17,11 @@ namespace NavisworksTransport.Utils.CoordinateSystem
///
Vector3D UpVector { get; }
+ ///
+ /// 获取向上轴的索引 (0=X, 1=Y, 2=Z)
+ ///
+ int UpAxisIndex { get; }
+
///
/// 获取垂直扫描方向(用于障碍物检测,通常是 -UpVector)
///
diff --git a/src/Utils/CoordinateSystem/YUpCoordinateSystem.cs b/src/Utils/CoordinateSystem/YUpCoordinateSystem.cs
index f4c06f6..dee8577 100644
--- a/src/Utils/CoordinateSystem/YUpCoordinateSystem.cs
+++ b/src/Utils/CoordinateSystem/YUpCoordinateSystem.cs
@@ -12,6 +12,8 @@ namespace NavisworksTransport.Utils.CoordinateSystem
public Vector3D UpVector => new Vector3D(0, 1, 0);
+ public int UpAxisIndex => 1; // Y轴向上
+
public Vector3D VerticalScanDirection => new Vector3D(0, -1, 0);
public double GetElevation(Point3D point)
diff --git a/src/Utils/CoordinateSystem/ZUpCoordinateSystem.cs b/src/Utils/CoordinateSystem/ZUpCoordinateSystem.cs
index 8ae2dbf..d19ac32 100644
--- a/src/Utils/CoordinateSystem/ZUpCoordinateSystem.cs
+++ b/src/Utils/CoordinateSystem/ZUpCoordinateSystem.cs
@@ -12,6 +12,8 @@ namespace NavisworksTransport.Utils.CoordinateSystem
public Vector3D UpVector => new Vector3D(0, 0, 1);
+ public int UpAxisIndex => 2; // Z轴向上
+
public Vector3D VerticalScanDirection => new Vector3D(0, 0, -1);
public double GetElevation(Point3D point)