header_utils
Loading...
Searching...
No Matches
rec2.h
1
4
5#pragma once
6
7#include <glm/common.hpp>
8#include <glm/vec2.hpp>
9#include <span>
10#include <functional>
11
12#define GHPL_HAS_REC2
13
15
16namespace ghassanpl
17{
18 template <template<typename> typename HASHER, typename FIRST, typename... T>
19 [[nodiscard]] constexpr size_t hash(FIRST&& first, T&&... values);
20
21 static inline constexpr struct bounding_box_for_t {} bounding_box_for;
22
23 template <typename T>
24 struct trec2
25 {
26 glm::tvec2<T> p1 = { 0,0 };
27 glm::tvec2<T> p2 = { 0,0 };
28
29 using tvec = glm::tvec2<T>;
30 using value_type = T;
31
32 constexpr trec2() noexcept = default;
33 constexpr trec2(tvec a, tvec b) noexcept : p1(a), p2(b) { }
34 explicit constexpr trec2(std::span<tvec const> points) noexcept
35 {
36 *this = trec2::exclusive();
37 for (auto& p : points)
38 include(p);
39 }
40
41 template <std::same_as<tvec>... ARGS>
42 explicit constexpr trec2(bounding_box_for_t, ARGS&&... args) noexcept
43 {
44 *this = trec2::exclusive();
45 (this->include(std::forward<ARGS>(args)), ...);
46 }
47
48 constexpr explicit trec2(tvec a) noexcept : p1(), p2(a) { }
49 constexpr trec2(T x1, T y1, T x2, T y2) noexcept : p1(x1, y1), p2(x2, y2) { }
50 constexpr trec2(const trec2&) noexcept = default;
51 constexpr trec2(trec2&&) noexcept = default;
53 constexpr explicit trec2(const trec2<U>& other) noexcept : p1(glm::tvec2<U>(other.p1)), p2(glm::tvec2<U>(other.p2)) {}
54 template <typename U>
55 constexpr explicit trec2(trec2<U>&& other) noexcept : p1(glm::tvec2<U>(other.p1)), p2(glm::tvec2<U>(other.p2)) {}
56
57 constexpr trec2& operator=(const trec2&) noexcept = default;
58 constexpr trec2& operator=(trec2&&) noexcept = default;
59
60 static constexpr trec2 from_points(std::span<tvec const> points) noexcept { return trec2{points}; }
61 template <std::same_as<tvec>... ARGS>
62 static constexpr trec2 from_points(ARGS&&... args) noexcept { return trec2(bounding_box_for, std::forward<ARGS>(args)...); }
63 static constexpr trec2 from_size(tvec s) noexcept { return { tvec{}, s }; };
64 static constexpr trec2 from_size(tvec p, tvec s) noexcept { return { p, p + s }; };
65 static constexpr trec2 from_size(T x, T y, T w, T h) noexcept { return { x, y, x + w, y + h }; };
66 static constexpr trec2 from_center_and_size(tvec p, tvec s) noexcept { return { p - s / T(2), p + s / T(2) }; };
67 static constexpr trec2 from_center_and_size(T x, T y, T w, T h) noexcept { return { x - w / T(2), y - h / T(2), x + w / T(2), y + h / T(2) }; };
68
69 static constexpr trec2 const& invalid() noexcept { static constexpr trec2 invalid = { T{1}, T{1}, T{-1}, T{-1} }; return invalid; };
70 static constexpr trec2 const& exclusive() noexcept
71 {
72 if constexpr (std::numeric_limits<T>::has_infinity)
73 {
74 static constexpr trec2 exclusive = { std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity() };
75 return exclusive;
76 }
77 else
78 {
79 static constexpr trec2 exclusive = { std::numeric_limits<T>::max(), std::numeric_limits<T>::max(), std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest() };
80 return exclusive;
81 }
82 }
83 static constexpr trec2 const& inclusive() noexcept
84 {
85 if constexpr (std::numeric_limits<T>::has_infinity)
86 {
87 static constexpr trec2 inclusive = { -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity() };
88 return inclusive;
89 }
90 else
91 {
92 static constexpr trec2 inclusive = { std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max(), std::numeric_limits<T>::max() };
93 return inclusive;
94 }
95 }
96
97 constexpr trec2 operator+(tvec op) const noexcept { return { p1 + op, p2 + op }; }
98 constexpr trec2& operator+=(tvec op) noexcept { p1 += op; p2 += op; return *this; };
99 constexpr trec2 operator-(tvec op) const noexcept { return { p1 - op, p2 - op }; }
100 constexpr trec2& operator-=(tvec op) noexcept { p1 -= op; p2 -= op; return *this; };
101 constexpr trec2 operator*(T op) const noexcept { return { p1 * op, p2 * op }; }
102 constexpr trec2 operator/(T op) const noexcept { return { p1 / op, p2 / op }; }
103 constexpr trec2 operator*(tvec op) const noexcept { return { p1 * op, p2 * op }; }
104 constexpr trec2 operator/(tvec op) const noexcept { return { p1 / op, p2 / op }; }
105
106 constexpr auto operator<=>(trec2 const& other) const noexcept = default;
107
108 constexpr tvec operator[](size_t i) const noexcept
109 {
110 switch (i % 4)
111 {
112 case 0: return p1;
113 case 1: return right_top();
114 case 2: return p2;
115 case 3: return left_bottom();
116 }
117 return {};
118 }
119
120 template <typename U> struct values_t { U left; U top; U right; U bottom; };
121 template <typename U> values_t(U&& left, U&& top, U&& right, U&& bottom) -> values_t<U>;
122#ifndef __clang__
123 template <typename SELF>
124 constexpr auto values(this SELF&& self) noexcept
125 {
126 return values_t {
127 std::forward_like<SELF>(self.p1.x),
128 std::forward_like<SELF>(self.p1.y),
129 std::forward_like<SELF>(self.p2.x),
130 std::forward_like<SELF>(self.p2.y)
131 };
132 }
133#endif
134
135 constexpr tvec size() const noexcept { return p2 - p1; }
136 constexpr tvec position() const noexcept { return p1; }
137 constexpr trec2& set_position(tvec pos) noexcept { p2 += pos - p1; p1 = pos; return *this; }
138 constexpr trec2& set_position(T x, T y) noexcept { p2.x += x - p1.x; p2.y += y - p1.y; p1 = { x, y }; return *this; }
139 constexpr trec2& set_x(T x) noexcept { p2.x += x - p1.x; p1.x = x; return *this; }
140 constexpr trec2& set_y(T y) noexcept { p2.y += y - p1.y; p1.y = y; return *this; }
141 constexpr trec2& set_size(tvec size) noexcept { p2 = p1 + size; return *this; }
142 constexpr trec2& set_size(T w, T h) noexcept { p2.x = p1.x + w; p2.y = p1.y + h; return *this; }
143
144 constexpr trec2& grow(T by) noexcept { p1.x -= by; p1.y -= by; p2.x += by; p2.y += by; return *this; }
145 constexpr trec2& shrink(T by) noexcept { return grow(-by); }
146 constexpr trec2& grow(tvec by) noexcept { p1 -= by; p2 += by; return *this; }
147 constexpr trec2& shrink(tvec by) noexcept { return grow(-by); }
148 constexpr trec2 grown(T by) const noexcept { auto copy = *this; copy.p1.x -= by; copy.p1.y -= by; copy.p2.x += by; copy.p2.y += by; return copy; }
149 constexpr trec2 shrunk(T by) const noexcept { return grown(-by); }
150 constexpr trec2 grown(tvec by) const noexcept { auto copy = *this; copy.p1 -= by; copy.p2 += by; return copy; }
151 constexpr trec2 shrunk(tvec by) const noexcept { return grown(-by); }
152 constexpr trec2& grow(T left, T top, T right, T bottom) noexcept { p1.x -= left; p1.y -= top; p2.x += right; p2.y += bottom; return *this; }
153 constexpr trec2& shrink(T left, T top, T right, T bottom) noexcept { return grow(-left, -top, -right, -bottom); }
154 constexpr trec2 grown(T left, T top, T right, T bottom) const noexcept { auto copy = *this; copy.p1.x -= left; copy.p1.y -= top; copy.p2.x += right; copy.p2.y += bottom; return copy; }
155 constexpr trec2 shrunk(T left, T top, T right, T bottom) const noexcept { return grown(-left, -top, -right, -bottom); }
156
157 constexpr trec2 at_position(tvec pos) const noexcept { auto copy = *this; copy.set_position(pos); return copy; }
158 constexpr trec2 at_position(T x, T y) const noexcept { auto copy = *this; copy.set_position(x, y); return copy; }
159 constexpr trec2 sized(tvec size) const noexcept { auto copy = *this; copy.set_size(size); return copy; }
160 constexpr trec2 sized(T w, T h) const noexcept { auto copy = *this; copy.set_size(w, h); return copy; }
161 constexpr trec2 translated(tvec op) const noexcept { return *this + op; }
162 constexpr trec2 translated(T x, T y) const noexcept { return *this + tvec{ x, y }; }
163 constexpr trec2 scaled(tvec op) const noexcept { return *this * op; }
164 constexpr trec2 scaled(T x, T y) const noexcept { return *this * tvec{ x, y }; }
165 constexpr trec2 scaled(T s) const noexcept { return *this * s; }
166 constexpr T width() const noexcept { return p2.x - p1.x; };
167 constexpr T height() const noexcept { return p2.y - p1.y; };
168 constexpr trec2& set_width(T w) noexcept { p2.x = p1.x + w; return *this; };
169 constexpr trec2& set_height(T h) noexcept { p2.y = p1.y + h; return *this; };
170 constexpr T x() const noexcept { return p1.x; }
171 constexpr T y() const noexcept { return p1.y; }
172 constexpr T left() const noexcept { return p1.x; }
173 constexpr T top() const noexcept { return p1.y; }
174 constexpr T right() const noexcept { return p2.x; }
175 constexpr T bottom() const noexcept { return p2.y; }
176 constexpr tvec left_top() const noexcept { return p1; }
177 constexpr tvec left_bottom() const noexcept { return { p1.x, p2.y }; }
178 constexpr tvec right_top() const noexcept { return { p2.x, p1.y }; }
179 constexpr tvec right_bottom() const noexcept { return p2; }
180 constexpr tvec half_size() const noexcept { return (p2 - p1) / T{ 2 }; }
181 constexpr tvec center() const noexcept { return p1 + half_size(); }
182 constexpr trec2& set_center(tvec pos) noexcept { const auto hw = half_size(); p1 = pos - hw; p2 = pos + hw; return *this; }
183 constexpr trec2 at_center(tvec pos) const noexcept { auto copy = *this; copy.set_center(pos); return copy; }
184
185 constexpr trec2 local() const noexcept { return { tvec{}, size() }; }
186 constexpr trec2 relative_to(trec2 const& other) const noexcept { return { p1 - other.position(), p2 - other.position() }; }
187
188 constexpr trec2 to_global(trec2 const& parent_rect) const noexcept { return { p1 + parent_rect.position(), p2 + parent_rect.position() }; }
189
190 constexpr glm::vec2 to_rect_space(tvec world_space) const noexcept { return glm::vec2{ world_space - p1 } / glm::vec2{ size() }; }
191 constexpr tvec to_world_space(glm::vec2 rect_space) const noexcept { return tvec{ rect_space * glm::vec2{ size() } } + p1; }
192
193 constexpr trec2& include(tvec pt) noexcept { this->p1 = glm::min(this->p1, pt); this->p2 = glm::max(this->p2, pt); return *this; };
194 constexpr trec2& include(trec2 const& rec) noexcept { return this->include(rec.p1).include(rec.p2); };
195
196 constexpr trec2 including(tvec pt) const noexcept { return { glm::min(this->p1, pt), glm::max(this->p2, pt) }; };
197 constexpr trec2 including(trec2 const& rec) const noexcept { return this->include(rec.p1).include(rec.p2); };
198
199 constexpr bool intersects(trec2 const& other) const noexcept
200 {
201 return (left() <= other.right() && other.left() <= right() && top() <= other.bottom() && other.top() <= bottom());
202 }
203
204 constexpr trec2 intersection(trec2 const& other) const noexcept
205 {
206 auto x1 = std::max(std::min(p1.x, p2.x), std::min(other.p1.x, other.p2.x));
207 auto y1 = std::max(std::min(p1.y, p2.y), std::min(other.p1.y, other.p2.y));
208 auto x2 = std::min(std::max(p1.x, p2.x), std::max(other.p1.x, other.p2.x));
209 auto y2 = std::min(std::max(p1.y, p2.y), std::max(other.p1.y, other.p2.y));
210 return { x1,y1,x2,y2 };
211 }
212
213 constexpr trec2 clipped_to(trec2 const& other) const noexcept
214 {
215 return intersection(other);
216 }
217
218 constexpr bool contains(glm::vec<2, T> const& other) const noexcept
219 {
220 return other.x >= p1.x && other.y >= p1.y && other.x < p2.x && other.y < p2.y;
221 }
222
224 constexpr bool contains(trec2 const& other) const noexcept
225 {
226 return other.p1.x >= p1.x && other.p1.y >= p1.y && other.p2.x <= p2.x && other.p2.y <= p2.y;
227 }
228
229 constexpr bool is_valid() const noexcept
230 {
231 return p1.x <= p2.x && p1.y <= p2.y;
232 }
233
234 constexpr trec2 valid() const noexcept
235 {
236 auto copy = *this;
237 if (copy.p1.x > copy.p2.x) std::swap(copy.p1.x, copy.p2.x);
238 if (copy.p1.y > copy.p2.y) std::swap(copy.p1.y, copy.p2.y);
239 return copy;
240 }
241
242 constexpr trec2& make_valid() noexcept
243 {
244 if (p1.x > p2.x) std::swap(p1.x, p2.x);
245 if (p1.y > p2.y) std::swap(p1.y, p2.y);
246 return *this;
247 }
248
249 constexpr std::pair<trec2, trec2> split_vertical(T top_height) const noexcept
250 {
251 if (top_height < 0)
252 top_height = this->height() + top_height;
253 return { trec2::from_size(this->p1, {this->width(), top_height}), trec2::from_size(this->p1 + tvec{0, top_height}, {this->width(), this->height() - top_height}) };
254 }
255
256 constexpr std::pair<trec2, trec2> split_horizontal(T left_width) const noexcept
257 {
258 if (left_width < 0)
259 left_width = this->width() + left_width;
260 return { trec2::from_size(this->p1, {left_width, this->height()}), trec2::from_size(this->p1 + tvec{left_width, 0}, {this->width() - left_width, this->height()})};
261 }
262
263 constexpr T calculate_area() const noexcept { return width() * height(); }
264
265 constexpr T edge_length() const noexcept { return (width() + height()) * 2; }
266
267 constexpr glm::vec2 edge_point_alpha(double edge_progress) const
268 {
269 edge_progress = glm::fract(edge_progress);
270 const auto w = width();
271 const auto h = height();
272 const auto el = (w + h) * 2;
273 const auto d = static_cast<T>(edge_progress * el);
274 if (d < w)
275 return glm::mix(this->left_top(), this->right_top(), d / w);
276 else if (d < w + h)
277 return glm::mix(this->right_top(), this->right_bottom(), (d - w) / h);
278 else if (d < w + h + w)
279 return glm::mix(this->right_bottom(), this->left_bottom(), (d - (w + h)) / w);
280 else
281 return glm::mix(this->left_bottom(), this->left_top(), (d - (w + h + w)) / h);
282 }
283
284 constexpr glm::vec2 edge_point(double edge_pos) const
285 {
286 const auto w = width();
287 const auto h = height();
288 edge_pos = fmod(edge_pos, (w + h) * 2);
289 if (edge_pos < w)
290 return glm::mix(this->left_top(), this->right_top(), edge_pos / w);
291 else if (edge_pos < w + h)
292 return glm::mix(this->right_top(), this->right_bottom(), (edge_pos - w) / h);
293 else if (edge_pos < w + h + w)
294 return glm::mix(this->right_bottom(), this->left_bottom(), (edge_pos - (w + h)) / w);
295 else
296 return glm::mix(this->left_bottom(), this->left_top(), (edge_pos - (w + h + w)) / h);
297 }
298
299 constexpr trec2 bounding_box() const noexcept
300 {
301 return *this;
302 }
303
304 constexpr glm::vec2 projected(glm::vec2 pt) const
305 {
306 const auto d = (pt - p1) / size();
307 const auto c = glm::clamp(d, glm::vec2{ 0 }, glm::vec2{ 1 });
308 return p1 + c * size();
309 }
310
312 };
313
314
315 template <typename T>
316 trec2<T> operator+(glm::tvec2<T> op, trec2<T> rec) noexcept { return { rec.p1 + op, rec.p2 + op }; }
317
318 template <typename T, typename STRINGIFIER>
319 auto stringify(STRINGIFIER& str, trec2<T>& b) { return str('[', b.p1.x, ',', b.p1.y, ',', b.p2.x, ',', b.p2.y, ']'); }
320 template <typename T, typename STRINGIFIER>
321 auto stringify(STRINGIFIER& str, trec2<T> const& b) { return str('[', b.p1.x, ',', b.p1.y, ',', b.p2.x, ',', b.p2.y, ']'); }
322}
323
324
325template <typename T>
326struct std::hash<ghassanpl::trec2<T>>
327{
328 std::size_t operator()(ghassanpl::trec2<T> const& s) const noexcept
329 {
330 return ghassanpl::hash(s.p1, s.p2);
331 }
332};
333
334#ifdef GHPL_HAS_ALIGN
335#include "align+rec2.h"
336#endif
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
constexpr __contains_fn contains
contains(range, el)
Definition ranges.h:247
@ invalid
Represents an invalid plane number.
Primary namespace for everything in this library.
Definition align+rec2.h:10