diff --git a/FlightRouteV2/.vs/FlyBase/v16/.suo b/FlightRouteV2/.vs/FlyBase/v16/.suo new file mode 100644 index 0000000..893da3a Binary files /dev/null and b/FlightRouteV2/.vs/FlyBase/v16/.suo differ diff --git a/FlightRouteV2/FlightRouteV2.cs b/FlightRouteV2/FlightRouteV2.cs new file mode 100644 index 0000000..6dad670 --- /dev/null +++ b/FlightRouteV2/FlightRouteV2.cs @@ -0,0 +1,1997 @@ +using Microsoft.SqlServer.Server; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +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 FlightRouteV2 +{ + //矩阵类 + public struct Matrix + { + public double M11, M12, M13; + public double M21, M22, M23; + public double M31, M32, M33; + public double M41, M42, M43; + /// + /// 构造函数,接受四个 Vector3 对象 + /// + /// 向量1 + /// 向量2 + /// 向量3 + /// 向量4 + public Matrix(Vector3 row1, Vector3 row2, Vector3 row3, Vector3 row4) + { + M11 = row1.X; M12 = row1.Y; M13 = row1.Z; + M21 = row2.X; M22 = row2.Y; M23 = row2.Z; + M31 = row3.X; M32 = row3.Y; M33 = row3.Z; + M41 = row4.X; M42 = row4.Y; M43 = row4.Z; + } + /// + /// 通过方法实现通过索引的访问 + /// + /// + public Vector3 this[int index] + { + get + { + switch (index) + { + case 0: return new Vector3(M11, M12, M13); + case 1: return new Vector3(M21, M22, M23); + case 2: return new Vector3(M31, M32, M33); + case 3: return new Vector3(M41, M42, M43); + default: + throw new IndexOutOfRangeException("Index out of range for Matrix"); + } + } + } + /// + /// // 重写 ToString 方法,以便能够直接打印矩阵 + /// + public override string ToString() + { + return $"v1:{M11}, {M12}, {M13}\n" + + $"v2:{M21}, {M22}, {M23}\n" + + $"v3:{M31}, {M32}, {M33}\n" + + $"off:{M41}, {M42}, {M43}"; + } + } + //向量类 + public struct Vector3 + { + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + /// + /// [数组下标]方式 访问XYZ属性 + /// + /// + /// [0]X [1]Y [2]Z + /// 访问下标0-2 + public double this[int index] + { + get + { + switch (index) + { + case 0: + return X; + case 1: + return Y; + case 2: + return Z; + default: + throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3"); + } + } + set + { + switch (index) + { + case 0: + X = value; + break; + case 1: + Y = value; + break; + case 2: + Z = value; + break; + default: + throw new IndexOutOfRangeException($"Index {index} is out of range for Vector3"); + } + } + } + // 静态属性表示单位向量 + public static Vector3 UnitX { get { return new Vector3(1.0, 0.0, 0.0); } } + public static Vector3 UnitY { get { return new Vector3(0.0, 1.0, 0.0); } } + public static Vector3 UnitZ { get { return new Vector3(0.0, 0.0, 1.0); } } + /// + /// 构造 初始化 + /// + /// x坐标 + /// y坐标 + /// z坐标 + public Vector3(double x, double y, double z) + { + this.X = x; + this.Y = y; + this.Z = z; + } + /// + /// 重载二元坐标加法+ 向量+向量 + /// + /// 向量加数 + /// 向量加数 + /// + public static Vector3 operator +(Vector3 v1, Vector3 v2) + { + return new Vector3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); + } + /// + /// 重载一元坐标加法+ 向量+小数 + /// + /// 向量 + /// 小数 + /// + public static Vector3 operator +(Vector3 v1, double i) + { + return new Vector3(v1.X + i, v1.Y + i, v1.Z + i); + } + /// + /// 重载一元坐标加法+ 向量+整数 + /// + /// 向量 + /// 整数 + /// + public static Vector3 operator +(Vector3 v1, int i) + { + return new Vector3(v1.X + (double)i, v1.Y + (double)i, v1.Z + (double)i); + } + /// + /// 重载二元坐标减法- 向量-向量 + /// + /// 向量被减数 + /// 向量减数 + /// + public static Vector3 operator -(Vector3 v1, Vector3 v2) + { + return new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); + } + /// + /// 重载一元坐标加法- 向量-小数 + /// + /// 向量被减数 + /// 小数减数 + /// + public static Vector3 operator -(Vector3 v1, double i) + { + return new Vector3(v1.X - i, v1.Y - i, v1.Z - i); + } + /// + /// 重载一元坐标加法- 向量-整数 + /// + /// 向量被减数 + /// 整数减数 + /// + public static Vector3 operator -(Vector3 v1, int i) + { + return new Vector3(v1.X - (double)i, v1.Y - (double)i, v1.Z - (double)i); + } + /// + /// 重载一元坐标乘法* 向量*小数 + /// + /// 向量 + /// 小数乘数 + /// 得到向量的倍数向量 + public static Vector3 operator *(Vector3 v1, double i) + { + return new Vector3(v1.X * i, v1.Y * i, v1.Z * i); + } + /// + /// 重载一元坐标乘法* 向量*整数 + /// + /// 向量 + /// 整数乘数 + /// 得到向量的倍数向量 + public static Vector3 operator *(Vector3 v1, int i) + { + return new Vector3(v1.X * (double)i, v1.Y * (double)i, v1.Z * (double)i); + } + /// + /// 重载一元坐标除法/ 向量/小数 + /// + /// 向量 + /// 小数除数 + /// 得到向量的商向量 + public static Vector3 operator /(Vector3 v1, double i) + { + return new Vector3(v1.X / i, v1.Y / i, v1.Z / i); + } + /// + /// 重载一元坐标除法/ 向量/整数 + /// + /// 向量 + /// 整数除数 + /// 得到向量的商向量 + public static Vector3 operator /(Vector3 v1, int i) + { + return new Vector3(v1.X / (double)i, v1.Y / (double)i, v1.Z / (double)i); + } + /// + /// 重载== 向量==向量 + /// + /// 向量1 + /// 向量2 + /// 布尔值 判断向量是否相等 + public static bool operator ==(Vector3 v1, Vector3 v2) + { + if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) return true; + return false; + } + /// + /// 重载!= 向量!=向量 + /// + /// 向量1 + /// 向量2 + /// 布尔值 判断向量是否不相等 + public static bool operator !=(Vector3 v1, Vector3 v2) + { + if (v1.X != v2.X || v1.Y != v2.Y || v1.Z != v2.Z) return true; + return false; + } + /// + /// 确定指定的对象是否等于当前向量。 + /// + /// 要与当前向量比较的对象。 + /// 如果指定的对象等于当前向量,则为 true;否则为 false + public override bool Equals(object obj) + { + // 检查对象是否与当前向量具有相同的类型 + if (obj is Vector3) + { + Vector3 vector = (Vector3)obj; + // 比较向量的每个分量 + return X == vector.X && + Y == vector.Y && + Z == vector.Z; + } + + // 如果对象不是 Vector3 类型,则它们不相等 + return false; + } + /// + /// 向量按矩阵旋转和偏移 + /// + /// 矩阵 + /// 返回一个新的向量 + public Vector3 Multiply(Matrix mat) + { + Vector3 re = new Vector3(); + //矩阵相乘 ps:旋转角度 + re.X = this.X * mat[1].X + this.Y * mat[2].X + this.Z * mat[0].X; + re.Y = this.X * mat[1].Y + this.Y * mat[2].Y + this.Z * mat[0].Y; + re.Z = this.X * mat[1].Z + this.Y * mat[2].Z + this.Z * mat[0].Z; + //off偏移 + re = re + mat[3]; + return re; + } + /// + /// 求模长 + /// + /// 向量到原点的模长 + public double GetMag() + { + return Math.Sqrt(Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2)); + } + /// + /// 求模长 平方 + /// + /// 向量到原点的模长的平方值 + public double GetMagSquared() + { + return Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2); + } + /// + /// 标准化坐标 无返回值 直接改变愿坐标 + /// + /// 标准化单位 + public void Normalize(double multiple = 1.0) + { + double magSq = Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2); + if (magSq > 0) + { + double oneOverMag = multiple / Math.Sqrt(magSq); + this.X *= oneOverMag; + this.Y *= oneOverMag; + this.Z *= oneOverMag; + } + } + /// + /// 标准化 返回一个标准化之后的值 不改变自身 + /// + /// 标准化单位 + /// 标准化之后的值 + public Vector3 NormalizEd(double multiple = 1.0) + { + Vector3 re = new Vector3(); + double magSq = Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2); + if (magSq > 0) + { + double oneOverMag = multiple / Math.Sqrt(magSq); + re.X = this.X * oneOverMag; + re.Y = this.Y * oneOverMag; + re.Z = this.Z * oneOverMag; + } + return re; + } + /// + /// 归零 改变自身数值 一般配合归位使用 + /// + /// + public void SetZero(Vector3 v2) + { + this.X -= v2.X; + this.Y -= v2.Y; + this.Z -= v2.Z; + } + /// + /// 归零 返回一个归零值 不改变自身 + /// + /// + /// + public Vector3 SetZeroEd(Vector3 v2) + { + Vector3 re = new Vector3(this.X - v2.X, this.Y - v2.Y, this.Z - v2.Z); + return re; + } + /// + /// 归位 + /// + /// + public void SetFormerly(Vector3 v2) + { + this.X += v2.X; + this.Y += v2.Y; + this.Z += v2.Z; + } + /// + /// 重写ToString 打印坐标 + /// + /// 坐标字符串 + public override string ToString() + { + string x = Convert.ToString(this.X); + string y = Convert.ToString(this.Y); + string z = Convert.ToString(this.Z); + return string.Format($"X轴:{x} Y轴:{y} Z轴:{z}"); + } + /// + /// 哈希码是一个整数值,用于对对象进行快速比较和索引 + /// + /// 哈希码 + public override int GetHashCode() + { + int hashCode = -307843816; + hashCode = hashCode * -1521134295 + X.GetHashCode(); + hashCode = hashCode * -1521134295 + Y.GetHashCode(); + hashCode = hashCode * -1521134295 + Z.GetHashCode(); + return hashCode; + } + } + //坐标操作与验证 + public static class FlyVecFun + { + /// + /// 航线 线间距 平方值 + /// + public static double LineDistanceSquare { get; set; } = 32400; + /// + /// 飞行过程中间距 平方值 + /// + public static double SpaceBetweenSquare { get; set; } = 90000; + /// + /// 输出日志回调函数 + /// + /// 日志内容 + public delegate void SomeCalculateWay(string str); + /// + /// 输出进度日志回调函数 + /// + /// 进度值ps:0-100 + public delegate void Schedule(int val); + /// + /// Arraylist 转 Vector3[] 坐标集 + /// + /// Arraylist 坐标集 + /// Vector3[] 坐标集 + public static Vector3[] ArrToVec(ArrayList arr) + { + int cou = arr.Count; + Vector3[] re = new Vector3[cou]; + int key = 0; + foreach (Vector3 item in arr) + { + re[key] = item; + key++; + } + return re; + } + /// + /// 取数组最大 或者最小值 + /// + /// 数组 + /// true返回最大值 false返回最小值 + /// 根据参数返回 最大或者最小值 + private static double GetMaxOrMin(double[] arr, bool isMax = true) + { + Array.Sort(arr);//给数组arr排序 + if (isMax) + return arr[arr.Length - 1]; + else + return arr[0]; + } + /// + /// 取数组最大 或者最小值 的数组下标 + /// + /// 数组 + /// true返回最大值 false返回最小值 + /// 数组下标 + private static int GetIndexOfMaxOrMin(double[] arr, bool isMax = true) + { + int[] indexes = new int[arr.Length]; + for (int i = 0; i < arr.Length; i++) + { + indexes[i] = i; // 保存每个元素的原始索引 + } + + Array.Sort(arr, indexes); // 按值排序同时更新索引数组 + + // 根据 isMax 参数返回相应的索引 + return isMax ? indexes[arr.Length - 1] : indexes[0]; + } + /// + /// 获取列表中最小值的随机下标 + /// + /// 输入的列表 + /// 最小值的随机下标 + private static int GetRandomMinIndex(List list) + { + // 检查输入的列表是否为 null 或为空 + if (list == null || list.Count == 0) + { + throw new ArgumentException("列表不能为 null 或为空"); + } + + int minValue = int.MaxValue; // 初始化为 int 类型的最大值 + List minIndices = new List(); // 存储最小值的下标列表 + + for (int i = 0; i < list.Count; i++) + { + // 如果当前元素比最小值小,更新最小值和清空之前的下标列表 + if (list[i] < minValue) + { + minValue = list[i]; + minIndices.Clear(); // 清空之前的下标列表 + minIndices.Add(i); // 添加当前下标 + } + // 如果当前元素等于最小值,添加当前下标到列表 + else if (list[i] == minValue) + { + minIndices.Add(i); + } + } + + // 如果最小值下标列表为空,表示没有找到最小值 + if (minIndices.Count == 0) + { + throw new InvalidOperationException("列表中没有找到最小值"); + } + + // 生成一个随机数,用于从最小值下标列表中随机选择一个下标 + Random random = new Random(); + return minIndices[random.Next(minIndices.Count)]; + } + /// + /// 二维数组转一维数组 并去重 + /// + /// 二维数组 + /// 去重一维数组 + private static List TwoArrToArr(List twoArr) + { + // 创建一个用于存储去重后的一维数组的列表 + List arr = new List(); + // 遍历二维数组的每个子数组 + foreach (int[] item in twoArr) + { + // 查找第一个元素在一维数组中的索引 + int i = arr.IndexOf(item[0]); + // 如果索引小于0,表示该元素在一维数组中不存在,将其添加到一维数组 + if (i < 0) + { + arr.Add(item[0]); + } + // 查找第二个元素在一维数组中的索引 + int x = arr.IndexOf(item[1]); + // 如果索引小于0,表示该元素在一维数组中不存在,将其添加到一维数组 + if (x < 0) + { + arr.Add(item[1]); + } + } + // 返回去重后的一维数组 + return arr; + } + /// + /// 获取交叉序列 ps:处理二维数组 把有关联的子数组合并 例如:[[0,2][0,3][3,4][5,6]] 结果[[0,2,3,4][5,6]] + /// + /// 需要处理的二维数组 + /// 交叉序列 + private static List> FindConnected(List arr) + { + Dictionary> graph = new Dictionary>(); + Dictionary visited = new Dictionary(); + List> result = new List>(); + + // 构建图 + foreach (var edge in arr) + { + foreach (var node in edge) + { + if (!graph.ContainsKey(node)) + { + graph[node] = new List(); + visited[node] = false; + } + } + } + foreach (var edge in arr) + { + graph[edge[0]].Add(edge[1]); + graph[edge[1]].Add(edge[0]); + } + foreach (var node in graph.Keys) + { + if (!visited[node]) + { + List connected = new List(); + 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]] + /// + /// 一组序列 + /// 所有序列的排列方式 + private static List> Permutations(List array) + { + List> result = new List>(); + GeneratePermutations(array, 0, array.Count - 1, result); + return result; + } + private static void GeneratePermutations(List array, int start, int end, List> result) + { + if (start == end) + { + result.Add(new List(array)); + } + else + { + for (int i = start; i <= end; i++) + { + int temp = array[start]; + array[start] = array[i]; + array[i] = temp; + GeneratePermutations(array, start + 1, end, result); + temp = array[start]; + array[start] = array[i]; + array[i] = temp; + } + } + } + /// + /// 按照对应关系 生成新的b坐标集合 + /// + /// a坐标集合 + /// b坐标集合 + /// a b集合的对应关系 + /// 坐标集合 + private static Vector3[] CreateNewBVecs(Vector3[] bVecs, List match) + { + Vector3[] new_bVecs = new Vector3[bVecs.Length]; + foreach (int[] m in match) + { + new_bVecs[m[0]] = bVecs[m[1]]; + } + return new_bVecs; + } + /// + /// 从一组向量集合中 不重复的随机选择4个向量为一组 最多100组 组合成二维数组 如:[[1,2,3,4][5,6,7,8]...] + /// + /// 坐标集和 + /// re空数组则代表不够4个坐标 + private static List RandomSel4Vec(Vector3[] vecs) + { + List result = new List(); + int len = vecs.Length; + // 如果坐标数组少于4个,或者为空,则返回空列表 + if (len < 4) + { + return result; + } + // 确定最大可选择的组数,最多为100组 + int numGroups = Math.Min(len / 4, 100); + List flattenedList = vecs.ToList(); + Random random = new Random(); + // 遍历每一组 + for (int i = 0; i < numGroups; i++) + { + List selectedGroup = new List(); + + // 随机选择4个不重复的坐标 + for (int j = 0; j < 4; j++) + { + int index = random.Next(flattenedList.Count); + selectedGroup.Add(flattenedList[index]); + flattenedList.RemoveAt(index); + } + + // 将选择的坐标组成的 List 转换为数组,并添加到结果中 + result.Add(selectedGroup.ToArray()); + } + return result; + } + /// + /// 设置中间航点 + /// + /// 起点 + /// 目标点 + /// 比例 + /// + private static Vector3 SetMiddleVec(Vector3 aVec, Vector3 bVec, double middlePos = 0.5) + { + return (bVec - aVec) * middlePos + aVec; + } + /// + /// 两点距离 + /// + /// 坐标1 + /// 坐标2 + /// 两点之间距离 + private static double GageLength(Vector3 v1, Vector3 v2) + { + return Math.Sqrt(GageLengthSquare(v1, v2)); + } + /// + /// 两点距离的平方 + /// + /// 坐标1 + /// 坐标2 + /// 两点距离的平方 + private static double GageLengthSquare(Vector3 v1, Vector3 v2) + { + return Math.Pow(v1.X - v2.X, 2) + Math.Pow(v1.Y - v2.Y, 2) + Math.Pow(v1.Z - v2.Z, 2); + } + /// + /// 点积 + /// + /// 向量1 + /// 向量2 + /// 点积 + private static double DotPro(Vector3 v1, Vector3 v2) + { + return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z; + } + /// + /// 叉积 + /// + /// 向量1 + /// 向量2 + /// 两个向量叉积 + private static Vector3 CrossPro(Vector3 v1, Vector3 v2) + { + double x = v1.Y * v2.Z - v1.Z * v2.Y; + double y = v1.Z * v2.X - v1.X * v2.Z; + double z = v1.X * v2.Y - v1.Y * v2.X; + return new Vector3(x, y, z); + } + /// + /// 计算两个向量之间的夹角 角度 + /// + /// 第一个向量 + /// 第二个向量 + /// 角度 + public static double AngleBetween(Vector3 v1, Vector3 v2) + { + // 计算点积 + double dotProduct = DotPro(v1, v2); + + // 计算向量长度 + double magnitude1 = v1.GetMag(); + double magnitude2 = v2.GetMag(); + + // 使用 Atan2 计算弧度 + double thetaRadians = Math.Atan2(CrossPro(v1, v2).GetMag(), dotProduct); + + // 弧度转角度 + double thetaDegrees = thetaRadians * (180 / Math.PI); + + return thetaDegrees; + } + /// + /// 检查4个点是否在一个平面上 + /// + /// 点1 + /// 点2 + /// 点3 + /// 点4 + /// true在一个平面 false不在一个平面 + public static bool IsVecsOnPlane(Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4) + { + //计算三个向量 + 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 = 10; //单位厘米 + return Math.Abs(distance) < epsilon; + } + /// + /// 判断3个点是否在同一条直线上 + /// + /// 点1 + /// 点2 + /// 点3 + /// true在一条直线上 false不在一条直线上 + private static bool IsVecsOnLine(Vector3 vec1, Vector3 vec2, Vector3 vec3) + { + Vector3 v1 = vec2 - vec1; + Vector3 v2 = vec3 - vec1; + // 计算点积 + double dotProduct = DotPro(v1, v2); + // 计算向量长度 + double magnitude1 = v1.GetMag(); + double magnitude2 = v2.GetMag(); + // 使用 Atan2 计算弧度 + double thetaRadians = Math.Atan2(CrossPro(v1, v2).GetMag(), dotProduct); + // 弧度转角度 + double thetaDegrees = thetaRadians * (180 / Math.PI); + if (Math.Abs(thetaDegrees) < 10) return true; + else return false; + } + /// + /// 从顶视图 判断点是否在两条内之间 + /// + /// 线段1端点 + /// 线段1端点 + /// 线段2端点 + /// 线段2端点 + /// 被判断点 + /// true点在两条线内部 false点不在两条线内部 + private static bool IsPointBetweenLines(Vector3 A, Vector3 B, Vector3 C, Vector3 D, Vector3 P) + { + /// Y轴亚平 即顶视图 + A = new Vector3(A.X,0,A.Z); + B = new Vector3(B.X, 0, B.Z); + C = new Vector3(C.X, 0, C.Z); + D = new Vector3(D.X, 0, D.Z); + P = new Vector3(P.X, 0, P.Z); + Vector3 dirAB = new Vector3(B.X - A.X, B.Y - A.Y, B.Z - A.Z); + Vector3 dirCD = new Vector3(D.X - C.X, D.Y - C.Y, D.Z - C.Z); + Vector3 vecAP = new Vector3(P.X - A.X, P.Y - A.Y, P.Z - A.Z); + Vector3 vecCP = new Vector3(P.X - C.X, P.Y - C.Y, P.Z - C.Z); + + double cross1 = dirAB.X * vecAP.Z - dirAB.Z * vecAP.X; + double cross2 = dirCD.X * vecCP.Z - dirCD.Z * vecCP.X; + + return cross1 * cross2 < 0; + } + /// + /// 辅助方法,用于检查向量是否为零向量 + /// + /// 向量 + /// + private static bool IsZero(this Vector3 vector) + { + return vector.X == 0 && vector.Y == 0 && vector.Z == 0; + } + /// + /// 获取两条线段 的最近位置的距离和占比 + /// + /// 线段1起始点 + /// 线段1起终点 + /// 线段2起始点 + /// 线段2起终点 + /// [在线段1占比,在线段2占比,最近距离] + private static double RecentlySquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) + { + if (a1 == a2) a2 += 1;// 防止线段长度为0 + if (b1 == b2) b2 += 1; + double ux = a2.X - a1.X; + double uy = a2.Y - a1.Y; + double uz = a2.Z - a1.Z; + double vx = b2.X - b1.X; + double vy = b2.Y - b1.Y; + double vz = b2.Z - b1.Z; + double wx = a1.X - b1.X; + double wy = a1.Y - b1.Y; + double wz = a1.Z - b1.Z; + double a = (ux * ux + uy * uy + uz * uz); + double b = (ux * vx + uy * vy + uz * vz); + double c = (vx * vx + vy * vy + vz * vz); + double d = (ux * wx + uy * wy + uz * wz); + double e = (vx * wx + vy * wy + vz * wz); + double dt = a * c - b * b; + double sd = dt; + double td = dt; + double sn = 0.0; + double tn = 0.0; + if (IsEqual(dt, 0.0)) + { + sn = 0.0; + sd = 1.00; + tn = e; + td = c; + } + else + { + sn = (b * e - c * d); + tn = (a * e - b * d); + if (sn < 0.0) + { + sn = 0.0; + tn = e; + td = c; + } + else if (sn > sd) + { + sn = sd; + tn = e + b; + td = c; + } + } + if (tn < 0.0) + { + tn = 0.0; + if (-d < 0.0) sn = 0.0; + else if (-d > a) sn = sd; + else + { + sn = -d; + sd = a; + } + } + else if (tn > td) + { + tn = td; + if ((-d + b) < 0.0) sn = 0.0; + else if ((-d + b) > a) sn = sd; + else + { + sn = (-d + b); + sd = a; + } + + } + double sc = 0.0; + double tc = 0.0; + if (IsEqual(sn, 0.0)) sc = 0.0; + else sc = sn / sd;//最近点在第一条线占比 + if (IsEqual(tn, 0.0)) tc = 0.0; + else tc = tn / td;//最近点在第二条线占比 + double dx = wx + (sc * ux) - (tc * vx); + double dy = wy + (sc * uy) - (tc * vy); + 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; + } + /// + /// 按比例在两条线段上截取对应点间的最小距离 平方 + /// + /// 线段1起始点 + /// 线段1起终点 + /// 线段2起始点 + /// 线段2起终点 + /// 最小距离的平方值 + private static double MinDistanceSquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) + { + //相对位置和相对速度 + Vector3 d0 = b1 - a1; + Vector3 v_rel = (b2 - b1) - (a2 - a1); + //计算最小距离位置 占比 + double vd = DotPro(v_rel, v_rel); + double proportion;//最近距离占比 + if (vd != 0) + { + proportion = Math.Max(0, Math.Min(1, -DotPro(d0, v_rel) / vd));//max min函数把比例限制在0-1 保证比例在线段上 + } + else + { + proportion = 0; + } + //计算最小距离平方 + Vector3 d_min = d0 + v_rel * proportion; + return d_min.GetMagSquared(); + } + /// + /// 获取坐标集合的重心或中心 + /// + /// 坐标集合 + /// 默认返回为true重心 false则为中心 + /// 重心或中心坐标 + public static Vector3 GetPosCenter(Vector3[] pos, bool isCentroid = true) + { + int cou = pos.Length; + if (isCentroid)//重心 + { + double x = 0; + double y = 0; + double z = 0; + foreach (var item in pos) + { + x += item.X; + y += item.Y; + z += item.Z; + } + x = x / cou; + y = y / cou; + z = z / cou; + return new Vector3(x, y, z); + } + else//中心 + { + double[] x = new double[cou]; + double[] y = new double[cou]; + double[] z = new double[cou]; + int key = 0; + foreach (var item in pos) + { + x[key] = item.X; + y[key] = item.Y; + z[key] = item.Z; + key++; + } + double xc = (GetMaxOrMin(x) + GetMaxOrMin(x, false)) * .5; + double yc = (GetMaxOrMin(y) + GetMaxOrMin(y, false)) * .5; + double zc = (GetMaxOrMin(z) + GetMaxOrMin(z, false)) * .5; + return new Vector3(xc, yc, zc); + } + } + /// + /// 获取坐标集合的重心或中心 + /// + /// 坐标集合 + /// 默认返回为true重心 false则为中心 + /// 重心或中心坐标 + private static Vector3 GetPosCenter(List pos, bool isCentroid = true) + { + int cou = pos.Count; + if (isCentroid)//重心 + { + double x = 0; + double y = 0; + double z = 0; + foreach (var item in pos) + { + x += item.X; + y += item.Y; + z += item.Z; + } + x = x / cou; + y = y / cou; + z = z / cou; + return new Vector3(x, y, z); + } + else//中心 + { + double[] x = new double[cou]; + double[] y = new double[cou]; + double[] z = new double[cou]; + int key = 0; + foreach (var item in pos) + { + x[key] = item.X; + y[key] = item.Y; + z[key] = item.Z; + key++; + } + double xc = (GetMaxOrMin(x) + GetMaxOrMin(x, false)) * .5; + double yc = (GetMaxOrMin(y) + GetMaxOrMin(y, false)) * .5; + double zc = (GetMaxOrMin(z) + GetMaxOrMin(z, false)) * .5; + return new Vector3(xc, yc, zc); + } + } + /// + /// 获取坐标集合 的总宽度 高度 长度 + /// + /// 坐标集合 + /// 返回数组[0]宽度[1]高度[2]长度 + public static double[] GetVecsWithHighLength(Vector3[] pos) + { + List w = new List(); + List h = new List(); + List l = new List(); + foreach (var item in pos) + { + w.Add(item.X); + h.Add(item.Y); + l.Add(item.Z); + } + double[] re = new double[3]; + re[0] = w.Max() - w.Min(); + re[1] = h.Max() - h.Min(); + re[2] = l.Max() - l.Min(); + return re; + } + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// + private static List AirImitation(Vector3[] aVecs, Vector3[] bVecs) + { + List planesCollision = new List(); //所有碰撞的组 + int planeCou = aVecs.Length; //获取飞机总数 + for (int a = 0; a < planeCou; a++) + { + for (int b = 0; a + 1 + b < planeCou; b++) + { + //判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); + if (distanceSquare < LineDistanceSquare) + { + //判断飞机距离是否过近 + 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 }); + } + } + } + } + return planesCollision; + } + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// + private static List AirImitation(List aVecs, List bVecs) + { + List planesCollision = new List(); //所有碰撞的组 + int planeCou = aVecs.Count; //获取飞机总数 + for (int a = 0; a < planeCou; a++) + { + for (int b = 0; a + 1 + b < planeCou; b++) + { + //判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); + if (distanceSquare < LineDistanceSquare) + { + //判断飞机距离是否过近 + 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 }); + } + } + } + } + return planesCollision; + } + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// + private static List AirImitation(Vector3[] aVecs , List bVecs) + { + List planesCollision = new List(); //所有碰撞的组 + int planeCou = aVecs.Length; //获取飞机总数 + for (int a = 0; a < planeCou; a++) + { + for (int b = 0; a + 1 + b < planeCou; b++) + { + //判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); + if (distanceSquare < LineDistanceSquare) + { + //判断飞机距离是否过近 + 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 }); + } + } + } + } + return planesCollision; + } + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// + private static List AirImitation( List aVecs, Vector3[] bVecs) + { + List planesCollision = new List(); //所有碰撞的组 + int planeCou = aVecs.Count; //获取飞机总数 + for (int a = 0; a < planeCou; a++) + { + for (int b = 0; a + 1 + b < planeCou; b++) + { + //判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(aVecs[a], bVecs[a], aVecs[a + 1 + b], bVecs[a + 1 + b]); + if (distanceSquare < LineDistanceSquare) + { + //判断飞机距离是否过近 + 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 }); + } + } + } + } + return planesCollision; + } + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// true:有碰撞 false:无碰撞 + private static bool OnlyImitation(int onlyPlaneId, Vector3[] aVecs, Vector3[] bVecs) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + 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, List bVecs) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + 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;//返回有碰撞 + } + } + } + return false;//返回没有碰撞; + } + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// true:有碰撞 false:无碰撞 + private static bool OnlyImitation(int onlyPlaneId, Vector3[] aVecs, List bVecs) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + 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) + { + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + 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;//返回有碰撞 + } + } + } + return false;//返回没有碰撞; + } + /// + /// 智能路径 规则:找ab组共同最外圈的点 然后对应找a或b里面最近点 为一组匹配 最后进行碰撞交叉互换 + /// + /// 起始点坐标组 + /// 目标点坐标组 + /// 日志输出 回调函数 + /// 交叉航线是否进行交换 + /// 交换次数 + /// 交叉线路数量上限 ps:超过这个数量则不进行交换 + /// 新的目标点 + public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint, bool isSwap = true, int swapCount = 5, int crossingLimit = 6) + { + long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + StrPrint("-------智能选择路径计算,开始-------"); + int planeCou = aVecs.Length; // 飞机总数 + List match = new List(); // ab对应关系 + ///记录a b集合索引 + List aIndex = new List(); + List bIndex = new List(); + for (int k = 0; k < planeCou; k++) + { + aIndex.Add(k); + bIndex.Add(k); + } + /// 遍历找出 AB集合对应关系 + for (int k = 0; k < planeCou; k++) + { + + // 遍历每次刷新 剩下为未匹配总数 + int remainCou = aIndex.Count; + // 遍历每次刷新 重心 + List allVecs = new List(); + for (int i = 0; i < remainCou; i++) + { + allVecs.Add(aVecs[aIndex[i]]); + allVecs.Add(bVecs[bIndex[i]]); + } + Vector3 centerVec = GetPosCenter(allVecs);//重心点 + // 遍历所有ab点距离重心点的距离 + double[] aLens = new double[remainCou]; + 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); + } + // 找出ab集合最外层坐标的下标 即离重心点最远的点 + int aMaxIndex = GetIndexOfMaxOrMin(aLens); // a集合到重心点最长的距离 数组的下标 + int bMaxIndex = GetIndexOfMaxOrMin(bLens); // b集合到重心点最长的距离 数组的下标 + if (aLens[aMaxIndex] > bLens[bMaxIndex])//找出 最外层如果为A集合点 对应B集合最近点 的下标 + { + double[] outAtoBLen = new double[remainCou];//最外层A点到 B集合所有点的距离 + for (int i = 0; i < remainCou; i++) + { + outAtoBLen[i] = GageLengthSquare(aVecs[aIndex[aMaxIndex]], bVecs[bIndex[i]]); + } + int bMinIndex = GetIndexOfMaxOrMin(outAtoBLen, false);// 最短距离 + match.Add(new int[] { aIndex[aMaxIndex], bIndex[bMinIndex] });// 映射到配对 + aIndex.RemoveAt(aMaxIndex); // 删除已经配对的a集合 ID + bIndex.RemoveAt(bMinIndex); // 删除已经配对的b集合 ID + } + else//找出 最外层如果为B集合点 对应A集合最近点 的下标 + { + double[] outBtoALen = new double[remainCou];//最外层B点到 A集合所有点的距离 + for (int i = 0; i < remainCou; i++) + { + outBtoALen[i] = GageLengthSquare(aVecs[aIndex[i]], bVecs[bIndex[bMaxIndex]]); + } + int aMinIndex = GetIndexOfMaxOrMin(outBtoALen, false);// 最短距离 + match.Add(new int[] { aIndex[aMinIndex], bIndex[bMaxIndex] });// 映射到配对 + aIndex.RemoveAt(aMinIndex); // 删除已经配对的a集合 ID + bIndex.RemoveAt(bMaxIndex); // 删除已经配对的b集合 ID + } + } + Vector3[] new_bVecs = CreateNewBVecs(bVecs, match);// 按照映射 获取a 对应的 新的b集合 + if (!isSwap) + { + return new_bVecs; + } + ///交叉 交换 + for (int i = 0; i < swapCount; i++) + { + List planesCollision = AirImitation(aVecs, new_bVecs);// 获取碰撞组 + List> formatCollision = FindConnected(planesCollision);// 获取交叉序列 例如:[[0,2][0,3][3,4][5,6]] 结果[[0,2,3,4][5,6]] + List> filteredCollision = formatCollision.Where(sublist => sublist.Count <= crossingLimit).ToList();// 过滤 只保留交叉数量小于等于crossingLimit的序列 + if (filteredCollision.Count == 0) break; + ///日志输出 + string log = ""; + foreach (List item in filteredCollision) + { + log += "["; + foreach (int itemInt in item) + { + log += $"{itemInt},"; + } + log += "]"; + } + StrPrint($"共迭代{swapCount}次交换,第{i}次。共{filteredCollision.Count}组,交换组为:{log}。"); + /// 遍历所有交叉组 分组做交换 + int cou = 0; + foreach (List swap_indices in filteredCollision) + { + cou++; + StrPrint($"进度:{cou}/{filteredCollision.Count}。交换组:[{string.Join(", ", swap_indices)}]。"); + ///交叉 生成所有排列 + List> all_permutations = Permutations(swap_indices);//所有排列组合 + List original = all_permutations[0];//原始排列 + all_permutations.RemoveAt(0);//删掉第一个 既原始排列 + /// 按所有的排列 互换航线 并检测出最佳的对应目标点 + List tempLen = new List(); //记录最少碰撞的 排列 + List tempNew_bVecsS = new List();//记录最少碰撞的 排列交换之后的目标坐标集 + foreach (List indices in all_permutations) + { + Vector3[] current_array = new Vector3[planeCou]; + Array.Copy(new_bVecs, current_array, planeCou);//复制一个new_bVecs 副本 + for (int k = 0; k < indices.Count; k++) + { + 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); + } + } + new_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)]; + } + } + + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------智能选择路径计算,结束-------"); + return new_bVecs; + } + /// + /// 智能错层 + /// + /// 起始坐标集合 + /// 终点做标集合 + /// 起始坐标航点名称 + /// 终点坐标航点名称 + /// 日志输出 回调函数 + /// 错层层高 + /// 返回一个二维向量坐标集合 middle[0]是第一个中间航点 middle[1]是第二个中间航点 返回空数组则代表两个图形不在一个平面上或者不够4个点 + public static List> CollisionLayer(Vector3[] aVecs, Vector3[] bVecs,string aName,string bName ,SomeCalculateWay StrPrint, double layHight = 220) + { + long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + StrPrint("-------错层,开始-------"); + List> re = new List>(); + ///判断有没有碰撞 有碰撞继续 没有直接返回 + List planesCollision = AirImitation(aVecs, bVecs); //获取碰撞组 + if (planesCollision.Count == 0) + { + StrPrint("没有检测到碰撞,故不用添加中间航点"); + StrPrint($"-------错层结束-------"); + return re;//直接返回 + } + //获取飞机总数 + int planeCou = aVecs.Length; + if (planeCou < 2)//至少不少于2架飞机 才开始错层 + { + StrPrint("图案至少要两个点阵!"); + return re; + } + + ///从ab图案中取最外层3个点 确定一个面 ps:方便后续叉积算法线标量 + Vector3 vec0 = new Vector3(0, 0, 0); //记录最外圈一个坐标 + Vector3 vec1 = new Vector3(0, 0, 0); //记录离最外圈坐标最远的一个点坐标 + Vector3 vec2 = new Vector3(0, 0, 0); //最外圈距离 和最远距离 之和最远的一个点 + // 求重心 + List allVecs = new List(); + for (int i = 0; i < planeCou; i++) + { + allVecs.Add(aVecs[i]); + allVecs.Add(bVecs[i]); + } + Vector3 centerVec = GetPosCenter(allVecs);//重心点 + // 遍历所有ab点 + double tempLong = 0; + double currentLong; + for (int i = 0; i < planeCou * 2; i++) //取最外圈一个坐标 + { + currentLong = GageLength(allVecs[i], centerVec); + if (tempLong < currentLong) + { + vec0 = allVecs[i]; + tempLong = currentLong; + } + } + tempLong = 0; + for (int i = 0; i < planeCou * 2; i++) //取最外圈点 + { + currentLong = GageLength(allVecs[i], vec0); + if (tempLong < currentLong) + { + vec1 = allVecs[i]; + tempLong = currentLong; + } + } + tempLong = 0; + for (int i = 0; i < planeCou * 2; i++) //取最外圈点 + { + currentLong =(GageLength(allVecs[i], vec0) + GageLength(allVecs[i], vec1)); + if (tempLong < currentLong) + { + vec2 = allVecs[i]; + tempLong = currentLong; + } + } + ///遍历两个图形所有点 是否在一个平面上 + string aNoPlaneSN= "";//记录a图案所有不在一个平面上的点 + string bNoPlaneSN = "";//记录b图案所有不在一个平面上的点 + for (int i = 0; i < planeCou; i++) + { + if (!IsVecsOnPlane(vec0, vec1, vec2, aVecs[i])) aNoPlaneSN += $"{i+1},"; + if (!IsVecsOnPlane(vec0, vec1, vec2, bVecs[i])) bNoPlaneSN += $"{i+1},"; + } + if (aNoPlaneSN != "" || bNoPlaneSN != "") + { + if (aNoPlaneSN != "") StrPrint($"“{aName}”:{aNoPlaneSN}号飞机 ,不在一个平面,故不能做搓层处理!"); + if (bNoPlaneSN != "") StrPrint($"“{bName}”:{bNoPlaneSN}号飞机 ,不在一个平面,故不能做搓层处理!"); + StrPrint($"-------错层,结束-------"); + return re;//两个图形不在一个平面上 返回 空数组 + } + ///检查完毕后 + //计算法线向量 + Vector3 side1 = vec1 - vec0; + Vector3 side2 = vec2 - vec0; + Vector3 normal = CrossPro(side1, side2); + Vector3 normalScalar = normal.NormalizEd();//法线标量 + //开始错层 + for (int i = 0; i < planeCou; i++) + { + int shiftCou = 1; //记录循环次数 即层数 + Vector3 aOrigin = aVecs[i]; //原点位置 + Vector3 bOrigin = bVecs[i]; //原点位置 + while (OnlyImitation(i, aVecs, bVecs)) + { + Vector3 shiftVec = normalScalar * ((shiftCou + 1) / 2 * layHight); + if (shiftCou % 2 == 1) + { + aVecs[i] = aOrigin + shiftVec; + bVecs[i] = bOrigin + shiftVec; + } + else + { + aVecs[i] = aOrigin - shiftVec; + bVecs[i] = bOrigin - shiftVec; + } + shiftCou += 1; + } + } + re.Add(aVecs.ToList()); + re.Add(bVecs.ToList()); + StrPrint($"错层成功"); + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------错层结束-------"); + return re; + } + /// + /// 路径绕行 + /// + /// 起始坐标集合 + /// 终点做标集合 + /// 日志输出 回调函数 + /// 返回一个二维数组 返回值长度0没有检测到碰撞或绕行失败 长度1为一个中间航点 长度为3为三个中间航点顺序(前中后) + public static List> ABypassB(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint, Schedule GetVal) + { + long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + StrPrint("-------3D绕行,开始-------"); + List> re = new List>(); + ///判断有没有碰撞 有碰撞继续 没有直接返回 + List planesCollision = AirImitation(aVecs, bVecs); //获取碰撞组 + if (planesCollision.Count == 0) + { + StrPrint("没有检测到碰撞,故不用添加中间航点"); + StrPrint($"-------3D绕行,结束-------"); + return re;//直接返回 + } + ///飞机总数 + int planeCou = aVecs.Length; + ///第一次绕行 中间1航点 + List collisionGroup = TwoArrToArr(planesCollision); //整合数组 + List middleVecs = new List(); //中心航点坐标组 + for (int i = 0; i < planeCou; i++) + { + middleVecs.Add(SetMiddleVec(aVecs[i], bVecs[i])); //添加默认中间航点 + } + for (int c = 0; c < 2; c++) + { + foreach (int i in collisionGroup)//开始绕碰撞组 + { + List grv = GetRingVec(aVecs[i], bVecs[i], 0.5, 40, 4);//中间可绕行航点列表 + foreach (Vector3 v in grv) + { + middleVecs[i] = v; + if (!OnlyImitation(i, aVecs, middleVecs) && !(OnlyImitation(i, middleVecs, bVecs))) + { + break; + } + } + } + planesCollision = AirImitation(aVecs, middleVecs).Concat(AirImitation(middleVecs, bVecs)).ToList(); //获取碰撞组 + collisionGroup = TwoArrToArr(planesCollision); //整合数组 + } + //没有碰撞 返回一个中间航点 并返回 + if (collisionGroup.Count == 0) + { + StrPrint("第一次绕行成功!"); + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------3D绕行,结束-------"); + re.Add(middleVecs); + return re; + } + else + { + StrPrint($"{string.Join("号, ", collisionGroup)}号,有碰撞,共{collisionGroup.Count}架!"); + StrPrint("第一次绕行未成功,准备开始第二次绕行!"); + } + + ///第二次绕行 两头 两航点 + bool isPassMark = false; + planesCollision = AirImitation(aVecs, bVecs); //获取碰撞组 + collisionGroup = TwoArrToArr(planesCollision); //整合数组 + List secondMiddleVecsOne = new List(); //中心航点坐标组1 + List secondMiddleVecsTwo = new List(); //中心航点坐标组2 + for (int i = 0; i < planeCou; i++) + { + secondMiddleVecsOne.Add(SetMiddleVec(aVecs[i], bVecs[i], 0.1)); //添加中间航点1 + secondMiddleVecsTwo.Add(SetMiddleVec(aVecs[i], bVecs[i], 0.9)); //添加中间航点2 + } + for (int c = 0; c < 2; c++) + { + int progress = 0;//进度 + foreach (int i in collisionGroup)//开始绕碰撞组 + { + progress++; + //StrPrint($"迭代{c}次{i}号绕行"); + List sgrv1 = GetRingVec(aVecs[i], bVecs[i], 0.1, 40, 8);//中间可绕行航点列表 + List sgrv2 = GetRingVec(aVecs[i], bVecs[i], 0.9, 40, 8);//中间可绕行航点列表 + //if (sgrv1.Count > 250) sgrv1.RemoveRange(250, sgrv1.Count - 250); + //if (sgrv2.Count > 250) sgrv2.RemoveRange(250, sgrv2.Count - 250); + StrPrint($"进度:{progress}/{collisionGroup.Count},本次绕行{Math.Pow(sgrv2.Count,2)}次"); + foreach (Vector3 v1 in sgrv1) + { + secondMiddleVecsOne[i] = v1; + foreach (Vector3 v2 in sgrv2) + { + secondMiddleVecsTwo[i] = v2; + if (!OnlyImitation(i, aVecs, secondMiddleVecsOne) && !OnlyImitation(i, secondMiddleVecsOne, secondMiddleVecsTwo) && !OnlyImitation(i, secondMiddleVecsTwo, bVecs)) + { + isPassMark = true; + break; + } + isPassMark = false; + } + if (isPassMark) + { + break; //不撞则跳出 进行下一航线的绕行 + } + } + } + planesCollision = AirImitation(aVecs, secondMiddleVecsOne).Concat(AirImitation(secondMiddleVecsOne, secondMiddleVecsTwo)).ToList(); //获取碰撞组 + planesCollision = planesCollision.Concat(AirImitation(secondMiddleVecsTwo, bVecs)).ToList(); + collisionGroup = TwoArrToArr(planesCollision); //整合数组 + } + //没有碰撞 返回两个中间航点 并返回 + if (collisionGroup.Count == 0) + { + StrPrint("第二次绕行成功!"); + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------3D绕行,结束-------"); + re.Add(secondMiddleVecsOne); + re.Add(secondMiddleVecsTwo); + return re; + } + else + { + StrPrint($"{string.Join("号, ", collisionGroup)}号,有碰撞,共{collisionGroup.Count}架!"); + StrPrint("第二次绕行未通过,准备开始第三次绕行!"); + } + + ///第三次绕行 两头 两航点 中间一行点 沿用第二次绕行 + isPassMark = false; + List thirdMiddleVecs = new List(); //中心航点坐标组 + for (int i = 0; i < planeCou; i++) + { + thirdMiddleVecs.Add(SetMiddleVec(secondMiddleVecsOne[i], secondMiddleVecsTwo[i], 0.5)); //添加中间航点(保持二次绕行的两端航点 在两端航点中间添加) + } + for (int c = 0; c < 2; c++) + { + int progress = 0;//进度 + foreach (int i in collisionGroup)//开始绕碰撞组 + { + progress++; + //StrPrint($"迭代{c}次{i}号绕行"); + List sgrv1 = GetRingVec(aVecs[i], bVecs[i], 0.1, 220, 8);//中间可绕行航点列表 + List sgrv2 = GetRingVec(aVecs[i], bVecs[i], 0.9, 220, 8);//中间可绕行航点列表 + List grv = GetRingVec(secondMiddleVecsOne[i], secondMiddleVecsTwo[i], 0.5, 220, 4);//中间可绕行航点列表 + //if (sgrv1.Count > 300) sgrv1.RemoveRange(300, sgrv1.Count - 300); + //if (sgrv2.Count > 300) sgrv2.RemoveRange(300, sgrv2.Count - 300); + //if (grv.Count > 300) grv.RemoveRange(300, grv.Count - 300); + StrPrint($"进度:{progress}/{collisionGroup.Count},本次绕行{Math.Pow(sgrv2.Count, 3)}次"); + foreach (Vector3 vm in grv) + { + thirdMiddleVecs[i] = vm; + foreach (Vector3 v1 in sgrv1) + { + secondMiddleVecsOne[i] = v1; + foreach (Vector3 v2 in sgrv2) + { + secondMiddleVecsTwo[i] = v2; + if (!OnlyImitation(i, aVecs, secondMiddleVecsOne) && !OnlyImitation(i, secondMiddleVecsOne, thirdMiddleVecs ) && !OnlyImitation(i, thirdMiddleVecs, secondMiddleVecsTwo) && !OnlyImitation(i, secondMiddleVecsTwo, bVecs)) + { + isPassMark = true; + break; + } + isPassMark = false; + } + if (isPassMark) + { + break; //不撞则跳出 进行下一航线的绕行 + } + } + if (isPassMark) + { + break; //不撞则跳出 进行下一航线的绕行 + } + } + } + planesCollision = AirImitation(aVecs, secondMiddleVecsOne).Concat(AirImitation(secondMiddleVecsOne, thirdMiddleVecs)).ToList(); //获取碰撞组 + planesCollision = planesCollision.Concat(AirImitation(thirdMiddleVecs, secondMiddleVecsTwo)).ToList(); + planesCollision = planesCollision.Concat(AirImitation(secondMiddleVecsTwo, bVecs)).ToList(); + collisionGroup = TwoArrToArr(planesCollision); //整合数组 + } + //没有碰撞 返回三个中间航点 并返回 + if (collisionGroup.Count == 0) + { + StrPrint("第三次绕行成功!"); + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------3D绕行,结束-------"); + re.Add(secondMiddleVecsOne); + re.Add(thirdMiddleVecs); + re.Add(secondMiddleVecsTwo); + return re; + } + else + { + StrPrint($"{string.Join("号, ", collisionGroup)}号,有碰撞,共{collisionGroup.Count}架!"); + StrPrint("第三次绕行未成功,准备开始第四次绕行!"); + } + + ///end + t = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t; + StrPrint($"用时:{t}秒"); + StrPrint($"-------3D绕行,结束-------"); + return re; + } + /// + /// 在圆圈上 用固定弦长手拉手 分割点 + /// + /// 大圆半径 + /// 固定弦长 ps:这个值决定绕行点一圈的密集成都值越小越密集 + /// + private static List GetVecsOnCircle(double radius, double chordLength) + { + List vecs = new List(); + // 计算圆的周长 + double circumference = (double)(2 * Math.PI * radius); + // 计算弧上的点数 + int numberOfPoints = (int)(circumference / chordLength); + // 计算每个点的弧度 + double angleIncrement = (double)(2 * Math.PI / numberOfPoints); + // 生成点的坐标 + for (int i = 0; i < numberOfPoints; i++) + { + double angle = i * angleIncrement; + double x = radius * (double)Math.Cos(angle); + double y = radius * (double)Math.Sin(angle); + double z = 0.0; // 如果是在平面上,Z 可能是 0 + vecs.Add(new Vector3(x, y, z)); + } + return vecs; + } + /// + /// 获取a指向b的向量矩阵 ps:偏移次数 加1 会在终点前后往返偏移 + /// + /// a向量 + /// b向量 + /// 默认中点位置比例 + /// 偏移次数 从0开始,每+1在中点前后往返偏移 + /// 偏移层高 + /// 层排布方向 "retrun"前后堆叠 "forward"向前排列(如:起点向目标点方向) "backward"向后排列 + /// 矩阵 + private static Matrix GetBasisMatrix(Vector3 aVec, Vector3 bVec, double middleProportion, int offCount, double layHight,string direction) + { + /// 计算前向向量 k帽 + Vector3 k_hat = (bVec - aVec).NormalizEd(); + /// 计算右向量,使用 Vector3.UnitY 作为上向量 i帽 + //Vector3 i_hat = CrossPro(Vector3.UnitY, k_hat).NormalizEd(); //固定方向i帽 + Random random = new Random();// 生成一个随机的单位向量 + Vector3 randomVector = new Vector3((double)random.NextDouble(), (double)random.NextDouble(), (double)random.NextDouble()); + Vector3 i_hat = CrossPro(k_hat, randomVector).NormalizEd();// 随机方向i帽 + /// 计算上向量 j帽 + Vector3 j_hat = CrossPro(k_hat, i_hat); + ///计算 对应的偏移比例 + double length = (bVec - aVec).GetMag(); + double offShift = middleProportion;//偏移比例 + if (direction == "retrun") + { + if (offCount % 2 == 1) //奇数 + offShift = middleProportion + (offCount + 2) / 2 * layHight / length; + else //偶数 + offShift = middleProportion - (offCount + 1) / 2 * layHight / length; + } + else if (direction == "forward") + { + offShift = middleProportion + offCount * layHight / length; + } + else if(direction == "backward") + { + offShift = middleProportion - offCount * layHight / length; + } + + /// 计算偏向量 + Vector3 off = aVec + (bVec - aVec) * offShift; + + /// 构建矩阵 + Matrix matrix = new Matrix + { + M11 = k_hat.X, + M12 = k_hat.Y, + M13 = k_hat.Z, + M21 = i_hat.X, + M22 = i_hat.Y, + M23 = i_hat.Z, + M31 = j_hat.X, + M32 = j_hat.Y, + M33 = j_hat.Z, + M41 = off.X, + M42 = off.Y, + M43 = off.Z + }; + return matrix; + } + /// + /// a b点中间的绕行航点列表 + /// + /// 起点 + /// 目标点 + /// 中间航点位置比例 + /// 绕行航点密度(值越小密度越大) ps:传递圈函数的弦长 向量矩阵函数的层高 + /// 绕行航点范围(值越小范围越大) ps:决定层的厚度 和 圈的直径 为 paunch/航线长度 + /// 绕行航点列表 + private static List GetRingVec(Vector3 aVec, Vector3 bVec, double middleProportion, double transfer, double paunch,bool singleCircle =true, string direction = "retrun") + { + List ringVec = new List(); //记录所有绕行中间航点坐标 + /// 根据a到b的长度 算出中间绕行几圈 + int ringCou = (int)Math.Ceiling(GageLength(aVec, bVec) / paunch / transfer); //算层数和圈数 ps:层的厚度 和 圈的直径 为 paunch/航线长度 + if (ringCou < 2) ringCou = 2; //最少两圈 两层 + /// 不是单圈的话 设置层数跟圈数相等 + int layCou = ringCou; + if (singleCircle) layCou = 1; + ///遍历出所有绕行航点 + for (int z = 0; z < layCou; z++) //迭代层 + { + Matrix mat = GetBasisMatrix(aVec, bVec, middleProportion, z, transfer, direction); //根据圈数越多 偏移层数也越多 即每层矩阵off位置 + for (int i = 0; i < ringCou; i++) //迭代圈 + { + if (i != 0) + { + List tempCi = GetVecsOnCircle(i * transfer, transfer); + foreach (Vector3 vec in tempCi) + { + ringVec.Add(vec.Multiply(mat));//按照矩阵旋转之后 添加到中间航点列表 + } + } + else + { + ringVec.Add(mat[3]); //第一次循环 并非圈 只在航线上 按层比例取点 即可 + } + } + } + return ringVec; + } + /// + /// 按照矩阵 拉散图案 + /// + /// 平面图案坐标组 + /// 回归矩阵坐标组 + /// 日志输出 回调函数 + /// 拉散图案的坐标组 + public static Vector3[] NormalPull(Vector3[] aVecs, Vector3[] bVecs, SomeCalculateWay StrPrint) + { + int planeCou = aVecs.Length; //获取飞机总数 + ///a图b图 中心 + Vector3 aCenterPos = GetPosCenter(aVecs, false); + Vector3 bCenterPos = GetPosCenter(bVecs, false); + ///判断bVec 矩阵的数量长宽 + for (int i = 0; i < planeCou; i++)//把矩阵高度压平 + { + bVecs[i] = new Vector3(bVecs[i].X, 0, bVecs[i].Z); + } + int row = 1 ; + for (int i = 0; i < planeCou-2; i++) + { + if (!(IsVecsOnLine(bVecs[i], bVecs[i + 1], bVecs[i + 2]))) + { + row = i+2;//列 + break; + } + } + int ran = (int)Math.Ceiling((double)planeCou/(double)row);//行 + ///计算a图的法线标量 + Vector3 side1 = aVecs[1] - aVecs[0]; + Vector3 side2 = aVecs[2] - aVecs[0]; + Vector3 normal = CrossPro(side1, side2); + Vector3 normalScalar = normal.NormalizEd();//法线标量 + normalScalar.Y = 0;//高度上压平 + ///判断a图 法线朝向 和 矩阵“平行”方向 获取此方向层数 ps:用于a图的拉散 + if (GageLength(normalScalar, bVecs[0]) < GageLength(normalScalar * -1, bVecs[0])) + { + normalScalar *= -1;//法线选择方向为 靠近矩阵1号机的方向 ps:由于取的三个点位置随机 按照右手定则 法线方向也随机 + } + if (Math.Abs(AngleBetween(bVecs[row] - bVecs[0], normalScalar) - 90) < Math.Abs(AngleBetween(bVecs[1] - bVecs[0], normalScalar) - 90)) + { + /// 图案“如平行于0 21 41..” 平行于列 + for (int k = 0; k < row; k++) + { + for (int i = 0; i < ran; i++) + { + int cou = i * row + k; + if (cou > planeCou) break;// 溢出跳出 + ///判断图在矩阵的左方 还是右方 + if (GageLength(aCenterPos, bVecs[0]) > GageLength(aCenterPos, bVecs[row - 1])) + { + aVecs[cou] -= normalScalar * (row - k) * 300;//左方 + } + else + { + aVecs[cou] += normalScalar * k * 300;//右方 + } + } + } + ///判断a图的中心点 是否在矩阵内部 在矩阵内部 做一个a b两组中心点对其 ps:相当于朝两边拉散 + if (IsPointBetweenLines(bVecs[(int)Math.Ceiling(((double)row/5))-1], bVecs[(int)Math.Ceiling(((double)row / 5)) - 1+row], bVecs[row-((int)Math.Ceiling(((double)row / 5)) - 1)], bVecs[(row - ((int)Math.Ceiling(((double)row / 5)) - 1))+row], aCenterPos)) + { + aCenterPos = GetPosCenter(aVecs, false);//重新算下中心点 + Vector3 offPos = aCenterPos - bCenterPos;//偏移量 + for (int i = 0; i < planeCou; i++) + { + aVecs[i] -= offPos; + } + } + + } + else + { + /// 图案“如平行于 0-20” 平行于行 + for (int k = 0; k < ran; k++) + { + for (int i = 0; i < row; i++) + { + int cou = k * row + i; + if (cou > planeCou) break;// 溢出跳出 + ///判断图在矩阵的上方 还是下方 + if (GageLength(aCenterPos, bVecs[0]) > GageLength(aCenterPos, bVecs[row * (ran - 1)])) + { + aVecs[cou] -= normalScalar * (ran - k) * 300;//上方 + } + else + { + aVecs[cou] += normalScalar * k * 300;//下方 + } + } + } + ///判断a图的中心点 是否在矩阵内部 在矩阵内部 做一个a b两组中心点对其 ps:相当于朝两边拉散 + if (IsPointBetweenLines(bVecs[(int)Math.Ceiling((double)ran / 5) * row - row], bVecs[(int)Math.Ceiling((double)ran / 5) * row - 1], bVecs[(ran - (int)Math.Ceiling((double)ran / 5)) * row], bVecs[(ran - (int)Math.Ceiling((double)ran / 5)) * row + row - 1], aCenterPos)) + { + aCenterPos = GetPosCenter(aVecs, false);//重新算下中心点 + Vector3 offPos = aCenterPos - bCenterPos;//偏移量 + for (int i = 0; i < planeCou; i++) + { + aVecs[i] -= offPos; + } + } + } + return aVecs; + } + } +} \ No newline at end of file diff --git a/FlightRouteV2/FlightRouteV2.csproj b/FlightRouteV2/FlightRouteV2.csproj new file mode 100644 index 0000000..da4f76c --- /dev/null +++ b/FlightRouteV2/FlightRouteV2.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {626A9BFA-07DE-4063-A178-360EB7057ED6} + Library + Properties + FlightRouteV2 + FlightRouteV2 + v4.8 + 512 + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlightRouteV2/Properties/AssemblyInfo.cs b/FlightRouteV2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..331cefd --- /dev/null +++ b/FlightRouteV2/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("FlyBase")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FlyBase")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("626a9bfa-07de-4063-a178-360eb7057ed6")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FlightRouteV2/Vector3.cs b/FlightRouteV2/Vector3.cs new file mode 100644 index 0000000..407a1ca --- /dev/null +++ b/FlightRouteV2/Vector3.cs @@ -0,0 +1,154 @@ +using System; + +namespace FlyBase +{ + public struct Vector3 + { + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + /// + /// 构造 初始化 + /// + /// x坐标 + /// y坐标 + /// z坐标 + public Vector3(double x, double y, double z) + { + this.X = x; + this.Y = y; + this.Z = z; + } + //重载二元坐标加法+ + public static Vector3 operator +(Vector3 v1, Vector3 v2) + { + return new Vector3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); + } + //重载一元坐标加法+ + public static Vector3 operator +(Vector3 v1, double i) + { + return new Vector3(v1.X + i, v1.Y + i, v1.Z + i); + } + //重载一元坐标加法+ + public static Vector3 operator +(Vector3 v1, int i) + { + return new Vector3(v1.X + (double)i, v1.Y + (double)i, v1.Z + (double)i); + } + //重载二元坐标减法- + public static Vector3 operator -(Vector3 v1, Vector3 v2) + { + return new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); + } + //重载一元坐标加法- + public static Vector3 operator -(Vector3 v1, double i) + { + return new Vector3(v1.X - i, v1.Y - i, v1.Z - i); + } + //重载一元坐标加法- + public static Vector3 operator -(Vector3 v1, int i) + { + return new Vector3(v1.X - (double)i, v1.Y - (double)i, v1.Z - (double)i); + } + //重载一元坐标乘法* + public static Vector3 operator *(Vector3 v1, double i) + { + return new Vector3(v1.X * i, v1.Y * i, v1.Z * i); + } + //重载一元坐标乘法* + public static Vector3 operator *(Vector3 v1, int i) + { + return new Vector3(v1.X * (double)i, v1.Y * (double)i, v1.Z * (double)i); + } + //重载一元坐标除法/ + public static Vector3 operator /(Vector3 v1, double i) + { + return new Vector3(v1.X / i, v1.Y / i, v1.Z / i); + } + //重载一元坐标除法/ + public static Vector3 operator /(Vector3 v1, int i) + { + return new Vector3(v1.X / (double)i, v1.Y / (double)i, v1.Z / (double)i); + } + //重载== + public static bool operator ==(Vector3 v1, Vector3 v2) + { + if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z) return true; + return false; + } + //重载!= + public static bool operator !=(Vector3 v1, Vector3 v2) + { + if (v1.X != v2.X || v1.Y != v2.Y || v1.Z != v2.Z) return true; + return false; + } + //模长 + public double GetMag() + { + return Math.Sqrt(Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2)); + } + /// + /// 标准化坐标 + /// + /// 标准化单位 + public void Normalize(double multiple = 1.0) + { + double magSq = Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2); + if (magSq > 0) + { + double oneOverMag = multiple / Math.Sqrt(magSq); + this.X *= oneOverMag; + this.Y *= oneOverMag; + this.Z *= oneOverMag; + } + } + /// + /// 标准化 返回一个标准化之后的值 不改变自身 + /// + /// 标准化单位 + /// 标准化之后的值 + public Vector3 NormalizEd(double multiple = 1.0) + { + Vector3 re = new Vector3(); + double magSq = Math.Pow(this.X, 2) + Math.Pow(this.Y, 2) + Math.Pow(this.Z, 2); + if (magSq > 0) + { + double oneOverMag = multiple / Math.Sqrt(magSq); + re.X = this.X * oneOverMag; + re.Y = this.Y * oneOverMag; + re.Z = this.Z * oneOverMag; + } + return re; + } + //归零 改变自身数值 一般配合归位使用 + public void SetZero(Vector3 v2) + { + this.X -= v2.X; + this.Y -= v2.Y; + this.Z -= v2.Z; + } + //归零 返回一个归零值 不改变自身 + public Vector3 SetZeroEd(Vector3 v2) + { + Vector3 re = new Vector3(this.X - v2.X, this.Y - v2.Y, this.Z - v2.Z); + return re; + } + //归位 + public void SetFormerly(Vector3 v2) + { + this.X += v2.X; + this.Y += v2.Y; + this.Z += v2.Z; + } + /// + /// 打印坐标 + /// + /// 坐标字符串 + public string PosToString() + { + string x = Convert.ToString(this.X); + string y = Convert.ToString(this.Y); + string z = Convert.ToString(this.Z); + return string.Format($"X轴:{x} Y轴:{y} Z轴:{z}"); + } + } +} \ No newline at end of file diff --git a/FlightRouteV2/bin/Debug/FlightRouteV2.dll b/FlightRouteV2/bin/Debug/FlightRouteV2.dll new file mode 100644 index 0000000..0cf5bbe Binary files /dev/null and b/FlightRouteV2/bin/Debug/FlightRouteV2.dll differ diff --git a/FlightRouteV2/bin/Debug/FlightRouteV2.pdb b/FlightRouteV2/bin/Debug/FlightRouteV2.pdb new file mode 100644 index 0000000..9808e34 Binary files /dev/null and b/FlightRouteV2/bin/Debug/FlightRouteV2.pdb differ diff --git a/FlightRouteV2/bin/Debug/FlyBase.dll b/FlightRouteV2/bin/Debug/FlyBase.dll new file mode 100644 index 0000000..88aa09c Binary files /dev/null and b/FlightRouteV2/bin/Debug/FlyBase.dll differ diff --git a/FlightRouteV2/bin/Debug/FlyBase.pdb b/FlightRouteV2/bin/Debug/FlyBase.pdb new file mode 100644 index 0000000..d63ecbc Binary files /dev/null and b/FlightRouteV2/bin/Debug/FlyBase.pdb differ diff --git a/FlightRouteV2/bin/Release/FlightRouteV2.dll b/FlightRouteV2/bin/Release/FlightRouteV2.dll new file mode 100644 index 0000000..b86bb34 Binary files /dev/null and b/FlightRouteV2/bin/Release/FlightRouteV2.dll differ diff --git a/FlightRouteV2/bin/Release/FlightRouteV2.pdb b/FlightRouteV2/bin/Release/FlightRouteV2.pdb new file mode 100644 index 0000000..d7856ee Binary files /dev/null and b/FlightRouteV2/bin/Release/FlightRouteV2.pdb differ diff --git a/FlightRouteV2/bin/Release/FlyBase.dll b/FlightRouteV2/bin/Release/FlyBase.dll new file mode 100644 index 0000000..9229221 Binary files /dev/null and b/FlightRouteV2/bin/Release/FlyBase.dll differ diff --git a/FlightRouteV2/bin/Release/FlyBase.pdb b/FlightRouteV2/bin/Release/FlyBase.pdb new file mode 100644 index 0000000..6adb3ca Binary files /dev/null and b/FlightRouteV2/bin/Release/FlyBase.pdb differ diff --git a/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.6.2.AssemblyAttributes.cs b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.6.2.AssemblyAttributes.cs new file mode 100644 index 0000000..edc4647 --- /dev/null +++ b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.6.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] diff --git a/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs new file mode 100644 index 0000000..3871b18 --- /dev/null +++ b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs new file mode 100644 index 0000000..15efebf --- /dev/null +++ b/FlightRouteV2/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] diff --git a/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferences.cache b/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferences.cache new file mode 100644 index 0000000..f5e894a Binary files /dev/null and b/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferences.cache differ diff --git a/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..2939541 Binary files /dev/null and b/FlightRouteV2/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.AssemblyReference.cache b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.AssemblyReference.cache new file mode 100644 index 0000000..c58ab16 Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.AssemblyReference.cache differ diff --git a/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.CoreCompileInputs.cache b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..638701b --- /dev/null +++ b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +254d0916f0a94457ded9d42398d6e5648a952309 diff --git a/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.FileListAbsolute.txt b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..c41e345 --- /dev/null +++ b/FlightRouteV2/obj/Debug/FlightRouteV2.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Debug\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Debug\FlightRouteV2.pdb +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlightRouteV2.csproj.AssemblyReference.cache +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlightRouteV2.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlightRouteV2.pdb +F:\company\flyCube\repos\FlyCube\FlightRouteV2\bin\Debug\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlightRouteV2\bin\Debug\FlightRouteV2.pdb +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Debug\FlightRouteV2.csproj.AssemblyReference.cache +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Debug\FlightRouteV2.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Debug\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Debug\FlightRouteV2.pdb diff --git a/FlightRouteV2/obj/Debug/FlightRouteV2.dll b/FlightRouteV2/obj/Debug/FlightRouteV2.dll new file mode 100644 index 0000000..0cf5bbe Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlightRouteV2.dll differ diff --git a/FlightRouteV2/obj/Debug/FlightRouteV2.pdb b/FlightRouteV2/obj/Debug/FlightRouteV2.pdb new file mode 100644 index 0000000..9808e34 Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlightRouteV2.pdb differ diff --git a/FlightRouteV2/obj/Debug/FlyBase.csproj.AssemblyReference.cache b/FlightRouteV2/obj/Debug/FlyBase.csproj.AssemblyReference.cache new file mode 100644 index 0000000..528262c Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlyBase.csproj.AssemblyReference.cache differ diff --git a/FlightRouteV2/obj/Debug/FlyBase.csproj.CoreCompileInputs.cache b/FlightRouteV2/obj/Debug/FlyBase.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..1bc7f9a --- /dev/null +++ b/FlightRouteV2/obj/Debug/FlyBase.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +65dcdc626d7d72bd83a6dbfb060115196969f69e diff --git a/FlightRouteV2/obj/Debug/FlyBase.csproj.FileListAbsolute.txt b/FlightRouteV2/obj/Debug/FlyBase.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..5ed0bc4 --- /dev/null +++ b/FlightRouteV2/obj/Debug/FlyBase.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +F:\company\flyCube\repos\fly\FlyBase\bin\Debug\FlyBase.dll +F:\company\flyCube\repos\fly\FlyBase\bin\Debug\FlyBase.pdb +F:\company\flyCube\repos\fly\FlyBase\obj\Debug\FlyBase.csproj.AssemblyReference.cache +F:\company\flyCube\repos\fly\FlyBase\obj\Debug\FlyBase.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\fly\FlyBase\obj\Debug\FlyBase.dll +F:\company\flyCube\repos\fly\FlyBase\obj\Debug\FlyBase.pdb +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Debug\FlyBase.dll +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Debug\FlyBase.pdb +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlyBase.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlyBase.dll +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlyBase.pdb +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Debug\FlyBase.csproj.AssemblyReference.cache diff --git a/FlightRouteV2/obj/Debug/FlyBase.dll b/FlightRouteV2/obj/Debug/FlyBase.dll new file mode 100644 index 0000000..88aa09c Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlyBase.dll differ diff --git a/FlightRouteV2/obj/Debug/FlyBase.pdb b/FlightRouteV2/obj/Debug/FlyBase.pdb new file mode 100644 index 0000000..d63ecbc Binary files /dev/null and b/FlightRouteV2/obj/Debug/FlyBase.pdb differ diff --git a/FlightRouteV2/obj/Release/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/FlightRouteV2/obj/Release/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs new file mode 100644 index 0000000..3871b18 --- /dev/null +++ b/FlightRouteV2/obj/Release/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/FlightRouteV2/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs b/FlightRouteV2/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs new file mode 100644 index 0000000..15efebf --- /dev/null +++ b/FlightRouteV2/obj/Release/.NETFramework,Version=v4.8.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] diff --git a/FlightRouteV2/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache b/FlightRouteV2/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 0000000..41b170c Binary files /dev/null and b/FlightRouteV2/obj/Release/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/FlightRouteV2/obj/Release/FlightRouteV2.csproj.AssemblyReference.cache b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.AssemblyReference.cache new file mode 100644 index 0000000..c58ab16 Binary files /dev/null and b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.AssemblyReference.cache differ diff --git a/FlightRouteV2/obj/Release/FlightRouteV2.csproj.CoreCompileInputs.cache b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..461b945 --- /dev/null +++ b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +1aaa80ef5aa2c66232cf0fd45d64bc898b5ea44e diff --git a/FlightRouteV2/obj/Release/FlightRouteV2.csproj.FileListAbsolute.txt b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..59aa564 --- /dev/null +++ b/FlightRouteV2/obj/Release/FlightRouteV2.csproj.FileListAbsolute.txt @@ -0,0 +1,6 @@ +F:\company\flyCube\repos\FlyCube\FlightRouteV2\bin\Release\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlightRouteV2\bin\Release\FlightRouteV2.pdb +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Release\FlightRouteV2.csproj.AssemblyReference.cache +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Release\FlightRouteV2.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Release\FlightRouteV2.dll +F:\company\flyCube\repos\FlyCube\FlightRouteV2\obj\Release\FlightRouteV2.pdb diff --git a/FlightRouteV2/obj/Release/FlightRouteV2.dll b/FlightRouteV2/obj/Release/FlightRouteV2.dll new file mode 100644 index 0000000..b86bb34 Binary files /dev/null and b/FlightRouteV2/obj/Release/FlightRouteV2.dll differ diff --git a/FlightRouteV2/obj/Release/FlightRouteV2.pdb b/FlightRouteV2/obj/Release/FlightRouteV2.pdb new file mode 100644 index 0000000..d7856ee Binary files /dev/null and b/FlightRouteV2/obj/Release/FlightRouteV2.pdb differ diff --git a/FlightRouteV2/obj/Release/FlyBase.csproj.AssemblyReference.cache b/FlightRouteV2/obj/Release/FlyBase.csproj.AssemblyReference.cache new file mode 100644 index 0000000..528262c Binary files /dev/null and b/FlightRouteV2/obj/Release/FlyBase.csproj.AssemblyReference.cache differ diff --git a/FlightRouteV2/obj/Release/FlyBase.csproj.CoreCompileInputs.cache b/FlightRouteV2/obj/Release/FlyBase.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..760a1fe --- /dev/null +++ b/FlightRouteV2/obj/Release/FlyBase.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +a7be80f0590ce7e3d3292f0020daba81f87a9940 diff --git a/FlightRouteV2/obj/Release/FlyBase.csproj.FileListAbsolute.txt b/FlightRouteV2/obj/Release/FlyBase.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..81f2923 --- /dev/null +++ b/FlightRouteV2/obj/Release/FlyBase.csproj.FileListAbsolute.txt @@ -0,0 +1,6 @@ +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Release\FlyBase.dll +F:\company\flyCube\repos\FlyCube\FlyBase\bin\Release\FlyBase.pdb +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Release\FlyBase.csproj.AssemblyReference.cache +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Release\FlyBase.csproj.CoreCompileInputs.cache +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Release\FlyBase.dll +F:\company\flyCube\repos\FlyCube\FlyBase\obj\Release\FlyBase.pdb diff --git a/FlightRouteV2/obj/Release/FlyBase.csprojAssemblyReference.cache b/FlightRouteV2/obj/Release/FlyBase.csprojAssemblyReference.cache new file mode 100644 index 0000000..d41e237 Binary files /dev/null and b/FlightRouteV2/obj/Release/FlyBase.csprojAssemblyReference.cache differ diff --git a/FlightRouteV2/obj/Release/FlyBase.dll b/FlightRouteV2/obj/Release/FlyBase.dll new file mode 100644 index 0000000..9229221 Binary files /dev/null and b/FlightRouteV2/obj/Release/FlyBase.dll differ diff --git a/FlightRouteV2/obj/Release/FlyBase.pdb b/FlightRouteV2/obj/Release/FlyBase.pdb new file mode 100644 index 0000000..6adb3ca Binary files /dev/null and b/FlightRouteV2/obj/Release/FlyBase.pdb differ diff --git a/FlyCube/MainWindow.xaml.cs b/FlyCube/MainWindow.xaml.cs index 80f11b4..f216fcc 100644 --- a/FlyCube/MainWindow.xaml.cs +++ b/FlyCube/MainWindow.xaml.cs @@ -35,6 +35,12 @@ namespace FlyCube InitializeComponent(); //创建一个 主画布对象 TopCanvas = new MainCanvas(this.LayerPlane); + Vector3 A = new Vector3(0,0,0); + Vector3 B = new Vector3(0, 0, 10); + Vector3 C = new Vector3(10, 0, 0); + Vector3 D = new Vector3(10, 0, 10); + Vector3 P = new Vector3(10, 0, 10); + //MessageBox.Show(FlyVecFun.IsPointBetweenLines(A, B, C, D, P).ToString()); } /// /// 3D绕行 @@ -51,7 +57,7 @@ namespace FlyCube Vector3[] aVecs = abVecs[0].ToArray(); Vector3[] bVecs = abVecs[1].ToArray(); //Vector3[] new_bVecs = FlyVecFun.ContactABOut(aVecs, bVecs, StrPrint); - Vector3[] new_bVecs = FlyVecFun.NormalPull(aVecs, bVecs); + Vector3[] new_bVecs = FlyVecFun.NormalPull(aVecs, bVecs, StrPrintAsync); //Task>> reTask = Task.Run(() => FlyVecFun.ABypassB(aVecs, bVecs, StrPrintAsync, GetVal)); //List> re = await reTask;