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