ActiveProtect/Models/Common.cs

396 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Numerics;
namespace ActiveProtect.Models
{
/// <summary>
/// 表示三维空间中的向量
/// </summary>
public class Vector3D
{
// 添加静态单位向量属性
public static Vector3D UnitX => new Vector3D(1, 0, 0);
public static Vector3D UnitY => new Vector3D(0, 1, 0);
public static Vector3D UnitZ => new Vector3D(0, 0, 1);
public static Vector3D Zero => new Vector3D(0, 0, 0);
/// <summary>
/// X 坐标
/// </summary>
public double X { get; set; }
/// <summary>
/// Y 坐标
/// </summary>
public double Y { get; set; }
/// <summary>
/// Z 坐标
/// </summary>
public double Z { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public Vector3D(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
/// <summary>
/// 计算两个向量之间的距离
/// </summary>
/// <param name="v1">第一个向量</param>
/// <param name="v2">第二个向量</param>
/// <returns>两个向量之间的距离</returns>
public static double Distance(Vector3D v1, Vector3D 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));
}
/// <summary>
/// 将向量转换为字符串表示
/// </summary>
/// <returns>向量的字符串表示</returns>
public override string ToString()
{
return $"({X:F2}, {Y:F2}, {Z:F2})";
}
/// <summary>
/// 向量减法运算符重载
/// </summary>
public static Vector3D operator -(Vector3D a, Vector3D b)
{
return new Vector3D(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
}
/// <summary>
/// 向量加法运算符重载
/// </summary>
public static Vector3D operator +(Vector3D a, Vector3D b)
{
return new Vector3D(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
/// <summary>
/// 向量与标量乘法运算符重载
/// </summary>
public static Vector3D operator *(Vector3D a, double scalar)
{
return new Vector3D(a.X * scalar, a.Y * scalar, a.Z * scalar);
}
/// <summary>
/// 向量与标量除法运算符重载
/// </summary>
public static Vector3D operator /(Vector3D a, double scalar)
{
return new Vector3D(a.X / scalar, a.Y / scalar, a.Z / scalar);
}
/// <summary>
/// 向量反向
/// </summary>
public static Vector3D operator -(Vector3D a)
{
return new Vector3D(-a.X, -a.Y, -a.Z);
}
/// <summary>
/// 向量相等运算符重载
/// </summary>
public static bool operator ==(Vector3D left, Vector3D right)
{
return left.X == right.X && left.Y == right.Y && left.Z == right.Z;
}
/// <summary>
/// 向量不相等运算符重载
/// </summary>
public static bool operator !=(Vector3D left, Vector3D right)
{
return !(left == right);
}
/// <summary>
/// 判断两个向量是否相等
/// </summary>
public override bool Equals(object? obj)
{
if (obj is Vector3D other)
{
return this == other;
}
return false;
}
/// <summary>
/// 获取向量的哈希码
/// </summary>
/// <returns>向量的哈希码</returns>
public override int GetHashCode()
{
return HashCode.Combine(X, Y, Z);
}
/// <summary>
/// 计算向量的模长
/// </summary>
/// <returns>向量的模长</returns>
public double Magnitude()
{
return Math.Sqrt(X * X + Y * Y + Z * Z);
}
/// <summary>
/// 计算向量模长的平方
/// </summary>
/// <returns>向量模长的平方</returns>
public double MagnitudeSquared()
{
return X * X + Y * Y + Z * Z;
}
/// <summary>
/// 向量归一化
/// </summary>
/// <returns>归一化后的向量</returns>
public Vector3D Normalize()
{
double mag = Magnitude();
if (mag > 0)
{
return new Vector3D(X / mag, Y / mag, Z / mag);
}
return new Vector3D(0, 0, 0);
}
/// <summary>
/// 计算两个向量的叉积
/// </summary>
/// <param name="a">第一个向量</param>
/// <param name="b">第二个向量</param>
/// <returns>叉积结果</returns>
public static Vector3D CrossProduct(Vector3D a, Vector3D b)
{
return new Vector3D(
a.Y * b.Z - a.Z * b.Y,
a.Z * b.X - a.X * b.Z,
a.X * b.Y - a.Y * b.X
);
}
/// <summary>
/// 计算两个向量的点积
/// </summary>
/// <param name="a">第一个向量</param>
/// <param name="b">第二个向量</param>
/// <returns>点积结果</returns>
public static double DotProduct(Vector3D a, Vector3D b)
{
return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
}
/// <summary>
/// 向量取反
/// </summary>
/// <param name="a">输入向量</param>
/// <returns>取反后的向量</returns>
public static Vector3D Negate(Vector3D a)
{
return new Vector3D(-a.X, -a.Y, -a.Z);
}
/// <summary>
/// 计算AB两点之间距离 A 点一定距离的点的坐标
/// </summary>
/// <param name="a">直线起点</param>
/// <param name="b">直线终点</param>
/// <param name="distance">距离起点距离</param>
/// <returns>直线上的点</returns>
public static Vector3D PointOnLine(Vector3D a, Vector3D b, double distance)
{
Vector3D direction = b - a;
Vector3D unitDirection = direction.Normalize();
return a + unitDirection * distance;
}
internal Vector3D Rotate(Orientation orientation, double misalignmentAngle)
{
// 首先,根据方向和失调角计算出旋转矩阵
Matrix4x4 rotationMatrix = CalculateRotationMatrix(orientation, misalignmentAngle);
// 然后,使用旋转矩阵对当前向量进行旋转
Vector3D rotatedVector = ApplyRotationMatrix(this, rotationMatrix);
return rotatedVector;
}
private static Matrix4x4 CalculateRotationMatrix(Orientation orientation, double misalignmentAngle)
{
// 创建旋转矩阵
Matrix4x4 yawRotation = Matrix4x4.CreateRotationY((float)orientation.Yaw);
Matrix4x4 pitchRotation = Matrix4x4.CreateRotationX((float)orientation.Pitch);
Matrix4x4 rollRotation = Matrix4x4.CreateRotationZ((float)orientation.Roll);
Matrix4x4 misalignmentRotation = Matrix4x4.CreateRotationY((float)misalignmentAngle);
// 组合旋转矩阵
return misalignmentRotation * yawRotation * pitchRotation * rollRotation;
}
private static Vector3D ApplyRotationMatrix(Vector3D vector, Matrix4x4 matrix)
{
double x = vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31 + matrix.M41;
double y = vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32 + matrix.M42;
double z = vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + matrix.M43;
return new Vector3D(x, y, z);
}
}
/// <summary>
/// 表示三维空间中的方向
/// </summary>
public struct Orientation
{
/// <summary>
/// 偏航角绕Y轴旋转
/// </summary>
public double Yaw { get; set; }
/// <summary>
/// 俯仰角绕X轴旋转
/// </summary>
public double Pitch { get; set; }
/// <summary>
/// 滚转角绕Z轴旋转
/// </summary>
public double Roll { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public Orientation(double yaw, double pitch, double roll)
{
Yaw = yaw;
Pitch = pitch;
Roll = roll;
}
/// <summary>
/// 将方向转换为字符串表示
/// </summary>
/// <returns>方向的字符串表示</returns>
public override readonly string ToString()
{
return $"(Yaw: {Yaw:F2}, Pitch: {Pitch:F2}, Roll: {Roll:F2})";
}
/// <summary>
/// 将角度归一化到 [-π, π] 范围内
/// </summary>
public void Normalize()
{
Yaw = NormalizeAngle(Yaw);
Pitch = NormalizeAngle(Pitch);
Roll = NormalizeAngle(Roll);
}
/// <summary>
/// 将单个角度归一化到 [-π, π] 范围内
/// </summary>
/// <param name="angle">输入角度</param>
/// <returns>归一化后的角度</returns>
private static double NormalizeAngle(double angle)
{
while (angle > Math.PI) angle -= 2 * Math.PI;
while (angle <= -Math.PI) angle += 2 * Math.PI;
return angle;
}
internal Vector3D Rotate(Vector3D vector, double misalignmentAngle)
{
throw new NotImplementedException();
}
/// <summary>
/// 根<><E6A0B9><EFBFBD>给定的方向向量创建方向
/// </summary>
/// <param name="direction">方向向量</param>
/// <returns>对应的方向</returns>
public static Orientation LookAt(Vector3D direction)
{
double yaw = Math.Atan2(direction.Z, direction.X);
double pitch = Math.Atan2(direction.Y, Math.Sqrt(direction.X * direction.X + direction.Z * direction.Z));
return new Orientation(yaw, pitch, 0);
}
/// <summary>
/// 将方向转换为单位向量
/// </summary>
/// <returns>对应的单位向量</returns>
public readonly Vector3D ToVector()
{
double cosYaw = Math.Cos(Yaw);
double sinYaw = Math.Sin(Yaw);
double cosPitch = Math.Cos(Pitch);
double sinPitch = Math.Sin(Pitch);
return new Vector3D(
cosYaw * cosPitch,
sinPitch,
sinYaw * cosPitch
);
}
/// <summary>
/// 从向量创建方向
/// </summary>
/// <param name="vector">输入向量</param>
/// <returns>对应的方向</returns>
public static Orientation FromVector(Vector3D vector)
{
Vector3D normalized = vector.Normalize();
double pitch = Math.Asin(normalized.Y);
double yaw;
if (Math.Abs(normalized.Y) > 0.9999) // 接近垂直
{
yaw = 0; // 或者保持之前的偏航角
}
else
{
yaw = Math.Atan2(normalized.Z, normalized.X);
}
return new Orientation(yaw, pitch, 0);
}
}
/// <summary>
/// 表示二维空间中的向量
/// </summary>
public struct Vector2D
{
public double X { get; set; }
public double Y { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
public Vector2D(double x, double y)
{
X = x;
Y = y;
}
/// <summary>
/// 零向量
/// </summary>
public static Vector2D Zero => new Vector2D(0, 0);
}
}