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