智能路径ContactABOut 增加静态跳过功能

This commit is contained in:
szdot 2024-01-23 18:18:35 +08:00
parent aa30959d71
commit 3a6de2e67f
6 changed files with 157 additions and 78 deletions

View File

@ -648,6 +648,36 @@ namespace FlightRouteV2
return new_bVecs;
}
/// <summary>
/// 从数组中删除指定索引处的元素
/// </summary>
/// <typeparam name="T">数组元素类型</typeparam>
/// <param name="array">要操作的数组</param>
/// <param name="indicesToRemove">要删除的元素的索引列表</param>
/// <returns>删除元素后的新数组</returns>
private static T[] RemoveElementsAtIndices<T>(T[] array, List<int> indicesToRemove)
{
// 检查索引是否有效
if (indicesToRemove == null || indicesToRemove.Count == 0)
{
// 没有要删除的索引,返回原数组
return array;
}
// 创建一个新数组,长度为原数组长度减去要删除的元素数量
T[] newArray = new T[array.Length - indicesToRemove.Count];
int newIndex = 0;
// 复制不包括指定索引的元素到新数组中
for (int i = 0; i < array.Length; i++)
{
if (!indicesToRemove.Contains(i))
{
newArray[newIndex] = array[i];
newIndex++;
}
}
// 返回新数组
return newArray;
}
/// <summary>
/// 设置中间航点
/// </summary>
/// <param name="aVec">起点</param>
@ -730,7 +760,7 @@ namespace FlightRouteV2
/// <param name="vec1">平面上的点1</param>
/// <param name="vec2">平面上的点2</param>
/// <param name="vec3">平面上的点3</param>
/// <param name="vec4">垂直于平面的点</param>
/// <param name="vec4">被求点</param>
/// <returns>交点坐标</returns>
private static Vector3 CalculateIntersectionPoint(Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4)
{
@ -841,7 +871,7 @@ namespace FlightRouteV2
else return false;
}
/// <summary>
/// 从顶视图 判断点是否在两条内之间
/// 从顶视图 判断点是否在两条线内之间
/// </summary>
/// <param name="A">线段1端点</param>
/// <param name="B">线段1端点</param>
@ -1337,15 +1367,43 @@ namespace FlightRouteV2
/// <param name="aVecs">起始点坐标组</param>
/// <param name="bVecs">目标点坐标组</param>
/// <param name="StrPrint">日志输出 回调函数</param>
/// <param name="isStaticSkip">静态跳过 true跳过即保持原地不动 false不跳过参与“最近和交换”计算</param>
/// <param name="staticThresholdSquare">静态距离判断 小于阈值判定为静态 注意是个平方值</param>
/// <param name="isSwap">交叉航线是否进行交换</param>
/// <param name="swapCount">交换次数</param>
/// <param name="crossingLimit">交叉线路数量上限 ps:超过这个数量则不进行交换</param>
/// <returns>新的目标点</returns>
public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint, bool isSwap = true, int swapCount = 5, int crossingLimit = 6)
public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint,bool isStaticSkip = true, double staticThresholdSquare = 25 , bool isSwap = true, int swapCount = 5, int crossingLimit = 6)
{
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
StrPrint("-------智能选择路径计算,开始-------");
int planeCou = aVecs.Length; // 飞机总数
List<int> staticAindex = new List<int>(); // a静态对应关系ab两图同一位置
List<int> staticBindex = new List<int>(); // b静态对应关系ab两图同一位置
Vector3[] new_aVecs = aVecs.ToArray(); //a图副本
Vector3[] new_bVecs = bVecs.ToArray(); //b图副本
///如果启动 静态航点跳过 把ab静态对应关系找出来 预存放到staticMatch
if (isStaticSkip)
{
for (int i = 0; i < planeCou; i++)
{
for (int j = 0; j < planeCou; j++)
{
if (GageLengthSquare(aVecs[i], bVecs[j]) <= staticThresholdSquare)
{
staticAindex.Add(i);
staticBindex.Add(j);
break;
}
}
}
//把静态的航点从列表里面清除
new_aVecs = RemoveElementsAtIndices(new_aVecs, staticAindex);
new_bVecs = RemoveElementsAtIndices(new_bVecs, staticBindex);
//刷新飞机总数 以下计算最近 和 交换航线时候 只有非静态飞机参与
planeCou = new_aVecs.Length;
}
List<int[]> match = new List<int[]>(); // ab对应关系
///记录a b集合索引
List<int> aIndex = new List<int>();
@ -1365,8 +1423,8 @@ namespace FlightRouteV2
List<Vector3> allVecs = new List<Vector3>();
for (int i = 0; i < remainCou; i++)
{
allVecs.Add(aVecs[aIndex[i]]);
allVecs.Add(bVecs[bIndex[i]]);
allVecs.Add(new_aVecs[aIndex[i]]);
allVecs.Add(new_bVecs[bIndex[i]]);
}
Vector3 centerVec = GetPosCenter(allVecs);//重心点
// 遍历所有ab点距离重心点的距离
@ -1374,8 +1432,8 @@ namespace FlightRouteV2
double[] bLens = new double[remainCou];
for (int i = 0; i < remainCou; i++)
{
aLens[i] = GageLengthSquare(aVecs[aIndex[i]], centerVec);
bLens[i] = GageLengthSquare(bVecs[bIndex[i]], centerVec);
aLens[i] = GageLengthSquare(new_aVecs[aIndex[i]], centerVec);
bLens[i] = GageLengthSquare(new_bVecs[bIndex[i]], centerVec);
}
// 找出ab集合最外层坐标的下标 即离重心点最远的点
int aMaxIndex = GetIndexOfMaxOrMin(aLens); // a集合到重心点最长的距离 数组的下标
@ -1385,7 +1443,7 @@ namespace FlightRouteV2
double[] outAtoBLen = new double[remainCou];//最外层A点到 B集合所有点的距离
for (int i = 0; i < remainCou; i++)
{
outAtoBLen[i] = GageLengthSquare(aVecs[aIndex[aMaxIndex]], bVecs[bIndex[i]]);
outAtoBLen[i] = GageLengthSquare(new_aVecs[aIndex[aMaxIndex]], new_bVecs[bIndex[i]]);
}
int bMinIndex = GetIndexOfMaxOrMin(outAtoBLen, false);// 最短距离
match.Add(new int[] { aIndex[aMaxIndex], bIndex[bMinIndex] });// 映射到配对
@ -1397,7 +1455,7 @@ namespace FlightRouteV2
double[] outBtoALen = new double[remainCou];//最外层B点到 A集合所有点的距离
for (int i = 0; i < remainCou; i++)
{
outBtoALen[i] = GageLengthSquare(aVecs[aIndex[i]], bVecs[bIndex[bMaxIndex]]);
outBtoALen[i] = GageLengthSquare(new_aVecs[aIndex[i]], new_bVecs[bIndex[bMaxIndex]]);
}
int aMinIndex = GetIndexOfMaxOrMin(outBtoALen, false);// 最短距离
match.Add(new int[] { aIndex[aMinIndex], bIndex[bMaxIndex] });// 映射到配对
@ -1405,77 +1463,95 @@ namespace FlightRouteV2
bIndex.RemoveAt(bMaxIndex); // 删除已经配对的b集合 ID
}
}
Vector3[] new_bVecs = CreateNewBVecs(bVecs, match);// 按照映射 获取a 对应的 新的b集合
if (!isSwap)
{
return new_bVecs;
}
Vector3[] re_bVecs = CreateNewBVecs(new_bVecs, match);// 按照映射 获取a 对应的 新的b集合
///交叉 交换
for (int i = 0; i < swapCount; i++)
if (isSwap)
{
List<int[]> planesCollision = AirImitation(aVecs, new_bVecs);// 获取碰撞组
List<List<int>> formatCollision = FindConnected(planesCollision);// 获取交叉序列 例如:[[0,2][0,3][3,4][5,6]] 结果[[0,2,3,4][5,6]]
List<List<int>> filteredCollision = formatCollision.Where(sublist => sublist.Count <= crossingLimit).ToList();// 过滤 只保留交叉数量小于等于crossingLimit的序列
if (filteredCollision.Count == 0) break;
///日志输出
string log = "";
foreach (List<int> item in filteredCollision)
for (int i = 0; i < swapCount; i++)
{
log += "[";
foreach (int itemInt in item)
List<int[]> planesCollision = AirImitation(new_aVecs, re_bVecs);// 获取碰撞组
List<List<int>> formatCollision = FindConnected(planesCollision);// 获取交叉序列 例如:[[0,2][0,3][3,4][5,6]] 结果[[0,2,3,4][5,6]]
List<List<int>> filteredCollision = formatCollision.Where(sublist => sublist.Count <= crossingLimit).ToList();// 过滤 只保留交叉数量小于等于crossingLimit的序列
if (filteredCollision.Count == 0) break;
///日志输出
string log = "";
foreach (List<int> item in filteredCollision)
{
log += $"{itemInt},";
log += "[";
foreach (int itemInt in item)
{
log += $"{itemInt},";
}
log += "]";
}
log += "]";
}
StrPrint($"共迭代{swapCount}次交换,第{i}次。共{filteredCollision.Count}组,交换组为:{log}。");
/// 遍历所有交叉组 分组做交换
int cou = 0;
foreach (List<int> swap_indices in filteredCollision)
{
cou++;
StrPrint($"进度:{cou}/{filteredCollision.Count}。交换组:[{string.Join(", ", swap_indices)}]。");
///交叉 生成所有排列
List<List<int>> all_permutations = Permutations(swap_indices);//所有排列组合
List<int> original = all_permutations[0];//原始排列
all_permutations.RemoveAt(0);//删掉第一个 既原始排列
/// 按所有的排列 互换航线 并检测出最佳的对应目标点
List<int> tempLen = new List<int>(); //记录最少碰撞的 排列
List<Vector3[]> tempNew_bVecsS = new List<Vector3[]>();//记录最少碰撞的 排列交换之后的目标坐标集
foreach (List<int> indices in all_permutations)
StrPrint($"共迭代{swapCount}次交换,第{i}次。共{filteredCollision.Count}组,交换组为:{log}。");
/// 遍历所有交叉组 分组做交换
int cou = 0;
foreach (List<int> swap_indices in filteredCollision)
{
Vector3[] current_array = new Vector3[planeCou];
Array.Copy(new_bVecs, current_array, planeCou);//复制一个new_bVecs 副本
for (int k = 0; k < indices.Count; k++)
cou++;
StrPrint($"进度:{cou}/{filteredCollision.Count}。交换组:[{string.Join(", ", swap_indices)}]。");
///交叉 生成所有排列
List<List<int>> all_permutations = Permutations(swap_indices);//所有排列组合
List<int> original = all_permutations[0];//原始排列
all_permutations.RemoveAt(0);//删掉第一个 既原始排列
/// 按所有的排列 互换航线 并检测出最佳的对应目标点
List<int> tempLen = new List<int>(); //记录最少碰撞的 排列
List<Vector3[]> tempNew_bVecsS = new List<Vector3[]>();//记录最少碰撞的 排列交换之后的目标坐标集
foreach (List<int> indices in all_permutations)
{
current_array[original[k]] = new_bVecs[indices[k]];
}
///把最少碰撞的排列 录入到数组
int collisionsCou = (AirImitation(aVecs, current_array)).Count;//此排列的碰撞次数
if (tempLen.Count == 0 || tempLen[0] == collisionsCou)//如果第一次添加 或者 碰撞次数等于最少碰撞
{
///录入数组
tempLen.Add(collisionsCou);
tempNew_bVecsS.Add(current_array);
}
else if (tempLen[0] > collisionsCou)
{
/// 如果最小值 大于 当前碰撞次数,清空之前记录
tempLen.Clear();
tempNew_bVecsS.Clear();
///录入数组
tempLen.Add(collisionsCou);
tempNew_bVecsS.Add(current_array);
Vector3[] current_array = new Vector3[planeCou];
Array.Copy(re_bVecs, current_array, planeCou);//复制一个re_bVecs 副本
for (int k = 0; k < indices.Count; k++)
{
current_array[original[k]] = re_bVecs[indices[k]];
}
///把最少碰撞的排列 录入到数组
int collisionsCou = (AirImitation(new_aVecs, current_array)).Count;//此排列的碰撞次数
if (tempLen.Count == 0 || tempLen[0] == collisionsCou)//如果第一次添加 或者 碰撞次数等于最少碰撞
{
///录入数组
tempLen.Add(collisionsCou);
tempNew_bVecsS.Add(current_array);
}
else if (tempLen[0] > collisionsCou)
{
/// 如果最小值 大于 当前碰撞次数,清空之前记录
tempLen.Clear();
tempNew_bVecsS.Clear();
///录入数组
tempLen.Add(collisionsCou);
tempNew_bVecsS.Add(current_array);
}
}
re_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)];
}
new_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)];
}
}
///静态飞机 赋值回 返回航点组 ps:航点赋值的位置是对应的a组的ID位置 映射到b组的位置
if (isStaticSkip)
{
planeCou = aVecs.Length;
List<Vector3> re_bVecsCopy = new List<Vector3>(re_bVecs);
List<Vector3> re_bVecsList = new List<Vector3>();
for (int i = 0; i < planeCou; i++)
{
if (staticAindex.IndexOf(i) != -1)
{
re_bVecsList.Add(aVecs[i]);
}
else
{
re_bVecsList.Add(re_bVecsCopy[0]);
re_bVecsCopy.RemoveAt(0);
}
}
re_bVecs = re_bVecsList.ToArray();
}
t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t;
StrPrint($"用时:{t}秒");
StrPrint($"-------智能选择路径计算,结束-------");
return new_bVecs;
return re_bVecs;
}
/// <summary>
/// 智能错层
@ -1504,19 +1580,21 @@ namespace FlightRouteV2
Vector3[] new_aVecs = aVecs.ToArray(); //a图副本
Vector3[] new_bVecs = bVecs.ToArray(); //b图副本
///把所有点压在 “共面”上
///把所有点压在 主面“共面”上
List<int> maxVecsOfCoplane = FindMaxPlaneIndices(aVecs);// 找出A图共面最多点的索引
StrPrint("正在进行“共面”检测,需要一些时间请耐心等待。。。");
if (maxVecsOfCoplane.Count < 4) //a图至少要有4个点 共面
{
StrPrint("a图案至少有4个点以上共面否则不可执行错层处理");
StrPrint($"-------错层结束-------");
return re;
}
//共面上取三个点
///共面上取三个点
Vector3 vec0 = new_aVecs[maxVecsOfCoplane[0]];
Vector3 vec1 = new_aVecs[maxVecsOfCoplane[1]];
Vector3 vec2 = new_aVecs[maxVecsOfCoplane[2]];
for (int i = 0; i < planeCou; i++) //遍历 把a图和b图点压到 “共面”上
///遍历 把a图和b图点压到 “共面”上
for (int i = 0; i < planeCou; i++)
{
if (!(maxVecsOfCoplane.Contains(i))) //除去在共面内的面
{
@ -1979,7 +2057,7 @@ namespace FlightRouteV2
/// <param name="bVecs">回归矩阵坐标组</param>
/// <param name="strPrint">日志输出 回调函数</param>
/// <returns>拉散图案的坐标组</returns>
public static Vector3[] NormalPull(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint)
public static Vector3[] NormalPull(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint,double pullingDistance = 300)
{
Vector3[] new_aVecs = aVecs.ToArray(); //a图副本
Vector3[] new_bVecs = bVecs.ToArray(); //矩阵副本
@ -2036,11 +2114,11 @@ namespace FlightRouteV2
///判断图在矩阵的左方 还是右方
if (GageLength(aCenterPos, new_bVecs[0]) > GageLength(aCenterPos, new_bVecs[row - 1]))
{
new_aVecs[cou] -= normalScalar * (row - k) * 300;//左方
new_aVecs[cou] -= normalScalar * (row - k) * pullingDistance;//左方
}
else
{
new_aVecs[cou] += normalScalar * k * 300;//右方
new_aVecs[cou] += normalScalar * k * pullingDistance;//右方
}
}
}
@ -2079,11 +2157,11 @@ namespace FlightRouteV2
///判断图在矩阵的上方 还是下方
if (GageLength(aCenterPos, new_bVecs[0]) > GageLength(aCenterPos, new_bVecs[row * (ran - 1)]))
{
new_aVecs[cou] -= normalScalar * (ran - k) * 300;//上方
new_aVecs[cou] -= normalScalar * (ran - k) * pullingDistance;//上方
}
else
{
new_aVecs[cou] += normalScalar * k * 300;//下方
new_aVecs[cou] += normalScalar * k * pullingDistance;//下方
}
}
}

