NavisworksTransport/src/PathPlanning/AerialPathGenerator.cs

315 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.PathPlanning
{
/// <summary>
/// 空中路径生成器
/// 用于生成吊装路径(起点吊起 → 平移 → 终点吊下)
/// 支持智能方向判断和基于地面投影点的动态路径生成
/// </summary>
public class AerialPathGenerator
{
private readonly HostCoordinateAdapter _adapter;
/// <summary>
/// 方向判断容差(米)
/// 当两个方向的距离差小于此值时,默认选择纵向
/// </summary>
private const double DIRECTION_TOLERANCE = 0.001;
public AerialPathGenerator()
: this(HostCoordinateAdapter.CreateFromManager())
{
}
public AerialPathGenerator(HostCoordinateAdapter adapter)
{
_adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));
}
/// <summary>
/// 生成吊装路径(起点吊起 → 平移 → 终点吊下)
/// 保留原有方法以保持向后兼容
/// </summary>
/// <param name="startPoint">起点(吊起位置)</param>
/// <param name="endPoint">终点(下降位置)</param>
/// <param name="liftHeightModelUnits">提升高度(模型单位)</param>
/// <returns>4个路径点起吊点、提升点、平移终点、下降点</returns>
public List<PathPoint> GenerateThreeStepHoistingPath(
Point3D startPoint,
Point3D endPoint,
double liftHeightModelUnits)
{
if (startPoint == null)
throw new ArgumentNullException(nameof(startPoint));
if (endPoint == null)
throw new ArgumentNullException(nameof(endPoint));
if (liftHeightModelUnits <= 0)
throw new ArgumentException("提升高度必须大于0", nameof(liftHeightModelUnits));
var pathPoints = new List<PathPoint>();
// 点1起吊点物体初始位置
var startPointPath = new PathPoint(
startPoint,
"起吊点",
PathPointType.StartPoint);
startPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(startPointPath);
// 点2提升点起点正上方达到提升高度
var liftPoint = HoistingCoordinateHelper.OffsetAlongUp(startPoint, liftHeightModelUnits, _adapter);
var liftPointPath = new PathPoint(
liftPoint,
"提升点",
PathPointType.WayPoint);
liftPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(liftPointPath);
// 点3平移终点终点正上方保持提升高度
var moveEndPoint = HoistingCoordinateHelper.ProjectToAerialElevation(endPoint, liftPoint, _adapter);
var moveEndPointPath = new PathPoint(
moveEndPoint,
"平移终点",
PathPointType.WayPoint);
moveEndPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(moveEndPointPath);
// 点4下降点终点位置物体最终位置
var endPointPath = new PathPoint(
endPoint,
"下降点",
PathPointType.EndPoint);
endPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(endPointPath);
return pathPoints;
}
/// <summary>
/// 判断移动方向并生成路径点
/// 根据用户点击的地面投影位置和上一个路径点,自动判断纵向或横向移动
/// </summary>
/// <param name="previousPoint">上一个路径点</param>
/// <param name="clickedGroundPoint">用户点击的地面投影位置</param>
/// <param name="targetHeightModelUnits">目标高度(模型单位)</param>
/// <param name="pointIndex">路径点序号</param>
/// <returns>生成的路径点</returns>
public PathPoint GenerateSmartHoistingPoint(
Point3D previousPoint,
Point3D clickedGroundPoint,
double targetHeightModelUnits,
int pointIndex)
{
if (previousPoint == null)
throw new ArgumentNullException(nameof(previousPoint));
if (clickedGroundPoint == null)
throw new ArgumentNullException(nameof(clickedGroundPoint));
// 注意targetHeightModelUnits 是绝对高度,可以是负数(如果起点在地下)
// 计算两个方向的距离
double deltaX = Math.Abs(clickedGroundPoint.X - previousPoint.X);
double deltaY = Math.Abs(clickedGroundPoint.Y - previousPoint.Y);
// 使用目标高度作为Z坐标XY使用地面点击位置
Point3D newPoint = HoistingCoordinateHelper.SetElevation(
clickedGroundPoint,
targetHeightModelUnits,
_adapter);
// 判断移动方向(仅用于记录,不影响位置)
HoistingPointDirection direction;
if (Math.Abs(deltaX - deltaY) < DIRECTION_TOLERANCE)
{
// 距离相等,默认选择纵向
direction = HoistingPointDirection.Longitudinal;
}
else if (deltaX > deltaY)
{
// 更偏向纵向移动X轴
direction = HoistingPointDirection.Longitudinal;
}
else
{
// 更偏向横向移动Y轴
direction = HoistingPointDirection.Lateral;
}
string 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);
double liftElevation = HoistingCoordinateHelper.GetElevation(startPoint, _adapter) + liftHeightModelUnits;
// 点1起吊点地面起点
var startPathPoint = new PathPoint(
startPoint,
"起吊点",
PathPointType.StartPoint);
startPathPoint.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(startPathPoint);
// 点2提升点起点正上方吊装高度
var liftPoint = HoistingCoordinateHelper.OffsetAlongUp(startPoint, liftHeightModelUnits, _adapter);
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],
liftElevation,
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;
}
/// <summary>
/// 生成多层阶梯式吊装路径
/// 支持在多个高度层进行水平移动,可混合上升和下降
/// </summary>
/// <param name="startPoint">起点(地面起吊位置)</param>
/// <param name="endPoint">终点(地面落点位置)</param>
/// <param name="levels">层级信息列表(按顺序执行)</param>
/// <returns>路径点列表</returns>
public List<PathPoint> GenerateMultiLevelHoistingPath(
Point3D startPoint,
Point3D endPoint,
List<HoistingLevel> levels)
{
if (startPoint == null)
throw new ArgumentNullException(nameof(startPoint));
if (endPoint == null)
throw new ArgumentNullException(nameof(endPoint));
if (levels == null || levels.Count == 0)
throw new ArgumentException("至少需要指定一个层级", nameof(levels));
var pathPoints = new List<PathPoint>();
// 点1起吊点物体初始位置
var startPointPath = new PathPoint(
startPoint,
"起吊点",
PathPointType.StartPoint);
startPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(startPointPath);
Point3D currentPoint = startPoint;
// 按层级顺序生成路径点
for (int i = 0; i < levels.Count; i++)
{
var level = levels[i];
double levelHeightModelUnits = UnitsConverter.ConvertFromMeters(level.HeightInMeters);
double currentHeight = HoistingCoordinateHelper.GetElevation(startPoint, _adapter) + levelHeightModelUnits;
// 垂直移动点(上升或下降到该层级高度)
var verticalPoint = HoistingCoordinateHelper.SetElevation(currentPoint, currentHeight, _adapter);
string verticalPointName = level.IsRise ? $"提升点{i + 1}" : $"下降点{i + 1}";
var verticalPathPoint = new PathPoint(
verticalPoint,
verticalPointName,
PathPointType.WayPoint);
verticalPathPoint.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(verticalPathPoint);
// 水平移动点(移动到该层级的目标位置,保持高度)
var horizontalPoint = HoistingCoordinateHelper.SetElevation(level.HorizontalTarget, currentHeight, _adapter);
string horizontalPointName = $"平移点{i + 1}";
var horizontalPathPoint = new PathPoint(
horizontalPoint,
horizontalPointName,
PathPointType.WayPoint);
horizontalPathPoint.Direction = HoistingPointDirection.Longitudinal;
pathPoints.Add(horizontalPathPoint);
// 更新当前点为水平移动后的位置
currentPoint = horizontalPoint;
}
// 最后:垂直下降到地面终点
var descendPoint = HoistingCoordinateHelper.ProjectToAerialElevation(endPoint, currentPoint, _adapter);
var descendPathPoint = new PathPoint(
descendPoint,
"最终下降点",
PathPointType.WayPoint);
descendPathPoint.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(descendPathPoint);
// 点N落地点物体最终位置
var endPointPath = new PathPoint(
endPoint,
"落地点",
PathPointType.EndPoint);
endPointPath.Direction = HoistingPointDirection.Vertical;
pathPoints.Add(endPointPath);
return pathPoints;
}
}
}