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
}
}