using System; namespace Syntriax.Engine.Core; /// /// Represents a two-dimensional vector. /// [System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")] public readonly struct Vector2D(float x, float y) { /// /// The X coordinate of the . /// public readonly float X = x; /// /// The Y coordinate of the . /// public readonly float Y = y; /// /// The magnitude (length) of the . /// public float Magnitude => Length(this); /// /// The squared magnitude (length) of the . /// public float MagnitudeSquared => LengthSquared(this); /// /// The normalized form of the (a with the same direction and a magnitude of 1). /// public Vector2D Normalized => Normalize(this); /// /// Represents the unit pointing upwards. /// public readonly static Vector2D Up = new(0f, 1f); /// /// Represents the unit pointing downwards. /// public readonly static Vector2D Down = new(0f, -1f); /// /// Represents the unit pointing leftwards. /// public readonly static Vector2D Left = new(-1f, 0f); /// /// Represents the unit pointing rightwards. /// public readonly static Vector2D Right = new(1f, 0f); /// /// Represents the zero . /// public readonly static Vector2D Zero = new(0f, 0f); /// /// Represents the with both components equal to 1. /// public readonly static Vector2D One = new(1f, 1f); public static Vector2D operator -(Vector2D vector) => new(0f - vector.X, 0f - vector.Y); public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value); public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value); public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y; public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y; /// /// Calculates the length of the . /// /// The . /// The length of the . public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector)); /// /// Calculates the squared length of the . /// /// The . /// The squared length of the . public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y; /// /// Calculates the distance between two s. /// /// The start . /// The end . /// The distance between the two s. public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); /// /// Inverts the direction of the . /// /// The . /// The inverted . public static Vector2D Invert(Vector2D vector) => -vector; /// /// Adds two s. /// /// The first . /// The second . /// The sum of the two s. public static Vector2D Add(Vector2D left, Vector2D right) => left + right; /// /// Subtracts one from another. /// /// The to subtract from. /// The to subtract. /// The result of subtracting the second from the first. public static Vector2D Subtract(Vector2D left, Vector2D right) => left - right; /// /// Multiplies a by a scalar value. /// /// The . /// The scalar value. /// The result of multiplying the by the scalar value. public static Vector2D Multiply(Vector2D vector, float value) => vector * value; /// /// Divides a by a scalar value. /// /// The . /// The scalar value. /// The result of dividing the by the scalar value. public static Vector2D Divide(Vector2D vector, float value) => vector / value; /// /// Calculates the absolute value of each component of the vector. /// /// The . /// The with each component's absolute value. public static Vector2D Abs(Vector2D vector) => new(Math.Abs(vector.X), Math.Abs(vector.Y)); /// /// Normalizes the (creates a unit with the same direction). /// /// The to normalize. /// The normalized . public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); /// /// Reflects a off a surface with the specified normal. /// /// The incident . /// The normal of the surface. /// The reflected . public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal; /// /// Calculates the from one point to another. /// /// The starting point. /// The ending point. /// The from the starting point to the ending point. public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; /// /// Scales a by another component-wise. /// /// The to scale. /// The containing the scaling factors for each component. /// The scaled . public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); /// /// Calculates a perpendicular to the given . /// /// The input . /// A perpendicular to the input . public static Vector2D Perpendicular(Vector2D vector) => new(-vector.Y, vector.X); /// /// Rotates a by the specified angle (in radians). /// /// The to rotate. /// The angle to rotate by, in radians. /// The rotated . public static Vector2D Rotate(Vector2D vector, float angleInRadian) => new(MathF.Cos(angleInRadian) * vector.X - MathF.Sin(angleInRadian) * vector.Y, MathF.Sin(angleInRadian) * vector.X + MathF.Cos(angleInRadian) * vector.Y); /// /// Returns the component-wise minimum of two s. /// /// The first . /// The second . /// The containing the minimum components from both input s. public static Vector2D Min(Vector2D left, Vector2D right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y); /// /// Returns the component-wise maximum of two s. /// /// The first . /// The second . /// The containing the maximum components from both input s. public static Vector2D Max(Vector2D left, Vector2D right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y); /// /// Clamps each component of a between the corresponding component of two other s. /// /// The to clamp. /// The representing the minimum values for each component. /// The representing the maximum values for each component. /// A with each component clamped between the corresponding components of the min and max s. public static Vector2D Clamp(Vector2D vector, Vector2D min, Vector2D max) => new(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y)); /// /// Performs linear interpolation between two s. /// /// The starting (t = 0). /// The ending (t = 1). /// The interpolation parameter. /// The interpolated . public static Vector2D Lerp(Vector2D from, Vector2D to, float t) => from + FromTo(from, to) * t; /// /// Calculates the cross product of two s. /// /// The first . /// The second . /// The cross product of the two s. public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; /// /// Calculates the angle between two s. /// /// The first . /// The second . /// The angle between the two s in radians. public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); /// /// Calculates the dot product of two s. /// /// The first . /// The second . /// The dot product of the two s. public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; /// /// Determines the orientation of three points represented by s. /// /// The first . /// The second . /// The third . /// /// 0 - Collinear. /// 1 - Clockwise. /// 2 - Counterclockwise. /// public static int Orientation(Vector2D left, Vector2D middle, Vector2D right) { Vector2D leftToMiddle = left.FromTo(middle); Vector2D middleToRight = middle.FromTo(right); float value = leftToMiddle.Y * middleToRight.X - leftToMiddle.X * middleToRight.Y; if (value > 0) return 1; if (value < 0) return 2; return 0; } /// /// Checks if two s are approximately equal within a specified epsilon range. /// /// The first . /// The second . /// The epsilon range. /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(Vector2D left, Vector2D right, float epsilon = float.Epsilon) => left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon); /// /// Converts the to its string representation. /// /// A string representation of the . public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})"; /// /// Determines whether the specified object is equal to the current . /// /// The object to compare with the current . /// if the specified object is equal to the current ; otherwise, . public override bool Equals(object? obj) => obj is Vector2D objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y); /// /// Generates a hash code for the . /// /// A hash code for the . public override int GetHashCode() => HashCode.Combine(X, Y); }