using System; using System.Runtime.InteropServices; using Chernobyl.Mathematics.Utility; namespace Chernobyl.Mathematics.Vectors { /// Represents a 2D vector using two integers. [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector2Int : IEquatable { #region Fields /// /// The X component of the Vector2Int. /// public int X; /// /// The Y component of the Vector2Int. /// public int Y; #endregion #region Constructors /// /// Constructs a new Vector2Int. /// /// The x coordinate of the net Vector2Int. /// The y coordinate of the net Vector2Int. public Vector2Int(int x, int y) { X = x; Y = y; } #endregion #region Public Members #region Instance #region public void Add() /// Add the Vector passed as parameter to this instance. /// Right operand. This parameter is only read from. public void Add(Vector2Int right) { X += right.X; Y += right.Y; } /// Add the Vector passed as parameter to this instance. /// Right operand. This parameter is only read from. public void Add(ref Vector2Int right) { X += right.X; Y += right.Y; } #endregion public void Add() #region public void Sub() /// Subtract the Vector passed as parameter from this instance. /// Right operand. This parameter is only read from. public void Sub(Vector2Int right) { X -= right.X; Y -= right.Y; } /// Subtract the Vector passed as parameter from this instance. /// Right operand. This parameter is only read from. public void Sub(ref Vector2Int right) { X -= right.X; Y -= right.Y; } #endregion public void Sub() #region public void Mult() /// Multiply this instance by a scalar. /// Scalar operand. public void Mult(int f) { X *= f; Y *= f; } #endregion public void Mult() #region public void Div() /// Divide this instance by a scalar. /// Scalar operand. public void Div(int f) { X /= f; Y /= f; } #endregion public void Div() #region public int Length /// /// Gets the length (magnitude) of the vector. /// /// /// public int Length => (int)Math.Sqrt(X * X + Y * Y); #endregion #region public int LengthFast /// /// Gets an approximation of the vector length (magnitude). /// /// /// This property uses an approximation of the square root function to calculate vector /// magnitude, with an upper error bound of 0.001. /// /// /// public int LengthFast => (int)(1.0f / Functions.InverseSqrtFast(X * X + Y * Y)); #endregion #region public int LengthSquared /// /// Gets the square of the vector length (magnitude). /// /// /// This property avoids the costly square root operation required by the Length property. /// This makes it more suitable for comparisons. /// /// /// public int LengthSquared => X * X + Y * Y; #endregion #region public Vector2Int PerpendicularRight /// /// Gets the perpendicular vector on the right side of this vector. /// public Vector2Int PerpendicularRight => new Vector2Int(Y, -X); #endregion #region public Vector2Int PerpendicularLeft /// /// Gets the perpendicular vector on the left side of this vector. /// public Vector2Int PerpendicularLeft => new Vector2Int(-Y, X); #endregion #region public void Normalize() /// /// Scales the Vector2Int to unit length. /// public void Normalize() { var length = Length; X /= length; Y /= length; } #endregion #region public void NormalizeFast() /// /// Scales the Vector2Int to approximately unit length. /// public void NormalizeFast() { var length = LengthFast; X /= length; Y /= length; } #endregion #region public void Scale() /// /// Scales the current Vector2Int by the given amounts. /// /// The scale of the X component. /// The scale of the Y component. public void Scale(int sx, int sy) { X = X * sx; Y = Y * sy; } /// Scales this instance by the given parameter. /// The scaling of the individual components. public void Scale(Vector2Int scale) { X *= scale.X; Y *= scale.Y; } /// Scales this instance by the given parameter. /// The scaling of the individual components. public void Scale(ref Vector2Int scale) { X *= scale.X; Y *= scale.Y; } #endregion public void Scale() #endregion #region Static #region Fields /// /// Defines a unit-length Vector2Int that points towards the X-axis. /// public static readonly Vector2Int UnitX = new Vector2Int(1, 0); /// /// Defines a unit-length Vector2Int that points towards the Y-axis. /// public static readonly Vector2Int UnitY = new Vector2Int(0, 1); /// /// Defines a zero-length Vector2Int. /// public static readonly Vector2Int Zero = new Vector2Int(0, 0); /// /// Defines an instance with all components set to 1. /// public static readonly Vector2Int One = new Vector2Int(1, 1); /// /// Defines the size of the Vector2Int struct in bytes. /// public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2Int()); #endregion #region Add /// /// Add two Vectors /// /// First operand /// Second operand /// Result of addition public static Vector2Int Add(Vector2Int a, Vector2Int b) { a.X += b.X; a.Y += b.Y; return a; } /// /// Add two Vectors /// /// First operand /// Second operand /// Result of addition public static void Add(ref Vector2Int a, ref Vector2Int b, out Vector2Int result) { result.X = a.X + b.X; result.Y = a.Y + b.Y; } #endregion #region Sub /// /// Subtract one Vector from another /// /// First operand /// Second operand /// Result of subtraction public static Vector2Int Sub(Vector2Int a, Vector2Int b) { a.X -= b.X; a.Y -= b.Y; return a; } /// /// Subtract one Vector from another /// /// First operand /// Second operand /// Result of subtraction public static void Sub(ref Vector2Int a, ref Vector2Int b, out Vector2Int result) { result.X = a.X - b.X; result.Y = a.Y - b.Y; } #endregion #region Mult /// /// Multiply a vector and a scalar /// /// Vector operand /// Scalar operand /// Result of the multiplication public static Vector2Int Mult(Vector2Int a, int f) { a.X *= f; a.Y *= f; return a; } /// /// Multiply a vector and a scalar /// /// Vector operand /// Scalar operand /// Result of the multiplication public static void Mult(ref Vector2Int a, int f, out Vector2Int result) { result.X = a.X * f; result.Y = a.Y * f; } #endregion #region Div /// /// Divide a vector by a scalar /// /// Vector operand /// Scalar operand /// Result of the division public static Vector2Int Div(Vector2Int a, int f) { a.X /= f; a.Y /= f; return a; } /// /// Divide a vector by a scalar /// /// Vector operand /// Scalar operand /// Result of the division public static void Div(ref Vector2Int a, int f, out Vector2Int result) { result.X = a.X / f; result.Y = a.Y / f; } #endregion #region ComponentMin /// /// Calculate the component-wise minimum of two vectors /// /// First operand /// Second operand /// The component-wise minimum public static Vector2Int ComponentMin(Vector2Int a, Vector2Int b) { a.X = a.X < b.X ? a.X : b.X; a.Y = a.Y < b.Y ? a.Y : b.Y; return a; } /// /// Calculate the component-wise minimum of two vectors /// /// First operand /// Second operand /// The component-wise minimum public static void ComponentMin(ref Vector2Int a, ref Vector2Int b, out Vector2Int result) { result.X = a.X < b.X ? a.X : b.X; result.Y = a.Y < b.Y ? a.Y : b.Y; } #endregion #region ComponentMax /// /// Calculate the component-wise maximum of two vectors /// /// First operand /// Second operand /// The component-wise maximum public static Vector2Int ComponentMax(Vector2Int a, Vector2Int b) { a.X = a.X > b.X ? a.X : b.X; a.Y = a.Y > b.Y ? a.Y : b.Y; return a; } /// /// Calculate the component-wise maximum of two vectors /// /// First operand /// Second operand /// The component-wise maximum public static void ComponentMax(ref Vector2Int a, ref Vector2Int b, out Vector2Int result) { result.X = a.X > b.X ? a.X : b.X; result.Y = a.Y > b.Y ? a.Y : b.Y; } #endregion #region Min /// /// Returns the Vector3 with the minimum magnitude /// /// Left operand /// Right operand /// The minimum Vector3 public static Vector2Int Min(Vector2Int left, Vector2Int right) => left.LengthSquared < right.LengthSquared ? left : right; #endregion #region Max /// /// Returns the Vector3 with the minimum magnitude /// /// Left operand /// Right operand /// The minimum Vector3 public static Vector2Int Max(Vector2Int left, Vector2Int right) => left.LengthSquared >= right.LengthSquared ? left : right; #endregion #region Clamp /// /// Clamp a vector to the given minimum and maximum vectors /// /// Input vector /// Minimum vector /// Maximum vector /// The clamped vector public static Vector2Int Clamp(Vector2Int vec, Vector2Int min, Vector2Int max) { vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; return vec; } /// /// Clamp a vector to the given minimum and maximum vectors /// /// Input vector /// Minimum vector /// Maximum vector /// The clamped vector public static void Clamp(ref Vector2Int vec, ref Vector2Int min, ref Vector2Int max, out Vector2Int result) { result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X; result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y; } #endregion #region Dot /// /// Calculate the dot (scalar) product of two vectors /// /// First operand /// Second operand /// The dot product of the two inputs public static int Dot(Vector2Int left, Vector2Int right) => left.X * right.X + left.Y * right.Y; /// /// Calculate the dot (scalar) product of two vectors /// /// First operand /// Second operand /// The dot product of the two inputs public static void Dot(ref Vector2Int left, ref Vector2Int right, out int result) => result = left.X * right.X + left.Y * right.Y; #endregion #region Lerp /// /// Returns a new Vector that is the linear blend of the 2 given Vectors /// /// First input vector /// Second input vector /// The blend factor. a when blend=0, b when blend=1. /// a when blend=0, b when blend=1, and a linear combination otherwise public static Vector2Int Lerp(Vector2Int a, Vector2Int b, int blend) { a.X = blend * (b.X - a.X) + a.X; a.Y = blend * (b.Y - a.Y) + a.Y; return a; } /// /// Returns a new Vector that is the linear blend of the 2 given Vectors /// /// First input vector /// Second input vector /// The blend factor. a when blend=0, b when blend=1. /// a when blend=0, b when blend=1, and a linear combination otherwise public static void Lerp(ref Vector2Int a, ref Vector2Int b, int blend, out Vector2Int result) { result.X = blend * (b.X - a.X) + a.X; result.Y = blend * (b.Y - a.Y) + a.Y; } #endregion #region Coordinates /// /// Get the coordinates for the cell above this. /// public Vector2Int GetNorthCoordinates() => this + new Vector2Int(0, 1); /// /// Get the coordinates for the cell above and to the right of this. /// public Vector2Int GetNorthEastCoordinates() => this + new Vector2Int(1, 1); /// /// Get the coordinates for the cell to the right of this. /// public Vector2Int GetEastCoordinates() => this + new Vector2Int(1, 0); /// /// Get the coordinates for the cell below and to the right this. /// public Vector2Int GetSouthEastCoordinates() => this + new Vector2Int(1, -1); /// /// Get the coordinates for the cell below this. /// public Vector2Int GetSouthCoordinates() => this + new Vector2Int(0, -1); /// /// Get the coordinates for the cell below and to the left this. /// public Vector2Int GetSouthWestCoordinates() => this + new Vector2Int(-1, -1); /// /// Get the coordinates for the cell to the left of this. /// public Vector2Int GetWestCoordinates() => this + new Vector2Int(-1, 0); /// /// Get the coordinates for the cell above and to the left of this. /// public Vector2Int GetNorthWestCoordinates() => this + new Vector2Int(-1, 1); #endregion #endregion #region Operators /// /// Adds two vectors together. /// /// The left side of the operand. /// The right side of the operand. /// The result of the addition. public static Vector2Int operator +(Vector2Int left, Vector2Int right) { left.X += right.X; left.Y += right.Y; return left; } /// /// Subtracts two vectors from each other. /// /// The left side of the operand. /// The right side of the operand. /// The result of the negation. public static Vector2Int operator -(Vector2Int left, Vector2Int right) { left.X -= right.X; left.Y -= right.Y; return left; } /// /// Negates a vector. /// /// The vector to be negated. /// The result of the multiplication. public static Vector2Int operator -(Vector2Int vec) { vec.X = -vec.X; vec.Y = -vec.Y; return vec; } /// /// Multiplies a vector by a scalar. /// /// The left side of the operand. /// The right side of the operand. /// The result of the multiplication. public static Vector2Int operator *(Vector2Int vec, int v) { vec.X *= v; vec.Y *= v; return vec; } /// /// Multiplies a vector by a scalar. /// /// The left side of the operand. /// The right side of the operand. /// The result of the multiplication. public static Vector2Int operator *(int v, Vector2Int vec) { vec.X *= v; vec.Y *= v; return vec; } /// /// Divides a vector by a scalar. /// /// The left side of the operand. /// The right side of the operand. /// The result of the multiplication. public static Vector2Int operator /(Vector2Int vec, int v) { vec.X /= v; vec.Y /= v; return vec; } /// /// Checks if two vectors are equal. /// /// The left side of the operand. /// The right side of the operand. /// True if they are equal, false if otherwise. public static bool operator ==(Vector2Int left, Vector2Int right) => left.Equals(right); /// /// Checks if two vectors are not equal. /// /// The left side of the operand. /// The right side of the operand. /// True if they are not equal, false if otherwise. public static bool operator !=(Vector2Int left, Vector2Int right) => !left.Equals(right); /// Converts a tuple to a Vector2Int. public static implicit operator Vector2Int((int X, int Y) t) => new Vector2Int(t.X, t.Y); /// Converts a tuple to a Vector2Int. public static implicit operator Vector2Int(Tuple t) => new Vector2Int(t.Item1, t.Item2); /// Converts a Vector2Int to a tuple. public static implicit operator (int X, int Y) (Vector2Int v) => (v.X, v.Y); /// Converts a Vector2Int to a tuple. public static implicit operator Tuple(Vector2Int v) => Tuple.Create(v.X, v.Y); /// Converts a Vector2Int to a Vector2. public static implicit operator Vector2(Vector2Int v) => new Vector2(v.X, v.Y); /// Converts a Vector2Int to a Vector3. public static implicit operator Vector3(Vector2Int v) => new Vector3(v.X, v.Y, 0); #endregion #region Overrides #region public override string ToString() /// /// Returns a System.String that represents the current Vector2Int. /// /// public override string ToString() { return $"({X}, {Y})"; } #endregion #region public override int GetHashCode() /// /// Returns the hashcode for this instance. /// /// A System.Int32 containing the unique hashcode for this instance. public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode(); #endregion #region public override bool Equals(object obj) /// /// Indicates whether this instance and a specified object are equal. /// /// The object to compare to. /// True if the instances are equal; false otherwise. public override bool Equals(object obj) { return obj is Vector2Int vector && Equals(vector); } #endregion #endregion #endregion #region IEquatable Members /// Indicates whether the current vector is equal to another vector. /// A vector to compare with this vector. /// true if the current vector is equal to the vector parameter; otherwise, false. public bool Equals(Vector2Int other) => X == other.X && Y == other.Y; #endregion } }