초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -0,0 +1,747 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics;
using Google.Protobuf.WellKnownTypes;
using Newtonsoft.Json.Linq;
using Amazon.DynamoDBv2.Model;
namespace ServerCore;
public static class MathHelper
{
// The infamous ''3.14159265358979...'' value (RO).
public const float PI = (float)Math.PI;
// A representation of positive infinity (RO).
public const float Infinity = Single.PositiveInfinity;
// A representation of negative infinity (RO).
public const float NegativeInfinity = Single.NegativeInfinity;
// Degrees-to-radians conversion constant (RO).
public const float Deg2Rad = PI * 2F / 360F;
// Radians-to-degrees conversion constant (RO).
public const float Rad2Deg = 1F / Deg2Rad;
// Returns the sine of angle /value/ in radians.
public static T sin<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Sin(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Sin(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Sin(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the cosine of angle /value/ in radians.
public static T cos<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Cos(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Cos(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Sin(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the tangent of angle /value/ in radians.
public static T tan<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Tan(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Tan(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Tan(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the arc-sine of /value/ - the angle in radians whose sine is /f/.
public static T asin<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Asin(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Asin(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Asin(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the arc-cosine of /value/ - the angle in radians whose cosine is /f/.
public static T acos<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Acos(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Acos(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Acos(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the arc-tangent of /value/ - the angle in radians whose tangent is /f/.
public static T atan<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)MathF.Atan(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)Math.Atan(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)Math.Atan(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the angle in radians whose ::ref::Tan is @@y/x@@.
public static T atan2<T>(T y, T x)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result_y = Convert.ToSingle(y);
var result_x = Convert.ToSingle(x);
return (T)(object)MathF.Atan2(result_y, result_x);
}
else if (typeof(T) == typeof(double))
{
var result_y = Convert.ToDouble(y);
var result_x = Convert.ToDouble(x);
return (T)(object)Math.Atan2(result_y, result_x);
}
else if (typeof(T) == typeof(decimal))
{
var result_y = Convert.ToDecimal(y);
var round_result_y = Math.Round((double)result_y, 28);
var result_x = Convert.ToDecimal(x);
var round_result_x = Math.Round((double)result_x, 28);
return (T)(object)(decimal)Math.Atan2(round_result_y, round_result_x);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : y:{y}, x:{x}");
}
}
// Returns square root of /value/.
public static T sqrt<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = MathF.Sqrt(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Sqrt(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
var round_result = Math.Round((double)result, 28);
return (T)(object)(decimal)Math.Sqrt(round_result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the absolute value of /value/.
public static T abs<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(Int16))
{
var result = (Int16)Math.Abs(Convert.ToInt16(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(Int32))
{
var result = (Int32)Math.Abs(Convert.ToInt32(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(float))
{
var result = MathF.Abs(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Abs(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Abs(Convert.ToDecimal(value));
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// *listonly*
public static T min<T>(T a, T b)
where T : struct, IComparable<T>
{
return a.CompareTo(b) < 0 ? a : b;
}
// Returns the smallest of two or more values.
public static T min<T>(params T[] values)
where T : struct, IComparable<T>
{
int len = values.Length;
if (len == 0)
{
return default(T);
}
T min_value = values[0];
for (int i = 1; i < len; i++)
{
if (values[i].CompareTo(min_value) < 0)
min_value = values[i];
}
return min_value;
}
public static T max<T>(T a, T b)
where T : IComparable<T>
{
return a.CompareTo(b) > 0 ? a : b;
}
public static T max<T>(params T[] values)
where T : IComparable<T>
{
if (values.Length == 0)
{
throw new ArgumentException("At least one value must be provided.", nameof(values));
}
T max_value = values[0];
for (int i = 1; i < values.Length; i++)
{
if (values[i].CompareTo(max_value) > 0)
{
max_value = values[i];
}
}
return max_value;
}
// Returns /f/ raised to power /p/.
public static T pow<T>(T baseValue, T exponent)
where T : struct, IConvertible
{
// 타입에 따라 적절한 연산을 수행
if (typeof(T) == typeof(float))
{
var base_v = Convert.ToSingle(baseValue);
var exponent_v = Convert.ToSingle(exponent);
return (T)(object)MathF.Pow(base_v, exponent_v);
}
else if (typeof(T) == typeof(double))
{
var base_v = Convert.ToDouble(baseValue);
var exponent_v = Convert.ToDouble(exponent);
return (T)(object)(double)Math.Pow(base_v, exponent_v);
}
else if (typeof(T) == typeof(decimal))
{
var base_v = Convert.ToDecimal(baseValue);
var exponent_v = Convert.ToDecimal(exponent);
var round_result_base_v = Math.Round((double)base_v, 28);
var round_result_exponent_v = Math.Round((double)exponent_v, 28);
return (T)(object)(decimal)Math.Pow(round_result_base_v, round_result_exponent_v);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {baseValue}, {exponent}");
}
}
// Returns e raised to the specified power.
public static T exp<T>(T power)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var power_v = Convert.ToSingle(power);
return (T)(object)MathF.Exp(power_v);
}
else if (typeof(T) == typeof(double))
{
var power_v = Convert.ToDouble(power);
return (T)(object)(double)Math.Exp(power_v);
}
else if (typeof(T) == typeof(decimal))
{
var power_v = Convert.ToDecimal(power);
var round_result_power_v = Math.Round((double)power_v, 28);
return (T)(object)(decimal)Math.Exp(round_result_power_v);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {power}");
}
}
// Returns the logarithm of a specified number in a specified base.
public static T log<T>(T f, T p)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var base_v = Convert.ToSingle(f);
var power_v = Convert.ToSingle(p);
return (T)(object)MathF.Log(base_v, power_v);
}
else if (typeof(T) == typeof(double))
{
var base_v = Convert.ToDouble(f);
var power_v = Convert.ToDouble(p);
return (T)(object)(double)Math.Log(base_v, power_v);
}
else if (typeof(T) == typeof(decimal))
{
var base_v = Convert.ToDecimal(f);
var power_v = Convert.ToDecimal(p);
var round_result_base_v = Math.Round((double)base_v, 28);
var round_result_power_v = Math.Round((double)power_v, 28);
return (T)(object)(decimal)Math.Log(round_result_base_v, round_result_power_v);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {f}, {p}");
}
}
// Returns the natural (base e) logarithm of a specified number.
public static T log<T>(T f)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var base_v = Convert.ToSingle(f);
return (T)(object)MathF.Log(base_v);
}
else if (typeof(T) == typeof(double))
{
var base_v = Convert.ToDouble(f);
return (T)(object)(double)Math.Log(base_v);
}
else if (typeof(T) == typeof(decimal))
{
var base_v = Convert.ToDecimal(f);
var round_result_base_v = Math.Round((double)base_v, 28);
return (T)(object)(decimal)Math.Log(round_result_base_v);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {f}");
}
}
// Returns the base 10 logarithm of a specified number.
public static T log10<T>(T f)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var base_v = Convert.ToSingle(f);
return (T)(object)MathF.Log10(base_v);
}
else if (typeof(T) == typeof(double))
{
var base_v = Convert.ToDouble(f);
return (T)(object)(double)Math.Log10(base_v);
}
else if (typeof(T) == typeof(decimal))
{
var base_v = Convert.ToDecimal(f);
var round_result_base_v = Math.Round((double)base_v, 28);
return (T)(object)(decimal)Math.Log10(round_result_base_v);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {f}");
}
}
// Returns the smallest integer greater to or equal to /value/.
public static T ceil<T>(T value)
where T : struct
{
if (typeof(T) == typeof(float))
{
var result = MathF.Ceiling(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Ceiling(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Ceiling(Convert.ToDecimal(value));
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the largest integer smaller to or equal to /value/.
public static T floor<T>(T value)
where T : struct
{
if (typeof(T) == typeof(float))
{
var result = MathF.Floor(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Floor(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Floor(Convert.ToDecimal(value));
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns /value/ rounded to T float, double, decimal
public static T round<T>(T value)
where T : struct
{
if (typeof(T) == typeof(float))
{
var result = MathF.Round(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Round(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Round(Convert.ToDecimal(value));
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns /value/ rounded to T float, double, decimal
public static T round<T>(T value, int decimalPlaces)
where T : struct
{
if (typeof(T) == typeof(float))
{
var result = MathF.Round(Convert.ToSingle(value), decimalPlaces);
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Round(Convert.ToDouble(value), decimalPlaces);
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Round(Convert.ToDecimal(value), decimalPlaces);
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the smallest integer greater to or equal to /value/.
public static T truncate<T>(T value)
where T : struct, IComparable<T>
{
if (typeof(T) == typeof(float))
{
var result = MathF.Truncate(Convert.ToSingle(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(double))
{
var result = Math.Truncate(Convert.ToDouble(value));
return (T)(object)result;
}
else if (typeof(T) == typeof(decimal))
{
var result = Math.Truncate(Convert.ToDecimal(value));
return (T)(object)result;
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
public static T roundUpOrDown<T>(T value, int decimalPlaces = 0)
where T : struct, IComparable<T>
{
dynamic dynamic_value = value;
double factor = Math.Pow(10, decimalPlaces); // 소숫점 자리수에 따라 곱할 값 설정, 0일 경우 소수점없이 올림 처리 한다 !!!
if (TypeHelper.NumericSignType.Positive == TypeHelper.checkNumericSignType<T>(dynamic_value))
{
return (T)(Math.Ceiling(dynamic_value * factor) / factor);
}
return (T)(Math.Floor(dynamic_value * factor) / factor);
}
// Returns the smallest integer greater to or equal to /value/.
public static T ceilToInt<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)(Int32)MathF.Ceiling(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)(Int32)Math.Ceiling(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
return (T)(object)(Int32)Math.Ceiling(result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the largest integer smaller to or equal to /value/.
public static T floorToInt<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)(Int32)MathF.Floor(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)(Int32)Math.Floor(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
return (T)(object)(Int32)Math.Floor(result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns /value/ rounded to the nearest integer.
public static T roundToInt<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)(Int32)MathF.Round(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)(Int32)Math.Round(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
return (T)(object)(Int32)Math.Round(result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns /value/ truncated to the nearest integer.
public static T truncateToInt<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result = Convert.ToSingle(value);
return (T)(object)(Int32)MathF.Truncate(result);
}
else if (typeof(T) == typeof(double))
{
var result = Convert.ToDouble(value);
return (T)(object)(Int32)Math.Round(result);
}
else if (typeof(T) == typeof(decimal))
{
var result = Convert.ToDecimal(value);
return (T)(object)(Int32)Math.Round(result);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Returns the sign of /value/.
public static T sign<T>(T value)
where T : struct, IConvertible
{
if (typeof(T) == typeof(float))
{
var result_v = Convert.ToSingle(value);
return (T)(object)(result_v >= 0F ? 1F : -1F);
}
else if (typeof(T) == typeof(double))
{
var result_v = Convert.ToDouble(value);
return (T)(object)(result_v >= 0D ? 1D : -1D);
}
else if (typeof(T) == typeof(decimal))
{
var result_v = Convert.ToDecimal(value);
return (T)(object)(result_v >= 0M ? 1M : -1M);
}
else
{
throw new NotSupportedException($"Invalid Type !!! : {value}");
}
}
// Clamps a value between a minimum generic type and maximum generic type value.
public static T clamp<T>(T value, T min, T max)
where T : IComparable<T>
{
if (value.CompareTo(min) < 0)
value = min;
else if (value.CompareTo(max) > 0)
value = max;
return value;
}
}

View File

@@ -0,0 +1,659 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics;
namespace ServerCore;
[Serializable]
public struct QuaternionHelper
{
const float radToDeg = (float)(180.0 / Math.PI);
const float degToRad = (float)(Math.PI / 180.0);
public const float kEpsilon = 1E-06f; // should probably be used in the 0 tests in LookRotation or Slerp
public Vector3 xyz
{
set
{
x = value.X;
y = value.Y;
z = value.Z;
}
get
{
return new Vector3(x, y, z);
}
}
public float x;
public float y;
public float z;
public float w;
public float this[Int32 index]
{
get
{
switch (index)
{
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.z;
case 3:
return this.w;
default:
throw new IndexOutOfRangeException("Invalid Quaternion index: " + index + ", can use only 0,1,2,3");
}
}
set
{
switch (index)
{
case 0:
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
this.z = value;
break;
case 3:
this.w = value;
break;
default:
throw new IndexOutOfRangeException("Invalid Quaternion index: " + index + ", can use only 0,1,2,3");
}
}
}
/// <summary>
/// <para>The identity rotation (RO).</para>
/// </summary>
public static QuaternionHelper identity
{
get
{
return new QuaternionHelper(0f, 0f, 0f, 1f);
}
}
/// <summary>
/// <para>Returns the euler angle representation of the rotation.</para>
/// </summary>
public Vector3 eulerAngles
{
get
{
return Vector3Helper.multiple(QuaternionHelper.toEulerRad(this), degToRad);
}
set
{
this = QuaternionHelper.fromEulerRad(Vector3Helper.multiple(value, degToRad));
}
}
/// <summary>
/// Gets the length (magnitude) of the quaternion.
/// </summary>
/// <seealso cref="LengthSquared"/>
public float Length
{
get
{
return (float)System.Math.Sqrt(x * x + y * y + z * z + w * w);
}
}
/// <summary>
/// Gets the square of the quaternion length (magnitude).
/// </summary>
public float LengthSquared
{
get
{
return x * x + y * y + z * z + w * w;
}
}
/// <summary>
/// <para>Constructs new Quaternion with given x,y,z,w components.</para>
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
/// <param name="w"></param>
public QuaternionHelper(float x, float y, float z, float w)
{
this.x = x;
this.y = y;
this.x = z;
this.w = w;
}
/// <summary>
/// Construct a new Quaternion from vector and w components
/// </summary>
/// <param name="v">The vector part</param>
/// <param name="w">The w part</param>
public QuaternionHelper(Vector3 v, float w)
{
this.x = v.X;
this.y = v.Y;
this.z = v.Z;
this.w = w;
}
/// <summary>
/// <para>Set x, y, z and w components of an existing Quaternion.</para>
/// </summary>
/// <param name="new_x"></param>
/// <param name="new_y"></param>
/// <param name="new_z"></param>
/// <param name="new_w"></param>
public void set(float new_x, float new_y, float new_z, float new_w)
{
this.x = new_x;
this.y = new_y;
this.z = new_z;
this.w = new_w;
}
/// <summary>
/// Scales the Quaternion to unit length.
/// </summary>
public void normalize()
{
float scale = 1.0f / this.Length;
xyz = Vector3Helper.multiple(xyz, scale);
w = w * scale;
}
/// <summary>
/// Scale the given quaternion to unit length
/// </summary>
/// <param name="q">The quaternion to normalize</param>
/// <returns>The normalized quaternion</returns>
public static QuaternionHelper normalize(QuaternionHelper q)
{
QuaternionHelper result;
normalize(ref q, out result);
return result;
}
/// <summary>
/// Scale the given quaternion to unit length
/// </summary>
/// <param name="q">The quaternion to normalize</param>
/// <param name="result">The normalized quaternion</param>
public static void normalize(ref QuaternionHelper q, out QuaternionHelper result)
{
float scale = 1.0f / q.Length;
result = new QuaternionHelper(Vector3Helper.multiple(q.xyz, scale), q.w * scale);
}
/// <summary>
/// <para>The dot product between two rotations.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public static float dot(QuaternionHelper a, QuaternionHelper b)
{
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
/// <summary>
/// <para>Creates a rotation which rotates /angle/ degrees around /axis/.</para>
/// </summary>
/// <param name="angle"></param>
/// <param name="axis"></param>
public static QuaternionHelper angleAxis(float angle, Vector3 axis)
{
return QuaternionHelper.angleAxis(angle, ref axis);
}
private static QuaternionHelper angleAxis(float degress, ref Vector3 axis)
{
if (Vector3Helper.sqrMagnitude(axis) == 0.0f)
{
return identity;
}
QuaternionHelper result = identity;
var radians = degress * degToRad;
radians *= 0.5f;
Vector3Helper.normalize(axis);
axis = Vector3Helper.multiple(axis, (float)System.Math.Sin(radians));
result.x = axis.X;
result.y = axis.Y;
result.z = axis.Z;
result.w = (float)System.Math.Cos(radians);
return normalize(result);
}
public void toAngleAxis(out float angle, out Vector3 axis)
{
QuaternionHelper.toAxisAngleRad(this, out axis, out angle);
angle *= radToDeg;
}
/// <summary>
/// <para>Creates a rotation which rotates from /fromDirection/ to /toDirection/.</para>
/// </summary>
/// <param name="fromDirection"></param>
/// <param name="toDirection"></param>
public static QuaternionHelper fromToRotation(Vector3 fromDirection, Vector3 toDirection)
{
return rotateTowards(lookRotation(fromDirection), lookRotation(toDirection), float.MaxValue);
}
/// <summary>
/// <para>Creates a rotation which rotates from /fromDirection/ to /toDirection/.</para>
/// </summary>
/// <param name="fromDirection"></param>
/// <param name="toDirection"></param>
public void setFromToRotation(Vector3 fromDirection, Vector3 toDirection)
{
this = QuaternionHelper.fromToRotation(fromDirection, toDirection);
}
/// <summary>
/// <para>Creates a rotation with the specified /forward/ and /upwards/ directions.</para>
/// </summary>
/// <param name="forward">The direction to look in.</param>
/// <param name="upwards">The vector that defines in which direction up is.</param>
public static QuaternionHelper lookRotation(Vector3 forward, Vector3 upwards)
{
return QuaternionHelper.lookRotation(ref forward, ref upwards);
}
public static QuaternionHelper lookRotation(Vector3 forward)
{
Vector3 up = Vector3Helper.up;
return QuaternionHelper.lookRotation(ref forward, ref up);
}
// 유니티와 결과물이 다르므로 다시 구현 해야 한다.
// from http://answers.unity3d.com/questions/467614/what-is-the-source-code-of-quaternionlookrotation.html
private static QuaternionHelper lookRotation(ref Vector3 forward, ref Vector3 up)
{
Vector3Helper.normalize(forward);
Vector3 vector = forward.normalize();
Vector3 vector2 = Vector3Helper.cross(up, vector).normalize();
Vector3 vector3 = Vector3Helper.cross(vector, vector2);
var m00 = vector2.X;
var m01 = vector2.Y;
var m02 = vector2.Z;
var m10 = vector3.X;
var m11 = vector3.Y;
var m12 = vector3.Z;
var m20 = vector.X;
var m21 = vector.Y;
var m22 = vector.Z;
float num8 = (m00 + m11) + m22;
var quaternion = new QuaternionHelper();
if (num8 > 0f)
{
var num = MathHelper.sqrt(num8 + 1f);
quaternion.w = num * 0.5f;
num = 0.5f / num;
quaternion.x = (m12 - m21) * num;
quaternion.y = (m20 - m02) * num;
quaternion.z = (m01 - m10) * num;
return quaternion;
}
if ((m00 >= m11) && (m00 >= m22))
{
var num7 = MathHelper.sqrt(((1f + m00) - m11) - m22);
var num4 = 0.5f / num7;
quaternion.x = 0.5f * num7;
quaternion.y = (m01 + m10) * num4;
quaternion.z = (m02 + m20) * num4;
quaternion.w = (m12 - m21) * num4;
return quaternion;
}
if (m11 > m22)
{
var num6 = MathHelper.sqrt(((1f + m11) - m00) - m22);
var num3 = 0.5f / num6;
quaternion.x = (m10 + m01) * num3;
quaternion.y = 0.5f * num6;
quaternion.z = (m21 + m12) * num3;
quaternion.w = (m20 - m02) * num3;
return quaternion;
}
var num5 = MathHelper.sqrt(((1f + m22) - m00) - m11);
var num2 = 0.5f / num5;
quaternion.x = (m20 + m02) * num2;
quaternion.y = (m21 + m12) * num2;
quaternion.z = 0.5f * num5;
quaternion.w = (m01 - m10) * num2;
return quaternion;
}
public void setLookRotation(Vector3 view)
{
Vector3 up = Vector3Helper.up;
this.setLookRotation(view, up);
}
/// <summary>
/// <para>Creates a rotation with the specified /forward/ and /upwards/ directions.</para>
/// </summary>
/// <param name="view">The direction to look in.</param>
/// <param name="up">The vector that defines in which direction up is.</param>
public void setLookRotation(Vector3 view, Vector3 up)
{
this = QuaternionHelper.lookRotation(view, up);
}
/// <summary>
/// <para>Spherically interpolates between /a/ and /b/ by t. The parameter /t/ is clamped to the range [0, 1].</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="t"></param>
public static QuaternionHelper slerp(QuaternionHelper a, QuaternionHelper b, float t)
{
return QuaternionHelper.slerp(ref a, ref b, t);
}
private static QuaternionHelper slerp(ref QuaternionHelper a, ref QuaternionHelper b, float t)
{
if (t > 1) t = 1;
if (t < 0) t = 0;
return slerpUnclamped(ref a, ref b, t);
}
/// <summary>
/// <para>Spherically interpolates between /a/ and /b/ by t. The parameter /t/ is not clamped.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="t"></param>
public static QuaternionHelper slerpUnclamped(QuaternionHelper a, QuaternionHelper b, float t)
{
return QuaternionHelper.slerpUnclamped(ref a, ref b, t);
}
private static QuaternionHelper slerpUnclamped(ref QuaternionHelper a, ref QuaternionHelper b, float t)
{
// if either input is zero, return the other.
if (a.LengthSquared == 0.0f)
{
if (b.LengthSquared == 0.0f)
{
return identity;
}
return b;
}
else if (b.LengthSquared == 0.0f)
{
return a;
}
float cosHalfAngle = a.w * b.w + Vector3Helper.dot(a.xyz, b.xyz);
if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f)
{
// angle = 0.0f, so just return one input.
return a;
}
else if (cosHalfAngle < 0.0f)
{
b.xyz = Vector3Helper.multiple(b.xyz, -1);
b.w = -b.w;
cosHalfAngle = -cosHalfAngle;
}
float blendA;
float blendB;
if (cosHalfAngle < 0.99f)
{
// do proper slerp for big angles
float halfAngle = (float)System.Math.Acos(cosHalfAngle);
float sinHalfAngle = (float)System.Math.Sin(halfAngle);
float oneOverSinHalfAngle = 1.0f / sinHalfAngle;
blendA = (float)System.Math.Sin(halfAngle * (1.0f - t)) * oneOverSinHalfAngle;
blendB = (float)System.Math.Sin(halfAngle * t) * oneOverSinHalfAngle;
}
else
{
// do lerp if angle is really small.
blendA = 1.0f - t;
blendB = t;
}
QuaternionHelper result = new QuaternionHelper(Vector3Helper.multiple(a.xyz, blendA) + Vector3Helper.multiple(b.xyz, blendB), blendA * a.w + blendB * b.w);
if (result.LengthSquared > 0.0f)
return normalize(result);
else
return identity;
}
/// <summary>
/// <para>Interpolates between /a/ and /b/ by /t/ and normalizes the result afterwards. The parameter /t/ is clamped to the range [0, 1].</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="t"></param>
public static QuaternionHelper lerp(QuaternionHelper a, QuaternionHelper b, float t)
{
if (t > 1) t = 1;
if (t < 0) t = 0;
return slerp(ref a, ref b, t); // TODO: use lerp not slerp, "Because quaternion works in 4D. Rotation in 4D are linear" ???
}
/// <summary>
/// <para>Interpolates between /a/ and /b/ by /t/ and normalizes the result afterwards. The parameter /t/ is not clamped.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="t"></param>
public static QuaternionHelper lerpUnclamped(QuaternionHelper a, QuaternionHelper b, float t)
{
return slerp(ref a, ref b, t);
}
/// <summary>
/// <para>Rotates a rotation /from/ towards /to/.</para>
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="maxDegreesDelta"></param>
public static QuaternionHelper rotateTowards(QuaternionHelper from, QuaternionHelper to, float maxDegreesDelta)
{
float angled = angle(from, to);
if (angled == 0.0f) return to;
return slerpUnclamped(from, to, MathHelper.min(1.0f, maxDegreesDelta / angled));
}
/// <summary>
/// <para>Returns the Inverse of /rotation/.</para>
/// </summary>
/// <param name="rotation"></param>
public static QuaternionHelper inverse(QuaternionHelper rotation)
{
float lengthSq = rotation.LengthSquared;
if (lengthSq != 0.0)
{
float i = 1.0f / lengthSq;
return new QuaternionHelper(Vector3Helper.multiple(rotation.xyz, -i), rotation.w * i);
}
return rotation;
}
/// <summary>
/// <para>Returns a nicely formatted string of the Quaternion.</para>
/// </summary>
/// <param name="format"></param>
public override string ToString()
{
return string.Format("({0:F1}, {1:F1}, {2:F1}, {3:F1})", this.x, this.y, this.z, this.w);
}
/// <summary>
/// <para>Returns a nicely formatted string of the Quaternion.</para>
/// </summary>
/// <param name="format"></param>
public string toString(string format)
{
return string.Format("({0}, {1}, {2}, {3})", this.x.ToString(format), this.y.ToString(format), this.z.ToString(format), this.w.ToString(format));
}
/// <summary>
/// <para>Returns the angle in degrees between two rotations /a/ and /b/.</para>
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public static float angle(QuaternionHelper a, QuaternionHelper b)
{
float f = QuaternionHelper.dot(a, b);
return MathHelper.acos(MathHelper.min(MathHelper.abs(f), 1f)) * 2f * radToDeg;
}
/// <summary>
/// <para>Returns a rotation that rotates z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis (in that order).</para>
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
public static QuaternionHelper euler(float x, float y, float z)
{
return QuaternionHelper.fromEulerRad(Vector3Helper.multiple(new Vector3((float)x, (float)y, (float)z), degToRad));
}
/// <summary>
/// <para>Returns a rotation that rotates z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis (in that order).</para>
/// </summary>
/// <param name="euler"></param>
public static QuaternionHelper euler(Vector3 euler)
{
return QuaternionHelper.fromEulerRad(Vector3Helper.multiple(euler, degToRad));
}
// 유니티와 결과물이 다르므로 다시 구현 해야 한다.
// from http://stackoverflow.com/questions/12088610/conversion-between-euler-quaternion-like-in-unity3d-engine
private static Vector3 toEulerRad(QuaternionHelper q1)
{
ArgumentNullReferenceCheckHelper.throwIfNull(q1, () => $"q1 is null !!!");
float sqw = q1.w * q1.w;
float sqx = q1.x * q1.x;
float sqy = q1.y * q1.y;
float sqz = q1.z * q1.z;
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
float test = q1.x * q1.w - q1.y * q1.z;
Vector3 v;
if (test > 0.4995f * unit)
{ // singularity at north pole
v.Y = 2f * MathHelper.atan2(q1.y, q1.x);
v.X = MathHelper.PI / 2;
v.Z = 0;
return normalizeAngles(Vector3Helper.multiple(v, MathHelper.Rad2Deg));
}
if (test < -0.4995f * unit)
{ // singularity at south pole
v.Y = -2f * MathHelper.atan2(q1.y, q1.x);
v.X = -MathHelper.PI / 2;
v.Z = 0;
return normalizeAngles(Vector3Helper.multiple(v, MathHelper.Rad2Deg));
}
QuaternionHelper q = new QuaternionHelper(q1.w, q1.z, q1.x, q1.y);
v.Y = MathHelper.atan2(2f * q.x * q.w + 2f * q.y * q.z, 1 - 2f * (q.z * q.z + q.w * q.w)); // Yaw
v.X = MathHelper.asin(2f * (q.x * q.z - q.w * q.y)); // Pitch
v.Z = MathHelper.atan2(2f * q.x * q.y + 2f * q.z * q.w, 1 - 2f * (q.y * q.y + q.z * q.z)); // Roll
return normalizeAngles(Vector3Helper.multiple(v, MathHelper.Rad2Deg));
}
private static Vector3 normalizeAngles(Vector3 angles)
{
angles.X = normalizeAngle(angles.Y);
angles.Y = normalizeAngle(angles.Y);
angles.Z = normalizeAngle(angles.Z);
return angles;
}
private static float normalizeAngle(float angle)
{
while (angle > 360)
angle -= 360;
while (angle < 0)
angle += 360;
return angle;
}
// from http://stackoverflow.com/questions/11492299/quaternion-to-euler-angles-algorithm-how-to-convert-to-y-up-and-between-ha
private static QuaternionHelper fromEulerRad(Vector3 euler)
{
var yaw = euler.X;
var pitch = euler.Y;
var roll = euler.Z;
float rollOver2 = roll * 0.5f;
float sinRollOver2 = (float)System.Math.Sin((float)rollOver2);
float cosRollOver2 = (float)System.Math.Cos((float)rollOver2);
float pitchOver2 = pitch * 0.5f;
float sinPitchOver2 = (float)System.Math.Sin((float)pitchOver2);
float cosPitchOver2 = (float)System.Math.Cos((float)pitchOver2);
float yawOver2 = yaw * 0.5f;
float sinYawOver2 = (float)System.Math.Sin((float)yawOver2);
float cosYawOver2 = (float)System.Math.Cos((float)yawOver2);
QuaternionHelper result;
result.x = sinYawOver2 * cosPitchOver2 * cosRollOver2 + cosYawOver2 * sinPitchOver2 * sinRollOver2;
result.y = cosYawOver2 * sinPitchOver2 * cosRollOver2 - sinYawOver2 * cosPitchOver2 * sinRollOver2;
result.z = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2;
result.w = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2;
return result;
}
private static void toAxisAngleRad(QuaternionHelper q, out Vector3 axis, out float angle)
{
if (System.Math.Abs(q.w) > 1.0f)
q.normalize();
angle = 2.0f * (float)System.Math.Acos(q.w); // angle
float den = (float)System.Math.Sqrt(1.0 - q.w * q.w);
if (den > 0.0001f)
{
axis = Vector3Helper.division(q.xyz, den);
}
else
{
// This occurs when the angle is zero.
// Not a problem: just set an arbitrary normalized axis.
axis = new Vector3(1, 0, 0);
}
}
public override Int32 GetHashCode()
{
return this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2 ^ this.w.GetHashCode() >> 1;
}
public override bool Equals(object? other)
{
if (!(other is QuaternionHelper))
{
return false;
}
QuaternionHelper quaternion = (QuaternionHelper)other;
return this.x.Equals(quaternion.x) && this.y.Equals(quaternion.y) && this.z.Equals(quaternion.z) && this.w.Equals(quaternion.w);
}
public bool Equals(QuaternionHelper other)
{
return this.x.Equals(other.x) && this.y.Equals(other.y) && this.z.Equals(other.z) && this.w.Equals(other.w);
}
public static QuaternionHelper operator *(QuaternionHelper lhs, QuaternionHelper rhs)
{
return new QuaternionHelper(lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y, lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z, lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x, lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z);
}
public static Vector3 operator *(QuaternionHelper rotation, Vector3 point)
{
float num = rotation.x * 2f;
float num2 = rotation.y * 2f;
float num3 = rotation.z * 2f;
float num4 = rotation.x * num;
float num5 = rotation.y * num2;
float num6 = rotation.z * num3;
float num7 = rotation.x * num2;
float num8 = rotation.x * num3;
float num9 = rotation.y * num3;
float num10 = rotation.w * num;
float num11 = rotation.w * num2;
float num12 = rotation.w * num3;
Vector3 result;
result.X = (1f - (num5 + num6)) * point.X + (num7 - num12) * point.Y + (num8 + num11) * point.Z;
result.Y = (num7 + num12) * point.X + (1f - (num4 + num6)) * point.Y + (num9 - num10) * point.Z;
result.Z = (num8 - num11) * point.X + (num9 + num10) * point.Y + (1f - (num4 + num5)) * point.Z;
return result;
}
public static bool operator ==(QuaternionHelper lhs, QuaternionHelper rhs)
{
return QuaternionHelper.dot(lhs, rhs) > 0.999999f;
}
public static bool operator !=(QuaternionHelper lhs, QuaternionHelper rhs)
{
return QuaternionHelper.dot(lhs, rhs) <= 0.999999f;
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore;
public class TransformHelper
{
public static Position rotateX(Position pos, Rotation rot)
{
double radian = (Math.PI * rot.Roll) / 180.0f;
var cosValue = Math.Cos(radian);
var sinValue = Math.Sin(radian);
double y = (pos.Y * cosValue) + (pos.Z * -sinValue);
double z = (pos.Y * sinValue) + (pos.Z * cosValue);
Position retValue = new Position
{
X = pos.X,
Y = y,
Z = z,
};
return retValue;
}
public static Position rotateY(Position pos, Rotation rot)
{
double radian = (Math.PI * rot.Pitch) / 180.0f;
var cosValue = Math.Cos(radian);
var sinValue = Math.Sin(radian);
double x = (pos.X * cosValue) + (pos.Z * -sinValue);
double z = (pos.X * sinValue) + (pos.Z * cosValue);
Position retValue = new Position
{
X = x,
Y = pos.Y,
Z = z,
};
return retValue;
}
public static Position rotateZ(Position pos, Rotation rot)
{
double radian = (Math.PI * rot.Yaw) / 180.0f;
var cosValue = Math.Cos(radian);
var sinValue = Math.Sin(radian);
double x = (pos.X * cosValue) + (pos.Y * -sinValue);
double y = (pos.X * sinValue) + (pos.Y * cosValue);
Position retValue = new Position
{
X = x,
Y = y,
Z = pos.Z,
};
return retValue;
}
public static Position rotate(Position pos, Rotation rot)
{
Position tempPos;
tempPos = rotateY(pos, rot);
tempPos = rotateZ(tempPos, rot);
tempPos = rotateX(tempPos, rot);
return tempPos;
}
}

View File

@@ -0,0 +1,376 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics;
namespace ServerCore;
public static class Vector3Helper
{
public const float Infinity = float.MaxValue;
public const float kEpsilon = 0.00001F;
public const float kEpsilonNormalSqrt = 1e-15F;
private static readonly Vector3 zeroVector = new Vector3(0F, 0F, 0F);
private static readonly Vector3 oneVector = new Vector3(1F, 1F, 1F);
private static readonly Vector3 upVector = new Vector3(0F, 1F, 0F);
private static readonly Vector3 downVector = new Vector3(0F, -1F, 0F);
private static readonly Vector3 leftVector = new Vector3(-1F, 0F, 0F);
private static readonly Vector3 rightVector = new Vector3(1F, 0F, 0F);
private static readonly Vector3 forwardVector = new Vector3(0F, 0F, 1F);
private static readonly Vector3 backwardVector = new Vector3(0F, 0F, -1F);
private static readonly Vector3 positiveInfinityVector = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
private static readonly Vector3 negativeInfinityVector = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
public static Vector3 zero { get { return zeroVector; } }
public static Vector3 normalize(this Vector3 _this)
{
return normalizeEx(_this);
}
public static Vector3 multipleEx(this Vector3 _this, float b)
{
return multiple(_this, b);
}
public static bool isZero(Vector3 v)
{
return Equals(v, zeroVector);
}
public static Vector3 deepClone(Vector3 from)
{
return new Vector3(from.X, from.Y, from.Z);
}
public static void deepCopy(Vector3 from, ref Vector3 to)
{
to.X = from.X;
to.Y = from.Y;
to.Z = from.Z;
}
public static Vector3 normalizeEx(Vector3 value)
{
float mag = magnitude(value);
if (mag > kEpsilon)
{
return new Vector3(value.X / mag, value.Y / mag, value.Z / mag);
}
else
{
return zero;
}
}
// 외적
public static Vector3 cross(Vector3 lhs, Vector3 rhs)
{
return new Vector3 (
lhs.Y * rhs.Z - lhs.Z * rhs.Y,
lhs.Z * rhs.X - lhs.X * rhs.Z,
lhs.X * rhs.Y - lhs.Y * rhs.X
);
}
// 외적을 이용한 a 점과 (from, to)방향 벡터의 수직 거리(수선의 발)
public static float pointToVectorDistance(Vector3 a, Vector3 from, Vector3 to)
{
// from->to 방향벡터
Vector3 line_vector = dir(to, from);
// from->a 방향벡터
Vector3 from_to_a_vector = dir(a, from);
// 외적 from에서 a로의 벡터와 from to 벡터의 외적
Vector3 crossed = cross(from_to_a_vector, line_vector);
// 외적 결과 벡터의 크기를 라인 백터의 크기로 나누면 직선 from->to와 a점 사이의 거리가 나온다.
return magnitude(crossed) / magnitude(line_vector);
}
// 외적을 이용한 (a, b)방향 벡터 점 p의 수직 거리(수선의 발)
public static float PointToDirDistance(Vector3 dir_a_b, Vector3 dir_a_p)
{
// 외적 a에서 p로의 방향 벡터와 a b 방향 벡터의 외적
Vector3 crossed = cross(dir_a_p, dir_a_b);
// 외적 결과 벡터의 크기를 라인 백터의 크기로 나누면 직선 a->b와 c점 사이의 거리가 나온다.
return magnitude(crossed) / magnitude(dir_a_b);
}
// 점과 선분사이의 최단 거리
public static bool pointToLineDistance(Vector3 p, Vector3 from, Vector3 to, bool is_capsule, out float dist)
{
dist = 0;
float from_to_distance = distance(from, to);
// from == to
if (0 == from_to_distance)
{
dist = distance(from, p);
return true;
}
Vector3 from_to_vector = dir(to, from);
Vector3 from_p_vector = dir(p, from);
Vector3 to_p_vector = dir(p, to);
// 수선의 발이 선분 위에 있는 경우
if (dot(from_p_vector, from_to_vector) * dot(to_p_vector, from_to_vector) <= 0)
{
// 외적을 이용한 방향 벡터와 점 사이의 수직거리를 얻는다.
dist = pointToVectorDistance(p, from, to);
return true;
}
// 수선의 발이 선분 위에 없으면 양끝점과 p의 거리 중 최단 거리를 리턴
if (is_capsule)
{
dist = Math.Min(distance(from, p), distance(to, p));
return true;
}
return false;
}
//내적
public static float dot(Vector3 lhs, Vector3 rhs) { return lhs.X * rhs.X + lhs.Y * rhs.Y + lhs.Z * rhs.Z; }
// 내적을 이용한 두 방향 벡터 사이의 각도
public static float angle(Vector3 a_dir, Vector3 b_dir)
{
// sqrt(a) * sqrt(b) = sqrt(a * b) -- valid for real numbers
float denominator = MathHelper.sqrt(sqrMagnitude(a_dir) * sqrMagnitude(b_dir));
if (denominator < kEpsilonNormalSqrt)
return 0F;
float dotted = MathHelper.clamp(dot(a_dir, b_dir) / denominator, -1F, 1F);
float angle = MathHelper.acos(dotted);
return angle;
}
public static Vector3 dir(Vector3 to, Vector3 from) { return new Vector3(to.X - from.X, to.Y - from.Y, to.Z - from.Z); }
public static float magnitude(Vector3 vector) { return MathHelper.sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z); }
public static float sqrMagnitude(Vector3 vector) { return vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z; }
public static float distance(Vector3 a, Vector3 b)
{
Vector3 vec = new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
return MathHelper.sqrt(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
}
public static float distance(Vector3 a, Vector3 b, float radius_a, float radius_b)
{
Vector3 vec = new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
float distance = MathHelper.sqrt(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
distance = distance - (radius_a + radius_b);
distance = Math.Max(0, distance);
return distance;
}
public static bool checkDistanceXZ(Vector3 sourcePos, Vector3 targetPos, float maxDiffDist, out float distance)
{
distance = 0;
var source_pos = sourcePos;
var target_pos = targetPos;
source_pos.Y = target_pos.Y;
var diff_distance = Vector3Helper.distance(source_pos, target_pos);
if (maxDiffDist < diff_distance)
{
distance = diff_distance;
return false;
}
return true;
}
public static bool equals(Vector3 a, Vector3 b)
{
return a.X.Equals(b.X) && a.Y.Equals(b.Y) && a.Z.Equals(b.Z);
}
// Adds two vectors.
public static Vector3 add(Vector3 a, Vector3 b)
{
return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
public static Vector3 sub(Vector3 a, Vector3 b)
{
return new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
}
public static Vector3 multiple(Vector3 a, float b)
{
return new Vector3(a.X * b, a.Y * b, a.Z * b);
}
public static Vector3 division(Vector3 a, float b)
{
return new Vector3(a.X / b, a.Y / b, a.Z / b);
}
public static void dirVectorToDegree(Vector3 dir, out float degree, Vector3 toAxis)
{
degree = 0;
if (true == Vector3Helper.equals(Vector3Helper.forward, toAxis))
{
degree = MathHelper.atan2(dir.X, dir.Z) * (180f / MathHelper.PI);
}
else if (true == Vector3Helper.equals(Vector3Helper.right, toAxis))
{
degree = MathHelper.atan2(dir.Z, dir.X) * (180f / MathHelper.PI);
}
}
public static void degreeToDirVectorWithXY(float degree, out Vector3 dir, Vector3 toAxis)
{
dir = Vector3Helper.zero;
float rad = degree * MathHelper.Deg2Rad;
if (true == Vector3Helper.Equals(Vector3Helper.forward, toAxis))
{
float x = MathHelper.sin(rad);
float y = MathHelper.cos(rad);
dir = new Vector3(x, y, 0);
}
else if (true == Vector3Helper.Equals(Vector3Helper.right, toAxis))
{
float x = MathHelper.cos(rad);
float y = MathHelper.sin(rad);
dir = new Vector3(x, y, 0);
}
}
public static void degreeToDirVectorWithXZ(float degree, out Vector3 dir, Vector3 toAxis)
{
dir = Vector3Helper.zero;
float rad = degree * MathHelper.Deg2Rad;
if (true == Vector3Helper.Equals(Vector3Helper.forward, toAxis))
{
float x = MathHelper.sin(rad);
float z = MathHelper.cos(rad);
dir = new Vector3(x, 0, z);
}
else if (true == Vector3Helper.Equals(Vector3Helper.right, toAxis))
{
float x = MathHelper.cos(rad);
float z = MathHelper.sin(rad);
dir = new Vector3(x, 0, z);
}
}
public static Vector3 rotateVectorByDegree(float degree, Vector3 baseVector, Vector3 toAxis)
{
float rad = degree * MathHelper.Deg2Rad;
if (true == Vector3Helper.Equals(Vector3Helper.forward, toAxis))
{
return rotateVectorZForwardByRadian(rad, baseVector);
}
else if (true == Vector3Helper.Equals(Vector3Helper.right, toAxis))
{
return rotateVectorXRightByRadian(rad, baseVector);
}
return Vector3Helper.zero;
}
public static Vector3 rotateVectorZForwardByRadian(float radian, Vector3 baseVector)
{
//일단 2d x, z 값만 활용 한다.
float ca = MathHelper.cos(radian);
float sa = MathHelper.sin(radian);
// z축이 forward 이므로 x,z를 바꾼다.
return new Vector3( (baseVector.Z * sa + baseVector.X * ca)
, backwardVector.Y
, (baseVector.Z * ca - baseVector.X * sa));
}
public static Vector3 rotateVectorXRightByRadian(float radian, Vector3 baseVector)
{
// 일단 2d x, z 값만 활용 한다.
float ca = MathHelper.cos(radian);
float sa = MathHelper.sin(radian);
return new Vector3( (baseVector.X * ca - baseVector.Z * sa)
, backwardVector.Y
, (baseVector.X * sa + baseVector.Z * ca));
}
// Shorthand for writing @@Vector3(0, 0, 0)@@
// Shorthand for writing @@Vector3(1, 1, 1)@@
public static Vector3 one { get { return oneVector; } }
// Shorthand for writing @@Vector3(0, 0, 1)@@
public static Vector3 forward { get { return forwardVector; } }
public static Vector3 back { get { return backwardVector; } }
// Shorthand for writing @@Vector3(0, 1, 0)@@
public static Vector3 up { get { return upVector; } }
public static Vector3 down { get { return downVector; } }
public static Vector3 left { get { return leftVector; } }
// Shorthand for writing @@Vector3(1, 0, 0)@@
public static Vector3 right { get { return rightVector; } }
public static Vector3 angleOnAxisX(float angle)
{
return new Vector3(angle, 0.0f, 0.0f);
}
public static Vector3 angleOnAxisY(float angle)
{
return new Vector3(0.0f, angle, 0.0f);
}
public static Vector3 angleOnAxisZ(float angle)
{
return new Vector3(0.0f, 0.0f, angle);
}
// Shorthand for writing @@Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity)@@
public static Vector3 positiveInfinity { get { return positiveInfinityVector; } }
// Shorthand for writing @@Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity)@@
public static Vector3 negativeInfinity { get { return negativeInfinityVector; } }
public static string toString(Vector3 a)
{
return string.Format("({0:F1}, {1:F1}, {2:F1})", a.X, a.Y, a.Z);
}
// Returns a vector that is made from the smallest components of two vectors.
public static Vector3 min(Vector3 lhs, Vector3 rhs)
{
return new Vector3(MathHelper.min(lhs.X, rhs.X), MathHelper.min(lhs.Y, rhs.Y), MathHelper.min(lhs.Z, rhs.Z));
}
// Returns a vector that is made from the largest components of two vectors.
public static Vector3 max(Vector3 lhs, Vector3 rhs)
{
return new Vector3(MathHelper.max(lhs.X, rhs.X), MathHelper.max(lhs.Y, rhs.Y), MathHelper.max(lhs.Z, rhs.Z));
}
}