#ifndef UTILS_H #define UTILS_H #include "pch.h" #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y)) struct Color { uint8_t r, g, b, a; }; template struct Vec2 { T x, y; template Vec2 operator*(U s) const { return {x * s, y * s}; } template Vec2 operator/(U s) const { return {x / s, y / s}; } Vec2 operator+(const Vec2 &other) const { return {x + other.x, y + other.y}; } Vec2 operator-(const Vec2 &other) const { return {x - other.x, y - other.y}; } Vec2 operator-() const { return {-x, -y}; } T dot(const Vec2 &o) const { return x * o.x + y * o.y; } float dist(const Vec2 &other) const { float dx = other.x - x; float dy = other.y - y; return std::sqrt(dx * dx + dy * dy); } Vec2 normalized() const { float length = std::sqrt(x * x + y * y); if (length == 0) return {0, 0}; return {x / length, y / length}; } float angle_to(const Vec2 &other) const { float dx = other.x - x; float dy = other.y - y; return std::atan2(dy, dx); } }; struct Line { Vec2 start; Vec2 end; Line(Vec2 start, Vec2 end) : start(start), end(end) {} bool intersects(const Line &other) const { float denom = (other.end.y - other.start.y) * (end.x - start.x) - (other.end.x - other.start.x) * (end.y - start.y); if (std::abs(denom) < 1e-6f) // Lines are parallel (or very close to it) return false; float ua = ((other.end.x - other.start.x) * (start.y - other.start.y) - (other.end.y - other.start.y) * (start.x - other.start.x)) / denom; float ub = ((end.x - start.x) * (start.y - other.start.y) - (end.y - start.y) * (start.x - other.start.x)) / denom; return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1; } }; struct Rect { Line diagonal; // from top-left to bottom-right Rect(Vec2 a, Vec2 b) : diagonal(a, b) { diagonal.start = { MIN(a.x, b.x), MIN(a.y, b.y) }; diagonal.end = { MAX(a.x, b.x), MAX(a.y, b.y) }; } bool contains(const Vec2 &point) const { return point.x >= diagonal.start.x && point.x <= diagonal.end.x && point.y >= diagonal.start.y && point.y <= diagonal.end.y; } bool intersects(const Rect &other) const { return !(diagonal.start.x > other.diagonal.end.x || diagonal.end.x < other.diagonal.start.x || diagonal.start.y > other.diagonal.end.y || diagonal.end.y < other.diagonal.start.y); } bool intersects(const Line &line) const { if (contains(line.start) || contains(line.end)) return true; Vec2 rect_points[4] = { diagonal.start, {diagonal.end.x, diagonal.start.y}, {diagonal.start.x, diagonal.end.y}, diagonal.end }; for (int i = 0; i < 4; i++) { Vec2 edge_start = rect_points[i]; Vec2 edge_end = rect_points[(i + 1) % 4]; if (Line{edge_start, edge_end}.intersects(line)) return true; } return false; } float x() const { return diagonal.start.x; } float y() const { return diagonal.start.y; } float w() const { return diagonal.end.x - diagonal.start.x; } float h() const { return diagonal.end.y - diagonal.start.y; } }; #endif