修改吊装路径功能,支持天车横移路径
This commit is contained in:
parent
7671360454
commit
60bbd468d8
@ -802,17 +802,24 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
if (_route.PathType == PathType.Hoisting)
|
||||
{
|
||||
// 吊装路径:有4个路径点,3个线段
|
||||
// 路径点0(起吊点):地面位置,物体底面应该在这里
|
||||
// 路径点1(提升点):悬挂点,物体顶面应该在这里
|
||||
// 路径点2(平移终点):悬挂点,物体顶面应该在这里
|
||||
// 路径点3(下降点):地面位置,物体底面应该在这里
|
||||
// 吊装路径:支持动态数量的路径点
|
||||
// 路径点结构:
|
||||
// 点0(起吊点):地面位置
|
||||
// 点1(提升点):悬挂点
|
||||
// 点2...点N-2:中间悬挂点(用户添加的转向点)
|
||||
// 点N-1(下降点):悬挂点
|
||||
// 点N(落地点):地面位置
|
||||
//
|
||||
// 线段0:起吊段(地面→悬挂点)
|
||||
// 线段1:平移段(悬挂点→悬挂点)
|
||||
// 线段2:下降段(悬挂点→地面)
|
||||
// 线段结构:
|
||||
// 线段0:起吊段(地面→悬挂点)- 垂直
|
||||
// 线段1...线段N-2:平移段(悬挂点→悬挂点)- 水平
|
||||
// 线段N-1:下降段(悬挂点→地面)- 垂直
|
||||
|
||||
if (segmentIndex == 0)
|
||||
int totalSegments = _pathPoints.Count - 1;
|
||||
int firstSegment = 0; // 起吊段
|
||||
int lastSegment = totalSegments - 1; // 下降段
|
||||
|
||||
if (segmentIndex == firstSegment)
|
||||
{
|
||||
// 起吊段:从地面逐渐上升到悬挂点-车辆高度
|
||||
// 进度0时(地面):物体底面在地面,不向下移动
|
||||
@ -821,13 +828,13 @@ namespace NavisworksTransport.Core.Animation
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - heightOffset);
|
||||
LogManager.Debug($"[吊装路径-起吊段] 进度={segmentProgress:F2}, 高度偏移={heightOffset:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
else if (segmentIndex == 1)
|
||||
else if (segmentIndex > firstSegment && segmentIndex < lastSegment)
|
||||
{
|
||||
// 平移段:全程都是悬挂点,物体顶面在悬挂点,物体底面=悬挂点-车辆高度
|
||||
// 平移段(中间的所有线段):全程都是悬挂点,物体顶面在悬挂点
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - vehicleHeight);
|
||||
LogManager.Debug($"[吊装路径-平移段] 进度={segmentProgress:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
LogManager.Debug($"[吊装路径-平移段] 线段{segmentIndex}, 进度={segmentProgress:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
else if (segmentIndex == 2)
|
||||
else if (segmentIndex == lastSegment)
|
||||
{
|
||||
// 下降段:从悬挂点-车辆高度逐渐下降到地面
|
||||
// 进度0时(悬挂点):物体顶面在悬挂点,物体底面=悬挂点-车辆高度
|
||||
|
||||
@ -44,6 +44,13 @@ namespace NavisworksTransport
|
||||
MouseClicked?.Invoke(sender, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 公开方法,允许外部代码手动触发ESC取消
|
||||
/// </summary>
|
||||
public static void TriggerEscCancel()
|
||||
{
|
||||
// 在 PathPlanningManager 中通过键盘钩子或其他方式调用
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写鼠标按下事件,获取精确的点击坐标
|
||||
|
||||
@ -56,6 +56,15 @@ namespace NavisworksTransport
|
||||
// 吊装起点(用于吊装模式下的两次点击)
|
||||
private Point3D _hoistingStartPoint = null;
|
||||
|
||||
// 吊装终点
|
||||
private Point3D _hoistingEndPoint = null;
|
||||
|
||||
// 吊装高度(米)
|
||||
private double _hoistingLiftHeightMeters = 0;
|
||||
|
||||
// 吊装中间点列表(用户点击的地面投影点)
|
||||
private List<Point3D> _hoistingGroundIntermediatePoints = new List<Point3D>();
|
||||
|
||||
// 路径点3D标记管理
|
||||
private List<PathPointMarker> _pathPointMarkers;
|
||||
|
||||
@ -911,7 +920,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
// 安全地移除事件订阅,多次取消订阅同一处理程序是安全的
|
||||
PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked;
|
||||
LogManager.Debug("[事件清理] 已安全移除PathPlanningManager.OnToolPluginMouseClicked订阅");
|
||||
LogManager.Debug("[事件清理] 已安全移除PathPlanningManager事件订阅");
|
||||
}
|
||||
catch (Exception cleanupEx)
|
||||
{
|
||||
@ -1208,6 +1217,33 @@ namespace NavisworksTransport
|
||||
{
|
||||
try
|
||||
{
|
||||
// 从数据库加载路径数据(如果有的话)
|
||||
if (route != null && !string.IsNullOrEmpty(route.Id) && _pathDatabase != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 从数据库加载完整路径数据(包括路径点)
|
||||
var loadedRoute = _pathDatabase.GetPathRouteSync(route.Id);
|
||||
if (loadedRoute != null && loadedRoute.Points.Count > 0)
|
||||
{
|
||||
// 清空现有路径点并从数据库加载
|
||||
route.Points.Clear();
|
||||
foreach (var point in loadedRoute.Points)
|
||||
{
|
||||
route.Points.Add(point);
|
||||
}
|
||||
// 更新其他属性
|
||||
route.TotalLength = loadedRoute.TotalLength;
|
||||
route.LiftHeightMeters = loadedRoute.LiftHeightMeters;
|
||||
LogManager.Debug($"已从数据库加载路径数据: {route.Name}, 共 {loadedRoute.Points.Count} 个点");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"从数据库加载路径数据失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// 直接设置字段,绕过事件触发
|
||||
var previousRoute = _currentRoute;
|
||||
_currentRoute = route;
|
||||
@ -1256,8 +1292,13 @@ namespace NavisworksTransport
|
||||
/// <param name="route">要编辑的路径</param>
|
||||
public void SwitchToEditingState(PathRoute route)
|
||||
{
|
||||
if (route == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(route));
|
||||
}
|
||||
|
||||
PathEditState = PathEditState.Editing;
|
||||
EditingRoute = route ?? throw new ArgumentNullException(nameof(route));
|
||||
EditingRoute = route;
|
||||
SetCurrentRouteInternal(route, triggerEvent: true);
|
||||
|
||||
// 智能管理ToolPlugin状态
|
||||
@ -1524,6 +1565,17 @@ namespace NavisworksTransport
|
||||
_editingRoute = newRoute;
|
||||
SetCurrentRouteInternal(newRoute, triggerEvent: true);
|
||||
|
||||
// 如果是吊装路径,清理吊装模式相关状态
|
||||
if (pathType == PathType.Hoisting)
|
||||
{
|
||||
_enableHoistingMode = false; // 将在StartClickTool中设置为true
|
||||
_hoistingStartPoint = null;
|
||||
_hoistingEndPoint = null;
|
||||
_hoistingLiftHeightMeters = 0;
|
||||
_hoistingGroundIntermediatePoints.Clear();
|
||||
LogManager.Debug($"[吊装模式] 已清理吊装模式状态,准备新建吊装路径");
|
||||
}
|
||||
|
||||
// 智能管理ToolPlugin状态
|
||||
ManageToolPluginForEditState();
|
||||
|
||||
@ -1588,10 +1640,74 @@ namespace NavisworksTransport
|
||||
LogManager.Info($"[{pathTypeName}] 已自动设置最后一个点为终点: {lastPoint.Name}");
|
||||
}
|
||||
}
|
||||
// 吊装路径:已有明确的起点和终点,不需要修改
|
||||
// 吊装路径:添加下降点和落地点
|
||||
else if (CurrentRoute.PathType == PathType.Hoisting)
|
||||
{
|
||||
LogManager.Info($"[吊装路径] 路径已包含明确的起点和终点,无需修改");
|
||||
LogManager.Info($"[吊装路径] 正在完成吊装路径,处理终点和下降点");
|
||||
|
||||
// 确保至少有起吊点、提升点和至少一个空中路径点
|
||||
if (CurrentRoute.Points.Count >= 3 && _hoistingGroundIntermediatePoints.Count > 0)
|
||||
{
|
||||
// 获取起吊点(用于获取地面Z坐标)
|
||||
var startPoint = CurrentRoute.Points.First();
|
||||
|
||||
// 获取吊装高度
|
||||
double liftHeightMeters = CurrentRoute.LiftHeightMeters > 0 ? CurrentRoute.LiftHeightMeters : 3.0;
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMeters);
|
||||
|
||||
// 获取最后一个地面点击点(原始坐标,未被调整过)
|
||||
var lastGroundClick = _hoistingGroundIntermediatePoints.Last();
|
||||
LogManager.Debug($"[吊装路径] 最后一个地面点击点: ({lastGroundClick.X:F2}, {lastGroundClick.Y:F2}, {lastGroundClick.Z:F2})");
|
||||
|
||||
// 删除最后一个空中路径点(它的坐标可能被调整过,不使用任何信息)
|
||||
CurrentRoute.Points.RemoveAt(CurrentRoute.Points.Count - 1);
|
||||
|
||||
// 创建落地点(终点):使用最后一个地面点击点的完整原始坐标(X、Y、Z)
|
||||
var endPoint = new PathPoint(
|
||||
new Point3D(lastGroundClick.X, lastGroundClick.Y, lastGroundClick.Z),
|
||||
"落地点",
|
||||
PathPointType.EndPoint);
|
||||
endPoint.Direction = HoistingPointDirection.Vertical;
|
||||
LogManager.Debug($"[吊装路径] 已创建落地点(终点): ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})");
|
||||
|
||||
// 向上生成下降点:在落地点正上方,Z坐标为吊装高度
|
||||
var descendPoint = new PathPoint(
|
||||
new Point3D(endPoint.Position.X, endPoint.Position.Y, startPoint.Position.Z + liftHeightModelUnits),
|
||||
"下降点",
|
||||
PathPointType.WayPoint);
|
||||
descendPoint.Direction = HoistingPointDirection.Vertical;
|
||||
LogManager.Debug($"[吊装路径] 已生成下降点(在终点正上方): ({descendPoint.Position.X:F2}, {descendPoint.Position.Y:F2}, {descendPoint.Position.Z:F2})");
|
||||
|
||||
// 添加下降点
|
||||
CurrentRoute.Points.Add(descendPoint);
|
||||
|
||||
// 添加落地点(终点)
|
||||
CurrentRoute.Points.Add(endPoint);
|
||||
LogManager.Debug($"[吊装路径] 已添加落地点(终点): ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})");
|
||||
|
||||
// 优化路径点:处理斜线和清除多余点
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
|
||||
// 重新计算路径长度
|
||||
CurrentRoute.RecalculateLength();
|
||||
|
||||
// 重新渲染路径
|
||||
_renderPlugin?.RenderPath(CurrentRoute);
|
||||
|
||||
LogManager.Info($"[吊装路径] 已完成吊装路径,共 {CurrentRoute.Points.Count} 个路径点");
|
||||
|
||||
// 清理吊装模式临时变量
|
||||
_hoistingStartPoint = null;
|
||||
_hoistingEndPoint = null;
|
||||
_hoistingLiftHeightMeters = 0;
|
||||
_hoistingGroundIntermediatePoints.Clear();
|
||||
_enableHoistingMode = false;
|
||||
LogManager.Debug($"[吊装路径] 已清理吊装模式临时变量");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"[吊装路径] 路径点不足或没有地面点击记录,无法完成吊装路径");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,37 +1843,191 @@ namespace NavisworksTransport
|
||||
/// <param name="modifiedPointIndex">修改的点的索引</param>
|
||||
private void UpdateAerialPathRelatedPoints(PathRoute route, int modifiedPointIndex)
|
||||
{
|
||||
if (route.PathType != PathType.Hoisting ||
|
||||
route.Points.Count != 4)
|
||||
if (route == null || route.PathType != PathType.Hoisting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var points = route.Points;
|
||||
if (points.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 修改起点(索引0):更新提升点(索引1)的X,Y坐标
|
||||
if (modifiedPointIndex == 0)
|
||||
if (modifiedPointIndex == 0 && points.Count > 1)
|
||||
{
|
||||
var startPoint = points[0];
|
||||
var liftPoint = points[1];
|
||||
liftPoint.X = startPoint.X;
|
||||
liftPoint.Y = startPoint.Y;
|
||||
liftPoint.Position = new Point3D(startPoint.Position.X, startPoint.Position.Y, liftPoint.Position.Z);
|
||||
LogManager.Debug($"[吊装路径] 修改起点,更新提升点位置: ({liftPoint.Position.X:F2}, {liftPoint.Position.Y:F2}, {liftPoint.Position.Z:F2})");
|
||||
}
|
||||
// 修改终点(索引3):更新平移终点(索引2)的X,Y坐标
|
||||
else if (modifiedPointIndex == 3)
|
||||
// 修改终点(最后一个点):更新下降点(倒数第二个点)的X,Y坐标
|
||||
else if (modifiedPointIndex == points.Count - 1 && points.Count > 1)
|
||||
{
|
||||
var endPoint = points[3];
|
||||
var moveEndPoint = points[2];
|
||||
moveEndPoint.X = endPoint.X;
|
||||
moveEndPoint.Y = endPoint.Y;
|
||||
var endPoint = points[modifiedPointIndex];
|
||||
var descendPoint = points[modifiedPointIndex - 1];
|
||||
descendPoint.Position = new Point3D(endPoint.Position.X, endPoint.Position.Y, descendPoint.Position.Z);
|
||||
LogManager.Debug($"[吊装路径] 修改终点,更新下降点位置: ({descendPoint.Position.X:F2}, {descendPoint.Position.Y:F2}, {descendPoint.Position.Z:F2})");
|
||||
}
|
||||
// 修改起吊高度(通过起点或终点的Z坐标变化):更新提升点和平移终点的Z坐标
|
||||
else if (modifiedPointIndex == 0 || modifiedPointIndex == 3)
|
||||
// 修改起吊高度(通过起点或终点的Z坐标变化):更新提升点和下降点的Z坐标
|
||||
else if (modifiedPointIndex == 0 || modifiedPointIndex == points.Count - 1)
|
||||
{
|
||||
// 这个逻辑在EditLiftHeightCommand中处理
|
||||
var modifiedPoint = points[modifiedPointIndex];
|
||||
double liftHeightModelUnits = modifiedPoint.Position.Z - (modifiedPointIndex == 0 ? points[0].Position.Z : points[modifiedPointIndex - 1].Position.Z);
|
||||
|
||||
// 更新提升点Z坐标
|
||||
if (points.Count > 1)
|
||||
{
|
||||
points[1].Position = new Point3D(points[1].Position.X, points[1].Position.Y, points[0].Position.Z + liftHeightModelUnits);
|
||||
}
|
||||
|
||||
// 更新下降点Z坐标
|
||||
if (points.Count > 2)
|
||||
{
|
||||
int descendPointIndex = points.Count - 2;
|
||||
points[descendPointIndex].Position = new Point3D(points[descendPointIndex].Position.X, points[descendPointIndex].Position.Y, points[modifiedPointIndex].Position.Z + liftHeightModelUnits);
|
||||
}
|
||||
|
||||
LogManager.Debug($"[吊装路径] 修改起吊高度,更新提升点和下降点Z坐标");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 优化直角转折路径点:出现斜线时插入点,在同一直线上时清除多余点
|
||||
/// </summary>
|
||||
/// <param name="route">要优化的路径</param>
|
||||
/// <returns>是否进行了优化</returns>
|
||||
private bool OptimizeRightAnglePathPoints(PathRoute route)
|
||||
{
|
||||
if (route == null || route.Points.Count < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasChanges = false;
|
||||
var points = route.Points;
|
||||
double tolerance = 0.001; // 容差,用于判断是否在同一直线上
|
||||
|
||||
// 第一步:处理斜线,插入转折点
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
var currentPoint = points[i];
|
||||
var nextPoint = points[i + 1];
|
||||
|
||||
// 判断是否为斜线(X和Y都不同)
|
||||
bool isDiagonal = (Math.Abs(currentPoint.Position.X - nextPoint.Position.X) > tolerance &&
|
||||
Math.Abs(currentPoint.Position.Y - nextPoint.Position.Y) > tolerance);
|
||||
|
||||
if (isDiagonal)
|
||||
{
|
||||
// 插入中间转折点
|
||||
Point3D intermediatePosition;
|
||||
HoistingPointDirection direction;
|
||||
|
||||
// 查找提升点的Z坐标作为吊装高度
|
||||
double aerialHeight = currentPoint.Position.Z;
|
||||
for (int j = 0; j < points.Count; j++)
|
||||
{
|
||||
if (points[j].Name == "提升点")
|
||||
{
|
||||
aerialHeight = points[j].Position.Z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算距离差
|
||||
double deltaX = Math.Abs(nextPoint.Position.X - currentPoint.Position.X);
|
||||
double deltaY = Math.Abs(nextPoint.Position.Y - currentPoint.Position.Y);
|
||||
|
||||
if (deltaX > deltaY)
|
||||
{
|
||||
// 纵向移动优先,先移动X
|
||||
intermediatePosition = new Point3D(
|
||||
nextPoint.Position.X,
|
||||
currentPoint.Position.Y,
|
||||
aerialHeight);
|
||||
direction = HoistingPointDirection.Longitudinal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 横向移动优先,先移动Y
|
||||
intermediatePosition = new Point3D(
|
||||
currentPoint.Position.X,
|
||||
nextPoint.Position.Y,
|
||||
aerialHeight);
|
||||
direction = HoistingPointDirection.Lateral;
|
||||
}
|
||||
|
||||
// 创建中间路径点
|
||||
var intermediatePoint = new PathPoint(
|
||||
intermediatePosition,
|
||||
$"中间点_{i + 1}",
|
||||
PathPointType.WayPoint);
|
||||
|
||||
// 设置方向属性
|
||||
intermediatePoint.Direction = direction;
|
||||
|
||||
// 插入到两点之间
|
||||
points.Insert(i + 1, intermediatePoint);
|
||||
hasChanges = true;
|
||||
|
||||
LogManager.Debug($"[直角路径优化] 在斜线处插入转折点 {i + 1}: ({intermediatePosition.X:F2}, {intermediatePosition.Y:F2}, {intermediatePosition.Z:F2})");
|
||||
|
||||
// 跳过新插入的点
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// 第二步:清除在同一直线上的多余点
|
||||
for (int i = 1; i < points.Count - 1; i++)
|
||||
{
|
||||
var prevPoint = points[i - 1];
|
||||
var currentPoint = points[i];
|
||||
var nextPoint = points[i + 1];
|
||||
|
||||
// 只删除普通的WayPoint,不删除起点、终点、起吊点、提升点、下降点等特殊点
|
||||
if (currentPoint.Type != PathPointType.WayPoint)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 额外检查:不删除提升点和下降点(通过名称识别)
|
||||
if (currentPoint.Name == "提升点" || currentPoint.Name == "下降点")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断三个点是否在同一直线上(只检查X或Y方向相同)
|
||||
bool sameX = Math.Abs(prevPoint.Position.X - currentPoint.Position.X) < tolerance &&
|
||||
Math.Abs(currentPoint.Position.X - nextPoint.Position.X) < tolerance;
|
||||
bool sameY = Math.Abs(prevPoint.Position.Y - currentPoint.Position.Y) < tolerance &&
|
||||
Math.Abs(currentPoint.Position.Y - nextPoint.Position.Y) < tolerance;
|
||||
|
||||
bool isCollinear = sameX || sameY;
|
||||
|
||||
if (isCollinear)
|
||||
{
|
||||
// 删除中间点
|
||||
points.RemoveAt(i);
|
||||
hasChanges = true;
|
||||
LogManager.Debug($"[直角路径优化] 删除共线的多余点 {i}: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
|
||||
// 调整索引,因为删除了一个点
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
// 重新计算路径长度
|
||||
route.RecalculateLength();
|
||||
LogManager.Info($"[直角路径优化] 路径点优化完成,当前点数: {points.Count}");
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新路径点位置(保存修改)
|
||||
/// </summary>
|
||||
@ -1782,6 +2052,12 @@ namespace NavisworksTransport
|
||||
// 吊装路径:自动更新关联点
|
||||
UpdateAerialPathRelatedPoints(CurrentRoute, _editingPointIndex);
|
||||
|
||||
// 吊装路径:优化路径点(处理斜线和清除多余点)
|
||||
if (CurrentRoute.PathType == PathType.Hoisting)
|
||||
{
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
}
|
||||
|
||||
// 核心修复:调用统一更新函数
|
||||
CurrentRoute.RecalculateAndSaveRoute($"修改路径点 {pointToUpdate.Name} 位置");
|
||||
|
||||
@ -2808,6 +3084,7 @@ namespace NavisworksTransport
|
||||
LogManager.Info("用户取消了吊装高度设置,清除起点并退出吊装模式");
|
||||
_hoistingStartPoint = null;
|
||||
_enableHoistingMode = false;
|
||||
_hoistingGroundIntermediatePoints.Clear();
|
||||
PathPointRenderPlugin.Instance.ClearPreviewPoint();
|
||||
StopClickTool();
|
||||
RaiseStatusChanged("已取消创建吊装路径", PathPlanningStatusType.Info);
|
||||
@ -2816,6 +3093,7 @@ namespace NavisworksTransport
|
||||
|
||||
// 获取用户设置的吊装高度
|
||||
double liftHeightMeters = heightDialog.LiftHeightMeters;
|
||||
_hoistingLiftHeightMeters = liftHeightMeters;
|
||||
LogManager.Info($"用户设置的吊装高度: {liftHeightMeters:F2}米");
|
||||
|
||||
// 保存吊装高度到当前路径
|
||||
@ -2824,14 +3102,43 @@ namespace NavisworksTransport
|
||||
CurrentRoute.LiftHeightMeters = liftHeightMeters;
|
||||
}
|
||||
|
||||
// 提示用户点击终点
|
||||
RaiseStatusChanged($"吊装高度已设置为 {liftHeightMeters:F2}米,请在3D视图中点击设置终点", PathPlanningStatusType.Info);
|
||||
// 立即生成起吊点和提升点
|
||||
try
|
||||
{
|
||||
var hoistingStartPoint = new PathPoint(_hoistingStartPoint, "起吊点", PathPointType.StartPoint);
|
||||
hoistingStartPoint.Direction = HoistingPointDirection.Vertical;
|
||||
CurrentRoute.AddPoint(hoistingStartPoint);
|
||||
LogManager.Debug($"[吊装模式] 已添加起吊点: ({hoistingStartPoint.Position.X:F2}, {hoistingStartPoint.Position.Y:F2}, {hoistingStartPoint.Position.Z:F2})");
|
||||
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMeters);
|
||||
var liftPoint = new PathPoint(
|
||||
new Point3D(_hoistingStartPoint.X, _hoistingStartPoint.Y, _hoistingStartPoint.Z + liftHeightModelUnits),
|
||||
"提升点",
|
||||
PathPointType.WayPoint);
|
||||
liftPoint.Direction = HoistingPointDirection.Vertical;
|
||||
CurrentRoute.AddPoint(liftPoint);
|
||||
LogManager.Debug($"[吊装模式] 已添加提升点: ({liftPoint.Position.X:F2}, {liftPoint.Position.Y:F2}, {liftPoint.Position.Z:F2})");
|
||||
|
||||
// 渲染路径
|
||||
if (_renderPlugin != null)
|
||||
{
|
||||
_renderPlugin.RenderPath(CurrentRoute);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[吊装模式] 生成起吊点和提升点失败: {ex.Message}", ex);
|
||||
}
|
||||
|
||||
// 提示用户点击添加转向点
|
||||
RaiseStatusChanged($"吊装高度已设置为 {liftHeightMeters:F2}米,点击添加转向点(点击地面位置),完成后点击完成按钮", PathPlanningStatusType.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[吊装模式] 弹出吊装高度对话框失败: {ex.Message}", ex);
|
||||
_hoistingStartPoint = null;
|
||||
_enableHoistingMode = false;
|
||||
_hoistingGroundIntermediatePoints.Clear();
|
||||
PathPointRenderPlugin.Instance.ClearPreviewPoint();
|
||||
StopClickTool();
|
||||
RaiseStatusChanged("设置吊装高度失败,已取消创建吊装路径", PathPlanningStatusType.Warning);
|
||||
@ -2842,67 +3149,72 @@ namespace NavisworksTransport
|
||||
}
|
||||
else
|
||||
{
|
||||
// 第二次点击:记录终点,生成完整吊装路径
|
||||
Point3D endPoint = clickedPoint;
|
||||
LogManager.Info($"[吊装模式] 已设置终点: ({endPoint.X:F2}, {endPoint.Y:F2}, {endPoint.Z:F2}),开始生成吊装路径");
|
||||
// 后续点击:添加空中路径点
|
||||
LogManager.Info($"[吊装模式] 用户点击: ({clickedPoint.X:F2}, {clickedPoint.Y:F2}, {clickedPoint.Z:F2})");
|
||||
|
||||
// 获取吊装高度
|
||||
double liftHeightMeters = CurrentRoute?.LiftHeightMeters ?? 3.0;
|
||||
double liftHeightMeters = _hoistingLiftHeightMeters;
|
||||
if (liftHeightMeters <= 0)
|
||||
{
|
||||
liftHeightMeters = 3.0;
|
||||
LogManager.Warning($"[吊装模式] 吊装高度无效,使用默认值: {liftHeightMeters}米");
|
||||
}
|
||||
|
||||
// 使用 AerialPathGenerator 生成吊装路径
|
||||
// 使用 AerialPathGenerator 生成单个空中路径点(智能方向判断)
|
||||
try
|
||||
{
|
||||
var generator = new AerialPathGenerator();
|
||||
var pathPoints = generator.GenerateThreeStepHoistingPath(
|
||||
_hoistingStartPoint,
|
||||
endPoint,
|
||||
liftHeightMeters);
|
||||
|
||||
LogManager.Info($"[吊装模式] 已生成吊装路径,包含 {pathPoints.Count} 个路径点");
|
||||
|
||||
// 清除当前路径点
|
||||
CurrentRoute.Points.Clear();
|
||||
|
||||
// 添加生成的路径点(使用 AddPoint 方法以自动更新 TotalLength)
|
||||
foreach (var point in pathPoints)
|
||||
|
||||
// 获取上一个路径点(用于方向判断)
|
||||
Point3D previousPoint;
|
||||
if (CurrentRoute.Points.Count > 0)
|
||||
{
|
||||
CurrentRoute.AddPoint(point);
|
||||
LogManager.Debug($"[吊装模式] 添加路径点: {point.Name} ({point.Position.X:F2}, {point.Position.Y:F2}, {point.Position.Z:F2})");
|
||||
}
|
||||
|
||||
// 渲染路径
|
||||
if (_renderPlugin != null)
|
||||
{
|
||||
_renderPlugin.RenderPath(CurrentRoute);
|
||||
LogManager.Info($"[吊装模式] 已渲染吊装路径: {CurrentRoute.Name}");
|
||||
// 如果已有路径点,使用最后一个路径点
|
||||
previousPoint = CurrentRoute.Points.Last().Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning("[吊装模式] 渲染插件未初始化,无法渲染路径");
|
||||
// 如果还没有路径点(第一次添加中间点),使用提升点
|
||||
previousPoint = new Point3D(
|
||||
_hoistingStartPoint.X,
|
||||
_hoistingStartPoint.Y,
|
||||
_hoistingStartPoint.Z + UnitsConverter.ConvertFromMeters(liftHeightMeters));
|
||||
}
|
||||
|
||||
// 停止点击工具
|
||||
StopClickTool();
|
||||
// 生成空中路径点
|
||||
var aerialPoint = generator.GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
clickedPoint,
|
||||
liftHeightMeters,
|
||||
CurrentRoute.Points.Count > 0 ? CurrentRoute.Points.Count : 1);
|
||||
|
||||
// 清除吊装模式状态
|
||||
_enableHoistingMode = false;
|
||||
_hoistingStartPoint = null;
|
||||
if (aerialPoint != null)
|
||||
{
|
||||
// 记录原始地面点击位置
|
||||
_hoistingGroundIntermediatePoints.Add(clickedPoint);
|
||||
LogManager.Debug($"[吊装模式] 已记录地面点击点: ({clickedPoint.X:F2}, {clickedPoint.Y:F2}, {clickedPoint.Z:F2})");
|
||||
|
||||
// 提示用户
|
||||
RaiseStatusChanged("吊装路径创建成功", PathPlanningStatusType.Success);
|
||||
// 添加到当前路径
|
||||
CurrentRoute.AddPoint(aerialPoint);
|
||||
LogManager.Info($"[吊装模式] 已添加空中路径点: {aerialPoint.Name} ({aerialPoint.Position.X:F2}, {aerialPoint.Position.Y:F2}, {aerialPoint.Position.Z:F2}) - 方向: {aerialPoint.Direction}");
|
||||
|
||||
LogManager.Info("[吊装模式] 吊装路径创建完成");
|
||||
// 优化路径点:处理斜线和清除多余点
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
|
||||
// 渲染路径
|
||||
if (_renderPlugin != null)
|
||||
{
|
||||
_renderPlugin.RenderPath(CurrentRoute);
|
||||
}
|
||||
|
||||
// 提示用户可以继续添加或点击完成
|
||||
string directionText = aerialPoint.Direction == HoistingPointDirection.Longitudinal ? "纵向" : "横向";
|
||||
RaiseStatusChanged($"已添加{directionText}路径点,继续点击或点击完成按钮", PathPlanningStatusType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[吊装模式] 生成吊装路径失败: {ex.Message}", ex);
|
||||
System.Windows.MessageBox.Show($"生成吊装路径失败: {ex.Message}", "错误",
|
||||
System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
|
||||
LogManager.Error($"[吊装模式] 生成空中路径点失败: {ex.Message}", ex);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@ -67,6 +67,28 @@ namespace NavisworksTransport
|
||||
Hoisting = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 吊装路径点方向类型
|
||||
/// 用于标识吊装路径中每个路径点的移动方向
|
||||
/// </summary>
|
||||
public enum HoistingPointDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// 垂直移动(起吊/下降)
|
||||
/// </summary>
|
||||
Vertical,
|
||||
|
||||
/// <summary>
|
||||
/// 纵向移动(X轴方向)
|
||||
/// </summary>
|
||||
Longitudinal,
|
||||
|
||||
/// <summary>
|
||||
/// 横向移动(Y轴方向)
|
||||
/// </summary>
|
||||
Lateral
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通道检测结果
|
||||
/// </summary>
|
||||
@ -297,6 +319,12 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
public double? CustomTurnRadius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方向类型(仅吊装路径使用)
|
||||
/// 用于标识吊装路径点的移动方向:垂直、纵向(X轴)、横向(Y轴)
|
||||
/// </summary>
|
||||
public HoistingPointDirection Direction { get; set; } = HoistingPointDirection.Vertical;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@ -311,6 +339,7 @@ namespace NavisworksTransport
|
||||
Notes = string.Empty;
|
||||
SpeedLimit = 0;
|
||||
CustomTurnRadius = null;
|
||||
Direction = HoistingPointDirection.Vertical;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -330,6 +359,7 @@ namespace NavisworksTransport
|
||||
Notes = string.Empty;
|
||||
SpeedLimit = 0;
|
||||
CustomTurnRadius = null;
|
||||
Direction = HoistingPointDirection.Vertical;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -649,6 +649,9 @@ namespace NavisworksTransport
|
||||
|
||||
try
|
||||
{
|
||||
// 清除所有其他路径的可视化,只保留当前路径
|
||||
ClearPathsExcept(pathRoute.Id);
|
||||
|
||||
var visualization = new PathVisualization
|
||||
{
|
||||
PathId = pathRoute.Id,
|
||||
@ -1706,8 +1709,25 @@ namespace NavisworksTransport
|
||||
bool isVerticalSegment = false;
|
||||
if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting)
|
||||
{
|
||||
// 吊装路径:0-1是起吊段(垂直),1-2是平移段(水平),2-3是下降段(垂直)
|
||||
isVerticalSegment = (i == 0 || i == 2);
|
||||
// 吊装路径:支持动态数量的路径点
|
||||
// 路径点结构:
|
||||
// 点0(起吊点):地面位置
|
||||
// 点1(提升点):悬挂点
|
||||
// 点2...点N-2:中间悬挂点(用户添加的转向点)
|
||||
// 点N-1(下降点):悬挂点
|
||||
// 点N(落地点):地面位置
|
||||
//
|
||||
// 线段结构:
|
||||
// 线段0:起吊段(垂直)
|
||||
// 线段1...线段N-2:平移段(水平)
|
||||
// 线段N-1:下降段(垂直)
|
||||
|
||||
int totalSegments = sortedPoints.Count - 1;
|
||||
int firstSegment = 0; // 起吊段
|
||||
int lastSegment = totalSegments - 1; // 下降段
|
||||
|
||||
// 第一个线段和最后一个线段是垂直的
|
||||
isVerticalSegment = (i == firstSegment || i == lastSegment);
|
||||
}
|
||||
|
||||
// 计算通行空间参数(根据段类型)
|
||||
|
||||
@ -8,11 +8,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <summary>
|
||||
/// 空中路径生成器
|
||||
/// 用于生成吊装路径(起点吊起 → 平移 → 终点吊下)
|
||||
/// 支持智能方向判断和基于地面投影点的动态路径生成
|
||||
/// </summary>
|
||||
public class AerialPathGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 方向判断容差(米)
|
||||
/// 当两个方向的距离差小于此值时,默认选择纵向
|
||||
/// </summary>
|
||||
private const double DIRECTION_TOLERANCE = 0.001;
|
||||
|
||||
/// <summary>
|
||||
/// 生成吊装路径(起点吊起 → 平移 → 终点吊下)
|
||||
/// 保留原有方法以保持向后兼容
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点(吊起位置)</param>
|
||||
/// <param name="endPoint">终点(下降位置)</param>
|
||||
@ -34,36 +42,198 @@ namespace NavisworksTransport.PathPlanning
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMeters);
|
||||
|
||||
// 点1:起吊点(物体初始位置)
|
||||
pathPoints.Add(new PathPoint(
|
||||
var startPointPath = new PathPoint(
|
||||
startPoint,
|
||||
"起吊点",
|
||||
PathPointType.StartPoint));
|
||||
PathPointType.StartPoint);
|
||||
startPointPath.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(startPointPath);
|
||||
|
||||
// 点2:提升点(起点正上方,达到提升高度)
|
||||
var liftPoint = new Point3D(
|
||||
startPoint.X,
|
||||
startPoint.Y,
|
||||
startPoint.Z + liftHeightModelUnits);
|
||||
pathPoints.Add(new PathPoint(
|
||||
var liftPointPath = new PathPoint(
|
||||
liftPoint,
|
||||
"提升点",
|
||||
PathPointType.WayPoint));
|
||||
PathPointType.WayPoint);
|
||||
liftPointPath.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(liftPointPath);
|
||||
|
||||
// 点3:平移终点(终点正上方,保持提升高度)
|
||||
var moveEndPoint = new Point3D(
|
||||
endPoint.X,
|
||||
endPoint.Y,
|
||||
liftPoint.Z); // 使用提升点的Z坐标,保持提升高度一致
|
||||
pathPoints.Add(new PathPoint(
|
||||
var moveEndPointPath = new PathPoint(
|
||||
moveEndPoint,
|
||||
"平移终点",
|
||||
PathPointType.WayPoint));
|
||||
PathPointType.WayPoint);
|
||||
moveEndPointPath.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(moveEndPointPath);
|
||||
|
||||
// 点4:下降点(终点位置,物体最终位置)
|
||||
pathPoints.Add(new PathPoint(
|
||||
var endPointPath = new PathPoint(
|
||||
endPoint,
|
||||
"下降点",
|
||||
PathPointType.EndPoint));
|
||||
PathPointType.EndPoint);
|
||||
endPointPath.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(endPointPath);
|
||||
|
||||
return pathPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断移动方向并生成路径点
|
||||
/// 根据用户点击的地面投影位置和上一个路径点,自动判断纵向或横向移动
|
||||
/// </summary>
|
||||
/// <param name="previousPoint">上一个路径点</param>
|
||||
/// <param name="clickedGroundPoint">用户点击的地面投影位置</param>
|
||||
/// <param name="liftHeightMeters">吊装高度(米)</param>
|
||||
/// <param name="pointIndex">路径点序号</param>
|
||||
/// <returns>生成的路径点</returns>
|
||||
public PathPoint GenerateSmartHoistingPoint(
|
||||
Point3D previousPoint,
|
||||
Point3D clickedGroundPoint,
|
||||
double liftHeightMeters,
|
||||
int pointIndex)
|
||||
{
|
||||
if (previousPoint == null)
|
||||
throw new ArgumentNullException(nameof(previousPoint));
|
||||
if (clickedGroundPoint == null)
|
||||
throw new ArgumentNullException(nameof(clickedGroundPoint));
|
||||
if (liftHeightMeters <= 0)
|
||||
throw new ArgumentException("提升高度必须大于0", nameof(liftHeightMeters));
|
||||
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMeters);
|
||||
|
||||
// 计算两个方向的距离
|
||||
double deltaX = Math.Abs(clickedGroundPoint.X - previousPoint.X);
|
||||
double deltaY = Math.Abs(clickedGroundPoint.Y - previousPoint.Y);
|
||||
|
||||
Point3D newPoint;
|
||||
HoistingPointDirection direction;
|
||||
string pointName;
|
||||
|
||||
// 判断移动方向
|
||||
if (Math.Abs(deltaX - deltaY) < DIRECTION_TOLERANCE)
|
||||
{
|
||||
// 距离相等,默认选择纵向
|
||||
newPoint = new Point3D(
|
||||
clickedGroundPoint.X,
|
||||
previousPoint.Y,
|
||||
previousPoint.Z); // 使用上一个路径点的Z坐标(保持吊装高度)
|
||||
direction = HoistingPointDirection.Longitudinal;
|
||||
pointName = $"路径点{pointIndex}";
|
||||
}
|
||||
else if (deltaX > deltaY)
|
||||
{
|
||||
// 更偏向纵向移动(X轴)
|
||||
// 保持Y坐标不变,使用点击的X坐标
|
||||
newPoint = new Point3D(
|
||||
clickedGroundPoint.X,
|
||||
previousPoint.Y,
|
||||
previousPoint.Z); // 使用上一个路径点的Z坐标(保持吊装高度)
|
||||
direction = HoistingPointDirection.Longitudinal;
|
||||
pointName = $"路径点{pointIndex}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 更偏向横向移动(Y轴)
|
||||
// 保持X坐标不变,使用点击的Y坐标
|
||||
newPoint = new Point3D(
|
||||
previousPoint.X,
|
||||
clickedGroundPoint.Y,
|
||||
previousPoint.Z); // 使用上一个路径点的Z坐标(保持吊装高度)
|
||||
direction = HoistingPointDirection.Lateral;
|
||||
pointName = $"路径点{pointIndex}";
|
||||
}
|
||||
|
||||
var pathPoint = new PathPoint(newPoint, pointName, PathPointType.WayPoint);
|
||||
pathPoint.Direction = direction;
|
||||
|
||||
return pathPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于智能判断生成吊装路径
|
||||
/// 支持用户点击地面投影位置,系统自动判断方向并生成空中路径点
|
||||
/// </summary>
|
||||
/// <param name="startPoint">地面起点(用户点击)</param>
|
||||
/// <param name="endPoint">地面终点(用户点击)</param>
|
||||
/// <param name="liftHeightMeters">吊装高度(米)</param>
|
||||
/// <param name="groundIntermediatePoints">用户点击的地面中间点列表</param>
|
||||
/// <returns>生成的路径点列表</returns>
|
||||
public List<PathPoint> GenerateSmartHoistingPath(
|
||||
Point3D startPoint,
|
||||
Point3D endPoint,
|
||||
double liftHeightMeters,
|
||||
List<Point3D> groundIntermediatePoints)
|
||||
{
|
||||
if (startPoint == null)
|
||||
throw new ArgumentNullException(nameof(startPoint));
|
||||
if (endPoint == null)
|
||||
throw new ArgumentNullException(nameof(endPoint));
|
||||
if (liftHeightMeters <= 0)
|
||||
throw new ArgumentException("提升高度必须大于0", nameof(liftHeightMeters));
|
||||
if (groundIntermediatePoints == null)
|
||||
throw new ArgumentNullException(nameof(groundIntermediatePoints));
|
||||
|
||||
var pathPoints = new List<PathPoint>();
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMeters);
|
||||
|
||||
// 点1:起吊点(地面起点)
|
||||
var startPathPoint = new PathPoint(
|
||||
startPoint,
|
||||
"起吊点",
|
||||
PathPointType.StartPoint);
|
||||
startPathPoint.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(startPathPoint);
|
||||
|
||||
// 点2:提升点(起点正上方,吊装高度)
|
||||
var liftPoint = new Point3D(
|
||||
startPoint.X,
|
||||
startPoint.Y,
|
||||
startPoint.Z + liftHeightModelUnits);
|
||||
var liftPathPoint = new PathPoint(
|
||||
liftPoint,
|
||||
"提升点",
|
||||
PathPointType.WayPoint);
|
||||
liftPathPoint.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(liftPathPoint);
|
||||
|
||||
// 中间点(智能判断方向)
|
||||
Point3D previousPoint = liftPoint;
|
||||
|
||||
for (int i = 0; i < groundIntermediatePoints.Count; i++)
|
||||
{
|
||||
var newPoint = GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
groundIntermediatePoints[i],
|
||||
liftHeightMeters,
|
||||
i + 1);
|
||||
|
||||
pathPoints.Add(newPoint);
|
||||
previousPoint = newPoint.Position;
|
||||
}
|
||||
|
||||
// 最后一个空中点(用于垂直下降)
|
||||
var lastAerialPoint = previousPoint;
|
||||
var descendPathPoint = new PathPoint(
|
||||
lastAerialPoint,
|
||||
"下降点",
|
||||
PathPointType.WayPoint);
|
||||
descendPathPoint.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(descendPathPoint);
|
||||
|
||||
// 落地点(地面终点)
|
||||
var endPathPoint = new PathPoint(
|
||||
endPoint,
|
||||
"落地点",
|
||||
PathPointType.EndPoint);
|
||||
endPathPoint.Direction = HoistingPointDirection.Vertical;
|
||||
pathPoints.Add(endPathPoint);
|
||||
|
||||
return pathPoints;
|
||||
}
|
||||
|
||||
@ -1066,7 +1066,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
_pathPlanningManager.StartClickTool(PathPointType.WayPoint, enableRailSnapping: false, enableHoistingMode: true);
|
||||
LogManager.Info($"已启动吊装路径点击工具: {newRoute.Name}");
|
||||
|
||||
UpdateMainStatus($"已进入新建吊装路径模式: {newRoute.Name} - 请在3D视图中点击设置起点");
|
||||
UpdateMainStatus($"已进入新建吊装路径模式: {newRoute.Name} - 请在3D视图中点击吊装起点(地面位置)");
|
||||
LogManager.Info($"开始新建吊装路径: {newRoute.Name},已强制重新初始化ToolPlugin获取鼠标焦点");
|
||||
}
|
||||
else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user