Remove legacy yaw recovery fallbacks

This commit is contained in:
tian 2026-04-12 15:29:08 +08:00
parent 315fa46043
commit 61e6b79299
4 changed files with 93 additions and 414 deletions

View File

@ -975,7 +975,7 @@ namespace NavisworksTransport.Core.Animation
startPosition = ApplyGroundPathObjectLiftOffset(startPosition);
}
ApplyLegacyYawPoseUpdate(startPosition);
ApplyTrackedTranslationOnly(startPosition);
SyncTrackedRotationToDisplayedPose(CurrentControlledObject ?? _animatedObject);
_hasGroundRealObjectBasePose = false;
@ -1878,9 +1878,8 @@ namespace NavisworksTransport.Core.Animation
_currentFrameIndex = 0; // 重置当前帧索引,确保从第一帧开始
_pausedProgress = 0.0; // 重置暂停进度
// 初始化动画状态时不再强行覆盖 _currentYaw 为第一帧的 yaw
// 这样在 ApplyLegacyYawPoseUpdate(firstFrame.Position, firstFrame.YawRadians) 时
// deltaYaw = firstFrame.YawRadians - 物体初始Yaw从而产生旋转增量让物体转向
// 初始化动画状态时不再强行覆盖 _currentYaw 为第一帧的 yaw
// 由记录姿态应用链自行解释第一帧姿态。
if (_animationFrames != null && _animationFrames.Count > 0)
{
@ -2119,7 +2118,7 @@ namespace NavisworksTransport.Core.Animation
if (_currentFrameIndex != lastFrameIndex)
{
_currentFrameIndex = lastFrameIndex;
ApplyAnimationFramePose(_animationFrames[_currentFrameIndex], _currentFrameIndex);
ApplyRecordedPose(_animationFrames[_currentFrameIndex], _currentFrameIndex);
LogManager.Info("[动画结束] 当前尚未到最后一帧,已补落最终姿态");
}
else
@ -2683,9 +2682,10 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 更新对象位置和朝向(支持绕物体中心旋转)
/// 仅按业务跟踪点执行平移,不改变当前姿态语义。
/// PreserveInitialPose 起点搬运等链路应显式使用此入口,而不是借用旧 yaw 链。
/// </summary>
private void ApplyLegacyYawPoseUpdate(Point3D newPosition, double newYaw = double.NaN)
private void ApplyTrackedTranslationOnly(Point3D newPosition)
{
try
{
@ -2699,50 +2699,8 @@ namespace NavisworksTransport.Core.Animation
newPosition.Z - _trackedPosition.Z
);
Transform3D incrementalTransform;
if (!double.IsNaN(newYaw))
{
// 有旋转:需要实现"绕物体当前位置自转"
// 由于Transform3DComponents.Rotation总是绕世界原点旋转
// 我们需要手动计算旋转导致的位置偏移,并补偿
double deltaYaw = newYaw - _currentYaw;
//LogManager.Debug($"[UpdateObjectPosition] 当前yaw={_currentYaw * 180 / Math.PI:F2}度, 目标yaw={newYaw * 180 / Math.PI:F2}度, 旋转增量deltaYaw={deltaYaw * 180 / Math.PI:F2}度");
// 计算绕当前位置旋转的等效变换:
// 1. 如果绕原点旋转deltaYaw当前位置_trackedPosition会移动到哪里
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = _trackedPosition.X * cos - _trackedPosition.Y * sin;
double rotatedY = _trackedPosition.X * sin + _trackedPosition.Y * cos;
// 2. 但我们希望物体绕自己旋转位置移动到newPosition
// 所以需要的平移 = newPosition - (旋转后的位置)
var compensatedTranslation = new Vector3D(
newPosition.X - rotatedX,
newPosition.Y - rotatedY,
newPosition.Z - _trackedPosition.Z // Z保持deltaPos
);
// 3. 组合:先旋转(绕原点),再平移(补偿+目标位置)
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
components.Translation = compensatedTranslation;
incrementalTransform = components.Combine();
_currentYaw = newYaw;
_trackedRotation = Rotation3D.Identity;
_hasTrackedRotation = false;
}
else
{
// 纯平移
incrementalTransform = Transform3D.CreateTranslation(deltaPos);
LogManager.Debug($"[LegacyYawPose] 纯平移: ({deltaPos.X:F2},{deltaPos.Y:F2},{deltaPos.Z:F2})");
}
Transform3D incrementalTransform = Transform3D.CreateTranslation(deltaPos);
LogManager.Debug($"[TrackedTranslation] 纯平移: ({deltaPos.X:F2},{deltaPos.Y:F2},{deltaPos.Z:F2})");
// 应用增量变换false = 增量模式)
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
@ -3056,10 +3014,9 @@ namespace NavisworksTransport.Core.Animation
ApplyResolvedObjectPose(
_savedObjectPosition,
_savedObjectYaw,
_savedObjectRotation,
_savedObjectHasCustomRotation,
frameIndex: -1,
-1,
planarHostYawRadians: _savedObjectYaw);
LogHostActualPoseAxes(obj, "[PAM恢复后宿主姿态]", false);
@ -3128,10 +3085,9 @@ namespace NavisworksTransport.Core.Animation
ApplyResolvedObjectPose(
targetPosition,
targetYawRadians,
targetRotation,
hasCustomRotation,
frameIndex: -1,
-1,
planarHostYawRadians: targetYawRadians);
LogHostActualPoseAxes(obj, "[动画姿态复用后宿主姿态]", false);
@ -3246,7 +3202,7 @@ namespace NavisworksTransport.Core.Animation
// 更新对象位置和朝向,复用动画主播放与恢复使用的同一入口。
var frameData = _animationFrames[_currentFrameIndex];
ApplyAnimationFramePose(frameData, _currentFrameIndex);
ApplyRecordedPose(frameData, _currentFrameIndex);
// 更新碰撞高亮
UpdateCollisionHighlightFromFrame();
@ -5488,11 +5444,11 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 保留给旧单轴调用方:按当前宿主 up 轴映射成三轴角度修正。
/// 单轴兼容入口:按当前宿主 up 轴映射成三轴角度修正。
/// </summary>
public void SetObjectRotationCorrection(double rotationCorrection)
{
SetObjectRotationCorrection(CreateLegacyUpAxisCorrection(rotationCorrection));
SetObjectRotationCorrection(CreateSingleAxisUpCorrection(rotationCorrection));
}
/// <summary>
@ -5529,14 +5485,14 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 保留给旧单轴调用方:按当前宿主 up 轴映射成三轴角度修正。
/// 单轴兼容入口:按当前宿主 up 轴映射成三轴角度修正。
/// </summary>
public void SetObjectRotationCorrectionDirect(double rotationCorrection)
{
SetObjectRotationCorrectionDirect(CreateLegacyUpAxisCorrection(rotationCorrection));
SetObjectRotationCorrectionDirect(CreateSingleAxisUpCorrection(rotationCorrection));
}
private LocalEulerRotationCorrection CreateLegacyUpAxisCorrection(double rotationCorrection)
private LocalEulerRotationCorrection CreateSingleAxisUpCorrection(double rotationCorrection)
{
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
return adapter.HostType == CoordinateSystemType.YUp
@ -5692,7 +5648,7 @@ namespace NavisworksTransport.Core.Animation
if (_currentFrameIndex < _animationFrames.Count)
{
var frameData = _animationFrames[_currentFrameIndex];
ApplyAnimationFramePose(frameData, _currentFrameIndex);
ApplyRecordedPose(frameData, _currentFrameIndex);
// 更新碰撞高亮(基于预计算结果)
UpdateCollisionHighlightFromFrame();
@ -5719,7 +5675,7 @@ namespace NavisworksTransport.Core.Animation
UpdateFPSCounterAndCheckSwitch();
}
private void ApplyAnimationFramePose(AnimationFrame frameData, int frameIndex)
private void ApplyRecordedPose(AnimationFrame frameData, int frameIndex)
{
if (frameData == null)
{
@ -5728,16 +5684,16 @@ namespace NavisworksTransport.Core.Animation
ApplyResolvedObjectPose(
frameData.Position,
ResolveAnimationFramePlaybackYawRadians(frameData),
frameData.Rotation,
frameData.HasCustomRotation,
frameIndex,
frameData.PlanarHostYawRadians);
frameData.PlanarHostYawRadians.HasValue
? (double?)ResolveAnimationFramePlaybackYawRadians(frameData)
: null);
}
private void ApplyResolvedObjectPose(
Point3D targetPosition,
double resolvedYawRadians,
Rotation3D targetRotation,
bool hasCustomRotation,
int frameIndex,
@ -5746,7 +5702,7 @@ namespace NavisworksTransport.Core.Animation
if (ShouldUsePlanarRealObjectPureIncrementFrames(_route?.PathType ?? PathType.Ground, IsRealObjectMode) &&
planarHostYawRadians.HasValue)
{
ApplyPlanarAnimationFrame(targetPosition, planarHostYawRadians.Value);
ApplyPlanarTrackedPose(targetPosition, planarHostYawRadians.Value);
return;
}
@ -5756,13 +5712,9 @@ namespace NavisworksTransport.Core.Animation
return;
}
if (_route?.PathType == PathType.Ground || _route?.PathType == PathType.Hoisting)
{
string pathTypeName = (_route?.PathType ?? PathType.Ground).GetDisplayName();
throw new InvalidOperationException(
$"平面路径播放帧 {frameIndex} 缺少完整姿态,禁止退回旧 yaw 链路。");
}
ApplyLegacyYawPoseUpdate(targetPosition, resolvedYawRadians);
$"{pathTypeName}记录姿态 {frameIndex} 缺少完整姿态,禁止退回旧 yaw 链路。");
}
private double ResolveAnimationFramePlaybackYawRadians(AnimationFrame frameData)
@ -5802,9 +5754,9 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 专门用于Ground路径动画帧播放。使用业务跟踪点 _trackedPosition 作为当前位置,不读取实时包围盒中心回写主链。
/// 应用平面路径的已记录姿态。使用业务跟踪点 _trackedPosition 作为当前位置,不读取实时包围盒中心回写主链。
/// </summary>
private void ApplyPlanarAnimationFrame(Point3D targetPosition, double targetYawRadians)
private void ApplyPlanarTrackedPose(Point3D targetPosition, double targetYawRadians)
{
var controlledObject = CurrentControlledObject;
if (controlledObject == null) return;

View File

@ -826,50 +826,10 @@ namespace NavisworksTransport
}
else
{
// 旧二维候选验证仍沿用“回到 CAD 原始位置再应用增量”的成熟语义。
doc.Models.ResetPermanentTransform(modelItems);
var originalBounds = testAnimatedObject.BoundingBox();
var originalPos = new Point3D(
(originalBounds.Min.X + originalBounds.Max.X) / 2,
(originalBounds.Min.Y + originalBounds.Max.Y) / 2,
(originalBounds.Min.Z + originalBounds.Max.Z) / 2
);
var originalYaw = ModelItemTransformHelper.GetYawFromTransform(testAnimatedObject.Transform);
var deltaPos = new Vector3D(
targetPosition.X - originalPos.X,
targetPosition.Y - originalPos.Y,
targetPosition.Z - originalPos.Z
);
double deltaYaw = targetYaw - originalYaw;
Transform3D transform;
if (Math.Abs(deltaYaw) > 0.001)
{
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = originalPos.X * cos - originalPos.Y * sin;
double rotatedY = originalPos.X * sin + originalPos.Y * cos;
var compensatedTranslation = new Vector3D(
targetPosition.X - rotatedX,
targetPosition.Y - rotatedY,
deltaPos.Z
);
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
components.Translation = compensatedTranslation;
transform = components.Combine();
}
else
{
transform = Transform3D.CreateTranslation(deltaPos);
}
doc.Models.OverridePermanentTransform(modelItems, transform, false);
throw new InvalidOperationException(
$"ClashDetective候选恢复缺少完整姿态对象 {testAnimatedObject.DisplayName}" +
$"目标跟踪点=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3})" +
$"TrackedYaw={targetYaw:F6}rad。");
}
var tempTestName = $"临时验证_{confirmedCount + 1}_{i}_{DateTime.Now:HHmmss_fff}";

View File

@ -98,22 +98,26 @@ namespace NavisworksTransport.Utils
{
if (animatedObject == null) return null;
try
{
// 从PathAnimationManager获取当前实际朝向
var pam = PathAnimationManager.GetInstance();
if (pam == null || !pam.ControlsAnimatedObject(animatedObject))
{
throw new InvalidOperationException(
$"保存碰撞场景前的动画物体状态必须复用 PathAnimationManager对象 {animatedObject.DisplayName} 不受当前动画管理器控制。");
}
// 从 PathAnimationManager 获取当前实际姿态,不再退回工具层旧 yaw 快照语义。
var currentYaw = pam.CurrentYaw;
var currentRotation = pam.TrackedRotation;
var hasCustomRotation = pam.HasTrackedRotation;
var currentState = pam.GetObjectCurrentPosition(animatedObject);
pam.SaveObjectState(animatedObject);
var state = ModelItemTransformHelper.SaveObjectState(
animatedObject,
currentYaw,
currentState.Position,
currentRotation,
hasCustomRotation);
var state = new ModelItemTransformHelper.ObjectStateSnapshot
{
Position = currentState.Position,
Rotation = currentRotation,
HasCustomRotation = hasCustomRotation
};
LogManager.Info(string.Format("已保存动画物体状态: {0}, 位置=({1:F2},{2:F2},{3:F2}), 朝向={4:F2}°, customRotation={5}",
animatedObject.DisplayName, state.Position.X, state.Position.Y, state.Position.Z,
@ -136,12 +140,6 @@ namespace NavisworksTransport.Utils
return state;
}
catch (Exception ex)
{
LogManager.Error(string.Format("保存动画物体状态失败: {0}", ex.Message), ex);
return null;
}
}
/// <summary>
/// 恢复动画物体到保存的状态
@ -152,8 +150,6 @@ namespace NavisworksTransport.Utils
{
if (animatedObject == null || state == null) return;
try
{
if (state.HasCustomRotation && state.Rotation != null)
{
var linear = new Transform3D(state.Rotation).Linear;
@ -171,57 +167,17 @@ namespace NavisworksTransport.Utils
}
var pam = PathAnimationManager.GetInstance();
if (pam != null && pam.ControlsAnimatedObject(animatedObject))
if (pam == null || !pam.ControlsAnimatedObject(animatedObject))
{
throw new InvalidOperationException(
$"恢复碰撞场景前的动画物体状态必须复用 PathAnimationManager对象 {animatedObject.DisplayName} 不受当前动画管理器控制。");
}
pam.RestoreAnimatedObjectState(animatedObject);
LogManager.Info(string.Format(
"动画物体已通过PathAnimationManager恢复状态: {0}, customRotation={1}",
animatedObject.DisplayName,
state.HasCustomRotation));
return;
}
if (state.HasCustomRotation)
{
bool isVirtualWithCustomRotation = VirtualObjectManager.Instance.IsVirtualObjectActive &&
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject;
if (isVirtualWithCustomRotation)
{
ModelItemTransformHelper.RestoreObjectStateWithScale(animatedObject, state);
}
else
{
ModelItemTransformHelper.RestoreObjectState(animatedObject, state);
}
LogManager.Info(string.Format("动画物体已通过状态快照恢复三维姿态: {0}", animatedObject.DisplayName));
return;
}
// 检查是否是虚拟物体
bool isVirtual = VirtualObjectManager.Instance.IsVirtualObjectActive &&
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject;
if (isVirtual)
{
// 虚拟物体:使用带当前缩放的移动方法
ModelItemTransformHelper.MoveItemToPositionAndYawWithCurrentScale(
animatedObject, state.Position, state.YawRadians);
LogManager.Info(string.Format("虚拟物体已恢复到原始状态: {0}, 位置=({1:F2},{2:F2},{3:F2}), 朝向={4:F2}°",
animatedObject.DisplayName, state.Position.X, state.Position.Y, state.Position.Z,
state.YawRadians * 180 / Math.PI));
}
else
{
// 普通物体:使用标准恢复
ModelItemTransformHelper.RestoreObjectState(animatedObject, state);
LogManager.Info(string.Format("动画物体已恢复到原始状态: {0}", animatedObject.DisplayName));
}
}
catch (Exception ex)
{
LogManager.Error(string.Format("恢复动画物体状态失败: {0}", ex.Message), ex);
}
}
}
}

