< Summary

Class:Towel.Mathematics.Quaternion<T>
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/Mathematics/Quaternion.cs
Covered lines:131
Uncovered lines:464
Coverable lines:595
Total lines:1173
Line coverage:22% (131 of 595)
Covered branches:27
Total branches:146
Branch coverage:18.4% (27 of 146)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: get_Identity()100%10%
File 1: get_X()100%10%
File 1: get_Y()100%10%
File 1: get_Z()100%10%
File 1: get_W()100%10%
File 1: get_DebuggerString()100%10%
File 1: .ctor(...)100%1100%
File 1: Factory_Matrix3x3(...)0%40%
File 1: Factory_Matrix4x4(...)0%80%
File 1: GetHasZeroMagnitude(...)0%60%
File 1: get_HasZeroMagnitude()100%10%
File 1: GetMagnitude(...)50%2100%
File 1: get_Magnitude()100%1100%
File 1: GetMagnitudeSquared(...)50%2100%
File 1: .cctor()100%1100%
File 1: get_MagnitudeSquared()100%1100%
File 1: Add(...)50%666.66%
File 1: Add(...)100%1100%
File 1: op_Addition(...)100%1100%
File 1: Add(...)100%10%
File 1: Add(...)100%10%
File 1: Subtract(...)50%666.66%
File 1: Subtract(...)100%1100%
File 1: op_Subtraction(...)100%1100%
File 1: Subtract(...)100%10%
File 1: Subtract(...)100%10%
File 1: Multiply(...)0%60%
File 1: .cctor()100%10%
File 1: .cctor()100%10%
File 1: Multiply(...)100%10%
File 1: op_Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)0%80%
File 1: .cctor()100%10%
File 1: .cctor()100%10%
File 1: Multiply(...)100%10%
File 1: op_Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)50%464.7%
File 1: Multiply(...)100%1100%
File 1: Multiply(...)100%10%
File 1: op_Multiply(...)100%1100%
File 1: op_Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Rotate(...)0%100%
File 1: Rotate(...)100%10%
File 1: Rotate(...)100%10%
File 1: Rotate(...)100%10%
File 1: Conjugate(...)50%464.7%
File 1: Conjugate(...)100%10%
File 1: Conjugate(...)100%10%
File 1: Conjugate()100%1100%
File 1: Normalize(...)50%466.66%
File 1: Normalize(...)100%10%
File 1: Normalize(...)100%10%
File 1: Normalize()100%1100%
File 1: Invert(...)0%60%
File 1: Invert(...)100%10%
File 1: Invert(...)100%10%
File 1: Invert()100%10%
File 1: LinearInterpolation(...)0%180%
File 1: LinearInterpolation(...)100%10%
File 1: LinearInterpolation(...)100%10%
File 1: LinearInterpolation(...)100%10%
File 1: SphericalInterpolation(...)0%80%
File 1: SphericalInterpolation(...)100%10%
File 1: SphericalInterpolation(...)100%10%
File 1: SphericalInterpolation(...)100%10%
File 1: ToMatrix3x3(...)0%160%
File 1: Equal(...)41.66%1252.94%
File 1: op_Equality(...)100%1100%
File 1: op_Inequality(...)100%10%
File 1: Equal(...)100%10%
File 1: Equal(...)66.66%1252.94%
File 1: Equal(...)100%1100%
File 1: Clone(...)0%20%
File 1: Clone()100%10%
File 1: GetHashCode()100%10%
File 1: Equals(...)0%20%

File(s)

/home/runner/work/Towel/Towel/Sources/Towel/Mathematics/Quaternion.cs

