From 1802eda971df80447d9e647ed4da89e1973c3e25 Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Sun, 22 Mar 2026 13:30:35 +0800
Subject: [PATCH] Separate asset axis conventions from host coordinates
---
.../ModelAxisConventionTests.cs | 34 +++++++
src/Core/Animation/PathAnimationManager.cs | 4 +-
src/Core/AssemblyReferencePathManager.cs | 10 +-
src/Core/VirtualObjectManager.cs | 91 +++----------------
.../CoordinateSystem/ModelAxisConvention.cs | 64 +++++++++++++
src/Utils/RailPathPoseHelper.cs | 4 +-
6 files changed, 123 insertions(+), 84 deletions(-)
diff --git a/UnitTests/CoordinateSystem/ModelAxisConventionTests.cs b/UnitTests/CoordinateSystem/ModelAxisConventionTests.cs
index 74f16e0..8526f21 100644
--- a/UnitTests/CoordinateSystem/ModelAxisConventionTests.cs
+++ b/UnitTests/CoordinateSystem/ModelAxisConventionTests.cs
@@ -59,6 +59,40 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem
AssertColumn(linear, 2, 1, 0, 0);
}
+ [TestMethod]
+ public void ReferenceRodAssetConvention_ShouldUseXForwardAndZUp()
+ {
+ ModelAxisConvention convention = ModelAxisConvention.CreateReferenceRodAssetConvention();
+
+ Assert.AreEqual(LocalAxisDirection.PositiveX, convention.ForwardAxis);
+ Assert.AreEqual(LocalAxisDirection.PositiveZ, convention.UpAxis);
+ Assert.AreEqual(LocalAxisDirection.NegativeY, convention.SideAxis);
+ }
+
+ [TestMethod]
+ public void VirtualObjectAssetConvention_CreateScaleVector_ShouldMapLengthWidthHeightToLocalAxes()
+ {
+ ModelAxisConvention convention = ModelAxisConvention.CreateVirtualObjectAssetConvention();
+
+ var scale = convention.CreateScaleVector3(12.0, 5.0, 7.0);
+
+ Assert.AreEqual(12.0, scale.X, 1e-6);
+ Assert.AreEqual(5.0, scale.Y, 1e-6);
+ Assert.AreEqual(7.0, scale.Z, 1e-6);
+ }
+
+ [TestMethod]
+ public void YUpConvention_CreateScaleVector_ShouldMapUpSizeToLocalY()
+ {
+ ModelAxisConvention convention = ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.YUp);
+
+ var scale = convention.CreateScaleVector3(12.0, 5.0, 7.0);
+
+ Assert.AreEqual(12.0, scale.X, 1e-6);
+ Assert.AreEqual(7.0, scale.Y, 1e-6);
+ Assert.AreEqual(5.0, scale.Z, 1e-6);
+ }
+
private static void AssertColumn(Matrix4x4 matrix, int column, double x, double y, double z)
{
switch (column)
diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs
index 9f75699..dc5978a 100644
--- a/src/Core/Animation/PathAnimationManager.cs
+++ b/src/Core/Animation/PathAnimationManager.cs
@@ -3368,7 +3368,7 @@ namespace NavisworksTransport.Core.Animation
{
if (_isVirtualObject)
{
- return ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp);
+ return ModelAxisConvention.CreateVirtualObjectAssetConvention();
}
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
@@ -3383,7 +3383,7 @@ namespace NavisworksTransport.Core.Animation
{
if (_isVirtualObject)
{
- return ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp);
+ return ModelAxisConvention.CreateVirtualObjectAssetConvention();
}
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
diff --git a/src/Core/AssemblyReferencePathManager.cs b/src/Core/AssemblyReferencePathManager.cs
index 7191415..986604f 100644
--- a/src/Core/AssemblyReferencePathManager.cs
+++ b/src/Core/AssemblyReferencePathManager.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
+using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.Core
{
@@ -15,6 +16,7 @@ namespace NavisworksTransport.Core
public class AssemblyReferencePathManager
{
private const double ReferenceRodBaseSizeInMeters = 0.01;
+ private static readonly ModelAxisConvention ReferenceRodAxisConvention = ModelAxisConvention.CreateReferenceRodAssetConvention();
private static AssemblyReferencePathManager _instance;
private static readonly object _lock = new object();
@@ -220,7 +222,7 @@ namespace NavisworksTransport.Core
var currentTransform = _referenceRodModel.Transform;
var components = currentTransform.Factor();
- components.Scale = new Vector3D(
+ components.Scale = ReferenceRodAxisConvention.CreateScaleVector(
lengthInMeters / ReferenceRodBaseSizeInMeters,
diameterInMeters / ReferenceRodBaseSizeInMeters,
diameterInMeters / ReferenceRodBaseSizeInMeters);
@@ -265,11 +267,11 @@ namespace NavisworksTransport.Core
endPoint.Y - startPoint.Y,
endPoint.Z - startPoint.Z));
- // 参考杆资源约定:几何中心在原点,长度轴沿局部 +X。
+ // 参考杆资源约定:几何中心在原点,长度轴沿本地 ForwardAxis。
// Navisworks API 文档中 Rotation3D(vector1, vector2) 的语义
- // 是“将 vector1 旋转到与 vector2 同方向”,这里直接将本地 X 轴对齐参考线方向。
+ // 是“将 vector1 旋转到与 vector2 同方向”,这里直接将资源本地 forward 轴对齐参考线方向。
return new Rotation3D(
- new UnitVector3D(1, 0, 0),
+ new UnitVector3D(ReferenceRodAxisConvention.ForwardVector),
new UnitVector3D(tangent));
}
diff --git a/src/Core/VirtualObjectManager.cs b/src/Core/VirtualObjectManager.cs
index 2809375..f8e7647 100644
--- a/src/Core/VirtualObjectManager.cs
+++ b/src/Core/VirtualObjectManager.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
+using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.Core
{
@@ -17,6 +18,7 @@ namespace NavisworksTransport.Core
///
public class VirtualObjectManager
{
+ private static readonly ModelAxisConvention VirtualObjectAxisConvention = ModelAxisConvention.CreateVirtualObjectAssetConvention();
private static VirtualObjectManager _instance;
private static readonly object _lock = new object();
@@ -188,62 +190,15 @@ namespace NavisworksTransport.Core
try
{
- var doc = Application.ActiveDocument;
- var modelItems = new ModelItemCollection { _virtualObjectModelItem };
-
- // 获取当前缩放
- var currentTransform = _virtualObjectModelItem.Transform;
- var currentComponents = currentTransform.Factor();
- var currentScale = currentComponents.Scale;
-
- // 重置到CAD原始状态
- doc.Models.ResetPermanentTransform(modelItems);
-
- // 获取CAD原始状态
- var originalBounds = _virtualObjectModelItem.BoundingBox();
- var originalGroundPos = new Point3D(
- originalBounds.Center.X,
- originalBounds.Center.Y,
- originalBounds.Min.Z
- );
- var originalYaw = GetYawFromTransform(_virtualObjectModelItem.Transform);
-
- // 计算增量
- var deltaPos = new Vector3D(
- position.X - originalGroundPos.X,
- position.Y - originalGroundPos.Y,
- position.Z - originalGroundPos.Z
- );
- double deltaYaw = yawRadians - originalYaw;
-
- // 构建变换,保留当前缩放
- var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
- var components = identity.Factor();
- components.Scale = currentScale;
-
- if (Math.Abs(deltaYaw) > 0.001)
- {
- double cos = Math.Cos(deltaYaw);
- double sin = Math.Sin(deltaYaw);
- double rotatedX = originalGroundPos.X * cos - originalGroundPos.Y * sin;
- double rotatedY = originalGroundPos.X * sin + originalGroundPos.Y * cos;
-
- components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
- components.Translation = new Vector3D(
- position.X - rotatedX,
- position.Y - rotatedY,
- deltaPos.Z
- );
- }
- else
- {
- components.Translation = deltaPos;
- }
-
- Transform3D transform = components.Combine();
- doc.Models.OverridePermanentTransform(modelItems, transform, false);
-
- LogManager.Debug($"虚拟物体已移动");
+ var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
+ var hostForward = adapter.FromCanonicalVector(new Vector3D(Math.Cos(yawRadians), Math.Sin(yawRadians), 0));
+ var hostUp = adapter.FromCanonicalVector(new Vector3D(
+ HostCoordinateAdapter.CanonicalUpVector3.X,
+ HostCoordinateAdapter.CanonicalUpVector3.Y,
+ HostCoordinateAdapter.CanonicalUpVector3.Z));
+ var rotation = VirtualObjectAxisConvention.CreateRotation(hostForward, hostUp);
+ MoveVirtualObject(position, rotation);
+ LogManager.Debug($"虚拟物体已按Canonical平面yaw应用完整姿态");
}
catch (Exception ex)
{
@@ -367,16 +322,14 @@ namespace NavisworksTransport.Core
if (_virtualObjectModel == null || _virtualObjectModelItem == null) return;
var doc = Application.ActiveDocument;
- double metersToUnits = Utils.UnitsConverter.GetMetersToUnitsConversionFactor(doc.Units);
-
double baseSizeMeters = 0.01;
- double scaleX = lengthMeters / baseSizeMeters;
- double scaleY = widthMeters / baseSizeMeters;
- double scaleZ = heightMeters / baseSizeMeters;
var currentTransform = _virtualObjectModel.Transform;
var transformComponents = currentTransform.Factor();
- transformComponents.Scale = new Vector3D(scaleX, scaleY, scaleZ);
+ transformComponents.Scale = VirtualObjectAxisConvention.CreateScaleVector(
+ lengthMeters / baseSizeMeters,
+ widthMeters / baseSizeMeters,
+ heightMeters / baseSizeMeters);
Transform3D newTransform = transformComponents.Combine();
doc.Models.SetModelUnitsAndTransform(_virtualObjectModel, _virtualObjectModel.Units, newTransform, false);
@@ -409,20 +362,6 @@ namespace NavisworksTransport.Core
}
}
- ///
- /// 从Transform中提取Yaw角度(简化版本)
- ///
- private double GetYawFromTransform(Transform3D transform)
- {
- try
- {
- // 使用ModelItemTransformHelper中的方法
- return ModelItemTransformHelper.GetYawFromTransform(transform);
- }
- catch { }
- return 0.0;
- }
-
///
/// 清理虚拟物体(用于程序退出或切换文档时)
///
diff --git a/src/Utils/CoordinateSystem/ModelAxisConvention.cs b/src/Utils/CoordinateSystem/ModelAxisConvention.cs
index 7affc79..f1c9fb4 100644
--- a/src/Utils/CoordinateSystem/ModelAxisConvention.cs
+++ b/src/Utils/CoordinateSystem/ModelAxisConvention.cs
@@ -108,6 +108,33 @@ namespace NavisworksTransport.Utils.CoordinateSystem
}
}
+ ///
+ /// 虚拟物体资源的本地轴约定。
+ /// 该约定仅描述资源文件本身的 local forward/up,不代表当前宿主文档的坐标系。
+ ///
+ public static ModelAxisConvention CreateVirtualObjectAssetConvention()
+ {
+ return new ModelAxisConvention(LocalAxisDirection.PositiveX, LocalAxisDirection.PositiveZ);
+ }
+
+ ///
+ /// 参考杆资源的本地轴约定。
+ /// 当前资源约定长度轴沿本地 +X,截面 up 沿本地 +Z。
+ ///
+ public static ModelAxisConvention CreateReferenceRodAssetConvention()
+ {
+ return new ModelAxisConvention(LocalAxisDirection.PositiveX, LocalAxisDirection.PositiveZ);
+ }
+
+ ///
+ /// Rail 资源的本地轴约定。
+ /// 当前资源约定前进方向沿本地 +X,向上沿本地 +Z。
+ ///
+ public static ModelAxisConvention CreateRailAssetConvention()
+ {
+ return new ModelAxisConvention(LocalAxisDirection.PositiveX, LocalAxisDirection.PositiveZ);
+ }
+
public double GetForwardSize(BoundingBox3D bounds)
{
return GetAxisExtent(bounds, ForwardAxis);
@@ -123,6 +150,23 @@ namespace NavisworksTransport.Utils.CoordinateSystem
return GetAxisExtent(bounds, SideAxis);
}
+ ///
+ /// 根据 forward/side/up 语义尺寸,构造资源本地 X/Y/Z 的缩放向量。
+ ///
+ public Vector3D CreateScaleVector(double forwardSize, double sideSize, double upSize)
+ {
+ Vector3 scale = CreateScaleVector3(forwardSize, sideSize, upSize);
+ return new Vector3D(scale.X, scale.Y, scale.Z);
+ }
+
+ public Vector3 CreateScaleVector3(double forwardSize, double sideSize, double upSize)
+ {
+ float scaleX = (float)ResolveLocalAxisScale(0, forwardSize, sideSize, upSize);
+ float scaleY = (float)ResolveLocalAxisScale(1, forwardSize, sideSize, upSize);
+ float scaleZ = (float)ResolveLocalAxisScale(2, forwardSize, sideSize, upSize);
+ return new Vector3(scaleX, scaleY, scaleZ);
+ }
+
private static Vector3 GetAxisVector3(LocalAxisDirection axis)
{
switch (axis)
@@ -203,6 +247,26 @@ namespace NavisworksTransport.Utils.CoordinateSystem
throw new InvalidOperationException("模型局部第三轴不是标准正交轴,无法确定局部轴约定。");
}
+ private double ResolveLocalAxisScale(int localAxisIndex, double forwardSize, double sideSize, double upSize)
+ {
+ if (MatchesAxis(ForwardAxis, localAxisIndex, out _))
+ {
+ return forwardSize;
+ }
+
+ if (MatchesAxis(UpAxis, localAxisIndex, out _))
+ {
+ return upSize;
+ }
+
+ if (MatchesAxis(SideAxis, localAxisIndex, out _))
+ {
+ return sideSize;
+ }
+
+ throw new InvalidOperationException("无法为模型局部轴解析缩放尺寸。");
+ }
+
private static bool IsApproximately(Vector3 vector, double x, double y, double z)
{
return Math.Abs(vector.X - x) < 1e-6 &&
diff --git a/src/Utils/RailPathPoseHelper.cs b/src/Utils/RailPathPoseHelper.cs
index c668a4d..82b507c 100644
--- a/src/Utils/RailPathPoseHelper.cs
+++ b/src/Utils/RailPathPoseHelper.cs
@@ -168,7 +168,7 @@ namespace NavisworksTransport.Utils
previousPoint,
currentPoint,
nextPoint,
- ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp),
+ ModelAxisConvention.CreateRailAssetConvention(),
out linearTransform);
}
@@ -247,7 +247,7 @@ namespace NavisworksTransport.Utils
previousPoint,
currentPoint,
nextPoint,
- ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp),
+ ModelAxisConvention.CreateRailAssetConvention(),
out rotation);
}