增加吊装路径水平环形检测
This commit is contained in:
parent
369605e12f
commit
cb7e1c0e17
@ -1732,6 +1732,11 @@ namespace NavisworksTransport
|
|||||||
|
|
||||||
// 注意:TotalLength 现在是计算属性,自动从几何数据计算,无需手动更新
|
// 注意:TotalLength 现在是计算属性,自动从几何数据计算,无需手动更新
|
||||||
|
|
||||||
|
// 检测并移除同一高度层的矩形环路
|
||||||
|
LogManager.Info($"[吊装路径] 开始检测矩形环路,当前路径点数: {CurrentRoute?.Points?.Count ?? 0}");
|
||||||
|
bool loopsRemoved = RemoveRectangularLoops(CurrentRoute);
|
||||||
|
LogManager.Info($"[吊装路径] 矩形环路检测完成,是否移除环路: {loopsRemoved}");
|
||||||
|
|
||||||
// 重新渲染路径
|
// 重新渲染路径
|
||||||
_renderPlugin?.RenderPath(CurrentRoute);
|
_renderPlugin?.RenderPath(CurrentRoute);
|
||||||
|
|
||||||
@ -1936,15 +1941,15 @@ namespace NavisworksTransport
|
|||||||
var nextPoint = points[startIndex + 1];
|
var nextPoint = points[startIndex + 1];
|
||||||
|
|
||||||
// 使用 Info 级别日志以便调试
|
// 使用 Info 级别日志以便调试
|
||||||
LogManager.Info($"[斜线处理] 检查索引 {startIndex} 和 {startIndex + 1} 之间的连线");
|
LogManager.Debug($"[斜线处理] 检查索引 {startIndex} 和 {startIndex + 1} 之间的连线");
|
||||||
LogManager.Info($"[斜线处理] 当前点 [{startIndex}]: {currentPoint.Name}, 位置: ({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2})");
|
LogManager.Debug($"[斜线处理] 当前点 [{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})");
|
LogManager.Debug($"[斜线处理] 下一点 [{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 deltaX = Math.Abs(nextPoint.Position.X - currentPoint.Position.X);
|
||||||
double deltaY = Math.Abs(nextPoint.Position.Y - currentPoint.Position.Y);
|
double deltaY = Math.Abs(nextPoint.Position.Y - currentPoint.Position.Y);
|
||||||
double deltaZ = Math.Abs(nextPoint.Position.Z - currentPoint.Position.Z);
|
double deltaZ = Math.Abs(nextPoint.Position.Z - currentPoint.Position.Z);
|
||||||
|
|
||||||
LogManager.Info($"[斜线处理] deltaX={deltaX:F2}, deltaY={deltaY:F2}, deltaZ={deltaZ:F2}");
|
LogManager.Debug($"[斜线处理] deltaX={deltaX:F2}, deltaY={deltaY:F2}, deltaZ={deltaZ:F2}");
|
||||||
|
|
||||||
// 检测三种斜线
|
// 检测三种斜线
|
||||||
bool isXYDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ < 0.001; // XY平面斜线
|
bool isXYDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ < 0.001; // XY平面斜线
|
||||||
@ -1952,11 +1957,11 @@ namespace NavisworksTransport
|
|||||||
bool isYZDiagonal = deltaY > 0.01 && deltaZ > 0.001 && deltaX < 0.01; // YZ平面斜线
|
bool isYZDiagonal = deltaY > 0.01 && deltaZ > 0.001 && deltaX < 0.01; // YZ平面斜线
|
||||||
bool isXYZDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ > 0.001; // XYZ空间斜线
|
bool isXYZDiagonal = deltaX > 0.01 && deltaY > 0.01 && deltaZ > 0.001; // XYZ空间斜线
|
||||||
|
|
||||||
LogManager.Info($"[斜线处理] 斜线检测结果: XY={isXYDiagonal}, XZ={isXZDiagonal}, YZ={isYZDiagonal}, XYZ={isXYZDiagonal}");
|
LogManager.Debug($"[斜线处理] 斜线检测结果: XY={isXYDiagonal}, XZ={isXZDiagonal}, YZ={isYZDiagonal}, XYZ={isXYZDiagonal}");
|
||||||
|
|
||||||
if (!isXYDiagonal && !isXZDiagonal && !isYZDiagonal && !isXYZDiagonal)
|
if (!isXYDiagonal && !isXZDiagonal && !isYZDiagonal && !isXYZDiagonal)
|
||||||
{
|
{
|
||||||
LogManager.Info($"[斜线处理] 未检测到斜线,跳过处理");
|
LogManager.Debug($"[斜线处理] 未检测到斜线,跳过处理");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2090,8 +2095,8 @@ namespace NavisworksTransport
|
|||||||
points[i].Index = i;
|
points[i].Index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.Info($"[斜线处理] 已插入中间点: {intermediatePoint.Name}, 位置: ({intermediatePoint.Position.X:F2}, {intermediatePoint.Position.Y:F2}, {intermediatePoint.Position.Z:F2}) - 方向: {direction}");
|
LogManager.Debug($"[斜线处理] 已插入中间点: {intermediatePoint.Name}, 位置: ({intermediatePoint.Position.X:F2}, {intermediatePoint.Position.Y:F2}, {intermediatePoint.Position.Z:F2}) - 方向: {direction}");
|
||||||
LogManager.Info($"[斜线处理] 插入位置: 索引 {insertPosition}, 当前路径点总数: {points.Count}");
|
LogManager.Debug($"[斜线处理] 插入位置: 索引 {insertPosition}, 当前路径点总数: {points.Count}");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2226,6 +2231,302 @@ namespace NavisworksTransport
|
|||||||
return hasChanges;
|
return hasChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检测并移除各水平层内的矩形环路
|
||||||
|
/// 限制条件:
|
||||||
|
/// 1. 只处理同一水平层内的点(Z坐标必须完全相同,只考虑浮点数精度误差)
|
||||||
|
/// 2. 不允许处理起点(索引0)和终点(最后一个点)
|
||||||
|
/// 3. 不允许跨层检测(不同Z高度的线段不互相检测)
|
||||||
|
/// 4. 支持多层吊装路径(多个不同高度的水平层)
|
||||||
|
/// 算法原理:按Z坐标分组(严格相等),对每个水平层分别检测正交路径中的相交线段
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="route">路径</param>
|
||||||
|
/// <returns>是否移除了环路</returns>
|
||||||
|
public bool RemoveRectangularLoops(PathRoute route)
|
||||||
|
{
|
||||||
|
if (route == null || route.Points.Count < 4)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasChanges = false;
|
||||||
|
var points = route.Points;
|
||||||
|
// 浮点数精度容差,用于判断Z坐标是否相等
|
||||||
|
const double epsilon = 1e-9;
|
||||||
|
|
||||||
|
LogManager.Debug($"[环路检测] 开始检测,路径点数: {points.Count}");
|
||||||
|
|
||||||
|
// 按Z坐标分组,找出所有水平层(排除起点和终点)
|
||||||
|
// 使用严格相等比较(只考虑浮点数精度误差)
|
||||||
|
var layers = new Dictionary<double, List<int>>();
|
||||||
|
for (int i = 1; i < points.Count - 1; i++) // 跳过起点(0)和终点(Count-1)
|
||||||
|
{
|
||||||
|
double z = points[i].Position.Z;
|
||||||
|
|
||||||
|
// 查找是否已有相同Z坐标的层(考虑浮点数精度)
|
||||||
|
bool found = false;
|
||||||
|
foreach (var key in layers.Keys)
|
||||||
|
{
|
||||||
|
if (Math.Abs(z - key) < epsilon)
|
||||||
|
{
|
||||||
|
layers[key].Add(i);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
layers[z] = new List<int> { i };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Debug($"[环路检测] 发现{layers.Count}个水平层");
|
||||||
|
|
||||||
|
// 按Z坐标从高到低排序处理
|
||||||
|
var sortedLayers = layers.OrderByDescending(l => l.Key).ToList();
|
||||||
|
int totalDeletedPoints = 0; // 记录已删除的点数,用于更新后续层的索引
|
||||||
|
|
||||||
|
// 对每个水平层分别进行环路检测
|
||||||
|
for (int layerIdx = 0; layerIdx < sortedLayers.Count; layerIdx++)
|
||||||
|
{
|
||||||
|
var layer = sortedLayers[layerIdx];
|
||||||
|
double layerZ = layer.Key;
|
||||||
|
var layerIndices = layer.Value.OrderBy(idx => idx).ToList();
|
||||||
|
|
||||||
|
// 更新索引:减去之前层删除的点数
|
||||||
|
for (int i = 0; i < layerIndices.Count; i++)
|
||||||
|
{
|
||||||
|
layerIndices[i] -= totalDeletedPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤掉无效索引(小于0或超出范围)
|
||||||
|
layerIndices = layerIndices.Where(idx => idx >= 0 && idx < points.Count).ToList();
|
||||||
|
|
||||||
|
if (layerIndices.Count < 2)
|
||||||
|
{
|
||||||
|
LogManager.Debug($"[环路检测] 层 Z={layerZ:F2} 剩余点太少,跳过");
|
||||||
|
continue; // 该层点太少,无法形成环路
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Debug($"[环路检测] 处理水平层 Z={layerZ:F2},包含{layerIndices.Count}个,索引范围: {layerIndices.First()}-{layerIndices.Last()}");
|
||||||
|
|
||||||
|
// 对该层进行环路检测
|
||||||
|
int pointsBefore = points.Count;
|
||||||
|
bool layerHasChanges = RemoveLoopsInLayer(points, layerIndices, epsilon);
|
||||||
|
int pointsDeleted = pointsBefore - points.Count;
|
||||||
|
totalDeletedPoints += pointsDeleted;
|
||||||
|
|
||||||
|
if (layerHasChanges)
|
||||||
|
{
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChanges)
|
||||||
|
{
|
||||||
|
LogManager.Debug($"[环路检测] 完成,当前路径点数: {points.Count}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对单个水平层进行环路检测和移除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="points">路径点列表</param>
|
||||||
|
/// <param name="layerIndices">该层的点索引列表(已排序)</param>
|
||||||
|
/// <param name="epsilon">浮点数精度容差</param>
|
||||||
|
/// <returns>是否移除了环路</returns>
|
||||||
|
private bool RemoveLoopsInLayer(List<PathPoint> points, List<int> layerIndices, double epsilon)
|
||||||
|
{
|
||||||
|
if (layerIndices.Count < 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasChanges = false;
|
||||||
|
double layerZ = points[layerIndices[0]].Position.Z;
|
||||||
|
|
||||||
|
// 在该层内进行环路检测
|
||||||
|
// n和m是layerIndices列表中的索引位置
|
||||||
|
int n = 0; // 第一个线段的起始索引(在layerIndices中的位置)
|
||||||
|
int m = 2; // 第二个线段相对于n的偏移(在layerIndices中的位置)
|
||||||
|
|
||||||
|
while (n + m + 1 < layerIndices.Count)
|
||||||
|
{
|
||||||
|
// 获取实际的路径点索引
|
||||||
|
int idx1 = layerIndices[n]; // 线段1起点
|
||||||
|
int idx2 = layerIndices[n + 1]; // 线段1终点
|
||||||
|
int idx3 = layerIndices[n + m]; // 线段2起点
|
||||||
|
int idx4 = layerIndices[n + m + 1]; // 线段2终点
|
||||||
|
|
||||||
|
// 获取线段坐标
|
||||||
|
var p1 = points[idx1].Position;
|
||||||
|
var p2 = points[idx2].Position;
|
||||||
|
var p3 = points[idx3].Position;
|
||||||
|
var p4 = points[idx4].Position;
|
||||||
|
|
||||||
|
// 确保所有点都在同一层(水平线段,Z坐标严格相同,只考虑浮点数精度)
|
||||||
|
if (Math.Abs(p1.Z - layerZ) > epsilon ||
|
||||||
|
Math.Abs(p2.Z - layerZ) > epsilon ||
|
||||||
|
Math.Abs(p3.Z - layerZ) > epsilon ||
|
||||||
|
Math.Abs(p4.Z - layerZ) > epsilon)
|
||||||
|
{
|
||||||
|
m++;
|
||||||
|
if (n + m + 1 >= layerIndices.Count)
|
||||||
|
{
|
||||||
|
m = 2;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测两条正交线段是否相交
|
||||||
|
Point3D intersection;
|
||||||
|
if (GetOrthogonalSegmentIntersection(p1, p2, p3, p4, out intersection))
|
||||||
|
{
|
||||||
|
LogManager.Debug($"[环路检测] 层Z={layerZ:F2} 发现相交: 线段{idx1}({points[idx1].Name}-{points[idx2].Name}) 与 线段{idx3}({points[idx3].Name}-{points[idx4].Name})");
|
||||||
|
LogManager.Debug($"[环路检测] 交点: ({intersection.X:F4}, {intersection.Y:F4}, {intersection.Z:F4})");
|
||||||
|
|
||||||
|
// 检查中间点是否包含特殊点
|
||||||
|
bool containsSpecialPoint = false;
|
||||||
|
for (int k = idx1 + 1; k <= idx3; k++)
|
||||||
|
{
|
||||||
|
if (points[k].Type != PathPointType.WayPoint ||
|
||||||
|
points[k].Name == "提升点" ||
|
||||||
|
points[k].Name == "下降点" ||
|
||||||
|
points[k].Name == "起吊点" ||
|
||||||
|
points[k].Name == "落地点")
|
||||||
|
{
|
||||||
|
containsSpecialPoint = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containsSpecialPoint)
|
||||||
|
{
|
||||||
|
LogManager.Debug("[环路检测] 环路包含特殊点,跳过");
|
||||||
|
m++;
|
||||||
|
if (n + m + 1 >= layerIndices.Count)
|
||||||
|
{
|
||||||
|
m = 2;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用交点替换 points[idx2]
|
||||||
|
points[idx2].Position = intersection;
|
||||||
|
points[idx2].Name = "路径点";
|
||||||
|
|
||||||
|
// 删除中间点 (idx2+1 到 idx3)
|
||||||
|
int d = idx3 - idx2; // 要删除的点数
|
||||||
|
for (int i = idx3 + 1; i < points.Count; i++)
|
||||||
|
{
|
||||||
|
points[i - d] = points[i];
|
||||||
|
}
|
||||||
|
// 移除末尾多余的点
|
||||||
|
points.RemoveRange(points.Count - d, d);
|
||||||
|
|
||||||
|
// 更新layerIndices(因为删除了点)
|
||||||
|
for (int i = 0; i < layerIndices.Count; i++)
|
||||||
|
{
|
||||||
|
if (layerIndices[i] > idx2 && layerIndices[i] <= idx3)
|
||||||
|
{
|
||||||
|
// 这些点被删除了,标记为-1
|
||||||
|
layerIndices[i] = -1;
|
||||||
|
}
|
||||||
|
else if (layerIndices[i] > idx3)
|
||||||
|
{
|
||||||
|
// 这些点的索引需要向前移动
|
||||||
|
layerIndices[i] -= d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layerIndices.RemoveAll(idx => idx == -1);
|
||||||
|
|
||||||
|
// 从交点重新开始检测
|
||||||
|
m = 2;
|
||||||
|
hasChanges = true;
|
||||||
|
LogManager.Info($"[环路优化] 层Z={layerZ:F2} 已移除环路,删除{d}个点");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m++;
|
||||||
|
if (n + m + 1 >= layerIndices.Count)
|
||||||
|
{
|
||||||
|
m = 2;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算两条正交线段的交点
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>是否相交(线段内部相交,非端点)</returns>
|
||||||
|
private bool GetOrthogonalSegmentIntersection(Point3D a1, Point3D a2, Point3D b1, Point3D b2, out Point3D intersection)
|
||||||
|
{
|
||||||
|
intersection = new Point3D(0, 0, 0);
|
||||||
|
|
||||||
|
// 判断线段A是水平还是垂直
|
||||||
|
bool aIsHorizontal = Math.Abs(a1.Y - a2.Y) < 0.001;
|
||||||
|
bool aIsVertical = Math.Abs(a1.X - a2.X) < 0.001;
|
||||||
|
|
||||||
|
// 判断线段B是水平还是垂直
|
||||||
|
bool bIsHorizontal = Math.Abs(b1.Y - b2.Y) < 0.001;
|
||||||
|
bool bIsVertical = Math.Abs(b1.X - b2.X) < 0.001;
|
||||||
|
|
||||||
|
// 必须一条水平一条垂直才可能形成矩形环路
|
||||||
|
if ((aIsHorizontal && bIsHorizontal) || (aIsVertical && bIsVertical))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保a是水平,b是垂直
|
||||||
|
if (aIsVertical && bIsHorizontal)
|
||||||
|
{
|
||||||
|
// 交换
|
||||||
|
var temp1 = a1; var temp2 = a2;
|
||||||
|
a1 = b1; a2 = b2;
|
||||||
|
b1 = temp1; b2 = temp2;
|
||||||
|
aIsHorizontal = true; aIsVertical = false;
|
||||||
|
bIsHorizontal = false; bIsVertical = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aIsHorizontal || !bIsVertical)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 水平线段A: y = a1.Y, x范围 [min(a1.X,a2.X), max(a1.X,a2.X)]
|
||||||
|
// 垂直线段B: x = b1.X, y范围 [min(b1.Y,b2.Y), max(b1.Y,b2.Y)]
|
||||||
|
|
||||||
|
double aY = a1.Y;
|
||||||
|
double bX = b1.X;
|
||||||
|
double aMinX = Math.Min(a1.X, a2.X);
|
||||||
|
double aMaxX = Math.Max(a1.X, a2.X);
|
||||||
|
double bMinY = Math.Min(b1.Y, b2.Y);
|
||||||
|
double bMaxY = Math.Max(b1.Y, b2.Y);
|
||||||
|
|
||||||
|
// 检查垂直线段的X是否在水平线段的X范围内(不包括端点)
|
||||||
|
// 且水平线段的Y是否在垂直线段的Y范围内(不包括端点)
|
||||||
|
const double eps = 0.001;
|
||||||
|
|
||||||
|
bool xInRange = bX > aMinX + eps && bX < aMaxX - eps;
|
||||||
|
bool yInRange = aY > bMinY + eps && aY < bMaxY - eps;
|
||||||
|
|
||||||
|
if (xInRange && yInRange)
|
||||||
|
{
|
||||||
|
intersection = new Point3D(bX, aY, a1.Z);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新路径点位置(保存修改)
|
/// 更新路径点位置(保存修改)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -2396,6 +2697,10 @@ namespace NavisworksTransport
|
|||||||
|
|
||||||
// 吊装路径:正交化路径(处理斜线和清除多余点)
|
// 吊装路径:正交化路径(处理斜线和清除多余点)
|
||||||
OrthogonalizePath(route);
|
OrthogonalizePath(route);
|
||||||
|
|
||||||
|
// 吊装路径:检测并移除矩形环路
|
||||||
|
LogManager.Info($"[吊装路径] 修改路径点后检测矩形环路");
|
||||||
|
RemoveRectangularLoops(route);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2689,6 +2689,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
if (coreRoute.PathType == PathType.Hoisting)
|
if (coreRoute.PathType == PathType.Hoisting)
|
||||||
{
|
{
|
||||||
_pathPlanningManager?.OrthogonalizePath(coreRoute);
|
_pathPlanningManager?.OrthogonalizePath(coreRoute);
|
||||||
|
|
||||||
|
// 吊装路径:检测并移除矩形环路
|
||||||
|
LogManager.Info($"[吊装路径] 删除路径点后检测矩形环路");
|
||||||
|
_pathPlanningManager?.RemoveRectangularLoops(coreRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用PathPlanningManager的3D删除方法
|
// 调用PathPlanningManager的3D删除方法
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user