feat: add 2-point vertical hoisting path support

- Add '2点路径' button in AerialHeightDialog for pure vertical lift
- Handle IsTwoPointMode on first click to create 2-point path directly
- Fix PathTargetFrameResolver to accept 2-point Hoisting paths
- Fix animation yaw for 2-point vertical paths (use _currentYaw)
- Fix TryApplyPlanarRealObjectStartIncrementalTransform to translate even
  when no rotation change (was skipping translation for pure vertical)
- Guard _pathPoints[2] access in animation code for <3 points
This commit is contained in:
tian 2026-06-01 22:56:50 +08:00
parent a375e977d4
commit 64a27f4c29
6 changed files with 131 additions and 13 deletions

View File

@ -770,6 +770,10 @@ namespace NavisworksTransport.Core.Animation
$"[路径起点诊断] 路径point0=({pathStartPoint.X:F3},{pathStartPoint.Y:F3},{pathStartPoint.Z:F3}), " +
$"起点目标trackedPoint=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3}), 路径类型={_route.PathType.GetDisplayName()}");
LogManager.Debug(
$"[移动到起点-诊断] _trackedPosition=({_trackedPosition.X:F3},{_trackedPosition.Y:F3},{_trackedPosition.Z:F3}), " +
$"startPosition=({startPosition.X:F3},{startPosition.Y:F3},{startPosition.Z:F3})");
if (shouldUsePlanarPureIncrementStart &&
TryApplyPlanarRealObjectStartIncrementalTransform(_route.PathType, startPosition, out double planarTargetYawRadians))
{
@ -1183,7 +1187,15 @@ namespace NavisworksTransport.Core.Animation
// 吊装路径所有线段都使用水平吊运方向与MoveObjectToPathStart保持一致
if (_route.PathType == PathType.Hoisting)
{
yawRadians = Math.Atan2(_pathPoints[2].Y - _pathPoints[1].Y, _pathPoints[2].X - _pathPoints[1].X);
if (_pathPoints.Count >= 3)
{
yawRadians = Math.Atan2(_pathPoints[2].Y - _pathPoints[1].Y, _pathPoints[2].X - _pathPoints[1].X);
}
else
{
// 2点路径纯垂直无水平方向保持当前朝向
yawRadians = _currentYaw;
}
}
// 🔥 空中路径:根据路径类型和线段索引调整物体位置
@ -4354,8 +4366,9 @@ namespace NavisworksTransport.Core.Animation
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
if (!PathTargetFrameResolver.TryResolvePlanarHostYaw(hostForward, adapter.HostType, out targetYawRadians))
{
LogManager.Error($"[{pathType.GetDisplayName()}纯增量起点] 无法从路径方向解析宿主平面角。");
return false;
// 纯垂直路径无水平方向,无法从路径计算 yaw保持物体当前朝向
LogManager.Debug($"[{pathType.GetDisplayName()}纯增量起点] 路径方向为纯垂直,保持当前朝向。");
targetYawRadians = _currentYaw;
}
// 提取非 up 轴修正角度
@ -4373,13 +4386,22 @@ namespace NavisworksTransport.Core.Animation
double currentYawRadians = _currentYaw;
double deltaYawRadians = NormalizeRadians(targetYawRadians - currentYawRadians);
if (Math.Abs(angleXRadians) > 1e-9 || Math.Abs(angleNonUpRadians) > 1e-9 || Math.Abs(deltaYawRadians) > 1e-9)
bool hasRotation = Math.Abs(angleXRadians) > 1e-9 ||
Math.Abs(angleNonUpRadians) > 1e-9 ||
Math.Abs(deltaYawRadians) > 1e-9;
double posDiff = Math.Abs(_trackedPosition.X - targetTrackedPosition.X) +
Math.Abs(_trackedPosition.Y - targetTrackedPosition.Y) +
Math.Abs(_trackedPosition.Z - targetTrackedPosition.Z);
bool hasTranslation = posDiff > 1e-6;
if (hasRotation || hasTranslation)
{
LogManager.Debug(
$"[{pathType.GetDisplayName()}纯增量起点] 当前Yaw={currentYawRadians * 180.0 / Math.PI:F2}°, " +
$"目标Yaw={targetYawRadians * 180.0 / Math.PI:F2}°, 增量Yaw={deltaYawRadians * 180.0 / Math.PI:F2}°, " +
$"当前跟踪点=({_trackedPosition.X:F3},{_trackedPosition.Y:F3},{_trackedPosition.Z:F3}), " +
$"目标跟踪点=({targetTrackedPosition.X:F3},{targetTrackedPosition.Y:F3},{targetTrackedPosition.Z:F3})");
$"目标跟踪点=({targetTrackedPosition.X:F3},{targetTrackedPosition.Y:F3},{targetTrackedPosition.Z:F3}), " +
$"旋转变化={hasRotation}, 位移变化={hasTranslation}");
ModelItemTransformHelper.MoveItemCombinedAxisRotationAndTranslation(
CurrentControlledObject,

View File

@ -4010,8 +4010,61 @@ namespace NavisworksTransport
LogManager.Error($"[吊装模式] 生成起吊点和提升点失败: {ex.Message}", ex);
}
// 提示用户点击添加转向点
RaiseStatusChanged($"吊装高度已设置为 {liftHeightMetersInput:F2}米,点击添加转向点(点击地面位置),完成后点击完成按钮", PathPlanningStatusType.Info);
// 检查完成模式
if (heightDialog.IsTwoPointMode)
{
// 2点路径提升点直接作为终点无下降段落
LogManager.Info("[吊装模式] 首次点击2点路径提升点即为终点");
var lastPoint = CurrentRoute.Points.Last();
lastPoint.Type = PathPointType.EndPoint;
lastPoint.Name = "终点";
// 清理吊装模式临时变量
_hoistingStartPoint = null;
_hoistingLiftHeight = 0;
_hoistingGroundIntermediatePoints.Clear();
_enableHoistingMode = false;
// 渲染最终路径
if (_renderPlugin != null)
{
_renderPlugin.RenderPath(CurrentRoute);
}
// 添加路径到集合
if (!_routes.Contains(CurrentRoute))
{
_routes.Add(CurrentRoute);
}
// 切换回查看状态
SwitchToViewingState();
// 触发事件通知UI刷新
RaisePathPointsListUpdated(CurrentRoute, "2点路径完成");
SetCurrentRouteInternal(CurrentRoute, triggerEvent: true);
RaiseRouteGenerated(CurrentRoute, RouteGenerationMethod.Manual);
RaiseStatusChanged("2点垂直吊装路径创建完成", PathPlanningStatusType.Success);
}
else if (heightDialog.IsSetAsEndPoint)
{
LogManager.Info("[吊装模式] 首次点击设为终点,直接完成路径");
bool finished = FinishEditing();
if (finished && CurrentRoute != null)
{
RaisePathPointsListUpdated(CurrentRoute, "设为终点完成路径");
}
else
{
RaiseStatusChanged("吊装路径完成失败", PathPlanningStatusType.Warning);
}
}
else
{
// 提示用户点击添加转向点
RaiseStatusChanged($"吊装高度已设置为 {liftHeightMetersInput:F2}米,点击添加转向点(点击地面位置),完成后点击完成按钮", PathPlanningStatusType.Info);
}
}
catch (Exception ex)
{

View File

@ -1,7 +1,7 @@
<Window x:Class="NavisworksTransport.UI.WPF.Views.AerialHeightDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="设置吊装提升高度" Height="240" Width="400"
Title="设置吊装提升高度" Height="240" Width="500"
WindowStartupLocation="CenterScreen"
ResizeMode="NoResize"
ShowInTaskbar="False"
@ -71,6 +71,15 @@
Background="#FFE8F5E9"
Foreground="#FF2E7D32"
ToolTip="将此点设为路径终点,直接降落完成路径"/>
<Button Content="2点路径"
Click="OnTwoPointPathClick"
Style="{StaticResource SecondaryButtonStyle}"
Width="90"
Height="32"
Margin="0,0,10,0"
Background="#FFFFF3E0"
Foreground="#FFE65100"
ToolTip="仅生成起点到终点的垂直路径2个点无下降段"/>
<Button Content="取消"
Click="OnCancelClick"
Style="{StaticResource SecondaryButtonStyle}"

View File

@ -18,6 +18,11 @@ namespace NavisworksTransport.UI.WPF.Views
/// </summary>
public bool IsSetAsEndPoint { get; private set; }
/// <summary>
/// 获取是否2点路径模式仅起点→终点无下降段
/// </summary>
public bool IsTwoPointMode { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
@ -59,6 +64,18 @@ namespace NavisworksTransport.UI.WPF.Views
}
}
/// <summary>
/// 2点路径按钮点击事件 - 仅起点到终点的垂直路径
/// </summary>
private void OnTwoPointPathClick(object sender, RoutedEventArgs e)
{
if (ValidateHeight())
{
IsTwoPointMode = true;
DialogResult = true;
}
}
/// <summary>
/// 取消按钮点击事件
/// </summary>

