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/utility.hpp"
17#include "../concurrency/concurrency.hpp"
18#include "../macros.hpp"
19#include <concepts>
20#include <mutex>
21
22
23
24namespace hi { inline namespace v1 {
25
30public:
31 using array_type = simd<float, 4>;
32 using value_type = array_type::value_type;
33
34 constexpr aarectangle() noexcept : v() {}
35 constexpr aarectangle(aarectangle const& rhs) noexcept = default;
36 constexpr aarectangle& operator=(aarectangle const& rhs) noexcept = default;
37 constexpr aarectangle(aarectangle&& rhs) noexcept = default;
38 constexpr aarectangle& operator=(aarectangle&& rhs) noexcept = default;
39
46
47 constexpr explicit aarectangle(array_type const& other) noexcept : v(other)
48 {
49 hi_axiom(holds_invariant());
50 }
51
59 constexpr aarectangle(float x, float y, float width, float height) noexcept :
60 v{x, y, x + width, y + height}
61 {
62 hi_axiom(holds_invariant());
63 }
64
69 constexpr explicit aarectangle(extent2 const& extent) noexcept : v(static_cast<array_type>(extent)._00xy())
70 {
71 hi_axiom(holds_invariant());
72 }
73
78 constexpr aarectangle(point2 const& p0, point2 const& p3) noexcept :
79 v(static_cast<array_type>(p0).xy00() + static_cast<array_type>(p3)._00xy())
80 {
81 hi_axiom(p0.holds_invariant());
82 hi_axiom(p3.holds_invariant());
83 hi_axiom(holds_invariant());
84 }
85
93 constexpr aarectangle(point2 const& p0, extent2 const& extent) noexcept :
94 v(static_cast<array_type>(p0).xyxy() + static_cast<array_type>(extent)._00xy())
95 {
96 hi_axiom(holds_invariant());
97 }
98
99 constexpr explicit operator array_type() const noexcept
100 {
101 return v;
102 }
103
108 {
109 return (v <= v.zwzw()).mask() == 0b1111;
110 }
111
114 [[nodiscard]] constexpr bool empty() const noexcept
115 {
116 return (v == v.zwxy()).mask() == 0b1111;
117 }
118
121 [[nodiscard]] constexpr explicit operator bool() const noexcept
122 {
123 return not empty();
124 }
125
131 constexpr aarectangle& operator|=(aarectangle const& rhs) noexcept
132 {
133 return *this = *this | rhs;
134 }
135
141 constexpr aarectangle& operator|=(point2 const& rhs) noexcept
142 {
143 return *this = *this | rhs;
144 }
145
146 [[nodiscard]] constexpr point2 operator[](std::size_t i) const noexcept
147 {
148 switch (i) {
149 case 0:
150 return point2{v.xy01()};
151 case 1:
152 return point2{v.zy01()};
153 case 2:
154 return point2{v.xw01()};
155 case 3:
156 return point2{v.zw01()};
157 default:
158 hi_no_default();
159 }
160 }
161
162 template<int I>
163 [[nodiscard]] constexpr friend point2 get(aarectangle const &rhs) noexcept
164 {
165 if constexpr (I == 0) {
166 return point2{rhs.v.xy01()};
167 } else if constexpr (I == 1) {
168 return point2{rhs.v.zy01()};
169 } else if constexpr (I == 2) {
170 return point2{rhs.v.xw01()};
171 } else if constexpr (I == 3) {
172 return point2{rhs.v.zw01()};
173 } else {
174 hi_static_no_default();
175 }
176 }
177
183 {
184 return extent2{v.zwzw() - v};
185 }
186
187 [[nodiscard]] constexpr value_type x() const noexcept
188 {
189 return v.x();
190 }
191
192 [[nodiscard]] constexpr value_type y() const noexcept
193 {
194 return v.y();
195 }
196
197 [[nodiscard]] constexpr value_type width() const noexcept
198 {
199 return (v.zwzw() - v).x();
200 }
201
202 [[nodiscard]] constexpr value_type height() const noexcept
203 {
204 return (v.zwzw() - v).y();
205 }
206
207 [[nodiscard]] constexpr value_type bottom() const noexcept
208 {
209 return v.y();
210 }
211
212 [[nodiscard]] constexpr value_type top() const noexcept
213 {
214 return v.w();
215 }
216
217 [[nodiscard]] constexpr value_type left() const noexcept
218 {
219 return v.x();
220 }
221
222 [[nodiscard]] constexpr value_type right() const noexcept
223 {
224 return v.z();
225 }
226
229 [[nodiscard]] constexpr value_type middle() const noexcept
230 {
231 return (bottom() + top()) / value_type{2};
232 }
233
236 [[nodiscard]] constexpr value_type center() const noexcept
237 {
238 return (left() + right()) / value_type{2};
239 }
240
243 [[nodiscard]] constexpr friend point2 midpoint(aarectangle const& rhs) noexcept
244 {
245 return midpoint(get<0>(rhs), get<3>(rhs));
246 }
247
248 constexpr aarectangle& set_width(value_type newWidth) noexcept
249 {
250 v = v.xyxw() + array_type{value_type{0}, value_type{0}, newWidth, value_type{0}};
251 return *this;
252 }
253
254 constexpr aarectangle& set_height(value_type newHeight) noexcept
255 {
256 v = v.xyzy() + array_type{value_type{0}, value_type{0}, value_type{0}, newHeight};
257 return *this;
258 }
259
264 [[nodiscard]] constexpr bool contains(point2 const& rhs) const noexcept
265 {
266 // No need to check with empty due to half open range check.
267 return (static_cast<array_type>(rhs).xyxy() >= v).mask() == 0b0011;
268 }
269
275 [[nodiscard]] constexpr bool contains(point3 const& rhs) const noexcept
276 {
277 return contains(point2{rhs});
278 }
279
286 [[nodiscard]] friend constexpr aarectangle
288 {
289 auto x = value_type{0};
291 x = haystack.left();
292
294 x = haystack.right() - needle.width();
295
297 x = haystack.center() - needle.width() / value_type{2};
298
299 } else {
300 hi_no_default();
301 }
302
303 auto y = value_type{0};
305 y = haystack.bottom();
306
307 } else if (alignment == vertical_alignment::top) {
308 y = haystack.top() - needle.height();
309
311 y = haystack.middle() - needle.height() / value_type{2};
312
313 } else {
314 hi_no_default();
315 }
316
317 return {point2{x, y}, needle};
318 }
319
327 {
328 return align(haystack, needle.size(), alignment);
329 }
330
334 {
335 return align(outside, inside, alignment);
336 }
337
338 [[nodiscard]] friend constexpr bool operator==(aarectangle const& lhs, aarectangle const& rhs) noexcept
339 {
340 return equal(lhs.v, rhs.v);
341 }
342
343 [[nodiscard]] friend constexpr bool overlaps(aarectangle const& lhs, aarectangle const& rhs) noexcept
344 {
345 if (lhs.empty() or rhs.empty()) {
346 return false;
347 }
348
349 hilet rhs_swap = rhs.v.zwxy();
350
351 // lhs.p0.x > rhs.p3.x | lhs.p0.y > rhs.p3.y
352 if (((lhs.v > rhs_swap).mask() & 0b0011) != 0) {
353 return false;
354 }
355
356 // lhs.p3.x < rhs.p0.x | lhs.p3.y < rhs.p0.y
357 if (((lhs.v < rhs_swap).mask() & 0b1100) != 0) {
358 return false;
359 }
360
361 return true;
362 }
363
364 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, aarectangle const& rhs) noexcept
365 {
366 if (!lhs) {
367 return rhs;
368 } else if (!rhs) {
369 return lhs;
370 } else {
371 return aarectangle{min(get<0>(lhs), get<0>(rhs)), max(get<3>(lhs), get<3>(rhs))};
372 }
373 }
374
375 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, point2 const& rhs) noexcept
376 {
377 if (!lhs) {
378 return aarectangle{rhs, rhs};
379 } else {
380 return aarectangle{min(get<0>(lhs), rhs), max(get<3>(lhs), rhs)};
381 }
382 }
383
389 [[nodiscard]] friend constexpr aarectangle operator*(aarectangle const& lhs, value_type rhs) noexcept
390 {
391 hilet new_extent = lhs.size() * rhs;
392 hilet diff = vector2{new_extent} - vector2{lhs.size()};
393 hilet offset = diff * 0.5f;
394
395 hilet p0 = get<0>(lhs) - offset;
396 hilet p3 = max(get<3>(lhs) + offset, p0);
397 return aarectangle{p0, p3};
398 }
399
406 [[nodiscard]] friend constexpr aarectangle operator+(aarectangle const& lhs, value_type rhs) noexcept
407 {
408 return aarectangle{lhs.v + neg<0b0011>(array_type::broadcast(rhs))};
409 }
410
417 [[nodiscard]] friend constexpr aarectangle operator-(aarectangle const& lhs, value_type rhs) noexcept
418 {
419 return lhs + -rhs;
420 }
421
422 [[nodiscard]] friend constexpr aarectangle round(aarectangle const& rhs) noexcept
423 {
424 hilet p0 = round(get<0>(rhs));
425 hilet size = round(rhs.size());
426 return aarectangle{p0, size};
427 }
428
431 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& rhs) noexcept
432 {
433 hilet p0 = floor(get<0>(rhs));
434 hilet p3 = ceil(get<3>(rhs));
435 return aarectangle{p0, p3};
436 }
437
440 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& lhs, extent2 const& rhs) noexcept
441 {
442 hilet p0 = floor(get<0>(lhs), rhs);
443 hilet p3 = ceil(get<3>(lhs), rhs);
444 return aarectangle{p0, p3};
445 }
446
449 [[nodiscard]] friend constexpr aarectangle floor(aarectangle const& rhs) noexcept
450 {
451 hilet p0 = ceil(get<0>(rhs));
452 hilet p3 = floor(get<3>(rhs));
453 return aarectangle{p0, p3};
454 }
455
456 [[nodiscard]] friend constexpr aarectangle bounding_rectangle(aarectangle const& rhs) noexcept
457 {
458 return rhs;
459 }
460
464 [[nodiscard]] friend constexpr aarectangle intersect(aarectangle const& lhs, aarectangle const& rhs) noexcept
465 {
466 hilet p0 = max(get<0>(lhs), get<0>(rhs));
467 hilet p3 = min(get<3>(lhs), get<3>(rhs));
468 if (p0.x() < p3.x() && p0.y() < p3.y()) {
469 return {p0, p3};
470 } else {
471 return {};
472 }
473 }
474
475 [[nodiscard]] friend value_type distance(aarectangle const& lhs, point2 const& rhs) noexcept
476 {
477 hilet lhs_ = static_cast<array_type>(lhs);
478 hilet rhs_ = static_cast<array_type>(rhs);
479 // Only (x,y) of subsequent calculations are valid, (z,w) have garbage values.
480 hilet closest_point = max(min(rhs_, lhs_.zwzw()), lhs_);
483 }
484
485private:
491 array_type v;
492};
493
494}} // namespace hi::v1
495
496template<>
497class std::atomic<hi::aarectangle> {
498public:
500 constexpr static bool is_always_lock_free = false;
501
502 constexpr atomic() noexcept = default;
503 atomic(atomic const&) = delete;
504 atomic(atomic&&) = delete;
505 atomic& operator=(atomic const&) = delete;
506 atomic& operator=(atomic&&) = delete;
507
508 constexpr atomic(value_type const& rhs) noexcept : _value(rhs) {}
509 atomic& operator=(value_type const& rhs) noexcept
510 {
511 store(rhs);
512 return *this;
513 }
514
515 operator value_type() const noexcept
516 {
517 return load();
518 }
519
520 [[nodiscard]] bool is_lock_free() const noexcept
521 {
522 return is_always_lock_free;
523 }
524
525 void store(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
526 {
527 hilet lock = std::scoped_lock(_mutex);
528 _value = desired;
529 }
530
531 value_type load(std::memory_order = std::memory_order_seq_cst) const noexcept
532 {
533 hilet lock = std::scoped_lock(_mutex);
534 return _value;
535 }
536
537 value_type exchange(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
538 {
539 hilet lock = std::scoped_lock(_mutex);
540 return std::exchange(_value, desired);
541 }
542
543 bool compare_exchange_weak(value_type& expected, value_type desired, std::memory_order, std::memory_order) noexcept
544 {
545 hilet lock = std::scoped_lock(_mutex);
546 if (_value == expected) {
547 _value = desired;
548 return true;
549 } else {
550 expected = _value;
551 return false;
552 }
553 }
554
556 value_type& expected,
557 value_type desired,
558 std::memory_order success,
559 std::memory_order failure) noexcept
560 {
561 return compare_exchange_weak(expected, desired, success, failure);
562 }
563
564 bool
565 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept
566 {
567 return compare_exchange_weak(expected, desired, order, order);
568 }
569
571 value_type& expected,
572 value_type desired,
573 std::memory_order order = std::memory_order_seq_cst) noexcept
574 {
575 return compare_exchange_strong(expected, desired, order, order);
576 }
577
578 value_type fetch_or(value_type arg, std::memory_order = std::memory_order_seq_cst) noexcept
579 {
580 hilet lock = std::scoped_lock(_mutex);
581 auto tmp = _value;
582 _value = tmp | arg;
583 return tmp;
584 }
585
586 value_type operator|=(value_type arg) noexcept
587 {
588 hilet lock = std::scoped_lock(_mutex);
589 return _value |= arg;
590 }
591
592private:
593 value_type _value;
594 mutable hi::unfair_mutex _mutex;
595};
596
597template<typename CharT>
598struct std::formatter<hi::aarectangle, CharT> {
599 auto parse(auto& pc)
600 {
601 return pc.end();
602 }
603
604 auto format(hi::aarectangle const& t, auto& fc) const
605 {
606 return std::vformat_to(fc.out(), "{}:{}", std::make_format_args(get<0>(t), t.size()));
607 }
608};
609
types and utilities for alignment.
Defined the geo::extent, extent2 and extent3 types.
@ 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:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
@ inside
The border is drawn inside the edge of a quad.
@ outside
The border is drawn outside the edge of a quad.
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
friend constexpr aarectangle ceil(aarectangle const &lhs, extent2 const &rhs) noexcept
Round rectangle by expanding to a certain granularity.
Definition aarectangle.hpp:440
constexpr extent2 size() const noexcept
Get size of the rectangle.
Definition aarectangle.hpp:182
friend constexpr aarectangle intersect(aarectangle const &lhs, aarectangle const &rhs) noexcept
Return the overlapping part of two rectangles.
Definition aarectangle.hpp:464
static constexpr aarectangle large() noexcept
Create a large axis aligned rectangle.
Definition aarectangle.hpp:42
friend constexpr aarectangle operator*(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:389
constexpr friend point2 midpoint(aarectangle const &rhs) noexcept
Get the center of the rectangle.
Definition aarectangle.hpp:243
constexpr aarectangle(extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:69
friend constexpr aarectangle operator-(aarectangle const &lhs, value_type rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition aarectangle.hpp:417
constexpr bool empty() const noexcept
Check if the rectangle has no area.
Definition aarectangle.hpp:114
constexpr bool contains(point3 const &rhs) const noexcept
Check if a 3D coordinate is inside the rectangle.
Definition aarectangle.hpp:275
constexpr bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition aarectangle.hpp:264
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:333
friend constexpr aarectangle floor(aarectangle const &rhs) noexcept
Round rectangle by shrinking to pixel edge.
Definition aarectangle.hpp:449
constexpr bool holds_invariant() const noexcept
Make sure p0 is left/bottom from p3.
Definition aarectangle.hpp:107
friend constexpr aarectangle align(aarectangle haystack, extent2 needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:287
friend constexpr aarectangle align(aarectangle haystack, aarectangle needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:326
friend constexpr aarectangle operator+(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:406
constexpr value_type center() const noexcept
The center on the x-axis between left and right.
Definition aarectangle.hpp:236
constexpr aarectangle & operator|=(point2 const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:141
constexpr aarectangle(float x, float y, float width, float height) noexcept
Create a box from the position and size.
Definition aarectangle.hpp:59
friend constexpr aarectangle ceil(aarectangle const &rhs) noexcept
Round rectangle by expanding to pixel edge.
Definition aarectangle.hpp:431
constexpr aarectangle(point2 const &p0, point2 const &p3) noexcept
Create a rectangle from the left-bottom and right-top points.
Definition aarectangle.hpp:78
constexpr aarectangle & operator|=(aarectangle const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:131
constexpr value_type middle() const noexcept
The middle on the y-axis between bottom and top.
Definition aarectangle.hpp:229
constexpr aarectangle(point2 const &p0, extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:93
Horizontal/Vertical alignment combination.
Definition alignment.hpp:242
A high-level geometric extent.
Definition extent2.hpp:29
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:19
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)