HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
extent.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 "vector.hpp"
12#include "../SIMD/module.hpp"
13#include "../utility/module.hpp"
14#include <compare>
15
16namespace hi { inline namespace v1 {
17namespace geo {
18
19template<int D>
20class scale;
21
29template<typename T, int D>
30class extent {
31public:
32 using value_type = T;
33 using array_type = simd<value_type, 4>;
34
35 static_assert(D == 2 || D == 3, "Only 2D or 3D extents are supported");
36
37 constexpr extent(extent const&) noexcept = default;
38 constexpr extent(extent&&) noexcept = default;
39 constexpr extent& operator=(extent const&) noexcept = default;
40 constexpr extent& operator=(extent&&) noexcept = default;
41
42 [[nodiscard]] constexpr static extent large() noexcept
43 {
44 return {large_number_v<value_type>, large_number_v<value_type>};
45 }
46
49 template<int E>
50 requires(E < D)
51 [[nodiscard]] constexpr extent(extent<value_type, E> const& other) noexcept : _v(static_cast<array_type>(other))
52 {
54 }
55
58 [[nodiscard]] constexpr explicit operator array_type() const noexcept
59 {
60 return _v;
61 }
62
63 [[nodiscard]] constexpr explicit extent(array_type const& other) noexcept : _v(other) {}
64
65 [[nodiscard]] constexpr explicit operator bool() const noexcept
66 {
67 if constexpr (D == 2) {
68 return _v.x() != value_type{0} or _v.y() != value_type{0};
69 } else if constexpr (D == 3) {
70 return _v.x() != value_type{0} or _v.y() != value_type{0} or _v.z() != value_type{0};
71 } else {
73 }
74 }
75
76 template<int E>
77 [[nodiscard]] constexpr explicit operator vector<value_type, E>() const noexcept
78 requires(E >= D)
79 {
81 return vector<value_type, E>{static_cast<array_type>(*this)};
82 }
83
86 [[nodiscard]] constexpr extent() noexcept : _v(value_type{0}, value_type{0}, value_type{0}, value_type{0})
87 {
89 }
90
95 [[nodiscard]] constexpr extent(value_type width, value_type height) noexcept
96 requires(D == 2)
97 : _v(width, height, value_type{0}, value_type{0})
98 {
100 }
101
107 [[nodiscard]] constexpr extent(value_type width, value_type height, value_type depth = value_type{0}) noexcept
108 requires(D == 3)
109 : _v(width, height, depth, value_type{0})
110 {
112 }
113
114 [[nodiscard]] static constexpr extent infinity() noexcept
115 requires(D == 2)
116 {
118 }
119
120 [[nodiscard]] static constexpr extent infinity() noexcept
121 requires(D == 3)
122 {
123 return extent{
127 }
128
129 [[nodiscard]] static constexpr extent large() noexcept
130 requires(D == 2)
131 {
132 return extent{value_type{16777216}, value_type{16777216}};
133 }
134
135 [[nodiscard]] static constexpr extent large() noexcept
136 requires(D == 3)
137 {
138 return extent{value_type{16777216}, value_type{16777216}, value_type{16777216}};
139 }
140
141 [[nodiscard]] static constexpr extent nan() noexcept
142 requires std::is_same_v<value_type, float> and (D == 2)
143 {
144 auto r = extent{};
147 return r;
148 }
149
150 [[nodiscard]] static constexpr extent nan() noexcept
151 requires std::is_same_v<value_type, float> and (D == 3)
152 {
153 auto r = extent{};
157 return r;
158 }
159
166 [[nodiscard]] constexpr value_type& width() noexcept
167 {
168 return _v.x();
169 }
170
177 [[nodiscard]] constexpr value_type& height() noexcept
178 {
179 return _v.y();
180 }
181
188 [[nodiscard]] constexpr value_type& depth() noexcept
189 requires(D == 3)
190 {
191 return _v.z();
192 }
193
200 [[nodiscard]] constexpr value_type width() const noexcept
201 {
202 return _v.x();
203 }
204
211 [[nodiscard]] constexpr value_type height() const noexcept
212 {
213 return _v.y();
214 }
215
222 [[nodiscard]] constexpr value_type depth() const noexcept
223 requires(D == 3)
224 {
225 return _v.z();
226 }
227
228 [[nodiscard]] constexpr vector<value_type, D> right() const noexcept
229 {
230 return vector<value_type, D>{_v.x000()};
231 }
232
233 [[nodiscard]] constexpr vector<value_type, D> up() const noexcept
234 {
235 return vector<value_type, D>{_v._0y00()};
236 }
237
238 constexpr extent& operator+=(extent const& rhs) noexcept
239 {
240 return *this = *this + rhs;
241 }
242
248 [[nodiscard]] constexpr friend extent operator+(extent const& lhs, extent const& rhs) noexcept
249 {
250 hi_axiom(lhs.holds_invariant() && rhs.holds_invariant());
251 return extent{lhs._v + rhs._v};
252 }
253
259 [[nodiscard]] constexpr friend extent operator-(extent const& lhs, extent const& rhs) noexcept
260 {
261 hi_axiom(lhs.holds_invariant() && rhs.holds_invariant());
262 return extent{lhs._v - rhs._v};
263 }
264
265 constexpr friend scale<D> operator/(extent const& lhs, extent const& rhs) noexcept;
266
272 [[nodiscard]] constexpr friend extent operator*(extent const& lhs, value_type const& rhs) noexcept
273 {
274 hi_axiom(lhs.holds_invariant());
275 return extent{lhs._v * rhs};
276 }
277
278 template<int E>
279 [[nodiscard]] constexpr friend auto operator+(extent const& lhs, vector<value_type, E> const& rhs) noexcept
280 {
281 hi_axiom(lhs.holds_invariant());
282 hi_axiom(rhs.holds_invariant());
283
284 return extent<value_type, std::max(D, E)>{static_cast<array_type>(lhs) + static_cast<array_type>(rhs)};
285 }
286
287 template<int E>
288 [[nodiscard]] constexpr friend auto operator+(vector<value_type, E> const& lhs, extent const& rhs) noexcept
289 {
290 hi_axiom(lhs.holds_invariant());
291 hi_axiom(rhs.holds_invariant());
292
293 return vector<value_type, std::max(D, E)>{static_cast<array_type>(lhs) + static_cast<array_type>(rhs)};
294 }
295
301 [[nodiscard]] constexpr friend extent operator+(extent const& lhs, value_type const& rhs) noexcept
302 {
303 hi_axiom(lhs.holds_invariant());
304
305 auto r = extent{};
306 for (std::size_t i = 0; i != D; ++i) {
307 r._v[i] = lhs._v[i] + rhs;
308 }
309
310 return r;
311 }
312
318 [[nodiscard]] constexpr friend extent operator*(value_type const& lhs, extent const& rhs) noexcept
319 {
320 hi_axiom(rhs.holds_invariant());
321 return extent{lhs * rhs._v};
322 }
323
329 [[nodiscard]] constexpr friend bool operator==(extent const& lhs, extent const& rhs) noexcept
330 {
331 hi_axiom(lhs.holds_invariant() && rhs.holds_invariant());
332 return equal(lhs._v, rhs._v);
333 }
334
335 [[nodiscard]] constexpr friend std::partial_ordering operator<=>(extent const& lhs, extent const& rhs) noexcept
336 requires(D == 3)
337 {
338 constexpr std::size_t mask = 0b111;
339
340 hilet equal = eq(lhs._v, rhs._v) & mask;
341 if (equal == mask) {
342 // Only equivalent if all elements are equal.
343 return std::partial_ordering::equivalent;
344 }
345
346 hilet less = lt(lhs._v, rhs._v) & mask;
347 if ((less | equal) == mask) {
348 // If one or more elements is less (but none are greater) then the ordering is less.
349 return std::partial_ordering::less;
350 }
351
352 hilet greater = lt(lhs._v, rhs._v) & mask;
353 if ((greater | equal) == mask) {
354 // If one or more elements is greater (but none are less) then the ordering is greater.
355 return std::partial_ordering::greater;
356 }
357
358 // Some elements are less and others are greater, we don't have an ordering.
359 return std::partial_ordering::unordered;
360 }
361
362 [[nodiscard]] constexpr friend std::partial_ordering operator<=>(extent const& lhs, extent const& rhs) noexcept
363 requires(D == 2)
364 {
365 constexpr std::size_t mask = 0b11;
366
367 hilet equal = (lhs._v == rhs._v).mask() & mask;
368 if (equal == mask) {
369 // Only equivalent if all elements are equal.
370 return std::partial_ordering::equivalent;
371 }
372
373 hilet less = (lhs._v < rhs._v).mask() & mask;
374 if ((less | equal) == mask) {
375 // If one or more elements is less (but none are greater) then the ordering is less.
376 return std::partial_ordering::less;
377 }
378
379 hilet greater = (lhs._v > rhs._v).mask() & mask;
380 if ((greater | equal) == mask) {
381 // If one or more elements is greater (but none are less) then the ordering is greater.
382 return std::partial_ordering::greater;
383 }
384
385 // Some elements are less and others are greater, we don't have an ordering.
386 return std::partial_ordering::unordered;
387 }
388
393 [[nodiscard]] hi_force_inline constexpr friend value_type squared_hypot(extent const& rhs) noexcept
394 {
395 hi_axiom(rhs.holds_invariant());
396 return squared_hypot<element_mask>(rhs._v);
397 }
398
403 [[nodiscard]] constexpr friend value_type hypot(extent const& rhs) noexcept
404 {
405 hi_axiom(rhs.holds_invariant());
406 return hypot<element_mask>(rhs._v);
407 }
408
413 [[nodiscard]] constexpr friend value_type rcp_hypot(extent const& rhs) noexcept
414 {
415 hi_axiom(rhs.holds_invariant());
416 return rcp_hypot<element_mask>(rhs._v);
417 }
418
423 [[nodiscard]] constexpr friend extent normalize(extent const& rhs) noexcept
424 {
425 hi_axiom(rhs.holds_invariant());
426 return extent{normalize<element_mask>(rhs._v)};
427 }
428
429 [[nodiscard]] constexpr friend extent ceil(extent const& rhs) noexcept
430 requires std::is_same_v<value_type, float>
431 {
432 hi_axiom(rhs.holds_invariant());
433 return extent{ceil(array_type{rhs})};
434 }
435
436 [[nodiscard]] constexpr friend extent floor(extent const& rhs) noexcept
437 requires std::is_same_v<value_type, float>
438 {
439 hi_axiom(rhs.holds_invariant());
440 return extent{floor(static_cast<array_type>(rhs))};
441 }
442
443 [[nodiscard]] constexpr friend extent round(extent const& rhs) noexcept
444 requires std::is_same_v<value_type, float>
445 {
446 hi_axiom(rhs.holds_invariant());
447 return extent{round(static_cast<array_type>(rhs))};
448 }
449
450 [[nodiscard]] constexpr friend extent min(extent const& lhs, extent const& rhs) noexcept
451 {
452 return extent{min(static_cast<array_type>(lhs), static_cast<array_type>(rhs))};
453 }
454
455 [[nodiscard]] constexpr friend extent max(extent const& lhs, extent const& rhs) noexcept
456 {
457 return extent{max(static_cast<array_type>(lhs), static_cast<array_type>(rhs))};
458 }
459
460 [[nodiscard]] constexpr friend extent clamp(extent const& value, extent const& min, extent const& max) noexcept
461 {
462 return extent{clamp(static_cast<array_type>(value), static_cast<array_type>(min), static_cast<array_type>(max))};
463 }
464
469 [[nodiscard]] constexpr bool holds_invariant() const noexcept
470 {
471 return _v.x() >= value_type{0} && _v.y() >= value_type{0} && _v.z() >= value_type{0} && _v.w() == value_type{0} &&
472 (D == 3 || _v.z() == value_type{0});
473 }
474
475 [[nodiscard]] friend std::string to_string(extent const& rhs) noexcept
476 {
477 if constexpr (D == 2) {
478 return std::format("[{}, {}]", rhs._v.x(), rhs._v.y());
479 } else if constexpr (D == 3) {
480 return std::format("[{}, {}, {}]", rhs._v.x(), rhs._v.y(), rhs._v.z());
481 } else {
483 }
484 }
485
486 friend std::ostream& operator<<(std::ostream& lhs, extent const& rhs) noexcept
487 {
488 return lhs << to_string(rhs);
489 }
490
491private:
492 array_type _v;
493
494 static constexpr std::size_t element_mask = (1_uz << D) - 1;
495};
496
497} // namespace geo
498
502using extent2 = geo::extent<float, 2>;
503
507using extent3 = geo::extent<float, 3>;
508
512using extent2i = geo::extent<int, 2>;
513
517using extent3i = geo::extent<int, 3>;
518
519template<>
520[[nodiscard]] constexpr extent2i narrow_cast(extent2 const& rhs) noexcept
521{
522 return {narrow_cast<int>(rhs.width()), narrow_cast<int>(rhs.height())};
523}
524
525template<>
526[[nodiscard]] constexpr extent2 narrow_cast(extent2i const& rhs) noexcept
527{
528 return {narrow_cast<float>(rhs.width()), narrow_cast<float>(rhs.height())};
529}
530
531}} // namespace hi::v1
532
533template<typename CharT>
534struct std::formatter<hi::geo::extent<float, 2>, CharT> {
535 auto parse(auto& pc)
536 {
537 return pc.end();
538 }
539
540 auto format(hi::geo::extent<float, 2> const& t, auto& fc)
541 {
542 return std::vformat_to(fc.out(), "[{}, {}]", std::make_format_args(t.width(), t.height()));
543 }
544};
545
546template<typename CharT>
547struct std::formatter<hi::geo::extent<float, 3>, CharT> {
548 auto parse(auto& pc)
549 {
550 return pc.end();
551 }
552
553 auto format(hi::geo::extent<float, 3> const& t, auto& fc)
554 {
555 return std::vformat_to(fc.out(), "[{}, {}, {}]", std::make_format_args(t.width(), t.height(), t.depth()));
556 }
557};
558
559template<typename CharT>
560struct std::formatter<hi::geo::extent<int, 2>, CharT> {
561 auto parse(auto& pc)
562 {
563 return pc.end();
564 }
565
566 auto format(hi::geo::extent<int, 2> const& t, auto& fc)
567 {
568 return std::vformat_to(fc.out(), "[{}, {}]", std::make_format_args(t.width(), t.height()));
569 }
570};
571
572template<typename CharT>
573struct std::formatter<hi::geo::extent<int, 3>, CharT> {
574 auto parse(auto& pc)
575 {
576 return pc.end();
577 }
578
579 auto format(hi::geo::extent<int, 3> const& t, auto& fc)
580 {
581 return std::vformat_to(fc.out(), "[{}, {}, {}]", std::make_format_args(t.width(), t.height(), t.depth()));
582 }
583};
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:308
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:264
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
geo::extent< int, 3 > extent3i
A 3D extent.
Definition extent.hpp:517
geo::extent< float, 3 > extent3
A 3D extent.
Definition extent.hpp:507
geo::extent< int, 2 > extent2i
A 2D extent.
Definition extent.hpp:512
geo::extent< float, 2 > extent2
A 2D extent.
Definition extent.hpp:502
@ other
The gui_event does not have associated data.
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
Definition extent.hpp:20
A high-level geometric extent.
Definition extent.hpp:30
hi_force_inline constexpr friend value_type squared_hypot(extent const &rhs) noexcept
Get the squared length of the extent.
Definition extent.hpp:393
constexpr extent() noexcept
Construct a empty extent / zero length.
Definition extent.hpp:86
constexpr extent(extent< value_type, E > const &other) noexcept
Construct a extent from a lower dimension extent.
Definition extent.hpp:51
constexpr value_type & width() noexcept
Access the x-as-width element from the extent.
Definition extent.hpp:166
constexpr friend extent operator*(value_type const &lhs, extent const &rhs) noexcept
Scale the extent by a scaler.
Definition extent.hpp:318
constexpr bool holds_invariant() const noexcept
Check if the extent is valid.
Definition extent.hpp:469
constexpr friend value_type rcp_hypot(extent const &rhs) noexcept
Get the length of the extent.
Definition extent.hpp:413
constexpr friend extent operator-(extent const &lhs, extent const &rhs) noexcept
Subtract two extents from each other.
Definition extent.hpp:259
constexpr value_type height() const noexcept
Access the y-as-height element from the extent.
Definition extent.hpp:211
constexpr friend extent normalize(extent const &rhs) noexcept
Normalize a extent to a unit extent.
Definition extent.hpp:423
constexpr friend extent operator*(extent const &lhs, value_type const &rhs) noexcept
Scale the extent by a scaler.
Definition extent.hpp:272
constexpr friend value_type hypot(extent const &rhs) noexcept
Get the length of the extent.
Definition extent.hpp:403
constexpr value_type & depth() noexcept
Access the z-as-depth element from the extent.
Definition extent.hpp:188
constexpr value_type width() const noexcept
Access the x-as-width element from the extent.
Definition extent.hpp:200
constexpr value_type depth() const noexcept
Access the z-as-depth element from the extent.
Definition extent.hpp:222
constexpr extent(value_type width, value_type height) noexcept
Construct a 2D extent from the width and height.
Definition extent.hpp:95
constexpr friend bool operator==(extent const &lhs, extent const &rhs) noexcept
Compare if two extents are equal.
Definition extent.hpp:329
constexpr extent(value_type width, value_type height, value_type depth=value_type{0}) noexcept
Construct a 3D extent from width, height and depth.
Definition extent.hpp:107
constexpr friend extent operator+(extent const &lhs, value_type const &rhs) noexcept
Add a scaler to the extent.
Definition extent.hpp:301
constexpr friend extent operator+(extent const &lhs, extent const &rhs) noexcept
Add two extents from each other.
Definition extent.hpp:248
constexpr value_type & height() noexcept
Access the y-as-height element from the extent.
Definition extent.hpp:177
T equal(T... args)
T infinity(T... args)
T max(T... args)
T signaling_NaN(T... args)