View File

@ -1237,197 +1237,8 @@ namespace NavisworksTransport.Utils
public class ObjectStateSnapshot
{
public Point3D Position { get; set; }
public double YawRadians { get; set; }
public Rotation3D Rotation { get; set; }
public bool HasCustomRotation { get; set; }
public Transform3D Transform { get; set; }
}
/// <summary>
/// 保存物体当前状态
/// 注意YawRadians 通过当前位置计算,因为 Transform 返回的是CAD原始值
/// </summary>
public static ObjectStateSnapshot SaveObjectState(
ModelItem item,
double? currentYaw = null,
Point3D currentPosition = null,
Rotation3D currentRotation = null,
bool hasCustomRotation = false)
{
if (item == null) return null;
var bounds = item.BoundingBox();
// 🔥 关键:如果提供了当前朝向(如 PathAnimationManager._currentYaw使用它
// 否则从 Transform 获取(但这可能不是实际朝向)
double yaw;
if (currentYaw.HasValue)
{
yaw = currentYaw.Value;
}
else
{
// 尝试通过包围盒方向计算(如果物体有几何特征)
yaw = GetYawFromTransform(item.Transform);
LogManager.Debug($"[SaveObjectState] 未提供当前朝向使用Transform: {yaw * 180 / Math.PI:F2}°");
}
return new ObjectStateSnapshot
{
Position = currentPosition ?? new Point3D(bounds.Center.X, bounds.Center.Y, bounds.Min.Z),
YawRadians = yaw,
Rotation = currentRotation ?? Rotation3D.Identity,
HasCustomRotation = hasCustomRotation,
Transform = item.Transform
};
}
/// <summary>
/// 从状态快照恢复物体位置和朝向(标准版本,会重置缩放)
/// </summary>
public static void RestoreObjectState(ModelItem item, ObjectStateSnapshot state)
{
RestoreObjectStateInternal(item, state, preserveScale: false);
}
/// <summary>
/// 从状态快照恢复物体位置和朝向(保留缩放版本,用于虚拟物体)
/// </summary>
public static void RestoreObjectStateWithScale(ModelItem item, ObjectStateSnapshot state)
{
RestoreObjectStateInternal(item, state, preserveScale: true);
}
/// <summary>
/// 从状态快照恢复物体位置的内部实现
/// </summary>
private static void RestoreObjectStateInternal(ModelItem item, ObjectStateSnapshot state, bool preserveScale)
{
if (item == null || state == null) return;
if (state.HasCustomRotation)
{
if (preserveScale)
{
MoveItemToPositionAndRotationWithCurrentScale(item, state.Position, state.Rotation);
}
else
{
MoveItemToPositionAndRotation(item, state.Position, state.Rotation);
}
return;
}
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 1. 先回到CAD原始位置
doc.Models.ResetPermanentTransform(modelItems);
// 2. 从CAD原始位置移动到保存的位置
// 获取CAD原始状态
var originalBounds = item.BoundingBox();
var originalCenterPos = originalBounds.Center;
var originalYaw = GetYawFromTransform(item.Transform);
// 计算到保存位置的增量
var deltaPos = new Vector3D(
state.Position.X - originalCenterPos.X,
state.Position.Y - originalCenterPos.Y,
state.Position.Z - originalCenterPos.Z
);
double deltaYaw = state.YawRadians - originalYaw;
// 应用增量变换
Transform3D transform;
if (Math.Abs(deltaYaw) > 0.001)
{
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = originalCenterPos.X * cos - originalCenterPos.Y * sin;
double rotatedY = originalCenterPos.X * sin + originalCenterPos.Y * cos;
var compensatedTranslation = new Vector3D(
state.Position.X - rotatedX,
state.Position.Y - rotatedY,
state.Position.Z - originalCenterPos.Z
);
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
components.Translation = compensatedTranslation;
transform = components.Combine();
}
else
{
transform = Transform3D.CreateTranslation(deltaPos);
}
doc.Models.OverridePermanentTransform(modelItems, transform, false);
}
/// <summary>
/// 将物体移动到指定位置和朝向,同时保持当前缩放(专为虚拟物体设计)
/// </summary>
public static void MoveItemToPositionAndYawWithCurrentScale(ModelItem item, Point3D targetPosition, double targetYaw)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 获取当前变换中的缩放
var currentTransform = item.Transform;
var currentComponents = currentTransform.Factor();
var currentScale = currentComponents.Scale;
// 重置到CAD原始状态
doc.Models.ResetPermanentTransform(modelItems);
// 获取CAD原始状态
var originalBounds = item.BoundingBox();
var originalCenterPos = originalBounds.Center;
var originalYaw = GetYawFromTransform(item.Transform);
// 计算从CAD原始位置到目标位置的增量
var deltaPos = new Vector3D(
targetPosition.X - originalCenterPos.X,
targetPosition.Y - originalCenterPos.Y,
targetPosition.Z - originalCenterPos.Z
);
double deltaYaw = targetYaw - originalYaw;
// 构建变换组件,保留原有缩放
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Scale = currentScale; // 保留当前缩放
if (Math.Abs(deltaYaw) > 0.001)
{
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
}
// 计算平移(考虑旋转带来的位置偏移)
if (Math.Abs(deltaYaw) > 0.001)
{
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = originalCenterPos.X * cos - originalCenterPos.Y * sin;
double rotatedY = originalCenterPos.X * sin + originalCenterPos.Y * cos;
components.Translation = new Vector3D(
targetPosition.X - rotatedX,
targetPosition.Y - rotatedY,
targetPosition.Z - originalCenterPos.Z
);
}
else
{
components.Translation = deltaPos;
}
// 应用组合变换
Transform3D transform = components.Combine();
doc.Models.OverridePermanentTransform(modelItems, transform, false);
}
}
}