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;