refactor: 分离虚拟物体平面姿态的路径对齐与角度修正

将两件事分开,修正始终生效、与路径几何无关:
- 新增 TryResolvePlanarVirtualObjectRotation:先尝试路径对齐+修正,
  纯垂直路径(无水平方向)时无法对齐则仅把角度修正叠加到当前姿态
- 起点和帧两处虚拟物体平面姿态都改用它
- 修复:虚拟物体在纯垂直路径上角度修正被丢弃的问题
257 单测全过
This commit is contained in:
tian 2026-08-01 12:31:53 +08:00
parent 2cce2f77c5
commit 8ae28463b7

View File

@ -5079,7 +5079,6 @@ namespace NavisworksTransport.Core.Animation
return TryCreateRealObjectPlanarRotationFromHostForward(hostForward, out rotation);
}
var convention = GetCurrentModelAxisConvention();
Vector3 canonicalPrevious = ToNumerics(adapter.ToCanonicalPoint(previousPoint));
Vector3 canonicalCurrent = ToNumerics(adapter.ToCanonicalPoint(currentPoint));
Vector3 canonicalNext = ToNumerics(adapter.ToCanonicalPoint(nextPoint));
@ -5090,19 +5089,7 @@ namespace NavisworksTransport.Core.Animation
forward = canonicalNext - canonicalCurrent;
}
Quaternion correctionQuaternion = adapter.CreateCanonicalRotationCorrection(_objectRotationCorrection);
if (!CanonicalPlanarPoseBuilder.TryCreateQuaternionFromForward(
forward,
HostCoordinateAdapter.CanonicalUpVector3,
convention,
correctionQuaternion,
out var quaternion))
{
return false;
}
rotation = adapter.FromCanonicalRotation(quaternion);
return true;
return TryResolvePlanarVirtualObjectRotation(forward, out rotation);
}
private double GetAnimatedObjectRailNormalExtent(
@ -5126,6 +5113,50 @@ namespace NavisworksTransport.Core.Animation
return GetAnimatedObjectHeight();
}
/// <summary>
/// 平面虚拟物体姿态:路径对齐(可选)+ 角度修正(始终应用,与路径无关)。
/// 路径方向有水平分量时对齐路径;无水平分量(纯垂直)时保持当前姿态,
/// 仅把角度修正叠加到当前姿态上,避免修正因路径几何而丢失。
/// </summary>
private bool TryResolvePlanarVirtualObjectRotation(Vector3 canonicalForward, out Rotation3D rotation)
{
rotation = Rotation3D.Identity;
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
var convention = GetCurrentModelAxisConvention();
Quaternion correctionQuaternion = adapter.CreateCanonicalRotationCorrection(_objectRotationCorrection);
if (CanonicalPlanarPoseBuilder.TryCreateQuaternionFromForward(
canonicalForward,
HostCoordinateAdapter.CanonicalUpVector3,
convention,
correctionQuaternion,
out var quaternion))
{
// 正常:路径对齐 + 角度修正
rotation = adapter.FromCanonicalRotation(quaternion);
return true;
}
// 纯垂直路径无水平方向:无法路径对齐,仅把角度修正叠加到当前姿态
LogManager.Debug("[平面虚拟物体姿态] 路径方向无水平分量,仅应用角度修正到当前姿态");
Quaternion currentHostQuaternion = Rotation3DToHostQuaternion(_trackedRotation);
Quaternion currentCanonicalQuaternion = AlignToGroundMinCrossSectionYawSearcher.HostQuaternionToCanonical(currentHostQuaternion, adapter);
Vector3 currentWorldForward = Vector3.Normalize(Vector3.Transform(convention.ForwardUnitVector, currentCanonicalQuaternion));
Vector3 currentWorldUp = Vector3.Normalize(Vector3.Transform(convention.UpUnitVector, currentCanonicalQuaternion));
LocalAxisPoseBuilder.ApplyLocalPreRotation(
convention,
correctionQuaternion,
out var correctedLocalForward,
out var correctedLocalUp);
Quaternion correctedQuaternion = LocalAxisPoseBuilder.CreateQuaternionFromLocalAxes(
correctedLocalForward,
correctedLocalUp,
currentWorldForward,
currentWorldUp);
rotation = adapter.FromCanonicalRotation(correctedQuaternion);
return true;
}
private bool TryCreatePlanarPathRotationFromHostForward(Vector3D hostForward, out Rotation3D rotation)
{
rotation = Rotation3D.Identity;
@ -5138,21 +5169,8 @@ namespace NavisworksTransport.Core.Animation
out rotation);
}
var convention = GetCurrentModelAxisConvention();
Vector3 canonicalForward = adapter.ToCanonicalVector3(new Vector3((float)hostForward.X, (float)hostForward.Y, (float)hostForward.Z));
Quaternion correctionQuaternion = adapter.CreateCanonicalRotationCorrection(_objectRotationCorrection);
if (!CanonicalPlanarPoseBuilder.TryCreateQuaternionFromForward(
canonicalForward,
HostCoordinateAdapter.CanonicalUpVector3,
convention,
correctionQuaternion,
out var quaternion))
{
return false;
}
rotation = adapter.FromCanonicalRotation(quaternion);
return true;
return TryResolvePlanarVirtualObjectRotation(canonicalForward, out rotation);
}