#LineLine coverage
 1using System.Diagnostics;
 2using System.Linq.Expressions;
 3using System.Text;
 4
 5namespace Towel.Mathematics;
 6
 7/// <summary>Standard 4-component quaternion [x, y, z, w]. W is the rotation ammount.</summary>
 8/// <typeparam name="T">The numeric type of this Quaternion.</typeparam>
 9[DebuggerDisplay("{" + nameof(DebuggerString) + "}")]
 10public class Quaternion<T>
 11{
 12  internal T _x;
 13  internal T _y;
 14  internal T _z;
 15  internal T _w;
 16
 17  #region Static Properties
 18
 19  /// <summary>Returns an identity quaternion (no rotation).</summary>
 20  public static Quaternion<T> Identity
 21  {
 22    get
 023    {
 024      return new Quaternion<T>(Constant<T>.Zero, Constant<T>.Zero, Constant<T>.Zero, Constant<T>.One);
 025    }
 26  }
 27
 28  #endregion
 29
 30  #region Properties
 31
 32  /// <summary>The X component of the quaternion. (axis, NOT rotation ammount)</summary>
 033  public T X { get { return _x; } set { _x = value; } }
 34  /// <summary>The Y component of the quaternion. (axis, NOT rotation ammount)</summary>
 035  public T Y { get { return _y; } set { _y = value; } }
 36  /// <summary>The Z component of the quaternion. (axis, NOT rotation ammount)</summary>
 037  public T Z { get { return _z; } set { _z = value; } }
 38  /// <summary>The W component of the quaternion. (rotation ammount, NOT axis)</summary>
 039  public T W { get { return _w; } set { _w = value; } }
 40
 41  #endregion
 42
 43  #region Debugger Properties
 44
 45  internal string DebuggerString
 46  {
 47    get
 048    {
 049      StringBuilder stringBuilder = new();
 050      stringBuilder.Append("[ ");
 051      stringBuilder.Append(_x);
 052      stringBuilder.Append(", ");
 053      stringBuilder.Append(_y);
 054      stringBuilder.Append(", ");
 055      stringBuilder.Append(_z);
 056      stringBuilder.Append(", ");
 057      stringBuilder.Append(_w);
 058      stringBuilder.Append(" ]");
 059      return stringBuilder.ToString();
 060    }
 61  }
 62
 63  #endregion
 64
 65  #region Constructors
 66
 67  /// <summary>Constructs a quaternion.</summary>
 68  /// <param name="x">The x component of the quaternion.</param>
 69  /// <param name="y">The y component of the quaternion.</param>
 70  /// <param name="z">The z component of the quaternion.</param>
 71  /// <param name="w">The w component of the quaternion.</param>
 161072  public Quaternion(T x, T y, T z, T w) { _x = x; _y = y; _z = z; _w = w; }
 73
 74  #endregion
 75
 76  #region Factories
 77
 78  ///// <summary>Creates a quaternion from an axis and rotation.</summary>
 79  ///// <param name="axis">The to create the quaternion from.</param>
 80  ///// <param name="angle">The angle to create the quaternion from.</param>
 81  ///// <returns>The newly created quaternion.</returns>
 82  // public static Quaternion<T> FactoryFromAxisAngle(Vector axis, T angle)
 83  // {
 84  //     throw new System.NotImplementedException();
 85  //     //if (axis.LengthSquared() is 0.0f)
 86  //     //    return FactoryIdentity;
 87  //     //T sinAngleOverAxisLength = Calc.Sin(angle / 2) / axis.Length();
 88  //     //return Quaternion<T>.Normalize(new Quaternion<T>(
 89  //     //    _multiply(axis.X, sinAngleOverAxisLength),
 90  //     //    axis.Y * sinAngleOverAxisLength,
 91  //     //    axis.Z * sinAngleOverAxisLength,
 92  //     //    Calc.Cos(angle / 2)));
 93  // }
 94
 95  /// <summary>Converts a 3x3 rotational matrix into a quaternion.</summary>
 96  /// <param name="matrix">The matrix to convert.</param>
 97  /// <returns>The rotation expressed as a quaternion.</returns>
 98  public static Quaternion<T> Factory_Matrix3x3(Matrix<T> matrix)
 099  {
 100    // Note: this method needs optimization
 101
 0102    if (matrix.Rows != 3 || matrix.Columns != 3)
 0103      throw new System.ArithmeticException("error converting matrix to quaternion. matrix is not 3x3.");
 104
 0105    T w = Statics.Subtraction(Statics.Addition(Constant<T>.One, matrix[0, 0], matrix[1, 1], matrix[2, 2]), Convert<int, 
 0106    return new Quaternion<T>(
 0107      Statics.Division(Statics.Subtraction(matrix[2, 1], matrix[1, 2]), Statics.Multiplication(Statics.Convert<int, T>(4
 0108      Statics.Division(Statics.Subtraction(matrix[0, 2], matrix[2, 0]), Statics.Multiplication(Statics.Convert<int, T>(4
 0109      Statics.Division(Statics.Subtraction(matrix[1, 0], matrix[0, 1]), Statics.Multiplication(Statics.Convert<int, T>(4
 0110      w);
 0111  }
 112
 113  /// <summary>Converts a 4x4 rotational matrix into a quaternion.</summary>
 114  /// <param name="matrix">The matrix to convert.</param>
 115  /// <returns>The rotation expressed as a quaternion.</returns>
 116  public static Quaternion<T> Factory_Matrix4x4(Matrix<T> matrix)
 0117  {
 118    // Note: this method needs optimization
 119
 0120    matrix = matrix.Transpose();
 121    T w, x, y, z;
 0122    T diagonal = Statics.Addition(matrix[0, 0], matrix[1, 1], matrix[2, 2]);
 0123    if (Statics.GreaterThan(diagonal, Constant<T>.Zero))
 0124    {
 0125      T w4 = Statics.Multiplication(Statics.SquareRoot(Statics.Addition(diagonal, Constant<T>.One)), Statics.Convert<int
 0126      w = Statics.Division(w4, Convert<int, T>(4));
 0127      x = Statics.Division(Statics.Subtraction(matrix[2, 1], matrix[1, 2]), w4);
 0128      y = Statics.Division(Statics.Subtraction(matrix[0, 2], matrix[2, 0]), w4);
 0129      z = Statics.Division(Statics.Subtraction(matrix[1, 0], matrix[0, 1]), w4);
 0130    }
 0131    else if (Statics.GreaterThan(matrix[0, 0], matrix[1, 1]) && Statics.GreaterThan(matrix[0, 0], matrix[2, 2]))
 0132    {
 0133      T x4 = Statics.Multiplication(Statics.SquareRoot(Statics.Subtraction(Statics.Subtraction(Statics.Addition(Constant
 0134      w = Statics.Division(Statics.Subtraction(matrix[2, 1], matrix[1, 2]), x4);
 0135      x = Statics.Division(x4, Convert<int, T>(4));
 0136      y = Statics.Division(Statics.Addition(matrix[0, 1], matrix[1, 0]), x4);
 0137      z = Statics.Division(Statics.Addition(matrix[0, 2], matrix[2, 0]), x4);
 0138    }
 0139    else if (Statics.GreaterThan(matrix[1, 1], matrix[2, 2]))
 0140    {
 0141      T y4 = Statics.Multiplication(Statics.SquareRoot(Statics.Subtraction(Statics.Subtraction(Statics.Addition(Constant
 0142      w = Statics.Division(Statics.Subtraction(matrix[0, 2], matrix[2, 0]), y4);
 0143      x = Statics.Division(Statics.Addition(matrix[0, 1], matrix[1, 0]), y4);
 0144      y = Statics.Division(y4, Convert<int, T>(4));
 0145      z = Statics.Division(Statics.Addition(matrix[1, 2], matrix[2, 1]), y4);
 0146    }
 147    else
 0148    {
 0149      T z4 = Statics.Multiplication(Statics.SquareRoot(Statics.Subtraction(Statics.Subtraction(Statics.Addition(Constant
 0150      w = Statics.Division(Statics.Subtraction(matrix[1, 0], matrix[0, 1]), z4);
 0151      x = Statics.Division(Statics.Addition(matrix[0, 2], matrix[2, 0]), z4);
 0152      y = Statics.Division(Statics.Addition(matrix[1, 2], matrix[2, 1]), z4);
 0153      z = Statics.Division(z4, Convert<int, T>(4));
 0154    }
 0155    return new Quaternion<T>(x, y, z, w);
 0156  }
 157
 158  #endregion
 159
 160  #region Mathematics
 161
 162  #region HasZeroMagnitude
 163
 164  /// <summary>Checks quaternion for zero magnitude.</summary>
 165  /// <param name="a">The quaternion to check for zero magnitude.</param>
 166  /// <returns>True if the quaternion has zero magnitude. False if not.</returns>
 167  public static bool GetHasZeroMagnitude(Quaternion<T> a)
 0168  {
 0169    return
 0170      Statics.Equate(a._x, Constant<T>.Zero) &&
 0171      Statics.Equate(a._y, Constant<T>.Zero) &&
 0172      Statics.Equate(a._z, Constant<T>.Zero) &&
 0173      Statics.Equate(a._w, Constant<T>.Zero);
 0174  }
 175
 176  /// <summary>Checks quaternion for zero magnitude.</summary>
 177  public bool HasZeroMagnitude
 178  {
 179    get
 0180    {
 0181      return GetHasZeroMagnitude(this);
 0182    }
 183  }
 184
 185  #endregion
 186
 187  #region Magnitude
 188
 189  /// <summary>Computes the magnitude of this quaternion.</summary>
 190  /// <param name="a">The <see cref="Quaternion{T}"/> to get the magnitude of.</param>
 191  /// <returns>The magnitude of this quaternion.</returns>
 192  public static T GetMagnitude(Quaternion<T> a)
 12193  {
 12194    if (a is null) throw new ArgumentNullException(nameof(a));
 12195    return SquareRoot(GetMagnitudeSquared(a));
 12196  }
 197
 198  /// <summary>Computes the magnitude of this quaternion.</summary>
 12199  public T Magnitude => GetMagnitude(this);
 200
 201  #endregion
 202
 203  #region MagnitudeSquared
 204
 205  /// <summary>Computes the magnitude of this quaternion, but doesn't square root it for
 206  /// possible optimization purposes.</summary>
 207  /// <param name="a">The <see cref="Quaternion{T}"/> to get the magnitude squared of.</param>
 208  /// <returns>The squared length of the quaternion.</returns>
 209  public static T GetMagnitudeSquared(Quaternion<T> a)
 18210  {
 18211    if (a is null) throw new ArgumentNullException(nameof(a));
 18212    return GetMagnitudeSquaredImplementation.Function(a._x, a._y, a._z, a._w);
 18213  }
 214
 215  internal static class GetMagnitudeSquaredImplementation
 216  {
 3217    internal static Func<T, T, T, T, T> Function = (T x, T y, T z, T w) =>
 3218    {
 3219      ParameterExpression X = Expression.Parameter(typeof(T));
 3220      ParameterExpression Y = Expression.Parameter(typeof(T));
 3221      ParameterExpression Z = Expression.Parameter(typeof(T));
 3222      ParameterExpression W = Expression.Parameter(typeof(T));
 3223      Expression BODY =
 3224        Expression.Add(Expression.Multiply(X, X),
 3225          Expression.Add(Expression.Multiply(Y, Y),
 3226            Expression.Add(Expression.Multiply(Z, Z),
 3227              Expression.Multiply(W, W))));
 3228      Function = Expression.Lambda<Func<T, T, T, T, T>>(BODY, X, Y, Z, W).Compile();
 3229      return Function(x, y, z, w);
 6230    };
 231  }
 232
 233  /// <summary>Computes the magnitude of this quaternion, but doesn't square root it for
 234  /// possible optimization purposes.</summary>
 6235  public T MagnitudeSquared => GetMagnitudeSquared(this);
 236
 237  #endregion
 238
 239  #region Add
 240
 241  /// <summary>Adds two quaternions together.</summary>
 242  /// <param name="a">The first quaternion of the addition.</param>
 243  /// <param name="b">The second quaternion of the addiiton.</param>
 244  /// <param name="c">The result of the addition.</param>
 245  public static void Add(Quaternion<T> a, Quaternion<T> b, ref Quaternion<T>? c)
 8246  {
 8247    if (a is null) throw new ArgumentNullException(nameof(a));
 8248    if (b is null) throw new ArgumentNullException(nameof(b));
 8249    T x = Addition(a._x, b._x);
 8250    T y = Addition(a._y, b._y);
 8251    T z = Addition(a._z, b._z);
 8252    T w = Addition(a._w, b._w);
 8253    if (c is null)
 8254    {
 8255      c = new Quaternion<T>(x, y, z, w);
 8256    }
 257    else
 0258    {
 0259      c._x = x;
 0260      c._y = y;
 0261      c._z = z;
 0262      c._w = w;
 0263    }
 8264  }
 265
 266  /// <summary>Adds two quaternions together.</summary>
 267  /// <param name="a">The first vector of the addition.</param>
 268  /// <param name="b">The second vector of the addiiton.</param>
 269  /// <returns>The result of the addition.</returns>
 270  public static Quaternion<T> Add(Quaternion<T> a, Quaternion<T> b)
 8271  {
 8272    Quaternion<T>? c = null;
 8273    Add(a, b, ref c);
 8274    return c!;
 8275  }
 276
 277  /// <summary>Adds two quaternions together.</summary>
 278  /// <param name="a">The first quaternion of the addition.</param>
 279  /// <param name="b">The second quaternion of the addition.</param>
 280  /// <returns>The result of the addition.</returns>
 8281  public static Quaternion<T> operator +(Quaternion<T> a, Quaternion<T> b) => Add(a, b);
 282
 283  /// <summary>Adds two quaternions together.</summary>
 284  /// <param name="b">The second quaternion of the addititon.</param>
 285  /// <param name="c">The result of the addition.</param>
 0286  public void Add(Quaternion<T> b, ref Quaternion<T>? c) => Add(this, b, ref c);
 287
 288  /// <summary>Adds two quaternions together.</summary>
 289  /// <param name="b">The quaternion to add to this one.</param>
 290  /// <returns>The result of the addition.</returns>
 0291  public Quaternion<T> Add(Quaternion<T> b) => this + b;
 292
 293  #endregion
 294
 295  #region Subtract
 296
 297  /// <summary>Subtracts two quaternions.</summary>
 298  /// <param name="a">The first quaternion of the subtraction.</param>
 299  /// <param name="b">The second quaternion of the subtraction.</param>
 300  /// <param name="c">The result of the subtraction.</param>
 301  public static void Subtract(Quaternion<T> a, Quaternion<T> b, ref Quaternion<T>? c)
 8302  {
 8303    if (a is null) throw new ArgumentNullException(nameof(a));
 8304    if (b is null) throw new ArgumentNullException(nameof(b));
 8305    T x = Subtraction(a._x, b._x);
 8306    T y = Subtraction(a._y, b._y);
 8307    T z = Subtraction(a._z, b._z);
 8308    T w = Subtraction(a._w, b._w);
 8309    if (c is null)
 8310    {
 8311      c = new Quaternion<T>(x, y, z, w);
 8312    }
 313    else
 0314    {
 0315      c._x = x;
 0316      c._y = y;
 0317      c._z = z;
 0318      c._w = w;
 0319    }
 8320  }
 321
 322  /// <summary>Subtracts two quaternions.</summary>
 323  /// <param name="a">The first vector of the subtraction.</param>
 324  /// <param name="b">The second vector of the subtraction.</param>
 325  /// <returns>The result of the subtraction.</returns>
 326  public static Quaternion<T> Subtract(Quaternion<T> a, Quaternion<T> b)
 8327  {
 8328    Quaternion<T>? c = null;
 8329    Subtract(a, b, ref c);
 8330    return c!;
 8331  }
 332
 333  /// <summary>Subtracts two quaternions.</summary>
 334  /// <param name="a">The first quaternion of the subtraction.</param>
 335  /// <param name="b">The second quaternion of the subtraction.</param>
 336  /// <returns>The result of the subtraction.</returns>
 8337  public static Quaternion<T> operator -(Quaternion<T> a, Quaternion<T> b) => Subtract(a, b);
 338
 339  /// <summary>Subtracts two quaternions.</summary>
 340  /// <param name="b">The second quaternion of the subtraction.</param>
 341  /// <param name="c">The result of the subtraction.</param>
 0342  public void Subtract(Quaternion<T> b, ref Quaternion<T>? c) => Subtract(this, b, ref c);
 343
 344  /// <summary>Subtracts two quaternions together.</summary>
 345  /// <param name="b">The second quaternion of the subtraction.</param>
 346  /// <returns>The result of the subtraction.</returns>
 0347  public Quaternion<T> Subtract(Quaternion<T> b) => this - b;
 348
 349  #endregion
 350
 351  #region Multiply (Quaternion * Quaternion)
 352
 353  /// <summary>Multiplies two quaternions.</summary>
 354  /// <param name="a">The first quaternion of the multiplication.</param>
 355  /// <param name="b">The second quaternion of the multiplication.</param>
 356  /// <param name="c">The resulting quaternion after the multiplication.</param>
 357  internal static void Multiply(Quaternion<T> a, Quaternion<T> b, ref Quaternion<T>? c)
 0358  {
 0359    if (a is null) throw new ArgumentNullException(nameof(a));
 0360    if (b is null) throw new ArgumentNullException(nameof(b));
 0361    T x = QuaternionMiltiplyXYZComponentImplementation.Function(a.X, b.W, a.W, b.X, a.Y, b.Z, a.Z, b.Y);
 0362    T y = QuaternionMiltiplyXYZComponentImplementation.Function(a.Y, b.W, a.W, b.Y, a.Z, b.X, a.X, b.Z);
 0363    T z = QuaternionMiltiplyXYZComponentImplementation.Function(a.Z, b.W, a.W, b.Z, a.X, b.Y, a.Y, b.X);
 0364    T w = QuaternionMiltiplyWComponentImplementation.Function(a.W, b.W, a.X, b.X, a.Y, b.Y, a.Z, b.Z);
 0365    if (c is null)
 0366    {
 0367      c = new Quaternion<T>(x, y, z, w);
 0368    }
 369    else
 0370    {
 0371      c._x = x;
 0372      c._y = y;
 0373      c._z = z;
 0374      c._w = w;
 0375    }
 0376  }
 377
 378  internal static class QuaternionMiltiplyXYZComponentImplementation
 379  {
 0380    internal static Func<T, T, T, T, T, T, T, T, T> Function = (T a, T b, T c, T d, T e, T f, T g, T h) =>
 0381    {
 0382      // parameters
 0383      ParameterExpression A = Expression.Parameter(typeof(T));
 0384      ParameterExpression B = Expression.Parameter(typeof(T));
 0385      ParameterExpression C = Expression.Parameter(typeof(T));
 0386      ParameterExpression D = Expression.Parameter(typeof(T));
 0387      ParameterExpression E = Expression.Parameter(typeof(T));
 0388      ParameterExpression F = Expression.Parameter(typeof(T));
 0389      ParameterExpression G = Expression.Parameter(typeof(T));
 0390      ParameterExpression H = Expression.Parameter(typeof(T));
 0391      // multiply
 0392      Expression AB = Expression.Multiply(A, B);
 0393      Expression CD = Expression.Multiply(C, D);
 0394      Expression EF = Expression.Multiply(E, F);
 0395      Expression GH = Expression.Multiply(G, H);
 0396      // add
 0397      Expression AB_add_CD = Expression.Add(AB, CD);
 0398      Expression AB_add_CD_add_EF = Expression.Add(AB_add_CD, EF);
 0399      // subtract
 0400      Expression AB_add_CD_add_EF_subtract_GH = Expression.Subtract(AB_add_CD_add_EF, GH);
 0401      // compile
 0402      Expression BODY = AB_add_CD_add_EF_subtract_GH;
 0403      Function = Expression.Lambda<Func<T, T, T, T, T, T, T, T, T>>(BODY, A, B, C, D, E, F, G, H).Compile();
 0404      return Function(a, b, c, d, e, f, g, h);
 0405    };
 406  }
 407
 408  internal static class QuaternionMiltiplyWComponentImplementation
 409  {
 0410    internal static Func<T, T, T, T, T, T, T, T, T> Function = (T a, T b, T c, T d, T e, T f, T g, T h) =>
 0411    {
 0412      // parameters
 0413      ParameterExpression A = Expression.Parameter(typeof(T));
 0414      ParameterExpression B = Expression.Parameter(typeof(T));
 0415      ParameterExpression C = Expression.Parameter(typeof(T));
 0416      ParameterExpression D = Expression.Parameter(typeof(T));
 0417      ParameterExpression E = Expression.Parameter(typeof(T));
 0418      ParameterExpression F = Expression.Parameter(typeof(T));
 0419      ParameterExpression G = Expression.Parameter(typeof(T));
 0420      ParameterExpression H = Expression.Parameter(typeof(T));
 0421      // multiply
 0422      Expression AB = Expression.Multiply(A, B);
 0423      Expression CD = Expression.Multiply(C, D);
 0424      Expression EF = Expression.Multiply(E, F);
 0425      Expression GH = Expression.Multiply(G, H);
 0426      // subtract
 0427      Expression AB_subtract_CD = Expression.Subtract(AB, CD);
 0428      Expression AB_subtract_CD_subtract_EF = Expression.Subtract(AB_subtract_CD, EF);
 0429      Expression AB_subtract_CD_subtract_EF_subtract_GH = Expression.Subtract(AB_subtract_CD_subtract_EF, GH);
 0430      // compile
 0431      Expression BODY = AB_subtract_CD_subtract_EF_subtract_GH;
 0432      Function = Expression.Lambda<Func<T, T, T, T, T, T, T, T, T>>(BODY, A, B, C, D, E, F, G, H).Compile();
 0433      return Function(a, b, c, d, e, f, g, h);
 0434    };
 435  }
 436
 437  /// <summary>Multiplies two quaternions.</summary>
 438  /// <param name="a">The first quaternion of the multiplication.</param>
 439  /// <param name="b">The second quaternion of the multiplication.</param>
 440  /// <returns>The resulting quaternion after the multiplication.</returns>
 441  public static Quaternion<T> Multiply(Quaternion<T> a, Quaternion<T> b)
 0442  {
 0443    Quaternion<T>? c = null;
 0444    Multiply(a, b, ref c);
 0445    return c!;
 0446  }
 447
 448  /// <summary>Multiplies two quaternions.</summary>
 449  /// <param name="a">The first quaternion of the multiplication.</param>
 450  /// <param name="b">The second quaternion of the multiplication.</param>
 451  /// <returns>The resulting quaternion after the multiplication.</returns>
 0452  public static Quaternion<T> operator *(Quaternion<T> a, Quaternion<T> b) => Multiply(a, b);
 453
 454  /// <summary>Multiplies two quaternions.</summary>
 455  /// <param name="b">The second quaternion of the multiplication.</param>
 456  /// <param name="c">The resulting quaternion after the multiplication.</param>
 0457  public void Multiply(Quaternion<T> b, ref Quaternion<T>? c) => Multiply(this, b, ref c);
 458
 459  /// <summary>Multiplies two quaternions.</summary>
 460  /// <param name="b">The second quaternion of the multiplication.</param>
 461  /// <returns>The resulting quaternion after the multiplication.</returns>
 0462  public Quaternion<T> Multiply(Quaternion<T> b) => this * b;
 463
 464  #endregion
 465
 466  #region Multiply (Quaternion * Vector)
 467
 468  /// <summary>Multiplies a quaternion and a vector.</summary>
 469  /// <param name="a">The quaternion of the multiplication.</param>
 470  /// <param name="b">The vector of the multiplication.</param>
 471  /// <param name="c">The resulting quaternion after the multiplication.</param>
 472  public static void Multiply(Quaternion<T> a, Vector<T> b, ref Quaternion<T>? c)
 0473  {
 0474    if (a is null) throw new ArgumentNullException(nameof(a));
 0475    if (b is null) throw new ArgumentNullException(nameof(b));
 0476    if (sourceof(b.Dimensions != 3, out string c1)) throw new ArgumentException(c1);
 0477    T x = QuaternionMiltiplyVectorXYZComponentImplementation.Function(a.W, b.X, a.Y, b.Z, a.Z, b.Y);
 0478    T y = QuaternionMiltiplyVectorXYZComponentImplementation.Function(a.W, b.Y, a.Z, b.X, a.X, b.Z);
 0479    T z = QuaternionMiltiplyVectorXYZComponentImplementation.Function(a.W, b.Z, a.X, b.Y, a.Y, b.X);
 0480    T w = QuaternionMiltiplyVectorWComponentImplementation.Function(a.X, b.X, a.Y, b.Y, a.Z, b.Z);
 0481    if (c is null)
 0482    {
 0483      c = new Quaternion<T>(x, y, z, w);
 0484    }
 485    else
 0486    {
 0487      c._x = x;
 0488      c._y = y;
 0489      c._z = z;
 0490      c._w = w;
 0491    }
 0492  }
 493
 494  internal static class QuaternionMiltiplyVectorXYZComponentImplementation
 495  {
 0496    internal static Func<T, T, T, T, T, T, T> Function = (T a, T b, T c, T d, T e, T f) =>
 0497    {
 0498      // parameters
 0499      ParameterExpression A = Expression.Parameter(typeof(T));
 0500      ParameterExpression B = Expression.Parameter(typeof(T));
 0501      ParameterExpression C = Expression.Parameter(typeof(T));
 0502      ParameterExpression D = Expression.Parameter(typeof(T));
 0503      ParameterExpression E = Expression.Parameter(typeof(T));
 0504      ParameterExpression F = Expression.Parameter(typeof(T));
 0505      // multiply
 0506      Expression AB = Expression.Multiply(A, B);
 0507      Expression CD = Expression.Multiply(C, D);
 0508      Expression EF = Expression.Multiply(E, F);
 0509      // add
 0510      Expression AB_add_CD = Expression.Add(AB, CD);
 0511      // subtract
 0512      Expression AB_add_CD_subtract_EF = Expression.Subtract(AB_add_CD, EF);
 0513      // compile
 0514      Expression BODY = AB_add_CD_subtract_EF;
 0515      Function = Expression.Lambda<Func<T, T, T, T, T, T, T>>(BODY, A, B, C, D, E, F).Compile();
 0516      return Function(a, b, c, d, e, f);
 0517    };
 518  }
 519
 520  internal static class QuaternionMiltiplyVectorWComponentImplementation
 521  {
 0522    internal static Func<T, T, T, T, T, T, T> Function = (T a, T b, T c, T d, T e, T f) =>
 0523    {
 0524      // parameters
 0525      ParameterExpression A = Expression.Parameter(typeof(T));
 0526      ParameterExpression B = Expression.Parameter(typeof(T));
 0527      ParameterExpression C = Expression.Parameter(typeof(T));
 0528      ParameterExpression D = Expression.Parameter(typeof(T));
 0529      ParameterExpression E = Expression.Parameter(typeof(T));
 0530      ParameterExpression F = Expression.Parameter(typeof(T));
 0531      // multiply
 0532      Expression nAB = Expression.Multiply(Expression.Negate(A), B);
 0533      Expression CD = Expression.Multiply(C, D);
 0534      Expression EF = Expression.Multiply(E, F);
 0535      // subtract
 0536      Expression nAB_subtract_CD = Expression.Subtract(nAB, CD);
 0537      Expression nAB_subtract_CD_subtract_EF = Expression.Subtract(nAB_subtract_CD, EF);
 0538      // compile
 0539      Expression BODY = nAB_subtract_CD_subtract_EF;
 0540      Function = Expression.Lambda<Func<T, T, T, T, T, T, T>>(BODY, A, B, C, D, E, F).Compile();
 0541      return Function(a, b, c, d, e, f);
 0542    };
 543  }
 544
 545  /// <summary>Multiplies a quaternion and a vector.</summary>
 546  /// <param name="a">The quaternion of the multiplication.</param>
 547  /// <param name="b">The vector of the multiplication.</param>
 548  /// <returns>The resulting quaternion after the multiplication.</returns>
 549  public static Quaternion<T> Multiply(Quaternion<T> a, Vector<T> b)
 0550  {
 0551    Quaternion<T>? c = null;
 0552    Multiply(a, b, ref c);
 0553    return c!;
 0554  }
 555
 556  /// <summary>Multiplies a quaternion and a vector.</summary>
 557  /// <param name="a">The quaternion of the multiplication.</param>
 558  /// <param name="b">The vector of the multiplication.</param>
 559  /// <returns>The resulting quaternion after the multiplication.</returns>
 0560  public static Quaternion<T> operator *(Quaternion<T> a, Vector<T> b) => Multiply(a, b);
 561
 562  /// <summary>Multiplies a quaternion and a vector.</summary>
 563  /// <param name="b">The vector of the multiplication.</param>
 564  /// <param name="c">The resulting quaternion after the multiplication.</param>
 0565  public void Multiply(Vector<T> b, ref Quaternion<T>? c) => Multiply(this, b, ref c);
 566
 567  /// <summary>Multiplies a quaternion and a vector.</summary>
 568  /// <param name="b">The vector of the multiplication.</param>
 569  /// <returns>The resulting quaternion after the multiplication.</returns>
 0570  public Quaternion<T> Multiply(Vector<T> b) => this * b;
 571
 572  #endregion
 573
 574  #region Multiply (Quaternion * Scalar)
 575
 576  /// <summary>Multiplies all the values in a quaternion by a scalar.</summary>
 577  /// <param name="a">The quaternion to have the values multiplied.</param>
 578  /// <param name="b">The scalar to multiply the values by.</param>
 579  /// <param name="c">The resulting quaternion after the multiplications.</param>
 580  internal static void Multiply(Quaternion<T> a, T b, ref Quaternion<T>? c)
 8581  {
 8582    if (a is null) throw new ArgumentNullException(nameof(a));
 8583    T x = Multiplication(a._x, b);
 8584    T y = Multiplication(a._y, b);
 8585    T z = Multiplication(a._z, b);
 8586    T w = Multiplication(a._w, b);
 8587    if (c is null)
 8588    {
 8589      c = new Quaternion<T>(x, y, z, w);
 8590    }
 591    else
 0592    {
 0593      c._x = x;
 0594      c._y = y;
 0595      c._z = z;
 0596      c._w = w;
 0597    }
 8598  }
 599
 600  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 601  /// <param name="a">The matrix to have the values multiplied.</param>
 602  /// <param name="b">The scalar to multiply the values by.</param>
 603  /// <returns>The resulting quaternion after the multiplications.</returns>
 604  public static Quaternion<T> Multiply(Quaternion<T> a, T b)
 8605  {
 8606    Quaternion<T>? c = null;
 8607    Multiply(a, b, ref c);
 8608    return c!;
 8609  }
 610
 611  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 612  /// <param name="b">The scalar to multiply the values by.</param>
 613  /// <param name="a">The quaternion to have the values multiplied.</param>
 614  /// <returns>The resulting quaternion after the multiplications.</returns>
 0615  public static Quaternion<T> Multiply(T b, Quaternion<T> a) => Multiply(a, b);
 616
 617  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 618  /// <param name="a">The quaternion to have the values multiplied.</param>
 619  /// <param name="b">The scalar to multiply the values by.</param>
 620  /// <returns>The resulting quaternion after the multiplications.</returns>
 8621  public static Quaternion<T> operator *(Quaternion<T> a, T b) => Multiply(a, b);
 622
 623  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 624  /// <param name="b">The scalar to multiply the values by.</param>
 625  /// <param name="a">The quaternion to have the values multiplied.</param>
 626  /// <returns>The resulting quaternion after the multiplications.</returns>
 0627  public static Quaternion<T> operator *(T b, Quaternion<T> a) => Multiply(b, a);
 628
 629  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 630  /// <param name="b">The scalar to multiply the values by.</param>
 631  /// <param name="c">The resulting quaternion after the multiplications.</param>
 0632  public void Multiply(T b, ref Quaternion<T>? c) => Multiply(this, b, ref c);
 633
 634  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 635  /// <param name="b">The scalar to multiply the values by.</param>
 636  /// <returns>The resulting matrix after the multiplications.</returns>
 0637  public Quaternion<T> Multiply(T b) => this * b;
 638
 639  #endregion
 640
 641  #region Rotate
 642
 643  /// <summary>Rotates a vector by a quaternion rotation [v' = qvq'].</summary>
 644  /// <param name="a">The quaternion rotation to rotate the vector by.</param>
 645  /// <param name="b">The vector to rotate.</param>
 646  /// <param name="c">The result of the rotation.</param>
 647  public static void Rotate(Quaternion<T> a, Vector<T> b, ref Vector<T>? c)
 0648  {
 0649    if (a is null) throw new ArgumentNullException(nameof(a));
 0650    if (b is null) throw new ArgumentNullException(nameof(b));
 0651    if (sourceof(b.Dimensions != 3, out string c1)) throw new ArgumentException(c1);
 0652    if (c is null || c.Dimensions != 3)
 0653    {
 0654      c = new Vector<T>(3);
 0655    }
 0656    Quaternion<T>? d = null;
 0657    Multiply(a, b, ref d);
 0658    Multiply(a.Conjugate(), d!, ref d!); // need to prevent this heep allocation on "a.Conjugate()" in future update
 0659    c.X = d.X;
 0660    c.Y = d.Y;
 0661    c.X = d.W;
 0662  }
 663
 664  /// <summary>Rotates a vector by a quaternion rotation [v' = qvq'].</summary>
 665  /// <param name="a">The quaternion rotation to rotate the vector by.</param>
 666  /// <param name="b">The vector to rotate.</param>
 667  /// <returns>The result of the rotation.</returns>
 668  public static Vector<T> Rotate(Quaternion<T> a, Vector<T> b)
 0669  {
 0670    Vector<T>? c = null;
 0671    Rotate(a, b, ref c);
 0672    return c!;
 0673  }
 674
 675  /// <summary>Rotates a vector by a quaternion rotation [v' = qvq'].</summary>
 676  /// <param name="b">The vector to rotate.</param>
 677  /// <param name="c">The result of the rotation.</param>
 678  public void Rotate(Vector<T> b, ref Vector<T>? c)
 0679  {
 0680    Rotate(this, b, ref c);
 0681  }
 682
 683  /// <summary>Rotates a vector by a quaternion rotation [v' = qvq'].</summary>
 684  /// <param name="b">The vector to rotate.</param>
 685  /// <returns>The result of the rotation.</returns>
 686  public Vector<T> Rotate(Vector<T> b)
 0687  {
 0688    Vector<T>? c = null;
 0689    Rotate(this, b, ref c);
 0690    return c!;
 0691  }
 692
 693  #endregion
 694
 695  #region Conjugate
 696
 697  /// <summary>Conjugates a quaternion.</summary>
 698  /// <param name="a">The quaternion to conjugate.</param>
 699  /// <param name="b">The result of the conjugation.</param>
 700  public static void Conjugate(Quaternion<T> a, ref Quaternion<T>? b)
 8701  {
 8702    if (a is null) throw new ArgumentNullException(nameof(a));
 8703    T x = Negation(a._x);
 8704    T y = Negation(a._y);
 8705    T z = Negation(a._z);
 8706    T w = a._w;
 8707    if (b is null)
 8708    {
 8709      b = new Quaternion<T>(x, y, z, w);
 8710    }
 711    else
 0712    {
 0713      b._x = x;
 0714      b._y = y;
 0715      b._z = z;
 0716      b._w = w;
 0717    }
 8718  }
 719
 720  /// <summary>Conjugates a quaternion.</summary>
 721  /// <param name="a">The quaternion to conjugate.</param>
 722  /// <returns>The result of the conjugation.</returns>
 723  public static Quaternion<T> Conjugate(Quaternion<T> a)
 0724  {
 0725    Quaternion<T>? b = null;
 0726    Conjugate(a, ref b);
 0727    return b!;
 0728  }
 729
 730  /// <summary>Conjugates a quaternion.</summary>
 731  /// <param name="b">The result of the conjugation.</param>
 0732  public void Conjugate(ref Quaternion<T>? b) => Conjugate(this, ref b);
 733
 734  /// <summary>Conjugates a quaternion.</summary>
 735  /// <returns>The result of the conjugation.</returns>
 736  public Quaternion<T> Conjugate()
 8737  {
 8738    Quaternion<T>? b = null;
 8739    Conjugate(this, ref b);
 8740    return b!;
 8741  }
 742
 743  #endregion
 744
 745  #region Normalize
 746
 747  /// <summary>Normalizes a quaternion.</summary>
 748  /// <param name="a">The quaternion to normalize.</param>
 749  /// <param name="b">The result of the normalization.</param>
 750  public static void Normalize(Quaternion<T> a, ref Quaternion<T>? b)
 6751  {
 6752    if (a is null) throw new ArgumentNullException(nameof(a));
 6753    T magnitude = a.Magnitude;
 6754    T x = Division(a._x, magnitude);
 6755    T y = Division(a._y, magnitude);
 6756    T z = Division(a._z, magnitude);
 6757    T w = Division(a._w, magnitude);
 6758    if (b is null)
 6759    {
 6760      b = new Quaternion<T>(x, y, z, w);
 6761    }
 762    else
 0763    {
 0764      b._x = x;
 0765      b._y = y;
 0766      b._z = z;
 0767      b._w = w;
 0768    }
 6769  }
 770
 771  /// <summary>Normalizes a quaternion.</summary>
 772  /// <param name="a">The quaternion to normalize.</param>
 773  /// <returns>The result of the normalization.</returns>
 774  public static Quaternion<T> Normalize(Quaternion<T> a)
 0775  {
 0776    Quaternion<T>? b = null;
 0777    Normalize(a, ref b);
 0778    return b!;
 0779  }
 780
 781  /// <summary>Normalizes a quaternion.</summary>
 782  /// <param name="b">The result of the normalization.</param>
 0783  public void Normalize(ref Quaternion<T>? b) => Normalize(this, ref b);
 784
 785  /// <summary>Normalizes a quaternion.</summary>
 786  /// <returns>The result of the normalization.</returns>
 787  public Quaternion<T> Normalize()
 6788  {
 6789    Quaternion<T>? b = null;
 6790    Normalize(this, ref b);
 6791    return b!;
 6792  }
 793
 794  #endregion
 795
 796  #region Invert
 797
 798  /// <summary>Inverts a quaternion.</summary>
 799  /// <param name="a">The quaternion to invert.</param>
 800  /// <param name="b">The result of the inversion.</param>
 801  public static void Invert(Quaternion<T> a, ref Quaternion<T>? b)
 0802  {
 803    // Note: I think this function is incorrect. Need to research.
 804
 0805    if (a is null) throw new ArgumentNullException(nameof(a));
 0806    T magnitudeSquared = a.MagnitudeSquared;
 807    T x;
 808    T y;
 809    T z;
 810    T w;
 0811    if (Equate(magnitudeSquared, Constant<T>.Zero))
 0812    {
 0813      x = a._x;
 0814      y = a._y;
 0815      z = a._z;
 0816      w = a._w;
 0817    }
 818    else
 0819    {
 0820      x = Multiplication(Negation(a.X), magnitudeSquared);
 0821      y = Multiplication(Negation(a.Y), magnitudeSquared);
 0822      z = Multiplication(Negation(a.Z), magnitudeSquared);
 0823      w = Multiplication(a.W, magnitudeSquared);
 0824    }
 0825    if (b is null)
 0826    {
 0827      b = new Quaternion<T>(x, y, z, w);
 0828    }
 829    else
 0830    {
 0831      b._x = x;
 0832      b._y = y;
 0833      b._z = z;
 0834      b._w = w;
 0835    }
 0836  }
 837
 838  /// <summary>Inverts a quaternion.</summary>
 839  /// <param name="a">The quaternion to invert.</param>
 840  /// <returns>The result of the inversion.</returns>
 841  public static Quaternion<T> Invert(Quaternion<T> a)
 0842  {
 0843    Quaternion<T>? b = null;
 0844    Invert(a, ref b);
 0845    return b!;
 0846  }
 847
 848  /// <summary>Inverts a quaternion.</summary>
 849  /// <param name="b">The result of the inversion.</param>
 0850  public void Invert(ref Quaternion<T>? b) => Invert(this, ref b);
 851
 852  /// <summary>Inverts a quaternion.</summary>
 853  /// <returns>The result of the inversion.</returns>
 854  public Quaternion<T> Invert()
 0855  {
 0856    Quaternion<T>? b = null;
 0857    Invert(this, ref b);
 0858    return b!;
 0859  }
 860
 861  #endregion
 862
 863  #region LinearInterpolation
 864
 865  /// <summary>Linear interpolation for quaternions.</summary>
 866  /// <param name="a">The min of the interpolation.</param>
 867  /// <param name="b">The max of the interpolation.</param>
 868  /// <param name="blend">The blending point of the interpolation.</param>
 869  /// <param name="c">The result of the linear interpolation.</param>
 870  public static void LinearInterpolation(Quaternion<T> a, Quaternion<T> b, T blend, ref Quaternion<T>? c)
 0871  {
 0872    if (a is null) throw new ArgumentNullException(nameof(a));
 0873    if (b is null) throw new ArgumentNullException(nameof(b));
 874    #warning TODO: sourceof with generic mathematics
 0875    if (LessThan(blend, Constant<T>.Zero) || GreaterThan(blend, Constant<T>.One))
 0876    {
 0877      throw new ArgumentOutOfRangeException(nameof(blend), blend, "!(0 <= " + nameof(blend) + " <= 1)");
 878    }
 879    T x;
 880    T y;
 881    T z;
 882    T w;
 0883    if (GetHasZeroMagnitude(a))
 0884    {
 0885      if (GetHasZeroMagnitude(b))
 0886      {
 0887        x = Constant<T>.Zero;
 0888        y = Constant<T>.Zero;
 0889        z = Constant<T>.Zero;
 0890        w = Constant<T>.One;
 0891      }
 892      else
 0893      {
 0894        x = b._x;
 0895        y = b._y;
 0896        z = b._z;
 0897        w = b._w;
 0898      }
 0899    }
 0900    else if (GetHasZeroMagnitude(b))
 0901    {
 0902      x = a._x;
 0903      y = a._y;
 0904      z = a._z;
 0905      w = a._w;
 0906    }
 907    else
 0908    {
 0909      x = Addition(Subtraction(Constant<T>.One, Multiplication(blend, a.X)), Multiplication(blend, b.X));
 0910      y = Addition(Subtraction(Constant<T>.One, Multiplication(blend, a.Y)), Multiplication(blend, b.Y));
 0911      z = Addition(Subtraction(Constant<T>.One, Multiplication(blend, a.Z)), Multiplication(blend, b.Z));
 0912      w = Addition(Subtraction(Constant<T>.One, Multiplication(blend, a.W)), Multiplication(blend, b.W));
 0913    }
 0914    if (c is null)
 0915    {
 0916      c = new Quaternion<T>(x, y, z, w);
 0917    }
 918    else
 0919    {
 0920      c._x = x;
 0921      c._y = y;
 0922      c._z = z;
 0923      c._w = w;
 0924    }
 0925    if (!GetHasZeroMagnitude(c))
 0926    {
 0927      Normalize(c, ref c);
 0928    }
 929    else
 0930    {
 0931      c._x = Constant<T>.Zero;
 0932      c._y = Constant<T>.Zero;
 0933      c._z = Constant<T>.Zero;
 0934      c._w = Constant<T>.One;
 0935    }
 0936  }
 937
 938  /// <summary>Linear interpolation for quaternions.</summary>
 939  /// <param name="a">The min of the interpolation.</param>
 940  /// <param name="b">The max of the interpolation.</param>
 941  /// <param name="blend">The blending point of the interpolation.</param>
 942  /// <returns>The result of the linear interpolation.</returns>
 943  public static Quaternion<T> LinearInterpolation(Quaternion<T> a, Quaternion<T> b, T blend)
 0944  {
 0945    Quaternion<T>? c = null;
 0946    LinearInterpolation(a, b, blend, ref c);
 0947    return c!;
 0948  }
 949
 950  /// <summary>Linear interpolation for quaternions.</summary>
 951  /// <param name="b">The max of the interpolation.</param>
 952  /// <param name="blend">The blending point of the interpolation.</param>
 953  /// <param name="c">The result of the linear interpolation.</param>
 954  public void LinearInterpolation(Quaternion<T> b, T blend, ref Quaternion<T>? c) =>
 0955    LinearInterpolation(this, b, blend, ref c);
 956
 957  /// <summary>Linear interpolation for quaternions.</summary>
 958  /// <param name="b">The max of the interpolation.</param>
 959  /// <param name="blend">The blending point of the interpolation.</param>
 960  /// <returns>The result of the linear interpolation.</returns>
 961  public Quaternion<T> LinearInterpolation(Quaternion<T> b, T blend)
 0962  {
 0963    Quaternion<T>? c = null;
 0964    LinearInterpolation(this, b, blend, ref c);
 0965    return c!;
 0966  }
 967
 968  #endregion
 969
 970  #region SphericalInterpolation
 971
 972  /// <summary>Spherical interpolation for quaternions.</summary>
 973  /// <param name="a">The min of the interpolation.</param>
 974  /// <param name="b">The max of the interpolation.</param>
 975  /// <param name="blend">The blending point of the interpolation.</param>
 976  /// <param name="c">The result of the spherical interpolation.</param>
 977#warning TODO
 978  [Obsolete("Not Implemented", true)]
 979  public static void SphericalInterpolation(Quaternion<T> a, Quaternion<T> b, T blend, ref Quaternion<T>? c)
 0980  {
 0981    if (a is null) throw new ArgumentNullException(nameof(a));
 0982    if (b is null) throw new ArgumentNullException(nameof(b));
 0983    if (LessThan(blend, Constant<T>.Zero) || GreaterThan(blend, Constant<T>.One))
 0984    {
 0985      throw new ArgumentOutOfRangeException(nameof(blend), blend, "!(0 <= " + nameof(blend) + " <= 1)");
 986    }
 0987    throw new NotImplementedException();
 988  }
 989
 990  /// <summary>Spherical interpolation for quaternions.</summary>
 991  /// <param name="a">The min of the interpolation.</param>
 992  /// <param name="b">The max of the interpolation.</param>
 993  /// <param name="blend">The blending point of the interpolation.</param>
 994  /// <returns>The result of the spherical interpolation.</returns>
 995  public static Quaternion<T> SphericalInterpolation(Quaternion<T> a, Quaternion<T> b, T blend)
 0996  {
 0997    Quaternion<T>? c = null;
 0998    LinearInterpolation(a, b, blend, ref c);
 0999    return c!;
 01000  }
 1001
 1002  /// <summary>Spherical interpolation for quaternions.</summary>
 1003  /// <param name="b">The max of the interpolation.</param>
 1004  /// <param name="blend">The blending point of the interpolation.</param>
 1005  /// <param name="c">The result of the spherical interpolation.</param>
 1006  public void SphericalInterpolation(Quaternion<T> b, T blend, ref Quaternion<T>? c) =>
 01007    LinearInterpolation(this, b, blend, ref c);
 1008
 1009  /// <summary>Spherical interpolation for quaternions.</summary>
 1010  /// <param name="b">The max of the interpolation.</param>
 1011  /// <param name="blend">The blending point of the interpolation.</param>
 1012  /// <returns>The result of the spherical interpolation.</returns>
 1013  public Quaternion<T> SphericalInterpolation(Quaternion<T> b, T blend)
 01014  {
 01015    Quaternion<T>? c = null;
 01016    LinearInterpolation(this, b, blend, ref c);
 01017    return c!;
 01018  }
 1019
 1020  #endregion
 1021
 1022  #region ToMatrix3x3
 1023
 1024  /// <summary>Converts a quaternion into a 3x3 matrix.</summary>
 1025  /// <param name="quaternion">The quaternion of the conversion.</param>
 1026  /// <returns>The resulting 3x3 matrix.</returns>
 1027  public static Matrix<T> ToMatrix3x3(Quaternion<T> quaternion)
 01028  {
 1029    // Note: this Method needs optimization...
 1030
 1031#pragma warning disable CS8509 // The switch expression does not handle all possible values of its input type (it is not
 01032    return new Matrix<T>(3, 3, (int x, int y) =>
 01033      (x, y) switch
 01034      {
 01035        (0, 0) => Subtraction(Subtraction(Addition(Multiplication(quaternion.W, quaternion.W), Multiplication(quaternion
 01036        (0, 1) => Subtraction(Multiplication(Multiplication(Convert<int, T>(2), quaternion.X), quaternion.Y), Multiplica
 01037        (0, 2) => Addition(Multiplication(Multiplication(Convert<int, T>(2), quaternion.X), quaternion.Z), Multiplicatio
 01038        (1, 0) => Addition(Multiplication(Multiplication(Convert<int, T>(2), quaternion.X), quaternion.Y), Multiplicatio
 01039        (1, 1) => Subtraction(Addition(Subtraction(Multiplication(quaternion.W, quaternion.W), Multiplication(quaternion
 01040        (1, 2) => Addition(Multiplication(Multiplication(Convert<int, T>(2), quaternion.Y), quaternion.Z), Multiplicatio
 01041        (2, 0) => Subtraction(Multiplication(Multiplication(Convert<int, T>(2), quaternion.X), quaternion.Z), Multiplica
 01042        (2, 1) => Subtraction(Multiplication(Multiplication(Convert<int, T>(2), quaternion.Y), quaternion.Z), Multiplica
 01043        (2, 2) => Addition(Subtraction(Subtraction(Multiplication(quaternion.W, quaternion.W), Multiplication(quaternion
 01044      });
 1045#pragma warning restore CS8509 // The switch expression does not handle all possible values of its input type (it is not
 01046  }
 1047
 1048  #endregion
 1049
 1050  #region Equal
 1051
 1052  /// <summary>Does a value equality check.</summary>
 1053  /// <param name="a">The first quaternion to check for equality.</param>
 1054  /// <param name="b">The second quaternion to check for equality.</param>
 1055  /// <returns>True if values are equal, false if not.</returns>
 1056  internal static bool Equal(Quaternion<T> a, Quaternion<T> b)
 541057  {
 541058    if (a is null)
 01059    {
 01060      if (b is null)
 01061      {
 01062        return true;
 1063      }
 1064      else
 01065      {
 01066        return false;
 1067      }
 1068    }
 541069    if (b is null)
 01070    {
 01071      return false;
 1072    }
 541073    return
 541074      Statics.Equate(a._x, b._x) &&
 541075      Statics.Equate(a._y, b._y) &&
 541076      Statics.Equate(a._z, b._z) &&
 541077      Statics.Equate(a._w, b._w);
 541078  }
 1079
 1080  /// <summary>Does a value equality check.</summary>
 1081  /// <param name="a">The first quaternion to check for equality.</param>
 1082  /// <param name="b">The second quaternion to check for equality.</param>
 1083  /// <returns>True if values are equal, false if not.</returns>
 541084  public static bool operator ==(Quaternion<T> a, Quaternion<T> b) => Equal(a, b);
 1085
 1086  /// <summary>Does a value non-equality check.</summary>
 1087  /// <param name="a">The first quaternion to check for non-equality.</param>
 1088  /// <param name="b">The second quaternion to check for non-equality.</param>
 1089  /// <returns>True if values are not equal, false if not.</returns>
 01090  public static bool operator !=(Quaternion<T> a, Quaternion<T> b) => !Equal(a, b);
 1091
 1092  /// <summary>Does a value equality check.</summary>
 1093  /// <param name="b">The second quaternion to check for equality.</param>
 1094  /// <returns>True if values are equal, false if not.</returns>
 01095  public bool Equal(Quaternion<T> b) => this == b;
 1096
 1097  #endregion
 1098
 1099  #region Equal (+leniency)
 1100
 1101  /// <summary>Does a value equality check with leniency.</summary>
 1102  /// <param name="a">The first quaternion to check for equality.</param>
 1103  /// <param name="b">The second quaternion to check for equality.</param>
 1104  /// <param name="leniency">How much the values can vary but still be considered equal.</param>
 1105  /// <returns>True if values are equal, false if not.</returns>
 1106  internal static bool Equal(Quaternion<T> a, Quaternion<T> b, T leniency)
 281107  {
 281108    if (a is null)
 01109    {
 01110      if (b is null)
 01111      {
 01112        return true;
 1113      }
 1114      else
 01115      {
 01116        return false;
 1117      }
 1118    }
 281119    if (b is null)
 01120    {
 01121      return false;
 1122    }
 281123    return
 281124      Statics.EqualToLeniency(a._x, b._x, leniency) &&
 281125      Statics.EqualToLeniency(a._y, b._y, leniency) &&
 281126      Statics.EqualToLeniency(a._z, b._z, leniency) &&
 281127      Statics.EqualToLeniency(a._w, b._w, leniency);
 281128  }
 1129
 1130  /// <summary>Does a value equality check with leniency.</summary>
 1131  /// <param name="b">The second quaternion to check for equality.</param>
 1132  /// <param name="leniency">How much the values can vary but still be considered equal.</param>
 1133  /// <returns>True if values are equal, false if not.</returns>
 281134  public bool Equal(Quaternion<T> b, T leniency) => Equal(this, b, leniency);
 1135
 1136  #endregion
 1137
 1138  #endregion
 1139
 1140  #region Other Methods
 1141
 1142  #region Clone
 1143
 1144  /// <summary>Creates a copy of a quaternion.</summary>
 1145  /// <param name="a">The quaternion to copy.</param>
 1146  /// <returns>The copy of this quaternion.</returns>
 1147  public static Quaternion<T> Clone(Quaternion<T> a)
 01148  {
 01149    if (a is null) throw new ArgumentNullException(nameof(a));
 01150    return new Quaternion<T>(a._x, a._y, a._z, a._w);
 01151  }
 1152
 1153  /// <summary>Copies this matrix.</summary>
 1154  /// <returns>The copy of this matrix.</returns>
 01155  public Quaternion<T> Clone() => Clone(this);
 1156
 1157  #endregion
 1158
 1159  #endregion
 1160
 1161  #region Overrides
 1162
 1163  /// <summary>Computes a hash code from the values in this quaternion.</summary>
 1164  /// <returns>The computed hash code.</returns>
 01165  public override int GetHashCode() => HashCode.Combine(Hash(_x), Hash(_y), Hash(_z), Hash(_w));
 1166
 1167  /// <summary>Does a reference equality check.</summary>
 1168  /// <param name="other">The other operand of the equality check.</param>
 1169  /// <returns>True if equal or false.</returns>
 01170  public override bool Equals(object? other) => other is Quaternion<T> b && Equal(this, b);
 1171
 1172  #endregion
 1173}