HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
aarectangle.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
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
9#pragma once
10
11#include "alignment.hpp"
12#include "extent2.hpp"
13#include "point2.hpp"
14#include "point3.hpp"
15#include "../SIMD/module.hpp"
16#include "../utility/module.hpp"
17#include "../concurrency/module.hpp"
18#include <concepts>
19#include <mutex>
20
21namespace hi { inline namespace v1 {
22
27public:
28 using array_type = simd<float, 4>;
29 using value_type = array_type::value_type;
30
31 constexpr aarectangle() noexcept : v() {}
32 constexpr aarectangle(aarectangle const& rhs) noexcept = default;
33 constexpr aarectangle& operator=(aarectangle const& rhs) noexcept = default;
34 constexpr aarectangle(aarectangle&& rhs) noexcept = default;
35 constexpr aarectangle& operator=(aarectangle&& rhs) noexcept = default;
36
39 [[nodiscard]] constexpr static aarectangle large() noexcept
40 {
41 return {point2{-large_number_v<float>, -large_number_v<float>}, point2{large_number_v<float>, large_number_v<float>}};
42 }
43
44 constexpr explicit aarectangle(array_type const& other) noexcept : v(other)
45 {
47 }
48
56 constexpr aarectangle(float x, float y, float width, float height) noexcept :
57 v{x, y, x + width, y + height}
58 {
60 }
61
66 constexpr explicit aarectangle(extent2 const& extent) noexcept : v(static_cast<array_type>(extent)._00xy())
67 {
69 }
70
75 constexpr aarectangle(point2 const& p0, point2 const& p3) noexcept :
76 v(static_cast<array_type>(p0).xy00() + static_cast<array_type>(p3)._00xy())
77 {
78 hi_axiom(p0.holds_invariant());
79 hi_axiom(p3.holds_invariant());
81 }
82
90 constexpr aarectangle(point2 const& p0, extent2 const& extent) noexcept :
91 v(static_cast<array_type>(p0).xyxy() + static_cast<array_type>(extent)._00xy())
92 {
94 }
95
96 constexpr explicit operator array_type() const noexcept
97 {
98 return v;
99 }
100
104 [[nodiscard]] constexpr bool holds_invariant() const noexcept
105 {
106 return (v <= v.zwzw()).mask() == 0b1111;
107 }
108
111 [[nodiscard]] constexpr bool empty() const noexcept
112 {
113 return (v == v.zwxy()).mask() == 0b1111;
114 }
115
118 [[nodiscard]] constexpr explicit operator bool() const noexcept
119 {
120 return not empty();
121 }
122
128 constexpr aarectangle& operator|=(aarectangle const& rhs) noexcept
129 {
130 return *this = *this | rhs;
131 }
132
138 constexpr aarectangle& operator|=(point2 const& rhs) noexcept
139 {
140 return *this = *this | rhs;
141 }
142
143 [[nodiscard]] constexpr point2 operator[](std::size_t i) const noexcept
144 {
145 switch (i) {
146 case 0:
147 return point2{v.xy01()};
148 case 1:
149 return point2{v.zy01()};
150 case 2:
151 return point2{v.xw01()};
152 case 3:
153 return point2{v.zw01()};
154 default:
156 }
157 }
158
159 template<int I>
160 [[nodiscard]] constexpr friend point2 get(aarectangle const& rhs) noexcept
161 {
162 if constexpr (I == 0) {
163 return point2{rhs.v.xy01()};
164 } else if constexpr (I == 1) {
165 return point2{rhs.v.zy01()};
166 } else if constexpr (I == 2) {
167 return point2{rhs.v.xw01()};
168 } else if constexpr (I == 3) {
169 return point2{rhs.v.zw01()};
170 } else {
172 }
173 }
174
179 [[nodiscard]] constexpr extent2 size() const noexcept
180 {
181 return extent2{v.zwzw() - v};
182 }
183
184 [[nodiscard]] constexpr value_type x() const noexcept
185 {
186 return v.x();
187 }
188
189 [[nodiscard]] constexpr value_type y() const noexcept
190 {
191 return v.y();
192 }
193
194 [[nodiscard]] constexpr value_type width() const noexcept
195 {
196 return (v.zwzw() - v).x();
197 }
198
199 [[nodiscard]] constexpr value_type height() const noexcept
200 {
201 return (v.zwzw() - v).y();
202 }
203
204 [[nodiscard]] constexpr value_type bottom() const noexcept
205 {
206 return v.y();
207 }
208
209 [[nodiscard]] constexpr value_type top() const noexcept
210 {
211 return v.w();
212 }
213
214 [[nodiscard]] constexpr value_type left() const noexcept
215 {
216 return v.x();
217 }
218
219 [[nodiscard]] constexpr value_type right() const noexcept
220 {
221 return v.z();
222 }
223
226 [[nodiscard]] constexpr value_type middle() const noexcept
227 {
228 return (bottom() + top()) / value_type{2};
229 }
230
233 [[nodiscard]] constexpr value_type center() const noexcept
234 {
235 return (left() + right()) / value_type{2};
236 }
237
240 [[nodiscard]] constexpr friend point2 midpoint(aarectangle const& rhs) noexcept
241 {
242 return midpoint(get<0>(rhs), get<3>(rhs));
243 }
244
245 constexpr aarectangle& set_width(value_type newWidth) noexcept
246 {
247 v = v.xyxw() + array_type{value_type{0}, value_type{0}, newWidth, value_type{0}};
248 return *this;
249 }
250
251 constexpr aarectangle& set_height(value_type newHeight) noexcept
252 {
253 v = v.xyzy() + array_type{value_type{0}, value_type{0}, value_type{0}, newHeight};
254 return *this;
255 }
256
261 [[nodiscard]] constexpr bool contains(point2 const& rhs) const noexcept
262 {
263 // No need to check with empty due to half open range check.
264 return (static_cast<array_type>(rhs).xyxy() >= v).mask() == 0b0011;
265 }
266
272 [[nodiscard]] constexpr bool contains(point3 const& rhs) const noexcept
273 {
274 return contains(point2{rhs});
275 }
276
283 [[nodiscard]] friend constexpr aarectangle
284 align(aarectangle haystack, extent2 needle, alignment alignment) noexcept
285 {
286 auto x = value_type{0};
288 x = haystack.left();
289
291 x = haystack.right() - needle.width();
292
294 x = haystack.center() - needle.width() / value_type{2};
295
296 } else {
298 }
299
300 auto y = value_type{0};
302 y = haystack.bottom();
303
304 } else if (alignment == vertical_alignment::top) {
305 y = haystack.top() - needle.height();
306
308 y = haystack.middle() - needle.height() / value_type{2};
309
310 } else {
312 }
313
314 return {point2{x, y}, needle};
315 }
316
323 [[nodiscard]] friend constexpr aarectangle align(aarectangle haystack, aarectangle needle, alignment alignment) noexcept
324 {
325 return align(haystack, needle.size(), alignment);
326 }
327
330 [[nodiscard]] static constexpr aarectangle _align(aarectangle outside, aarectangle inside, alignment alignment) noexcept
331 {
332 return align(outside, inside, alignment);
333 }
334
335 [[nodiscard]] friend constexpr bool operator==(aarectangle const& lhs, aarectangle const& rhs) noexcept
336 {
337 return equal(lhs.v, rhs.v);
338 }
339
340 [[nodiscard]] friend constexpr bool overlaps(aarectangle const& lhs, aarectangle const& rhs) noexcept
341 {
342 if (lhs.empty() or rhs.empty()) {
343 return false;
344 }
345
346 hilet rhs_swap = rhs.v.zwxy();
347
348 // lhs.p0.x > rhs.p3.x | lhs.p0.y > rhs.p3.y
349 if (((lhs.v > rhs_swap).mask() & 0b0011) != 0) {
350 return false;
351 }
352
353 // lhs.p3.x < rhs.p0.x | lhs.p3.y < rhs.p0.y
354 if (((lhs.v < rhs_swap).mask() & 0b1100) != 0) {
355 return false;
356 }
357
358 return true;
359 }
360
361 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, aarectangle const& rhs) noexcept
362 {
363 if (!lhs) {
364 return rhs;
365 } else if (!rhs) {
366 return lhs;
367 } else {
368 return aarectangle{min(get<0>(lhs), get<0>(rhs)), max(get<3>(lhs), get<3>(rhs))};
369 }
370 }
371
372 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, point2 const& rhs) noexcept
373 {
374 if (!lhs) {
375 return aarectangle{rhs, rhs};
376 } else {
377 return aarectangle{min(get<0>(lhs), rhs), max(get<3>(lhs), rhs)};
378 }
379 }
380
386 [[nodiscard]] friend constexpr aarectangle operator*(aarectangle const& lhs, value_type rhs) noexcept
387 {
388 hilet new_extent = lhs.size() * rhs;
389 hilet diff = vector2{new_extent} - vector2{lhs.size()};
390 hilet offset = diff * 0.5f;
391
392 hilet p0 = get<0>(lhs) - offset;
393 hilet p3 = max(get<3>(lhs) + offset, p0);
394 return aarectangle{p0, p3};
395 }
396
403 [[nodiscard]] friend constexpr aarectangle operator+(aarectangle const& lhs, value_type rhs) noexcept
404 {
405 return aarectangle{lhs.v + neg<0b0011>(array_type::broadcast(rhs))};
406 }
407
414 [[nodiscard]] friend constexpr aarectangle operator-(aarectangle const& lhs, value_type rhs) noexcept
415 {
416 return lhs + -rhs;
417 }
418
419 [[nodiscard]] friend constexpr aarectangle round(aarectangle const& rhs) noexcept
420 {
421 hilet p0 = round(get<0>(rhs));
422 hilet size = round(rhs.size());
423 return aarectangle{p0, size};
424 }
425
428 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& rhs) noexcept
429 {
430 hilet p0 = floor(get<0>(rhs));
431 hilet p3 = ceil(get<3>(rhs));
432 return aarectangle{p0, p3};
433 }
434
437 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& lhs, extent2 const& rhs) noexcept
438 {
439 hilet p0 = floor(get<0>(lhs), rhs);
440 hilet p3 = ceil(get<3>(lhs), rhs);
441 return aarectangle{p0, p3};
442 }
443
446 [[nodiscard]] friend constexpr aarectangle floor(aarectangle const& rhs) noexcept
447 {
448 hilet p0 = ceil(get<0>(rhs));
449 hilet p3 = floor(get<3>(rhs));
450 return aarectangle{p0, p3};
451 }
452
453 [[nodiscard]] friend constexpr aarectangle bounding_rectangle(aarectangle const& rhs) noexcept
454 {
455 return rhs;
456 }
457
461 [[nodiscard]] friend constexpr aarectangle intersect(aarectangle const& lhs, aarectangle const& rhs) noexcept
462 {
463 hilet p0 = max(get<0>(lhs), get<0>(rhs));
464 hilet p3 = min(get<3>(lhs), get<3>(rhs));
465 if (p0.x() < p3.x() && p0.y() < p3.y()) {
466 return {p0, p3};
467 } else {
468 return {};
469 }
470 }
471
472 [[nodiscard]] friend value_type distance(aarectangle const& lhs, point2 const& rhs) noexcept
473 {
474 hilet lhs_ = static_cast<array_type>(lhs);
475 hilet rhs_ = static_cast<array_type>(rhs);
476 // Only (x,y) of subsequent calculations are valid, (z,w) have garbage values.
477 hilet closest_point = max(min(rhs_, lhs_.zwzw()), lhs_);
478 hilet v_closest_point = closest_point - rhs_;
479 return hypot<0b0011>(v_closest_point);
480 }
481
482private:
488 array_type v;
489};
490
491}} // namespace hi::v1
492
493template<>
494class std::atomic<hi::aarectangle> {
495public:
497 static constexpr bool is_always_lock_free = false;
498
499 constexpr atomic() noexcept = default;
500 atomic(atomic const&) = delete;
501 atomic(atomic&&) = delete;
502 atomic& operator=(atomic const&) = delete;
503 atomic& operator=(atomic&&) = delete;
504
505 constexpr atomic(value_type const& rhs) noexcept : _value(rhs) {}
506 atomic& operator=(value_type const& rhs) noexcept
507 {
508 store(rhs);
509 return *this;
510 }
511
512 operator value_type() const noexcept
513 {
514 return load();
515 }
516
517 [[nodiscard]] bool is_lock_free() const noexcept
518 {
519 return is_always_lock_free;
520 }
521
522 void store(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
523 {
524 hilet lock = std::scoped_lock(_mutex);
525 _value = desired;
526 }
527
528 value_type load(std::memory_order = std::memory_order_seq_cst) const noexcept
529 {
530 hilet lock = std::scoped_lock(_mutex);
531 return _value;
532 }
533
534 value_type exchange(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
535 {
536 hilet lock = std::scoped_lock(_mutex);
537 return std::exchange(_value, desired);
538 }
539
540 bool compare_exchange_weak(value_type& expected, value_type desired, std::memory_order, std::memory_order) noexcept
541 {
542 hilet lock = std::scoped_lock(_mutex);
543 if (_value == expected) {
544 _value = desired;
545 return true;
546 } else {
547 expected = _value;
548 return false;
549 }
550 }
551
553 value_type& expected,
554 value_type desired,
555 std::memory_order success,
556 std::memory_order failure) noexcept
557 {
558 return compare_exchange_weak(expected, desired, success, failure);
559 }
560
561 bool
562 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept
563 {
564 return compare_exchange_weak(expected, desired, order, order);
565 }
566
568 value_type& expected,
569 value_type desired,
570 std::memory_order order = std::memory_order_seq_cst) noexcept
571 {
572 return compare_exchange_strong(expected, desired, order, order);
573 }
574
575 value_type fetch_or(value_type arg, std::memory_order = std::memory_order_seq_cst) noexcept
576 {
577 hilet lock = std::scoped_lock(_mutex);
578 auto tmp = _value;
579 _value = tmp | arg;
580 return tmp;
581 }
582
583 value_type operator|=(value_type arg) noexcept
584 {
585 hilet lock = std::scoped_lock(_mutex);
586 return _value |= arg;
587 }
588
589private:
590 value_type _value;
591 mutable hi::unfair_mutex _mutex;
592};
593
594template<typename CharT>
595struct std::formatter<hi::aarectangle, CharT> {
596 auto parse(auto& pc)
597 {
598 return pc.end();
599 }
600
601 auto format(hi::aarectangle const& t, auto& fc)
602 {
603 return std::vformat_to(fc.out(), "{}:{}", std::make_format_args(get<0>(t), t.size()));
604 }
605};
606
types and utilities for alignment.
Defined the geo::extent, extent2 and extent3 types.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ middle
Align to the vertical-middle.
@ bottom
Align to the bottom.
@ top
Align to the top.
@ right
Align the text to the right side.
@ left
Align the text to the left side.
@ center
Align the text in the center.
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
@ inside
The border is drawn inside the edge of a quad.
@ outside
The border is drawn outside the edge of a quad.
An unfair mutex This is a fast implementation of a mutex which does not fairly arbitrate between mult...
Definition unfair_mutex.hpp:36
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:26
friend constexpr aarectangle ceil(aarectangle const &lhs, extent2 const &rhs) noexcept
Round rectangle by expanding to a certain granularity.
Definition aarectangle.hpp:437
constexpr extent2 size() const noexcept
Get size of the rectangle.
Definition aarectangle.hpp:179
friend constexpr aarectangle intersect(aarectangle const &lhs, aarectangle const &rhs) noexcept
Return the overlapping part of two rectangles.
Definition aarectangle.hpp:461
static constexpr aarectangle large() noexcept
Create a large axis aligned rectangle.
Definition aarectangle.hpp:39
friend constexpr aarectangle operator*(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:386
constexpr friend point2 midpoint(aarectangle const &rhs) noexcept
Get the center of the rectangle.
Definition aarectangle.hpp:240
constexpr aarectangle(extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:66
friend constexpr aarectangle operator-(aarectangle const &lhs, value_type rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition aarectangle.hpp:414
constexpr bool empty() const noexcept
Check if the rectangle has no area.
Definition aarectangle.hpp:111
constexpr bool contains(point3 const &rhs) const noexcept
Check if a 3D coordinate is inside the rectangle.
Definition aarectangle.hpp:272
constexpr bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition aarectangle.hpp:261
static constexpr aarectangle _align(aarectangle outside, aarectangle inside, alignment alignment) noexcept
Need to call the hidden friend function from within another class.
Definition aarectangle.hpp:330
friend constexpr aarectangle floor(aarectangle const &rhs) noexcept
Round rectangle by shrinking to pixel edge.
Definition aarectangle.hpp:446
constexpr bool holds_invariant() const noexcept
Make sure p0 is left/bottom from p3.
Definition aarectangle.hpp:104
friend constexpr aarectangle align(aarectangle haystack, extent2 needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:284
friend constexpr aarectangle align(aarectangle haystack, aarectangle needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:323
friend constexpr aarectangle operator+(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:403
constexpr value_type center() const noexcept
The center on the x-axis between left and right.
Definition aarectangle.hpp:233
constexpr aarectangle & operator|=(point2 const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:138
constexpr aarectangle(float x, float y, float width, float height) noexcept
Create a box from the position and size.
Definition aarectangle.hpp:56
friend constexpr aarectangle ceil(aarectangle const &rhs) noexcept
Round rectangle by expanding to pixel edge.
Definition aarectangle.hpp:428
constexpr aarectangle(point2 const &p0, point2 const &p3) noexcept
Create a rectangle from the left-bottom and right-top points.
Definition aarectangle.hpp:75
constexpr aarectangle & operator|=(aarectangle const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:128
constexpr value_type middle() const noexcept
The middle on the y-axis between bottom and top.
Definition aarectangle.hpp:226
constexpr aarectangle(point2 const &p0, extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:90
Horizontal/Vertical alignment combination.
Definition alignment.hpp:239
A high-level geometric extent.
Definition extent2.hpp:26
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:18
T compare_exchange_weak(T... args)
T exchange(T... args)
T fetch_or(T... args)
T is_lock_free(T... args)
T load(T... args)
T lock(T... args)
T max(T... args)
T min(T... args)
T operator=(T... args)
T operator|=(T... args)
T store(T... args)