using System;
namespace Syntriax.Engine.Core;
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")]
public record Vector2D(float X, float Y)
{
public float Magnitude => Length(this);
public float MagnitudeSquared => LengthSquared(this);
public Vector2D Normalized => Normalize(this);
public readonly static Vector2D Up = new(0f, 1f);
public readonly static Vector2D Down = new(0f, -1f);
public readonly static Vector2D Left = new(-1f, 0f);
public readonly static Vector2D Right = new(1f, 0f);
public readonly static Vector2D Zero = new(0f, 0f);
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 float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector));
public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y;
public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to));
public static Vector2D Invert(Vector2D vector) => -vector;
public static Vector2D Add(Vector2D left, Vector2D right) => left + right;
public static Vector2D Subtract(Vector2D left, Vector2D right) => left - right;
public static Vector2D Multiply(Vector2D vector, float value) => vector * value;
public static Vector2D Subdivide(Vector2D vector, float value) => vector / value;
public static Vector2D Normalize(Vector2D vector) => vector / Length(vector);
public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal;
public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from;
public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y);
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);
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);
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);
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));
public static Vector2D Lerp(Vector2D from, Vector2D to, float t) => from + FromTo(from, to) * t;
public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X;
public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right)));
public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y;
///
/// Finds the Orientation of 3 s
///
/// 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;
}
public static bool ApproximatelyEquals(Vector2D left, Vector2D right, float epsilon = float.Epsilon)
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon);
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
}