View File

@ -47,15 +47,26 @@ namespace NavisworksTransport.Utils.CoordinateSystem
if (pathType == NavisworksTransport.PathType.Hoisting)
{
if (pathPoints.Count < 3)
if (pathPoints.Count < 2)
{
return false;
}
hostForward = new Vector3(
(float)(pathPoints[2].X - pathPoints[1].X),
(float)(pathPoints[2].Y - pathPoints[1].Y),
(float)(pathPoints[2].Z - pathPoints[1].Z));
// 优先使用第一个水平段方向点2-点12点路径使用唯一线段方向
if (pathPoints.Count >= 3)
{
hostForward = new Vector3(
(float)(pathPoints[2].X - pathPoints[1].X),
(float)(pathPoints[2].Y - pathPoints[1].Y),
(float)(pathPoints[2].Z - pathPoints[1].Z));
}
else
{
hostForward = new Vector3(
(float)(pathPoints[1].X - pathPoints[0].X),
(float)(pathPoints[1].Y - pathPoints[0].Y),
(float)(pathPoints[1].Z - pathPoints[0].Z));
}
return hostForward.LengthSquared() >= 1e-9f;
}

View File

@ -629,6 +629,12 @@ namespace NavisworksTransport.Utils
targetPosition.Y - rotatedTp.Y,
targetPosition.Z - rotatedTp.Z);
var combined = components.Combine();
LogManager.Debug(
$"[组合旋转平移] tracked=({trackedPosition.X:F3},{trackedPosition.Y:F3},{trackedPosition.Z:F3}), " +
$"target=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"translation=({components.Translation.X:F3},{components.Translation.Y:F3},{components.Translation.Z:F3})");
doc.Models.OverridePermanentTransform(modelItems, combined, false);
}