From 7c4783dca6f33ecb51fe1ab8bb6ca140db3976cb Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 5 Aug 2026 23:53:39 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86=20fragment=20?= =?UTF-8?q?=E5=8F=82=E8=80=83=E5=A7=BF=E6=80=81=E6=AE=8B=E7=95=99=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=880.18.2=20=E9=BB=98=E8=AE=A4=E8=BD=B4=E7=BA=A6?= =?UTF-8?q?=E5=AE=9A=E5=90=8E=E7=9A=84=E6=AD=BB=E4=BB=A3=E7=A0=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除: - RealObjectReferencePoseResolver: TryResolveFromModelItem / TryResolveFromFragmentMatrices (fragment 代表姿态解析链,已无调用者;保留诊断用 TryDetectDefaultUpAxis) - RealObjectReferencePose.cs(无引用死文件) - PathAnimationManager: _realObjectReferenceHostSemantic* 字段(无消费) - FragmentRepresentativePoseHelper: TryGetRepresentativeRotation(ModelItem/矩阵集合) 与 TryInterpretRepresentativeFrame(仅死链使用;保留诊断用 TryGetRepresentativeFrame) - 测试:RealObjectReferencePoseResolverTests(测死链)、 FragmentRepresentativePoseHelperTests 缩减至在用方法 保留(非残留): - GeometryHelper/GeometryCacheManager fragment(几何三角形生成) - FragmentDefaultUpContext / RealObjectRailAxisConventionResolver(在用) - TestAutomationHttpService(集成测试服务) 验证:单元测试 187/187、集成真实物体动画 3/3、F1 Rail+42" Completed --- NavisworksTransport.UnitTests.csproj | 1 - TransportPlugin.csproj | 1 - .../FragmentRepresentativePoseHelperTests.cs | 108 +------ .../RealObjectReferencePoseResolverTests.cs | 160 ---------- src/Core/Animation/PathAnimationManager.cs | 9 - .../FragmentRepresentativePoseHelper.cs | 141 +------- .../RealObjectReferencePose.cs | 67 ---- .../RealObjectReferencePoseResolver.cs | 302 +----------------- 8 files changed, 22 insertions(+), 767 deletions(-) delete mode 100644 UnitTests/CoordinateSystem/RealObjectReferencePoseResolverTests.cs delete mode 100644 src/Utils/CoordinateSystem/RealObjectReferencePose.cs diff --git a/NavisworksTransport.UnitTests.csproj b/NavisworksTransport.UnitTests.csproj index 7068f09..5c6b277 100644 --- a/NavisworksTransport.UnitTests.csproj +++ b/NavisworksTransport.UnitTests.csproj @@ -103,7 +103,6 @@ - diff --git a/TransportPlugin.csproj b/TransportPlugin.csproj index 958e086..96c805d 100644 --- a/TransportPlugin.csproj +++ b/TransportPlugin.csproj @@ -364,7 +364,6 @@ - diff --git a/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs b/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs index 751eba4..cea12c2 100644 --- a/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs +++ b/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using NavisworksTransport.Utils.CoordinateSystem; -using System; using System.Numerics; namespace NavisworksTransport.UnitTests.CoordinateSystem @@ -8,71 +7,6 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem [TestClass] public class FragmentRepresentativePoseHelperTests { - [TestMethod] - public void ShouldAverageFragmentMatrices_AndIgnoreTranslation() - { - Quaternion expectedRotation = Quaternion.Normalize( - Quaternion.CreateFromAxisAngle(Vector3.UnitZ, (float)(Math.PI / 6.0))); - - double[] fragmentMatrix1 = CreateFragmentMatrix(expectedRotation, new Vector3(10.0f, 20.0f, 30.0f)); - double[] fragmentMatrix2 = CreateFragmentMatrix(expectedRotation, new Vector3(-3.0f, 8.0f, 1.0f)); - - bool ok = FragmentRepresentativePoseHelper.TryGetRepresentativeRotation( - new[] { fragmentMatrix1, fragmentMatrix2 }, - out Quaternion representativeRotation); - - Assert.IsTrue(ok); - AssertVector( - Vector3.Transform(Vector3.UnitX, representativeRotation), - Vector3.Transform(Vector3.UnitX, expectedRotation), - 1e-4); - AssertVector( - Vector3.Transform(Vector3.UnitY, representativeRotation), - Vector3.Transform(Vector3.UnitY, expectedRotation), - 1e-4); - AssertVector( - Vector3.Transform(Vector3.UnitZ, representativeRotation), - Vector3.Transform(Vector3.UnitZ, expectedRotation), - 1e-4); - } - - [TestMethod] - public void ShouldIgnoreQuaternionSignWhenAveragingFragments() - { - Quaternion expectedRotation = Quaternion.Normalize( - Quaternion.CreateFromAxisAngle(Vector3.UnitX, (float)(Math.PI / 4.0))); - Quaternion oppositeSignRotation = new Quaternion( - -expectedRotation.X, - -expectedRotation.Y, - -expectedRotation.Z, - -expectedRotation.W); - - bool ok = FragmentRepresentativePoseHelper.TryGetRepresentativeRotation( - new[] { expectedRotation, oppositeSignRotation }, - out Quaternion representativeRotation); - - Assert.IsTrue(ok); - AssertVector( - Vector3.Transform(Vector3.UnitY, representativeRotation), - Vector3.Transform(Vector3.UnitY, expectedRotation), - 1e-4); - AssertVector( - Vector3.Transform(Vector3.UnitZ, representativeRotation), - Vector3.Transform(Vector3.UnitZ, expectedRotation), - 1e-4); - } - - [TestMethod] - public void ShouldFail_WhenNoFragmentRotationsAreAvailable() - { - bool ok = FragmentRepresentativePoseHelper.TryGetRepresentativeRotation( - Array.Empty(), - out Quaternion representativeRotation); - - Assert.IsFalse(ok); - Assert.AreEqual(Quaternion.Identity, representativeRotation); - } - [TestMethod] public void ShouldPreserveAxes_ForObservedYUpRealObjectFragmentBasis() { @@ -126,47 +60,11 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem AssertVector(Vector3.Transform(Vector3.UnitZ, frame.Rotation), axisZ, 1e-4); } - [TestMethod] - public void TryInterpretRepresentativeFrame_YUpHost_WithFragmentDefaultUpZ_ShouldMapZToHostY() - { - var raw = new FragmentRepresentativePoseHelper.RepresentativeFrame( - new Vector3(1.0f, 0.0f, 0.0f), - new Vector3(0.0f, 0.0f, -1.0f), - new Vector3(0.0f, 1.0f, 0.0f), - Quaternion.Identity); - - bool ok = FragmentRepresentativePoseHelper.TryInterpretRepresentativeFrame( - raw, - "Z", - "Y", - out var interpreted); - - Assert.IsTrue(ok); - AssertVector(interpreted.AxisX, new Vector3(1.0f, 0.0f, 0.0f), 1e-4); - AssertVector(interpreted.AxisY, new Vector3(0.0f, 1.0f, 0.0f), 1e-4); - AssertVector(interpreted.AxisZ, new Vector3(0.0f, 0.0f, 1.0f), 1e-4); - } - - private static double[] CreateFragmentMatrix(Quaternion rotation, Vector3 translation) - { - Vector3 axisX = Vector3.Transform(Vector3.UnitX, rotation); - Vector3 axisY = Vector3.Transform(Vector3.UnitY, rotation); - Vector3 axisZ = Vector3.Transform(Vector3.UnitZ, rotation); - - return new[] - { - (double)axisX.X, (double)axisX.Y, (double)axisX.Z, 0.0, - (double)axisY.X, (double)axisY.Y, (double)axisY.Z, 0.0, - (double)axisZ.X, (double)axisZ.Y, (double)axisZ.Z, 0.0, - (double)translation.X, (double)translation.Y, (double)translation.Z, 1.0 - }; - } - private static void AssertVector(Vector3 actual, Vector3 expected, double tolerance) { - Assert.AreEqual(expected.X, actual.X, tolerance); - Assert.AreEqual(expected.Y, actual.Y, tolerance); - Assert.AreEqual(expected.Z, actual.Z, tolerance); + Assert.AreEqual(expected.X, actual.X, tolerance, "X 分量"); + Assert.AreEqual(expected.Y, actual.Y, tolerance, "Y 分量"); + Assert.AreEqual(expected.Z, actual.Z, tolerance, "Z 分量"); } } } diff --git a/UnitTests/CoordinateSystem/RealObjectReferencePoseResolverTests.cs b/UnitTests/CoordinateSystem/RealObjectReferencePoseResolverTests.cs deleted file mode 100644 index 0faa079..0000000 --- a/UnitTests/CoordinateSystem/RealObjectReferencePoseResolverTests.cs +++ /dev/null @@ -1,160 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NavisworksTransport.Utils.CoordinateSystem; -using System.Collections.Generic; -using System.Numerics; - -namespace NavisworksTransport.UnitTests.CoordinateSystem -{ - [TestClass] - public class RealObjectReferencePoseResolverTests - { - [TestMethod] - public void YUp_HostWithFragmentDefaultZ_ShouldInterpretRepresentativeFrameToHostSemantics() - { - var fragmentMatrices = new List - { - CreateMatrix( - axisX: new Vector3(1.0f, 0.0f, 0.0f), - axisY: new Vector3(0.0f, 1.0f, 0.0f), - axisZ: new Vector3(0.0f, 0.0f, 1.0f)) - }; - - bool ok = RealObjectReferencePoseResolver.TryResolveFromFragmentMatrices( - fragmentMatrices, - fragmentDefaultUpAxis: "Z", - hostUpAxis: "Y", - out RealObjectReferencePose pose); - - Assert.IsTrue(ok); - AssertVector(pose.RawAxisX, 1.0, 0.0, 0.0); - AssertVector(pose.RawAxisY, 0.0, 1.0, 0.0); - AssertVector(pose.RawAxisZ, 0.0, 0.0, 1.0); - AssertVector(pose.AxisX, 1.0, 0.0, 0.0); - AssertVector(pose.AxisY, 0.0, 0.0, 1.0); - AssertVector(pose.AxisZ, 0.0, -1.0, 0.0); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostWorldXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveY, pose.HostWorldYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostWorldZAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostSemanticXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostSemanticYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.NegativeY, pose.HostSemanticZAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostUpLocalAxis); - } - - [TestMethod] - public void YUp_WorldAxisMapping_ShouldFollowRawRepresentativeFrame() - { - var fragmentMatrices = new List - { - CreateMatrix( - axisX: new Vector3(0.0f, 0.0f, 1.0f), - axisY: new Vector3(1.0f, 0.0f, 0.0f), - axisZ: new Vector3(0.0f, 1.0f, 0.0f)) - }; - - bool ok = RealObjectReferencePoseResolver.TryResolveFromFragmentMatrices( - fragmentMatrices, - fragmentDefaultUpAxis: "Z", - hostUpAxis: "Y", - out RealObjectReferencePose pose); - - Assert.IsTrue(ok); - Assert.AreEqual(LocalAxisDirection.PositiveY, pose.HostWorldXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostWorldYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostWorldZAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostSemanticXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostSemanticYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.NegativeY, pose.HostSemanticZAxisLocalAxis); - } - - [TestMethod] - public void DetectDefaultUpAxis_ShouldReturnZ_WhenRepresentativeZMatchesHostUp() - { - var fragmentMatrices = new List - { - CreateMatrix( - axisX: new Vector3(1.0f, 0.0f, 0.0f), - axisY: new Vector3(0.0f, 0.0f, -1.0f), - axisZ: new Vector3(0.0f, 1.0f, 0.0f)) - }; - - bool ok = RealObjectReferencePoseResolver.TryDetectDefaultUpAxis( - fragmentMatrices, - "Y", - out string detectedAxis, - out float yAlignment, - out float zAlignment); - - Assert.IsTrue(ok); - Assert.AreEqual("Z", detectedAxis); - Assert.AreEqual(0.0, yAlignment, 1e-6); - Assert.AreEqual(1.0, zAlignment, 1e-6); - } - - [TestMethod] - public void YUp_WorldAxisMapping_ShouldAcceptSlightlyRotatedRawFragmentFrame() - { - var fragmentMatrices = new List - { - CreateMatrix( - axisX: Vector3.Normalize(new Vector3(0.9980f, 0.0638f, 0.0f)), - axisY: new Vector3(0.0f, 0.0f, -1.0f), - axisZ: Vector3.Normalize(new Vector3(-0.0638f, 0.9980f, 0.0f))) - }; - - bool ok = RealObjectReferencePoseResolver.TryResolveFromFragmentMatrices( - fragmentMatrices, - fragmentDefaultUpAxis: "Y", - hostUpAxis: "Y", - out RealObjectReferencePose pose); - - Assert.IsTrue(ok); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostWorldXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostWorldYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.NegativeY, pose.HostWorldZAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveX, pose.HostSemanticXAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveY, pose.HostSemanticYAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveZ, pose.HostSemanticZAxisLocalAxis); - Assert.AreEqual(LocalAxisDirection.PositiveY, pose.HostUpLocalAxis); - } - - [TestMethod] - public void YUp_WorldAxisMapping_ShouldRejectAmbiguousRawFragmentFrame() - { - var fragmentMatrices = new List - { - CreateMatrix( - axisX: Vector3.Normalize(new Vector3(0.80f, 0.60f, 0.0f)), - axisY: new Vector3(0.0f, 0.0f, -1.0f), - axisZ: Vector3.Normalize(new Vector3(-0.60f, 0.80f, 0.0f))) - }; - - bool ok = RealObjectReferencePoseResolver.TryResolveFromFragmentMatrices( - fragmentMatrices, - fragmentDefaultUpAxis: "Y", - hostUpAxis: "Y", - out RealObjectReferencePose pose); - - Assert.IsFalse(ok); - Assert.IsNull(pose); - } - - private static double[] CreateMatrix(Vector3 axisX, Vector3 axisY, Vector3 axisZ) - { - return new double[] - { - axisX.X, axisX.Y, axisX.Z, 0.0, - axisY.X, axisY.Y, axisY.Z, 0.0, - axisZ.X, axisZ.Y, axisZ.Z, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; - } - - private static void AssertVector(Vector3 actual, double x, double y, double z, double tolerance = 1e-6) - { - Assert.AreEqual(x, actual.X, tolerance); - Assert.AreEqual(y, actual.Y, tolerance); - Assert.AreEqual(z, actual.Z, tolerance); - } - } -} diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 5d9966e..755b02d 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -119,9 +119,6 @@ namespace NavisworksTransport.Core.Animation private LocalAxisDirection _realObjectReferenceHostWorldXAxisLocalAxis = LocalAxisDirection.PositiveX; private LocalAxisDirection _realObjectReferenceHostWorldYAxisLocalAxis = LocalAxisDirection.PositiveY; private LocalAxisDirection _realObjectReferenceHostWorldZAxisLocalAxis = LocalAxisDirection.PositiveZ; - private LocalAxisDirection _realObjectReferenceHostSemanticXAxisLocalAxis = LocalAxisDirection.PositiveX; - private LocalAxisDirection _realObjectReferenceHostSemanticYAxisLocalAxis = LocalAxisDirection.PositiveY; - private LocalAxisDirection _realObjectReferenceHostSemanticZAxisLocalAxis = LocalAxisDirection.PositiveZ; private LocalAxisDirection _realObjectReferenceHostUpLocalAxis = LocalAxisDirection.PositiveY; private bool _hasRealObjectReferenceRotation = false; private LocalAxisDirection _realObjectPlanarSelectedForwardAxis = LocalAxisDirection.PositiveX; @@ -5411,9 +5408,6 @@ namespace NavisworksTransport.Core.Animation _realObjectReferenceHostWorldXAxisLocalAxis = LocalAxisDirection.PositiveX; _realObjectReferenceHostWorldYAxisLocalAxis = LocalAxisDirection.PositiveY; _realObjectReferenceHostWorldZAxisLocalAxis = LocalAxisDirection.PositiveZ; - _realObjectReferenceHostSemanticXAxisLocalAxis = LocalAxisDirection.PositiveX; - _realObjectReferenceHostSemanticYAxisLocalAxis = hostUpLocal; - _realObjectReferenceHostSemanticZAxisLocalAxis = LocalAxisDirection.PositiveZ; _hasRealObjectReferenceRotation = true; LogManager.Info( @@ -5513,9 +5507,6 @@ namespace NavisworksTransport.Core.Animation _realObjectReferenceHostWorldXAxisLocalAxis = LocalAxisDirection.PositiveX; _realObjectReferenceHostWorldYAxisLocalAxis = LocalAxisDirection.PositiveY; _realObjectReferenceHostWorldZAxisLocalAxis = LocalAxisDirection.PositiveZ; - _realObjectReferenceHostSemanticXAxisLocalAxis = LocalAxisDirection.PositiveX; - _realObjectReferenceHostSemanticYAxisLocalAxis = LocalAxisDirection.PositiveY; - _realObjectReferenceHostSemanticZAxisLocalAxis = LocalAxisDirection.PositiveZ; _realObjectReferenceHostUpLocalAxis = LocalAxisDirection.PositiveY; _hasRealObjectReferenceRotation = false; _realObjectPlanarSelectedForwardAxis = LocalAxisDirection.PositiveX; diff --git a/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs b/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs index 4982a2b..830085f 100644 --- a/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs +++ b/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs @@ -2,19 +2,16 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using Autodesk.Navisworks.Api; -using ComApi = Autodesk.Navisworks.Api.Interop.ComApi; -using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge; namespace NavisworksTransport.Utils.CoordinateSystem { /// - /// Fragment 代表姿态辅助工具。 - /// - /// 语义: - /// - 从 fragment 的 world 矩阵中提取旋转 - /// - 对多个 fragment 旋转做同半球加权平均 - /// - 返回一个可作为真实物体参考位姿的代表旋转 + /// Fragment 代表帧辅助工具(诊断用途)。 + /// + /// 说明:真实物体姿态链已不依赖 fragment(0.18.2 起使用默认轴约定, + /// forward=+X、up=宿主 up)。本工具仅保留系统诊断面板 + /// (SystemManagementViewModel 方法5:Fragment 矩阵分析)所需的 + /// TryGetRepresentativeFrame / TryExtractRotationFromFragmentMatrix。 /// public static class FragmentRepresentativePoseHelper { @@ -37,58 +34,8 @@ namespace NavisworksTransport.Utils.CoordinateSystem } /// - /// 从 ModelItem 的 fragment 几何中提取代表旋转。 + /// 从 fragment 矩阵集合中提取代表帧。 /// - public static bool TryGetRepresentativeRotation(ModelItem item, out Quaternion representativeRotation) - { - representativeRotation = Quaternion.Identity; - - if (item == null) - { - return false; - } - - try - { - var selection = ComApiBridge.ToInwOpSelection(new ModelItemCollection { item }); - var fragmentInfos = GeometryHelper.GetAllFragments(selection); - return TryGetRepresentativeRotation( - fragmentInfos.Select(fragmentInfo => fragmentInfo.TransformMatrix), - out representativeRotation); - } - catch (Exception ex) - { - LogManager.Warning($"[fragment代表姿态] 从ModelItem提取失败: {ex.Message}"); - return false; - } - } - - /// - /// 从 fragment 矩阵集合中提取代表旋转。 - /// - public static bool TryGetRepresentativeRotation( - IEnumerable fragmentMatrices, - out Quaternion representativeRotation) - { - representativeRotation = Quaternion.Identity; - - if (fragmentMatrices == null) - { - return false; - } - - var fragmentRotations = new List(); - foreach (double[] fragmentMatrix in fragmentMatrices) - { - if (TryExtractRotationFromFragmentMatrix(fragmentMatrix, out Quaternion fragmentRotation)) - { - fragmentRotations.Add(fragmentRotation); - } - } - - return TryGetRepresentativeRotation(fragmentRotations, out representativeRotation); - } - public static bool TryGetRepresentativeFrame( IEnumerable fragmentMatrices, out RepresentativeFrame representativeFrame) @@ -121,80 +68,10 @@ namespace NavisworksTransport.Utils.CoordinateSystem return true; } - public static bool TryInterpretRepresentativeFrame( - RepresentativeFrame rawFrame, - string fragmentDefaultUpAxis, - string hostUpAxis, - out RepresentativeFrame interpretedFrame) - { - interpretedFrame = default; - - bool hostIsYUp = string.Equals(hostUpAxis, "Y", StringComparison.OrdinalIgnoreCase); - bool fragmentIsYUp = string.Equals(fragmentDefaultUpAxis, "Y", StringComparison.OrdinalIgnoreCase); - - Vector3 semanticAxisX = rawFrame.AxisX; - Vector3 semanticAxisY; - Vector3 semanticAxisZ; - - if (hostIsYUp == fragmentIsYUp) - { - semanticAxisY = rawFrame.AxisY; - semanticAxisZ = rawFrame.AxisZ; - } - else if (hostIsYUp) - { - // fragment 按 ZUp 解释,宿主按 YUp 解释:X 保持,Y 取原始 Z,Z 由右手系重建。 - semanticAxisY = rawFrame.AxisZ; - semanticAxisZ = Vector3.Normalize(Vector3.Cross(semanticAxisX, semanticAxisY)); - } - else - { - // fragment 按 YUp 解释,宿主按 ZUp 解释:X 保持,Z 取原始 Y,Y 由右手系重建。 - semanticAxisZ = rawFrame.AxisY; - semanticAxisY = Vector3.Normalize(Vector3.Cross(semanticAxisZ, semanticAxisX)); - } - - if (!TryNormalize(semanticAxisX, out semanticAxisX) || - !TryNormalize(semanticAxisY, out semanticAxisY) || - !TryNormalize(semanticAxisZ, out semanticAxisZ)) - { - return false; - } - - // 用解释后的三轴重新正交化,保证右手系稳定。 - Vector3 axisX = semanticAxisX; - Vector3 axisY = semanticAxisY - Vector3.Dot(semanticAxisY, axisX) * axisX; - if (!TryNormalize(axisY, out axisY)) - { - return false; - } - - Vector3 axisZ = Vector3.Cross(axisX, axisY); - if (!TryNormalize(axisZ, out axisZ)) - { - return false; - } - - if (hostIsYUp && Vector3.Dot(axisY, semanticAxisY) < 0.0f) - { - axisY = -axisY; - axisZ = -axisZ; - } - else if (!hostIsYUp && Vector3.Dot(axisZ, semanticAxisZ) < 0.0f) - { - axisY = -axisY; - axisZ = -axisZ; - } - - Quaternion rotation = Quaternion.Normalize(CreateQuaternionFromBasis(axisX, axisY, axisZ)); - interpretedFrame = new RepresentativeFrame(axisX, axisY, axisZ, rotation); - return true; - } - /// - /// 从 fragment 旋转集合中提取代表旋转。 + /// 从 fragment 旋转集合中提取代表旋转(同半球加权平均)。 /// - public static bool TryGetRepresentativeRotation( + private static bool TryGetRepresentativeRotation( IEnumerable fragmentRotations, out Quaternion representativeRotation) { diff --git a/src/Utils/CoordinateSystem/RealObjectReferencePose.cs b/src/Utils/CoordinateSystem/RealObjectReferencePose.cs deleted file mode 100644 index 0f47001..0000000 --- a/src/Utils/CoordinateSystem/RealObjectReferencePose.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Numerics; - -namespace NavisworksTransport.Utils.CoordinateSystem -{ - /// - /// 真实物体在当前宿主语义下解释后的参考姿态。 - /// 这不是 fragment 原始几何框架,而是已经结合 Fragment默认Up 解释后的结果。 - /// - public sealed class RealObjectReferencePose - { - public RealObjectReferencePose( - Quaternion rotation, - Vector3 rawAxisX, - Vector3 rawAxisY, - Vector3 rawAxisZ, - Vector3 axisX, - Vector3 axisY, - Vector3 axisZ, - LocalAxisDirection hostWorldXAxisLocalAxis, - LocalAxisDirection hostWorldYAxisLocalAxis, - LocalAxisDirection hostWorldZAxisLocalAxis, - LocalAxisDirection hostSemanticXAxisLocalAxis, - LocalAxisDirection hostSemanticYAxisLocalAxis, - LocalAxisDirection hostSemanticZAxisLocalAxis, - LocalAxisDirection hostUpLocalAxis, - int fragmentCount, - string fragmentDefaultUpAxis, - string hostUpAxis) - { - Rotation = rotation; - RawAxisX = rawAxisX; - RawAxisY = rawAxisY; - RawAxisZ = rawAxisZ; - AxisX = axisX; - AxisY = axisY; - AxisZ = axisZ; - HostWorldXAxisLocalAxis = hostWorldXAxisLocalAxis; - HostWorldYAxisLocalAxis = hostWorldYAxisLocalAxis; - HostWorldZAxisLocalAxis = hostWorldZAxisLocalAxis; - HostSemanticXAxisLocalAxis = hostSemanticXAxisLocalAxis; - HostSemanticYAxisLocalAxis = hostSemanticYAxisLocalAxis; - HostSemanticZAxisLocalAxis = hostSemanticZAxisLocalAxis; - HostUpLocalAxis = hostUpLocalAxis; - FragmentCount = fragmentCount; - FragmentDefaultUpAxis = fragmentDefaultUpAxis; - HostUpAxis = hostUpAxis; - } - - public Quaternion Rotation { get; } - public Vector3 RawAxisX { get; } - public Vector3 RawAxisY { get; } - public Vector3 RawAxisZ { get; } - public Vector3 AxisX { get; } - public Vector3 AxisY { get; } - public Vector3 AxisZ { get; } - public LocalAxisDirection HostWorldXAxisLocalAxis { get; } - public LocalAxisDirection HostWorldYAxisLocalAxis { get; } - public LocalAxisDirection HostWorldZAxisLocalAxis { get; } - public LocalAxisDirection HostSemanticXAxisLocalAxis { get; } - public LocalAxisDirection HostSemanticYAxisLocalAxis { get; } - public LocalAxisDirection HostSemanticZAxisLocalAxis { get; } - public LocalAxisDirection HostUpLocalAxis { get; } - public int FragmentCount { get; } - public string FragmentDefaultUpAxis { get; } - public string HostUpAxis { get; } - } -} diff --git a/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs b/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs index 13ab441..caf7508 100644 --- a/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs +++ b/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs @@ -1,305 +1,23 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Numerics; -using System.Runtime.InteropServices; -using Autodesk.Navisworks.Api; -using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge; namespace NavisworksTransport.Utils.CoordinateSystem { /// - /// 统一的真实物体参考姿态解析入口。 - /// 负责: - /// 1. 从 fragment 提取代表姿态 - /// 2. 按 Fragment默认Up 解释成当前宿主语义下的真实姿态 - /// 3. 为 Ground / Hoisting / Rail 提供统一参考姿态来源 + /// 真实物体 fragment 姿态解析入口(仅保留诊断用途)。 + /// + /// 说明:真实物体姿态链已不依赖 fragment(0.18.2 起使用默认轴约定, + /// forward=+X、up=宿主 up)。原 TryResolveFromModelItem / + /// TryResolveFromFragmentMatrices(fragment 代表姿态解析链)已删除。 + /// 本类仅保留系统诊断面板(SystemManagementViewModel 方法5)使用的 + /// TryDetectDefaultUpAxis。 /// public static class RealObjectReferencePoseResolver { - private const float WorldAxisMinimumAlignment = 0.98f; - private const float SemanticAxisMinimumAlignment = 0.985f; - private const float MinimumBestToSecondGap = 0.02f; - - public static bool TryResolveFromModelItem( - ModelItem sourceObject, - Document doc, - out RealObjectReferencePose referencePose) - { - referencePose = null; - - if (sourceObject == null) - { - return false; - } - - try - { - var selection = ComApiBridge.ToInwOpSelection(new ModelItemCollection { sourceObject }); - var fragmentInfos = GeometryHelper.GetAllFragments(selection); - try - { - var fragmentMatrices = fragmentInfos - .Where(fragmentInfo => fragmentInfo.TransformMatrix != null && fragmentInfo.TransformMatrix.Length == 16) - .Select(fragmentInfo => fragmentInfo.TransformMatrix) - .ToList(); - - return TryResolveFromFragmentMatrices(fragmentMatrices, doc, out referencePose); - } - finally - { - if (fragmentInfos != null) - { - foreach (var fragmentInfo in fragmentInfos) - { - if (fragmentInfo?.Fragment != null) - { - try - { - Marshal.ReleaseComObject(fragmentInfo.Fragment); - } - catch - { - } - } - } - } - - if (selection != null) - { - try - { - Marshal.ReleaseComObject(selection); - } - catch - { - } - } - } - } - catch (Exception ex) - { - LogManager.Warning($"[真实物体参考姿态] 从 fragment 提取代表姿态失败: {ex.Message}"); - return false; - } - } - - public static bool TryResolveFromFragmentMatrices( - IReadOnlyCollection fragmentMatrices, - Document doc, - out RealObjectReferencePose referencePose) - { - string fragmentDefaultUpAxis = FragmentDefaultUpContext.GetCurrentDocumentFragmentDefaultUpAxis(doc); - string hostUpAxis = FragmentDefaultUpContext.GetCurrentHostUpAxis(doc); - return TryResolveFromFragmentMatrices(fragmentMatrices, fragmentDefaultUpAxis, hostUpAxis, out referencePose); - } - - public static bool TryResolveFromFragmentMatrices( - IReadOnlyCollection fragmentMatrices, - string fragmentDefaultUpAxis, - string hostUpAxis, - out RealObjectReferencePose referencePose) - { - referencePose = null; - - if (fragmentMatrices == null || fragmentMatrices.Count == 0) - { - return false; - } - - if (!FragmentRepresentativePoseHelper.TryGetRepresentativeFrame(fragmentMatrices, out var rawFrame)) - { - return false; - } - - if (!FragmentRepresentativePoseHelper.TryInterpretRepresentativeFrame( - rawFrame, - fragmentDefaultUpAxis, - hostUpAxis, - out var interpretedFrame)) - { - return false; - } - - if (!TryResolveSemanticLocalAxes( - rawFrame, - interpretedFrame, - out var hostSemanticXAxisLocalAxis, - out var hostSemanticYAxisLocalAxis, - out var hostSemanticZAxisLocalAxis)) - { - return false; - } - - if (!TryResolveWorldLocalAxes( - rawFrame, - out var hostWorldXAxisLocalAxis, - out var hostWorldYAxisLocalAxis, - out var hostWorldZAxisLocalAxis)) - { - return false; - } - - referencePose = new RealObjectReferencePose( - interpretedFrame.Rotation, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - interpretedFrame.AxisX, - interpretedFrame.AxisY, - interpretedFrame.AxisZ, - hostWorldXAxisLocalAxis, - hostWorldYAxisLocalAxis, - hostWorldZAxisLocalAxis, - hostSemanticXAxisLocalAxis, - hostSemanticYAxisLocalAxis, - hostSemanticZAxisLocalAxis, - string.Equals(hostUpAxis, "Y", StringComparison.OrdinalIgnoreCase) - ? hostSemanticYAxisLocalAxis - : hostSemanticZAxisLocalAxis, - fragmentMatrices.Count, - fragmentDefaultUpAxis, - hostUpAxis); - return true; - } - - private static bool TryResolveWorldLocalAxes( - FragmentRepresentativePoseHelper.RepresentativeFrame rawFrame, - out LocalAxisDirection hostWorldXAxisLocalAxis, - out LocalAxisDirection hostWorldYAxisLocalAxis, - out LocalAxisDirection hostWorldZAxisLocalAxis) - { - hostWorldXAxisLocalAxis = LocalAxisDirection.PositiveX; - hostWorldYAxisLocalAxis = LocalAxisDirection.PositiveY; - hostWorldZAxisLocalAxis = LocalAxisDirection.PositiveZ; - - if (!TryMatchRawAxisDirection( - Vector3.UnitX, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - WorldAxisMinimumAlignment, - out hostWorldXAxisLocalAxis)) - { - return false; - } - - if (!TryMatchRawAxisDirection( - Vector3.UnitY, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - WorldAxisMinimumAlignment, - out hostWorldYAxisLocalAxis)) - { - return false; - } - - if (!TryMatchRawAxisDirection( - Vector3.UnitZ, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - WorldAxisMinimumAlignment, - out hostWorldZAxisLocalAxis)) - { - return false; - } - - return true; - } - - private static bool TryResolveSemanticLocalAxes( - FragmentRepresentativePoseHelper.RepresentativeFrame rawFrame, - FragmentRepresentativePoseHelper.RepresentativeFrame interpretedFrame, - out LocalAxisDirection hostSemanticXAxisLocalAxis, - out LocalAxisDirection hostSemanticYAxisLocalAxis, - out LocalAxisDirection hostSemanticZAxisLocalAxis) - { - hostSemanticXAxisLocalAxis = LocalAxisDirection.PositiveX; - hostSemanticYAxisLocalAxis = LocalAxisDirection.PositiveY; - hostSemanticZAxisLocalAxis = LocalAxisDirection.PositiveZ; - - if (!TryMatchRawAxisDirection( - interpretedFrame.AxisX, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - SemanticAxisMinimumAlignment, - out hostSemanticXAxisLocalAxis)) - { - return false; - } - - if (!TryMatchRawAxisDirection( - interpretedFrame.AxisY, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - SemanticAxisMinimumAlignment, - out hostSemanticYAxisLocalAxis)) - { - return false; - } - - if (!TryMatchRawAxisDirection( - interpretedFrame.AxisZ, - rawFrame.AxisX, - rawFrame.AxisY, - rawFrame.AxisZ, - SemanticAxisMinimumAlignment, - out hostSemanticZAxisLocalAxis)) - { - return false; - } - - return true; - } - - private static bool TryMatchRawAxisDirection( - Vector3 targetAxis, - Vector3 rawAxisX, - Vector3 rawAxisY, - Vector3 rawAxisZ, - float minimumAlignment, - out LocalAxisDirection axisDirection) - { - axisDirection = LocalAxisDirection.PositiveX; - float bestAlignment = float.NegativeInfinity; - float secondBestAlignment = float.NegativeInfinity; - - TryUpdateBestMatch(targetAxis, rawAxisX, LocalAxisDirection.PositiveX, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - TryUpdateBestMatch(targetAxis, -rawAxisX, LocalAxisDirection.NegativeX, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - TryUpdateBestMatch(targetAxis, rawAxisY, LocalAxisDirection.PositiveY, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - TryUpdateBestMatch(targetAxis, -rawAxisY, LocalAxisDirection.NegativeY, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - TryUpdateBestMatch(targetAxis, rawAxisZ, LocalAxisDirection.PositiveZ, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - TryUpdateBestMatch(targetAxis, -rawAxisZ, LocalAxisDirection.NegativeZ, ref bestAlignment, ref secondBestAlignment, ref axisDirection); - - return bestAlignment >= minimumAlignment - && bestAlignment - secondBestAlignment >= MinimumBestToSecondGap; - } - - private static void TryUpdateBestMatch( - Vector3 targetAxis, - Vector3 candidateAxis, - LocalAxisDirection candidateDirection, - ref float bestAlignment, - ref float secondBestAlignment, - ref LocalAxisDirection bestDirection) - { - float alignment = Vector3.Dot(Vector3.Normalize(targetAxis), Vector3.Normalize(candidateAxis)); - if (alignment > bestAlignment) - { - secondBestAlignment = bestAlignment; - bestAlignment = alignment; - bestDirection = candidateDirection; - } - else if (alignment > secondBestAlignment) - { - secondBestAlignment = alignment; - } - } - + /// + /// 从 fragment 矩阵检测物体的默认 Up 轴(Y 或 Z 更贴近宿主 up)。 + /// public static bool TryDetectDefaultUpAxis( IReadOnlyCollection fragmentMatrices, string hostUpAxis,