From 51453df037b6b8d34171972c97b535dccb0e0a48 Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Sat, 6 Jun 2026 13:12:18 +0800
Subject: [PATCH] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=20CHANGELOG=20?=
=?UTF-8?q?=E5=92=8C=20VERSION=20=E8=87=B3=200.15.6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 记录自动调整评测与姿态对准修正、skipCadRestore 重构
- 记录别名树 DisplayPath 重名修复
- 版本号 0.15.4 → 0.15.6
---
CHANGELOG.md | 12 ++
VERSION.md | 2 +-
src/Core/Animation/PathAnimationManager.cs | 154 +++++++-----------
.../ViewModels/AnimationControlViewModel.cs | 6 +-
4 files changed, 79 insertions(+), 95 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f9b1bc..2be25bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
# NavisworksTransport 变更日志
+## [0.15.6] - 2026-06-06
+
+### 🐛 Bug 修复
+
+- **自动调整评测与姿态对准修正**:
+ - `GetYawFromRotation` 通过 canonical space 转换计算偏航角,修复 YUp 模式下硬编码 `atan2(Y,X)` 用错水平面的问题
+ - 评测器改为 CAD 原位纯旋转(`ApplyRotationCorrectionInPlace`),以 X 轴为统一参考前向,且旋转分解顺序与增量链一致
+ - 门型约束从评测内硬过滤改为两轮优化:先无约束找最小截面积,不满足约束再带约束重搜
+ - 确认时走 `skipCadRestore` 路径:原地校正后不复位到 CAD,从当前姿态偏航到路径方向,避免读到 CAD 原始 yaw
+ - `MoveObjectToPathStart` 新增 `skipCadRestore` 参数,跳过 CAD 复位步骤
+- **别名树 DisplayPath 重名修复**:所有层级路径段加 `#N` 后缀去重,移除旧格式兼容代码
+
## [0.15.5] - 2026-06-02
### ✨ 新功能
diff --git a/VERSION.md b/VERSION.md
index 49f4740..455e8f3 100644
--- a/VERSION.md
+++ b/VERSION.md
@@ -1,3 +1,3 @@
# 版本号
-0.15.4
+0.15.6
diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs
index c74b477..d6c07fe 100644
--- a/src/Core/Animation/PathAnimationManager.cs
+++ b/src/Core/Animation/PathAnimationManager.cs
@@ -461,61 +461,18 @@ namespace NavisworksTransport.Core.Animation
}
///
- /// 自动调整确认专用:先原地旋转校正(对齐 X),再偏航到路径方向并移动到起点。
- /// 不走 MoveObjectToPathStart 的 CAD 恢复→偏航链,避免读到 CAD 的原始 yaw。
+ /// 将当前显示姿态同步为跟踪状态(yaw=0 对应对齐 X 轴)。
+ /// 用于自动调整确认前,替代 RestoreObjectToCADPosition 的复位→设置链路。
///
- public void ApplyAutoAdjustedPoseAndMoveToPathStart(LocalEulerRotationCorrection correction)
+ public void SyncTrackedStateToCurrentDisplayPose()
{
var item = CurrentControlledObject;
- if (item == null || _pathPoints == null || _pathPoints.Count < 2) return;
-
- // 1. 原地旋转校正 → 物体对齐 X 轴
- RestoreObjectToCADPosition();
- _objectStartPlacementMode = ObjectStartPlacementMode.AlignToPathPose;
- _hasPathPreservedPoseRotation = false;
- _objectRotationCorrection = correction;
- ApplyRotationCorrectionInPlace(correction);
-
- // 2. 计算路径起点位置(与 MoveObjectToPathStart 一致)
- Point3D pathStartPoint = _pathPoints[0];
- Point3D startPosition = ResolveGroundTrackedCenter(pathStartPoint, GetAnimatedObjectGroundContactHeight());
- startPosition = ApplyGroundPathObjectLiftOffset(startPosition);
-
- // 3. 解析路径方向 yaw
- var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
- if (!PathTargetFrameResolver.TryResolvePlanarStartHostForward(
- _route?.PathType ?? PathType.Ground, _pathPoints, out var hostForward))
- {
- LogManager.Warning("[自动调整确认] 无法解析路径起始方向");
- return;
- }
-
- if (!PathTargetFrameResolver.TryResolvePlanarHostYaw(hostForward, adapter.HostType, out double pathYaw))
- {
- LogManager.Warning("[自动调整确认] 无法从路径方向解析 yaw");
- return;
- }
-
- // 4. 从当前 X 朝向偏航到路径方向 + 平移到起点
- Point3D currentCenter = GetLiveBoundingBoxCenter(item);
- var nonUpAxis = adapter.HostType == CoordinateSystemType.YUp ? Vector3.UnitZ : Vector3.UnitY;
- ModelItemTransformHelper.MoveItemCombinedAxisRotationAndTranslation(
- item, currentCenter,
- Vector3.UnitX, 0,
- nonUpAxis, 0,
- adapter.HostUpVector3, (float)pathYaw,
- startPosition);
-
- // 5. 更新跟踪状态
- _trackedPosition = startPosition;
- _currentYaw = pathYaw;
- // Ground 真实物体基姿态
- _groundRealObjectBaseYaw = pathYaw;
- _hasGroundRealObjectBasePose = true;
-
- LogManager.Debug(
- $"[自动调整确认] 校正={correction}, 路径Yaw={pathYaw * 180.0 / Math.PI:F2}°, " +
- $"起点=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3})");
+ if (item == null) return;
+ _trackedPosition = GetLiveBoundingBoxCenter(item);
+ _currentYaw = 0.0;
+ _trackedRotation = item.Transform.Factor().Rotation;
+ _hasTrackedRotation = true;
+ _hasGroundRealObjectBasePose = false;
}
///
@@ -739,7 +696,7 @@ namespace NavisworksTransport.Core.Animation
/// 动画对象(可选,如果不提供则使用当前的_animatedObject)
/// 路径点(可选,如果不提供则使用当前的_pathPoints)
/// 是否成功移动
- public bool MoveObjectToPathStart(ModelItem animatedObject = null, List pathPoints = null)
+ public bool MoveObjectToPathStart(ModelItem animatedObject = null, List pathPoints = null, bool skipCadRestore = false)
{
_objectStartPlacementMode = ObjectStartPlacementMode.AlignToPathPose;
@@ -752,47 +709,48 @@ namespace NavisworksTransport.Core.Animation
try
{
- // 🔥 重要:先恢复物体到原始状态(CAD位置和原始朝向),确保每次计算都从相同的状态开始
- // 这样可以避免之前旋转导致的包围盒尺寸计算不准确的问题
- // 注意:也要处理虚拟物体(当前控制对象可能不在 _animatedObject 中)
- if (CurrentControlledObject != null || IsVirtualObjectMode)
+ if (!skipCadRestore)
{
- RestoreObjectToCADPosition();
- }
-
- // 如果提供了参数,更新内部状态
- if (animatedObject != null)
- {
- _animatedObject = animatedObject;
- bool isVirtualObject =
- VirtualObjectManager.Instance.IsVirtualObjectActive &&
- ReferenceEquals(animatedObject, VirtualObjectManager.Instance.CurrentVirtualObject);
- _animatedObjectMode = isVirtualObject
- ? AnimatedObjectMode.VirtualObject
- : AnimatedObjectMode.RealObject;
- ResetRealObjectReferenceRotation();
- _originalTransform = animatedObject.Transform;
- _originalCenter = animatedObject.BoundingBox().Center;
- _trackedPosition = ResolveInitialBusinessTrackedPosition(animatedObject);
- if (isVirtualObject)
+ if (CurrentControlledObject != null || IsVirtualObjectMode)
{
- _currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
- _trackedRotation = _originalTransform.Factor().Rotation;
- _hasTrackedRotation = true;
- }
- else
- {
- SyncTrackedRotationToObjectReference(animatedObject, isVirtualObject: false);
+ RestoreObjectToCADPosition();
}
- LogManager.Info(
- $"[移动到起点] 更新动画对象内部状态: 对象={animatedObject.DisplayName}, 虚拟物体={IsVirtualObjectMode}");
- }
+ // 如果提供了参数,更新内部状态
+ if (animatedObject != null)
+ {
+ _animatedObject = animatedObject;
+ bool isVirtualObject =
+ VirtualObjectManager.Instance.IsVirtualObjectActive &&
+ ReferenceEquals(animatedObject, VirtualObjectManager.Instance.CurrentVirtualObject);
+ _animatedObjectMode = isVirtualObject
+ ? AnimatedObjectMode.VirtualObject
+ : AnimatedObjectMode.RealObject;
+ ResetRealObjectReferenceRotation();
+ _originalTransform = animatedObject.Transform;
+ _originalCenter = animatedObject.BoundingBox().Center;
+ _trackedPosition = ResolveInitialBusinessTrackedPosition(animatedObject);
+ if (isVirtualObject)
+ {
+ _currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
+ _trackedRotation = _originalTransform.Factor().Rotation;
+ _hasTrackedRotation = true;
+ }
+ else
+ {
+ SyncTrackedRotationToObjectReference(animatedObject, isVirtualObject: false);
+ }
- if (pathPoints != null)
- {
- _pathPoints = pathPoints;
+ LogManager.Info(
+ $"[移动到起点] 更新动画对象内部状态: 对象={animatedObject.DisplayName}, 虚拟物体={IsVirtualObjectMode}");
+ }
+
+ if (pathPoints != null)
+ {
+ _pathPoints = pathPoints;
+ }
}
+ // skipCadRestore: 调用方已设置好 _trackedPosition、_currentYaw、_objectRotationCorrection
// 检查路径点
if (_pathPoints == null || _pathPoints.Count < 2)
@@ -866,6 +824,13 @@ namespace NavisworksTransport.Core.Animation
$"[移动到起点-诊断] _trackedPosition=({_trackedPosition.X:F3},{_trackedPosition.Y:F3},{_trackedPosition.Z:F3}), " +
$"startPosition=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3})");
+ // skipCadRestore 时,校正已原地施加,yaw 增量不应再包含校正的 up 轴分量
+ var savedCorrection = _objectRotationCorrection;
+ if (skipCadRestore)
+ {
+ _objectRotationCorrection = LocalEulerRotationCorrection.Zero;
+ }
+
if (shouldUsePlanarPureIncrementStart &&
TryApplyPlanarRealObjectStartIncrementalTransform(_route.PathType, startPosition, out double planarTargetYawRadians))
{
@@ -957,6 +922,11 @@ namespace NavisworksTransport.Core.Animation
return false;
}
+ if (skipCadRestore)
+ {
+ _objectRotationCorrection = savedCorrection;
+ }
+
return true;
}
catch (Exception ex)
@@ -5551,7 +5521,7 @@ namespace NavisworksTransport.Core.Animation
}
}
- public void ApplyObjectStartPlacementRequest(ObjectStartPlacementRequest request)
+ public void ApplyObjectStartPlacementRequest(ObjectStartPlacementRequest request, bool skipCadRestore = false)
{
_objectStartPlacementMode = request.PlacementMode;
if (_objectStartPlacementMode != ObjectStartPlacementMode.PreserveInitialPose)
@@ -5570,7 +5540,7 @@ namespace NavisworksTransport.Core.Animation
{
try
{
- MoveObjectToPathStartUsingCurrentPlacementMode();
+ MoveObjectToPathStartUsingCurrentPlacementMode(skipCadRestore: skipCadRestore);
}
catch (Exception ex)
{
@@ -5613,11 +5583,11 @@ namespace NavisworksTransport.Core.Animation
LogManager.Debug($"[起点摆放] 当前模式已设置为: {_objectStartPlacementMode}");
}
- private bool MoveObjectToPathStartUsingCurrentPlacementMode(ModelItem animatedObject = null, List pathPoints = null)
+ private bool MoveObjectToPathStartUsingCurrentPlacementMode(ModelItem animatedObject = null, List pathPoints = null, bool skipCadRestore = false)
{
return _objectStartPlacementMode == ObjectStartPlacementMode.PreserveInitialPose
? MoveObjectToPathStartPreservingInitialPose(animatedObject, pathPoints)
- : MoveObjectToPathStart(animatedObject, pathPoints);
+ : MoveObjectToPathStart(animatedObject, pathPoints, skipCadRestore);
}
///
diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
index f4459ab..9332368 100644
--- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
+++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
@@ -2191,11 +2191,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
bool isAutoAdjusted = dialog.AutoAdjustAabbSizes.HasValue;
if (isAutoAdjusted)
{
- // 自动调整:先原地校正(对齐 X),再偏航到路径方向
+ // 自动调整:先原地校正(对齐 X),再通过 MoveObjectToPathStart(skipCadRestore) 偏航到路径
_pathAnimationManager?.SetObjectStartVerticalLiftDirect(
placementRequest.VerticalLiftInMeters);
- _pathAnimationManager?.ApplyAutoAdjustedPoseAndMoveToPathStart(
+ _pathAnimationManager?.ApplyRotationCorrectionInPlace(
placementRequest.RotationCorrection);
+ _pathAnimationManager?.SyncTrackedStateToCurrentDisplayPose();
+ _pathAnimationManager?.ApplyObjectStartPlacementRequest(placementRequest, skipCadRestore: true);
_pathAnimationManager?.SetObjectRotationCorrectionDirect(
placementRequest.RotationCorrection);
_objectRotationCorrection = placementRequest.RotationCorrection;