From 29da68f6d3b621cc6b20df84feadc40282e4600a Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Thu, 6 Aug 2026 00:09:08 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86=E6=96=B9?=
=?UTF-8?q?=E6=B3=955=20fragment=20=E7=9F=A9=E9=98=B5=E5=88=86=E6=9E=90?=
=?UTF-8?q?=E4=BE=9D=E8=B5=96=E9=93=BE=EF=BC=88=E4=BF=9D=E7=95=99=E5=9D=90?=
=?UTF-8?q?=E6=A0=87=E7=B3=BB=E6=A3=80=E6=B5=8B=E5=85=B6=E4=BD=99=E6=96=B9?=
=?UTF-8?q?=E6=B3=95=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
删除(fragment 矩阵分析诊断链):
- SystemManagementViewModel: 方法5 文本块、AnalyzeFragmentOrientations、
AppendFragmentAnalysis、FragmentOrientationAnalysis 类
- FragmentRepresentativePoseHelper.cs(TryGetRepresentativeFrame 无调用者)
- RealObjectReferencePoseResolver.cs(TryDetectDefaultUpAxis 只被方法5 用)
- FragmentRepresentativePoseHelperTests.cs
- FragmentDefaultUpContext: 删 GetCurrentHostUpAxis / GetCurrentDocumentFragmentDefaultUpAxis /
IsSupportedAxis(均无调用者)
保留:
- 坐标系检测 方法1/2/3/4/6(文档级检测)
- 真实物体变换诊断(TransformDiagnosticInfo 保留,轴可视化 fallback
到几何后代/选中节点 Transform,不再用 fragment)
- FragmentDefaultUpContext 改名 DocumentKeyContext(仅文档 key 缓存,
用于模型根旋转提示;名字不再含 fragment)
验证:单元测试 185/185、集成测试 25/25
---
NavisworksTransport.UnitTests.csproj | 3 +-
TransportPlugin.csproj | 4 +-
...extTests.cs => DocumentKeyContextTests.cs} | 10 +-
.../FragmentRepresentativePoseHelperTests.cs | 70 -----
.../ViewModels/SystemManagementViewModel.cs | 255 +-----------------
...aultUpContext.cs => DocumentKeyContext.cs} | 45 +---
.../FragmentRepresentativePoseHelper.cs | 246 -----------------
.../RealObjectReferencePoseResolver.cs | 52 ----
8 files changed, 15 insertions(+), 670 deletions(-)
rename UnitTests/CoordinateSystem/{FragmentDefaultUpContextTests.cs => DocumentKeyContextTests.cs} (76%)
delete mode 100644 UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs
rename src/Utils/CoordinateSystem/{FragmentDefaultUpContext.cs => DocumentKeyContext.cs} (54%)
delete mode 100644 src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs
delete mode 100644 src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs
diff --git a/NavisworksTransport.UnitTests.csproj b/NavisworksTransport.UnitTests.csproj
index 5c6b277..77e0d33 100644
--- a/NavisworksTransport.UnitTests.csproj
+++ b/NavisworksTransport.UnitTests.csproj
@@ -96,7 +96,6 @@
-
@@ -112,7 +111,7 @@
-
+
diff --git a/TransportPlugin.csproj b/TransportPlugin.csproj
index 96c805d..57fa132 100644
--- a/TransportPlugin.csproj
+++ b/TransportPlugin.csproj
@@ -362,9 +362,7 @@
-
-
-
+
diff --git a/UnitTests/CoordinateSystem/FragmentDefaultUpContextTests.cs b/UnitTests/CoordinateSystem/DocumentKeyContextTests.cs
similarity index 76%
rename from UnitTests/CoordinateSystem/FragmentDefaultUpContextTests.cs
rename to UnitTests/CoordinateSystem/DocumentKeyContextTests.cs
index 17b135b..3c9edcd 100644
--- a/UnitTests/CoordinateSystem/FragmentDefaultUpContextTests.cs
+++ b/UnitTests/CoordinateSystem/DocumentKeyContextTests.cs
@@ -4,12 +4,12 @@ using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.UnitTests.CoordinateSystem
{
[TestClass]
- public class FragmentDefaultUpContextTests
+ public class DocumentKeyContextTests
{
[TestInitialize]
public void SetUp()
{
- FragmentDefaultUpContext.ResetForTests();
+ DocumentKeyContext.ResetForTests();
}
[TestMethod]
@@ -17,12 +17,12 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem
{
const int runtimeDocumentId = 42;
- string initialKey = FragmentDefaultUpContext.GetOrCreateDocumentKey(
+ string initialKey = DocumentKeyContext.GetOrCreateDocumentKey(
runtimeDocumentId,
@"C:\models\floor2.nwd",
"Floor2");
- string transientKey = FragmentDefaultUpContext.GetOrCreateDocumentKey(
+ string transientKey = DocumentKeyContext.GetOrCreateDocumentKey(
runtimeDocumentId,
string.Empty,
"无标题");
@@ -36,7 +36,7 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem
{
const int runtimeDocumentId = 7;
- string key = FragmentDefaultUpContext.GetOrCreateDocumentKey(
+ string key = DocumentKeyContext.GetOrCreateDocumentKey(
runtimeDocumentId,
string.Empty,
"无标题");
diff --git a/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs b/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs
deleted file mode 100644
index cea12c2..0000000
--- a/UnitTests/CoordinateSystem/FragmentRepresentativePoseHelperTests.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using NavisworksTransport.Utils.CoordinateSystem;
-using System.Numerics;
-
-namespace NavisworksTransport.UnitTests.CoordinateSystem
-{
- [TestClass]
- public class FragmentRepresentativePoseHelperTests
- {
- [TestMethod]
- public void ShouldPreserveAxes_ForObservedYUpRealObjectFragmentBasis()
- {
- Vector3 axisX = new Vector3(1.0f, 0.0f, 0.0f);
- Vector3 axisY = new Vector3(0.0f, 0.0f, 1.0f);
- Vector3 axisZ = new Vector3(0.0f, -1.0f, 0.0f);
-
- double[] fragmentMatrix =
- {
- 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
- };
-
- bool ok = FragmentRepresentativePoseHelper.TryExtractRotationFromFragmentMatrix(
- fragmentMatrix,
- out Quaternion rotation);
-
- Assert.IsTrue(ok);
- AssertVector(Vector3.Transform(Vector3.UnitX, rotation), axisX, 1e-4);
- AssertVector(Vector3.Transform(Vector3.UnitY, rotation), axisY, 1e-4);
- AssertVector(Vector3.Transform(Vector3.UnitZ, rotation), axisZ, 1e-4);
- }
-
- [TestMethod]
- public void RepresentativeFrame_ShouldExposeSameAxes_AsRepresentativeRotation()
- {
- Vector3 axisX = new Vector3(1.0f, 0.0f, 0.0f);
- Vector3 axisY = new Vector3(0.0f, 0.0f, 1.0f);
- Vector3 axisZ = new Vector3(0.0f, -1.0f, 0.0f);
-
- double[] fragmentMatrix =
- {
- 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
- };
-
- bool ok = FragmentRepresentativePoseHelper.TryGetRepresentativeFrame(
- new[] { fragmentMatrix },
- out FragmentRepresentativePoseHelper.RepresentativeFrame frame);
-
- Assert.IsTrue(ok);
- AssertVector(frame.AxisX, axisX, 1e-4);
- AssertVector(frame.AxisY, axisY, 1e-4);
- AssertVector(frame.AxisZ, axisZ, 1e-4);
- AssertVector(Vector3.Transform(Vector3.UnitX, frame.Rotation), axisX, 1e-4);
- AssertVector(Vector3.Transform(Vector3.UnitY, frame.Rotation), axisY, 1e-4);
- AssertVector(Vector3.Transform(Vector3.UnitZ, frame.Rotation), axisZ, 1e-4);
- }
-
- private static void AssertVector(Vector3 actual, Vector3 expected, double 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/src/UI/WPF/ViewModels/SystemManagementViewModel.cs b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
index 793c354..b29bfda 100644
--- a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
+++ b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
@@ -454,7 +454,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private string GetCurrentDocumentKey()
{
- return FragmentDefaultUpContext.GetCurrentDocumentKey();
+ return DocumentKeyContext.GetCurrentDocumentKey();
}
private void ShowRootModelRotationHintIfNeeded()
@@ -1463,11 +1463,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
TransformDiagnosticInfo geometryInfo = geometryDescendants.Count > 0
? CreateTransformDiagnosticInfo(geometryDescendants[0], "首个几何后代")
: null;
- FragmentOrientationAnalysis fragmentAnalysis = AnalyzeFragmentOrientations(item);
-
- Quaternion visualizationQuaternion = fragmentAnalysis != null && fragmentAnalysis.HasRepresentativeOrientation
- ? fragmentAnalysis.RepresentativeRotation
- : geometryInfo?.RotationQuaternion ?? selectedInfo.RotationQuaternion;
+ Quaternion visualizationQuaternion = geometryInfo?.RotationQuaternion ?? selectedInfo.RotationQuaternion;
double axisLength = GetTransformAxisVisualizationLength(bounds);
RenderCapturedRealObjectTransformAxes(boundsCenter, visualizationQuaternion, axisLength);
@@ -1499,12 +1495,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
info.AppendLine();
}
- AppendFragmentAnalysis(info, fragmentAnalysis);
info.AppendLine();
info.AppendLine("【可视化说明】");
info.AppendLine($"三轴原点使用包围盒中心: ({boundsCenter.X:F3}, {boundsCenter.Y:F3}, {boundsCenter.Z:F3})");
info.AppendLine($"轴长度 = {axisLength:F3}");
- info.AppendLine($"三轴方向来源 = {(fragmentAnalysis != null && fragmentAnalysis.HasRepresentativeOrientation ? "fragment代表姿态" : geometryInfo != null ? "首个几何后代Transform" : "选中节点Transform")}");
+ info.AppendLine($"三轴方向来源 = {(geometryInfo != null ? "首个几何后代Transform" : "选中节点Transform")}");
info.AppendLine("红色=X轴,绿色=Y轴,蓝色=Z轴");
string message = info.ToString();
@@ -1667,196 +1662,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
- private static FragmentOrientationAnalysis AnalyzeFragmentOrientations(ModelItem item)
- {
- if (item == null)
- {
- return null;
- }
-
- Autodesk.Navisworks.Api.ModelItemCollection collection = new Autodesk.Navisworks.Api.ModelItemCollection { item };
- var comSelection = ComApiBridge.ToInwOpSelection(collection);
- List fragments = null;
- try
- {
- fragments = GeometryHelper.GetAllFragments(comSelection);
- var validMatrices = fragments
- .Where(f => f.TransformMatrix != null && f.TransformMatrix.Length == 16)
- .Select(f => f.TransformMatrix)
- .ToList();
-
- var analysis = new FragmentOrientationAnalysis
- {
- FragmentCount = fragments.Count,
- ValidTransformCount = validMatrices.Count,
- ValidMatrices = validMatrices
- };
-
- if (validMatrices.Count == 0)
- {
- return analysis;
- }
-
- Vector3 referenceX = NormalizeOrUnitX(GetMatrixAxis(validMatrices[0], 0));
- Vector3 referenceY = NormalizeOrUnitY(GetMatrixAxis(validMatrices[0], 1));
- Vector3 referenceZ = NormalizeOrUnitZ(GetMatrixAxis(validMatrices[0], 2));
-
- Vector3 sumX = referenceX;
- Vector3 sumY = referenceY;
- Vector3 sumZ = referenceZ;
- double xDotSum = 1.0;
- double yDotSum = 1.0;
- double zDotSum = 1.0;
-
- for (int i = 1; i < validMatrices.Count; i++)
- {
- Vector3 axisX = NormalizeWithReference(GetMatrixAxis(validMatrices[i], 0), referenceX);
- Vector3 axisY = NormalizeWithReference(GetMatrixAxis(validMatrices[i], 1), referenceY);
- Vector3 axisZ = NormalizeWithReference(GetMatrixAxis(validMatrices[i], 2), referenceZ);
-
- xDotSum += Math.Abs(Vector3.Dot(axisX, referenceX));
- yDotSum += Math.Abs(Vector3.Dot(axisY, referenceY));
- zDotSum += Math.Abs(Vector3.Dot(axisZ, referenceZ));
-
- sumX += axisX;
- sumY += axisY;
- sumZ += axisZ;
- }
-
- Vector3 representativeX = NormalizeOrUnitX(sumX);
- Vector3 representativeY = sumY - Vector3.Dot(sumY, representativeX) * representativeX;
- representativeY = NormalizeOrUnitY(representativeY);
- Vector3 representativeZ = Vector3.Normalize(Vector3.Cross(representativeX, representativeY));
- if (Vector3.Dot(representativeZ, NormalizeOrUnitZ(sumZ)) < 0)
- {
- representativeZ = -representativeZ;
- }
- representativeY = Vector3.Normalize(Vector3.Cross(representativeZ, representativeX));
-
- Matrix4x4 linear = new Matrix4x4(
- representativeX.X, representativeY.X, representativeZ.X, 0f,
- representativeX.Y, representativeY.Y, representativeZ.Y, 0f,
- representativeX.Z, representativeY.Z, representativeZ.Z, 0f,
- 0f, 0f, 0f, 1f);
-
- analysis.HasRepresentativeOrientation = true;
- analysis.RepresentativeRotation = Quaternion.Normalize(Quaternion.CreateFromRotationMatrix(linear));
- analysis.RepresentativeXAxis = representativeX;
- analysis.RepresentativeYAxis = representativeY;
- analysis.RepresentativeZAxis = representativeZ;
- analysis.AverageXAxisConsistency = xDotSum / validMatrices.Count;
- analysis.AverageYAxisConsistency = yDotSum / validMatrices.Count;
- analysis.AverageZAxisConsistency = zDotSum / validMatrices.Count;
- analysis.SampleTranslation = GetMatrixTranslation(validMatrices[0]);
- return analysis;
- }
- finally
- {
- if (fragments != null)
- {
- foreach (var fragment in fragments)
- {
- if (fragment?.Fragment != null)
- {
- try
- {
- Marshal.ReleaseComObject(fragment.Fragment);
- }
- catch
- {
- }
- }
- }
- }
-
- if (comSelection != null)
- {
- try
- {
- Marshal.ReleaseComObject(comSelection);
- }
- catch
- {
- }
- }
- }
- }
-
- private static void AppendFragmentAnalysis(StringBuilder info, FragmentOrientationAnalysis analysis)
- {
- info.AppendLine("【Fragment 姿态分析】");
- if (analysis == null)
- {
- info.AppendLine("未能执行 fragment 分析");
- info.AppendLine();
- return;
- }
-
- info.AppendLine($"Fragment 总数 = {analysis.FragmentCount}");
- info.AppendLine($"有效变换矩阵数 = {analysis.ValidTransformCount}");
- if (!analysis.HasRepresentativeOrientation)
- {
- info.AppendLine("未得到可用的 fragment 代表姿态");
- info.AppendLine();
- return;
- }
-
- info.AppendLine($"示例平移 = ({analysis.SampleTranslation.X:F3}, {analysis.SampleTranslation.Y:F3}, {analysis.SampleTranslation.Z:F3})");
- info.AppendLine($"代表X轴 = ({analysis.RepresentativeXAxis.X:F4}, {analysis.RepresentativeXAxis.Y:F4}, {analysis.RepresentativeXAxis.Z:F4})");
- info.AppendLine($"代表Y轴 = ({analysis.RepresentativeYAxis.X:F4}, {analysis.RepresentativeYAxis.Y:F4}, {analysis.RepresentativeYAxis.Z:F4})");
- info.AppendLine($"代表Z轴 = ({analysis.RepresentativeZAxis.X:F4}, {analysis.RepresentativeZAxis.Y:F4}, {analysis.RepresentativeZAxis.Z:F4})");
- info.AppendLine($"X轴一致性 = {analysis.AverageXAxisConsistency:F4}");
- info.AppendLine($"Y轴一致性 = {analysis.AverageYAxisConsistency:F4}");
- info.AppendLine($"Z轴一致性 = {analysis.AverageZAxisConsistency:F4}");
- info.AppendLine();
- }
-
- private static Vector3 GetMatrixAxis(double[] matrix, int axisIndex)
- {
- switch (axisIndex)
- {
- case 0:
- return new Vector3((float)matrix[0], (float)matrix[1], (float)matrix[2]);
- case 1:
- return new Vector3((float)matrix[4], (float)matrix[5], (float)matrix[6]);
- case 2:
- return new Vector3((float)matrix[8], (float)matrix[9], (float)matrix[10]);
- default:
- throw new ArgumentOutOfRangeException(nameof(axisIndex));
- }
- }
-
- private static Vector3 GetMatrixTranslation(double[] matrix)
- {
- return new Vector3((float)matrix[12], (float)matrix[13], (float)matrix[14]);
- }
-
- private static Vector3 NormalizeWithReference(Vector3 axis, Vector3 reference)
- {
- Vector3 normalized = NormalizeOrFallback(axis, reference);
- return Vector3.Dot(normalized, reference) < 0 ? -normalized : normalized;
- }
-
- private static Vector3 NormalizeOrUnitX(Vector3 value)
- {
- return NormalizeOrFallback(value, Vector3.UnitX);
- }
-
- private static Vector3 NormalizeOrUnitY(Vector3 value)
- {
- return NormalizeOrFallback(value, Vector3.UnitY);
- }
-
- private static Vector3 NormalizeOrUnitZ(Vector3 value)
- {
- return NormalizeOrFallback(value, Vector3.UnitZ);
- }
-
- private static Vector3 NormalizeOrFallback(Vector3 value, Vector3 fallback)
- {
- return value.LengthSquared() < 1e-8f ? fallback : Vector3.Normalize(value);
- }
-
private sealed class TransformDiagnosticInfo
{
public string Label { get; set; }
@@ -1873,22 +1678,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public Vector3 HostZAxis { get; set; }
}
- private sealed class FragmentOrientationAnalysis
- {
- public int FragmentCount { get; set; }
- public int ValidTransformCount { get; set; }
- public List ValidMatrices { get; set; }
- public bool HasRepresentativeOrientation { get; set; }
- public Quaternion RepresentativeRotation { get; set; }
- public Vector3 RepresentativeXAxis { get; set; }
- public Vector3 RepresentativeYAxis { get; set; }
- public Vector3 RepresentativeZAxis { get; set; }
- public double AverageXAxisConsistency { get; set; }
- public double AverageYAxisConsistency { get; set; }
- public double AverageZAxisConsistency { get; set; }
- public Vector3 SampleTranslation { get; set; }
- }
-
///
/// 快速取面测试 — 激活 FaceInferToolPlugin,用户在模型上点击后显示面法向量
///
@@ -2284,44 +2073,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
sb.AppendLine();
- // 方法5: Fragment 矩阵分析(选一个水平物体后更精确)
- sb.AppendLine($"方法5 - Fragment 矩阵分析 (选择物体后启用):");
- var selection = doc.CurrentSelection.SelectedItems;
- if (selection.Count > 0)
- {
- ModelItem selectedItem = selection[0];
- FragmentOrientationAnalysis fragAnalysis = AnalyzeFragmentOrientations(selectedItem);
- if (fragAnalysis != null && fragAnalysis.HasRepresentativeOrientation)
- {
- string hostUpAxis = FragmentDefaultUpContext.GetCurrentHostUpAxis(doc);
- if (RealObjectReferencePoseResolver.TryDetectDefaultUpAxis(
- fragAnalysis.ValidMatrices,
- hostUpAxis,
- out string fragDetectedAxis,
- out float yAlignment,
- out float zAlignment))
- {
- sb.AppendLine($" 对象: {selectedItem.DisplayName}");
- sb.AppendLine($" Fragment Y 对齐度: {yAlignment:F4}");
- sb.AppendLine($" Fragment Z 对齐度: {zAlignment:F4}");
- sb.AppendLine($" 判定: Fragment 默认 Up = {fragDetectedAxis} ({(zAlignment > yAlignment ? "Z更贴近" : "Y更贴近")}向上轴)");
- }
- else
- {
- sb.AppendLine($" 未能从 fragment 姿态中检测默认Up。");
- }
- }
- else
- {
- sb.AppendLine($" 选中物体 ({selectedItem.DisplayName}) 无有效 fragment 姿态。");
- }
- }
- else
- {
- sb.AppendLine($" (未选择对象,跳过此方法。请先选中一个水平放置的物体)");
- }
- sb.AppendLine();
-
// 最终建议
sb.AppendLine($"【最终建议】");
if (detectedCoordinateSystem == "YUp")
diff --git a/src/Utils/CoordinateSystem/FragmentDefaultUpContext.cs b/src/Utils/CoordinateSystem/DocumentKeyContext.cs
similarity index 54%
rename from src/Utils/CoordinateSystem/FragmentDefaultUpContext.cs
rename to src/Utils/CoordinateSystem/DocumentKeyContext.cs
index cde723e..612e684 100644
--- a/src/Utils/CoordinateSystem/FragmentDefaultUpContext.cs
+++ b/src/Utils/CoordinateSystem/DocumentKeyContext.cs
@@ -6,10 +6,12 @@ using Autodesk.Navisworks.Api;
namespace NavisworksTransport.Utils.CoordinateSystem
{
///
- /// 当前文档级的 fragment 默认 Up 运行时状态。
- /// 自动从 CoordinateSystemManager 派生,不暴露独立设置。
+ /// 当前文档运行时 key 缓存。
+ /// 用于"模型根旋转提示"等按文档去重的交互(同一文档只提示一次)。
+ /// 原名 FragmentDefaultUpContext(曾承担 fragment 默认 Up 运行时状态),
+ /// 0.18.2 去掉 fragment 参考姿态依赖后,仅保留文档 key 功能。
///
- internal static class FragmentDefaultUpContext
+ internal static class DocumentKeyContext
{
private static readonly ConcurrentDictionary RuntimeDocumentKeys =
new ConcurrentDictionary();
@@ -57,43 +59,6 @@ namespace NavisworksTransport.Utils.CoordinateSystem
return resolvedKey;
}
- public static string GetCurrentHostUpAxis(Document doc = null)
- {
- doc = doc ?? Autodesk.Navisworks.Api.Application.ActiveDocument;
- if (doc != null && !doc.IsClear)
- {
- UnitVector3D worldUp = doc.CurrentViewpoint.Value.WorldUpVector;
- if (!worldUp.IsZero)
- {
- return Math.Abs(worldUp.Y) >= Math.Abs(worldUp.Z) ? "Y" : "Z";
- }
-
- Vector3D documentUp = doc.UpVector;
- if (!documentUp.IsZero)
- {
- return Math.Abs(documentUp.Y) >= Math.Abs(documentUp.Z) ? "Y" : "Z";
- }
- }
-
- return "Z";
- }
-
- ///
- /// 获取当前文档的 Fragment Default Up 轴。
- /// 自动从 CoordinateSystemManager 的 ResolvedType 派生。
- /// YUp → "Y", ZUp → "Z"。
- ///
- public static string GetCurrentDocumentFragmentDefaultUpAxis(Document doc = null)
- {
- return CoordinateSystemManager.Instance.ResolvedType == CoordinateSystemType.YUp ? "Y" : "Z";
- }
-
- public static bool IsSupportedAxis(string axisName)
- {
- return string.Equals(axisName, "Y", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(axisName, "Z", StringComparison.OrdinalIgnoreCase);
- }
-
internal static void ResetForTests()
{
RuntimeDocumentKeys.Clear();
diff --git a/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs b/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs
deleted file mode 100644
index 830085f..0000000
--- a/src/Utils/CoordinateSystem/FragmentRepresentativePoseHelper.cs
+++ /dev/null
@@ -1,246 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Numerics;
-
-namespace NavisworksTransport.Utils.CoordinateSystem
-{
- ///
- /// Fragment 代表帧辅助工具(诊断用途)。
- ///
- /// 说明:真实物体姿态链已不依赖 fragment(0.18.2 起使用默认轴约定,
- /// forward=+X、up=宿主 up)。本工具仅保留系统诊断面板
- /// (SystemManagementViewModel 方法5:Fragment 矩阵分析)所需的
- /// TryGetRepresentativeFrame / TryExtractRotationFromFragmentMatrix。
- ///
- public static class FragmentRepresentativePoseHelper
- {
- private const float AxisEpsilon = 1e-6f;
-
- public readonly struct RepresentativeFrame
- {
- public Vector3 AxisX { get; }
- public Vector3 AxisY { get; }
- public Vector3 AxisZ { get; }
- public Quaternion Rotation { get; }
-
- public RepresentativeFrame(Vector3 axisX, Vector3 axisY, Vector3 axisZ, Quaternion rotation)
- {
- AxisX = axisX;
- AxisY = axisY;
- AxisZ = axisZ;
- Rotation = rotation;
- }
- }
-
- ///
- /// 从 fragment 矩阵集合中提取代表帧。
- ///
- public static bool TryGetRepresentativeFrame(
- IEnumerable fragmentMatrices,
- out RepresentativeFrame representativeFrame)
- {
- representativeFrame = default;
-
- if (fragmentMatrices == null)
- {
- return false;
- }
-
- var rotations = new List();
- foreach (double[] fragmentMatrix in fragmentMatrices)
- {
- if (TryExtractRotationFromFragmentMatrix(fragmentMatrix, out Quaternion fragmentRotation))
- {
- rotations.Add(fragmentRotation);
- }
- }
-
- if (!TryGetRepresentativeRotation(rotations, out Quaternion representativeRotation))
- {
- return false;
- }
-
- Vector3 axisX = Vector3.Normalize(Vector3.Transform(Vector3.UnitX, representativeRotation));
- Vector3 axisY = Vector3.Normalize(Vector3.Transform(Vector3.UnitY, representativeRotation));
- Vector3 axisZ = Vector3.Normalize(Vector3.Transform(Vector3.UnitZ, representativeRotation));
- representativeFrame = new RepresentativeFrame(axisX, axisY, axisZ, representativeRotation);
- return true;
- }
-
- ///
- /// 从 fragment 旋转集合中提取代表旋转(同半球加权平均)。
- ///
- private static bool TryGetRepresentativeRotation(
- IEnumerable fragmentRotations,
- out Quaternion representativeRotation)
- {
- representativeRotation = Quaternion.Identity;
-
- if (fragmentRotations == null)
- {
- return false;
- }
-
- var rotations = fragmentRotations
- .Where(rotation => TryNormalize(rotation, out _))
- .Select(rotation => Quaternion.Normalize(rotation))
- .ToList();
-
- if (rotations.Count == 0)
- {
- return false;
- }
-
- Quaternion seed = rotations[0];
- Vector4 sum = Vector4.Zero;
- foreach (Quaternion rotation in rotations)
- {
- Quaternion aligned = Quaternion.Dot(seed, rotation) < 0.0f
- ? new Quaternion(-rotation.X, -rotation.Y, -rotation.Z, -rotation.W)
- : rotation;
-
- sum += new Vector4(aligned.X, aligned.Y, aligned.Z, aligned.W);
- }
-
- if (sum.LengthSquared() < AxisEpsilon)
- {
- return false;
- }
-
- representativeRotation = Quaternion.Normalize(new Quaternion(sum.X, sum.Y, sum.Z, sum.W));
- return true;
- }
-
- ///
- /// 从 fragment 的 4x4 world matrix 中提取旋转。
- /// 仅使用旋转部分,忽略平移。
- ///
- public static bool TryExtractRotationFromFragmentMatrix(double[] fragmentMatrix, out Quaternion rotation)
- {
- rotation = Quaternion.Identity;
-
- if (fragmentMatrix == null || fragmentMatrix.Length != 16)
- {
- return false;
- }
-
- Vector3 axisX = new Vector3(
- (float)fragmentMatrix[0],
- (float)fragmentMatrix[1],
- (float)fragmentMatrix[2]);
- Vector3 axisY = new Vector3(
- (float)fragmentMatrix[4],
- (float)fragmentMatrix[5],
- (float)fragmentMatrix[6]);
- Vector3 axisZ = new Vector3(
- (float)fragmentMatrix[8],
- (float)fragmentMatrix[9],
- (float)fragmentMatrix[10]);
-
- if (!TryNormalize(axisX, out axisX) ||
- !TryNormalize(axisY, out axisY) ||
- !TryNormalize(axisZ, out axisZ))
- {
- return false;
- }
-
- // 先将三个轴正交化,避免 fragment 矩阵里存在轻微数值误差或尺度干扰。
- Vector3 orthogonalY = axisY - Vector3.Dot(axisY, axisX) * axisX;
- if (!TryNormalize(orthogonalY, out orthogonalY))
- {
- orthogonalY = Vector3.Normalize(Vector3.Cross(axisZ, axisX));
- }
-
- Vector3 orthogonalZ = Vector3.Cross(axisX, orthogonalY);
- if (!TryNormalize(orthogonalZ, out orthogonalZ))
- {
- return false;
- }
-
- orthogonalY = Vector3.Normalize(Vector3.Cross(orthogonalZ, axisX));
-
- rotation = Quaternion.Normalize(CreateQuaternionFromBasis(axisX, orthogonalY, orthogonalZ));
- return true;
- }
-
- private static Quaternion CreateQuaternionFromBasis(Vector3 axisX, Vector3 axisY, Vector3 axisZ)
- {
- float m00 = axisX.X;
- float m01 = axisY.X;
- float m02 = axisZ.X;
- float m10 = axisX.Y;
- float m11 = axisY.Y;
- float m12 = axisZ.Y;
- float m20 = axisX.Z;
- float m21 = axisY.Z;
- float m22 = axisZ.Z;
-
- float trace = m00 + m11 + m22;
- float qx;
- float qy;
- float qz;
- float qw;
-
- if (trace > 0.0f)
- {
- float s = (float)Math.Sqrt(trace + 1.0f) * 2.0f;
- qw = 0.25f * s;
- qx = (m21 - m12) / s;
- qy = (m02 - m20) / s;
- qz = (m10 - m01) / s;
- }
- else if (m00 > m11 && m00 > m22)
- {
- float s = (float)Math.Sqrt(1.0f + m00 - m11 - m22) * 2.0f;
- qw = (m21 - m12) / s;
- qx = 0.25f * s;
- qy = (m01 + m10) / s;
- qz = (m02 + m20) / s;
- }
- else if (m11 > m22)
- {
- float s = (float)Math.Sqrt(1.0f + m11 - m00 - m22) * 2.0f;
- qw = (m02 - m20) / s;
- qx = (m01 + m10) / s;
- qy = 0.25f * s;
- qz = (m12 + m21) / s;
- }
- else
- {
- float s = (float)Math.Sqrt(1.0f + m22 - m00 - m11) * 2.0f;
- qw = (m10 - m01) / s;
- qx = (m02 + m20) / s;
- qy = (m12 + m21) / s;
- qz = 0.25f * s;
- }
-
- return new Quaternion(qx, qy, qz, qw);
- }
-
- private static bool TryNormalize(Quaternion value, out Quaternion normalized)
- {
- float lengthSquared = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W;
- if (lengthSquared < AxisEpsilon)
- {
- normalized = Quaternion.Identity;
- return false;
- }
-
- normalized = Quaternion.Normalize(value);
- return true;
- }
-
- private static bool TryNormalize(Vector3 value, out Vector3 normalized)
- {
- if (value.LengthSquared() < AxisEpsilon)
- {
- normalized = Vector3.Zero;
- return false;
- }
-
- normalized = Vector3.Normalize(value);
- return true;
- }
- }
-}
diff --git a/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs b/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs
deleted file mode 100644
index caf7508..0000000
--- a/src/Utils/CoordinateSystem/RealObjectReferencePoseResolver.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-
-namespace NavisworksTransport.Utils.CoordinateSystem
-{
- ///
- /// 真实物体 fragment 姿态解析入口(仅保留诊断用途)。
- ///
- /// 说明:真实物体姿态链已不依赖 fragment(0.18.2 起使用默认轴约定,
- /// forward=+X、up=宿主 up)。原 TryResolveFromModelItem /
- /// TryResolveFromFragmentMatrices(fragment 代表姿态解析链)已删除。
- /// 本类仅保留系统诊断面板(SystemManagementViewModel 方法5)使用的
- /// TryDetectDefaultUpAxis。
- ///
- public static class RealObjectReferencePoseResolver
- {
- ///
- /// 从 fragment 矩阵检测物体的默认 Up 轴(Y 或 Z 更贴近宿主 up)。
- ///
- public static bool TryDetectDefaultUpAxis(
- IReadOnlyCollection fragmentMatrices,
- string hostUpAxis,
- out string detectedAxis,
- out float yAlignment,
- out float zAlignment)
- {
- detectedAxis = "Y";
- yAlignment = 0.0f;
- zAlignment = 0.0f;
-
- if (fragmentMatrices == null || fragmentMatrices.Count == 0)
- {
- return false;
- }
-
- if (!FragmentRepresentativePoseHelper.TryGetRepresentativeFrame(fragmentMatrices, out var rawFrame))
- {
- return false;
- }
-
- Vector3 hostUpVector = string.Equals(hostUpAxis, "Y", StringComparison.OrdinalIgnoreCase)
- ? Vector3.UnitY
- : Vector3.UnitZ;
-
- yAlignment = Math.Abs(Vector3.Dot(Vector3.Normalize(rawFrame.AxisY), hostUpVector));
- zAlignment = Math.Abs(Vector3.Dot(Vector3.Normalize(rawFrame.AxisZ), hostUpVector));
- detectedAxis = zAlignment > yAlignment ? "Z" : "Y";
- return true;
- }
- }
-}