HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
aarect.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 <concepts>
11
12namespace tt {
13
16template<typename T>
18private:
19 friend class sfloat_rgba32;
20
27
28public:
29 axis_aligned_rectangle() noexcept : v() {}
30 axis_aligned_rectangle(axis_aligned_rectangle const &rhs) noexcept = default;
31 axis_aligned_rectangle &operator=(axis_aligned_rectangle const &rhs) noexcept = default;
32 axis_aligned_rectangle(axis_aligned_rectangle &&rhs) noexcept = default;
33 axis_aligned_rectangle &operator=(axis_aligned_rectangle &&rhs) noexcept = default;
34
42 axis_aligned_rectangle(tt::arithmetic auto x, tt::arithmetic auto y, tt::arithmetic auto width, tt::arithmetic auto height) noexcept :
43 v({narrow_cast<T>(x),
44 narrow_cast<T>(y),
45 narrow_cast<T>(x) + narrow_cast<T>(width),
46 narrow_cast<T>(y) + narrow_cast<T>(height)})
47 {
48 }
49
55 axis_aligned_rectangle(tt::arithmetic auto width, tt::arithmetic auto height) noexcept :
56 v(numeric_array<T, 4>(0.0f, 0.0f, narrow_cast<T>(width), narrow_cast<T>(height)))
57 {
58 }
59
65 axis_aligned_rectangle(numeric_array<T,4> const &position, numeric_array<T,4> const &extent) noexcept : v(position.xyxy() + extent._00xy())
66 {
67 tt_axiom(position.is_point());
68 tt_axiom(position.z() == 0.0);
69 tt_axiom(extent.is_vector());
70 tt_axiom(extent.z() == 0.0);
71 }
72
77 explicit axis_aligned_rectangle(numeric_array<T,4> const &extent) noexcept : v(extent._00xy())
78 {
79 tt_axiom(extent.is_vector());
80 tt_axiom(extent.z() == 0.0);
81 }
82
86 [[nodiscard]] static axis_aligned_rectangle p0p3(numeric_array<T,4> const &v) noexcept
87 {
89 r.v = v;
90 return r;
91 }
92
97 [[nodiscard]] static axis_aligned_rectangle p0p3(numeric_array<T,4> const &p0, numeric_array<T,4> const &p3) noexcept
98 {
99 tt_axiom(p0.is_point());
100 tt_axiom(p3.is_point());
101 return axis_aligned_rectangle::p0p3(p0.xy00() + p3._00xy());
102 }
103
104 [[nodiscard]] static axis_aligned_rectangle infinity() noexcept requires (std::floating_point<T>)
105 {
111 }
112
116 [[nodiscard]] bool valid() const noexcept
117 {
118 return le(v, v.zwzw()) == 0b1111;
119 }
120
123 [[nodiscard]] bool empty() const noexcept
124 {
125 return eq(v, v.zwxy()) == 0b1111;
126 }
127
130 [[nodiscard]] operator bool() const noexcept
131 {
132 return !empty();
133 }
134
141 {
142 return *this = *this | rhs;
143 }
144
151 {
152 return *this = *this | rhs;
153 }
154
160 {
161 return *this = *this + rhs;
162 }
163
169 {
170 return *this = *this - rhs;
171 }
172
178 {
179 return *this = *this * rhs;
180 }
181
187 template<size_t I>
188 [[nodiscard]] numeric_array<T,4> corner() const noexcept
189 {
190 static_assert(I <= 3);
191 if constexpr (I == 0) {
192 return v.xy01();
193 } else if constexpr (I == 1) {
194 return v.zy01();
195 } else if constexpr (I == 2) {
196 return v.xw01();
197 } else {
198 return v.zw01();
199 }
200 }
201
202 [[nodiscard]] numeric_array<T,4> p0() const noexcept
203 {
204 return corner<0>();
205 }
206
207 [[nodiscard]] numeric_array<T,4> p3() const noexcept
208 {
209 return corner<3>();
210 }
211
216 [[nodiscard]] numeric_array<T,4> offset() const noexcept
217 {
218 return v.xy00();
219 }
220
225 [[nodiscard]] numeric_array<T,4> extent() const noexcept
226 {
227 return (v.zwzw() - v).xy00();
228 }
229
230 [[nodiscard]] T x() const noexcept
231 {
232 return v.x();
233 }
234
235 [[nodiscard]] T y() const noexcept
236 {
237 return v.y();
238 }
239
240 [[nodiscard]] T width() const noexcept
241 {
242 return (v.zwzw() - v).x();
243 }
244
245 [[nodiscard]] T height() const noexcept
246 {
247 return (v.zwzw() - v).y();
248 }
249
250 [[nodiscard]] T bottom() const noexcept
251 {
252 return v.y();
253 }
254
255 [[nodiscard]] T top() const noexcept
256 {
257 return v.w();
258 }
259
260 [[nodiscard]] T left() const noexcept
261 {
262 return v.x();
263 }
264
265 [[nodiscard]] T right() const noexcept
266 {
267 return v.z();
268 }
269
272 [[nodiscard]] T middle() const noexcept
273 {
274 return (bottom() + top()) * 0.5f;
275 }
276
279 [[nodiscard]] T center() const noexcept
280 {
281 return (left() + right()) * 0.5f;
282 }
283
284 axis_aligned_rectangle &set_width(T newWidth) noexcept
285 {
286 v = v.xyxw() + numeric_array<T,4>{0.0f, 0.0f, newWidth, 0.0f};
287 return *this;
288 }
289
290 axis_aligned_rectangle &set_height(T newHeight) noexcept
291 {
292 v = v.xyzy() + numeric_array<T,4>{0.0f, 0.0f, 0.0f, newHeight};
293 return *this;
294 }
295
300 [[nodiscard]] bool contains(numeric_array<T,4> const &rhs) const noexcept
301 {
302 // No need to check with empty due to half open range check.
303 return ge(rhs.xyxy(), v) == 0b0011;
304 }
305
312 [[nodiscard]] friend axis_aligned_rectangle align(axis_aligned_rectangle haystack, axis_aligned_rectangle needle, alignment alignment) noexcept
313 {
314 T x;
315 if (alignment == horizontal_alignment::left) {
316 x = haystack.p0().x();
317
318 } else if (alignment == horizontal_alignment::right) {
319 x = haystack.p3().x() - needle.width();
320
321 } else if (alignment == horizontal_alignment::center) {
322 x = (haystack.p0().x() + (haystack.width() * 0.5f)) - (needle.width() * 0.5f);
323
324 } else {
325 tt_no_default();
326 }
327
328 T y;
329 if (alignment == vertical_alignment::bottom) {
330 y = haystack.p0().y();
331
332 } else if (alignment == vertical_alignment::top) {
333 y = haystack.p3().y() - needle.height();
334
335 } else if (alignment == vertical_alignment::middle) {
336 y = (haystack.p0().y() + (haystack.height() * 0.5f)) - (needle.height() * 0.5f);
337
338 } else {
339 tt_no_default();
340 }
341
342 return {numeric_array<T,4>::point({x, y}), needle.extent()};
343 }
344
347 [[nodiscard]] static axis_aligned_rectangle _align(axis_aligned_rectangle outside, axis_aligned_rectangle inside, alignment alignment) noexcept
348 {
349 return align(outside, inside, alignment);
350 }
351
352 [[nodiscard]] friend bool operator==(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
353 {
354 return lhs.v == rhs.v;
355 }
356
357 [[nodiscard]] friend bool operator!=(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
358 {
359 return !(lhs == rhs);
360 }
361
362 [[nodiscard]] friend bool overlaps(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
363 {
364 if (lhs.empty() || rhs.empty()) {
365 return false;
366 }
367
368 ttlet rhs_swap = rhs.v.zwxy();
369
370 // lhs.p0.x > rhs.p3.x | lhs.p0.y > rhs.p3.y
371 if ((gt(lhs.v, rhs_swap) & 0b0011) != 0) {
372 return false;
373 }
374
375 // lhs.p3.x < rhs.p0.x | lhs.p3.y < rhs.p0.y
376 if ((lt(lhs.v, rhs_swap) & 0b1100) != 0) {
377 return false;
378 }
379
380 return true;
381 }
382
383 [[nodiscard]] friend axis_aligned_rectangle operator|(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
384 {
385 if (!lhs) {
386 return rhs;
387 } else if (!rhs) {
388 return lhs;
389 } else {
390 return axis_aligned_rectangle::p0p3(min(lhs.p0(), rhs.p0()), max(lhs.p3(), rhs.p3()));
391 }
392 }
393
394 [[nodiscard]] friend axis_aligned_rectangle operator|(axis_aligned_rectangle const &lhs, numeric_array<T,4> const &rhs) noexcept
395 {
396 tt_axiom(rhs.is_point());
397 if (!lhs) {
398 return axis_aligned_rectangle::p0p3(rhs, rhs);
399 } else {
400 return axis_aligned_rectangle::p0p3(min(lhs.p0(), rhs), max(lhs.p3(), rhs));
401 }
402 }
403
404 [[nodiscard]] friend axis_aligned_rectangle operator+(axis_aligned_rectangle const &lhs, numeric_array<T,4> const &rhs) noexcept
405 {
406 return axis_aligned_rectangle::p0p3(lhs.v + rhs.xyxy());
407 }
408
409 [[nodiscard]] friend axis_aligned_rectangle operator-(axis_aligned_rectangle const &lhs, numeric_array<T,4> const &rhs) noexcept
410 {
411 return axis_aligned_rectangle::p0p3(lhs.v - rhs.xyxy());
412 }
413
414 [[nodiscard]] friend axis_aligned_rectangle operator*(axis_aligned_rectangle const &lhs, T rhs) noexcept
415 {
416 return axis_aligned_rectangle::p0p3(lhs.v * rhs);
417 }
418
421 [[nodiscard]] friend numeric_array<T,4> center(axis_aligned_rectangle const &rhs) noexcept
422 {
423 return (rhs.p0() + rhs.p3()) * 0.5f;
424 }
425
431 [[nodiscard]] friend axis_aligned_rectangle scale(axis_aligned_rectangle const &lhs, T rhs) noexcept
432 {
433 ttlet extent = lhs.extent();
434 ttlet scaled_extent = extent * rhs;
435 ttlet diff_extent = scaled_extent - extent;
436 ttlet half_diff_extent = diff_extent * 0.5f;
437
438 ttlet p1 = lhs.p0() - half_diff_extent;
439 ttlet p2 = lhs.p3() + half_diff_extent;
440 return axis_aligned_rectangle::p0p3(p1, p2);
441 }
442
449 [[nodiscard]] friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, T rhs) noexcept
450 {
451 return axis_aligned_rectangle::p0p3(lhs.v + neg<0b0011>(numeric_array<T,4>{rhs, rhs, rhs, rhs}));
452 }
453
460 [[nodiscard]] friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, numeric_array<T,4> rhs) noexcept
461 {
462 return axis_aligned_rectangle::p0p3(lhs.v + neg<1, 1, 0, 0>(rhs.xyxy()));
463 }
464
471 [[nodiscard]] friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, T rhs) noexcept
472 {
473 return expand(lhs, -rhs);
474 }
475
482 [[nodiscard]] friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, numeric_array<T,4> rhs) noexcept
483 {
484 return expand(lhs, -rhs);
485 }
486
487 [[nodiscard]] friend axis_aligned_rectangle round(axis_aligned_rectangle const &rhs) noexcept
488 {
489 return axis_aligned_rectangle::p0p3(round(rhs.v));
490 }
491
494 [[nodiscard]] friend axis_aligned_rectangle ceil(axis_aligned_rectangle const &rhs) noexcept
495 {
496 auto p0 = floor(rhs.p0());
497 auto p3 = ceil(rhs.p3());
498 return axis_aligned_rectangle::p0p3(p0, p3);
499 }
500
503 [[nodiscard]] friend axis_aligned_rectangle floor(axis_aligned_rectangle const &rhs) noexcept
504 {
505 auto p0 = ceil(rhs.p0());
506 auto p3 = floor(rhs.p3());
507 return axis_aligned_rectangle::p0p3(p0, p3);
508 }
509
513 [[nodiscard]] friend axis_aligned_rectangle intersect(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
514 {
515 ttlet p0 = max(lhs.p0(), rhs.p0());
516 ttlet p3 = max(p0, min(lhs.p3(), rhs.p3()));
517 return axis_aligned_rectangle::p0p3(p0, p3);
518 }
519
527 [[nodiscard]] friend axis_aligned_rectangle fit(axis_aligned_rectangle const &bounds, axis_aligned_rectangle const &rectangle) noexcept
528 {
529 ttlet resized_rectangle = axis_aligned_rectangle{
530 rectangle.x(),
531 rectangle.y(),
532 std::min(rectangle.width(), bounds.width()),
533 std::min(rectangle.height(), bounds.height())};
534
535 ttlet translate_from_p0 = max(numeric_array<T,4>{}, bounds.p0() - resized_rectangle.p0());
536 ttlet translate_from_p3 = min(numeric_array<T,4>{}, bounds.p3() - resized_rectangle.p3());
537 return resized_rectangle + (translate_from_p0 + translate_from_p3);
538 }
539};
540
541using aarect = axis_aligned_rectangle<float>;
542using iaarect = axis_aligned_rectangle<int>;
543
544} // namespace tt
STL namespace.
Class which represents an axis-aligned rectangle.
Definition aarect.hpp:17
axis_aligned_rectangle & operator-=(numeric_array< T, 4 > const &rhs) noexcept
Translate the box to a new position.
Definition aarect.hpp:168
friend axis_aligned_rectangle scale(axis_aligned_rectangle const &lhs, T rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarect.hpp:431
numeric_array< T, 4 > corner() const noexcept
Get coordinate of a corner.
Definition aarect.hpp:188
friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, numeric_array< T, 4 > rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarect.hpp:460
friend axis_aligned_rectangle ceil(axis_aligned_rectangle const &rhs) noexcept
Round rectangle by expanding to pixel edge.
Definition aarect.hpp:494
axis_aligned_rectangle(numeric_array< T, 4 > const &position, numeric_array< T, 4 > const &extent) noexcept
Create a rectangle from the position and size.
Definition aarect.hpp:65
T center() const noexcept
The center on the x-axis between left and right.
Definition aarect.hpp:279
friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, numeric_array< T, 4 > rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition aarect.hpp:482
static axis_aligned_rectangle p0p3(numeric_array< T, 4 > const &p0, numeric_array< T, 4 > const &p3) noexcept
Create axis_aligned_rectangle from two oposite points.
Definition aarect.hpp:97
friend axis_aligned_rectangle fit(axis_aligned_rectangle const &bounds, axis_aligned_rectangle const &rectangle) noexcept
Make a rectangle fit inside bounds.
Definition aarect.hpp:527
numeric_array< T, 4 > offset() const noexcept
Get vector from origin to the bottom-left corner.
Definition aarect.hpp:216
axis_aligned_rectangle(tt::arithmetic auto x, tt::arithmetic auto y, tt::arithmetic auto width, tt::arithmetic auto height) noexcept
Create a box from the position and size.
Definition aarect.hpp:42
friend axis_aligned_rectangle floor(axis_aligned_rectangle const &rhs) noexcept
Round rectangle by shrinking to pixel edge.
Definition aarect.hpp:503
axis_aligned_rectangle & operator|=(axis_aligned_rectangle const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarect.hpp:140
static axis_aligned_rectangle p0p3(numeric_array< T, 4 > const &v) noexcept
Create axis_aligned_rectangle from packed p0p3 coordinates.
Definition aarect.hpp:86
axis_aligned_rectangle & operator*=(T rhs) noexcept
Scale the box by moving the positions (scaling the vectors).
Definition aarect.hpp:177
friend axis_aligned_rectangle align(axis_aligned_rectangle haystack, axis_aligned_rectangle needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarect.hpp:312
friend numeric_array< T, 4 > center(axis_aligned_rectangle const &rhs) noexcept
Get the center of the rectangle.
Definition aarect.hpp:421
axis_aligned_rectangle(numeric_array< T, 4 > const &extent) noexcept
Create a rectangle from the size.
Definition aarect.hpp:77
T middle() const noexcept
The middle on the y-axis between bottom and top.
Definition aarect.hpp:272
numeric_array< T, 4 > extent() const noexcept
Get size of the rectangle.
Definition aarect.hpp:225
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 aarect.hpp:347
bool valid() const noexcept
Make sure p0 is left/bottom from p3.
Definition aarect.hpp:116
bool contains(numeric_array< T, 4 > const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition aarect.hpp:300
friend axis_aligned_rectangle shrink(axis_aligned_rectangle const &lhs, T rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition aarect.hpp:471
axis_aligned_rectangle(tt::arithmetic auto width, tt::arithmetic auto height) noexcept
Create a box from the position and size.
Definition aarect.hpp:55
friend axis_aligned_rectangle expand(axis_aligned_rectangle const &lhs, T rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarect.hpp:449
friend axis_aligned_rectangle intersect(axis_aligned_rectangle const &lhs, axis_aligned_rectangle const &rhs) noexcept
Return the overlapping part of two rectangles.
Definition aarect.hpp:513
axis_aligned_rectangle & operator+=(numeric_array< T, 4 > const &rhs) noexcept
Translate the box to a new position.
Definition aarect.hpp:159
axis_aligned_rectangle & operator|=(numeric_array< T, 4 > const &rhs) noexcept
Expand the current rectangle to include the new point.
Definition aarect.hpp:150
bool empty() const noexcept
Check if the rectangle has no area.
Definition aarect.hpp:123
Definition sfloat_rgba32.hpp:14
Definition numeric_array.hpp:27
static constexpr numeric_array point() noexcept
Get a point at the origin.
Definition numeric_array.hpp:90
Definition concepts.hpp:15
T infinity(T... args)
T max(T... args)
T min(T... args)