197
src/Math.cppm
Normal file
197
src/Math.cppm
Normal file
@@ -0,0 +1,197 @@
|
||||
module;
|
||||
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
export module LunarWM.Math;
|
||||
|
||||
export namespace LunarWM {
|
||||
namespace Math {
|
||||
|
||||
template <typename T = float>
|
||||
requires std::is_arithmetic_v<T>
|
||||
struct Vec2 {
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<U> operator+(Vec2<U> const &other) {
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<U> operator-(Vec2<U> const &other) {
|
||||
return {x - other.x, y - other.y};
|
||||
}
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<U> operator*(Vec2<U> const &other) {
|
||||
return {x * other.x, y * other.x};
|
||||
}
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<U> operator*(T scalar) {
|
||||
return {x * scalar, y * scalar};
|
||||
}
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<U> operator/(T scalar) {
|
||||
return {x / scalar, y / scalar};
|
||||
}
|
||||
template <typename U = T>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2 operator-() {
|
||||
return {-x, -y};
|
||||
}
|
||||
T length() const { return std::sqrt(x * x + y * y); }
|
||||
T lengthSquared() const { return x * x + y * y; }
|
||||
Vec2<T> normalized() const {
|
||||
T len = length();
|
||||
if (len == T(0))
|
||||
return {T(0), T(0)};
|
||||
return *this / len;
|
||||
}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires std::is_arithmetic_v<T>
|
||||
Vec2<T> operator*(T scalar, Vec2<T> const &v) {
|
||||
return {v.x * scalar, v.y * scalar};
|
||||
}
|
||||
|
||||
template <typename T = float>
|
||||
requires std::is_arithmetic_v<T>
|
||||
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<T> pos, size;
|
||||
};
|
||||
|
||||
template <typename T = float>
|
||||
requires std::is_arithmetic_v<T>
|
||||
struct Box {
|
||||
template <typename U = int>
|
||||
requires std::is_arithmetic_v<U>
|
||||
Vec2<T> &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<T> &first() { return m_data[0]; }
|
||||
Vec2<T> &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<T> rect) {
|
||||
this->m_data[0] = rect.pos;
|
||||
this->m_data[0] = rect.pos + rect.size;
|
||||
}
|
||||
|
||||
private:
|
||||
Vec2<T> m_data[2] = {};
|
||||
};
|
||||
|
||||
template <typename T = int>
|
||||
requires std::is_arithmetic_v<T>
|
||||
std::vector<Math::Rect<T>> subtract_rect(Math::Rect<T> const &src,
|
||||
Math::Rect<T> const &clip) {
|
||||
std::vector<Math::Rect<T>> 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
|
||||
Reference in New Issue
Block a user