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坐标
/// 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 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;
}
///
/// 求模长
///
/// 向量到原点的模长
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 delegate void SomeCalculateWay(string str);
///
/// 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 ArrayList TwoArrToArr(ArrayList twoArr)
{
ArrayList arr = new ArrayList();
foreach (int[] item in twoArr)
{
int i = arr.IndexOf(item[0]);
if (i < 1) arr.Add(item[0]);
int x = arr.IndexOf(item[1]);
if (x < 1) arr.Add(item[1]);
}
return arr;
}
///
/// 二维数组转一维数组 并去重
///
/// 二维数组
/// 去重一维数组
private static List TwoArrToArr(List twoArr)
{
List arr = new List();
foreach (int[] item in twoArr)
{
int i = arr.IndexOf(item[0]);
if (i < 1) arr.Add(item[0]);
int x = arr.IndexOf(item[1]);
if (x < 1) arr.Add(item[1]);
}
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
/// 坐标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);
}
///
/// 检查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帽 三点的坐标组成的矩阵 “可以想象成臂长为1的操作轴图标”
///
private static Vector3 MatrixMul(Vector3 vec, Vector3[] mat)
{
Vector3 re = new Vector3();//声明返回值
re.X = vec.X * mat[0].X + vec.Y * mat[1].X + vec.Z * mat[2].X;
re.Y = vec.X * mat[0].Y + vec.Y * mat[1].Y + vec.Z * mat[2].Y;
re.Z = vec.X * mat[0].Z + vec.Y * mat[1].Z + vec.Z * mat[2].Z;
return re;
}
///
/// 获取两条线段 的最近位置的距离和占比
///
/// 线段1起始点
/// 线段1起终点
/// 线段2起始点
/// 线段2起终点
/// [在线段1占比,在线段2占比,最近距离]
public static double RecentlySquareOfLine(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
bool IsEqual(double x, double y)
{
if (Math.Abs(x - y) < 1e-7)
{
return true;
}
return false;
}
if (a1 == a2) a2 += 1;// 防止线段长度为0
if (b1 == b2) b2 += 1;
double ux = a2.X - a1.X;
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;//两线最近距离的平方
}
///
/// 按比例在两条线段上截取对应点间的最小距离 平方
///
/// 线段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();
}
///
/// 获取坐标集合的重心或中心
///
/// 坐标集合
/// 默认返回为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则为中心
/// 重心或中心坐标
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);
}
}
///
/// 获取坐标集合 的总宽度 高度 长度
///
/// 坐标集合
/// 返回数组[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;
}
///
/// 碰撞检测
///
/// 始点坐标集合
/// 终点坐标集合
/// 航线最小间距平方值
/// 飞行过程中最小间距平方值
///
public static List AirImitation(Vector3[] startPos, Vector3[] endPos, double lineDistanceSquare = 36100, double spaceBetweenSquare = 48400)
{
List planesCollision = new List(); //所有碰撞的组
int planeCou = startPos.Length; //获取飞机总数
for (int a = 0; a < planeCou; a++)
{
for (int b = 0; a + 1 + b < planeCou; b++)
{
//判断两条轨迹 之间的最小距离
double distanceSquare = RecentlySquareOfLine(startPos[a], endPos[a], startPos[a + 1 + b], endPos[a + 1 + b]);
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;
}
///
/// 碰撞检测
///
/// 始点坐标集合
/// 终点坐标集合
/// 航线最小间距平方值
/// 飞行过程中最小间距平方值
///
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)
{
//选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测
for (int contrastId = 0; contrastId < startPos.Length; contrastId++)
{
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;//返回没有碰撞;
}
///
/// 单机碰撞检测
///
/// 飞机的id PS:id从0开始
/// 飞机起始坐标集合
/// 飞机终点坐标集合
/// 航线小距离的平方对比值
/// 飞行过程中最小间距的平方对比值
/// true:有碰撞 false:无碰撞
public static bool OnlyImitation(int onlyPlaneId, List startPos, List endPos, double lineDistanceSquare = 32400, double spaceBetweenSquare = 90000)
{
//选出与指定飞机 航线有交叉的飞机 用于模拟飞行碰撞检测
for (int contrastId = 0; contrastId < startPos.Count; contrastId++)
{
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] = aOrigin + shiftVec;
endPos[i] = bOrigin + shiftVec;
}
else
{
startPos[i] = aOrigin - shiftVec;
endPos[i] = bOrigin - shiftVec;
}
shiftCou += 1;
}
}
re.Add(startPos);
re.Add(endPos);
return re;
}
///
/// 路径绕行
///
/// 起始坐标集合
/// 终点做标集合
/// 返回一个二维数组 长度为1即1个中间航点 长度为3即前中后三个中间航点
public static List> ABypassB(Vector3[] aVecs, Vector3[] bVecs)
{
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++)
{
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;
}
///
/// 在圆圈上 用固定弦长手拉手 分割点
///
/// 大圆半径
/// 固定弦长 ps:这个值决定绕行点一圈的密集成都值越小越密集
///
public static List GetVecsOnCircle(double radius, double chordLength = 220)
{
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.0f; // 如果是在平面上,Z 可能是 0
vecs.Add(new Vector3(x, y, z));
}
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
{
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++) //迭代圈
{
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;
}
}
}