完善多层吊装路径
This commit is contained in:
parent
edcbd0802b
commit
62548197b3
@ -1689,47 +1689,46 @@ namespace NavisworksTransport
|
||||
{
|
||||
LogManager.Info($"[吊装路径] 正在完成吊装路径,处理终点和下降点");
|
||||
|
||||
// 确保至少有起吊点、提升点和至少一个空中路径点
|
||||
if (CurrentRoute.Points.Count >= 3 && _hoistingGroundIntermediatePoints.Count > 0)
|
||||
// 确保至少有起吊点、提升点
|
||||
if (CurrentRoute.Points.Count >= 2)
|
||||
{
|
||||
// 获取起吊点(用于获取地面Z坐标)
|
||||
var startPoint = CurrentRoute.Points.First();
|
||||
|
||||
// 获取吊装高度(内部使用模型单位,如果未设置则默认3米)
|
||||
double liftHeightModelUnits = CurrentRoute.LiftHeight > 0 ? CurrentRoute.LiftHeight : UnitsConverter.ConvertFromMeters(3.0);
|
||||
// 获取最后一个路径点(用于获取当前的空中XY位置)
|
||||
var lastPoint = CurrentRoute.Points.Last();
|
||||
LogManager.Info($"[吊装路径] 最后一个路径点: {lastPoint.Name}, 位置: ({lastPoint.Position.X:F2}, {lastPoint.Position.Y:F2}, {lastPoint.Position.Z:F2})");
|
||||
|
||||
// 获取最后一个地面点击点(原始坐标,未被调整过)
|
||||
var lastGroundClick = _hoistingGroundIntermediatePoints.Last();
|
||||
LogManager.Debug($"[吊装路径] 最后一个地面点击点: ({lastGroundClick.X:F2}, {lastGroundClick.Y:F2}, {lastGroundClick.Z:F2})");
|
||||
// 计算下一个索引
|
||||
int nextIndex = CurrentRoute.Points.Count;
|
||||
|
||||
// 删除最后一个空中路径点(它的坐标可能被调整过,不使用任何信息)
|
||||
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坐标为吊装高度
|
||||
// 创建下降点:在落地点正上方,Z坐标为最后一个路径点的Z(保持当前高度)
|
||||
var descendPoint = new PathPoint(
|
||||
new Point3D(endPoint.Position.X, endPoint.Position.Y, startPoint.Position.Z + liftHeightModelUnits),
|
||||
new Point3D(lastPoint.Position.X, lastPoint.Position.Y, lastPoint.Position.Z),
|
||||
"下降点",
|
||||
PathPointType.WayPoint);
|
||||
descendPoint.Direction = HoistingPointDirection.Vertical;
|
||||
LogManager.Debug($"[吊装路径] 已生成下降点(在终点正上方): ({descendPoint.Position.X:F2}, {descendPoint.Position.Y:F2}, {descendPoint.Position.Z:F2})");
|
||||
descendPoint.Index = nextIndex++;
|
||||
LogManager.Info($"[吊装路径] 已生成下降点(在终点正上方): ({descendPoint.Position.X:F2}, {descendPoint.Position.Y:F2}, {descendPoint.Position.Z:F2})");
|
||||
|
||||
// 创建落地点(终点):使用最后一个路径点的XY,使用起点Z作为地面高度
|
||||
var endPoint = new PathPoint(
|
||||
new Point3D(lastPoint.Position.X, lastPoint.Position.Y, startPoint.Position.Z),
|
||||
"落地点",
|
||||
PathPointType.EndPoint);
|
||||
endPoint.Direction = HoistingPointDirection.Vertical;
|
||||
endPoint.Index = nextIndex++;
|
||||
LogManager.Info($"[吊装路径] 已创建落地点(终点): ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.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})");
|
||||
LogManager.Info($"[吊装路径] 已添加下降点和落地点,当前共 {CurrentRoute.Points.Count} 个路径点");
|
||||
|
||||
// 优化路径点:处理斜线和清除多余点
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
// 注意:不需要再次调用 OrthogonalizePath,因为添加的只是垂直线段
|
||||
// 垂直线段不会形成斜线,所以不需要优化
|
||||
|
||||
// 注意:TotalLength 现在是计算属性,自动从几何数据计算,无需手动更新
|
||||
|
||||
@ -1921,6 +1920,7 @@ namespace NavisworksTransport
|
||||
|
||||
/// <summary>
|
||||
/// 检测两点之间是否为斜线,如果是则插入中间转折点或修正坐标
|
||||
/// 处理三种斜线:XY平面斜线、XZ平面斜线、YZ平面斜线
|
||||
/// </summary>
|
||||
/// <param name="points">路径点列表</param>
|
||||
/// <param name="startIndex">开始检查的索引</param>
|
||||
@ -1935,134 +1935,193 @@ namespace NavisworksTransport
|
||||
var currentPoint = points[startIndex];
|
||||
var nextPoint = points[startIndex + 1];
|
||||
|
||||
LogManager.Debug($"[斜线处理] 检查索引 {startIndex} 和 {startIndex + 1} 之间的连线");
|
||||
LogManager.Debug($"[斜线处理] 当前点 [{startIndex}]: {currentPoint.Name}, 位置: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
LogManager.Debug($"[斜线处理] 下一点 [{startIndex + 1}]: {nextPoint.Name}, 位置: ({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
|
||||
// 使用 Info 级别日志以便调试
|
||||
LogManager.Info($"[斜线处理] 检查索引 {startIndex} 和 {startIndex + 1} 之间的连线");
|
||||
LogManager.Info($"[斜线处理] 当前点 [{startIndex}]: {currentPoint.Name}, 位置: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
LogManager.Info($"[斜线处理] 下一点 [{startIndex + 1}]: {nextPoint.Name}, 位置: ({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
|
||||
|
||||
double deltaX = Math.Abs(nextPoint.Position.X - currentPoint.Position.X);
|
||||
double deltaY = Math.Abs(nextPoint.Position.Y - currentPoint.Position.Y);
|
||||
double deltaZ = Math.Abs(nextPoint.Position.Z - currentPoint.Position.Z);
|
||||
|
||||
// 检测斜线(X和Y都变化)
|
||||
bool isDiagonal = deltaX > 0.01 && deltaY > 0.01;
|
||||
LogManager.Info($"[斜线处理] deltaX={deltaX:F2}, deltaY={deltaY:F2}, deltaZ={deltaZ:F2}");
|
||||
|
||||
if (!isDiagonal)
|
||||
// 检测三种斜线
|
||||
bool isXYDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ < 0.001; // XY平面斜线
|
||||
bool isXZDiagonal = deltaX > 0.01 && deltaZ > 0.001 && deltaY < 0.01; // XZ平面斜线
|
||||
bool isYZDiagonal = deltaY > 0.01 && deltaZ > 0.001 && deltaX < 0.01; // YZ平面斜线
|
||||
bool isXYZDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ > 0.001; // XYZ空间斜线
|
||||
|
||||
LogManager.Info($"[斜线处理] 斜线检测结果: XY={isXYDiagonal}, XZ={isXZDiagonal}, YZ={isYZDiagonal}, XYZ={isXYZDiagonal}");
|
||||
|
||||
if (!isXYDiagonal && !isXZDiagonal && !isYZDiagonal && !isXYZDiagonal)
|
||||
{
|
||||
LogManager.Info($"[斜线处理] 未检测到斜线,跳过处理");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 区分两种情况:
|
||||
// 1. 真正的斜线:deltaX和deltaY都比较大(>2.0)→ 插入中间点
|
||||
// 2. 微小偏差:其中一个值很小(<0.5)→ 修改下一点坐标,使其与上一点对齐
|
||||
|
||||
if (deltaX > 2.0 && deltaY > 2.0)
|
||||
// 处理XY平面斜线(水平斜线)
|
||||
if (isXYDiagonal)
|
||||
{
|
||||
// 真正的斜线:插入中间点
|
||||
LogManager.Debug($"[斜线处理] 检测到斜线,需要插入中间点 (deltaX={deltaX:F2}, deltaY={deltaY:F2})");
|
||||
|
||||
int intermediateIndex = points.Count > 0 ? points.Count : 1;
|
||||
var intermediatePoint = new PathPoint(
|
||||
new Point3D(
|
||||
nextPoint.Position.X, // 使用新点的X
|
||||
currentPoint.Position.Y, // 保持上一个点的Y
|
||||
currentPoint.Position.Z // 保持吊装高度
|
||||
),
|
||||
$"路径点{intermediateIndex}",
|
||||
PathPointType.WayPoint);
|
||||
intermediatePoint.Direction = HoistingPointDirection.Longitudinal; // 纵向移动
|
||||
|
||||
int insertPosition = startIndex + 1;
|
||||
points.Insert(insertPosition, intermediatePoint);
|
||||
|
||||
// 更新所有点的索引
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
points[i].Index = i;
|
||||
}
|
||||
|
||||
LogManager.Debug($"[斜线处理] 已插入中间点: {intermediatePoint.Name}, 位置: ({intermediatePoint.Position.X:F2}, {intermediatePoint.Position.Y:F2}, {intermediatePoint.Position.Z:F2}) - 方向: 纵向");
|
||||
LogManager.Debug($"[斜线处理] 插入位置: 索引 {insertPosition}, 当前路径点总数: {points.Count}");
|
||||
|
||||
return true;
|
||||
return HandleXYDiagonal(points, startIndex, currentPoint, nextPoint, deltaX, deltaY);
|
||||
}
|
||||
else if (deltaX < 0.5 && deltaY > 0.5)
|
||||
|
||||
// 处理XZ平面斜线(垂直斜线:X和Z同时变化)
|
||||
if (isXZDiagonal)
|
||||
{
|
||||
// X方向微小偏差,Y方向移动:修改下一点坐标,保持X与上一点对齐(垂直线)
|
||||
LogManager.Debug($"[斜线处理] 检测到X方向微小偏差 (deltaX={deltaX:F2}, deltaY={deltaY:F2}),修正下一点坐标使其垂直");
|
||||
|
||||
nextPoint.Position = new Point3D(
|
||||
currentPoint.Position.X, // 保持上一个点的X
|
||||
nextPoint.Position.Y, // 保持新点的Y
|
||||
nextPoint.Position.Z); // 保持新点的Z
|
||||
|
||||
LogManager.Debug($"[斜线处理] 已修正下一点 {nextPoint.Name} 坐标: ({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
|
||||
return true;
|
||||
return HandleXZDiagonal(points, startIndex, currentPoint, nextPoint, deltaX, deltaZ);
|
||||
}
|
||||
else if (deltaY < 0.5 && deltaX > 0.5)
|
||||
|
||||
// 处理YZ平面斜线(垂直斜线:Y和Z同时变化)
|
||||
if (isYZDiagonal)
|
||||
{
|
||||
// Y方向微小偏差,X方向移动:修改下一点坐标,保持Y与上一点对齐(水平线)
|
||||
LogManager.Debug($"[斜线处理] 检测到Y方向微小偏差 (deltaX={deltaX:F2}, deltaY={deltaY:F2}),修正下一点坐标使其水平");
|
||||
|
||||
nextPoint.Position = new Point3D(
|
||||
nextPoint.Position.X, // 保持新点的X
|
||||
currentPoint.Position.Y, // 保持上一个点的Y
|
||||
nextPoint.Position.Z); // 保持新点的Z
|
||||
|
||||
LogManager.Debug($"[斜线处理] 已修正下一点 {nextPoint.Name} 坐标: ({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
|
||||
return true;
|
||||
return HandleYZDiagonal(points, startIndex, currentPoint, nextPoint, deltaY, deltaZ);
|
||||
}
|
||||
|
||||
// 处理XYZ空间斜线(X、Y、Z都变化)
|
||||
if (isXYZDiagonal)
|
||||
{
|
||||
return HandleXYZDiagonal(points, startIndex, currentPoint, nextPoint, deltaX, deltaY, deltaZ);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理XY平面斜线(水平斜线)
|
||||
/// 策略:插入中间点将斜线拆分为直角转折,保持用户点击的坐标不变
|
||||
/// </summary>
|
||||
private bool HandleXYDiagonal(IList<PathPoint> points, int startIndex, PathPoint currentPoint, PathPoint nextPoint, double deltaX, double deltaY)
|
||||
{
|
||||
LogManager.Debug($"[斜线处理] 检测到XY平面斜线 (deltaX={deltaX:F2}, deltaY={deltaY:F2})");
|
||||
|
||||
// 策略:插入中间点,将斜线拆分为 X-only → Y-only 的两段直角路径
|
||||
// 不修改用户点击的坐标,只插入转折点
|
||||
// 转折点:X用新点的X,Y用旧点的Y(先X方向移动,再Y方向移动)
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(nextPoint.Position.X, currentPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Longitudinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理XZ平面斜线(垂直斜线:X和Z同时变化)
|
||||
/// 策略:先水平移动(X变化,Z不变),再垂直移动(Z变化,X不变)
|
||||
/// </summary>
|
||||
private bool HandleXZDiagonal(IList<PathPoint> points, int startIndex, PathPoint currentPoint, PathPoint nextPoint, double deltaX, double deltaZ)
|
||||
{
|
||||
LogManager.Debug($"[斜线处理] 检测到XZ平面斜线 (deltaX={deltaX:F2}, deltaZ={deltaZ:F2})");
|
||||
|
||||
// 插入中间点:先水平移动(到新X,旧Z),目标点自然就是(新X,新Z)
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(nextPoint.Position.X, currentPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Longitudinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理YZ平面斜线(垂直斜线:Y和Z同时变化)
|
||||
/// 策略:先水平移动(Y变化,Z不变),再垂直移动(Z变化,Y不变)
|
||||
/// </summary>
|
||||
private bool HandleYZDiagonal(IList<PathPoint> points, int startIndex, PathPoint currentPoint, PathPoint nextPoint, double deltaY, double deltaZ)
|
||||
{
|
||||
LogManager.Debug($"[斜线处理] 检测到YZ平面斜线 (deltaY={deltaY:F2}, deltaZ={deltaZ:F2})");
|
||||
|
||||
// 插入中间点:先水平移动(到新Y,旧Z),目标点自然就是(新Y,新Z)
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(currentPoint.Position.X, nextPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Lateral);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理XYZ空间斜线(X、Y、Z都变化)
|
||||
/// 策略:先水平移动(XY平面,Z不变),再垂直移动(Z变化,XY不变)
|
||||
/// 水平移动时如果XY也是斜线,则进一步拆分
|
||||
/// </summary>
|
||||
private bool HandleXYZDiagonal(IList<PathPoint> points, int startIndex, PathPoint currentPoint, PathPoint nextPoint, double deltaX, double deltaY, double deltaZ)
|
||||
{
|
||||
LogManager.Debug($"[斜线处理] 检测到XYZ空间斜线 (deltaX={deltaX:F2}, deltaY={deltaY:F2}, deltaZ={deltaZ:F2})");
|
||||
|
||||
// 分两步:
|
||||
// 1. 先水平移动到目标XY(保持当前Z)
|
||||
// 2. 再垂直移动到目标Z(保持XY不变)
|
||||
|
||||
// 如果水平移动也是斜线(X和Y都变化),则先处理XY斜线
|
||||
if (deltaX > 0.01 && deltaY > 0.01)
|
||||
{
|
||||
// 插入中间点:先X方向移动(保持Y),到目标X后再处理Y和Z
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(nextPoint.Position.X, currentPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Longitudinal);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 中等程度的偏差,插入中间点
|
||||
LogManager.Debug($"[斜线处理] 检测到中等程度斜线,需要插入中间点 (deltaX={deltaX:F2}, deltaY={deltaY:F2})");
|
||||
|
||||
int intermediateIndex = points.Count > 0 ? points.Count : 1;
|
||||
var intermediatePoint = new PathPoint(
|
||||
new Point3D(
|
||||
nextPoint.Position.X, // 使用新点的X
|
||||
currentPoint.Position.Y, // 保持上一个点的Y
|
||||
currentPoint.Position.Z // 保持吊装高度
|
||||
),
|
||||
$"路径点{intermediateIndex}",
|
||||
PathPointType.WayPoint);
|
||||
intermediatePoint.Direction = HoistingPointDirection.Longitudinal; // 纵向移动
|
||||
|
||||
int insertPosition = startIndex + 1;
|
||||
points.Insert(insertPosition, intermediatePoint);
|
||||
|
||||
// 更新所有点的索引
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
// 水平方向只有一个轴变化,直接插入中间点处理垂直斜线
|
||||
// 选择变化较大的水平轴作为先移动的方向
|
||||
if (deltaX > deltaY)
|
||||
{
|
||||
points[i].Index = i;
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(nextPoint.Position.X, currentPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Longitudinal);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InsertIntermediatePoint(points, startIndex, currentPoint, nextPoint,
|
||||
new Point3D(currentPoint.Position.X, nextPoint.Position.Y, currentPoint.Position.Z),
|
||||
HoistingPointDirection.Lateral);
|
||||
}
|
||||
|
||||
LogManager.Debug($"[斜线处理] 已插入中间点: {intermediatePoint.Name}, 位置: ({intermediatePoint.Position.X:F2}, {intermediatePoint.Position.Y:F2}, {intermediatePoint.Position.Z:F2}) - 方向: 纵向");
|
||||
LogManager.Debug($"[斜线处理] 插入位置: 索引 {insertPosition}, 当前路径点总数: {points.Count}");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 优化直角转折路径点:出现斜线时插入点,在同一直线上时清除多余点
|
||||
/// 插入中间点的辅助方法
|
||||
/// </summary>
|
||||
/// <param name="route">要优化的路径</param>
|
||||
/// <returns>是否进行了优化</returns>
|
||||
public bool OptimizeRightAnglePathPoints(PathRoute route)
|
||||
private bool InsertIntermediatePoint(IList<PathPoint> points, int startIndex, PathPoint currentPoint, PathPoint nextPoint,
|
||||
Point3D intermediatePosition, HoistingPointDirection direction)
|
||||
{
|
||||
int intermediateIndex = points.Count > 0 ? points.Count : 1;
|
||||
var intermediatePoint = new PathPoint(intermediatePosition, $"路径点{intermediateIndex}", PathPointType.WayPoint);
|
||||
intermediatePoint.Direction = direction;
|
||||
|
||||
int insertPosition = startIndex + 1;
|
||||
points.Insert(insertPosition, intermediatePoint);
|
||||
|
||||
// 更新所有点的索引
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
points[i].Index = i;
|
||||
}
|
||||
|
||||
LogManager.Info($"[斜线处理] 已插入中间点: {intermediatePoint.Name}, 位置: ({intermediatePoint.Position.X:F2}, {intermediatePoint.Position.Y:F2}, {intermediatePoint.Position.Z:F2}) - 方向: {direction}");
|
||||
LogManager.Info($"[斜线处理] 插入位置: 索引 {insertPosition}, 当前路径点总数: {points.Count}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正交化路径:将斜线路径转换为轴对齐的直角路径
|
||||
/// 出现斜线时插入转折点,使所有线段平行于X、Y或Z轴
|
||||
/// </summary>
|
||||
/// <param name="route">要正交化的路径</param>
|
||||
/// <param name="startIndex">开始正交化的索引,默认从0开始(处理所有点)。用于增量处理,避免修改已处理的点。</param>
|
||||
/// <returns>是否进行了正交化</returns>
|
||||
public bool OrthogonalizePath(PathRoute route, int startIndex = 0)
|
||||
{
|
||||
if (route == null || route.Points.Count < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保startIndex有效
|
||||
if (startIndex < 0) startIndex = 0;
|
||||
if (startIndex >= route.Points.Count - 1) return false;
|
||||
|
||||
bool hasChanges = false;
|
||||
var points = route.Points;
|
||||
double tolerance = 0.001; // 容差,用于判断是否在同一直线上
|
||||
double smallDeviation = 0.5; // 微小偏差阈值,用于修正坐标
|
||||
double minDistance = 1.0; // 最小距离阈值,小于此距离不删除点
|
||||
|
||||
// 第一步:处理斜线,插入转折点或修正坐标
|
||||
// 注意:由于可能插入点,需要从后往前遍历或使用while循环
|
||||
int i = 0;
|
||||
// 从startIndex开始,只处理新添加的点
|
||||
int i = startIndex;
|
||||
while (i < points.Count - 1)
|
||||
{
|
||||
int originalCount = points.Count;
|
||||
@ -2074,7 +2133,7 @@ namespace NavisworksTransport
|
||||
if (points.Count > originalCount)
|
||||
{
|
||||
// 插入了点,继续检查当前索引(因为插入点可能需要进一步优化)
|
||||
LogManager.Debug($"[直角路径优化] 索引{i}处插入了点,继续检查");
|
||||
LogManager.Info($"[直角路径优化] 索引{i}处插入了点,继续检查");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2088,64 +2147,10 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
// 第二步:处理微小转折(X或Y方向微小偏差)
|
||||
for (i = 1; i < points.Count - 1; i++)
|
||||
{
|
||||
var prevPoint = points[i - 1];
|
||||
var currentPoint = points[i];
|
||||
var nextPoint = points[i + 1];
|
||||
|
||||
// 计算两个方向的偏差
|
||||
double deltaX1 = Math.Abs(currentPoint.Position.X - prevPoint.Position.X);
|
||||
double deltaY1 = Math.Abs(currentPoint.Position.Y - prevPoint.Position.Y);
|
||||
double deltaX2 = Math.Abs(nextPoint.Position.X - currentPoint.Position.X);
|
||||
double deltaY2 = Math.Abs(nextPoint.Position.Y - currentPoint.Position.Y);
|
||||
|
||||
// 检测微小转折:前一段和后一段都有微小偏差,但方向不同
|
||||
// 例如:前一段X变化很小,Y变化较大;后一段X变化较大,Y变化很小
|
||||
bool hasSmallTurn = false;
|
||||
|
||||
// 前一段垂直,后一段水平
|
||||
if (deltaX1 < smallDeviation && deltaY1 > smallDeviation &&
|
||||
deltaY2 < smallDeviation && deltaX2 > smallDeviation)
|
||||
{
|
||||
hasSmallTurn = true;
|
||||
}
|
||||
// 前一段水平,后一段垂直
|
||||
else if (deltaY1 < smallDeviation && deltaX1 > smallDeviation &&
|
||||
deltaX2 < smallDeviation && deltaY2 > smallDeviation)
|
||||
{
|
||||
hasSmallTurn = true;
|
||||
}
|
||||
|
||||
if (hasSmallTurn && currentPoint.Type == PathPointType.WayPoint)
|
||||
{
|
||||
// 修正转折点坐标,使其完全垂直
|
||||
if (deltaX1 < smallDeviation)
|
||||
{
|
||||
// 前一段垂直:调整转折点X与上一点对齐
|
||||
currentPoint.Position = new Point3D(
|
||||
prevPoint.Position.X,
|
||||
currentPoint.Position.Y,
|
||||
currentPoint.Position.Z);
|
||||
LogManager.Debug($"[直角路径优化] 修正微小转折点 {i} X坐标: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
hasChanges = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 前一段水平:调整转折点Y与上一点对齐
|
||||
currentPoint.Position = new Point3D(
|
||||
currentPoint.Position.X,
|
||||
prevPoint.Position.Y,
|
||||
currentPoint.Position.Z);
|
||||
LogManager.Debug($"[直角路径优化] 修正微小转折点 {i} Y坐标: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第三步:清除在同一直线上的多余点
|
||||
i = 1;
|
||||
// 第二步:清除在同一直线上的多余点
|
||||
// 只检查从startIndex开始的新插入点,避免修改已处理的路径
|
||||
int startForCollinear = Math.Max(1, startIndex);
|
||||
i = startForCollinear;
|
||||
while (i < points.Count - 1)
|
||||
{
|
||||
var prevPoint = points[i - 1];
|
||||
@ -2166,7 +2171,20 @@ namespace NavisworksTransport
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断三个点是否在同一直线上(只检查X或Y方向相同)
|
||||
// 判断三个点是否在同一直线上(需要在3D空间中共线)
|
||||
// 首先检查Z坐标是否相同(在同一平面上)
|
||||
double deltaZ1 = Math.Abs(currentPoint.Position.Z - prevPoint.Position.Z);
|
||||
double deltaZ2 = Math.Abs(nextPoint.Position.Z - currentPoint.Position.Z);
|
||||
bool sameZ = deltaZ1 < tolerance && deltaZ2 < tolerance;
|
||||
|
||||
// 如果Z不同,这三个点一定不共线(一个是垂直过渡点)
|
||||
if (!sameZ)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在同一平面上,检查XY方向是否共线
|
||||
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 &&
|
||||
@ -2185,7 +2203,7 @@ namespace NavisworksTransport
|
||||
// 删除中间点
|
||||
points.RemoveAt(i);
|
||||
hasChanges = true;
|
||||
LogManager.Debug($"[直角路径优化] 删除共线的多余点 {i}: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
LogManager.Info($"[直角路径优化] 删除共线的多余点 {i}: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
||||
|
||||
// 不调整索引,因为删除了一个点,新位置的点会在下一次循环被检查
|
||||
continue;
|
||||
@ -2376,8 +2394,8 @@ namespace NavisworksTransport
|
||||
UpdateAerialPathRelatedPoints(route, pointIndex);
|
||||
}
|
||||
|
||||
// 吊装路径:优化路径点(处理斜线和清除多余点)
|
||||
OptimizeRightAnglePathPoints(route);
|
||||
// 吊装路径:正交化路径(处理斜线和清除多余点)
|
||||
OrthogonalizePath(route);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2876,35 +2894,40 @@ namespace NavisworksTransport
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取吊装高度(LiftHeight内部是模型单位,转换为米传给方法)
|
||||
double liftHeightMeters = CurrentRoute.LiftHeight > 0
|
||||
? UnitsConverter.ConvertToMeters(CurrentRoute.LiftHeight)
|
||||
: 3.0;
|
||||
// 获取吊装高度(LiftHeight内部是模型单位)
|
||||
double liftHeightModelUnits = CurrentRoute.LiftHeight > 0
|
||||
? CurrentRoute.LiftHeight
|
||||
: UnitsConverter.ConvertFromMeters(3.0);
|
||||
|
||||
// 使用 AerialPathGenerator 生成空中路径点
|
||||
var generator = new AerialPathGenerator();
|
||||
confirmPoint = generator.GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
_previewPoint.Position, // 用户点击的地面位置
|
||||
liftHeightMeters,
|
||||
liftHeightModelUnits, // 直接使用模型单位
|
||||
CurrentRoute.Points.Count > 0 ? CurrentRoute.Points.Count : 1);
|
||||
|
||||
LogManager.Info($"[预览点-吊装路径] 已生成空中路径点: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})");
|
||||
|
||||
// 插入到正确位置
|
||||
int optimizeStartIndex;
|
||||
if (_previewInsertIndex >= 0 && _previewInsertIndex <= CurrentRoute.Points.Count)
|
||||
{
|
||||
CurrentRoute.InsertPoint(confirmPoint, _previewInsertIndex);
|
||||
LogManager.Info($"[预览点-吊装路径] 已插入到索引 {_previewInsertIndex}");
|
||||
// 从插入位置的前一个点开始优化
|
||||
optimizeStartIndex = Math.Max(0, _previewInsertIndex - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 追加模式:记录添加前的点数
|
||||
optimizeStartIndex = Math.Max(0, CurrentRoute.Points.Count - 1);
|
||||
CurrentRoute.AddPoint(confirmPoint);
|
||||
LogManager.Info($"[预览点-吊装路径] 已追加到末尾");
|
||||
}
|
||||
|
||||
// 调用路径优化方法处理斜线、微小转折和共线点
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
// 调用正交化方法处理斜线、微小转折和共线点(增量处理)
|
||||
OrthogonalizePath(CurrentRoute, optimizeStartIndex);
|
||||
LogManager.Info($"[预览点-吊装路径] 路径优化完成,当前路径点数: {CurrentRoute.Points.Count}");
|
||||
}
|
||||
else
|
||||
@ -3611,70 +3634,132 @@ namespace NavisworksTransport
|
||||
}
|
||||
else
|
||||
{
|
||||
// 后续点击:添加空中路径点
|
||||
LogManager.Debug($"[吊装模式] 用户点击: ({clickedPoint.X:F2}, {clickedPoint.Y:F2}, {clickedPoint.Z:F2})");
|
||||
// 后续点击:添加新的层级(每次都需要输入高度)
|
||||
LogManager.Debug($"[吊装模式] 用户点击,准备添加新层级: ({clickedPoint.X:F2}, {clickedPoint.Y:F2}, {clickedPoint.Z:F2})");
|
||||
|
||||
// 获取吊装高度(模型单位)
|
||||
double liftHeightModelUnits = _hoistingLiftHeight;
|
||||
if (liftHeightModelUnits <= 0)
|
||||
// 记录地面点击位置,后续在UI线程中处理
|
||||
Point3D groundPoint = clickedPoint;
|
||||
|
||||
// 在UI线程中弹出高度对话框并生成路径点
|
||||
_uiStateManager.QueueUIUpdate(() =>
|
||||
{
|
||||
liftHeightModelUnits = UnitsConverter.ConvertFromMeters(3.0);
|
||||
LogManager.Warning($"[吊装模式] 吊装高度无效,使用默认值: 3.0米");
|
||||
}
|
||||
|
||||
// 使用 AerialPathGenerator 生成单个空中路径点(智能方向判断)
|
||||
try
|
||||
{
|
||||
var generator = new AerialPathGenerator();
|
||||
|
||||
// 获取上一个路径点(用于方向判断)
|
||||
Point3D previousPoint;
|
||||
if (CurrentRoute.Points.Count > 0)
|
||||
try
|
||||
{
|
||||
// 如果已有路径点,使用最后一个路径点
|
||||
previousPoint = CurrentRoute.Points.Last().Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果还没有路径点(第一次添加中间点),使用提升点
|
||||
previousPoint = new Point3D(
|
||||
_hoistingStartPoint.X,
|
||||
_hoistingStartPoint.Y,
|
||||
_hoistingStartPoint.Z + liftHeightModelUnits);
|
||||
}
|
||||
// 计算默认高度(上一次的高度,如果没有则使用3米)
|
||||
double defaultHeightMeters = _hoistingLiftHeight > 0
|
||||
? UnitsConverter.ConvertToMeters(_hoistingLiftHeight)
|
||||
: 3.0;
|
||||
|
||||
var heightDialog = new NavisworksTransport.UI.WPF.Views.AerialHeightDialog(defaultHeight: defaultHeightMeters);
|
||||
bool? dialogResult = heightDialog.ShowDialog();
|
||||
|
||||
// 生成空中路径点
|
||||
var aerialPoint = generator.GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
clickedPoint,
|
||||
liftHeightModelUnits,
|
||||
CurrentRoute.Points.Count > 0 ? CurrentRoute.Points.Count : 1);
|
||||
|
||||
if (aerialPoint != null)
|
||||
{
|
||||
// 保存上一个路径点的索引(用于插入中间点)
|
||||
int previousPointIndex = CurrentRoute.Points.Count - 1;
|
||||
var previousPathPoint = CurrentRoute.Points[previousPointIndex];
|
||||
LogManager.Debug($"[吊装模式] 上一个路径点索引: {previousPointIndex}, 名称: {previousPathPoint.Name}, 位置: ({previousPathPoint.Position.X:F2}, {previousPathPoint.Position.Y:F2})");
|
||||
|
||||
// 记录原始地面点击位置
|
||||
_hoistingGroundIntermediatePoints.Add(clickedPoint);
|
||||
LogManager.Debug($"[吊装模式] 已记录地面点击点: ({clickedPoint.X:F2}, {clickedPoint.Y:F2}, {clickedPoint.Z:F2})");
|
||||
|
||||
// 添加空中路径点(临时)
|
||||
CurrentRoute.AddPoint(aerialPoint);
|
||||
LogManager.Debug($"[吊装模式] 已添加空中路径点: {aerialPoint.Name}, 位置: ({aerialPoint.Position.X:F2}, {aerialPoint.Position.Y:F2}), 当前路径点数: {CurrentRoute.Points.Count}");
|
||||
|
||||
// 调用路径优化方法处理斜线、微小转折和共线点
|
||||
OptimizeRightAnglePathPoints(CurrentRoute);
|
||||
LogManager.Debug($"[吊装模式] 路径优化完成,当前路径点数: {CurrentRoute.Points.Count}");
|
||||
for (int i = 0; i < CurrentRoute.Points.Count; i++)
|
||||
// 如果用户取消,则只是跳过这次点击,继续等待下一次点击
|
||||
if (dialogResult != true)
|
||||
{
|
||||
var p = CurrentRoute.Points[i];
|
||||
LogManager.Debug($" [{i}] {p.Name}: ({p.Position.X:F2}, {p.Position.Y:F2}, {p.Position.Z:F2})");
|
||||
LogManager.Info("[吊装模式] 用户取消了高度设置,继续等待点击");
|
||||
RaiseStatusChanged("已取消,继续点击添加层级或点击完成按钮", PathPlanningStatusType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
LogManager.Debug($"[吊装模式] 已添加空中路径点: {aerialPoint.Name} ({aerialPoint.Position.X:F2}, {aerialPoint.Position.Y:F2}, {aerialPoint.Position.Z:F2}) - 方向: {aerialPoint.Direction}");
|
||||
// 检查用户是否选择"设为终点"(完成路径)
|
||||
bool isSetAsEndPoint = heightDialog.IsSetAsEndPoint;
|
||||
|
||||
// 获取用户设置的高度
|
||||
double liftHeightMetersInput = heightDialog.LiftHeightMeters;
|
||||
double liftHeightModelUnits = UnitsConverter.ConvertFromMeters(liftHeightMetersInput);
|
||||
double previousHeight = _hoistingLiftHeight;
|
||||
_hoistingLiftHeight = liftHeightModelUnits;
|
||||
|
||||
// 更新路径的吊装高度(使用最新的高度)
|
||||
if (CurrentRoute != null)
|
||||
{
|
||||
CurrentRoute.LiftHeight = liftHeightModelUnits;
|
||||
}
|
||||
|
||||
LogManager.Info($"[吊装模式] 用户设置高度: {liftHeightMetersInput:F2}米,上一高度: {UnitsConverter.ConvertToMeters(previousHeight):F2}米");
|
||||
|
||||
// 获取上一个路径点
|
||||
Point3D previousPoint;
|
||||
if (CurrentRoute.Points.Count > 0)
|
||||
{
|
||||
previousPoint = CurrentRoute.Points.Last().Position;
|
||||
var lastPoint = CurrentRoute.Points.Last();
|
||||
LogManager.Info($"[吊装模式] 上一路径点: {lastPoint.Name}, Z={lastPoint.Position.Z:F2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
previousPoint = new Point3D(
|
||||
_hoistingStartPoint.X,
|
||||
_hoistingStartPoint.Y,
|
||||
_hoistingStartPoint.Z + liftHeightModelUnits);
|
||||
LogManager.Info($"[吊装模式] 无上一路径点,使用起点+高度: Z={previousPoint.Z:F2}");
|
||||
}
|
||||
|
||||
// 记录原始地面点击位置
|
||||
_hoistingGroundIntermediatePoints.Add(groundPoint);
|
||||
LogManager.Debug($"[吊装模式] 已记录地面点击点: ({groundPoint.X:F2}, {groundPoint.Y:F2}, {groundPoint.Z:F2})");
|
||||
|
||||
// 检查高度是否变化(比较绝对高度)
|
||||
// liftHeightModelUnits 是相对地面的高度,需要加上起点Z得到绝对高度
|
||||
double newAbsoluteHeight = _hoistingStartPoint.Z + liftHeightModelUnits;
|
||||
double heightDiff = Math.Abs(newAbsoluteHeight - previousPoint.Z);
|
||||
bool heightChanged = heightDiff > 0.001;
|
||||
|
||||
LogManager.Info($"[吊装模式] 起点=({_hoistingStartPoint.X:F2}, {_hoistingStartPoint.Y:F2}, {_hoistingStartPoint.Z:F2})");
|
||||
LogManager.Info($"[吊装模式] 相对高度(米)={liftHeightMetersInput:F2}, 相对高度(模型)={liftHeightModelUnits:F2}");
|
||||
LogManager.Info($"[吊装模式] 新绝对高度={newAbsoluteHeight:F2}, 上一位置Z={previousPoint.Z:F2}");
|
||||
|
||||
// 步骤1:水平移动点(在旧高度上移动到新XY)
|
||||
// 使用 AerialPathGenerator 生成水平路径点
|
||||
LogManager.Info($"[吊装模式] 生成水平路径点: previousPoint=({previousPoint.X:F2}, {previousPoint.Y:F2}, {previousPoint.Z:F2}), groundPoint=({groundPoint.X:F2}, {groundPoint.Y:F2}, {groundPoint.Z:F2})");
|
||||
|
||||
// 记录添加新点前的点数,用于增量优化
|
||||
int pointCountBefore = CurrentRoute.Points.Count;
|
||||
|
||||
var generator = new AerialPathGenerator();
|
||||
var aerialPoint = generator.GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
groundPoint,
|
||||
previousPoint.Z, // 保持旧高度
|
||||
CurrentRoute.Points.Count > 0 ? CurrentRoute.Points.Count : 1);
|
||||
|
||||
if (aerialPoint != null)
|
||||
{
|
||||
// 添加水平移动路径点
|
||||
CurrentRoute.AddPoint(aerialPoint);
|
||||
LogManager.Info($"[吊装模式] 已添加水平路径点: {aerialPoint.Name}, 位置: ({aerialPoint.Position.X:F2}, {aerialPoint.Position.Y:F2}, {aerialPoint.Position.Z:F2})");
|
||||
|
||||
// 更新上一个点为水平路径点
|
||||
previousPoint = aerialPoint.Position;
|
||||
}
|
||||
|
||||
// 步骤2:在添加垂直过渡点前,先正交化水平路径(此时所有点在同一高度,可以处理斜线)
|
||||
// 使用增量处理,只处理新添加的点(从添加前最后一个点的索引开始)
|
||||
int orthogonalizeStartIndex = Math.Max(0, pointCountBefore - 1);
|
||||
OrthogonalizePath(CurrentRoute, orthogonalizeStartIndex);
|
||||
|
||||
// 步骤3:如果需要,添加垂直过渡点
|
||||
if (heightChanged)
|
||||
{
|
||||
// 高度变化:垂直上升到新高度
|
||||
LogManager.Info($"[吊装模式] 高度变化,插入垂直过渡点: Z={previousPoint.Z:F2} -> Z={newAbsoluteHeight:F2}");
|
||||
|
||||
var verticalTransitionPoint = new Point3D(
|
||||
previousPoint.X,
|
||||
previousPoint.Y,
|
||||
newAbsoluteHeight);
|
||||
var verticalPoint = new PathPoint(
|
||||
verticalTransitionPoint,
|
||||
$"高度过渡{CurrentRoute.Points.Count}",
|
||||
PathPointType.WayPoint);
|
||||
verticalPoint.Direction = HoistingPointDirection.Vertical;
|
||||
CurrentRoute.AddPoint(verticalPoint);
|
||||
LogManager.Info($"[吊装模式] 已添加垂直过渡点: ({verticalTransitionPoint.X:F2}, {verticalTransitionPoint.Y:F2}, {verticalTransitionPoint.Z:F2})");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info($"[吊装模式] 高度未变化,无需垂直过渡");
|
||||
}
|
||||
|
||||
// 渲染路径
|
||||
if (_renderPlugin != null)
|
||||
@ -3682,15 +3767,28 @@ namespace NavisworksTransport
|
||||
_renderPlugin.RenderPath(CurrentRoute);
|
||||
}
|
||||
|
||||
// 提示用户可以继续添加或点击完成
|
||||
string directionText = aerialPoint.Direction == HoistingPointDirection.Longitudinal ? "纵向" : "横向";
|
||||
RaiseStatusChanged($"已添加{directionText}路径点,继续点击或点击完成按钮", PathPlanningStatusType.Info);
|
||||
// 如果用户选择"设为终点",调用 FinishEditing 完成路径
|
||||
if (isSetAsEndPoint)
|
||||
{
|
||||
LogManager.Info("[吊装模式] 用户选择设为终点,调用 FinishEditing 完成路径");
|
||||
bool finished = FinishEditing();
|
||||
if (finished && CurrentRoute != null)
|
||||
{
|
||||
// 触发路径列表更新事件,通知UI刷新
|
||||
RaisePathPointsListUpdated(CurrentRoute, "设为终点完成路径");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string transitionText = heightChanged ? "(含高度过渡)" : "";
|
||||
RaiseStatusChanged($"已添加层级路径点{transitionText}(高度: {liftHeightMetersInput:F2}米),继续点击添加新层级或点击完成按钮", PathPlanningStatusType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[吊装模式] 生成空中路径点失败: {ex.Message}", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[吊装模式] 添加层级失败: {ex.Message}", ex);
|
||||
}
|
||||
}, UIUpdatePriority.High);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1494,16 +1494,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
else if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting)
|
||||
{
|
||||
if (isVerticalSegment)
|
||||
{
|
||||
// 吊装路径的垂直段(起吊段和下降段):通行空间底面在地面,不需要偏移
|
||||
verticalOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 吊装的水平段:路径点是悬挂点位置,通行空间顶面在悬挂点,中心需要向上偏移半个高度
|
||||
verticalOffset = height / 2.0;
|
||||
}
|
||||
// 吊装路径:物体顶面中心就是路径点,通行空间整体向下移动半个高度
|
||||
// 这样通行空间顶面中心对齐路径点
|
||||
verticalOffset = -height / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1575,16 +1568,16 @@ namespace NavisworksTransport
|
||||
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
// 通行空间模式且有垂直偏移时,沿Z轴平移(确保只有垂直偏移,没有水平偏移)
|
||||
adjustedStartPoint = new Point3D(
|
||||
startPoint.X + up.X * verticalOffset,
|
||||
startPoint.Y + up.Y * verticalOffset,
|
||||
startPoint.Z + up.Z * verticalOffset
|
||||
startPoint.X,
|
||||
startPoint.Y,
|
||||
startPoint.Z + verticalOffset
|
||||
);
|
||||
adjustedEndPoint = new Point3D(
|
||||
endPoint.X + up.X * verticalOffset,
|
||||
endPoint.Y + up.Y * verticalOffset,
|
||||
endPoint.Z + up.Z * verticalOffset
|
||||
endPoint.X,
|
||||
endPoint.Y,
|
||||
endPoint.Z + verticalOffset
|
||||
);
|
||||
}
|
||||
else
|
||||
@ -1646,28 +1639,28 @@ namespace NavisworksTransport
|
||||
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
// 通行空间模式且有垂直偏移时,沿Z轴平移(确保只有垂直偏移,没有水平偏移)
|
||||
adjustedStartPoint = new Point3D(
|
||||
startPoint.X + up.X * verticalOffset,
|
||||
startPoint.Y + up.Y * verticalOffset,
|
||||
startPoint.Z + up.Z * verticalOffset
|
||||
startPoint.X,
|
||||
startPoint.Y,
|
||||
startPoint.Z + verticalOffset
|
||||
);
|
||||
adjustedEndPoint = new Point3D(
|
||||
endPoint.X + up.X * verticalOffset,
|
||||
endPoint.Y + up.Y * verticalOffset,
|
||||
endPoint.Z + up.Z * verticalOffset
|
||||
endPoint.X,
|
||||
endPoint.Y,
|
||||
endPoint.Z + verticalOffset
|
||||
);
|
||||
|
||||
// 对 SampledPoints 应用垂直偏移(沿着up向量方向)
|
||||
// 对 SampledPoints 应用垂直偏移(沿Z轴)
|
||||
adjustedSampledPoints = new List<Point3D>();
|
||||
if (edge.SampledPoints != null)
|
||||
{
|
||||
foreach (var point in edge.SampledPoints)
|
||||
{
|
||||
adjustedSampledPoints.Add(new Point3D(
|
||||
point.X + up.X * verticalOffset,
|
||||
point.Y + up.Y * verticalOffset,
|
||||
point.Z + up.Z * verticalOffset
|
||||
point.X,
|
||||
point.Y,
|
||||
point.Z + verticalOffset
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -1873,17 +1866,37 @@ namespace NavisworksTransport
|
||||
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
adjustedStartPoint = new Point3D(
|
||||
startPoint.Position.X + up.X * verticalOffset,
|
||||
startPoint.Position.Y + up.Y * verticalOffset,
|
||||
startPoint.Position.Z + up.Z * verticalOffset
|
||||
);
|
||||
adjustedEndPoint = new Point3D(
|
||||
endPoint.Position.X + up.X * verticalOffset,
|
||||
endPoint.Position.Y + up.Y * verticalOffset,
|
||||
endPoint.Position.Z + up.Z * verticalOffset
|
||||
);
|
||||
// 通行空间模式且有垂直偏移时
|
||||
// 垂直空中路径:只沿Z轴偏移(没有水平偏移)
|
||||
// 水平路径:沿up向量偏移(up是垂直的)
|
||||
if (isVerticalSegment)
|
||||
{
|
||||
// 垂直段:只沿Z轴偏移
|
||||
adjustedStartPoint = new Point3D(
|
||||
startPoint.Position.X,
|
||||
startPoint.Position.Y,
|
||||
startPoint.Position.Z + verticalOffset
|
||||
);
|
||||
adjustedEndPoint = new Point3D(
|
||||
endPoint.Position.X,
|
||||
endPoint.Position.Y,
|
||||
endPoint.Position.Z + verticalOffset
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 水平段:沿up向量偏移(up是垂直的)
|
||||
adjustedStartPoint = new Point3D(
|
||||
startPoint.Position.X + up.X * verticalOffset,
|
||||
startPoint.Position.Y + up.Y * verticalOffset,
|
||||
startPoint.Position.Z + up.Z * verticalOffset
|
||||
);
|
||||
adjustedEndPoint = new Point3D(
|
||||
endPoint.Position.X + up.X * verticalOffset,
|
||||
endPoint.Position.Y + up.Y * verticalOffset,
|
||||
endPoint.Position.Z + up.Z * verticalOffset
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2789,6 +2802,7 @@ namespace NavisworksTransport
|
||||
// 直线段:单个长方体
|
||||
// 设置颜色和透明度
|
||||
graphics.Color(lineMarker.Color, lineMarker.Opacity);
|
||||
|
||||
RenderCuboidMarker(
|
||||
graphics,
|
||||
lineMarker.StartPoint,
|
||||
|
||||
@ -89,31 +89,30 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="previousPoint">上一个路径点</param>
|
||||
/// <param name="clickedGroundPoint">用户点击的地面投影位置</param>
|
||||
/// <param name="liftHeightMeters">吊装高度(米)</param>
|
||||
/// <param name="targetHeightModelUnits">目标高度(模型单位)</param>
|
||||
/// <param name="pointIndex">路径点序号</param>
|
||||
/// <returns>生成的路径点</returns>
|
||||
public PathPoint GenerateSmartHoistingPoint(
|
||||
Point3D previousPoint,
|
||||
Point3D clickedGroundPoint,
|
||||
double liftHeightMeters,
|
||||
double targetHeightModelUnits,
|
||||
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));
|
||||
// 注意:targetHeightModelUnits 是绝对高度,可以是负数(如果起点在地下)
|
||||
|
||||
// 计算两个方向的距离
|
||||
double deltaX = Math.Abs(clickedGroundPoint.X - previousPoint.X);
|
||||
double deltaY = Math.Abs(clickedGroundPoint.Y - previousPoint.Y);
|
||||
|
||||
// 直接使用地面点的完整XY值,不调整位置
|
||||
// 使用目标高度作为Z坐标,XY使用地面点击位置
|
||||
Point3D newPoint = new Point3D(
|
||||
clickedGroundPoint.X,
|
||||
clickedGroundPoint.Y,
|
||||
previousPoint.Z); // 使用上一个路径点的Z坐标(保持吊装高度)
|
||||
targetHeightModelUnits); // 使用传入的目标高度
|
||||
|
||||
// 判断移动方向(仅用于记录,不影响位置)
|
||||
HoistingPointDirection direction;
|
||||
@ -195,7 +194,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var newPoint = GenerateSmartHoistingPoint(
|
||||
previousPoint,
|
||||
groundIntermediatePoints[i],
|
||||
liftHeightMeters,
|
||||
liftHeightModelUnits, // 使用模型单位的高度
|
||||
i + 1);
|
||||
|
||||
pathPoints.Add(newPoint);
|
||||
|
||||
@ -2685,10 +2685,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
coreRoute.Points.Remove(corePoint);
|
||||
LogManager.Info($"已从Core数据删除路径点: {corePoint.Name}");
|
||||
|
||||
// 吊装路径:优化路径点(处理斜线和清除多余点)
|
||||
// 吊装路径:正交化路径(处理斜线和清除多余点)
|
||||
if (coreRoute.PathType == PathType.Hoisting)
|
||||
{
|
||||
_pathPlanningManager?.OptimizeRightAnglePathPoints(coreRoute);
|
||||
_pathPlanningManager?.OrthogonalizePath(coreRoute);
|
||||
}
|
||||
|
||||
// 调用PathPlanningManager的3D删除方法
|
||||
|
||||
@ -55,17 +55,28 @@
|
||||
<!-- 按钮栏 -->
|
||||
<Border Grid.Row="2" Background="#FFF8FBFF" BorderBrush="#FFD4E7FF" BorderThickness="0,1,0,0" Padding="20,12">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="确定"
|
||||
<Button Content="继续"
|
||||
Click="OnOKClick"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"
|
||||
Margin="0,0,10,0"/>
|
||||
Margin="0,0,10,0"
|
||||
ToolTip="设置高度并继续添加更多路径点"/>
|
||||
<Button Content="设为终点"
|
||||
Click="OnSetAsEndPointClick"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"
|
||||
Margin="0,0,10,0"
|
||||
Background="#FFE8F5E9"
|
||||
Foreground="#FF2E7D32"
|
||||
ToolTip="将此点设为路径终点,直接降落完成路径"/>
|
||||
<Button Content="取消"
|
||||
Click="OnCancelClick"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"/>
|
||||
Height="32"
|
||||
ToolTip="取消这次点击"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
@ -13,6 +13,11 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
/// </summary>
|
||||
public double LiftHeightMeters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否设为终点(完成路径)
|
||||
/// </summary>
|
||||
public bool IsSetAsEndPoint { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
@ -31,19 +36,26 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确定按钮点击事件
|
||||
/// 确定按钮点击事件 - 添加层级(继续)
|
||||
/// </summary>
|
||||
private void OnOKClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (double.TryParse(HeightTextBox.Text, out double height) && height > 0)
|
||||
if (ValidateHeight())
|
||||
{
|
||||
LiftHeightMeters = height;
|
||||
IsSetAsEndPoint = false;
|
||||
DialogResult = true;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设为终点按钮点击事件 - 完成路径
|
||||
/// </summary>
|
||||
private void OnSetAsEndPointClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ValidateHeight())
|
||||
{
|
||||
System.Windows.MessageBox.Show("请输入有效的提升高度(大于0的数字)", "错误",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
IsSetAsEndPoint = true;
|
||||
DialogResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,5 +66,23 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
{
|
||||
DialogResult = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证输入的高度是否有效
|
||||
/// </summary>
|
||||
private bool ValidateHeight()
|
||||
{
|
||||
if (double.TryParse(HeightTextBox.Text, out double height) && height > 0)
|
||||
{
|
||||
LiftHeightMeters = height;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show("请输入有效的提升高度(大于0的数字)", "错误",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,11 +213,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
<Button Content="吊装路径"
|
||||
Command="{Binding NewHoistingPathCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
ToolTip="创建吊装路径"/>
|
||||
<Button Content="多层吊装"
|
||||
Command="{Binding NewMultiLevelHoistingPathCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
ToolTip="创建多层阶梯式吊装路径"/>
|
||||
ToolTip="创建吊装路径(支持多层)"/>
|
||||
<Button Content="删除"
|
||||
Command="{Binding DeletePathCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
@ -270,151 +266,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 区域3: 多层吊装路径 -->
|
||||
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,10,0,0" Padding="10"
|
||||
Visibility="{Binding IsMultiLevelHoistingMode, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel>
|
||||
<Label Content="多层阶梯式吊装路径" Style="{StaticResource SectionHeaderStyle}"/>
|
||||
<TextBlock Text="设置多个高度层级,支持上升和下降的阶梯式移动"
|
||||
FontSize="10" Foreground="#FF666666" Margin="0,-5,0,5"/>
|
||||
|
||||
<!-- 起点/终点设置 -->
|
||||
<Grid Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 起点 -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<Button Content="选择起点"
|
||||
Command="{Binding SelectMultiLevelStartPointCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
ToolTip="在3D视图中点击选择地面起吊位置"/>
|
||||
<TextBox Text="{Binding MultiLevelStartPointText, Mode=OneWay}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"
|
||||
Width="100"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 终点 -->
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Button Content="选择终点"
|
||||
Command="{Binding SelectMultiLevelEndPointCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
ToolTip="在3D视图中点击选择最终放置位置"/>
|
||||
<TextBox Text="{Binding MultiLevelEndPointText, Mode=OneWay}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"
|
||||
Width="100"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- 层级列表标题 -->
|
||||
<Grid Margin="0,10,0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="层级列表" VerticalAlignment="Center" FontSize="11" Foreground="#FF666666"/>
|
||||
<Button Grid.Column="1" Content="+ 添加层级"
|
||||
Command="{Binding AddMultiLevelCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="80" Height="24"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 层级列表 -->
|
||||
<DataGrid ItemsSource="{Binding MultiLevelItems}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
CanUserDeleteRows="False"
|
||||
SelectionMode="Single"
|
||||
GridLinesVisibility="Horizontal"
|
||||
AlternatingRowBackground="#FFF0F8FF"
|
||||
HeadersVisibility="Column"
|
||||
RowHeaderWidth="0"
|
||||
Height="150">
|
||||
<DataGrid.Columns>
|
||||
<!-- 序号 -->
|
||||
<DataGridTextColumn Header="序号" Binding="{Binding Index, Converter={StaticResource IndexPlusOneConverter}}" Width="45" IsReadOnly="True"/>
|
||||
|
||||
<!-- 高度 -->
|
||||
<DataGridTemplateColumn Header="高度(m)" Width="80">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding HeightInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
|
||||
Width="70" Height="22" FontSize="10"
|
||||
VerticalAlignment="Center" VerticalContentAlignment="Center"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<!-- 方向 -->
|
||||
<DataGridTemplateColumn Header="方向" Width="55">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ToggleButton Content="{Binding IsRise, Converter={StaticResource DirectionToTextConverter}}"
|
||||
IsChecked="{Binding IsRise, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="50" Height="22" FontSize="10"
|
||||
Background="{Binding IsRise, Converter={StaticResource DirectionToColorConverter}}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<!-- 目标位置 -->
|
||||
<DataGridTemplateColumn Header="目标位置" Width="*" MinWidth="100">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding HorizontalTarget, Converter={StaticResource TargetToTextConverter}}"
|
||||
VerticalAlignment="Center" Width="70" FontSize="10"/>
|
||||
<Button Content="📍"
|
||||
Command="{Binding DataContext.PickMultiLevelTargetCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||
CommandParameter="{Binding}"
|
||||
Width="24" Height="22" FontSize="10"
|
||||
ToolTip="拾取目标位置"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<!-- 操作 -->
|
||||
<DataGridTemplateColumn Header="操作" Width="50">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Content="×"
|
||||
Command="{Binding DataContext.DeleteMultiLevelCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||
CommandParameter="{Binding}"
|
||||
Width="24" Height="22"
|
||||
Foreground="Red" FontWeight="Bold"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<!-- 统计信息和创建按钮 -->
|
||||
<Grid Margin="0,10,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{Binding MultiLevelStatsText}"
|
||||
VerticalAlignment="Center" FontSize="10" Foreground="#FF666666"/>
|
||||
<Button Grid.Column="1" Content="创建路径"
|
||||
Command="{Binding CreateMultiLevelPathCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
IsEnabled="{Binding CanCreateMultiLevelPath}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 取消按钮 -->
|
||||
<Button Content="取消多层吊装"
|
||||
Command="{Binding CancelMultiLevelHoistingCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,10,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 区域4: 路径编辑 -->
|
||||
<!-- 区域3: 路径编辑 -->
|
||||
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,10,0,0" Padding="10">
|
||||
<StackPanel>
|
||||
<Label Content="路径编辑" Style="{StaticResource SectionHeaderStyle}"/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user