export module LunarWM.Math; import std; export namespace LunarWM::Math { template requires std::is_arithmetic_v struct Vec2 { template requires std::is_arithmetic_v auto operator+(Vec2 const &other) -> Vec2 { return { x + other.x, y + other.y }; } template requires std::is_arithmetic_v auto operator-(Vec2 const &other) -> Vec2 { return { x - other.x, y - other.y }; } template requires std::is_arithmetic_v auto operator*(Vec2 const &other) -> Vec2 { return { x * other.x, y * other.x }; } template requires std::is_arithmetic_v auto operator*(T scalar) -> Vec2 { return { x * scalar, y * scalar }; } template requires std::is_arithmetic_v auto operator/(T scalar) -> Vec2 { return { x / scalar, y / scalar }; } template requires std::is_arithmetic_v auto operator-() -> Vec2 { return { -x, -y }; } auto length() const -> T { return std::sqrt(x * x + y * y); } auto lengthSquared() const -> T { return x * x + y * y; } auto normalized() const -> Vec2 { T len = length(); if (len == T(0)) { return { T(0), T(0) }; } return *this / len; } T x, y; }; template requires std::is_arithmetic_v auto operator*(T scalar, Vec2 const &v) -> Vec2 { return { v.x * scalar, v.y * scalar }; } template requires std::is_arithmetic_v struct Rect { Rect(Vec2 pos, Vec2 size) : pos(pos) , size(size) { } Rect(T x, T y, T w, T h) : pos({ x, y }) , size({ w, h }) { } auto x() -> T & { return pos.x; } auto y() -> T & { return pos.y; } auto w() -> T & { return size.x; } auto h() -> T & { return size.y; } auto x() const -> T { return pos.x; } auto y() const -> T { return pos.y; } auto w() const -> T { return size.x; } auto h() const -> T { return size.y; } auto left() const -> T { return x(); } auto right() const -> T { return x() + w(); } auto top() const -> T { return y(); } auto bottom() const -> T { return y() + h(); } auto left() -> T & { return x(); } auto top() -> T & { return y(); } Vec2 pos, size; }; template requires std::is_arithmetic_v struct Box { template requires std::is_arithmetic_v auto operator[](U const index) -> Vec2 & { if (index < 0 || index > 1) { throw std::out_of_range("A box only has two points"); } return m_data[index]; } auto first() -> Vec2 & { return m_data[0]; } auto second() -> Vec2 & { return m_data[1]; } auto x0() -> T & { return m_data[0].x; } auto y0() -> T & { return m_data[0].y; } auto x1() -> T & { return m_data[1].x; } auto y1() -> T & { return m_data[1].y; } auto left() -> T & { if (x0() < x1()) { return x0(); } return x1(); } auto right() -> T & { if (x0() > x1()) { return x0(); } return x1(); } auto top() -> T & { if (y0() < y1()) { return y0(); } return y1(); } auto bottom() -> T & { if (y0() > y1()) { return y0(); } return y1(); } Box() = default; explicit Box(Rect rect) { this->m_data[0] = rect.pos; this->m_data[1] = rect.pos + rect.size; } private: std::array, 2> m_data = {}; }; template requires std::is_arithmetic_v auto subtract_rect(Math::Rect const &src, Math::Rect const &clip) -> std::vector> { std::vector> result; auto sx = src.x(); auto sy = src.y(); auto sw = src.w(); auto sh = src.h(); auto cx = clip.x(); auto cy = clip.y(); auto cw = clip.w(); auto ch = clip.h(); T s_right = sx + sw; T s_bottom = sy + sh; T c_right = cx + cw; T c_bottom = cy + ch; // No overlap → keep src if (c_right <= sx || cx >= s_right || c_bottom <= sy || cy >= s_bottom) { result.push_back(src); return result; } // Top piece if (cy > sy) { result.emplace_back(sx, sy, sw, cy - sy); } // Bottom piece if (c_bottom < s_bottom) { result.emplace_back(sx, c_bottom, sw, s_bottom - c_bottom); } // Middle pieces left and right of clip T middle_top = std::max(sy, cy); T middle_bottom = std::min(s_bottom, c_bottom); T middle_height = middle_bottom - middle_top; if (middle_height > 0) { // Left piece if (cx > sx) { result.emplace_back(sx, middle_top, cx - sx, middle_height); } // Right piece if (c_right < s_right) { result.emplace_back( c_right, middle_top, s_right - c_right, middle_height); } } return result; } template requires std::is_arithmetic_v struct Viewport { Rect rect; Vec2 depth_limits; }; template constexpr auto deg2rad(T degrees) -> T { return degrees * (std::numbers::pi / 180.0); } } // namespace LunarWM::Math