HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
matrix.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 "extent.hpp"
13#include "point.hpp"
14#include "rectangle.hpp"
15#include "quad.hpp"
16#include "circle.hpp"
17#include "line_segment.hpp"
18#include "corner_radii.hpp"
20#include <array>
21
22namespace hi {
23inline namespace v1 {
24namespace geo {
25
32template<int D>
33class matrix {
34public:
35 static_assert(D == 2 || D == 3, "Only 2D or 3D rotation-matrices are supported");
36
37 constexpr matrix(matrix const&) noexcept = default;
38 constexpr matrix(matrix&&) noexcept = default;
39 constexpr matrix& operator=(matrix const&) noexcept = default;
40 constexpr matrix& operator=(matrix&&) noexcept = default;
41
44 constexpr matrix() noexcept
45 {
46 hilet a = f32x4::broadcast(1.0f);
47 _col0 = a.x000();
48 _col1 = a._0y00();
49 _col2 = a._00z0();
50 _col3 = a._000w();
51 };
52
60 constexpr matrix(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3 = f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept :
61 _col0(col0), _col1(col1), _col2(col2), _col3(col3)
62 {
63 }
64
72 constexpr matrix(vector3 col0, vector3 col1, vector3 col2, vector3 col3 = vector3{}) noexcept
73 requires(D == 3)
74 :
75 _col0(static_cast<f32x4>(col0)),
76 _col1(static_cast<f32x4>(col1)),
77 _col2(static_cast<f32x4>(col2)),
78 _col3(static_cast<f32x4>(col3).xyz1())
79 {
80 }
81
87 constexpr matrix(vector2 col0, vector2 col1) noexcept
88 requires(D == 2)
89 :
90 _col0(static_cast<f32x4>(col0)),
91 _col1(static_cast<f32x4>(col1)),
92 _col2(f32x4{0.0f, 0.0f, 1.0f, 0.0f}),
93 _col3(f32x4{0.0f, 0.0f, 0.0f, 1.0f})
94 {
95 }
96
112 constexpr matrix(
113 float c0r0,
114 float c1r0,
115 float c2r0,
116 float c0r1,
117 float c1r1,
118 float c2r1,
119 float c0r2,
120 float c1r2,
121 float c2r2) noexcept
122 requires(D == 3)
123 :
124 _col0(c0r0, c0r1, c0r2, 0.0f), _col1(c1r0, c1r1, c1r2, 0.0f), _col2(c2r0, c2r1, c2r2, 0.0f), _col3(0.0f, 0.0f, 0.0f, 1.0f)
125 {
126 }
127
150 constexpr matrix(
151 float c0r0,
152 float c1r0,
153 float c2r0,
154 float c3r0,
155 float c0r1,
156 float c1r1,
157 float c2r1,
158 float c3r1,
159 float c0r2,
160 float c1r2,
161 float c2r2,
162 float c3r2,
163 float c0r3,
164 float c1r3,
165 float c2r3,
166 float c3r3) noexcept
167 requires(D == 3)
168 :
169 _col0(c0r0, c0r1, c0r2, c0r3), _col1(c1r0, c1r1, c1r2, c1r3), _col2(c2r0, c2r1, c2r2, c2r3), _col3(c3r0, c3r1, c3r2, c3r3)
170 {
171 }
172
175 template<int E>
176 requires(E < D)
177 [[nodiscard]] constexpr matrix(matrix<E> const& other) noexcept :
178 _col0(get<0>(other)), _col1(get<1>(other)), _col2(get<2>(other)), _col3(get<3>(other))
179 {
180 }
181
184 template<int E>
185 requires(E < D)
186 constexpr matrix& operator=(matrix<E> const& rhs) noexcept
187 {
188 _col0 = get<0>(rhs);
189 _col1 = get<1>(rhs);
190 _col2 = get<2>(rhs);
191 _col3 = get<3>(rhs);
192 return *this;
193 }
194
197 [[nodiscard]] constexpr explicit operator std::array<f32x4, 4>() const noexcept
198 {
199 hi_axiom(holds_invariant());
200 return {_col0, _col1, _col2, _col3};
201 }
202
212 [[nodiscard]] constexpr static matrix
213 uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept;
214
220 template<int I>
221 [[nodiscard]] friend constexpr f32x4 const& get(matrix const& rhs) noexcept
222 {
223 if constexpr (I == 0) {
224 return rhs._col0;
225 } else if constexpr (I == 1) {
226 return rhs._col1;
227 } else if constexpr (I == 2) {
228 return rhs._col2;
229 } else if constexpr (I == 3) {
230 return rhs._col3;
231 } else {
233 }
234 }
235
241 template<int I>
242 [[nodiscard]] friend constexpr f32x4& get(matrix& rhs) noexcept
243 {
244 if constexpr (I == 0) {
245 return rhs._col0;
246 } else if constexpr (I == 1) {
247 return rhs._col1;
248 } else if constexpr (I == 2) {
249 return rhs._col2;
250 } else if constexpr (I == 3) {
251 return rhs._col3;
252 } else {
254 }
255 }
256
257 [[nodiscard]] constexpr bool holds_invariant() const noexcept
258 {
259 return true;
260 }
261
267 [[nodiscard]] constexpr f32x4 operator*(f32x4 const& rhs) const noexcept
268 {
269 return {_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
270 }
271
277 [[nodiscard]] constexpr float operator*(float const& rhs) const noexcept
278 {
279 // As if _col0 * rhs.xxxx() in operator*(f32x4 rhs)
280 auto abs_scale = hypot<D>(_col0 * f32x4::broadcast(rhs));
281
282 // We want to keep the sign of the original scaler, even if the matrix has rotation.
283 return std::copysign(abs_scale, rhs);
284 }
285
291 [[nodiscard]] constexpr corner_radii<float> operator*(corner_radii<float> const& rhs) const noexcept
292 {
293 return {*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
294 }
295
303 template<int E>
304 [[nodiscard]] constexpr auto operator*(vector<float, E> const& rhs) const noexcept
305 {
306 hi_axiom(rhs.holds_invariant());
307 return vector<float, std::max(D, E)>{
308 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
309 _col2 * static_cast<f32x4>(rhs).zzzz()};
310 }
311
319 template<int E>
320 [[nodiscard]] constexpr auto operator*(extent<float, E> const& rhs) const noexcept
321 {
322 hi_axiom(rhs.holds_invariant());
323 return extent<float, std::max(D, E)>{
324 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
325 _col2 * static_cast<f32x4>(rhs).zzzz()};
326 }
327
333 template<int E>
334 [[nodiscard]] constexpr auto operator*(point<float, E> const& rhs) const noexcept
335 {
336 hi_axiom(rhs.holds_invariant());
337 return point<float, std::max(D, E)>{
338 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
339 _col2 * static_cast<f32x4>(rhs).zzzz() + _col3 * static_cast<f32x4>(rhs).wwww()};
340 }
341
351 [[nodiscard]] constexpr rectangle operator*(aarectangle const& rhs) const noexcept
352 {
353 return *this * rectangle{rhs};
354 }
355
362 [[nodiscard]] constexpr rectangle operator*(rectangle const& rhs) const noexcept
363 {
364 return rectangle{*this * rhs.origin, *this * rhs.right, *this * rhs.up};
365 }
366
372 [[nodiscard]] constexpr quad operator*(quad const& rhs) const noexcept
373 {
374 return quad{*this * rhs.p0, *this * rhs.p1, *this * rhs.p2, *this * rhs.p3};
375 }
376
382 [[nodiscard]] constexpr circle operator*(circle const& rhs) const noexcept
383 {
384 return circle{*this * midpoint(rhs), *this * rhs.radius()};
385 }
386
392 [[nodiscard]] constexpr line_segment operator*(line_segment const& rhs) const noexcept
393 {
394 return line_segment{*this * rhs.origin(), *this * rhs.direction()};
395 }
396
399 [[nodiscard]] constexpr auto operator*(matrix const& rhs) const noexcept
400 {
401 return matrix{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
402 }
403
406 [[nodiscard]] friend constexpr matrix transpose(matrix const& rhs) noexcept
407 {
408 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
409 return {std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
410 }
411
412
446 template<char DstX, char DstY, char DstZ, char DstW = 'w'>
447 [[nodiscard]] friend constexpr matrix reflect(matrix const& rhs) noexcept
448 requires(D == 3)
449 {
450 return matrix{reflect_column<DstX>(), reflect_column<DstY>(), reflect_column<DstZ>(), reflect_column<DstW>()} * rhs;
451 }
452
458 template<int E>
459 [[nodiscard]] constexpr bool operator==(matrix<E> const& rhs) const noexcept
460 {
461 return _col0 == rhs._col0 && _col1 == rhs._col1 && _col2 == rhs._col2 && _col3 == rhs._col3;
462 }
463
466 [[nodiscard]] constexpr matrix operator~() const
467 {
468 // rc
469 // var s0 : Number = i00 * i11 -
470 // i10 * i01;
471 // var c0 : Number = i20 * i31 -
472 // i30 * i21;
473 hilet s0c0 = _col0 * _col1.yxwz();
474
475 // var s1 : Number = i00 * i12 -
476 // i10 * i02;
477 // var c1 : Number = i20 * i32 -
478 // i30 * i22;
479 hilet s1c1 = _col0 * _col2.yxwz();
480 hilet s0c0s1c1 = hsub(s0c0, s1c1);
481
482 // var s2 : Number = i00 * i13 -
483 // i10 * i03;
484 // var c2 : Number = i20 * i33 -
485 // i30 * i23;
486 hilet s2c2 = _col0 * _col3.yxwz();
487
488 // var s3 : Number = i01 * i12 -
489 // i11 * i02;
490 // var c3 : Number = i21 * i32 -
491 // i31 * i22;
492 hilet s3c3 = _col1 * _col2.yxwz();
493 hilet s2c2s3c3 = hsub(s2c2, s3c3);
494
495 // var s4 : Number = i01 * i13 -
496 // i11 * i03;
497 // var c4 : Number = i21 * i33 -
498 // i31 * i23;
499 hilet s4c4 = _col1 * _col3.yxwz();
500
501 // var s5 : Number = i02 * i13 -
502 // i12 * i03;
503 // var c5 : Number = i22 * i33 -
504 // i32 * i23;
505 hilet s5c5 = _col2 * _col3.yxwz();
506 hilet s4c4s5c5 = hsub(s4c4, s5c5);
507
508 // det = (s0 * c5 +
509 // -s1 * c4 +
510 // s2 * c3 +
511 // s3 * c2 +
512 // -s4 * c1 +
513 // s5 * c0)
514 hilet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
515 hilet s45__ = s4c4s5c5.xz00();
516
517 hilet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
518 hilet c10__ = s0c0s1c1.wy00();
519
520 hilet det_prod_half0 = neg<0b0010>(s0123 * c5432);
521 hilet det_prod_half1 = neg<0b0001>(s45__ * c10__);
522
523 hilet det_sum0 = hadd(det_prod_half0, det_prod_half1);
524 hilet det_sum1 = hadd(det_sum0, det_sum0);
525 hilet det = hadd(det_sum1, det_sum1).xxxx();
526
527 if (det.x() == 0.0f) {
528 throw std::domain_error("Divide by zero");
529 }
530
531 hilet invdet = rcp(det);
532
533 hilet t = transpose(*this);
534
535 // rc rc rc rc
536 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
537 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
538 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
539 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
540 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
541 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
542 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
543 hilet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
544
545 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
546 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
547 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
548 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
549 tmp_c5543 = -tmp_c5543;
550 tmp_c4221 = -tmp_c4221;
551 tmp_c3100 = -tmp_c3100;
552 hilet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
553
554 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
555 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
556 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
557 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
558 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
559 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
560 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
561 hilet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
562
563 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
564 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
565 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
566 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
567 tmp_s5543 = -tmp_s5543;
568 tmp_s4221 = -tmp_s4221;
569 tmp_s3100 = -tmp_s3100;
570 hilet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
571
572 return {inv_col0, inv_col1, inv_col2, inv_col3};
573 }
574
575private:
576 f32x4 _col0;
577 f32x4 _col1;
578 f32x4 _col2;
579 f32x4 _col3;
580
581 template<char Axis>
582 [[nodiscard]] static constexpr f32x4 reflect_column() noexcept
583 {
584 if constexpr (Axis == 'x') {
585 return f32x4{1.0f, 0.0f, 0.0f, 0.0f};
586 } else if constexpr (Axis == 'X') {
587 return f32x4{-1.0f, 0.0f, 0.0f, 0.0f};
588 } else if constexpr (Axis == 'y') {
589 return f32x4{0.0f, 1.0f, 0.0f, 0.0f};
590 } else if constexpr (Axis == 'Y') {
591 return f32x4{0.0f, -1.0f, 0.0f, 0.0f};
592 } else if constexpr (Axis == 'z') {
593 return f32x4{0.0f, 0.0f, 1.0f, 0.0f};
594 } else if constexpr (Axis == 'Z') {
595 return f32x4{0.0f, 0.0f, -1.0f, 0.0f};
596 } else if constexpr (Axis == 'w') {
597 return f32x4{0.0f, 0.0f, 0.0f, 1.0f};
598 } else if constexpr (Axis == 'W') {
599 return f32x4{0.0f, 0.0f, 0.0f, -1.0f};
600 } else {
602 }
603 }
604};
605
606} // namespace geo
607
610using matrix2 = geo::matrix<2>;
611
614using matrix3 = geo::matrix<3>;
615
616}} // namespace hi::inline v1
617
Defined the geo::extent, extent2 and extent3 types.
Defined the corner_radii type.
Defines line_segment.
Defined the circle type.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#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
@ other
The gui_event does not have associated data.
@ rectangle
The gui_event has rectangle data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
geo::matrix< 2 > matrix2
A 2D homogenious transformation matrix.
Definition matrix.hpp:610
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:27
A type defining a 2D circle.
Definition circle.hpp:18
The 4 radii of the corners of a quad or rectangle.
Definition corner_radii.hpp:19
A high-level geometric extent.
Definition extent.hpp:30
Line segment.
Definition line_segment.hpp:19
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix.hpp:33
friend constexpr f32x4 const & get(matrix const &rhs) noexcept
Get a column.
Definition matrix.hpp:221
friend constexpr matrix reflect(matrix const &rhs) noexcept
Reflect axis of a matrix.
Definition matrix.hpp:447
constexpr bool operator==(matrix< E > const &rhs) const noexcept
Compare two matrices potentially of different dimensions.
Definition matrix.hpp:459
constexpr matrix(float c0r0, float c1r0, float c2r0, float c0r1, float c1r1, float c2r1, float c0r2, float c1r2, float c2r2) noexcept
Construct a 3x3 matrix from scalar values.
Definition matrix.hpp:112
constexpr float operator*(float const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:277
constexpr matrix(vector2 col0, vector2 col1) noexcept
Construct a matrix from four vectors.
Definition matrix.hpp:87
constexpr matrix(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3=f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept
Construct a matrix from four columns.
Definition matrix.hpp:60
constexpr auto operator*(vector< float, E > const &rhs) const noexcept
Transform a vector by the matrix.
Definition matrix.hpp:304
constexpr matrix operator~() const
Invert matrix.
Definition matrix.hpp:466
static constexpr matrix uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept
Create a transformation matrix to translate and uniformly-scale a src_rectangle to a dst_rectangle.
Definition scale.hpp:240
constexpr auto operator*(matrix const &rhs) const noexcept
Matrix/Matrix multiplication.
Definition matrix.hpp:399
constexpr rectangle operator*(rectangle const &rhs) const noexcept
Transform a rectangle by the matrix.
Definition matrix.hpp:362
constexpr rectangle operator*(aarectangle const &rhs) const noexcept
Transform an axis-aligned rectangle by the matrix.
Definition matrix.hpp:351
friend constexpr f32x4 & get(matrix &rhs) noexcept
Get a column.
Definition matrix.hpp:242
constexpr matrix(matrix< E > const &other) noexcept
Copy-construct a matrix from a smaller matrix.
Definition matrix.hpp:177
constexpr corner_radii< float > operator*(corner_radii< float > const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:291
constexpr circle operator*(circle const &rhs) const noexcept
Transform a circle by the matrix.
Definition matrix.hpp:382
constexpr matrix(float c0r0, float c1r0, float c2r0, float c3r0, float c0r1, float c1r1, float c2r1, float c3r1, float c0r2, float c1r2, float c2r2, float c3r2, float c0r3, float c1r3, float c2r3, float c3r3) noexcept
Construct a 4x4 matrix from scalar values.
Definition matrix.hpp:150
constexpr auto operator*(point< float, E > const &rhs) const noexcept
Transform a point by the matrix.
Definition matrix.hpp:334
constexpr auto operator*(extent< float, E > const &rhs) const noexcept
Transform a extent by the matrix.
Definition matrix.hpp:320
constexpr matrix() noexcept
Constructs an identity matrix.
Definition matrix.hpp:44
constexpr f32x4 operator*(f32x4 const &rhs) const noexcept
Transform a f32x4 numeric array by the matrix.
Definition matrix.hpp:267
constexpr line_segment operator*(line_segment const &rhs) const noexcept
Transform a line-segment by the matrix.
Definition matrix.hpp:392
friend constexpr matrix transpose(matrix const &rhs) noexcept
Matrix transpose.
Definition matrix.hpp:406
constexpr quad operator*(quad const &rhs) const noexcept
Transform a quad by the matrix.
Definition matrix.hpp:372
constexpr matrix(vector3 col0, vector3 col1, vector3 col2, vector3 col3=vector3{}) noexcept
Construct a matrix from four vectors.
Definition matrix.hpp:72
T copysign(T... args)
T max(T... args)