chore: 更新 CHANGELOG 和 VERSION 至 0.15.6

- 记录自动调整评测与姿态对准修正、skipCadRestore 重构
- 记录别名树 DisplayPath 重名修复
- 版本号 0.15.4 → 0.15.6
This commit is contained in:
tian 2026-06-06 13:12:18 +08:00
parent f5387c8699
commit 51453df037
4 changed files with 79 additions and 95 deletions

View File

@ -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
### ✨ 新功能

View File

@ -1,3 +1,3 @@
# 版本号
0.15.4
0.15.6

View File

@ -461,61 +461,18 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 自动调整确认专用:先原地旋转校正(对齐 X再偏航到路径方向并移动到起点
/// 不走 MoveObjectToPathStart 的 CAD 恢复→偏航链,避免读到 CAD 的原始 yaw
/// 将当前显示姿态同步为跟踪状态yaw=0 对应对齐 X 轴)
/// 用于自动调整确认前,替代 RestoreObjectToCADPosition 的复位→设置链路
/// </summary>
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;
}
/// <summary>
@ -739,7 +696,7 @@ namespace NavisworksTransport.Core.Animation
/// <param name="animatedObject">动画对象可选如果不提供则使用当前的_animatedObject</param>
/// <param name="pathPoints">路径点可选如果不提供则使用当前的_pathPoints</param>
/// <returns>是否成功移动</returns>
public bool MoveObjectToPathStart(ModelItem animatedObject = null, List<Point3D> pathPoints = null)
public bool MoveObjectToPathStart(ModelItem animatedObject = null, List<Point3D> 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<Point3D> pathPoints = null)
private bool MoveObjectToPathStartUsingCurrentPlacementMode(ModelItem animatedObject = null, List<Point3D> pathPoints = null, bool skipCadRestore = false)
{
return _objectStartPlacementMode == ObjectStartPlacementMode.PreserveInitialPose
? MoveObjectToPathStartPreservingInitialPose(animatedObject, pathPoints)
: MoveObjectToPathStart(animatedObject, pathPoints);
: MoveObjectToPathStart(animatedObject, pathPoints, skipCadRestore);
}
/// <summary>

View File

@ -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;