namespace Theriapolis.Core.Util; /// /// Lightweight 2D float vector for world-pixel-space polyline coordinates. /// Intentionally avoids System.Numerics to keep Core dependency-free. /// public readonly struct Vec2 { public readonly float X; public readonly float Y; public Vec2(float x, float y) { X = x; Y = y; } public static Vec2 operator +(Vec2 a, Vec2 b) => new(a.X + b.X, a.Y + b.Y); public static Vec2 operator -(Vec2 a, Vec2 b) => new(a.X - b.X, a.Y - b.Y); public static Vec2 operator *(Vec2 a, float s) => new(a.X * s, a.Y * s); public static Vec2 operator *(float s, Vec2 a) => new(a.X * s, a.Y * s); public static Vec2 operator /(Vec2 a, float s) => new(a.X / s, a.Y / s); public float LengthSquared => X * X + Y * Y; public float Length => MathF.Sqrt(LengthSquared); public Vec2 Normalized { get { float len = Length; return len < 1e-6f ? new Vec2(0, 0) : this * (1f / len); } } /// 90° CCW rotation — perpendicular vector. public Vec2 Perp => new(-Y, X); public static float Dot(Vec2 a, Vec2 b) => a.X * b.X + a.Y * b.Y; public static float DistSq(Vec2 a, Vec2 b) => (a - b).LengthSquared; public static float Dist(Vec2 a, Vec2 b) => (a - b).Length; /// Linear interpolation between a and b at parameter t. public static Vec2 Lerp(Vec2 a, Vec2 b, float t) => a + (b - a) * t; public override string ToString() => $"({X:F1}, {Y:F1})"; }