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
97 constexpr matrix(
98 float c0r0,
99 float c1r0,
100 float c2r0,
101 float c0r1,
102 float c1r1,
103 float c2r1,
104 float c0r2,
105 float c1r2,
106 float c2r2) noexcept
107 requires(D == 3)
108 :
109 _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)
110 {
111 }
112
135 constexpr matrix(
136 float c0r0,
137 float c1r0,
138 float c2r0,
139 float c3r0,
140 float c0r1,
141 float c1r1,
142 float c2r1,
143 float c3r1,
144 float c0r2,
145 float c1r2,
146 float c2r2,
147 float c3r2,
148 float c0r3,
149 float c1r3,
150 float c2r3,
151 float c3r3) noexcept
152 requires(D == 3)
153 :
154 _col0(c0r0, c0r1, c0r2, c0r3), _col1(c1r0, c1r1, c1r2, c1r3), _col2(c2r0, c2r1, c2r2, c2r3), _col3(c3r0, c3r1, c3r2, c3r3)
155 {
156 }
157
160 template<int E>
161 requires(E < D)
162 [[nodiscard]] constexpr matrix(matrix<E> const& other) noexcept :
163 _col0(get<0>(other)), _col1(get<1>(other)), _col2(get<2>(other)), _col3(get<3>(other))
164 {
165 }
166
169 template<int E>
170 requires(E < D)
171 constexpr matrix& operator=(matrix<E> const& rhs) noexcept
172 {
173 _col0 = get<0>(rhs);
174 _col1 = get<1>(rhs);
175 _col2 = get<2>(rhs);
176 _col3 = get<3>(rhs);
177 return *this;
178 }
179
182 [[nodiscard]] constexpr explicit operator std::array<f32x4, 4>() const noexcept
183 {
184 hi_axiom(holds_invariant());
185 return {_col0, _col1, _col2, _col3};
186 }
187
197 [[nodiscard]] constexpr static matrix
198 uniform(aarectangle src_rectangle, aarectangle dst_rectangle, alignment alignment) noexcept;
199
205 template<int I>
206 [[nodiscard]] friend constexpr f32x4 const& get(matrix const& rhs) noexcept
207 {
208 if constexpr (I == 0) {
209 return rhs._col0;
210 } else if constexpr (I == 1) {
211 return rhs._col1;
212 } else if constexpr (I == 2) {
213 return rhs._col2;
214 } else if constexpr (I == 3) {
215 return rhs._col3;
216 } else {
218 }
219 }
220
226 template<int I>
227 [[nodiscard]] friend constexpr f32x4& get(matrix& rhs) noexcept
228 {
229 if constexpr (I == 0) {
230 return rhs._col0;
231 } else if constexpr (I == 1) {
232 return rhs._col1;
233 } else if constexpr (I == 2) {
234 return rhs._col2;
235 } else if constexpr (I == 3) {
236 return rhs._col3;
237 } else {
239 }
240 }
241
242 [[nodiscard]] constexpr bool holds_invariant() const noexcept
243 {
244 return true;
245 }
246
252 [[nodiscard]] constexpr f32x4 operator*(f32x4 const& rhs) const noexcept
253 {
254 return {_col0 * rhs.xxxx() + _col1 * rhs.yyyy() + _col2 * rhs.zzzz() + _col3 * rhs.wwww()};
255 }
256
262 [[nodiscard]] constexpr float operator*(float const& rhs) const noexcept
263 {
264 // As if _col0 * rhs.xxxx() in operator*(f32x4 rhs)
265 auto abs_scale = hypot<D>(_col0 * f32x4::broadcast(rhs));
266
267 // We want to keep the sign of the original scaler, even if the matrix has rotation.
268 return std::copysign(abs_scale, rhs);
269 }
270
276 [[nodiscard]] constexpr corner_radii operator*(corner_radii const& rhs) const noexcept
277 {
278 return {*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
279 }
280
288 template<int E>
289 [[nodiscard]] constexpr auto operator*(vector<float, E> const& rhs) const noexcept
290 {
291 hi_axiom(rhs.holds_invariant());
292 return vector<float, std::max(D, E)>{
293 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
294 _col2 * static_cast<f32x4>(rhs).zzzz()};
295 }
296
304 template<int E>
305 [[nodiscard]] constexpr auto operator*(extent<float, E> const& rhs) const noexcept
306 {
307 hi_axiom(rhs.holds_invariant());
308 return extent<float, std::max(D, E)>{
309 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
310 _col2 * static_cast<f32x4>(rhs).zzzz()};
311 }
312
318 template<int E>
319 [[nodiscard]] constexpr auto operator*(point<float, E> const& rhs) const noexcept
320 {
321 hi_axiom(rhs.holds_invariant());
322 return point<float, std::max(D, E)>{
323 _col0 * static_cast<f32x4>(rhs).xxxx() + _col1 * static_cast<f32x4>(rhs).yyyy() +
324 _col2 * static_cast<f32x4>(rhs).zzzz() + _col3 * static_cast<f32x4>(rhs).wwww()};
325 }
326
336 [[nodiscard]] constexpr rectangle operator*(aarectangle const& rhs) const noexcept
337 {
338 return *this * rectangle{rhs};
339 }
340
347 [[nodiscard]] constexpr rectangle operator*(rectangle const& rhs) const noexcept
348 {
349 return rectangle{*this * rhs.origin, *this * rhs.right, *this * rhs.up};
350 }
351
357 [[nodiscard]] constexpr quad operator*(quad const& rhs) const noexcept
358 {
359 return quad{*this * rhs.p0, *this * rhs.p1, *this * rhs.p2, *this * rhs.p3};
360 }
361
367 [[nodiscard]] constexpr circle operator*(circle const& rhs) const noexcept
368 {
369 return circle{*this * midpoint(rhs), *this * rhs.radius()};
370 }
371
377 [[nodiscard]] constexpr line_segment operator*(line_segment const& rhs) const noexcept
378 {
379 return line_segment{*this * rhs.origin(), *this * rhs.direction()};
380 }
381
384 [[nodiscard]] constexpr auto operator*(matrix const& rhs) const noexcept
385 {
386 return matrix{*this * get<0>(rhs), *this * get<1>(rhs), *this * get<2>(rhs), *this * get<3>(rhs)};
387 }
388
391 [[nodiscard]] friend constexpr matrix transpose(matrix const& rhs) noexcept
392 {
393 auto tmp = transpose(rhs._col0, rhs._col1, rhs._col2, rhs._col3);
394 return {std::get<0>(tmp), std::get<1>(tmp), std::get<2>(tmp), std::get<3>(tmp)};
395 }
396
397
431 template<char DstX, char DstY, char DstZ, char DstW = 'w'>
432 [[nodiscard]] friend constexpr matrix reflect(matrix const& rhs) noexcept
433 requires(D == 3)
434 {
435 return matrix{reflect_column<DstX>(), reflect_column<DstY>(), reflect_column<DstZ>(), reflect_column<DstW>()} * rhs;
436 }
437
443 template<int E>
444 [[nodiscard]] constexpr bool operator==(matrix<E> const& rhs) const noexcept
445 {
446 return _col0 == rhs._col0 && _col1 == rhs._col1 && _col2 == rhs._col2 && _col3 == rhs._col3;
447 }
448
451 [[nodiscard]] constexpr matrix operator~() const
452 {
453 // rc
454 // var s0 : Number = i00 * i11 -
455 // i10 * i01;
456 // var c0 : Number = i20 * i31 -
457 // i30 * i21;
458 hilet s0c0 = _col0 * _col1.yxwz();
459
460 // var s1 : Number = i00 * i12 -
461 // i10 * i02;
462 // var c1 : Number = i20 * i32 -
463 // i30 * i22;
464 hilet s1c1 = _col0 * _col2.yxwz();
465 hilet s0c0s1c1 = hsub(s0c0, s1c1);
466
467 // var s2 : Number = i00 * i13 -
468 // i10 * i03;
469 // var c2 : Number = i20 * i33 -
470 // i30 * i23;
471 hilet s2c2 = _col0 * _col3.yxwz();
472
473 // var s3 : Number = i01 * i12 -
474 // i11 * i02;
475 // var c3 : Number = i21 * i32 -
476 // i31 * i22;
477 hilet s3c3 = _col1 * _col2.yxwz();
478 hilet s2c2s3c3 = hsub(s2c2, s3c3);
479
480 // var s4 : Number = i01 * i13 -
481 // i11 * i03;
482 // var c4 : Number = i21 * i33 -
483 // i31 * i23;
484 hilet s4c4 = _col1 * _col3.yxwz();
485
486 // var s5 : Number = i02 * i13 -
487 // i12 * i03;
488 // var c5 : Number = i22 * i33 -
489 // i32 * i23;
490 hilet s5c5 = _col2 * _col3.yxwz();
491 hilet s4c4s5c5 = hsub(s4c4, s5c5);
492
493 // det = (s0 * c5 +
494 // -s1 * c4 +
495 // s2 * c3 +
496 // s3 * c2 +
497 // -s4 * c1 +
498 // s5 * c0)
499 hilet s0123 = s0c0s1c1.xz00() + s2c2s3c3._00xz();
500 hilet s45__ = s4c4s5c5.xz00();
501
502 hilet c5432 = s4c4s5c5.wy00() + s2c2s3c3._00wy();
503 hilet c10__ = s0c0s1c1.wy00();
504
505 hilet det_prod_half0 = neg<0b0010>(s0123 * c5432);
506 hilet det_prod_half1 = neg<0b0001>(s45__ * c10__);
507
508 hilet det_sum0 = hadd(det_prod_half0, det_prod_half1);
509 hilet det_sum1 = hadd(det_sum0, det_sum0);
510 hilet det = hadd(det_sum1, det_sum1).xxxx();
511
512 if (det.x() == 0.0f) {
513 throw std::domain_error("Divide by zero");
514 }
515
516 hilet invdet = rcp(det);
517
518 hilet t = transpose(*this);
519
520 // rc rc rc rc
521 // m.i00 := (i11 * c5 + i12 * -c4 + i13 * c3) * invdet;
522 // m.i10 := (i10 * -c5 + i12 * c2 + i13 * -c1) * invdet;
523 // m.i20 := (i10 * c4 + i11 * -c2 + i13 * c0) * invdet;
524 // m.i30 := (i10 * -c3 + i11 * c1 + i12 * -c0) * invdet;
525 auto tmp_c5543 = neg<0b1010>(c5432.xxyz());
526 auto tmp_c4221 = neg<0b0101>(c5432.yww0() + c10__._000x());
527 auto tmp_c3100 = neg<0b1010>(c5432.z000() + c10__._0xyy());
528 hilet inv_col0 = ((t._col1.yxxx() * tmp_c5543) + (t._col1.zzyy() * tmp_c4221) + (t._col1.wwwz() * tmp_c3100)) * invdet;
529
530 // m.i01 := (i01 * -c5 + i02 * c4 + i03 * -c3) * invdet;
531 // m.i11 := (i00 * c5 + i02 * -c2 + i03 * c1) * invdet;
532 // m.i21 := (i00 * -c4 + i01 * c2 + i03 * -c0) * invdet;
533 // m.i31 := (i00 * c3 + i01 * -c1 + i02 * c0) * invdet;
534 tmp_c5543 = -tmp_c5543;
535 tmp_c4221 = -tmp_c4221;
536 tmp_c3100 = -tmp_c3100;
537 hilet inv_col1 = ((t._col0.yxxx() * tmp_c5543) + (t._col0.zzyy() * tmp_c4221) + (t._col0.wwwz() * tmp_c3100)) * invdet;
538
539 // m.i02 := (i31 * s5 + i32 * -s4 + i33 * s3) * invdet;
540 // m.i12 := (i30 * -s5 + i32 * s2 + i33 * -s1) * invdet;
541 // m.i22 := (i30 * s4 + i31 * -s2 + i33 * s0) * invdet;
542 // m.i32 := (i30 * -s3 + i31 * s1 + i32 * -s0) * invdet;
543 auto tmp_s5543 = neg<0b1010>(s45__.yyx0() + s0123._000w());
544 auto tmp_s4221 = neg<0b0101>(s45__.x000() + s0123._0zzy());
545 auto tmp_s3100 = neg<0b1010>(s0123.wyxx());
546 hilet inv_col2 = ((t._col3.yxxx() * tmp_s5543) + (t._col3.zzyy() * tmp_s4221) + (t._col3.wwwz() * tmp_s3100)) * invdet;
547
548 // m.i03 := (i21 * -s5 + i22 * s4 + i23 * -s3) * invdet;
549 // m.i13 := (i20 * s5 + i22 * -s2 + i23 * s1) * invdet;
550 // m.i23 := (i20 * -s4 + i21 * s2 + i23 * -s0) * invdet;
551 // m.i33 := (i20 * s3 + i21 * -s1 + i22 * s0) * invdet;
552 tmp_s5543 = -tmp_s5543;
553 tmp_s4221 = -tmp_s4221;
554 tmp_s3100 = -tmp_s3100;
555 hilet inv_col3 = ((t._col2.yxxx() * tmp_s5543) + (t._col2.zzyy() * tmp_s4221) + (t._col2.wwwz() * tmp_s3100)) * invdet;
556
557 return {inv_col0, inv_col1, inv_col2, inv_col3};
558 }
559
560private:
561 f32x4 _col0;
562 f32x4 _col1;
563 f32x4 _col2;
564 f32x4 _col3;
565
566 template<char Axis>
567 [[nodiscard]] static constexpr f32x4 reflect_column() noexcept
568 {
569 if constexpr (Axis == 'x') {
570 return f32x4{1.0f, 0.0f, 0.0f, 0.0f};
571 } else if constexpr (Axis == 'X') {
572 return f32x4{-1.0f, 0.0f, 0.0f, 0.0f};
573 } else if constexpr (Axis == 'y') {
574 return f32x4{0.0f, 1.0f, 0.0f, 0.0f};
575 } else if constexpr (Axis == 'Y') {
576 return f32x4{0.0f, -1.0f, 0.0f, 0.0f};
577 } else if constexpr (Axis == 'z') {
578 return f32x4{0.0f, 0.0f, 1.0f, 0.0f};
579 } else if constexpr (Axis == 'Z') {
580 return f32x4{0.0f, 0.0f, -1.0f, 0.0f};
581 } else if constexpr (Axis == 'w') {
582 return f32x4{0.0f, 0.0f, 0.0f, 1.0f};
583 } else if constexpr (Axis == 'W') {
584 return f32x4{0.0f, 0.0f, 0.0f, -1.0f};
585 } else {
587 }
588 }
589};
590
591} // namespace geo
592
595using matrix2 = geo::matrix<2>;
596
599using matrix3 = geo::matrix<3>;
600
601}} // namespace hi::inline v1
602
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:308
#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
@ 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:595
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:26
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:18
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:206
friend constexpr matrix reflect(matrix const &rhs) noexcept
Reflect axis of a matrix.
Definition matrix.hpp:432
constexpr bool operator==(matrix< E > const &rhs) const noexcept
Compare two matrices potentially of different dimensions.
Definition matrix.hpp:444
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:97
constexpr float operator*(float const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:262
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:289
constexpr matrix operator~() const
Invert matrix.
Definition matrix.hpp:451
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:384
constexpr rectangle operator*(rectangle const &rhs) const noexcept
Transform a rectangle by the matrix.
Definition matrix.hpp:347
constexpr rectangle operator*(aarectangle const &rhs) const noexcept
Transform an axis-aligned rectangle by the matrix.
Definition matrix.hpp:336
friend constexpr f32x4 & get(matrix &rhs) noexcept
Get a column.
Definition matrix.hpp:227
constexpr corner_radii operator*(corner_radii const &rhs) const noexcept
Transform a float by the scaling factor of the matrix.
Definition matrix.hpp:276
constexpr matrix(matrix< E > const &other) noexcept
Copy-construct a matrix from a smaller matrix.
Definition matrix.hpp:162
constexpr circle operator*(circle const &rhs) const noexcept
Transform a circle by the matrix.
Definition matrix.hpp:367
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:135
constexpr auto operator*(point< float, E > const &rhs) const noexcept
Transform a point by the matrix.
Definition matrix.hpp:319
constexpr auto operator*(extent< float, E > const &rhs) const noexcept
Transform a extent by the matrix.
Definition matrix.hpp:305
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:252
constexpr line_segment operator*(line_segment const &rhs) const noexcept
Transform a line-segment by the matrix.
Definition matrix.hpp:377
friend constexpr matrix transpose(matrix const &rhs) noexcept
Matrix transpose.
Definition matrix.hpp:391
constexpr quad operator*(quad const &rhs) const noexcept
Transform a quad by the matrix.
Definition matrix.hpp:357
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)