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 "../utility/utility.hpp"
16#include "../concurrency/concurrency.hpp"
17#include "../concurrency/unfair_mutex.hpp" // XXX #616
18#include "../concurrency/thread.hpp" // XXX #616
19#include "../macros.hpp"
20#include <hikocpu/hikocpu.hpp>
21#include <concepts>
22#include <mutex>
23#include <exception>
24#include <compare>
25
26hi_export_module(hikogui.geometry : aarectangle);
27
28hi_export namespace hi { inline namespace v1 {
29
34public:
35 using array_type = simd<float, 4>;
36 using value_type = array_type::value_type;
37
38 constexpr aarectangle() noexcept : v() {}
39 constexpr aarectangle(aarectangle const& rhs) noexcept = default;
40 constexpr aarectangle& operator=(aarectangle const& rhs) noexcept = default;
41 constexpr aarectangle(aarectangle&& rhs) noexcept = default;
42 constexpr aarectangle& operator=(aarectangle&& rhs) noexcept = default;
43
46 [[nodiscard]] constexpr static aarectangle large() noexcept
47 {
48 return {point2{-large_number_v<float>, -large_number_v<float>}, point2{large_number_v<float>, large_number_v<float>}};
49 }
50
51 constexpr explicit aarectangle(array_type const& other) noexcept : v(other)
52 {
53 hi_axiom(holds_invariant());
54 }
55
63 constexpr aarectangle(float x, float y, float width, float height) noexcept :
64 v{x, y, x + width, y + height}
65 {
66 hi_axiom(holds_invariant());
67 }
68
73 constexpr explicit aarectangle(extent2 const& extent) noexcept : v(static_cast<array_type>(extent)._00xy())
74 {
75 hi_axiom(holds_invariant());
76 }
77
82 constexpr aarectangle(point2 const& p0, point2 const& p3) noexcept :
83 v(static_cast<array_type>(p0).xy00() + static_cast<array_type>(p3)._00xy())
84 {
85 hi_axiom(p0.holds_invariant());
86 hi_axiom(p3.holds_invariant());
87 hi_axiom(holds_invariant());
88 }
89
97 constexpr aarectangle(point2 const& p0, extent2 const& extent) noexcept :
98 v(static_cast<array_type>(p0).xyxy() + static_cast<array_type>(extent)._00xy())
99 {
100 hi_axiom(holds_invariant());
101 }
102
103 constexpr explicit operator array_type() const noexcept
104 {
105 return v;
106 }
107
111 [[nodiscard]] constexpr bool holds_invariant() const noexcept
112 {
113 return (v <= v.zwzw()).mask() == 0b1111;
114 }
115
118 [[nodiscard]] constexpr bool empty() const noexcept
119 {
120 return (v == v.zwxy()).mask() == 0b1111;
121 }
122
125 [[nodiscard]] constexpr explicit operator bool() const noexcept
126 {
127 return not empty();
128 }
129
135 constexpr aarectangle& operator|=(aarectangle const& rhs) noexcept
136 {
137 return *this = *this | rhs;
138 }
139
145 constexpr aarectangle& operator|=(point2 const& rhs) noexcept
146 {
147 return *this = *this | rhs;
148 }
149
150 [[nodiscard]] constexpr point2 operator[](std::size_t i) const noexcept
151 {
152 switch (i) {
153 case 0:
154 return point2{v.xy01()};
155 case 1:
156 return point2{v.zy01()};
157 case 2:
158 return point2{v.xw01()};
159 case 3:
160 return point2{v.zw01()};
161 default:
162 hi_no_default();
163 }
164 }
165
166 template<int I>
167 [[nodiscard]] constexpr friend point2 get(aarectangle const &rhs) noexcept
168 {
169 if constexpr (I == 0) {
170 return point2{rhs.v.xy01()};
171 } else if constexpr (I == 1) {
172 return point2{rhs.v.zy01()};
173 } else if constexpr (I == 2) {
174 return point2{rhs.v.xw01()};
175 } else if constexpr (I == 3) {
176 return point2{rhs.v.zw01()};
177 } else {
178 hi_static_no_default();
179 }
180 }
181
186 [[nodiscard]] constexpr extent2 size() const noexcept
187 {
188 return extent2{v.zwzw() - v};
189 }
190
191 [[nodiscard]] constexpr value_type x() const noexcept
192 {
193 return v.x();
194 }
195
196 [[nodiscard]] constexpr value_type y() const noexcept
197 {
198 return v.y();
199 }
200
201 [[nodiscard]] constexpr value_type width() const noexcept
202 {
203 return (v.zwzw() - v).x();
204 }
205
206 [[nodiscard]] constexpr value_type height() const noexcept
207 {
208 return (v.zwzw() - v).y();
209 }
210
211 [[nodiscard]] constexpr value_type bottom() const noexcept
212 {
213 return v.y();
214 }
215
216 [[nodiscard]] constexpr value_type top() const noexcept
217 {
218 return v.w();
219 }
220
221 [[nodiscard]] constexpr value_type left() const noexcept
222 {
223 return v.x();
224 }
225
226 [[nodiscard]] constexpr value_type right() const noexcept
227 {
228 return v.z();
229 }
230
233 [[nodiscard]] constexpr value_type middle() const noexcept
234 {
235 return (bottom() + top()) / value_type{2};
236 }
237
240 [[nodiscard]] constexpr value_type center() const noexcept
241 {
242 return (left() + right()) / value_type{2};
243 }
244
247 [[nodiscard]] constexpr friend point2 midpoint(aarectangle const& rhs) noexcept
248 {
249 return midpoint(get<0>(rhs), get<3>(rhs));
250 }
251
252 constexpr aarectangle& set_width(value_type newWidth) noexcept
253 {
254 v = v.xyxw() + array_type{value_type{0}, value_type{0}, newWidth, value_type{0}};
255 return *this;
256 }
257
258 constexpr aarectangle& set_height(value_type newHeight) noexcept
259 {
260 v = v.xyzy() + array_type{value_type{0}, value_type{0}, value_type{0}, newHeight};
261 return *this;
262 }
263
268 [[nodiscard]] constexpr bool contains(point2 const& rhs) const noexcept
269 {
270 // No need to check with empty due to half open range check.
271 return (static_cast<array_type>(rhs).xyxy() >= v).mask() == 0b0011;
272 }
273
279 [[nodiscard]] constexpr bool contains(point3 const& rhs) const noexcept
280 {
281 return contains(point2{rhs});
282 }
283
290 [[nodiscard]] friend constexpr aarectangle
291 align(aarectangle haystack, extent2 needle, alignment alignment) noexcept
292 {
293 auto x = value_type{0};
295 x = haystack.left();
296
298 x = haystack.right() - needle.width();
299
301 x = haystack.center() - needle.width() / value_type{2};
302
303 } else {
304 hi_no_default();
305 }
306
307 auto y = value_type{0};
309 y = haystack.bottom();
310
311 } else if (alignment == vertical_alignment::top) {
312 y = haystack.top() - needle.height();
313
315 y = haystack.middle() - needle.height() / value_type{2};
316
317 } else {
318 hi_no_default();
319 }
320
321 return {point2{x, y}, needle};
322 }
323
330 [[nodiscard]] friend constexpr aarectangle align(aarectangle haystack, aarectangle needle, alignment alignment) noexcept
331 {
332 return align(haystack, needle.size(), alignment);
333 }
334
337 [[nodiscard]] constexpr static aarectangle _align(aarectangle outside, aarectangle inside, alignment alignment) noexcept
338 {
339 return align(outside, inside, alignment);
340 }
341
342 [[nodiscard]] friend constexpr bool operator==(aarectangle const& lhs, aarectangle const& rhs) noexcept
343 {
344 return equal(lhs.v, rhs.v);
345 }
346
347 [[nodiscard]] friend constexpr bool overlaps(aarectangle const& lhs, aarectangle const& rhs) noexcept
348 {
349 if (lhs.empty() or rhs.empty()) {
350 return false;
351 }
352
353 auto const rhs_swap = rhs.v.zwxy();
354
355 // lhs.p0.x > rhs.p3.x | lhs.p0.y > rhs.p3.y
356 if (((lhs.v > rhs_swap).mask() & 0b0011) != 0) {
357 return false;
358 }
359
360 // lhs.p3.x < rhs.p0.x | lhs.p3.y < rhs.p0.y
361 if (((lhs.v < rhs_swap).mask() & 0b1100) != 0) {
362 return false;
363 }
364
365 return true;
366 }
367
368 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, aarectangle const& rhs) noexcept
369 {
370 if (!lhs) {
371 return rhs;
372 } else if (!rhs) {
373 return lhs;
374 } else {
375 return aarectangle{min(get<0>(lhs), get<0>(rhs)), max(get<3>(lhs), get<3>(rhs))};
376 }
377 }
378
379 [[nodiscard]] friend constexpr aarectangle operator|(aarectangle const& lhs, point2 const& rhs) noexcept
380 {
381 if (!lhs) {
382 return aarectangle{rhs, rhs};
383 } else {
384 return aarectangle{min(get<0>(lhs), rhs), max(get<3>(lhs), rhs)};
385 }
386 }
387
393 [[nodiscard]] friend constexpr aarectangle operator*(aarectangle const& lhs, value_type rhs) noexcept
394 {
395 auto const new_extent = lhs.size() * rhs;
396 auto const diff = vector2{new_extent} - vector2{lhs.size()};
397 auto const offset = diff * 0.5f;
398
399 auto const p0 = get<0>(lhs) - offset;
400 auto const p3 = max(get<3>(lhs) + offset, p0);
401 return aarectangle{p0, p3};
402 }
403
410 [[nodiscard]] friend constexpr aarectangle operator+(aarectangle const& lhs, value_type rhs) noexcept
411 {
412 return aarectangle{lhs.v + neg_mask<0b0011>(array_type::broadcast(rhs))};
413 }
414
415 friend constexpr aarectangle &operator+=(aarectangle &lhs, value_type rhs) noexcept
416 {
417 return lhs = lhs + rhs;
418 }
419
426 [[nodiscard]] friend constexpr aarectangle operator-(aarectangle const& lhs, value_type rhs) noexcept
427 {
428 return lhs + -rhs;
429 }
430
431 friend constexpr aarectangle &operator-=(aarectangle &lhs, value_type rhs) noexcept
432 {
433 return lhs = lhs - rhs;
434 }
435
436 [[nodiscard]] friend constexpr aarectangle round(aarectangle const& rhs) noexcept
437 {
438 auto const p0 = round(get<0>(rhs));
439 auto const size = round(rhs.size());
440 return aarectangle{p0, size};
441 }
442
445 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& rhs) noexcept
446 {
447 auto const p0 = floor(get<0>(rhs));
448 auto const p3 = ceil(get<3>(rhs));
449 return aarectangle{p0, p3};
450 }
451
454 [[nodiscard]] friend constexpr aarectangle ceil(aarectangle const& lhs, extent2 const& rhs) noexcept
455 {
456 auto const p0 = floor(get<0>(lhs), rhs);
457 auto const p3 = ceil(get<3>(lhs), rhs);
458 return aarectangle{p0, p3};
459 }
460
463 [[nodiscard]] friend constexpr aarectangle floor(aarectangle const& rhs) noexcept
464 {
465 auto const p0 = ceil(get<0>(rhs));
466 auto const p3 = floor(get<3>(rhs));
467 return aarectangle{p0, p3};
468 }
469
470 [[nodiscard]] friend constexpr aarectangle bounding_rectangle(aarectangle const& rhs) noexcept
471 {
472 return rhs;
473 }
474
478 [[nodiscard]] friend constexpr aarectangle intersect(aarectangle const& lhs, aarectangle const& rhs) noexcept
479 {
480 auto const p0 = max(get<0>(lhs), get<0>(rhs));
481 auto const p3 = min(get<3>(lhs), get<3>(rhs));
482 if (p0.x() < p3.x() && p0.y() < p3.y()) {
483 return {p0, p3};
484 } else {
485 return {};
486 }
487 }
488
489 [[nodiscard]] friend value_type distance(aarectangle const& lhs, point2 const& rhs) noexcept
490 {
491 auto const lhs_ = static_cast<array_type>(lhs);
492 auto const rhs_ = static_cast<array_type>(rhs);
493 // Only (x,y) of subsequent calculations are valid, (z,w) have garbage values.
494 auto const closest_point = max(min(rhs_, lhs_.zwzw()), lhs_);
495 auto const v_closest_point = closest_point - rhs_;
496 return hypot<0b0011>(v_closest_point).x();
497 }
498
499private:
505 array_type v;
506};
507
508}} // namespace hi::v1
509
510template<>
511class std::atomic<hi::aarectangle> {
512public:
514 constexpr static bool is_always_lock_free = false;
515
516 constexpr atomic() noexcept = default;
517 atomic(atomic const&) = delete;
518 atomic(atomic&&) = delete;
519 atomic& operator=(atomic const&) = delete;
520 atomic& operator=(atomic&&) = delete;
521
522 constexpr atomic(value_type const& rhs) noexcept : _value(rhs) {}
523 atomic& operator=(value_type const& rhs) noexcept
524 {
525 store(rhs);
526 return *this;
527 }
528
529 operator value_type() const noexcept
530 {
531 return load();
532 }
533
534 [[nodiscard]] bool is_lock_free() const noexcept
535 {
536 return is_always_lock_free;
537 }
538
539 void store(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
540 {
541 auto const lock = std::scoped_lock(_mutex);
542 _value = desired;
543 }
544
545 value_type load(std::memory_order = std::memory_order_seq_cst) const noexcept
546 {
547 auto const lock = std::scoped_lock(_mutex);
548 return _value;
549 }
550
551 value_type exchange(value_type desired, std::memory_order = std::memory_order_seq_cst) noexcept
552 {
553 auto const lock = std::scoped_lock(_mutex);
554 return std::exchange(_value, desired);
555 }
556
557 bool compare_exchange_weak(value_type& expected, value_type desired, std::memory_order, std::memory_order) noexcept
558 {
559 auto const lock = std::scoped_lock(_mutex);
560 if (_value == expected) {
561 _value = desired;
562 return true;
563 } else {
564 expected = _value;
565 return false;
566 }
567 }
568
570 value_type& expected,
571 value_type desired,
572 std::memory_order success,
573 std::memory_order failure) noexcept
574 {
575 return compare_exchange_weak(expected, desired, success, failure);
576 }
577
578 bool
579 compare_exchange_weak(value_type& expected, value_type desired, std::memory_order order = std::memory_order_seq_cst) noexcept
580 {
581 return compare_exchange_weak(expected, desired, order, order);
582 }
583
585 value_type& expected,
586 value_type desired,
587 std::memory_order order = std::memory_order_seq_cst) noexcept
588 {
589 return compare_exchange_strong(expected, desired, order, order);
590 }
591
592 value_type fetch_or(value_type arg, std::memory_order = std::memory_order_seq_cst) noexcept
593 {
594 auto const lock = std::scoped_lock(_mutex);
595 auto tmp = _value;
596 _value = tmp | arg;
597 return tmp;
598 }
599
600 value_type operator|=(value_type arg) noexcept
601 {
602 auto const lock = std::scoped_lock(_mutex);
603 return _value |= arg;
604 }
605
606private:
607 value_type _value;
608 mutable hi::unfair_mutex _mutex;
609};
610
611// XXX #617 MSVC bug does not handle partial specialization in modules.
612hi_export template<>
613struct std::formatter<hi::aarectangle, char> : std::formatter<std::string, char> {
614 auto format(hi::aarectangle const& t, auto& fc) const
615 {
616 return std::formatter<std::string, char>::format(std::format("{}:{}", get<0>(t), t.size()), fc);
617 }
618};
Functions and types for accessing operating system threads.
Definition of the unfair_mutex.
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.
The HikoGUI namespace.
Definition array_generic.hpp:20
@ inside
The border is drawn inside the edge of a quad.
@ outside
The border is drawn outside the edge of a quad.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Definition simd_intf.hpp:18
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
friend constexpr aarectangle ceil(aarectangle const &lhs, extent2 const &rhs) noexcept
Round rectangle by expanding to a certain granularity.
Definition aarectangle.hpp:454
constexpr extent2 size() const noexcept
Get size of the rectangle.
Definition aarectangle.hpp:186
friend constexpr aarectangle intersect(aarectangle const &lhs, aarectangle const &rhs) noexcept
Return the overlapping part of two rectangles.
Definition aarectangle.hpp:478
static constexpr aarectangle large() noexcept
Create a large axis aligned rectangle.
Definition aarectangle.hpp:46
friend constexpr aarectangle operator*(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:393
constexpr friend point2 midpoint(aarectangle const &rhs) noexcept
Get the center of the rectangle.
Definition aarectangle.hpp:247
constexpr aarectangle(extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:73
friend constexpr aarectangle operator-(aarectangle const &lhs, value_type rhs) noexcept
Shrink the rectangle for the same amount in all directions.
Definition aarectangle.hpp:426
constexpr bool empty() const noexcept
Check if the rectangle has no area.
Definition aarectangle.hpp:118
constexpr bool contains(point3 const &rhs) const noexcept
Check if a 3D coordinate is inside the rectangle.
Definition aarectangle.hpp:279
constexpr bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition aarectangle.hpp:268
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:337
friend constexpr aarectangle floor(aarectangle const &rhs) noexcept
Round rectangle by shrinking to pixel edge.
Definition aarectangle.hpp:463
constexpr bool holds_invariant() const noexcept
Make sure p0 is left/bottom from p3.
Definition aarectangle.hpp:111
friend constexpr aarectangle align(aarectangle haystack, extent2 needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:291
friend constexpr aarectangle align(aarectangle haystack, aarectangle needle, alignment alignment) noexcept
Align a rectangle within another rectangle.
Definition aarectangle.hpp:330
friend constexpr aarectangle operator+(aarectangle const &lhs, value_type rhs) noexcept
Expand the rectangle for the same amount in all directions.
Definition aarectangle.hpp:410
constexpr value_type center() const noexcept
The center on the x-axis between left and right.
Definition aarectangle.hpp:240
constexpr aarectangle & operator|=(point2 const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:145
constexpr aarectangle(float x, float y, float width, float height) noexcept
Create a box from the position and size.
Definition aarectangle.hpp:63
friend constexpr aarectangle ceil(aarectangle const &rhs) noexcept
Round rectangle by expanding to pixel edge.
Definition aarectangle.hpp:445
constexpr aarectangle(point2 const &p0, point2 const &p3) noexcept
Create a rectangle from the left-bottom and right-top points.
Definition aarectangle.hpp:82
constexpr aarectangle & operator|=(aarectangle const &rhs) noexcept
Expand the current rectangle to include the new rectangle.
Definition aarectangle.hpp:135
constexpr value_type middle() const noexcept
The middle on the y-axis between bottom and top.
Definition aarectangle.hpp:233
constexpr aarectangle(point2 const &p0, extent2 const &extent) noexcept
Create a rectangle from the size.
Definition aarectangle.hpp:97
Horizontal/Vertical alignment combination.
Definition alignment.hpp:244
A high-level geometric extent.
Definition extent2.hpp:32
A high-level geometric vector Part of the high-level vector, point, mat and color types.
Definition vector2.hpp:27
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 operator=(T... args)
T operator|=(T... args)
T store(T... args)