From 825384813f706bb70f562307e2a2911cfe92a2f2 Mon Sep 17 00:00:00 2001 From: szdot Date: Mon, 25 Dec 2023 20:46:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A4=E6=96=AD=E5=B9=B3=E9=9D=A2=EF=BC=88bu?= =?UTF-8?q?g=E4=BF=AE=E6=94=B9=EF=BC=89=20=E6=99=BA=E8=83=BD=E6=8C=AB?= =?UTF-8?q?=E5=B1=82=E5=88=A4=E6=96=AD4=E7=82=B9=E5=B9=B3=E9=9D=A2=20?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E8=B7=AF=E5=BE=84=E6=B7=BB=E5=8A=A0=E4=BA=A4?= =?UTF-8?q?=E5=8F=89=E4=B8=8A=E9=99=90=E5=8F=82=E6=95=B0=203D=E7=BB=95?= =?UTF-8?q?=E8=A1=8C=E4=BF=AE=E6=94=B9=EF=BC=88=E6=97=A5=E5=BF=97=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FlieOperate/FileBase.cs | 4 +- FlieOperate/FlieOperate.csproj | 9 +- FlyBase/FlyBase.cs | 420 ++++++++++++++++++++------------- FlyCube/FlyCube.csproj | 1 + FlyCube/FlyCube.sln | 3 - FlyCube/MainWindow.xaml | 3 +- FlyCube/MainWindow.xaml.cs | 123 +++++----- 7 files changed, 333 insertions(+), 230 deletions(-) diff --git a/FlieOperate/FileBase.cs b/FlieOperate/FileBase.cs index 57c83da..6d78136 100644 --- a/FlieOperate/FileBase.cs +++ b/FlieOperate/FileBase.cs @@ -1,4 +1,4 @@ -using FlyBase; +using FlightRouteV2; using System; using System.Collections; using System.Collections.Generic; @@ -12,7 +12,7 @@ namespace FlieOperate /// /// 关于文件的 操作类 /// - public class FileBase + public static class FileBase { /// /// 逐行读取 文档 diff --git a/FlieOperate/FlieOperate.csproj b/FlieOperate/FlieOperate.csproj index 768baff..172b145 100644 --- a/FlieOperate/FlieOperate.csproj +++ b/FlieOperate/FlieOperate.csproj @@ -31,9 +31,6 @@ 4 - - ..\FlyCube\bin\Release\FlyBase.dll - ..\FlyCube\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll @@ -59,5 +56,11 @@ + + + {626a9bfa-07de-4063-a178-360eb7057ed6} + FlyBase + + \ No newline at end of file diff --git a/FlyBase/FlyBase.cs b/FlyBase/FlyBase.cs index 8249903..5ba5bf4 100644 --- a/FlyBase/FlyBase.cs +++ b/FlyBase/FlyBase.cs @@ -8,17 +8,19 @@ using System.Net.Http; using System.Net.NetworkInformation; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Policy; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Documents; using System.Windows.Shapes; using static System.Net.WebRequestMethods; -namespace FlyBase +namespace FlightRouteV2 { //矩阵类 public struct Matrix @@ -263,8 +265,9 @@ namespace FlyBase public override bool Equals(object obj) { // 检查对象是否与当前向量具有相同的类型 - if (obj is Vector3 vector) + if (obj is Vector3) { + Vector3 vector = (Vector3)obj; // 比较向量的每个分量 return X == vector.X && Y == vector.Y && @@ -537,19 +540,7 @@ namespace FlyBase Dictionary> graph = new Dictionary>(); Dictionary visited = new Dictionary(); List> result = new List>(); - void DFS(int node, List connected) - { - visited[node] = true; - connected.Add(node); - - foreach (var neighbor in graph[node]) - { - if (!visited[neighbor]) - { - DFS(neighbor, connected); - } - } - } + // 构建图 foreach (var edge in arr) { @@ -572,18 +563,31 @@ namespace FlyBase if (!visited[node]) { List connected = new List(); - DFS(node, connected); + DFS(node, connected, graph, visited); result.Add(connected); } } return result; } + private static void DFS(int node, List connected, Dictionary> graph, Dictionary visited) + { + visited[node] = true; + connected.Add(node); + + foreach (var neighbor in graph[node]) + { + if (!visited[neighbor]) + { + DFS(neighbor, connected, graph, visited); + } + } + } /// /// 获取一组序列的所有排列方式 ps:[0,1,2] 结果[[0, 1, 2],[0, 2, 1],[1, 0, 2],[1, 2, 0],[2, 0, 1],[2, 1, 0]] /// /// 一组序列 /// 所有序列的排列方式 - public static List> Permutations(List array) + private static List> Permutations(List array) { List> result = new List>(); GeneratePermutations(array, 0, array.Count - 1, result); @@ -616,20 +620,12 @@ namespace FlyBase /// b坐标集合 /// a b集合的对应关系 /// 坐标集合 - private static Vector3[] CreateNewBVecs(Vector3[] aVecs, Vector3[] bVecs, List match) + private static Vector3[] CreateNewBVecs(Vector3[] bVecs, List match) { - Dictionary indexMap = new Dictionary(); - // 构建索引映射 - foreach (var pair in match) - { - indexMap[pair[0]] = pair[1]; - } - // 根据映射构建新的bb数组 Vector3[] new_bVecs = new Vector3[bVecs.Length]; - foreach (var entry in indexMap) + foreach (int[] m in match) { - int newIndex = entry.Value; - new_bVecs[newIndex] = bVecs[entry.Key]; + new_bVecs[m[0]] = bVecs[m[1]]; } return new_bVecs; } @@ -733,17 +729,17 @@ namespace FlyBase /// true在一个平面 false不在一个平面 public static bool IsVecsOnPlane(Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4) { - // 计算两条边 - Vector3 side1 = vec2 - vec1; - Vector3 side2 = vec3 - vec2; - // 计算法线向量 - Vector3 normal = CrossPro(side1, side2); - // 计算第四个点到第一个点的向量 - Vector3 toPoint4 = vec4 - vec1; - // 设置容差值,根据具体情况调整 - float tolerance = 0.01f; - // 判断四个点是否在同一个平面上 - return Math.Abs(DotPro(toPoint4, normal)) < tolerance; + //计算三个向量 + Vector3 v1v2 = vec2 - vec1; + Vector3 v1v3 = vec3 - vec1; + Vector3 v1v4 = vec4 - vec1; + //计算法线向量 + Vector3 normal_vector = CrossPro(v1v2,v1v3); + //计算点到平面的距离 + double distance = DotPro(normal_vector, v1v4) / normal_vector.GetMag(); + //设置一个阈值,判断是否共面 + double epsilon = 0.1; + return Math.Abs(distance) < epsilon; } /// /// 判断4个点是否在同一条直线上 @@ -753,7 +749,7 @@ namespace FlyBase /// 点3 /// 点4 /// true在一条直线上 false不在一条直线上 - public static bool IsVecsOnLine(Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4) + private static bool IsVecsOnLine(Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4) { // 计算相邻点之间的方向向量 Vector3 dir1 = new Vector3(vec2.X - vec1.X, vec2.Y - vec1.Y, vec2.Z - vec1.Z); @@ -762,7 +758,7 @@ namespace FlyBase // 检查任意两个相邻方向向量的叉积是否为零 // 这是在三维空间中判断共线的条件 - return CrossPro(dir1, dir2).IsZero() && CrossPro(dir2, dir3).IsZero(); + return CrossPro(dir1, dir2).GetMag() <0.1 && CrossPro(dir2, dir3).GetMag() <0.1; } /// /// 辅助方法,用于检查向量是否为零向量 @@ -774,20 +770,6 @@ namespace FlyBase return vector.X == 0 && vector.Y == 0 && vector.Z == 0; } /// - /// 坐标置换 向量乘以矩阵(i帽j帽k帽)得到置换后的向量坐标 ps:x指向i帽 y轴指向j帽 z轴指向k帽 - /// - /// 要变换的向量 - /// 矩阵标量 既i帽 j帽 k帽 三点的坐标组成的矩阵 “可以想象成臂长为1的操作轴图标” - /// - private static Vector3 MatrixMul(Vector3 vec, Vector3[] mat) - { - Vector3 re = new Vector3();//声明返回值 - re.X = vec.X * mat[0].X + vec.Y * mat[1].X + vec.Z * mat[2].X; - re.Y = vec.X * mat[0].Y + vec.Y * mat[1].Y + vec.Z * mat[2].Y; - re.Z = vec.X * mat[0].Z + vec.Y * mat[1].Z + vec.Z * mat[2].Z; - return re; - } - /// /// 获取两条线段 的最近位置的距离和占比 /// /// 线段1起始点 @@ -795,16 +777,8 @@ namespace FlyBase /// 线段2起始点 /// 线段2起终点 /// [在线段1占比,在线段2占比,最近距离] - public static double RecentlySquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) + private static double RecentlySquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) { - bool IsEqual(double x, double y) - { - if (Math.Abs(x - y) < 1e-7) - { - return true; - } - return false; - } if (a1 == a2) a2 += 1;// 防止线段长度为0 if (b1 == b2) b2 += 1; double ux = a2.X - a1.X; @@ -884,6 +858,14 @@ namespace FlyBase double dz = wz + (sc * uz) - (tc * vz); return dx * dx + dy * dy + dz * dz;//两线最近距离的平方 } + private static bool IsEqual(double x, double y) + { + if (Math.Abs(x - y) < 1e-7) + { + return true; + } + return false; + } /// /// 按比例在两条线段上截取对应点间的最小距离 平方 /// @@ -892,7 +874,7 @@ namespace FlyBase /// 线段2起始点 /// 线段2起终点 /// 最小距离的平方值 - public static double MinDistanceSquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) + private static double MinDistanceSquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) { //相对位置和相对速度 Vector3 d0 = b1 - a1; @@ -962,7 +944,7 @@ namespace FlyBase /// 坐标集合 /// 默认返回为true重心 false则为中心 /// 重心或中心坐标 - public static Vector3 GetPosCenter(List pos, bool isCentroid = true) + private static Vector3 GetPosCenter(List pos, bool isCentroid = true) { int cou = pos.Count; if (isCentroid)//重心 @@ -1025,25 +1007,25 @@ namespace FlyBase /// /// 碰撞检测 /// - /// 始点坐标集合 - /// 终点坐标集合 + /// 始点坐标集合 + /// 终点坐标集合 /// 航线最小间距平方值 /// 飞行过程中最小间距平方值 /// - public static List AirImitation(Vector3[] startPos, Vector3[] endPos, double lineDistanceSquare = 36100, double spaceBetweenSquare = 48400) + private static List AirImitation(Vector3[] aVecs, Vector3[] bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 650000) { List planesCollision = new List(); //所有碰撞的组 - int planeCou = startPos.Length; //获取飞机总数 + int planeCou = aVecs.Length; //获取飞机总数 for (int a = 0; a < planeCou; a++) { for (int b = 0; a + 1 + b < planeCou; b++) { //判断两条轨迹 之间的最小距离 - double distanceSquare = RecentlySquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); if (distanceSquare < lineDistanceSquare) { //判断飞机距离是否过近 - double planeLenSquare = MinDistanceSquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + double planeLenSquare = MinDistanceSquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); if (planeLenSquare < spaceBetweenSquare) { planesCollision.Add(new int[] { a, a + 1 + b }); @@ -1056,25 +1038,25 @@ namespace FlyBase /// /// 碰撞检测 /// - /// 始点坐标集合 - /// 终点坐标集合 + /// 始点坐标集合 + /// 终点坐标集合 /// 航线最小间距平方值 /// 飞行过程中最小间距平方值 /// - public static List AirImitation(List startPos, List endPos, double lineDistanceSquare = 36100, double spaceBetweenSquare = 48400) + private static List AirImitation(List aVecs, List bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 650000) { List planesCollision = new List(); //所有碰撞的组 - int planeCou = startPos.Count; //获取飞机总数 + int planeCou = aVecs.Count; //获取飞机总数 for (int a = 0; a < planeCou; a++) { for (int b = 0; a + 1 + b < planeCou; b++) { //判断两条轨迹 之间的最小距离 - double distanceSquare = RecentlySquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); if (distanceSquare < lineDistanceSquare) { //判断飞机距离是否过近 - double planeLenSquare = MinDistanceSquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + double planeLenSquare = MinDistanceSquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); if (planeLenSquare < spaceBetweenSquare) { planesCollision.Add(new int[] { a, a + 1 + b }); @@ -1088,22 +1070,22 @@ namespace FlyBase /// 单机碰撞检测 /// /// 飞机的id PS:id从0开始 - /// 飞机起始坐标集合 - /// 飞机终点坐标集合 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 /// 航线小距离的平方对比值 /// 飞行过程中最小间距的平方对比值 /// true:有碰撞 false:无碰撞 - public static bool OnlyImitation(int onlyPlaneId, Vector3[] startPos, Vector3[] endPos, double lineDistanceSquare = 32400, double spaceBetweenSquare = 90000) + private static bool OnlyImitation(int onlyPlaneId, Vector3[] aVecs, Vector3[] bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 250000) { //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 - for (int contrastId = 0; contrastId < startPos.Length; contrastId++) + for (int contrastId = 0; contrastId < aVecs.Length; contrastId++) { if (onlyPlaneId == contrastId) continue;//不和自己比较 // 判断两条轨迹 之间的最小距离 - double distanceSquare = RecentlySquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//航线最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//航线最小距离 if (distanceSquare < lineDistanceSquare) { - double minDistanceSquare = MinDistanceSquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//按比例飞行最小间距 + double minDistanceSquare = MinDistanceSquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//按比例飞行最小间距 if (minDistanceSquare < spaceBetweenSquare) { return true;//返回有碰撞 @@ -1116,22 +1098,78 @@ namespace FlyBase /// 单机碰撞检测 /// /// 飞机的id PS:id从0开始 - /// 飞机起始坐标集合 - /// 飞机终点坐标集合 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 /// 航线小距离的平方对比值 /// 飞行过程中最小间距的平方对比值 /// true:有碰撞 false:无碰撞 - public static bool OnlyImitation(int onlyPlaneId, List startPos, List endPos, double lineDistanceSquare = 32400, double spaceBetweenSquare = 90000) + private static bool OnlyImitation(int onlyPlaneId, List aVecs, List bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 250000) { //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 - for (int contrastId = 0; contrastId < startPos.Count; contrastId++) + for (int contrastId = 0; contrastId < aVecs.Count; contrastId++) { if (onlyPlaneId == contrastId) continue;//不和自己比较 // 判断两条轨迹 之间的最小距离 - double distanceSquare = RecentlySquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//航线最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//航线最小距离 if (distanceSquare < lineDistanceSquare) { - double minDistanceSquare = MinDistanceSquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//按比例飞行最小间距 + double minDistanceSquare = MinDistanceSquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//按比例飞行最小间距 + if (minDistanceSquare < spaceBetweenSquare) + { + return true;//返回有碰撞 + } + } + } + return false;//返回没有碰撞; + } + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// 航线小距离的平方对比值 + /// 飞行过程中最小间距的平方对比值 + /// true:有碰撞 false:无碰撞 + private static bool OnlyImitation(int onlyPlaneId, Vector3[] aVecs, List bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 250000) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + for (int contrastId = 0; contrastId < aVecs.Length; contrastId++) + { + if (onlyPlaneId == contrastId) continue;//不和自己比较 + // 判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//航线最小距离 + if (distanceSquare < lineDistanceSquare) + { + double minDistanceSquare = MinDistanceSquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//按比例飞行最小间距 + if (minDistanceSquare < spaceBetweenSquare) + { + return true;//返回有碰撞 + } + } + } + return false;//返回没有碰撞; + } + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// 航线小距离的平方对比值 + /// 飞行过程中最小间距的平方对比值 + /// true:有碰撞 false:无碰撞 + private static bool OnlyImitation(int onlyPlaneId, List aVecs, Vector3[] bVecs, double lineDistanceSquare = 36100, double spaceBetweenSquare = 250000) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + for (int contrastId = 0; contrastId < aVecs.Count; contrastId++) + { + if (onlyPlaneId == contrastId) continue;//不和自己比较 + // 判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//航线最小距离 + if (distanceSquare < lineDistanceSquare) + { + double minDistanceSquare = MinDistanceSquareOfLine(aVecs[onlyPlaneId], bVecs[onlyPlaneId], aVecs[contrastId], bVecs[contrastId]);//按比例飞行最小间距 if (minDistanceSquare < spaceBetweenSquare) { return true;//返回有碰撞 @@ -1143,11 +1181,13 @@ namespace FlyBase /// /// 智能路径 规则:找ab组共同最外圈的点 然后对应找a或b里面最近点 为一组匹配 最后进行碰撞交叉互换 /// - /// 起始点坐标组 - /// 目标点坐标组 + /// 起始点坐标组 + /// 目标点坐标组 + /// 日志输出 回调函数 /// 交换次数 - /// - public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, int swapCount = 5) + /// 交叉线路数量上限 ps:超过这个数量则不进行交换 + /// 新的目标点 + public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint, int swapCount = 5, int crossingLimit = 6) { int planeCou = aVecs.Length; // 飞机总数 List match = new List(); // ab对应关系 @@ -1162,6 +1202,7 @@ namespace FlyBase // 遍历找出 AB集合对应关系 for (int k = 0; k < planeCou; k++) { + // 遍历每次刷新 剩下为未匹配总数 int remainCou = aIndex.Count; // 遍历每次刷新 重心 @@ -1185,7 +1226,6 @@ namespace FlyBase int bMaxIndex = GetIndexOfMaxOrMin(bLens); // b集合到重心点最长的距离 数组的下标 if (aLens[aMaxIndex] > bLens[bMaxIndex])//找出 最外层如果为A集合点 对应B集合最近点 的下标 { - //MessageBox.Show(aIndex[aMaxIndex].ToString()); double[] outAtoBLen = new double[remainCou];//最外层A点到 B集合所有点的距离 for (int i = 0; i < remainCou; i++) { @@ -1209,8 +1249,7 @@ namespace FlyBase bIndex.RemoveAt(bMaxIndex); // 删除已经配对的b集合 ID } } - Vector3[] new_bVecs = CreateNewBVecs(aVecs, bVecs, match);// 按照映射 获取a 对应的 新的b集合 - return new_bVecs; + Vector3[] new_bVecs = CreateNewBVecs(bVecs, match);// 按照映射 获取a 对应的 新的b集合 //交叉 交换 for (int i = 0; i < swapCount; i++) @@ -1220,7 +1259,7 @@ namespace FlyBase // 遍历所有交叉组 分组做交换 foreach (List swap_indices in formatCollision) { - if (swap_indices.Count <= 6) // 只尝试5组交叉碰撞以下的航线互换 + if (swap_indices.Count <= crossingLimit) // 只尝试5组交叉碰撞以下的航线互换 { //交叉 生成所有排列 List> all_permutations = Permutations(swap_indices); @@ -1244,7 +1283,7 @@ namespace FlyBase tempLen.Add(AirImitation(aVecs, current_array).Count);// 迭代 记录所有排列的碰撞次数 tempNew_bVecsS.Add(current_array); //迭代 记录所有排列交换之后的目标坐标集 } - new_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)]; + new_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)].ToArray(); } } } @@ -1253,44 +1292,55 @@ namespace FlyBase /// /// 智能挫层 /// - /// 起始坐标集合 - /// 终点做标集合 + /// 起始坐标集合 + /// 终点做标集合 + /// 日志输出 回调函数 /// 挫层层高 /// 返回一个二维向量坐标集合 middle[0]是第一个中间航点 middle[1]是第二个中间航点 返回空数组则代表两个图形不在一个平面上或者不够4个点 - public static List CollisionLayer(Vector3[] startPos, Vector3[] endPos, double layHight = 220) + public static List CollisionLayer(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint, double layHight = 220) { List re = new List(); //获取飞机总数 - int planeCou = startPos.Length; - //检测两个图形是否在一个平面上 - Vector3[] allPos = startPos.Concat(endPos).ToArray();//合并两个集合 - List ppppVecArr = RandomSel4Vec(allPos);//随机选择 - if (ppppVecArr.Count == 0)//两个图形不够四个点 返回 空数组 + int planeCou = aVecs.Length; + if (planeCou < 2)//至少不少于2架飞机 才开始挫层 { + StrPrint("图案至少要两个点阵!"); return re; } - // 使用 foreach 遍历 List 中的元素 - foreach (Vector3[] pppVec in ppppVecArr) + //检测两个图形是否在一个平面上 + Vector3 vec0 = new Vector3(0, 0, 0); + Vector3 vec1 = new Vector3(0, 0, 0); + Vector3 vec2 = new Vector3(0, 0, 0); + Vector3 vec3 = new Vector3(0, 0, 0); + + //遍历所有点 查看是不是都再一个平面内 + for (int i = 0; i < planeCou; i++) { - if (!(IsVecsOnPlane(pppVec[0], pppVec[1], pppVec[2], pppVec[3]))) + vec0 = aVecs[i]; vec1 = bVecs[planeCou - i - 1]; vec2 = aVecs[planeCou - i - 1]; vec3 = bVecs[i]; + if (!(IsVecsOnPlane(vec0, vec1, vec2, vec3))) { + StrPrint("图案不在一个平面!"); return re;//两个图形不在一个平面上 返回 空数组 } - + else + { + break; + } } //遍历选出4个不共线的点 ps:方便后续叉积算法线标量 - bool isVecsOnLine = false; Vector3 vec0 = new Vector3(0, 0, 0); Vector3 vec1 = new Vector3(0, 0, 0); Vector3 vec2 = new Vector3(0, 0, 0); Vector3 vec3 = new Vector3(0, 0, 0); + bool isVecsOnLine = false; for (int i = 0; i < planeCou; i++) //遍历所有点 找出不在一条直线上的四个点 { - vec0 = startPos[i]; vec1 = endPos[planeCou - i - 1]; vec2 = startPos[planeCou - i - 1]; vec3 = endPos[i]; + vec0 = aVecs[i]; vec1 = bVecs[planeCou - i - 1]; vec2 = aVecs[planeCou - i - 1]; vec3 = bVecs[i]; isVecsOnLine = IsVecsOnLine(vec0, vec1, vec2, vec3); - if (isVecsOnLine) + if (!isVecsOnLine) { break; } } if (isVecsOnLine) { + StrPrint("所有点都在一条直线上!"); return re;//两个图案的所有点都在一条直线上 返回 空数组 } //检查完毕后 @@ -1303,35 +1353,37 @@ namespace FlyBase for (int i = 0; i < planeCou; i++) { int shiftCou = 1; //记录循环次数 即层数 - Vector3 aOrigin = startPos[i]; //原点位置 - Vector3 bOrigin = endPos[i]; //原点位置 - while (OnlyImitation(i, startPos, endPos)) + Vector3 aOrigin = aVecs[i]; //原点位置 + Vector3 bOrigin = bVecs[i]; //原点位置 + while (OnlyImitation(i, aVecs, bVecs)) { Vector3 shiftVec = normalScalar * ((shiftCou + 1) / 2 * layHight); if (shiftCou % 2 == 1) { - startPos[i] = aOrigin + shiftVec; - endPos[i] = bOrigin + shiftVec; + aVecs[i] = aOrigin + shiftVec; + bVecs[i] = bOrigin + shiftVec; } else { - startPos[i] = aOrigin - shiftVec; - endPos[i] = bOrigin - shiftVec; + aVecs[i] = aOrigin - shiftVec; + bVecs[i] = bOrigin - shiftVec; } shiftCou += 1; } } - re.Add(startPos); - re.Add(endPos); + StrPrint("挫层完成!"); + re.Add(aVecs); + re.Add(bVecs); return re; } /// /// 路径绕行 /// - /// 起始坐标集合 - /// 终点做标集合 - /// 返回一个二维数组 长度为1即1个中间航点 长度为3即前中后三个中间航点 - public static List> ABypassB(Vector3[] aVecs, Vector3[] bVecs) + /// 起始坐标集合 + /// 终点做标集合 + /// 日志输出 回调函数 + /// 返回一个二维数组 返回值长度0绕行失败 长度1为一个中间航点 长度为3为三个中间航点顺序(前中后) + public static List> ABypassB(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint) { List> re = new List>(); int planeCou = aVecs.Length; @@ -1355,29 +1407,23 @@ namespace FlyBase List firstCollisionGroup = new List(); //有碰撞飞机列表(第一次绕行) for (int i = 0; i < planeCou; i++) { - bool isPassMark = false;//初始标记 + StrPrint($"第一次绕行进度:{(int)((double)i/planeCou*100)}%"); + bool isPassMark = false; //初始标记 int index = sortedIndices[i];//从内到外排序的索引 tempAVecs.Add(aVecs[index]); tempBVecs.Add(bVecs[index]); if (i == 0) //如果是第一条航线 直接添加中间航点 { middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); //添加中间航点 + continue; //跳出 继续第二条航线计算 } else //从第二条开始绕 { middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); // 添加默认中间航点 // 首次默认中间航点检测 - if (!(OnlyImitation(i, tempAVecs, middleVecs))) //前半段碰 碰撞检测 + if (!(OnlyImitation(i, tempAVecs, middleVecs)) && !(OnlyImitation(i, middleVecs, tempBVecs))) //前半段碰 碰撞检测 { - if (!(OnlyImitation(i, middleVecs, tempBVecs))) //后半段碰 碰撞检测 - { - isPassMark = true; //中间航点 - continue; //不撞则跳出 进行下一航线的绕行 - } - else - { - middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 - } + continue; //不撞则跳出 进行下一航线的绕行 } else { @@ -1387,19 +1433,12 @@ namespace FlyBase List ringVecs = GetRingVec(aVecs[index], bVecs[index], 0.5); //所有可绕行的中间航点集合 foreach (Vector3 v in ringVecs) { - middleVecs.Add(v); + middleVecs.Add(v); //添加临时绕行航点 //检测 - if (!(OnlyImitation(i, tempAVecs, middleVecs))) //前半段碰 碰撞检测 + if (!(OnlyImitation(i, tempAVecs, middleVecs)) && !(OnlyImitation(i, middleVecs, tempBVecs))) //前半段碰 碰撞检测 { - if (!(OnlyImitation(i, middleVecs, tempBVecs))) //后半段碰 碰撞检测 - { - isPassMark = true; //中间航点 碰撞检测通过标记 - break; //不撞则跳出 进行下一航线的绕行 - } - else - { - middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 - } + isPassMark = true; //中间航点 碰撞检测通过标记 + break; //不撞则跳出 进行下一航线的绕行 } else { @@ -1407,22 +1446,39 @@ namespace FlyBase } } } - if (!(isPassMark)) // 如果绕行失败 添加一个默认中间航点 + // 如果绕行失败 + if (!isPassMark) { - middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); + middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); //添加一个默认中间航点 firstCollisionGroup.Add(index); } } - //中间航点坐标集 按飞机id顺序重新映射 ps:恢复原id映射 - middleVecs = sortedIndices.Select(index => middleVecs[index]).ToList(); + //中间航点坐标集 按飞机id顺序重新映射 ps:恢复原id映射 排序 + Vector3[] tempMiddleVecs = new Vector3[planeCou]; + for (int i = 0; i < planeCou; i++) + { + tempMiddleVecs[sortedIndices[i]] = middleVecs[i]; + } + middleVecs = new List(tempMiddleVecs); //没有碰撞 返回一个中间航点 并返回 if (firstCollisionGroup.Count == 0) { + StrPrint("第一次绕行通过!"); re.Add(middleVecs); return re; } + else + { + string str = ""; + foreach (int v in firstCollisionGroup) { + str += v.ToString() + "号,"; + } + str += "有碰撞,共" + firstCollisionGroup.Count.ToString() + "架!"; + StrPrint(str); + StrPrint("第一次绕行未通过,准备开始第二次绕行!"); + } - //第二次绕行 ps:有碰撞进行第二次 前后再各加以航点 嵌套迭代 + //第二次绕行 ps:有碰撞进行第二次 前后再各加一航点 嵌套迭代 List firstMiddleVecs = new List(); //前中间航点 List secondMiddleVecs = new List(); //后中间航点 List secondCollisionGroup = new List(); //最终有碰撞飞机列表 @@ -1431,8 +1487,11 @@ namespace FlyBase firstMiddleVecs.Add(SetMiddleVec(aVecs[i], middleVecs[i], 0)); secondMiddleVecs.Add(SetMiddleVec(middleVecs[i], bVecs[i], 1)); } + int z = 0;//计算进度 foreach (int index in firstCollisionGroup) { + z++;//计算进度 + StrPrint($"第二次绕行进度:{(int)((double)z / firstCollisionGroup.Count * 100)}%"); bool isPassMark = false; // 正中 绕行列表 List ringVecs = GetRingVec(aVecs[index], bVecs[index], 0.5); //所有可绕行的中间航点集合 @@ -1447,20 +1506,49 @@ namespace FlyBase foreach (Vector3 sr in secondRingVecs) { secondMiddleVecs[index] = sr; //后中点逐点 - // 检测 - if (!(OnlyImitation(index, aVecs, firstMiddleVecs))){ + // 检测 起点到 第一中间航点 + if (!(OnlyImitation(index, aVecs, firstMiddleVecs)) && !(OnlyImitation(index, firstMiddleVecs, middleVecs)) && !(OnlyImitation(index, middleVecs, secondMiddleVecs)) && !(OnlyImitation(index, secondMiddleVecs, bVecs))) + { + isPassMark = true; //碰撞检测通过标记 + break; //不撞则跳出 进行下一航线的绕行 } - //if not(self.onlyImitation(v, aVecs, firstMiddleVecs)): #前半段碰 碰撞检测 - // if not(self.onlyImitation(v, firstMiddleVecs, middleVecs)):#后半段碰 碰撞检测 - // if not(self.onlyImitation(v, middleVecs, secondMiddleVecs)): #前半段碰 碰撞检测 - // if not(self.onlyImitation(v, secondMiddleVecs, bVecs)):#后半段碰 碰撞检测 - // isPassMark = True #碰撞检测通过标记 - // break #不撞则跳出 进行下一航线的绕行 + } + if (isPassMark) + { + break; //不撞则跳出 进行下一航线的绕行 } } + if (isPassMark) + { + break; //不撞则跳出 进行下一航线的绕行 + } + } + if (!isPassMark) //如果绕行失败 添加一个默认中间航点 + { + middleVecs[index] = SetMiddleVec(aVecs[index], bVecs[index]); //添加中间航点 + firstMiddleVecs[index] = SetMiddleVec(aVecs[index], middleVecs[index], 0); // 添加中间航点 + secondMiddleVecs[index] = SetMiddleVec(middleVecs[index], bVecs[index], 1); // 添加中间航点 + secondCollisionGroup.Add(index);// 二次绕行仍不通过 添加到列表 (暂时无用) } } - + if (secondCollisionGroup.Count == 0)//如果二次绕行通过 添加中间三航点 + { + re.Add(firstMiddleVecs); + re.Add(middleVecs); + re.Add(secondMiddleVecs); + StrPrint("第二次绕行通过!"); + } + else + { + string str = ""; + foreach (int v in secondCollisionGroup) + { + str += v.ToString() + "号,"; + } + str += "仍有碰撞,共" + secondCollisionGroup.Count.ToString() + "架!"; + StrPrint(str); + StrPrint("第二次绕行仍未通过!"); + } return re; } /// @@ -1469,7 +1557,7 @@ namespace FlyBase /// 大圆半径 /// 固定弦长 ps:这个值决定绕行点一圈的密集成都值越小越密集 /// - public static List GetVecsOnCircle(double radius, double chordLength = 220) + private static List GetVecsOnCircle(double radius, double chordLength = 220) { List vecs = new List(); // 计算圆的周长 @@ -1498,7 +1586,7 @@ namespace FlyBase /// 偏移次数 从0开始,每+1在中点前后往返偏移 /// 偏移层高 /// 矩阵 - public static Matrix GetBasisMatrix(Vector3 aVec, Vector3 bVec, double middleProportion = 0.5, int offCount = 0, double layHight = 220) + private static Matrix GetBasisMatrix(Vector3 aVec, Vector3 bVec, double middleProportion = 0.5, int offCount = 0, double layHight = 220) { // 计算前向向量 k帽 Vector3 k_hat = (bVec - aVec).NormalizEd(); @@ -1542,7 +1630,7 @@ namespace FlyBase /// 传递圈函数的弦长 向量矩阵函数的层高 /// 绕行航点范围 ps:绕行中间航点肚子(值越大肚子越小) /// - public static List GetRingVec(Vector3 aVec, Vector3 bVec, double middleProportion, double transfer = 220, double paunch = 3) + private static List GetRingVec(Vector3 aVec, Vector3 bVec, double middleProportion, double transfer = 220, double paunch = 3) { List ringVec = new List(); //记录所有绕行中间航点坐标 // 根据a到b的长度 算出中间绕行几圈 diff --git a/FlyCube/FlyCube.csproj b/FlyCube/FlyCube.csproj index 9dbef46..e8bfd55 100644 --- a/FlyCube/FlyCube.csproj +++ b/FlyCube/FlyCube.csproj @@ -98,6 +98,7 @@ ResXFileCodeGenerator Resources.Designer.cs + SettingsSingleFileGenerator diff --git a/FlyCube/FlyCube.sln b/FlyCube/FlyCube.sln index cda8c92..7df902b 100644 --- a/FlyCube/FlyCube.sln +++ b/FlyCube/FlyCube.sln @@ -8,9 +8,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlyBase", "..\FlyBase\FlyBase.csproj", "{626A9BFA-07DE-4063-A178-360EB7057ED6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlieOperate", "..\FlieOperate\FlieOperate.csproj", "{C354FD6B-5863-4246-BB48-6DF14A85C161}" - ProjectSection(ProjectDependencies) = postProject - {626A9BFA-07DE-4063-A178-360EB7057ED6} = {626A9BFA-07DE-4063-A178-360EB7057ED6} - EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/FlyCube/MainWindow.xaml b/FlyCube/MainWindow.xaml index eec7bd5..9753047 100644 --- a/FlyCube/MainWindow.xaml +++ b/FlyCube/MainWindow.xaml @@ -21,7 +21,8 @@