Separate asset axis conventions from host coordinates

This commit is contained in:
tian 2026-03-22 13:30:35 +08:00
parent 5e7f9bdf51
commit 1802eda971
6 changed files with 123 additions and 84 deletions

View File

@ -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)

View File

@ -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();

View File

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

View File

@ -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
/// </summary>
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
}
}
/// <summary>
/// 从Transform中提取Yaw角度简化版本
/// </summary>
private double GetYawFromTransform(Transform3D transform)
{
try
{
// 使用ModelItemTransformHelper中的方法
return ModelItemTransformHelper.GetYawFromTransform(transform);
}
catch { }
return 0.0;
}
/// <summary>
/// 清理虚拟物体(用于程序退出或切换文档时)
/// </summary>

View File

@ -108,6 +108,33 @@ namespace NavisworksTransport.Utils.CoordinateSystem
}
}
/// <summary>
/// 虚拟物体资源的本地轴约定。
/// 该约定仅描述资源文件本身的 local forward/up不代表当前宿主文档的坐标系。
/// </summary>
public static ModelAxisConvention CreateVirtualObjectAssetConvention()
{
return new ModelAxisConvention(LocalAxisDirection.PositiveX, LocalAxisDirection.PositiveZ);
}
/// <summary>
/// 参考杆资源的本地轴约定。
/// 当前资源约定长度轴沿本地 +X截面 up 沿本地 +Z。
/// </summary>
public static ModelAxisConvention CreateReferenceRodAssetConvention()
{
return new ModelAxisConvention(LocalAxisDirection.PositiveX, LocalAxisDirection.PositiveZ);
}
/// <summary>
/// Rail 资源的本地轴约定。
/// 当前资源约定前进方向沿本地 +X向上沿本地 +Z。
/// </summary>
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);
}
/// <summary>
/// 根据 forward/side/up 语义尺寸,构造资源本地 X/Y/Z 的缩放向量。
/// </summary>
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 &&

View File

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