diff --git a/doc/design/2026/free-path-design.md b/doc/design/2026/free-path-design.md index e3dee0b..bcacda9 100644 --- a/doc/design/2026/free-path-design.md +++ b/doc/design/2026/free-path-design.md @@ -8,6 +8,12 @@ > - 决策点1(旋转姿态):**最终改为 —— 自由路径保持物体原始姿态**,不自动对齐路径方向 > (真实物体/YUp 的自动姿态解析易出错;用户通过"调整物体"控制朝向) > - 决策点2(旧数据迁移):方案A —— 自动转换 IsTwoPointVertical → Free +> +> **架构原则(2026-08)**:"调整物体"只是调整物体的**姿态修正 + 上下偏移**, +> 与路径对齐无关。物体在起点的姿态/位置由两个分离步骤决定: +> - **第一步(统一,路径无关,无分支)**:调整物体的结果(姿态修正 X/Y/Z + 上下偏移 lift) +> - **第二步(各路径自己的处理逻辑)**:路径起点对齐(路径点→物体位置 + 基座姿态对齐) +> 所有路径都遵循此架构;只有第二步允许分支。 --- diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 1b7dce7..c6d30b0 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -802,20 +802,18 @@ namespace NavisworksTransport.Core.Animation IsRealObjectMode && (_route.PathType == PathType.Ground || _route.PathType == PathType.Hoisting || _route.PathType == PathType.Free); - // 根据路径类型调整起点位置 + // ===== 第二步:路径起点位置对齐(各路径类型各自处理,不含 lift)===== Point3D pathStartPoint = _pathPoints[0]; Point3D startPosition = pathStartPoint; if (_route.PathType == PathType.Free) { - // 自由路径:路径点即物体几何中心,再叠加上下偏移(lift) - startPosition = ApplyGroundPathObjectLiftOffset(startPosition); + // 自由路径:路径点即物体几何中心 LogManager.Debug($"[移动到起点] 自由路径:路径点即物体中心=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2})"); } else if (_route.PathType == PathType.Hoisting) { // 吊装路径:第一个路径点(起吊点)是地面位置,动画跟踪点统一使用几何中心 startPosition = ResolveGroundTrackedCenter(startPosition, GetAnimatedObjectGroundContactHeight()); - startPosition = ApplyGroundPathObjectLiftOffset(startPosition); LogManager.Debug($"[移动到起点] 吊装路径:起吊点已转换为物体中心=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2})"); } else if (_route.PathType == PathType.Rail) @@ -835,8 +833,8 @@ namespace NavisworksTransport.Core.Animation startPosition = RailPathPoseHelper.ResolveObjectSpaceCenterPosition(_route, startPosition, previousPoint, nextPoint, objectHeight); LogManager.Debug($"[移动到起点] Rail路径调整: 参考点=({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2}), 物体中心=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), 物体高度={objectHeight:F2}, 安装={_route.RailMountMode}, 参考面={(PathRoute.IsTopReferenceFaceForMountMode(_route.RailMountMode) ? "顶面参考点" : "底面参考点")}"); } + // Rail 流程提前返回(三维姿态就地应用),在此应用第一步的上下偏移 startPosition = ApplyGroundPathObjectLiftOffset(startPosition); - if (TryCreateRailPathRotation( previousPoint, _pathPoints[0], @@ -859,10 +857,13 @@ namespace NavisworksTransport.Core.Animation { // 地面路径:路径点在接触面上,动画跟踪点统一使用几何中心 startPosition = ResolveGroundTrackedCenter(startPosition, GetAnimatedObjectGroundContactHeight()); - startPosition = ApplyGroundPathObjectLiftOffset(startPosition); LogManager.Debug($"[移动到起点] 地面路径中心点=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2})"); } + // ===== 第一步:调整物体的结果——上下偏移(统一,路径无关)===== + // 注:Rail 因流程提前返回(三维姿态就地应用),lift 在其分支内应用 + startPosition = ApplyGroundPathObjectLiftOffset(startPosition); + LogManager.Debug( $"[路径起点诊断] 路径point0=({pathStartPoint.X:F3},{pathStartPoint.Y:F3},{pathStartPoint.Z:F3}), " + $"起点目标trackedPoint=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3}), 路径类型={_route.PathType.GetDisplayName()}"); @@ -1051,8 +1052,7 @@ namespace NavisworksTransport.Core.Animation Point3D startPosition = pathStartPoint; if (_route.PathType == PathType.Free) { - // 自由路径:路径点即物体几何中心,无需半高偏移,仅叠加上下偏移 - startPosition = ApplyGroundPathObjectLiftOffset(startPosition); + // 自由路径:路径点即物体几何中心,无需半高偏移 } else if (_route.PathType == PathType.Hoisting) { @@ -1086,9 +1086,11 @@ namespace NavisworksTransport.Core.Animation else { startPosition = ResolveGroundTrackedCenter(startPosition, GetAnimatedObjectGroundContactHeight()); - startPosition = ApplyGroundPathObjectLiftOffset(startPosition); } + // 第一步:调整物体的结果——上下偏移(统一,路径无关) + startPosition = ApplyGroundPathObjectLiftOffset(startPosition); + ApplyTrackedTranslationOnly(startPosition); SyncTrackedRotationToDisplayedPose(CurrentControlledObject ?? _animatedObject); _hasGroundRealObjectBasePose = false;