diff --git a/FlieOperate/FileBase.cs b/FlieOperate/FileBase.cs index 3edce87..57c83da 100644 --- a/FlieOperate/FileBase.cs +++ b/FlieOperate/FileBase.cs @@ -1,9 +1,10 @@ -using System; +using FlyBase; +using System; +using System.Collections; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; using System.Windows.Forms; namespace FlieOperate @@ -13,6 +14,204 @@ namespace FlieOperate /// public class FileBase { + /// + /// 逐行读取 文档 + /// + /// 文件路径 + /// + private static string[] ReadFile(string path) + { + StreamReader sr = new StreamReader(path, Encoding.Default); + String line; + ArrayList arrlist = new ArrayList(); + while ((line = sr.ReadLine()) != null) + { + arrlist.Add(line); + } + if (arrlist.Count == 1)//判断 svg的文件内容 是否写在一行里面 + { + string temp = (string)arrlist[0]; + string[] strArray = Regex.Split(temp, "/>"); + return strArray; + } + string[] arr = new string[arrlist.Count]; + int key = 0; + foreach (var item in arrlist) + { + arr[key] = (string)item; + key++; + } + return arr; + } + /// + /// svg航点坐标文档 转坐标集合 PS:灯光映射 支持格式 + /// + /// 文件路径 + /// + public static Vector3[] SvgToPosForLight(string path) + { + //读取文档内容 + string[] arr; + arr = ReadFile(path); + //获取飞机x轴 z轴 坐标 + ArrayList tempVec = new ArrayList();//记录飞机坐标 + string cx = @"cx=""(?\-{0,1}\d*\.{0,1}\d*)"""; + string cy = @"cy=""(?\-{0,1}\d*\.{0,1}\d*)"""; + string r = @"r=""(?\d*\.{0,1}\d*)"""; + foreach (string item in arr) + { + if (item.IndexOf("= 0)//找到svg里面标签 + { + Regex reg = new Regex(cx); + string strX = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 + reg = new Regex(cy); + string strZ = reg.Match(item).Groups["mark"].ToString();//正则匹配获取y轴 在三维里面用作z轴 + double x = Convert.ToDouble(strX); + double z = Convert.ToDouble(strZ); + tempVec.Add(new Vector3(x, 0, z)); + } + } + Vector3[] vec = FlyVecFun.ArrToVec(tempVec);//把arrlist转换成坐标集合 + return vec;//返回坐标集合 + } + /// + /// txt航点坐标文档 转坐标集合 PS:目前是C4D坐标文档 + /// + /// 文件路径 + /// 参数形式返回航点名称集合 + /// 航点集合 + public static List TxtToPos(string path, out string[] flightPointNames) + { + //读取文档内容 + string[] arr; + arr = ReadFile(path); + //处理文档内容 + int group = 0;//获取有几组坐标 + foreach (string item in arr) + { + if (item.IndexOf(" ") <= 0)//找到航点名称 + { + group++; + } + } + int planesCou = (arr.Length - group) / group;//获取飞机总数 + flightPointNames = new string[group];//记录航点名称 + int gKey = 0;//航点名称数组下标 + int pKey = 0;//所有坐标序号 + Vector3[] pos = new Vector3[planesCou];//临时记录飞机坐标 + List re = new List();//返回值 + for (int i = 0; i < arr.Length; i++) + { + if (i % (planesCou + 1) == 0)//分析是否是航点名称 行 + { + flightPointNames[gKey] = arr[i];//记录航点名称 + gKey++; + } + else//否则 当坐标行处理 + { + string[] tempArr = arr[i].Split(' ');//每行坐标分割 + pos[pKey % planesCou] = new Vector3(Convert.ToDouble(tempArr[1]), Convert.ToDouble(tempArr[2]), Convert.ToDouble(tempArr[3])); + if (pKey % planesCou == planesCou - 1)//当一组组标循环完成 之后记录到返回组 + { + re.Add(pos); + pos = new Vector3[planesCou];//重新new一下 更新内存地址 + } + pKey++; + } + } + return re;//out flightPointNames 输出航点名称,re返回值 返回航点集合 + } + /// + /// svg航点坐标文档 转坐标集合 + /// + /// 文件路径 + /// 坐标集合 + public static Vector3[] SvgToPos(string path) + { + //读取文档内容 + string[] arr; + arr = ReadFile(path); + //获取飞机x轴 z轴 坐标 + ArrayList tempVec = new ArrayList();//记录飞机坐标 + string cx = @"cx=""(?\-{0,1}\d*\.{0,1}\d*)"""; + string cy = @"cy=""(?\-{0,1}\d*\.{0,1}\d*)"""; + string r = @"r=""(?\d*\.{0,1}\d*)"""; + foreach (string item in arr) + { + if (item.IndexOf("= 0)//找到svg里面标签 + { + Regex reg = new Regex(cx); + string strX = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 + reg = new Regex(cy); + string strZ = reg.Match(item).Groups["mark"].ToString();//正则匹配获取y轴 在三维里面用作z轴 + reg = new Regex(r); + string radius = reg.Match(item).Groups["mark"].ToString();//正则匹配获取球半径 + //按比例缩放(半径为100公分) 获取世界坐标 + double Rate = 100 / Convert.ToDouble(radius); + double x = Rate * Convert.ToDouble(strX); + double z = Rate * Convert.ToDouble(strZ) * -1; + tempVec.Add(new Vector3(x, 0, z)); + } + } + //坐标集原点相对位置 移到坐标集质心 + Vector3[] vec = FlyVecFun.ArrToVec(tempVec);//把arrlist转换成坐标集合 + Vector3 centerPos = FlyVecFun.GetPosCenter(vec);//获取中心点 + int key = 0; + foreach (Vector3 item in vec) + { + item.SetZero(centerPos); + vec[key] = item; + key++; + } + return vec;//返回坐标集合 + } + /// + /// obj航点坐标文档 转坐标集合 + /// + /// 文件路径 + /// 坐标集合 + public static Vector3[] ObjToPos(string path) + { + //读取文档内容 + string[] arr; + arr =ReadFile(path); + //获取飞机x轴 z轴 坐标 + string pCou = @"#\s+(?\d*)\s+vertices";//匹配obj里面标记点的数量 + string pPos = @"v\s+(?\-{0,1}\d*\.{0,1}\d*)\s+(?\-{0,1}\d*\.{0,1}\d*)\s+(?\-{0,1}\d*\.{0,1}\d*)"; + int linage = 0;//行数 + string tempPos;//临时记录一下 xyz坐标 + ArrayList tempVec = new ArrayList();//记录飞机坐标 + foreach (string item in arr) + { + Regex reg = new Regex(pCou); + string cou = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 + if (cou != "") + { + for (int i = Convert.ToInt32(cou); i > 0; i--) + { + tempPos = arr[linage - i]; + reg = new Regex(pPos); + string strX = reg.Match(tempPos).Groups["markX"].ToString(); + string strY = reg.Match(tempPos).Groups["markY"].ToString(); + string strZ = reg.Match(tempPos).Groups["markZ"].ToString(); + tempVec.Add(new Vector3(Convert.ToDouble(strX), Convert.ToDouble(strY), Convert.ToDouble(strZ))); + } + } + linage++; + } + //坐标集原点相对位置 移到坐标集质心 + Vector3[] vec = FlyVecFun.ArrToVec(tempVec);//把arrlist转换成坐标集合 + //重新定义中心点为原点 + //Vector3 centerPos = getPosCenter(vec);//获取中心点 + //int key = 0; + //foreach (Vector3 item in vec) + //{ + // item.setZero(centerPos); + // vec[key] = item; + // key++; + //} + return vec;//返回坐标集合 + } /// /// 资源管理器 文件类型 中文说明 和扩展名是 成对关系 数组长度要一致 /// diff --git a/FlieOperate/FlieOperate.csproj b/FlieOperate/FlieOperate.csproj index e509561..768baff 100644 --- a/FlieOperate/FlieOperate.csproj +++ b/FlieOperate/FlieOperate.csproj @@ -31,6 +31,9 @@ 4 + + ..\FlyCube\bin\Release\FlyBase.dll + ..\FlyCube\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll diff --git a/FlieOperate/Properties/AssemblyInfo.cs b/FlieOperate/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..62ce263 --- /dev/null +++ b/FlieOperate/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("FlieOperate")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FlieOperate")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("c354fd6b-5863-4246-bb48-6df14a85c161")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FlieOperate/packages.config b/FlieOperate/packages.config new file mode 100644 index 0000000..5eaa239 --- /dev/null +++ b/FlieOperate/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/FlyBase/FlyBase.cs b/FlyBase/FlyBase.cs index 1daffd4..8249903 100644 --- a/FlyBase/FlyBase.cs +++ b/FlyBase/FlyBase.cs @@ -1,20 +1,127 @@ -using System; +using Microsoft.SqlServer.Server; +using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.Http; +using System.Net.NetworkInformation; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Security.Policy; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Shapes; +using static System.Net.WebRequestMethods; namespace FlyBase { + //矩阵类 + 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坐标 @@ -149,6 +256,41 @@ namespace FlyBase return false; } /// + /// 确定指定的对象是否等于当前向量。 + /// + /// 要与当前向量比较的对象。 + /// 如果指定的对象等于当前向量,则为 true;否则为 false + public override bool Equals(object obj) + { + // 检查对象是否与当前向量具有相同的类型 + if (obj is Vector3 vector) + { + // 比较向量的每个分量 + 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; + } + /// /// 求模长 /// /// 向量到原点的模长 @@ -157,6 +299,14 @@ namespace FlyBase 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); + } + /// /// 标准化坐标 无返回值 直接改变愿坐标 /// /// 标准化单位 @@ -220,203 +370,43 @@ namespace FlyBase this.Z += v2.Z; } /// - /// 打印坐标 + /// 重写ToString 打印坐标 /// /// 坐标字符串 - public string PosToString() + 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 { - //逐行读取 文档 - private static string[] ReadFile(string path) - { - StreamReader sr = new StreamReader(path, Encoding.Default); - String line; - ArrayList arrlist = new ArrayList(); - while ((line = sr.ReadLine()) != null) - { - arrlist.Add(line); - } - if (arrlist.Count == 1)//判断 svg的文件内容 是否写在一行里面 - { - string temp = (string)arrlist[0]; - string[] strArray = Regex.Split(temp, "/>"); - return strArray; - } - string[] arr = new string[arrlist.Count]; - int key = 0; - foreach (var item in arrlist) - { - arr[key] = (string)item; - key++; - } - return arr; - } - //svg航点坐标文档 转坐标集合 PS:灯光映射 支持格式 - public static Vector3[] SvgToPosForLight(string path) - { - //读取文档内容 - string[] arr; - arr = FlyVecFun.ReadFile(path); - //获取飞机x轴 z轴 坐标 - ArrayList tempVec = new ArrayList();//记录飞机坐标 - string cx = @"cx=""(?\-{0,1}\d*\.{0,1}\d*)"""; - string cy = @"cy=""(?\-{0,1}\d*\.{0,1}\d*)"""; - string r = @"r=""(?\d*\.{0,1}\d*)"""; - foreach (string item in arr) - { - if (item.IndexOf("= 0)//找到svg里面标签 - { - Regex reg = new Regex(cx); - string strX = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 - reg = new Regex(cy); - string strZ = reg.Match(item).Groups["mark"].ToString();//正则匹配获取y轴 在三维里面用作z轴 - double x = Convert.ToDouble(strX); - double z = Convert.ToDouble(strZ); - tempVec.Add(new Vector3(x, 0, z)); - } - } - Vector3[] vec = ArrToVec(tempVec);//把arrlist转换成坐标集合 - return vec;//返回坐标集合 - } - //txt航点坐标文档 转坐标集合 PS:目前是C4D坐标文档 - public static List TxtToPos(string path, out string[] flightPointNames) - { - //读取文档内容 - string[] arr; - arr = FlyVecFun.ReadFile(path); - //处理文档内容 - int group = 0;//获取有几组坐标 - foreach (string item in arr) - { - if (item.IndexOf(" ") <= 0)//找到航点名称 - { - group++; - } - } - int planesCou = (arr.Length - group) / group;//获取飞机总数 - flightPointNames = new string[group];//记录航点名称 - int gKey = 0;//航点名称数组下标 - int pKey = 0;//所有坐标序号 - Vector3[] pos = new Vector3[planesCou];//临时记录飞机坐标 - List re = new List();//返回值 - for (int i = 0; i < arr.Length; i++) - { - if (i % (planesCou + 1) == 0)//分析是否是航点名称 行 - { - flightPointNames[gKey] = arr[i];//记录航点名称 - gKey++; - } - else//否则 当坐标行处理 - { - string[] tempArr = arr[i].Split(' ');//每行坐标分割 - pos[pKey % planesCou] = new Vector3(Convert.ToDouble(tempArr[1]), Convert.ToDouble(tempArr[2]), Convert.ToDouble(tempArr[3])); - if (pKey % planesCou == planesCou - 1)//当一组组标循环完成 之后记录到返回组 - { - re.Add(pos); - pos = new Vector3[planesCou];//重新new一下 更新内存地址 - } - pKey++; - } - } - return re;//out flightPointNames 输出航点名称,re返回值 返回航点集合 - } - //svg航点坐标文档 转坐标集合 - public static Vector3[] SvgToPos(string path) - { - //读取文档内容 - string[] arr; - arr = FlyVecFun.ReadFile(path); - //获取飞机x轴 z轴 坐标 - ArrayList tempVec = new ArrayList();//记录飞机坐标 - string cx = @"cx=""(?\-{0,1}\d*\.{0,1}\d*)"""; - string cy = @"cy=""(?\-{0,1}\d*\.{0,1}\d*)"""; - string r = @"r=""(?\d*\.{0,1}\d*)"""; - foreach (string item in arr) - { - if (item.IndexOf("= 0)//找到svg里面标签 - { - Regex reg = new Regex(cx); - string strX = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 - reg = new Regex(cy); - string strZ = reg.Match(item).Groups["mark"].ToString();//正则匹配获取y轴 在三维里面用作z轴 - reg = new Regex(r); - string radius = reg.Match(item).Groups["mark"].ToString();//正则匹配获取球半径 - //按比例缩放(半径为100公分) 获取世界坐标 - double Rate = 100 / Convert.ToDouble(radius); - double x = Rate * Convert.ToDouble(strX); - double z = Rate * Convert.ToDouble(strZ) * -1; - tempVec.Add(new Vector3(x, 0, z)); - } - } - //坐标集原点相对位置 移到坐标集质心 - Vector3[] vec = ArrToVec(tempVec);//把arrlist转换成坐标集合 - Vector3 centerPos = GetPosCenter(vec);//获取中心点 - int key = 0; - foreach (Vector3 item in vec) - { - item.SetZero(centerPos); - vec[key] = item; - key++; - } - return vec;//返回坐标集合 - } - //obj航点坐标文档 转坐标集合 - public static Vector3[] ObjToPos(string path) - { - //读取文档内容 - string[] arr; - arr = FlyVecFun.ReadFile(path); - //获取飞机x轴 z轴 坐标 - string pCou = @"#\s+(?\d*)\s+vertices";//匹配obj里面标记点的数量 - string pPos = @"v\s+(?\-{0,1}\d*\.{0,1}\d*)\s+(?\-{0,1}\d*\.{0,1}\d*)\s+(?\-{0,1}\d*\.{0,1}\d*)"; - int linage = 0;//行数 - string tempPos;//临时记录一下 xyz坐标 - ArrayList tempVec = new ArrayList();//记录飞机坐标 - foreach (string item in arr) - { - Regex reg = new Regex(pCou); - string cou = reg.Match(item).Groups["mark"].ToString();//正则匹配获取x轴 - if (cou != "") - { - for (int i = Convert.ToInt32(cou); i > 0; i--) - { - tempPos = arr[linage - i]; - reg = new Regex(pPos); - string strX = reg.Match(tempPos).Groups["markX"].ToString(); - string strY = reg.Match(tempPos).Groups["markY"].ToString(); - string strZ = reg.Match(tempPos).Groups["markZ"].ToString(); - tempVec.Add(new Vector3(Convert.ToDouble(strX), Convert.ToDouble(strY), Convert.ToDouble(strZ))); - } - } - linage++; - } - //坐标集原点相对位置 移到坐标集质心 - Vector3[] vec = ArrToVec(tempVec);//把arrlist转换成坐标集合 - //重新定义中心点为原点 - //Vector3 centerPos = getPosCenter(vec);//获取中心点 - //int key = 0; - //foreach (Vector3 item in vec) - //{ - // item.setZero(centerPos); - // vec[key] = item; - // key++; - //} - return vec;//返回坐标集合 - } + /// + /// 输出日志回调函数 + /// + /// 日志内容 + public delegate void SomeCalculateWay(string str); /// /// Arraylist 转 Vector3[] 坐标集 /// /// Arraylist 坐标集 /// Vector3[] 坐标集 - private static Vector3[] ArrToVec(ArrayList arr) + public static Vector3[] ArrToVec(ArrayList arr) { int cou = arr.Count; Vector3[] re = new Vector3[cou]; @@ -428,16 +418,86 @@ namespace FlyBase } return re; } - //数组最大值 最小值 + /// + /// 取数组最大 或者最小值 + /// + /// 数组 + /// true返回最大值 false返回最小值 + /// 根据参数返回 最大或者最小值 private static double GetMaxOrMin(double[] arr, bool isMax = true) { - ArrayList list = new ArrayList(arr); - list.Sort(); - if (isMax) return Convert.ToDouble(list[list.Count - 1]); - else return Convert.ToDouble(list[0]); - + 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 ArrayList TwoArrToArr(ArrayList twoArr) { ArrayList arr = new ArrayList(); @@ -450,7 +510,11 @@ namespace FlyBase } return arr; } - //重写 泛值List int[] + /// + /// 二维数组转一维数组 并去重 + /// + /// 二维数组 + /// 去重一维数组 private static List TwoArrToArr(List twoArr) { List arr = new List(); @@ -464,6 +528,159 @@ namespace FlyBase return arr; } /// + /// 处理二维数组 把有关联的子数组合并 例如:[[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>(); + 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) + { + 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); + result.Add(connected); + } + } + return result; + } + /// + /// 获取一组序列的所有排列方式 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) + { + 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[] aVecs, 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) + { + int newIndex = entry.Value; + new_bVecs[newIndex] = bVecs[entry.Key]; + } + 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 @@ -471,14 +688,34 @@ namespace FlyBase /// 两点之间距离 private static double GageLength(Vector3 v1, Vector3 v2) { - return Math.Sqrt(Math.Pow(v1.X - v2.X, 2) + Math.Pow(v1.Y - v2.Y, 2) + Math.Pow(v1.Z - v2.Z, 2)); + return Math.Sqrt(GageLengthSquare(v1, v2)); } - //点乘 用来求朝向 返回0到1之间 + /// + /// 两点距离的平方 + /// + /// 坐标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; @@ -487,10 +724,60 @@ namespace FlyBase return new Vector3(x, y, z); } /// + /// 检查4个点是否在一个平面上 + /// + /// 点1 + /// 点2 + /// 点3 + /// 点4 + /// 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; + } + /// + /// 判断4个点是否在同一条直线上 + /// + /// 点1 + /// 点2 + /// 点3 + /// 点4 + /// true在一条直线上 false不在一条直线上 + public 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); + Vector3 dir2 = new Vector3(vec3.X - vec2.X, vec3.Y - vec2.Y, vec3.Z - vec2.Z); + Vector3 dir3 = new Vector3(vec4.X - vec3.X, vec4.Y - vec3.Y, vec4.Z - vec3.Z); + + // 检查任意两个相邻方向向量的叉积是否为零 + // 这是在三维空间中判断共线的条件 + return CrossPro(dir1, dir2).IsZero() && CrossPro(dir2, dir3).IsZero(); + } + /// + /// 辅助方法,用于检查向量是否为零向量 + /// + /// 向量 + /// + private static bool IsZero(this Vector3 vector) + { + return vector.X == 0 && vector.Y == 0 && vector.Z == 0; + } + /// /// 坐标置换 向量乘以矩阵(i帽j帽k帽)得到置换后的向量坐标 ps:x指向i帽 y轴指向j帽 z轴指向k帽 /// /// 要变换的向量 - /// 矩阵标量 既i帽 j帽 k帽 三点的坐标组成的矩阵 + /// 矩阵标量 既i帽 j帽 k帽 三点的坐标组成的矩阵 “可以想象成臂长为1的操作轴图标” /// private static Vector3 MatrixMul(Vector3 vec, Vector3[] mat) { @@ -500,18 +787,25 @@ namespace FlyBase re.Z = vec.X * mat[0].Z + vec.Y * mat[1].Z + vec.Z * mat[2].Z; return re; } - //两条线段之间的最近距离 - private static bool IsEqual(double a, double b) + /// + /// 获取两条线段 的最近位置的距离和占比 + /// + /// 线段1起始点 + /// 线段1起终点 + /// 线段2起始点 + /// 线段2起终点 + /// [在线段1占比,在线段2占比,最近距离] + public static double RecentlySquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) { - if (Math.Abs(a - b) < 1e-7) + bool IsEqual(double x, double y) { - return true; + if (Math.Abs(x - y) < 1e-7) + { + return true; + } + return false; } - return false; - } - private static double[] RecentlyOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2) - { - if (a1 == a2) a2 += 1; + if (a1 == a2) a2 += 1;// 防止线段长度为0 if (b1 == b2) b2 += 1; double ux = a2.X - a1.X; double uy = a2.Y - a1.Y; @@ -582,17 +876,41 @@ namespace FlyBase double sc = 0.0; double tc = 0.0; if (IsEqual(sn, 0.0)) sc = 0.0; - else sc = sn / sd; + else sc = sn / sd;//最近点在第一条线占比 if (IsEqual(tn, 0.0)) tc = 0.0; - else tc = tn / td; + 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); - double[] re = new double[3]; - re[0] = sc;//最近点在第一条线占比 - re[1] = tc;//最近点在第二条线占比 - re[2] = Math.Sqrt(dx * dx + dy * dy + dz * dz);//两线最近距离 - return re; + return dx * dx + dy * dy + dz * dz;//两线最近距离的平方 + } + /// + /// 按比例在两条线段上截取对应点间的最小距离 平方 + /// + /// 线段1起始点 + /// 线段1起终点 + /// 线段2起始点 + /// 线段2起终点 + /// 最小距离的平方值 + public 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(); } /// /// 获取坐标集合的重心或中心 @@ -639,6 +957,50 @@ namespace FlyBase } } /// + /// 获取坐标集合的重心或中心 + /// + /// 坐标集合 + /// 默认返回为true重心 false则为中心 + /// 重心或中心坐标 + public 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); + } + } + /// /// 获取坐标集合 的总宽度 高度 长度 /// /// 坐标集合 @@ -655,462 +1017,558 @@ namespace FlyBase 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(); + re[0] = w.Max() - w.Min(); + re[1] = h.Max() - h.Min(); + re[2] = l.Max() - l.Min(); return re; } - /* - //从最外层AB规划路径 - private static void contactABOut(Vector3[] aPos, Vector3[] bPos,bool stressRefresh = true) + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// 航线最小间距平方值 + /// 飞行过程中最小间距平方值 + /// + public static List AirImitation(Vector3[] startPos, Vector3[] endPos, double lineDistanceSquare = 36100, double spaceBetweenSquare = 48400) { - if (!stressRefresh)//不刷新重心 初始化重心 + List planesCollision = new List(); //所有碰撞的组 + int planeCou = startPos.Length; //获取飞机总数 + for (int a = 0; a < planeCou; a++) { - Vector3[] abPos = new Vector3[aPos.Length + bPos.Length]; - aPos.CopyTo(abPos, 0); - bPos.CopyTo(abPos, aPos.Length); - Vector3 centerPos=getPosCenter(abPos);//重心 - } - while (aPos.Length != 0) - { - if (stressRefresh)//刷新重心 + for (int b = 0; a + 1 + b < planeCou; b++) { - Vector3[] abPos = new Vector3[aPos.Length + bPos.Length]; - aPos.CopyTo(abPos, 0); - bPos.CopyTo(abPos, aPos.Length); - Vector3 centerPos = getPosCenter(abPos);//重心 - } - - } - } - */ - //输出日志回调函数 - public delegate void SomeCalculateWay(string str); - //碰撞检测 - public static List AirImitation(Vector3[] startPos, Vector3[] endPos, double lineDistance = 180, double spaceBetween = 900, int checkFps = 10) - { - int cou = startPos.Length;//飞机总数 - //获取所有飞行时间 和航线距离 - double[] planesLen = new double[cou];//记录所有航线距离 - double[] planesFlyTime = new double[cou];//记录所有飞行时间 - for (int i = 0; i < cou; i++) - { - double len = GageLength(startPos[i], endPos[i]);//距离 - planesLen[i] = len; - double flyTime = len / 300;//时间 - planesFlyTime[i] = flyTime; - } - //选出航线有交叉的飞机 用于模拟飞行碰撞检测 - List needCheck = new List();//需要检查的飞机 二维数组 记录交叉组 - List distances = new List();//记录所有需要检查飞机 航线的最短距离 - for (int i = 0; i < cou; i++) - { - for (int x = 0; x < cou; x++) - { - if (i + 1 + x < cou) + //判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + if (distanceSquare < lineDistanceSquare) { - double distance = RecentlyOfLine(startPos[i], endPos[i], startPos[i + 1 + x], endPos[i + 1 + x])[2];//航线距离 - if (distance < lineDistance) + //判断飞机距离是否过近 + double planeLenSquare = MinDistanceSquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + if (planeLenSquare < spaceBetweenSquare) { - int[] z = new int[] { i, i + 1 + x }; - needCheck.Add(z); - distances.Add(distance); + planesCollision.Add(new int[] { a, a + 1 + b }); } } - else break; } } - //碰撞检测 - List planesCollision = new List();//记录碰撞组 - for (int i = 0; i < needCheck.Count; i++) - { - double zongTime; - int frist = (needCheck[i])[0];//第一架 - int second = (needCheck[i])[1];//第二架 - Vector3 fristFormerly = endPos[frist];//记第一架 终点原位 - Vector3 secondFormerly = endPos[second];//记第二架 终点原位 - //获取对比飞机 飞行时间较长的时间 - if (planesFlyTime[frist] >= planesFlyTime[second]) zongTime = planesFlyTime[frist] + 1;//最长飞行时间 多加1秒放bug - else zongTime = planesFlyTime[second] + 1;//最长飞行时间 多加1秒放bug - Convert.ToInt32(zongTime); - //以帧为单位计算 检测对比飞机之间距离 - for (int currentTime = 0; currentTime < zongTime * checkFps; currentTime++) - { - endPos[frist].SetZero(startPos[frist]);//归零 - endPos[frist].Normalize(300 / checkFps * currentTime);//当前时间飞行 标准化长度 坐标 - if (endPos[frist].GetMag() >= planesLen[frist]) endPos[frist] = fristFormerly;//溢出距离 当前坐标定义为终点位置 - else endPos[frist].SetFormerly(startPos[frist]);//归位 当前时间飞机坐标 - - endPos[second].SetZero(startPos[second]);//归零 - endPos[second].Normalize(300 / checkFps * currentTime);//当前时间飞行 标准化长度 坐标 - if (endPos[second].GetMag() >= planesLen[second]) endPos[second] = secondFormerly;//溢出距离 当前坐标定义为终点位置 - else endPos[second].SetFormerly(startPos[second]);//归位 当前时间飞机坐标 - - //判断距离 碰撞记录id - if (GageLength(endPos[frist], endPos[second]) < spaceBetween + 300 * ((double)distances[i] / lineDistance))//间距小于 基础间距+300*(航线实际距离/航线检测最小距离) 既:例基础间距+航线距离的反比 - { - endPos[frist] = fristFormerly;//第一架 终点回归原位 - endPos[second] = secondFormerly;//第二架 终点回归原位 - int[] z = new int[] { frist, second }; - planesCollision.Add(z); - break; - } - endPos[frist] = fristFormerly;//第一架 终点回归原位 - endPos[second] = secondFormerly;//第二架 终点回归原位 - } - } - return planesCollision;//返回二维数组 飞机ID从0开始 + return planesCollision; } - //单机碰撞检测 - public static bool OnlyImitation(int onlyPlaneId, Vector3[] startPos, Vector3[] endPos, double lineDistance = 180, double spaceBetween = 1200, int checkFps = 10)//飞机id从0开始 + /// + /// 碰撞检测 + /// + /// 始点坐标集合 + /// 终点坐标集合 + /// 航线最小间距平方值 + /// 飞行过程中最小间距平方值 + /// + public static List AirImitation(List startPos, List endPos, double lineDistanceSquare = 36100, double spaceBetweenSquare = 48400) + { + List planesCollision = new List(); //所有碰撞的组 + int planeCou = startPos.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]); + if (distanceSquare < lineDistanceSquare) + { + //判断飞机距离是否过近 + double planeLenSquare = MinDistanceSquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]); + if (planeLenSquare < spaceBetweenSquare) + { + planesCollision.Add(new int[] { a, a + 1 + b }); + } + } + } + } + return planesCollision; + } + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// 航线小距离的平方对比值 + /// 飞行过程中最小间距的平方对比值 + /// true:有碰撞 false:无碰撞 + public static bool OnlyImitation(int onlyPlaneId, Vector3[] startPos, Vector3[] endPos, double lineDistanceSquare = 32400, double spaceBetweenSquare = 90000) { - //指定飞机 起始坐标 终点坐标 飞行时间 - Vector3 onlyStartVec = startPos[onlyPlaneId]; - Vector3 onlyEndVec = endPos[onlyPlaneId]; - double onlyFlyTime = GageLength(onlyStartVec, onlyEndVec) / 300; //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 for (int contrastId = 0; contrastId < startPos.Length; contrastId++) { if (onlyPlaneId == contrastId) continue;//不和自己比较 - Vector3 StartVec = startPos[contrastId];//对比飞机起始坐标 - Vector3 EndVec = endPos[contrastId];//对比飞机结束坐标 // 判断两条轨迹 之间的最小距离 - double distance = RecentlyOfLine(onlyStartVec, onlyEndVec, StartVec, EndVec)[2];//航线最小距离 - if (distance < lineDistance) + double distanceSquare = RecentlySquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//航线最小距离 + if (distanceSquare < lineDistanceSquare) { - double flyTime = GageLength(EndVec, StartVec) / 300;//获取飞行总时间 - //指定飞机 和 当前比较飞机 以飞行时间长得为总时间 - int zongFlyTime;//声明 以航线较长的飞行时间 为总时长 - if (onlyFlyTime >= flyTime) zongFlyTime = (int)onlyFlyTime + 1;//总时间延长一到两秒 - else zongFlyTime = (int)flyTime + 1;//总时间延长一到两秒 - //碰撞检测 - for (int currentTime = 0; currentTime < zongFlyTime * checkFps; currentTime++) + double minDistanceSquare = MinDistanceSquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//按比例飞行最小间距 + if (minDistanceSquare < spaceBetweenSquare) { - //飞机当前坐标 - Vector3 onlyCurrentVec = onlyEndVec.SetZeroEd(onlyStartVec);//归零的 当前坐标 - onlyCurrentVec.Normalize(300 / checkFps * currentTime);//当前时间飞行 标准化长度 坐标 - if (onlyCurrentVec.GetMag() >= GageLength(onlyEndVec, onlyStartVec)) onlyCurrentVec = onlyEndVec;//溢出距离 当前坐标定义为终点位置 - else onlyCurrentVec.SetFormerly(onlyStartVec);//归位 当前时间飞机坐标 - - //要进行比较飞机 当前坐标 - Vector3 currentVec = EndVec.SetZeroEd(StartVec);//归零的 当前坐标 - currentVec.Normalize(300 / checkFps * currentTime);//当前时间飞行 标准化长度 坐标 - if (currentVec.GetMag() >= GageLength(EndVec, StartVec)) currentVec = EndVec;//溢出距离 当前坐标定义为终点位置 - else currentVec.SetFormerly(StartVec);//归位 当前时间飞机坐标 - - double planeLen = GageLength(onlyCurrentVec, currentVec);//获取检测飞机s 当前间距 - //间距小于 基础间距+800*(航线实际距离/航线检测最小距离) 既:例基础间距+航线距离的反比 - if (planeLen < spaceBetween + 300 * (distance / lineDistance)) - { - return true;//返回有碰撞 - } + return true;//返回有碰撞 } } } return false;//返回没有碰撞; } - //智能挫层 - public static ArrayList CollisionLayer(Vector3[] startPos, Vector3[] endPos, string axes = "y") + /// + /// 单机碰撞检测 + /// + /// 飞机的id PS:id从0开始 + /// 飞机起始坐标集合 + /// 飞机终点坐标集合 + /// 航线小距离的平方对比值 + /// 飞行过程中最小间距的平方对比值 + /// true:有碰撞 false:无碰撞 + public static bool OnlyImitation(int onlyPlaneId, List startPos, List endPos, double lineDistanceSquare = 32400, double spaceBetweenSquare = 90000) { - //获取所有碰撞飞机id - List planesCollisionInt = new List();//声明碰撞id组 - int key = 0; - foreach (var item in startPos)//遍历所有飞机 单体检测碰撞 + //选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测 + for (int contrastId = 0; contrastId < startPos.Count; contrastId++) { - if (OnlyImitation(key, startPos, endPos)) planesCollisionInt.Add(key);//如果碰撞 添加到碰撞id组 - key++; - } - //记录第一图案原位 - double defaultPos = startPos[0].Y; - //有碰撞飞机先拉开 - int k = 0; - foreach (int i in planesCollisionInt) - { - startPos[i].Y = startPos[i].Y + 9400 + k * 300; - k++; - } - //中间航点挫层 - foreach (int i in planesCollisionInt) - { - int shiftCou = 0;//记录循环次数 - while (true) + if (onlyPlaneId == contrastId) continue;//不和自己比较 + // 判断两条轨迹 之间的最小距离 + double distanceSquare = RecentlySquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//航线最小距离 + if (distanceSquare < lineDistanceSquare) { + double minDistanceSquare = MinDistanceSquareOfLine(startPos[onlyPlaneId], endPos[onlyPlaneId], startPos[contrastId], endPos[contrastId]);//按比例飞行最小间距 + if (minDistanceSquare < spaceBetweenSquare) + { + return true;//返回有碰撞 + } + } + } + return false;//返回没有碰撞; + } + /// + /// 智能路径 规则:找ab组共同最外圈的点 然后对应找a或b里面最近点 为一组匹配 最后进行碰撞交叉互换 + /// + /// 起始点坐标组 + /// 目标点坐标组 + /// 交换次数 + /// + public static Vector3[] ContactABOut(Vector3[] aVecs, Vector3[] bVecs, int swapCount = 5) + { + 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集合最近点 的下标 + { + //MessageBox.Show(aIndex[aMaxIndex].ToString()); + 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(aVecs, bVecs, match);// 按照映射 获取a 对应的 新的b集合 + 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]] + // 遍历所有交叉组 分组做交换 + foreach (List swap_indices in formatCollision) + { + if (swap_indices.Count <= 6) // 只尝试5组交叉碰撞以下的航线互换 + { + //交叉 生成所有排列 + List> all_permutations = Permutations(swap_indices); + //删掉第一个 既原始排列 + all_permutations.RemoveAt(0); + // 按所有的排列 互换航线 并检测出最佳的对应目标点 + List tempLen = new List(); //记录所有排列的 的碰撞次数 + List tempNew_bVecsS = new List();//记录所有排列交换之后的目标坐标集 + foreach (List indices in all_permutations) + { + Vector3[] current_array = new_bVecs.ToArray();//复制一个new_bVecs 副本 + for (int k = 0; k < indices.Count - 1; k++) + { + int index1 = indices[k]; + int index2 = indices[k + 1]; + // 交换元素 + Vector3 temp = current_array[index1]; + current_array[index1] = current_array[index2]; + current_array[index2] = temp; + } + tempLen.Add(AirImitation(aVecs, current_array).Count);// 迭代 记录所有排列的碰撞次数 + tempNew_bVecsS.Add(current_array); //迭代 记录所有排列交换之后的目标坐标集 + } + new_bVecs = tempNew_bVecsS[GetRandomMinIndex(tempLen)]; + } + } + } + return new_bVecs; + } + /// + /// 智能挫层 + /// + /// 起始坐标集合 + /// 终点做标集合 + /// 挫层层高 + /// 返回一个二维向量坐标集合 middle[0]是第一个中间航点 middle[1]是第二个中间航点 返回空数组则代表两个图形不在一个平面上或者不够4个点 + public static List CollisionLayer(Vector3[] startPos, Vector3[] endPos, 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)//两个图形不够四个点 返回 空数组 + { + return re; + } + // 使用 foreach 遍历 List 中的元素 + foreach (Vector3[] pppVec in ppppVecArr) + { + if (!(IsVecsOnPlane(pppVec[0], pppVec[1], pppVec[2], pppVec[3]))) + { + return re;//两个图形不在一个平面上 返回 空数组 + } + + } + //遍历选出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); + for (int i = 0; i < planeCou; i++) //遍历所有点 找出不在一条直线上的四个点 + { + vec0 = startPos[i]; vec1 = endPos[planeCou - i - 1]; vec2 = startPos[planeCou - i - 1]; vec3 = endPos[i]; + isVecsOnLine = IsVecsOnLine(vec0, vec1, vec2, vec3); + if (isVecsOnLine) + { + break; + } + } + if (isVecsOnLine) + { + return re;//两个图案的所有点都在一条直线上 返回 空数组 + } + //检查完毕后 + //计算法线向量 + Vector3 side1 = vec0 - vec1; + Vector3 side2 = vec2 - vec3; + Vector3 normal = CrossPro(side1, side2); + Vector3 normalScalar = normal.NormalizEd();//法线标量 + //开始挫层 + for (int i = 0; i < planeCou; i++) + { + int shiftCou = 1; //记录循环次数 即层数 + Vector3 aOrigin = startPos[i]; //原点位置 + Vector3 bOrigin = endPos[i]; //原点位置 + while (OnlyImitation(i, startPos, endPos)) + { + Vector3 shiftVec = normalScalar * ((shiftCou + 1) / 2 * layHight); if (shiftCou % 2 == 1) { - startPos[i].Y = defaultPos + (shiftCou + 1) / 2 * 350; - endPos[i].Y = defaultPos + (shiftCou + 1) / 2 * 350; + startPos[i] = aOrigin + shiftVec; + endPos[i] = bOrigin + shiftVec; } else { - startPos[i].Y = defaultPos + shiftCou / 2 * -350; - endPos[i].Y = defaultPos + shiftCou / 2 * -350; + startPos[i] = aOrigin - shiftVec; + endPos[i] = bOrigin - shiftVec; } - if (!(OnlyImitation(i, startPos, endPos))) break;//如果 不碰撞跳出 - shiftCou++; + shiftCou += 1; } } - ArrayList middle = new ArrayList(); - middle.Add(startPos); - middle.Add(endPos); - return middle;//返回一个二维向量数组 middle[0]是第一个中间航点 middle[1]是第二个中间航点 - } - //添加中间航点 群组 - private static Vector3[] SetMiddleCurvedValue(Vector3[] startPos, Vector3[] endPos, double middlePos = 0.5, double scale = 1) - { - int cou = startPos.Length;//飞机总数 - Vector3[] mps = new Vector3[cou]; - //算中间航点 - for (int i = 0; i < cou; i++) - { - Vector3 ap = startPos[i]; - Vector3 bp = endPos[i]; - mps[i] = (bp - ap) * middlePos + ap; - } - Vector3 centerPos = GetPosCenter(mps);//计算所有中间航点的重心点 - //中间航点缩放 - for (int i = 0; i < cou; i++) - { - mps[i] = (mps[i] - centerPos) * scale + centerPos + .1; - } - return mps; - } - //添加中间航点 单体 - private static Vector3 SetOddMiddleCurvedValue(Vector3 startPos, Vector3 endPos, double middlePos = 0.5) - { - //算中间航点 - Vector3 mp = (endPos - startPos) * middlePos + startPos + .1; - return mp; - } - //3D绕行与让行 ps:起点s 中点s 终点s 需要检查的ID组 绕行比例 每个比例的绕行次数 绕行的法线偏移距离 - private static Vector3[] ABypassB(Vector3[] startPos, Vector3[] middlePos, Vector3[] endPos, List check, double[] mRate, int loopIndex = 800, double offsetDistance = 60)//法线螺旋线绕行 - { - Console.WriteLine("check:{0}", check.Count); - bool pa; - //设置绕行 - foreach (int id in check) - { - pa = false; - Vector3 initialPos = middlePos[id];//记录初始位置 如果绕行不成功 还原位置 - for (int k = 0; k < mRate.Length; k++) - { - //初始化位置 - middlePos[id] = SetOddMiddleCurvedValue(startPos[id], endPos[id], mRate[k]); - //碰撞绕行 - for (int i = 0; i < loopIndex; i++) - { - if (i != 0)//第一次保证原位置 ps:先不移动位置 检测一次 移动其他飞机之后 可能让本架飞机不碰撞 - { - //获取法线向量 - Vector3 a = startPos[id]; - Vector3 b = endPos[id]; - Vector3 c = middlePos[id]; - Vector3 mp = FlyVecFun.CrossPro(a - c, b - c);//乘差算 坐标原点上面的法线 方向向量 - if (k % 2 == 0) mp.Normalize(offsetDistance);//正螺旋 - else mp.Normalize(offsetDistance * -1);//逆螺旋 - middlePos[id] = mp + c; - } - //碰撞检测 - if (OnlyImitation(id, startPos, middlePos)) continue;//前半段检测 - if (OnlyImitation(id, middlePos, endPos)) continue;//后半段检测 - pa = true; - break; - } - if (pa) break; - } - if (!pa) middlePos[id] = initialPos;//让行不成功 位置还原 - } - return middlePos; - } - private static List ThreeStageABypassB(Vector3[] startPos, Vector3[] fMiddlePos, Vector3[] middlePos, Vector3[] bMiddlePos, Vector3[] endPos, List check, double[] mRate)//三段绕 - { - //初始化 - double[] fmRate = { 0 }; - double[] bmRate = { 1 }; - //二段绕行 - foreach (int id in check) - { - bool pa = false; - Vector3 initialPos = middlePos[id];//记录初始位置 如果绕行不成功 还原位置 - for (int k = 0; k < mRate.Length; k++) - { - - //初始化位置 - middlePos[id] = SetOddMiddleCurvedValue(startPos[id], endPos[id], mRate[k]); - //二段碰撞绕行 - for (int i = 0; i < 800; i++) - { - if (i != 0)//第一次保证原位置 ps:先不移动位置 检测一次 移动其他飞机之后 可能让本架飞机不碰撞 - { - //获取法线向量 - Vector3 a = startPos[id]; - Vector3 b = endPos[id]; - Vector3 c = middlePos[id]; - Vector3 mp = FlyVecFun.CrossPro(a - c, b - c);//乘差算 坐标原点上面的法线 方向 - mp.Normalize(60); - middlePos[id] = mp + c; - } - //绕一段 和 三段 - Vector3[] tempFMiddlePos;//临时存放 一段 - Vector3[] tempBMiddlePos;//临时存放 三段 - List xId = new List();//临时存放当前id 用于绕行方法 - xId.Add(id); - if (OnlyImitation(id, startPos, middlePos) || OnlyImitation(id, middlePos, endPos))//因为二段改变位置 检测直接二段绕行 是否通过 - { - tempFMiddlePos = FlyVecFun.ABypassB(startPos, fMiddlePos, middlePos, xId, fmRate, 45, 90);//一段绕行 - if (OnlyImitation(id, startPos, tempFMiddlePos)) continue;//检测一段 前 重新循环二段 - else if (OnlyImitation(id, tempFMiddlePos, middlePos)) continue;//检测一段 后 重新循环二段 - - tempBMiddlePos = FlyVecFun.ABypassB(middlePos, bMiddlePos, endPos, xId, bmRate, 45, 90);//三段绕行 - if (OnlyImitation(id, startPos, tempBMiddlePos)) continue;//检测三段 前 重新循环二段 - else if (OnlyImitation(id, fMiddlePos, middlePos)) continue;//检测三段 后 重新循环二段 - - fMiddlePos = tempFMiddlePos;//如果通过 更新一段坐标 - bMiddlePos = tempBMiddlePos;//如果通过 更新三段坐标 - } - pa = true; - break;//跳出 - } - if (pa) break; - } - if (!pa) middlePos[id] = initialPos;//绕行不成功 位置还原 - } - List re = new List(); - re.Add(fMiddlePos); - re.Add(middlePos); - re.Add(bMiddlePos); + re.Add(startPos); + re.Add(endPos); return re; } - private static List ABNeedCheck(Vector3[] startPos, Vector3[] middlePos, Vector3[] endPos)//前航点到中间航点 中间航点到终点 所有碰撞飞机id + /// + /// 路径绕行 + /// + /// 起始坐标集合 + /// 终点做标集合 + /// 返回一个二维数组 长度为1即1个中间航点 长度为3即前中后三个中间航点 + public static List> ABypassB(Vector3[] aVecs, Vector3[] bVecs) { - List re = new List(); - //获取从起点到中点再到结束点 所有碰撞飞机 - int key = 0; - foreach (var item in startPos) + List> re = new List>(); + int planeCou = aVecs.Length; + //第一次绕行 + //起始坐标组重心点 与 目标坐标组重心点 + Vector3 aCenterPoint = GetPosCenter(aVecs); + Vector3 bCenterPoint = GetPosCenter(bVecs); + //记录所有航线中心距 ps:起点离起点组中心点距离 + 目标点离目标点组中心点距离 + double[] centerDistanceS = new double[planeCou]; + for (int i = 0; i < planeCou; i++) { - if (OnlyImitation(key, startPos, middlePos) || OnlyImitation(key, middlePos, endPos)) re.Add(key);//记录 起点到中点 或者 中点到终点有碰撞的飞机 - key++; + centerDistanceS[i] = GageLengthSquare(aVecs[i], aCenterPoint) + GageLengthSquare(bVecs[i], bCenterPoint); } + //记录从中心开始排序 + int[] sortedIndices = Enumerable.Range(0, centerDistanceS.Length).ToArray(); + Array.Sort(sortedIndices, (x, y) => centerDistanceS[x].CompareTo(centerDistanceS[y]));// 对索引数组按原始数组的值进行排序 + //从中心航线 逐条绕行 ps:映射从中心内部到此到外部顺序 + List tempAVecs = new List(); // 逐条起点坐标组 + List tempBVecs = new List(); // 逐条目标点坐标组 + List middleVecs = new List(); //中心航点坐标组 + List firstCollisionGroup = new List(); //有碰撞飞机列表(第一次绕行) + for (int i = 0; i < planeCou; i++) + { + 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])); //添加中间航点 + } + else //从第二条开始绕 + { + middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); // 添加默认中间航点 + // 首次默认中间航点检测 + if (!(OnlyImitation(i, tempAVecs, middleVecs))) //前半段碰 碰撞检测 + { + if (!(OnlyImitation(i, middleVecs, tempBVecs))) //后半段碰 碰撞检测 + { + isPassMark = true; //中间航点 + continue; //不撞则跳出 进行下一航线的绕行 + } + else + { + middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 + } + } + else + { + middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 + } + // 绕行列表遍历 检测 + List ringVecs = GetRingVec(aVecs[index], bVecs[index], 0.5); //所有可绕行的中间航点集合 + foreach (Vector3 v in ringVecs) + { + middleVecs.Add(v); + //检测 + if (!(OnlyImitation(i, tempAVecs, middleVecs))) //前半段碰 碰撞检测 + { + if (!(OnlyImitation(i, middleVecs, tempBVecs))) //后半段碰 碰撞检测 + { + isPassMark = true; //中间航点 碰撞检测通过标记 + break; //不撞则跳出 进行下一航线的绕行 + } + else + { + middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 + } + } + else + { + middleVecs.RemoveAt(i); //碰撞检测未通过删除临时中间航点 + } + } + } + if (!(isPassMark)) // 如果绕行失败 添加一个默认中间航点 + { + middleVecs.Add(SetMiddleVec(aVecs[index], bVecs[index])); + firstCollisionGroup.Add(index); + } + } + //中间航点坐标集 按飞机id顺序重新映射 ps:恢复原id映射 + middleVecs = sortedIndices.Select(index => middleVecs[index]).ToList(); + //没有碰撞 返回一个中间航点 并返回 + if (firstCollisionGroup.Count == 0) + { + re.Add(middleVecs); + return re; + } + + //第二次绕行 ps:有碰撞进行第二次 前后再各加以航点 嵌套迭代 + List firstMiddleVecs = new List(); //前中间航点 + List secondMiddleVecs = new List(); //后中间航点 + List secondCollisionGroup = new List(); //最终有碰撞飞机列表 + for (int i = 0; i < planeCou; i++) + { + firstMiddleVecs.Add(SetMiddleVec(aVecs[i], middleVecs[i], 0)); + secondMiddleVecs.Add(SetMiddleVec(middleVecs[i], bVecs[i], 1)); + } + foreach (int index in firstCollisionGroup) + { + bool isPassMark = false; + // 正中 绕行列表 + List ringVecs = GetRingVec(aVecs[index], bVecs[index], 0.5); //所有可绕行的中间航点集合 + foreach (Vector3 r in ringVecs) + { + middleVecs[index] = r; //中点逐点 + List firstRingVecs = GetRingVec(aVecs[index], middleVecs[index], 0, 220, 6); //所有可绕行的 前中间航点集合 + foreach (Vector3 fr in firstRingVecs) + { + firstMiddleVecs[index] = fr; //前中点逐点 + List secondRingVecs = GetRingVec(middleVecs[index], bVecs[index], 1, 220, 6); //所有可绕行的 后中间航点集合 + foreach (Vector3 sr in secondRingVecs) + { + secondMiddleVecs[index] = sr; //后中点逐点 + // 检测 + if (!(OnlyImitation(index, aVecs, firstMiddleVecs))){ + } + //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 #不撞则跳出 进行下一航线的绕行 + } + } + } + } + return re; } - public static List ExeABypassB(Vector3[] startPos, Vector3[] endPos, out bool isSuccess, SomeCalculateWay strPrint)//绕行获取中间航点 + /// + /// 在圆圈上 用固定弦长手拉手 分割点 + /// + /// 大圆半径 + /// 固定弦长 ps:这个值决定绕行点一圈的密集成都值越小越密集 + /// + public static List GetVecsOnCircle(double radius, double chordLength = 220) { - isSuccess = false; - List middlePosS = new List();//声明返回坐标集合 可能是1 到 3组坐标 既 1到3个中间航点 - List check = new List();//记录需要绕行的id组 - List checkEd = new List();//复查绕行未通过的id组 - //中段绕行 初始化 - double[] mRate = { .5, .6, .4, .7, .3 };//中点绕行的比例 - Vector3[] middlePos = SetMiddleCurvedValue(startPos, endPos, 0.5, 1);//加中间航点 - bool pa = false; - strPrint("中(二)段绕行开始"); - while (true)//中段绕行循环 + 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++) { - //前中后所有碰撞的飞机id - check = ABNeedCheck(startPos, middlePos, endPos); - //绕行 - if (check.Count != 0)//有碰撞 - { - middlePos = ABypassB(startPos, middlePos, endPos, check, mRate); - } - //重新检查碰撞 - checkEd = ABNeedCheck(startPos, middlePos, endPos); - if (checkEd.Count == 0)//如果绕行没有碰撞 - { - strPrint("成功"); - middlePosS.Add(middlePos);//添加中间坐标组 - isSuccess = true; - return middlePosS;//第一次绕行 没有碰撞 直接返回 - } - if (check.SequenceEqual(checkEd)) - { - if (pa)//判定第二次 check 和 checkEd一致 - { - strPrint("一致跳出");//如果一个中间航点 算不过去 跳出然后 进行三段绕行 - break;//连续两次check 和 checkEd一致 跳出 - } - pa = true; - } - else pa = false; + double angle = i * angleIncrement; + double x = radius * (double)Math.Cos(angle); + double y = radius * (double)Math.Sin(angle); + double z = 0.0f; // 如果是在平面上,Z 可能是 0 + vecs.Add(new Vector3(x, y, z)); } - //一段绕行初始化 - Vector3[] fMiddlePos = SetMiddleCurvedValue(startPos, middlePos, 0, 1); - double[] fmRate = { 0, .05, .1, .15, .2 };//中点绕行的比例 - pa = false; - check = ABNeedCheck(startPos, fMiddlePos, middlePos); - if (check.Count != 0)//检测是否进行一段循环 + return vecs; + } + /// + /// 获取a指向b的向量矩阵 ps:偏移次数 加1 会在终点前后往返偏移 + /// + /// a向量 + /// b向量 + /// 默认中点位置比例 + /// 偏移次数 从0开始,每+1在中点前后往返偏移 + /// 偏移层高 + /// 矩阵 + public static Matrix GetBasisMatrix(Vector3 aVec, Vector3 bVec, double middleProportion = 0.5, int offCount = 0, double layHight = 220) + { + // 计算前向向量 k帽 + Vector3 k_hat = (bVec - aVec).NormalizEd(); + // 计算右向量,使用 Vector3.UnitY 作为上向量 i帽 + Vector3 i_hat = CrossPro(Vector3.UnitY, k_hat).NormalizEd(); + // 计算上向量 j帽 + Vector3 j_hat = CrossPro(k_hat, i_hat); + //计算 对应的偏移比例 + double length = (bVec - aVec).GetMag(); + double offShift;//偏移比例 + if (offCount % 2 == 1) //奇数 + offShift = middleProportion + (offCount + 2) / 2 * layHight / length; + else //偶数 + offShift = middleProportion - (offCount + 1) / 2 * layHight / length; + // 计算偏向量 + Vector3 off = aVec + (bVec - aVec) * offShift; + // 构建矩阵 + Matrix matrix = new Matrix { - strPrint("一段绕行开始"); - while (true)//一段绕行 循环体 + 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:绕行中间航点肚子(值越大肚子越小) + /// + public static List GetRingVec(Vector3 aVec, Vector3 bVec, double middleProportion, double transfer = 220, double paunch = 3) + { + List ringVec = new List(); //记录所有绕行中间航点坐标 + // 根据a到b的长度 算出中间绕行几圈 + int ringCou = (int)Math.Ceiling(GageLength(aVec, bVec) / paunch / transfer); //绝对中心绕行的圈数 即中间航点的'肚子'大小 + if (ringCou < 2) ringCou = 2; //最少两圈 两层 + if (ringCou > 15) ringCou = 15; //最多15圈 15层 + for (int z = 0; z < ringCou; z++) //迭代层 + { + Matrix mat = GetBasisMatrix(aVec, bVec, middleProportion, z, transfer); //根据圈数越多 偏移层数也越多 即每层矩阵off位置 + for (int i = 0; i < ringCou; i++) //迭代圈 { - //前中后所有碰撞的飞机id - check = ABNeedCheck(startPos, fMiddlePos, middlePos); - if (check.Count != 0) fMiddlePos = ABypassB(startPos, fMiddlePos, middlePos, check, fmRate, 1500, 15);//有碰撞 绕行 - else//没有碰撞 添加返回值并跳出 一段绕行 循环 + if (i != 0) { - strPrint("成功"); - isSuccess = true; - middlePosS.Add(fMiddlePos);//添加一段 绕行结果 - break; - } - //重新检查碰撞 - checkEd = ABNeedCheck(startPos, fMiddlePos, middlePos); - //多次绕行 结果相同 则判定未能成功通过 但是也会添加 绕行结果 - if (check.SequenceEqual(checkEd))//如果两次 碰撞检测结果完全相同 - { - if (pa)//判定第二次 check 和 checkEd一致 + List tempCi = GetVecsOnCircle(i * transfer, transfer); + foreach (Vector3 vec in tempCi) { - strPrint("一致跳出");//如果一个中间航点 算不过去 跳出然后 进行三段绕行 - isSuccess = false; - middlePosS.Add(fMiddlePos);//添加一段 绕行结果 - break;//连续两次check 和 checkEd一致 跳出 + ringVec.Add(vec.Multiply(mat));//按照矩阵旋转之后 添加到中间航点列表 } - pa = true; } - else pa = false; + else + { + ringVec.Add(mat[3]); //第一次循环 并非圈 只在航线上 按层比例取点 即可 + } } } - //添加中段绕行结果 - middlePosS.Add(middlePos); - //三段绕行初始化 - Vector3[] bMiddlePos = SetMiddleCurvedValue(middlePos, endPos, 1, 1); - double[] bmRate = { 1, .95, 0.9, .85, .8 };//中点绕行的比例 - pa = false; - check = ABNeedCheck(middlePos, bMiddlePos, endPos); - if (check.Count != 0)//检测是否进行三段循环 - { - strPrint("三段绕行开始"); - while (true)//一段绕行 循环体 - { - //前中后所有碰撞的飞机id - check = ABNeedCheck(middlePos, bMiddlePos, endPos); - if (check.Count != 0) bMiddlePos = ABypassB(middlePos, bMiddlePos, endPos, check, bmRate, 1500, 15);//有碰撞 绕行 - else//没有碰撞 添加返回值并跳出 三段绕行 循环 - { - strPrint("成功"); - isSuccess = true; - middlePosS.Add(bMiddlePos);//添加三段 绕行结果 - break; - } - //重新检查碰撞 - checkEd = ABNeedCheck(middlePos, bMiddlePos, endPos); - //多次绕行 结果相同 则判定未能成功通过 但是也会添加 绕行结果 - if (check.SequenceEqual(checkEd))//如果两次 碰撞检测结果完全相同 - { - if (pa)//判定第二次 check 和 checkEd一致 - { - strPrint("一致跳出");//如果一个中间航点 算不过去 跳出然后 进行三段绕行 - isSuccess = false; - middlePosS.Add(bMiddlePos);//添加三段 绕行结果 - break;//连续两次check 和 checkEd一致 跳出 - } - pa = true; - } - else pa = false; - } - } - //三段绕行未果 进行三点同时绕行 - - return middlePosS; + return ringVec; } } } \ No newline at end of file diff --git a/FlyBase/FlyBase.csproj b/FlyBase/FlyBase.csproj new file mode 100644 index 0000000..a87500d --- /dev/null +++ b/FlyBase/FlyBase.csproj @@ -0,0 +1,49 @@ + + + + + Debug + AnyCPU + {626A9BFA-07DE-4063-A178-360EB7057ED6} + Library + Properties + FlyBase + FlyBase + v4.7.2 + 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/FlyBase/Properties/AssemblyInfo.cs b/FlyBase/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..331cefd --- /dev/null +++ b/FlyBase/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/FlyBase/Vector3.cs b/FlyBase/Vector3.cs new file mode 100644 index 0000000..407a1ca --- /dev/null +++ b/FlyBase/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/FlyCube/App.config b/FlyCube/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/FlyCube/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/FlyCube/App.xaml b/FlyCube/App.xaml new file mode 100644 index 0000000..827d759 --- /dev/null +++ b/FlyCube/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/FlyCube/App.xaml.cs b/FlyCube/App.xaml.cs new file mode 100644 index 0000000..478bbaf --- /dev/null +++ b/FlyCube/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace FlyCube +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + } +} diff --git a/FlyCube/FlyCube.csproj b/FlyCube/FlyCube.csproj new file mode 100644 index 0000000..9dbef46 --- /dev/null +++ b/FlyCube/FlyCube.csproj @@ -0,0 +1,122 @@ + + + + + Debug + AnyCPU + {B36F850B-75B9-42C9-9C48-88141AB6D4B1} + WinExe + FlyCube + FlyCube + v4.7.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + 4.0 + + + + + + packages\WpfAnimatedGif.2.0.2\lib\net40\WpfAnimatedGif.dll + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + AxisControl.xaml + + + MainWindow.xaml + Code + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {c354fd6b-5863-4246-bb48-6df14a85c161} + FlieOperate + + + {626a9bfa-07de-4063-a178-360eb7057ed6} + FlyBase + + + + + \ No newline at end of file diff --git a/FlyCube/FlyCube.sln b/FlyCube/FlyCube.sln new file mode 100644 index 0000000..cda8c92 --- /dev/null +++ b/FlyCube/FlyCube.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34018.315 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlyCube", "FlyCube.csproj", "{B36F850B-75B9-42C9-9C48-88141AB6D4B1}" +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 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B36F850B-75B9-42C9-9C48-88141AB6D4B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B36F850B-75B9-42C9-9C48-88141AB6D4B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B36F850B-75B9-42C9-9C48-88141AB6D4B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B36F850B-75B9-42C9-9C48-88141AB6D4B1}.Release|Any CPU.Build.0 = Release|Any CPU + {626A9BFA-07DE-4063-A178-360EB7057ED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {626A9BFA-07DE-4063-A178-360EB7057ED6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {626A9BFA-07DE-4063-A178-360EB7057ED6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {626A9BFA-07DE-4063-A178-360EB7057ED6}.Release|Any CPU.Build.0 = Release|Any CPU + {C354FD6B-5863-4246-BB48-6DF14A85C161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C354FD6B-5863-4246-BB48-6DF14A85C161}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C354FD6B-5863-4246-BB48-6DF14A85C161}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C354FD6B-5863-4246-BB48-6DF14A85C161}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AEC8BEB7-E150-46F0-829B-4B0984B4B59B} + EndGlobalSection +EndGlobal diff --git a/FlyCube/MainWindow.xaml b/FlyCube/MainWindow.xaml index 9b60084..eec7bd5 100644 --- a/FlyCube/MainWindow.xaml +++ b/FlyCube/MainWindow.xaml @@ -21,6 +21,7 @@ public string ImagePath { get; set; } - public MainWindow() - { - InitializeComponent(); - //创建一个 主画布对象 - TopCanvas = new MainCanvas(this.LayerPlane); - - } /// /// 导入航点 /// @@ -97,7 +162,6 @@ namespace FlyCube PlaneVecOnCanvas[planeId] = v; planeId++; } - } /// /// 输出航点 @@ -132,8 +196,11 @@ namespace FlyCube } } - - + /// + /// 渲染输出航点 + /// + /// + /// private void Render_Click(object sender, RoutedEventArgs e) { ImageUtility img = new ImageUtility(this.ImagePath); @@ -141,7 +208,7 @@ namespace FlyCube foreach (Vector3 item in PlaneVecOnCanvas) { List ledInfos = new List(); - Color[] colors = img.GetColorsForGifPos((int)item.X, (int)item.Y); + Color[] colors = img.GetColorsForGifPos((int)item.X, (int)item.Z); string c = ""; foreach (var color in colors) { @@ -150,20 +217,20 @@ namespace FlyCube //添加灯光信息 LedInfos led = new LedInfos(); led.Delay = 0.1; - led.LEDMode = 0; + led.LEDMode = (int)LightClass.常亮; led.LEDInterval = 0.0; led.LEDRate = 0; led.LEDTimes = 0; led.LEDRGB = color.ToString().Remove(0, 3); ledInfos.Add(led); - //记录这一帧颜色 用于下次循环和 这一帧进行对比 + //记录这一帧颜色 用于下次循环时和 这一帧进行对比 c = color.ToString().Remove(0, 3); } else//如果和上一帧颜色一样 则不进行Add 并把上一帧的 灯光延时自加0.1秒 { - ledInfos[ledInfos.Count-1].Delay += 0.1; + ledInfos[ledInfos.Count - 1].Delay += 0.1; } - + } this.FcgmInfo.tasks[2].singleCopterInfos[id].ledInfos = ledInfos; id++; @@ -171,7 +238,7 @@ namespace FlyCube MessageBox.Show("成功"); } - + } /// /// 灯光 组 diff --git a/FlyCube/Properties/AssemblyInfo.cs b/FlyCube/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c80e3ce --- /dev/null +++ b/FlyCube/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("FlyCube")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FlyCube")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +//若要开始生成可本地化的应用程序,请设置 +//.csproj 文件中的 CultureYouAreCodingWith +//例如,如果您在源文件中使用的是美国英语, +//使用的是美国英语,请将 设置为 en-US。 然后取消 +//对以下 NeutralResourceLanguage 特性的注释。 更新 +//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //主题特定资源词典所处位置 + //(未在页面中找到资源时使用, + //或应用程序资源字典中找到时使用) + ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 + //(未在页面中找到资源时使用, + //、应用程序或任何主题专用资源字典中找到时使用) +)] + + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FlyCube/Properties/Resources.Designer.cs b/FlyCube/Properties/Resources.Designer.cs new file mode 100644 index 0000000..4029942 --- /dev/null +++ b/FlyCube/Properties/Resources.Designer.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本: 4.0.30319.42000 +// +// 对此文件的更改可能导致不正确的行为,如果 +// 重新生成代码,则所做更改将丢失。 +// +//------------------------------------------------------------------------------ + + +namespace FlyCube.Properties +{ + /// + /// 强类型资源类,用于查找本地化字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// 返回此类使用的缓存 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FlyCube.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/FlyCube/Properties/Resources.resx b/FlyCube/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/FlyCube/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FlyCube/Properties/Settings.Designer.cs b/FlyCube/Properties/Settings.Designer.cs new file mode 100644 index 0000000..f74ee18 --- /dev/null +++ b/FlyCube/Properties/Settings.Designer.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +namespace FlyCube.Properties +{ + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/FlyCube/Properties/Settings.settings b/FlyCube/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/FlyCube/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/FlyCube/packages.config b/FlyCube/packages.config new file mode 100644 index 0000000..8fc7f38 --- /dev/null +++ b/FlyCube/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file