module; import std; export module LunarWM.Math; export namespace LunarWM { namespace Math { template requires std::is_arithmetic_v struct Vec2 { template requires std::is_arithmetic_v Vec2 operator+(Vec2 const &other) { return {x + other.x, y + other.y}; } template requires std::is_arithmetic_v Vec2 operator-(Vec2 const &other) { return {x - other.x, y - other.y}; } template requires std::is_arithmetic_v Vec2 operator*(Vec2 const &other) { return {x * other.x, y * other.x}; } template requires std::is_arithmetic_v Vec2 operator*(T scalar) { return {x * scalar, y * scalar}; } template requires std::is_arithmetic_v Vec2 operator/(T scalar) { return {x / scalar, y / scalar}; } template requires std::is_arithmetic_v Vec2 operator-() { return {-x, -y}; } T length() const { return std::sqrt(x * x + y * y); } T lengthSquared() const { return x * x + y * y; } Vec2 normalized() const { T len = length(); if (len == T(0)) return {T(0), T(0)}; return *this / len; } T x, y; }; template requires std::is_arithmetic_v Vec2 operator*(T scalar, Vec2 const &v) { return {v.x * scalar, v.y * scalar}; } template requires std::is_arithmetic_v struct Rect { T &x() { return pos.x; } T &y() { return pos.y; } T &w() { return size.x; } T &h() { return size.y; } T x() const { return pos.x; } T y() const { return pos.y; } T w() const { return size.x; } T h() const { return size.y; } T left() const { return x(); } T right() const { return x() + w(); } T top() const { return y(); } T bottom() const { return y() + h(); } T &left() { return x(); } T &top() { return y(); } Rect(T x, T y, T w, T h) : pos({x, y}), size({w, h}) {} Vec2 pos, size; }; template requires std::is_arithmetic_v struct Box { template requires std::is_arithmetic_v Vec2 &operator[](U const index) { if (index < 0 || index > 1) throw std::out_of_range("A box only has two points"); return m_data[index]; } Vec2 &first() { return m_data[0]; } Vec2 &second() { return m_data[1]; } T &x0() { return m_data[0].x; } T &y0() { return m_data[0].y; } T &x1() { return m_data[1].x; } T &y1() { return m_data[1].y; } T &left() { if (x0() < x1()) return x0(); return x1(); } T &right() { if (x0() > x1()) return x0(); return x1(); } T &top() { if (y0() < y1()) return y0(); return y1(); } T &bottom() { if (y0() > y1()) return y0(); return y1(); } Box() {} Box(Rect rect) { this->m_data[0] = rect.pos; this->m_data[1] = rect.pos + rect.size; } private: Vec2 m_data[2] = {}; }; template requires std::is_arithmetic_v std::vector> subtract_rect(Math::Rect const &src, Math::Rect const &clip) { 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; } } // namespace Math } // namespace LunarWM