NavisworksTransport/UnitTests/CoordinateSystem/RotatedObjectExtentHelperTests.cs
tian cf6b2ef959 fix: 修复 7 个 pre-existing 单测失败(optimizer 初始候选 + ZUp 测试语义)
ObjectPassageProjectionOptimizer.OptimizeWithEvaluator:
- 初始化 bestScore 评估 correction=Zero 作为初始候选
- 旧逻辑 bestScore=Invalid 导致 Zero 从未被评估,
  当 baseline 已对齐路径时随机采样必然替换它,refine 收敛不回 0
- 影响 3 个 Optimize 测试:baseline 已对齐时找不到 correction=0

ZUp 测试语义修正(4 个):
- LocalEulerRotationCorrection 语义:Y=up轴/yaw, Z=non-up轴
- ZUp 下 up=Z, non-up=Y,绕 Z(up) 转应使用 YDegrees 不是 ZDegrees
- 旧测试在 ZUp 下把 ZDegrees 当字面 Z 轴,与实现语义矛盾
2026-06-23 23:18:42 +08:00

327 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using NavisworksTransport.Utils.CoordinateSystem;
using System;
using System.Numerics;
namespace NavisworksTransport.UnitTests.CoordinateSystem
{
[TestClass]
public class RotatedObjectExtentHelperTests
{
[TestMethod]
public void YUp_HostY90_ForRealObject_ShouldKeepUpExtentUnchanged()
{
var adapter = new HostCoordinateAdapter(CoordinateSystemType.YUp);
var convention = ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.YUp);
Quaternion correction = adapter.CreateHostRotationCorrection(
new LocalEulerRotationCorrection(0.0, 90.0, 0.0));
var result = RotatedObjectExtentHelper.CalculateProjectedSemanticExtents(
convention,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
correctionQuaternion: correction);
Assert.AreEqual(4.0, result.forwardExtent, 1e-6);
Assert.AreEqual(6.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void YUp_HostZ90_ForRealObject_ShouldPromoteForwardSizeToUpExtent()
{
var adapter = new HostCoordinateAdapter(CoordinateSystemType.YUp);
var convention = ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.YUp);
Quaternion correction = adapter.CreateHostRotationCorrection(
new LocalEulerRotationCorrection(0.0, 0.0, 90.0));
var result = RotatedObjectExtentHelper.CalculateProjectedSemanticExtents(
convention,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
correctionQuaternion: correction);
Assert.AreEqual(2.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(6.0, result.upExtent, 1e-6);
}
[TestMethod]
public void ZUp_HostZDegrees_ShouldPromoteForwardSizeToUpExtent()
{
// ZUp 下 ZDegrees = non-up 轴(=Y)。绕 Y 转 90°X(forward)→-Z(up), Z(up)→X。
// forward(6) 提升到 upup(2) 降到 forward。
var adapter = new HostCoordinateAdapter(CoordinateSystemType.ZUp);
var convention = ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp);
Quaternion correction = adapter.CreateCanonicalRotationCorrection(
new LocalEulerRotationCorrection(0.0, 0.0, 90.0));
var result = RotatedObjectExtentHelper.CalculateProjectedSemanticExtents(
convention,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
correctionQuaternion: correction);
Assert.AreEqual(2.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(6.0, result.upExtent, 1e-6);
}
[TestMethod]
public void ZUp_HostYDegrees_ShouldKeepUpExtentUnchanged()
{
// ZUp 下 YDegrees = up 轴(=Z)。绕 Z 转 90°X→Y, Y→-X, Z(up) 不变。
// forward 和 side 互换up 不变。
var adapter = new HostCoordinateAdapter(CoordinateSystemType.ZUp);
var convention = ModelAxisConvention.CreateDefaultForHost(CoordinateSystemType.ZUp);
Quaternion correction = adapter.CreateCanonicalRotationCorrection(
new LocalEulerRotationCorrection(0.0, 90.0, 0.0));
var result = RotatedObjectExtentHelper.CalculateProjectedSemanticExtents(
convention,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
correctionQuaternion: correction);
Assert.AreEqual(4.0, result.forwardExtent, 1e-6);
Assert.AreEqual(6.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostY90_ShouldSwapForwardAndSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 90.0, 0.0));
Assert.AreEqual(4.0, result.forwardExtent, 1e-6);
Assert.AreEqual(6.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostY45_ShouldBlendForwardAndSide_AndKeepUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 45.0, 0.0));
double expectedPlanar = 5.0 * Math.Sqrt(2.0);
Assert.AreEqual(expectedPlanar, result.forwardExtent, 1e-6);
Assert.AreEqual(expectedPlanar, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostY135_ShouldBlendForwardAndSide_AndKeepUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 135.0, 0.0));
double expectedPlanar = 5.0 * Math.Sqrt(2.0);
Assert.AreEqual(expectedPlanar, result.forwardExtent, 1e-6);
Assert.AreEqual(expectedPlanar, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostY180_ShouldKeepSemanticExtents()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 180.0, 0.0));
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostY270_ShouldSwapForwardAndSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 270.0, 0.0));
Assert.AreEqual(4.0, result.forwardExtent, 1e-6);
Assert.AreEqual(6.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostX90_ShouldKeepForward_AndSwapSideWithUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(90.0, 0.0, 0.0));
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(2.0, result.sideExtent, 1e-6);
Assert.AreEqual(4.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostX45_ShouldKeepForward_AndBlendSideWithUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(45.0, 0.0, 0.0));
double expectedBlend = 3.0 * Math.Sqrt(2.0);
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.sideExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostX135_ShouldKeepForward_AndBlendSideWithUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(135.0, 0.0, 0.0));
double expectedBlend = 3.0 * Math.Sqrt(2.0);
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.sideExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostX180_ShouldKeepSemanticExtents()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(180.0, 0.0, 0.0));
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostX270_ShouldKeepForward_AndSwapSideWithUp()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(270.0, 0.0, 0.0));
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(2.0, result.sideExtent, 1e-6);
Assert.AreEqual(4.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostZ90_ShouldPromoteUpToForward_AndKeepSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 0.0, 90.0));
Assert.AreEqual(2.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(6.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostZ45_ShouldBlendForwardWithUp_AndKeepSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 0.0, 45.0));
double expectedBlend = 4.0 * Math.Sqrt(2.0);
Assert.AreEqual(expectedBlend, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostZ135_ShouldBlendForwardWithUp_AndKeepSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 0.0, 135.0));
double expectedBlend = 4.0 * Math.Sqrt(2.0);
Assert.AreEqual(expectedBlend, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(expectedBlend, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostZ180_ShouldKeepSemanticExtents()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 0.0, 180.0));
Assert.AreEqual(6.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(2.0, result.upExtent, 1e-6);
}
[TestMethod]
public void Ground_YUp_HostZ270_ShouldPromoteUpToForward_AndKeepSide()
{
var result = RotatedObjectExtentHelper.CalculateGroundSemanticExtents(
CoordinateSystemType.YUp,
forwardSize: 6.0,
sideSize: 4.0,
upSize: 2.0,
hostCorrection: new LocalEulerRotationCorrection(0.0, 0.0, 270.0));
Assert.AreEqual(2.0, result.forwardExtent, 1e-6);
Assert.AreEqual(4.0, result.sideExtent, 1e-6);
Assert.AreEqual(6.0, result.upExtent, 1e-6);
}
}
}