HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
axis_aligned_rectangle.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "numeric_array.hpp"
8#include "../alignment.hpp"
9#include "../concepts.hpp"
10#include "extent.hpp"
11#include "point.hpp"
12#include <concepts>
13
14namespace tt {
15
19private:
20 friend class sfloat_rgba32;
21
27 f32x4 v;
28
29public:
30 axis_aligned_rectangle() noexcept : v() {}
31 axis_aligned_rectangle(axis_aligned_rectangle const &rhs) noexcept = default;
32 axis_aligned_rectangle &operator=(axis_aligned_rectangle const &rhs) noexcept = default;
33 axis_aligned_rectangle(axis_aligned_rectangle &&rhs) noexcept = default;
34 axis_aligned_rectangle &operator=(axis_aligned_rectangle &&rhs) noexcept = default;
35
36 explicit axis_aligned_rectangle(f32x4 const &other) noexcept : v(other)
37 {
38 tt_axiom(is_valid());
39 }
40
48 axis_aligned_rectangle(float x, float y, float width, float height) noexcept : v{x, y, x + width, y + height}
49 {
50 tt_axiom(is_valid());
51 }
52
57 explicit axis_aligned_rectangle(extent2 const &extent) noexcept : v(static_cast<f32x4>(extent)._00xy())
58 {
59 tt_axiom(is_valid());
60 }
61
66 axis_aligned_rectangle(point2 const &p0, point2 const &p3) noexcept :
67 v(static_cast<f32x4>(p0).xy00() + static_cast<f32x4>(p3)._00xy())
68 {
69 tt_axiom(p0.is_valid());
70 tt_axiom(p3.is_valid());
71 tt_axiom(is_valid());
72 }
73
78 axis_aligned_rectangle(point2 const &p0, extent2 const &extent) noexcept :
79 v(static_cast<f32x4>(p0).xyxy() + static_cast<f32x4>(extent)._00xy())
80 {
81 tt_axiom(is_valid());
82 }
83
87 [[nodiscard]] bool is_valid() const noexcept
88 {
89 return le(v, v.zwzw()) == 0b1111;
90 }
91
94 [[nodiscard]] bool empty() const noexcept
95 {
96 return eq(v, v.zwxy()) == 0b1111;
97 }
98
101 [[nodiscard]] operator bool() const noexcept
102 {
103 return !empty();
104 }
105
112 {
113 return *this = *this | rhs;
114 }
115
122 {
123 return *this = *this | rhs;
124 }
125
126 [[nodiscard]] constexpr point2 operator[](size_t i) const noexcept
127 {
128 switch (i) {
129 case 0: return point2{v.xy01()};
130 case 1: return point2{v.zy01()};
131 case 2: return point2{v.xw01()};
132 case 3: return point2{v.zw01()};
133 default: tt_no_default();
134 }
135 }
136
137 template<int I>
138 [[nodiscard]] constexpr friend point2 get(axis_aligned_rectangle const &rhs) noexcept
139 {
140 if constexpr (I == 0) {
141 return point2{rhs.v.xy01()};
142 } else if constexpr (I == 1) {
143 return point2{rhs.v.zy01()};
144 } else if constexpr (I == 2) {
145 return point2{rhs.v.xw01()};
146 } else if constexpr (I == 3) {
147 return point2{rhs.v.zw01()};
148 } else {
149 tt_static_no_default();
150 }
151 }
152
157 [[nodiscard]] extent2 extent() const noexcept
158 {
159 return extent2{v.zwzw() - v};
160 }
161
162 [[nodiscard]] float width() const noexcept
163 {
164 return (v.zwzw() - v).x();
165 }
166
167 [[nodiscard]] float height() const noexcept
168 {
169 return (v.zwzw() - v).y();
170 }
171
172 [[nodiscard]] float bottom() const noexcept
173 {
174 return v.y();
175 }
176
177 [[nodiscard]] float top() const noexcept
178 {
179 return v.w();
180 }
181
182 [[nodiscard]] float left() const noexcept
183 {
184 return v.x();
185 }
186
187 [[nodiscard]] float right() const noexcept
188 {
189 return v.z();
190 }
191
194 [[nodiscard]] float middle() const noexcept
195 {
196 return (bottom() + top()) * 0.5f;
197 }
198
201 [[nodiscard]] float center() const noexcept
202 {
203 return (left() + right()) * 0.5f;
204 }
205
206 axis_aligned_rectangle &set_width(float newWidth) noexcept
207 {
208 v = v.xyxw() + f32x4{0.0f, 0.0f, newWidth, 0.0f};
209 return *this;
210 }
211
212 axis_aligned_rectangle &set_height(float newHeight) noexcept
213 {
214 v = v.xyzy() + f32x4{0.0f, 0.0f, 0.0f, newHeight};
215 return *this;
216 }
217
222 [[nodiscard]] bool contains(point2 const &rhs) const noexcept
223 {
224 // No need to check with empty due to half open range check.
225 return ge(static_cast<f32x4>(rhs).xyxy(), v) == 0b0011;
226 }
227
234 [[nodiscard]] friend axis_aligned_rectangle
235 align(axis_aligned_rectangle haystack, axis_aligned_rectangle needle, alignment alignment) noexcept
236 {
237 float x;
238 if (alignment == horizontal_alignment::left) {
239 x = haystack.left();
240
241 } else if (alignment == horizontal_alignment::right) {
242 x = haystack.right() - needle.width();
243
244 } else if (alignment == horizontal_alignment::center) {
245 x = haystack.center() - needle.width() * 0.5f;
246
247 } else {
248 tt_no_default();
249 }
250
251 float y;
252 if (alignment == vertical_alignment::bottom) {
253 y = haystack.bottom();
254
255 } else if (alignment == vertical_alignment::top) {
256 y = haystack.top() - needle.height();
257
258 } else if (alignment == vertical_alignment::middle) {
259 y = haystack.middle() - needle.height() * 0.5f;
260
261 } else {
262 tt_no_default();
263 }
264
265 return {point2{x, y}, needle.extent()};
266 }
267
270 [[nodiscard]] static axis_aligned_rectangle
271 _align(axis_aligned_rectangle outside, axis_aligned_rectangle inside, alignment alignment) noexcept
272 {
273 return align(outside, inside, alignment);
274 }
275
276 [[nodiscard]] friend bool operator==(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
277 {
278 return lhs.v == rhs.v;
279 }
280
281 [[nodiscard]] friend bool operator!=(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
282 {
283 return !(lhs == rhs);
284 }
285
286 [[nodiscard]] friend bool overlaps(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
287 {
288 if (lhs.empty() || rhs.empty()) {
289 return false;
290 }
291
292 ttlet rhs_swap = rhs.v.zwxy();
293
294 // lhs.p0.x > rhs.p3.x | lhs.p0.y > rhs.p3.y
295 if ((gt(lhs.v, rhs_swap) & 0b0011) != 0) {
296 return false;
297 }
298
299 // lhs.p3.x < rhs.p0.x | lhs.p3.y < rhs.p0.y
300 if ((lt(lhs.v, rhs_swap) & 0b1100) != 0) {
301 return false;
302 }
303
304 return true;
305 }
306
307 [[nodiscard]] friend axis_aligned_rectangle
308 operator|(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
309 {
310 if (!lhs) {
311 return rhs;
312 } else if (!rhs) {
313 return lhs;
314 } else {
315 return axis_aligned_rectangle{min(get<0>(lhs), get<0>(rhs)), max(get<3>(lhs), get<3>(rhs))};
316 }
317 }
318
319 [[nodiscard]] friend axis_aligned_rectangle operator|(axis_aligned_rectangle const &lhs, point2 const &rhs) noexcept
320 {
321 if (!lhs) {
322 return axis_aligned_rectangle{rhs, rhs};
323 } else {
324 return axis_aligned_rectangle{min(get<0>(lhs), rhs), max(get<3>(lhs), rhs)};
325 }
326 }
327
330 [[nodiscard]] friend point2 center(axis_aligned_rectangle const &rhs) noexcept
331 {
332 return get<0>(rhs) + (get<3>(rhs) - get<0>(rhs)) * 0.5f;
333 }
334
340 [[nodiscard]] friend axis_aligned_rectangle scale(axis_aligned_rectangle const &lhs, float rhs) noexcept
341 {
342 ttlet extent = lhs.extent();
343 ttlet scaled_extent = extent * rhs;
344 ttlet diff_extent = scaled_extent - extent;
345 ttlet half_diff_extent = diff_extent * 0.5f;
346
347 ttlet p1 = get<0>(lhs) - vector2{half_diff_extent};
348 ttlet p2 = get<3>(lhs) + vector2{half_diff_extent};
349 return axis_aligned_rectangle{p1, p2};
350 }
351
358 [[nodiscard]] friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, float rhs) noexcept
359 {
360 return axis_aligned_rectangle{lhs.v + neg<0b0011>(f32x4::broadcast(rhs))};
361 }
362
369 [[nodiscard]] friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, float rhs) noexcept
370 {
371 return expand(lhs, -rhs);
372 }
373
374 [[nodiscard]] friend axis_aligned_rectangle round(axis_aligned_rectangle const &rhs) noexcept
375 {
376 auto p0 = round(get<0>(rhs));
377 auto p3 = round(get<3>(rhs));
378 return axis_aligned_rectangle{p0, p3};
379 }
380
383 [[nodiscard]] friend axis_aligned_rectangle ceil(axis_aligned_rectangle const &rhs) noexcept
384 {
385 auto p0 = floor(get<0>(rhs));
386 auto p3 = ceil(get<3>(rhs));
387 return axis_aligned_rectangle{p0, p3};
388 }
389
392 [[nodiscard]] friend axis_aligned_rectangle floor(axis_aligned_rectangle const &rhs) noexcept
393 {
394 auto p0 = ceil(get<0>(rhs));
395 auto p3 = floor(get<3>(rhs));
396 return axis_aligned_rectangle{p0, p3};
397 }
398
402 [[nodiscard]] friend axis_aligned_rectangle
404 {
405 ttlet p0 = max(get<0>(lhs), get<0>(rhs));
406 ttlet p3 = min(get<3>(lhs), get<3>(rhs));
407 if (p0.x() < p3.x() && p0.y() < p3.y()) {
408 return {p0, p3};
409 } else {
410 return {};
411 }
412 }
413
421 [[nodiscard]] friend axis_aligned_rectangle
423};
424
426
427} // namespace tt
Definition sfloat_rgba32.hpp:15
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:18
friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, float rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition axis_aligned_rectangle.hpp:369
axis_aligned_rectangle & operator|=(axis_aligned_rectangle const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition axis_aligned_rectangle.hpp:111
bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition axis_aligned_rectangle.hpp:222
extent2 extent() const noexcept
Get size of the rectangle.
Definition axis_aligned_rectangle.hpp:157
static axis_aligned_rectangle _align(axis_aligned_rectangle outside, axis_aligned_rectangle inside, alignment alignment) noexcept
Need to call the hiden friend function from within another class.
Definition axis_aligned_rectangle.hpp:271
friend axis_aligned_rectangle ceil(axis_aligned_rectangle const &rhs) noexcept
Round rectangle by expanding to pixel edge.
Definition axis_aligned_rectangle.hpp:383
friend point2 center(axis_aligned_rectangle const &rhs) noexcept
Get the center of the rectangle.
Definition axis_aligned_rectangle.hpp:330
float middle() const noexcept
The middle on the y-axis between bottom and top.
Definition axis_aligned_rectangle.hpp:194
axis_aligned_rectangle(point2 const &p0, extent2 const &extent) noexcept
Create a rectangle from the size.
Definition axis_aligned_rectangle.hpp:78
axis_aligned_rectangle(point2 const &p0, point2 const &p3) noexcept
Create a rectangle from the left-bottom and right-top points.
Definition axis_aligned_rectangle.hpp:66
friend axis_aligned_rectangle fit(axis_aligned_rectangle const &bounds, axis_aligned_rectangle const &rectangle) noexcept
Make a rectangle fit inside bounds.
friend axis_aligned_rectangle scale(axis_aligned_rectangle const &lhs, float rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition axis_aligned_rectangle.hpp:340
friend axis_aligned_rectangle floor(axis_aligned_rectangle const &rhs) noexcept
Round rectangle by shrinking to pixel edge.
Definition axis_aligned_rectangle.hpp:392
axis_aligned_rectangle(float x, float y, float width, float height) noexcept
Create a box from the position and size.
Definition axis_aligned_rectangle.hpp:48
friend axis_aligned_rectangle align(axis_aligned_rectangle haystack, axis_aligned_rectangle needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition axis_aligned_rectangle.hpp:235
friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, float rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition axis_aligned_rectangle.hpp:358
axis_aligned_rectangle & operator|=(point2 const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition axis_aligned_rectangle.hpp:121
bool is_valid() const noexcept
Make sure p0 is left/bottom from p3.
Definition axis_aligned_rectangle.hpp:87
bool empty() const noexcept
Check if the rectangle has no area.
Definition axis_aligned_rectangle.hpp:94
axis_aligned_rectangle(extent2 const &extent) noexcept
Create a rectangle from the size.
Definition axis_aligned_rectangle.hpp:57
friend axis_aligned_rectangle intersect(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
Return the overlapping part of two rectangles.
Definition axis_aligned_rectangle.hpp:403
float center() const noexcept
The center on the x-axis between left and right.
Definition axis_aligned_rectangle.hpp:201
Class which represents an rectangle.
Definition rectangle.hpp:16
T max(T... args)
T min(T... args)