using System; using System.Collections.Generic; using System.Globalization; using GTA.Math; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RageCoop.Core { internal struct LVector2 : IEquatable { /// /// Gets or sets the X component of the vector. /// /// The X component of the vector. public float X; /// /// Gets or sets the Y component of the vector. /// /// The Y component of the vector. public float Y; /// /// Initializes a new instance of the class. /// /// Initial value for the X component of the vector. /// Initial value for the Y component of the vector. public LVector2(float x, float y) { X = x; Y = y; } /// /// Returns this vector with a magnitude of 1. /// public LVector2 Normalized => Normalize(new LVector2(X, Y)); /// /// Returns a null vector. (0,0) /// public static LVector2 Zero => new LVector2(0.0f, 0.0f); /// /// The X unit (1, 0). /// public static LVector2 UnitX => new LVector2(1.0f, 0.0f); /// /// The Y unit (0, 1). /// public static LVector2 UnitY => new LVector2(0.0f, 1.0f); /// /// Returns the up vector. (0,1) /// public static LVector2 Up => new LVector2(0.0f, 1.0f); /// /// Returns the down vector. (0,-1) /// public static LVector2 Down => new LVector2(0.0f, -1.0f); /// /// Returns the right vector. (1,0) /// public static LVector2 Right => new LVector2(1.0f, 0.0f); /// /// Returns the left vector. (-1,0) /// public static LVector2 Left => new LVector2(-1.0f, 0.0f); /// /// Gets or sets the component at the specified index. /// /// The value of the X or Y component, depending on the index. /// The index of the component to access. Use 0 for the X component and 1 for the Y component. /// The value of the component at the specified index. /// Thrown when the is out of the range [0, 1]. public float this[int index] { get { switch (index) { case 0: return X; case 1: return Y; } throw new ArgumentOutOfRangeException("index", "Indices for Vector2 run from 0 to 1, inclusive."); } set { switch (index) { case 0: X = value; break; case 1: Y = value; break; default: throw new ArgumentOutOfRangeException("index", "Indices for Vector2 run from 0 to 1, inclusive."); } } } /// /// Calculates the length of the vector. /// /// The length of the vector. public float Length() { return (float)System.Math.Sqrt((X * X) + (Y * Y)); } /// /// Calculates the squared length of the vector. /// /// The squared length of the vector. public float LengthSquared() { return (X * X) + (Y * Y); } /// /// Converts the vector into a unit vector. /// public void Normalize() { float length = Length(); if (length == 0) { return; } float num = 1 / length; X *= num; Y *= num; } /// /// Calculates the distance between two vectors. /// /// The second vector to calculate the distance to. /// The distance to the other vector. public float DistanceTo(LVector2 position) { return (position - this).Length(); } /// /// Calculates the squared distance between two vectors. /// /// The second vector to calculate the squared distance to. /// The squared distance to the other vector. public float DistanceToSquared(LVector2 position) { return DistanceSquared(position, this); } /// /// Calculates the distance between two vectors. /// /// The first vector to calculate the distance to the second vector. /// The second vector to calculate the distance to the first vector. /// The distance between the two vectors. public static float Distance(LVector2 position1, LVector2 position2) { return (position1 - position2).Length(); } /// /// Calculates the squared distance between two vectors. /// /// The first vector to calculate the squared distance to the second vector. /// The second vector to calculate the squared distance to the first vector. /// The squared distance between the two vectors. public static float DistanceSquared(LVector2 position1, LVector2 position2) { return (position1 - position2).LengthSquared(); } /// /// Returns the angle in degrees between from and to. /// The angle returned is always the acute angle between the two vectors. /// public static float Angle(LVector2 from, LVector2 to) { return System.Math.Abs(SignedAngle(from, to)); } /// /// Returns the signed angle in degrees between from and to. /// public static float SignedAngle(LVector2 from, LVector2 to) { return (float)((System.Math.Atan2(to.Y, to.X) - System.Math.Atan2(from.Y, from.X)) * (180.0 / System.Math.PI)); } /// /// Converts a vector to a heading. /// public float ToHeading() { return (float)((System.Math.Atan2(X, -Y) + System.Math.PI) * (180.0 / System.Math.PI)); } /// /// Returns a new normalized vector with random X and Y components. /// public static LVector2 RandomXY() { LVector2 v; double radian = CoreUtils.SafeRandom.NextDouble() * 2 * System.Math.PI; v.X = (float)(System.Math.Cos(radian)); v.Y = (float)(System.Math.Sin(radian)); v.Normalize(); return v; } /// /// Adds two vectors. /// /// The first vector to add. /// The second vector to add. /// The sum of the two vectors. public static LVector2 Add(LVector2 left, LVector2 right) => new LVector2(left.X + right.X, left.Y + right.Y); /// /// Subtracts two vectors. /// /// The first vector to subtract. /// The second vector to subtract. /// The difference of the two vectors. public static LVector2 Subtract(LVector2 left, LVector2 right) => new LVector2(left.X - right.X, left.Y - right.Y); /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static LVector2 Multiply(LVector2 value, float scale) => new LVector2(value.X * scale, value.Y * scale); /// /// Multiplies a vector with another by performing component-wise multiplication. /// /// The first vector to multiply. /// The second vector to multiply. /// The multiplied vector. public static LVector2 Multiply(LVector2 left, LVector2 right) => new LVector2(left.X * right.X, left.Y * right.Y); /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static LVector2 Divide(LVector2 value, float scale) => new LVector2(value.X / scale, value.Y / scale); /// /// Reverses the direction of a given vector. /// /// The vector to negate. /// A vector facing in the opposite direction. public static LVector2 Negate(LVector2 value) => new LVector2(-value.X, -value.Y); /// /// Restricts a value to be within a specified range. /// /// The value to clamp. /// The minimum value. /// The maximum value. /// The clamped value. public static LVector2 Clamp(LVector2 value, LVector2 min, LVector2 max) { float x = value.X; x = (x > max.X) ? max.X : x; x = (x < min.X) ? min.X : x; float y = value.Y; y = (y > max.Y) ? max.Y : y; y = (y < min.Y) ? min.Y : y; return new LVector2(x, y); } /// /// Performs a linear interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// The linear interpolation of the two vectors. /// /// This method performs the linear interpolation based on the following formula. /// start + (end - start) * amount /// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned. /// public static LVector2 Lerp(LVector2 start, LVector2 end, float amount) { LVector2 vector; vector.X = start.X + ((end.X - start.X) * amount); vector.Y = start.Y + ((end.Y - start.Y) * amount); return vector; } /// /// Converts the vector into a unit vector. /// /// The vector to normalize. /// The normalized vector. public static LVector2 Normalize(LVector2 vector) { vector.Normalize(); return vector; } /// /// Calculates the dot product of two vectors. /// /// First source vector. /// Second source vector. /// The dot product of the two vectors. public static float Dot(LVector2 left, LVector2 right) => (left.X * right.X + left.Y * right.Y); /// /// Returns the reflection of a vector off a surface that has the specified normal. /// /// The source vector. /// Normal of the surface. /// The reflected vector. /// Reflect only gives the direction of a reflection off a surface, it does not determine /// whether the original vector was close enough to the surface to hit it. public static LVector2 Reflect(LVector2 vector, LVector2 normal) { LVector2 result; float dot = ((vector.X * normal.X) + (vector.Y * normal.Y)); result.X = vector.X - ((2.0f * dot) * normal.X); result.Y = vector.Y - ((2.0f * dot) * normal.Y); return result; } /// /// Returns a vector containing the smallest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// A vector containing the smallest components of the source vectors. public static LVector2 Minimize(LVector2 left, LVector2 right) { LVector2 vector; vector.X = (left.X < right.X) ? left.X : right.X; vector.Y = (left.Y < right.Y) ? left.Y : right.Y; return vector; } /// /// Returns a vector containing the largest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// A vector containing the largest components of the source vectors. public static LVector2 Maximize(LVector2 left, LVector2 right) { LVector2 vector; vector.X = (left.X > right.X) ? left.X : right.X; vector.Y = (left.Y > right.Y) ? left.Y : right.Y; return vector; } /// /// Adds two vectors. /// /// The first vector to add. /// The second vector to add. /// The sum of the two vectors. public static LVector2 operator +(LVector2 left, LVector2 right) => new LVector2(left.X + right.X, left.Y + right.Y); /// /// Subtracts two vectors. /// /// The first vector to subtract. /// The second vector to subtract. /// The difference of the two vectors. public static LVector2 operator -(LVector2 left, LVector2 right) => new LVector2(left.X - right.X, left.Y - right.Y); /// /// Reverses the direction of a given vector. /// /// The vector to negate. /// A vector facing in the opposite direction. public static LVector2 operator -(LVector2 value) => new LVector2(-value.X, -value.Y); /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static LVector2 operator *(LVector2 vector, float scale) => new LVector2(vector.X * scale, vector.Y * scale); /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static LVector2 operator *(float scale, LVector2 vector) => new LVector2(vector.X * scale, vector.Y * scale); /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static LVector2 operator /(LVector2 vector, float scale) => new LVector2(vector.X / scale, vector.Y / scale); /// /// Tests for equality between two objects. /// /// The first value to compare. /// The second value to compare. /// if has the same value as ; otherwise, . public static bool operator ==(LVector2 left, LVector2 right) => Equals(left, right); /// /// Tests for inequality between two objects. /// /// The first value to compare. /// The second value to compare. /// if has a different value than ; otherwise, . public static bool operator !=(LVector2 left, LVector2 right) => !Equals(left, right); /// /// Converts a Vector2 to a Vector3 implicitly. /// public static implicit operator LVector3(LVector2 vector) => new LVector3(vector.X, vector.Y, 0); /// /// Converts the value of the object to its equivalent string representation. /// /// The string representation of the value of this instance. public override string ToString() { return string.Format(CultureInfo.CurrentCulture, "X:{0} Y:{1}", X, Y); } /// /// Converts the value of the object to its equivalent string representation. /// /// The format. /// The string representation of the value of this instance. public string ToString(string format) { if (format == null) { return ToString(); } return string.Format(CultureInfo.CurrentCulture, "X:{0} Y:{1}", X.ToString(format, CultureInfo.CurrentCulture), Y.ToString(format, CultureInfo.CurrentCulture)); } /// /// Returns the hash code for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { unchecked { return (X.GetHashCode() * 397) ^ Y.GetHashCode(); } } /// /// Returns a value that indicates whether the current instance is equal to a specified object. /// /// Object to make the comparison with. /// if the current instance is equal to the specified object; otherwise, . public override bool Equals(object obj) { if (obj == null || obj.GetType() != GetType()) { return false; } return Equals((LVector2)obj); } /// /// Returns a value that indicates whether the current instance is equal to the specified object. /// /// Object to make the comparison with. /// if the current instance is equal to the specified object; otherwise. public bool Equals(LVector2 other) => (X == other.X && Y == other.Y); public static implicit operator LVector2(Vector2 v) => new(v.X, v.Y); public static implicit operator Vector2(LVector2 v) => new(v.X, v.Y); } }