using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Text; namespace GenericVector; internal static class Vector { /// Gets the element at the specified index. /// The vector to get the element from. /// The index of the element to get. /// The value of the element at . /// was less than zero or greater than the number of elements. [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T GetElement(this Vector3 vector, int index) where T : INumber { if ((uint)(index) >= Vector3.Count) { throw new ArgumentOutOfRangeException(nameof(index)); } return vector.GetElementUnsafe(index); } /// Creates a new with the element at the specified index set to the specified value and the remaining elements set to the same value as that in the given vector. /// The vector to get the remaining elements from. /// The index of the element to set. /// The value to set the element to. /// A with the value of the element at set to and the remaining elements set to the same value as that in . /// was less than zero or greater than the number of elements. internal static Vector3 WithElement(this Vector3 vector, int index, T value) where T : INumber { if ((uint)(index) >= Vector3.Count) { throw new ArgumentOutOfRangeException(nameof(index)); } var result = vector; result.SetElementUnsafe(index, value); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T GetElementUnsafe(in this Vector3 vector, int index) where T : INumber { Debug.Assert(index is >= 0 and < Vector3.Count); ref var address = ref Unsafe.AsRef(in vector.X); return Unsafe.Add(ref address, index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void SetElementUnsafe(ref this Vector3 vector, int index, T value) where T : INumber { Debug.Assert(index is >= 0 and < Vector3.Count); Unsafe.Add(ref vector.X, index) = value; } } public struct Vector3 : IEquatable>, ISpanFormattable where T : INumber { /// The X component of the vector. public T X; /// The Y component of the vector. public T Y; /// The Z component of the vector. public T Z; // private unsafe fixed T Components[3]; /// /// Returns the vector (0,0,0). /// public static Vector3 Zero => new(); /// /// Returns the vector (1,1,1). /// public static Vector3 One => new(T.One, T.One, T.One); /// /// Returns the vector (1,0,0). /// public static Vector3 UnitX => new(T.One, T.Zero, T.Zero); /// /// Returns the vector (0,1,0). /// public static Vector3 UnitY => new(T.Zero, T.One, T.Zero); /// /// Returns the vector (0,0,1). /// public static Vector3 UnitZ => new(T.Zero, T.Zero, T.One); public const int Count = 3; /// Gets or sets the element at the specified index. /// The index of the element to get or set. /// The the element at . /// was less than zero or greater than the number of elements. public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.GetElement(index); [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this = this.WithElement(index, value); } /// Creates a new object whose three elements have the same value. /// The value to assign to all three elements. public Vector3(T value) : this(value, value, value) { } /// Creates a vector whose elements have the specified values. /// The value to assign to the field. /// The value to assign to the field. /// The value to assign to the field. public Vector3(T x, T y, T z) { X = x; Y = y; Z = z; } /// Constructs a vector from the given . The span must contain at least 3 elements. /// The span of elements to assign to the vector. public Vector3(ReadOnlySpan values) { if (values.Length < 3) { throw new ArgumentOutOfRangeException(nameof(values)); } this = Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); } public override string ToString() { return ToString(""); } /// /// Returns a String representing this Vector3 instance, using the specified format to format individual elements. /// /// The format of individual elements. /// The string representation. public string ToString(string format) { return ToString(format, CultureInfo.CurrentCulture); } /// /// Returns a String representing this Vector3 instance, using the specified format to format individual elements /// and the given IFormatProvider. /// /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. public string ToString(string? format, IFormatProvider? formatProvider) { var sb = new StringBuilder(); var separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; sb.Append('<'); sb.Append(X.ToString(format, formatProvider)); sb.Append(separator); sb.Append(' '); sb.Append(Y.ToString(format, formatProvider)); sb.Append(separator); sb.Append(' '); sb.Append(Z.ToString(format, formatProvider)); sb.Append('>'); return sb.ToString(); } /// Returns a value that indicates whether this instance and a specified object are equal. /// The object to compare with the current instance. /// if the current instance and are equal; otherwise, . If is , the method returns . /// The current instance and are equal if is a object and their corresponding elements are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly override bool Equals([NotNullWhen(true)] object? obj) { return (obj is Vector3 other) && Equals(other); } /// Returns a value that indicates whether this instance and another vector are equal. /// The other vector. /// if the two vectors are equal; otherwise, . /// Two vectors are equal if their , , and elements are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Vector3 other) { // This function needs to account for floating-point equality around NaN // and so must behave equivalently to the underlying float/double.Equals if (typeof(T) == typeof(float) && Vector128.IsHardwareAccelerated) { #if NET8_0 return Unsafe.BitCast, Vector3>(this).AsVector128().Equals(Unsafe.BitCast, Vector3>(other).AsVector128()); #else var _this = Unsafe.As, Vector3>(ref Unsafe.AsRef(in this)); var _other = Unsafe.As, Vector3>(ref Unsafe.AsRef(in other)); return _this.AsVector128().Equals(_other.AsVector128()); #endif } if ((typeof(T) == typeof(int) || typeof(T) == typeof(uint)) && Vector128.IsHardwareAccelerated) { var _this = Vector128.Create( Unsafe.As(ref Unsafe.AsRef(X)), Unsafe.As(ref Unsafe.AsRef(Y)), Unsafe.As(ref Unsafe.AsRef(Z)), 0); var _other = Vector128.Create( Unsafe.As(ref Unsafe.AsRef(other.X)), Unsafe.As(ref Unsafe.AsRef(other.Y)), Unsafe.As(ref Unsafe.AsRef(other.Z)), 0); return _this.Equals(_other); } // if (!RuntimeHelpers.IsReferenceOrContainsReferences()) // { // var size = Unsafe.SizeOf(); // // if (Vector128.IsHardwareAccelerated && (size * Count) < 16) // { // Span data = stackalloc byte[32]; // data.Clear(); // optional? // // var copy = this; // make you guys happy // MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref copy, 1)).CopyTo(data); // MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref other, 1)).CopyTo(data[16..]); // // MemoryMarshal.Cast() // } // } if (typeof(T) == typeof(double) && Vector256.IsHardwareAccelerated) { var _this = Vector256.Create( Unsafe.As(ref Unsafe.AsRef(X)), Unsafe.As(ref Unsafe.AsRef(Y)), Unsafe.As(ref Unsafe.AsRef(Z)), 0); var _other = Vector256.Create( Unsafe.As(ref Unsafe.AsRef(other.X)), Unsafe.As(ref Unsafe.AsRef(other.Y)), Unsafe.As(ref Unsafe.AsRef(other.Z)), 0); return _this.Equals(_other); } if ((typeof(T) == typeof(long) || typeof(T) == typeof(ulong)) && Vector256.IsHardwareAccelerated) { var _this = Vector256.Create( Unsafe.As(ref Unsafe.AsRef(X)), Unsafe.As(ref Unsafe.AsRef(Y)), Unsafe.As(ref Unsafe.AsRef(Z)), 0); var _other = Vector256.Create( Unsafe.As(ref Unsafe.AsRef(other.X)), Unsafe.As(ref Unsafe.AsRef(other.Y)), Unsafe.As(ref Unsafe.AsRef(other.Z)), 0); return _this.Equals(_other); } return SoftwareFallback(in this, other); static bool SoftwareFallback(in Vector3 self, Vector3 other) { return self.X.Equals(other.X) && self.Y.Equals(other.Y) && self.Z.Equals(other.Z); } } /// Returns the hash code for this instance. /// The hash code. public readonly override int GetHashCode() { return HashCode.Combine(X, Y, Z); } public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) { var separator = NumberFormatInfo.GetInstance(provider).NumberGroupSeparator.AsSpan(); return destination.TryWrite($"<{X}{separator} {Y}{separator} {Z}{separator}>", out charsWritten); } private Vector3 As() where TOther : INumber { return new Vector3( TOther.CreateTruncating(X), TOther.CreateTruncating(Y), TOther.CreateTruncating(Z) ); } #region Maths /// Adds two vectors together. /// The first vector to add. /// The second vector to add. /// The summed vector. /// The method defines the addition operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator +(Vector3 left, Vector3 right) { return new Vector3( left.X + right.X, left.Y + right.Y, left.Z + right.Z ); } /// Divides the first vector by the second. /// The first vector. /// The second vector. /// The vector that results from dividing by . /// The method defines the division operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator /(Vector3 left, Vector3 right) { return new Vector3( left.X / right.X, left.Y / right.Y, left.Z / right.Z ); } /// Divides the specified vector by a specified scalar value. /// The vector. /// The scalar value. /// The result of the division. /// The method defines the division operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator /(Vector3 value1, T value2) { return value1 / new Vector3(value2); } /// Returns a value that indicates whether each pair of elements in two specified vectors is equal. /// The first vector to compare. /// The second vector to compare. /// if and are equal; otherwise, . /// Two objects are equal if each element in is equal to the corresponding element in . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector3 left, Vector3 right) { return (left.X == right.X) && (left.Y == right.Y) && (left.Z == right.Z); } /// Returns a value that indicates whether two specified vectors are not equal. /// The first vector to compare. /// The second vector to compare. /// if and are not equal; otherwise, . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vector3 left, Vector3 right) { return !(left == right); } /// Returns a new vector whose values are the product of each pair of elements in two specified vectors. /// The first vector. /// The second vector. /// The element-wise product vector. /// The method defines the multiplication operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(Vector3 left, Vector3 right) { return new Vector3( left.X * right.X, left.Y * right.Y, left.Z * right.Z ); } /// Multiplies the specified vector by the specified scalar value. /// The vector. /// The scalar value. /// The scaled vector. /// The method defines the multiplication operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(Vector3 left, T right) { return left * new Vector3(right); } /// Multiplies the scalar value by the specified vector. /// The vector. /// The scalar value. /// The scaled vector. /// The method defines the multiplication operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(T left, Vector3 right) { return right * left; } /// Subtracts the second vector from the first. /// The first vector. /// The second vector. /// The vector that results from subtracting from . /// The method defines the subtraction operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator -(Vector3 left, Vector3 right) { return new Vector3( left.X - right.X, left.Y - right.Y, left.Z - right.Z ); } /// Negates the specified vector. /// The vector to negate. /// The negated vector. /// The method defines the unary negation operation for objects. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator -(Vector3 value) { return Zero - value; } /// Returns a vector whose elements are the absolute values of each of the specified vector's elements. /// A vector. /// The absolute value vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Abs(Vector3 value) { return new Vector3( T.Abs(value.X), T.Abs(value.Y), T.Abs(value.Z) ); } /// Adds two vectors together. /// The first vector to add. /// The second vector to add. /// The summed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Add(Vector3 left, Vector3 right) { return left + right; } /// Restricts a vector between a minimum and a maximum value. /// The vector to restrict. /// The minimum value. /// The maximum value. /// The restricted vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) { // We must follow HLSL behavior in the case user specified min value is bigger than max value. return Min(Max(value1, min), max); } /// Computes the cross product of two vectors. /// The first vector. /// The second vector. /// The cross product. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Cross(Vector3 vector1, Vector3 vector2) { return new Vector3( (vector1.Y * vector2.Z) - (vector1.Z * vector2.Y), (vector1.Z * vector2.X) - (vector1.X * vector2.Z), (vector1.X * vector2.Y) - (vector1.Y * vector2.X) ); } /// Computes the cross product of two vectors. /// The first vector. /// The second vector. /// The cross product. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Cross(Vector3 vector1, Vector3 vector2) where TIntermediate : INumber { return new Vector3( T.CreateTruncating((TIntermediate.CreateTruncating(vector1.Y) * TIntermediate.CreateTruncating(vector2.Z)) - (TIntermediate.CreateTruncating(vector1.Z) * TIntermediate.CreateTruncating(vector2.Y))), T.CreateTruncating((TIntermediate.CreateTruncating(vector1.Z) * TIntermediate.CreateTruncating(vector2.X)) - (TIntermediate.CreateTruncating(vector1.X) * TIntermediate.CreateTruncating(vector2.Z))), T.CreateTruncating((TIntermediate.CreateTruncating(vector1.X) * TIntermediate.CreateTruncating(vector2.Y)) - (TIntermediate.CreateTruncating(vector1.Y) * TIntermediate.CreateTruncating(vector2.X))) ); } /// Computes the Euclidean distance between the two given points. /// The first point. /// The second point. /// The distance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TReturn Distance(Vector3 value1, Vector3 value2) where TReturn : INumber, IRootFunctions { var distanceSquared = DistanceSquared(value1, value2); return TReturn.Sqrt(TReturn.CreateTruncating(distanceSquared)); } /// Returns the Euclidean distance squared between two specified points. /// The first point. /// The second point. /// The distance squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T DistanceSquared(Vector3 value1, Vector3 value2) { var difference = value1 - value2; return Dot(difference, difference); } /// Returns the Euclidean distance squared between two specified points. /// The first point. /// The second point. /// The distance squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TReturn DistanceSquared(Vector3 value1, Vector3 value2) where TReturn : INumber { var difference = value1 - value2; return Dot(difference, difference); } /// Divides the first vector by the second. /// The first vector. /// The second vector. /// The vector resulting from the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Divide(Vector3 left, Vector3 right) { return left / right; } /// Divides the specified vector by a specified scalar value. /// The vector. /// The scalar value. /// The vector that results from the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Divide(Vector3 left, T divisor) { return left / divisor; } /// Returns the dot product of two vectors. /// The first vector. /// The second vector. /// The dot product. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Dot(Vector3 vector1, Vector3 vector2) { return (vector1.X * vector2.X) + (vector1.Y * vector2.Y) + (vector1.Z * vector2.Z); } /// Returns the dot product of two vectors. /// The first vector. /// The second vector. /// The dot product. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TReturn Dot(Vector3 vector1, Vector3 vector2) where TReturn : INumber { return (TReturn.CreateTruncating(vector1.X) * TReturn.CreateTruncating(vector2.X)) + (TReturn.CreateTruncating(vector1.Y) * TReturn.CreateTruncating(vector2.Y)) + (TReturn.CreateTruncating(vector1.Z) * TReturn.CreateTruncating(vector2.Z)); } /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. /// A value between 0 and 1 that indicates the weight of . /// The interpolated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(Vector3 value1, Vector3 value2, T amount) { return (value1 * (T.One - amount)) + (value2 * amount); } /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. /// A value between 0 and 1 that indicates the weight of . /// The interpolated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(Vector3 value1, Vector3 value2, TFloat amount) where TFloat : INumber, IFloatingPoint { return (value1.As() * (TFloat.One - amount)) + (value2.As() * amount); } /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. /// The first vector. /// The second vector. /// The maximized vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Max(Vector3 value1, Vector3 value2) { return new Vector3( (value1.X > value2.X) ? value1.X : value2.X, (value1.Y > value2.Y) ? value1.Y : value2.Y, (value1.Z > value2.Z) ? value1.Z : value2.Z ); } /// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors. /// The first vector. /// The second vector. /// The minimized vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Min(Vector3 value1, Vector3 value2) { return new Vector3( (value1.X < value2.X) ? value1.X : value2.X, (value1.Y < value2.Y) ? value1.Y : value2.Y, (value1.Z < value2.Z) ? value1.Z : value2.Z ); } /// Returns a new vector whose values are the product of each pair of elements in two specified vectors. /// The first vector. /// The second vector. /// The element-wise product vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Multiply(Vector3 left, Vector3 right) { return left * right; } /// Multiplies a vector by a specified scalar. /// The vector to multiply. /// The scalar value. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Multiply(Vector3 left, T right) { return left * right; } /// Multiplies a scalar value by a specified vector. /// The scaled value. /// The vector. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Multiply(T left, Vector3 right) { return left * right; } /// Negates a specified vector. /// The vector to negate. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Negate(Vector3 value) { return -value; } /// Returns a vector with the same direction as the specified vector, but with a length of one. /// The vector to normalize. /// The normalized vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Normalize(Vector3 value) where TReturn : IFloatingPoint, IRootFunctions { return value.As() / value.Length(); } /// Returns the reflection of a vector off a surface that has the specified normal. /// The source vector. /// The normal of the surface being reflected off. /// The reflected vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Reflect(Vector3 vector, Vector3 normal) where TReturn : IFloatingPoint { var dot = Dot(vector, normal); return vector.As() - (TReturn.CreateTruncating(2) * (dot * normal.As())); } /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 SquareRoot(Vector3 value) where TReturn : IFloatingPoint, IRootFunctions { return new Vector3( TReturn.Sqrt(TReturn.CreateTruncating(value.X)), TReturn.Sqrt(TReturn.CreateTruncating(value.Y)), TReturn.Sqrt(TReturn.CreateTruncating(value.Z)) ); } /// Subtracts the second vector from the first. /// The first vector. /// The second vector. /// The difference vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Subtract(Vector3 left, Vector3 right) { return left - right; } // /// Transforms a vector by a specified 4x4 matrix. // /// The vector to transform. // /// The transformation matrix. // /// The transformed vector. // [MethodImpl(MethodImplOptions.AggressiveInlining)] // public static Vector3 Transform(Vector3 position, Matrix4x4 matrix) // { // return Vector4.Transform(position, in matrix.AsImpl()).AsVector128().AsVector3(); // } /// Transforms a vector by the specified Quaternion rotation value. /// The vector to rotate. /// The rotation to apply. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Transform(Vector3 value, Quaternion rotation) where TReturn : INumber { var x2 = rotation.X + rotation.X; var y2 = rotation.Y + rotation.Y; var z2 = rotation.Z + rotation.Z; var wx2 = TReturn.CreateTruncating(rotation.W * x2); var wy2 = TReturn.CreateTruncating(rotation.W * y2); var wz2 = TReturn.CreateTruncating(rotation.W * z2); var xx2 = TReturn.CreateTruncating(rotation.X * x2); var xy2 = TReturn.CreateTruncating(rotation.X * y2); var xz2 = TReturn.CreateTruncating(rotation.X * z2); var yy2 = TReturn.CreateTruncating(rotation.Y * y2); var yz2 = TReturn.CreateTruncating(rotation.Y * z2); var zz2 = TReturn.CreateTruncating(rotation.Z * z2); return new Vector3( TReturn.CreateTruncating(value.X) * (TReturn.One - yy2 - zz2) + TReturn.CreateTruncating(value.Y) * (xy2 - wz2) + TReturn.CreateTruncating(value.Z) * (xz2 + wy2), TReturn.CreateTruncating(value.X) * (xy2 + wz2) + TReturn.CreateTruncating(value.Y) * (TReturn.One - xx2 - zz2) + TReturn.CreateTruncating(value.Z) * (yz2 - wx2), TReturn.CreateTruncating(value.X) * (xz2 - wy2) + TReturn.CreateTruncating(value.Y) * (yz2 + wx2) + TReturn.CreateTruncating(value.Z) * (TReturn.One - xx2 - yy2) ); } // /// Transforms a vector normal by the given 4x4 matrix. // /// The source vector. // /// The matrix. // /// The transformed vector. // [MethodImpl(MethodImplOptions.AggressiveInlining)] // public static Vector3 TransformNormal(Vector3 normal, Matrix4x4 matrix) // { // return TransformNormal(normal, in matrix.AsImpl()); // } // // [MethodImpl(MethodImplOptions.AggressiveInlining)] // internal static Vector3 TransformNormal(Vector3 normal, in Matrix4x4.Impl matrix) // { // Vector4 result = matrix.X * normal.X; // // result += matrix.Y * normal.Y; // result += matrix.Z * normal.Z; // // return result.AsVector128().AsVector3(); // } /// Returns the length of this vector object. /// The vector's length. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly TReturn Length() where TReturn : INumber, IFloatingPoint, IRootFunctions { var lengthSquared = LengthSquared(); return TReturn.Sqrt(lengthSquared); } /// Returns the length of the vector squared. /// The vector's length squared. /// This operation offers better performance than a call to the method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T LengthSquared() { return Dot(this, this); } /// Returns the length of the vector squared. /// The vector's length squared. /// This operation offers better performance than a call to the method. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly TReturn LengthSquared() where TReturn : INumber { return Dot(this, this); } #endregion }