#ifndef VEC2_HPP #define VEC2_HPP #include #include #include template class Vec2 { public: T x, y; Vec2() : x(0), y(0) {} Vec2(T x, T y) : x(x), y(y) {} template explicit Vec2(const Vec2& other) : x(static_cast(other.x)), y(static_cast(other.y)) {} Vec2& move(const Vec2 newpos) { x = newpos.x; y = newpos.y; return *this; } Vec2 operator+(const Vec2& other) const { return Vec2(x + other.x, y + other.y); } Vec2 operator-(const Vec2& other) const { return Vec2(x - other.x, y - other.y); } Vec2 operator*(const Vec2& other) const { return Vec2(x * other.x, y * other.y); } Vec2 operator/(const Vec2& other) const { return Vec2(x / other.x, y / other.y); } template Vec2 operator+(U scalar) const { return Vec2(x + scalar, y + scalar); } template Vec2 operator-(U scalar) const { return Vec2(x - scalar, y - scalar); } Vec2 operator-() const { return Vec2(-x, -y); } template Vec2 operator*(U scalar) const { return Vec2(x * scalar, y * scalar); } template Vec2 operator/(U scalar) const { return Vec2(x / scalar, y / scalar); } template Vec2& operator=(U scalar) { x = y = static_cast(scalar); return *this; } Vec2& operator+=(const Vec2& other) { x += other.x; y += other.y; return *this; } Vec2& operator-=(const Vec2& other) { x -= other.x; y -= other.y; return *this; } Vec2& operator*=(const Vec2& other) { x *= other.x; y *= other.y; return *this; } Vec2& operator/=(const Vec2& other) { x /= other.x; y /= other.y; return *this; } template Vec2& operator+=(U scalar) { x += scalar; y += scalar; return *this; } template Vec2& operator-=(U scalar) { x -= scalar; y -= scalar; return *this; } template Vec2& operator*=(U scalar) { x *= scalar; y *= scalar; return *this; } template Vec2& operator/=(U scalar) { x /= scalar; y /= scalar; return *this; } T dot(const Vec2& other) const { return x * other.x + y * other.y; } template U length() const { return std::sqrt(static_cast(x * x + y * y)); } T lengthSquared() const { return x * x + y * y; } template U distance(const Vec2& other) const { return (*this - other).template length(); } T distanceSquared(const Vec2& other) const { Vec2 diff = *this - other; return diff.x * diff.x + diff.y * diff.y; } template Vec2 normalized() const { auto len = length(); if (len > 0) { return Vec2(static_cast(x) / len, static_cast(y) / len); } return Vec2(static_cast(x), static_cast(y)); } bool operator==(const Vec2& other) const { return x == other.x && y == other.y; } bool operator!=(const Vec2& other) const { return x != other.x || y != other.y; } bool operator<(const Vec2& other) const { return (x < other.x) || (x == other.x && y < other.y); } bool operator<=(const Vec2& other) const { return (x < other.x) || (x == other.x && y <= other.y); } bool operator>(const Vec2& other) const { return (x > other.x) || (x == other.x && y > other.y); } bool operator>=(const Vec2& other) const { return (x > other.x) || (x == other.x && y >= other.y); } Vec2 abs() const { return Vec2(std::abs(x), std::abs(y)); } Vec2 floor() const { return Vec2(std::floor(x), std::floor(y)); } Vec2 ceil() const { return Vec2(std::ceil(x), std::ceil(y)); } Vec2 round() const { return Vec2(std::round(x), std::round(y)); } Vec2 min(const Vec2& other) const { return Vec2(std::min(x, other.x), std::min(y, other.y)); } Vec2 max(const Vec2& other) const { return Vec2(std::max(x, other.x), std::max(y, other.y)); } Vec2 clamp(const Vec2& minVal, const Vec2& maxVal) const { return Vec2( std::clamp(x, minVal.x, maxVal.x), std::clamp(y, minVal.y, maxVal.y) ); } template Vec2 clamp(U minVal, U maxVal) const { return Vec2( std::clamp(x, static_cast(minVal), static_cast(maxVal)), std::clamp(y, static_cast(minVal), static_cast(maxVal)) ); } template bool isZero(U epsilon = static_cast(1e-10)) const { return std::abs(static_cast(x)) < epsilon && std::abs(static_cast(y)) < epsilon; } template bool equals(const Vec2& other, U epsilon = static_cast(1e-10)) const { return std::abs(static_cast(x - other.x)) < epsilon && std::abs(static_cast(y - other.y)) < epsilon; } Vec2 perpendicular() const { return Vec2(-y, x); } template Vec2 reflect(const Vec2& normal) const { auto this_f = Vec2(static_cast(x), static_cast(y)); return this_f - static_cast(2.0) * this_f.dot(normal) * normal; } template Vec2 lerp(const Vec2& other, U t) const { t = std::clamp(t, static_cast(0.0), static_cast(1.0)); auto this_f = Vec2(static_cast(x), static_cast(y)); return this_f + (other - this_f) * t; } template Vec2 slerp(const Vec2& other, U t) const { t = std::clamp(t, static_cast(0.0), static_cast(1.0)); auto this_f = Vec2(static_cast(x), static_cast(y)); U dot = this_f.dot(other); dot = std::clamp(dot, static_cast(-1.0), static_cast(1.0)); U theta = std::acos(dot) * t; auto relative = other - this_f * dot; relative = relative.normalized(); return (this_f * std::cos(theta)) + (relative * std::sin(theta)); } template Vec2 rotate(U angle) const { U cosA = std::cos(angle); U sinA = std::sin(angle); return Vec2( static_cast(x) * cosA - static_cast(y) * sinA, static_cast(x) * sinA + static_cast(y) * cosA ); } template U angle() const { return std::atan2(static_cast(y), static_cast(x)); } template U angleTo(const Vec2& other) const { auto this_f = Vec2(static_cast(x), static_cast(y)); return std::acos(this_f.dot(other) / (this_f.length() * other.length())); } template U directionTo(const Vec2& other) const { auto this_f = Vec2(static_cast(x), static_cast(y)); auto direction = other - this_f; return direction.angle(); } T& operator[](int index) { return (&x)[index]; } const T& operator[](int index) const { return (&x)[index]; } std::string toString() const { return "(" + std::to_string(x) + ", " + std::to_string(y) + ")"; } std::ostream& operator<<(std::ostream& os) { os << toString(); return os; } struct Hash { std::size_t operator()(const Vec2& v) const { return std::hash()(v.x) ^ (std::hash()(v.y) << 1); } }; float aspect() { return static_cast(x) / static_cast(y); } Vec2 toFloat() { return Vec2(static_cast(x), static_cast(y)); } }; template inline std::ostream& operator<<(std::ostream& os, const Vec2& vec) { os << vec.toString(); return os; } template auto operator+(U scalar, const Vec2& vec) -> Vec2 { using ResultType = decltype(scalar + vec.x); return Vec2(scalar + vec.x, scalar + vec.y); } template auto operator-(U scalar, const Vec2& vec) -> Vec2 { using ResultType = decltype(scalar - vec.x); return Vec2(scalar - vec.x, scalar - vec.y); } template auto operator*(U scalar, const Vec2& vec) -> Vec2 { using ResultType = decltype(scalar * vec.x); return Vec2(scalar * vec.x, scalar * vec.y); } template auto operator/(U scalar, const Vec2& vec) -> Vec2 { using ResultType = decltype(scalar / vec.x); return Vec2(scalar / vec.x, scalar / vec.y); } namespace std { template struct hash> { size_t operator()(const Vec2& v) const { return hash()(v.x) ^ (hash()(v.y) << 1); } }; } using Vec2f = Vec2; using Vec2d = Vec2; using Vec2i = Vec2; using Vec2u = Vec2; #endif