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 "../color/color.hpp"
21#include <array>
22
23namespace hi {
24inline namespace v1 {
25namespace geo {
26
33template<int D>
34class matrix {
35public:
36 static_assert(D == 2 || D == 3, "Only 2D or 3D rotation-matrices are supported");
37
38 constexpr matrix(matrix const&) noexcept = default;
39 constexpr matrix(matrix&&) noexcept = default;
40 constexpr matrix& operator=(matrix const&) noexcept = default;
41 constexpr matrix& operator=(matrix&&) noexcept = default;
42
45 constexpr matrix() noexcept
46 {
47 hilet a = f32x4::broadcast(1.0f);
48 _col0 = a.x000();
49 _col1 = a._0y00();
50 _col2 = a._00z0();
51 _col3 = a._000w();
52 };
53
61 constexpr matrix(f32x4 col0, f32x4 col1, f32x4 col2, f32x4 col3 = f32x4{0.0f, 0.0f, 0.0f, 1.0f}) noexcept :
62 _col0(col0), _col1(col1), _col2(col2), _col3(col3)
63 {
64 }
65
73 constexpr matrix(vector3 col0, vector3 col1, vector3 col2, vector3 col3 = vector3{}) noexcept
74 requires(D == 3)
75 :
76 _col0(static_cast<f32x4>(col0)),
77 _col1(static_cast<f32x4>(col1)),
78 _col2(static_cast<f32x4>(col2)),
79 _col3(static_cast<f32x4>(col3).xyz1())
80 {
81 }
82
98 constexpr matrix(
99 float c0r0,
100 float c1r0,
101 float c2r0,
102 float c0r1,
103 float c1r1,
104 float c2r1,
105 float c0r2,
106 float c1r2,
107 float c2r2) noexcept
108 requires(D == 3)
109 :
110 _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)
111 {
112 }
113
136 constexpr matrix(
137 float c0r0,
138 float c1r0,
139 float c2r0,
140 float c3r0,
141 float c0r1,
142 float c1r1,
143 float c2r1,
144 float c3r1,
145 float c0r2,
146 float c1r2,
147 float c2r2,
148 float c3r2,
149 float c0r3,
150 float c1r3,
151 float c2r3,
152 float c3r3) noexcept
153 requires(D == 3)
154 :
155 _col0(c0r0, c0r1, c0r2, c0r3), _col1(c1r0, c1r1, c1r2, c1r3), _col2(c2r0, c2r1, c2r2, c2r3), _col3(c3r0, c3r1, c3r2, c3r3)
156 {
157 }
158
161 template<int E>
162 requires(E < D)
163 [[nodiscard]] constexpr matrix(matrix<E> const& other) noexcept :
164 _col0(get<0>(other)), _col1(get<1>(other)), _col2(get<2>(other)), _col3(get<3>(other))
165 {
166 }
167
170 template<int E>
171 requires(E < D)
172 constexpr matrix& operator=(matrix<E> const& rhs) noexcept
173 {
174 _col0 = get<0>(rhs);
175 _col1 = get<1>(rhs);
176 _col2 = get<2>(rhs);
177 _col3 = get<3>(rhs);
178 return *this;
179 }
180
183 [[nodiscard]] constexpr explicit operator std::array<f32x4, 4>() const noexcept
184 {
185 hi_axiom(holds_invariant());
186 return {_col0, _col1, _col2, _col3};
187 }
188
198 [[nodiscard]] constexpr static matrix
199 uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept;
200
206 template<int I>
207 [[nodiscard]] friend constexpr f32x4 const& get(matrix const& rhs) noexcept
208 {
209 if constexpr (I == 0) {
210 return rhs._col0;
211 } else if constexpr (I == 1) {
212 return rhs._col1;
213 } else if constexpr (I == 2) {
214 return rhs._col2;
215 } else if constexpr (I == 3) {
216 return rhs._col3;
217 } else {
219 }
220 }
221
227 template<int I>
228 [[nodiscard]] friend constexpr f32x4& get(matrix& rhs) noexcept
229 {
230 if constexpr (I == 0) {
231 return rhs._col0;
232 } else if constexpr (I == 1) {
233 return rhs._col1;
234 } else if constexpr (I == 2) {
235 return rhs._col2;
236 } else if constexpr (I == 3) {
237 return rhs._col3;
238 } else {
240 }
241 }
242
243 [[nodiscard]] constexpr bool holds_invariant() const noexcept
244 {
245 return true;
246 }
247
253 [[nodiscard]] constexpr f32x4 operator*(f32x4 const& rhs) const noexcept
254 {
255 return {_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
256 }
257
263 [[nodiscard]] constexpr float operator*(float const& rhs) const noexcept
264 {
265 // As if _col0 * rhs.xxxx() in operator*(f32x4 rhs)
266 auto abs_scale = hypot<D>(_col0 * f32x4::broadcast(rhs));
267
268 // We want to keep the sign of the original scaler, even if the matrix has rotation.
269 return std::copysign(abs_scale, rhs);
270 }
271
277 [[nodiscard]] constexpr corner_radii operator*(corner_radii const& rhs) const noexcept
278 {
279 return {*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
280 }
281
289 template<int E>
290 [[nodiscard]] constexpr auto operator*(vector<float, E> const& rhs) const noexcept
291 {
292 hi_axiom(rhs.holds_invariant());
293 return vector<float, std::max(D, E)>{
294 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
295 _col2 * static_cast<f32x4>(rhs).zzzz()};
296 }
297
305 template<int E>
306 [[nodiscard]] constexpr auto operator*(extent<float, E> const& rhs) const noexcept
307 {
308 hi_axiom(rhs.holds_invariant());
309 return extent<float, std::max(D, E)>{
310 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
311 _col2 * static_cast<f32x4>(rhs).zzzz()};
312 }
313
319 template<int E>
320 [[nodiscard]] constexpr auto operator*(point<float, E> const& rhs) const noexcept
321 {
322 hi_axiom(rhs.holds_invariant());
323 return point<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() + _col3 * static_cast<f32x4>(rhs).wwww()};
326 }
327
337 [[nodiscard]] constexpr rectangle operator*(aarectangle const& rhs) const noexcept
338 {
339 return *this * rectangle{rhs};
340 }
341
348 [[nodiscard]] constexpr rectangle operator*(rectangle const& rhs) const noexcept
349 {
350 return rectangle{*this * rhs.origin, *this * rhs.right, *this * rhs.up};
351 }
352
358 [[nodiscard]] constexpr quad operator*(quad const& rhs) const noexcept
359 {
360 return quad{*this * rhs.p0, *this * rhs.p1, *this * rhs.p2, *this * rhs.p3};
361 }
362
368 [[nodiscard]] constexpr circle operator*(circle const& rhs) const noexcept
369 {
370 return circle{*this * midpoint(rhs), *this * rhs.radius()};
371 }
372
378 [[nodiscard]] constexpr line_segment operator*(line_segment const& rhs) const noexcept
379 {
380 return line_segment{*this * rhs.origin(), *this * rhs.direction()};
381 }
382
391 [[nodiscard]] constexpr auto operator*(color const& rhs) const noexcept
392 {
393 hi_axiom(rhs.holds_invariant());
394 auto r = color{
395 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
396 _col2 * static_cast<f32x4>(rhs).zzzz() + _col3};
397
398 r.a() = rhs.a();
399 return r;
400 }
401
404 [[nodiscard]] constexpr auto operator*(matrix const& rhs) const noexcept
405 {
406 return matrix{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
407 }
408
411 [[nodiscard]] friend constexpr matrix transpose(matrix const& rhs) noexcept
412 {
413 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
414 return {std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
415 }
416
417
451 template<char DstX, char DstY, char DstZ, char DstW = 'w'>
452 [[nodiscard]] friend constexpr matrix reflect(matrix const& rhs) noexcept
453 requires(D == 3)
454 {
455 return matrix{reflect_column<DstX>(), reflect_column<DstY>(), reflect_column<DstZ>(), reflect_column<DstW>()} * rhs;
456 }
457
463 template<int E>
464 [[nodiscard]] constexpr bool operator==(matrix<E> const& rhs) const noexcept
465 {
466 return _col0 == rhs._col0 && _col1 == rhs._col1 && _col2 == rhs._col2 && _col3 == rhs._col3;
467 }
468
471 [[nodiscard]] constexpr matrix operator~() const
472 {
473 // rc
474 // var s0 : Number = i00 * i11 -
475 // i10 * i01;
476 // var c0 : Number = i20 * i31 -
477 // i30 * i21;
478 hilet s0c0 = _col0 * _col1.yxwz();
479
480 // var s1 : Number = i00 * i12 -
481 // i10 * i02;
482 // var c1 : Number = i20 * i32 -
483 // i30 * i22;
484 hilet s1c1 = _col0 * _col2.yxwz();
485 hilet s0c0s1c1 = hsub(s0c0, s1c1);
486
487 // var s2 : Number = i00 * i13 -
488 // i10 * i03;
489 // var c2 : Number = i20 * i33 -
490 // i30 * i23;
491 hilet s2c2 = _col0 * _col3.yxwz();
492
493 // var s3 : Number = i01 * i12 -
494 // i11 * i02;
495 // var c3 : Number = i21 * i32 -
496 // i31 * i22;
497 hilet s3c3 = _col1 * _col2.yxwz();
498 hilet s2c2s3c3 = hsub(s2c2, s3c3);
499
500 // var s4 : Number = i01 * i13 -
501 // i11 * i03;
502 // var c4 : Number = i21 * i33 -
503 // i31 * i23;
504 hilet s4c4 = _col1 * _col3.yxwz();
505
506 // var s5 : Number = i02 * i13 -
507 // i12 * i03;
508 // var c5 : Number = i22 * i33 -
509 // i32 * i23;
510 hilet s5c5 = _col2 * _col3.yxwz();
511 hilet s4c4s5c5 = hsub(s4c4, s5c5);
512
513 // det = (s0 * c5 +
514 // -s1 * c4 +
515 // s2 * c3 +
516 // s3 * c2 +
517 // -s4 * c1 +
518 // s5 * c0)
519 hilet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
520 hilet s45__ = s4c4s5c5.xz00();
521
522 hilet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
523 hilet c10__ = s0c0s1c1.wy00();
524
525 hilet det_prod_half0 = neg<0b0010>(s0123 * c5432);
526 hilet det_prod_half1 = neg<0b0001>(s45__ * c10__);
527
528 hilet det_sum0 = hadd(det_prod_half0, det_prod_half1);
529 hilet det_sum1 = hadd(det_sum0, det_sum0);
530 hilet det = hadd(det_sum1, det_sum1).xxxx();
531
532 if (det.x() == 0.0f) {
533 throw std::domain_error("Divide by zero");
534 }
535
536 hilet invdet = rcp(det);
537
538 hilet t = transpose(*this);
539
540 // rc rc rc rc
541 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
542 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
543 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
544 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
545 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
546 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
547 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
548 hilet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
549
550 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
551 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
552 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
553 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
554 tmp_c5543 = -tmp_c5543;
555 tmp_c4221 = -tmp_c4221;
556 tmp_c3100 = -tmp_c3100;
557 hilet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
558
559 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
560 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
561 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
562 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
563 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
564 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
565 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
566 hilet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
567
568 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
569 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
570 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
571 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
572 tmp_s5543 = -tmp_s5543;
573 tmp_s4221 = -tmp_s4221;
574 tmp_s3100 = -tmp_s3100;
575 hilet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
576
577 return {inv_col0, inv_col1, inv_col2, inv_col3};
578 }
579
580private:
581 f32x4 _col0;
582 f32x4 _col1;
583 f32x4 _col2;
584 f32x4 _col3;
585
586 template<char Axis>
587 [[nodiscard]] static constexpr f32x4 reflect_column() noexcept
588 {
589 if constexpr (Axis == 'x') {
590 return f32x4{1.0f, 0.0f, 0.0f, 0.0f};
591 } else if constexpr (Axis == 'X') {
592 return f32x4{-1.0f, 0.0f, 0.0f, 0.0f};
593 } else if constexpr (Axis == 'y') {
594 return f32x4{0.0f, 1.0f, 0.0f, 0.0f};
595 } else if constexpr (Axis == 'Y') {
596 return f32x4{0.0f, -1.0f, 0.0f, 0.0f};
597 } else if constexpr (Axis == 'z') {
598 return f32x4{0.0f, 0.0f, 1.0f, 0.0f};
599 } else if constexpr (Axis == 'Z') {
600 return f32x4{0.0f, 0.0f, -1.0f, 0.0f};
601 } else if constexpr (Axis == 'w') {
602 return f32x4{0.0f, 0.0f, 0.0f, 1.0f};
603 } else if constexpr (Axis == 'W') {
604 return f32x4{0.0f, 0.0f, 0.0f, -1.0f};
605 } else {
607 }
608 }
609};
610
611} // namespace geo
612
615using matrix2 = geo::matrix<2>;
616
619using matrix3 = geo::matrix<3>;
620
621}} // namespace hi::inline v1
622
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:181
#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
Defined the geo::extent, extent2 and extent3 types.
Defined the corner_radii type.
Defines line_segment.
Defined the circle type.
@ other
The gui_event does not have associated data.
@ rectangle
The gui_event has rectangle data.
DOXYGEN BUG.
Definition algorithm.hpp:15
geometry/margins.hpp
Definition assert.hpp:18
geo::matrix< 2 > matrix2
A 2D homogenious transformation matrix.
Definition matrix.hpp:615
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:28
A type defining a 2D circle.
Definition circle.hpp:19
The 4 radiuses of the corners of a quad or rectangle.
Definition corner_radii.hpp:17
A high-level geometric extent.
Definition extent.hpp:31
Line segment.
Definition line_segment.hpp:19
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix.hpp:34
friend constexpr f32x4 const & get(matrix const &rhs) noexcept
Get a column.
Definition matrix.hpp:207
friend constexpr matrix reflect(matrix const &rhs) noexcept
Reflect axis of a matrix.
Definition matrix.hpp:452
constexpr bool operator==(matrix< E > const &rhs) const noexcept
Compare two matrices potentially of different dimensions.
Definition matrix.hpp:464
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:98
constexpr float operator*(float const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:263
constexpr auto operator*(color const &rhs) const noexcept
Transform a color by a color matrix.
Definition matrix.hpp:391
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:61
constexpr auto operator*(vector< float, E > const &rhs) const noexcept
Transform a vector by the matrix.
Definition matrix.hpp:290
constexpr matrix operator~() const
Invert matrix.
Definition matrix.hpp:471
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:211
constexpr auto operator*(matrix const &rhs) const noexcept
Matrix/Matrix multiplication.
Definition matrix.hpp:404
constexpr rectangle operator*(rectangle const &rhs) const noexcept
Transform a rectangle by the matrix.
Definition matrix.hpp:348
constexpr rectangle operator*(aarectangle const &rhs) const noexcept
Transform an axis-aligned rectangle by the matrix.
Definition matrix.hpp:337
friend constexpr f32x4 & get(matrix &rhs) noexcept
Get a column.
Definition matrix.hpp:228
constexpr corner_radii operator*(corner_radii const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:277
constexpr matrix(matrix< E > const &other) noexcept
Copy-construct a matrix from a smaller matrix.
Definition matrix.hpp:163
constexpr circle operator*(circle const &rhs) const noexcept
Transform a circle by the matrix.
Definition matrix.hpp:368
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:136
constexpr auto operator*(point< float, E > const &rhs) const noexcept
Transform a point by the matrix.
Definition matrix.hpp:320
constexpr auto operator*(extent< float, E > const &rhs) const noexcept
Transform a extent by the matrix.
Definition matrix.hpp:306
constexpr matrix() noexcept
Constructs an identity matrix.
Definition matrix.hpp:45
constexpr f32x4 operator*(f32x4 const &rhs) const noexcept
Transform a f32x4 numeric array by the matrix.
Definition matrix.hpp:253
constexpr line_segment operator*(line_segment const &rhs) const noexcept
Transform a line-segment by the matrix.
Definition matrix.hpp:378
friend constexpr matrix transpose(matrix const &rhs) noexcept
Matrix transpose.
Definition matrix.hpp:411
constexpr quad operator*(quad const &rhs) const noexcept
Transform a quad by the matrix.
Definition matrix.hpp:358
constexpr matrix(vector3 col0, vector3 col1, vector3 col2, vector3 col3=vector3{}) noexcept
Construct a matrix from four vectors.
Definition matrix.hpp:73
T copysign(T... args)
T max(T... args)