View File

@ -73,6 +73,7 @@ namespace FlyCube
File.Delete(pathd);
}
SaveFile(pathd, txtd);
}
/// <summary>
/// 3D绕行
@ -88,11 +89,11 @@ namespace FlyCube
List<Vector3[]> abVecs = FileBase.TxtToPos(FliePath, out string[] fightNames);//从txt文件里面读取航点 信息
Vector3[] aVecs = abVecs[0].ToArray();
Vector3[] bVecs = abVecs[1].ToArray();
Vector3[] new_bVecs = FlyVecFun.ContactABOut(aVecs, bVecs, StrPrint);
//Vector3[] new_aVecs = FlyVecFun.NormalPull(aVecs, bVecs, StrPrintAsync);
//Vector3[] new_bVecs = FlyVecFun.ContactABOut(aVecs, bVecs, StrPrint);
Vector3[] new_aVecs = FlyVecFun.NormalPull(aVecs, bVecs, StrPrintAsync);
bool isPass;
Task<List<List<Vector3>>> reTask = Task.Run(() => FlyVecFun.ABypassB(aVecs, bVecs, StrPrintAsync, GetVal, cts.Token, out isPass));
Task<List<List<Vector3>>> reTask = Task.Run(() => FlyVecFun.ABypassB(new_aVecs, bVecs, StrPrintAsync, GetVal, cts.Token, out isPass));
List<List<Vector3>> re = await reTask;
string txta = "";
@ -114,7 +115,7 @@ namespace FlyCube
{
txtc += i + " 0" + " " + re[2][i].X + " " + re[2][i].Y + " " + re[2][i].Z + "\r\n";
}
txtd += i + " 0" + " " + new_bVecs[i].X + " " + new_bVecs[i].Y + " " + new_bVecs[i].Z + "\r\n";
txtd += i + " 0" + " " + new_aVecs[i].X + " " + new_aVecs[i].Y + " " + new_aVecs[i].Z + "\r\n";
}
if (re.Count > 0)