NDEVR
API Documentation
Matrix.hpp
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: Matrix
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/BaseValues.h>
34#include <NDEVR/Vector.h>
35#include <NDEVR/Angle.h>
36#include <NDEVR/AngleDefinitions.h>
37namespace NDEVR
38{
42 template<uint01 t_cols, uint01 t_rows>
44
45 template<>
46 class MatrixInverter<1, 1>
47 {
48 public:
49 template<class t_type>
51 {
52 return value;
53 }
54 };
55
56 template<>
57 class MatrixInverter<2, 2>
58 {
59 public:
60 template<class t_type>
61 static constexpr t_type determinant(const Vector<2, Vector<2, t_type>>& value)
62 {
63 return value[0][0] * value[1][1] - value[1][0] * value[0][1];
64 }
65 template<class t_type>
66 static Vector<2, Vector<2, t_type>> invert(const Vector<2, Vector<2, t_type>>& value)
67 {
68 t_type OneOverDeterminant = static_cast<t_type>(1) / value.determinant();
69 return Vector<3, Vector<3, t_type>>(
70 +value[1][1] * OneOverDeterminant,
71 -value[0][1] * OneOverDeterminant,
72 -value[1][0] * OneOverDeterminant,
73 +value[0][0] * OneOverDeterminant).template getAs<t_type, 2, 2>();
74 }
75 };
76
77 template<>
78 class MatrixInverter<3, 3>
79 {
80 public:
81 template<class t_type>
82 static constexpr t_type determinant(const Vector<3, Vector<3, t_type>>& value)
83 {
84 return + value[0][0] * (value[1][1] * value[2][2] - value[2][1] * value[1][2])
85 - value[1][0] * (value[0][1] * value[2][2] - value[2][1] * value[0][2])
86 + value[2][0] * (value[0][1] * value[1][2] - value[1][1] * value[0][2]);
87 }
88 template<class t_type>
89 static Vector<3, Vector<3, t_type>> invert(const Vector<3, Vector<3, t_type>>& value)
90 {
91 t_type OneOverDeterminant = static_cast<t_type>(1) / determinant(value);
92 Vector<3, Vector<3, t_type>> Inverse;
93 Inverse[0][0] = +(value[1][1] * value[2][2] - value[2][1] * value[1][2]) * OneOverDeterminant;
94 Inverse[1][0] = -(value[1][0] * value[2][2] - value[2][0] * value[1][2]) * OneOverDeterminant;
95 Inverse[2][0] = +(value[1][0] * value[2][1] - value[2][0] * value[1][1]) * OneOverDeterminant;
96 Inverse[0][1] = -(value[0][1] * value[2][2] - value[2][1] * value[0][2]) * OneOverDeterminant;
97 Inverse[1][1] = +(value[0][0] * value[2][2] - value[2][0] * value[0][2]) * OneOverDeterminant;
98 Inverse[2][1] = -(value[0][0] * value[2][1] - value[2][0] * value[0][1]) * OneOverDeterminant;
99 Inverse[0][2] = +(value[0][1] * value[1][2] - value[1][1] * value[0][2]) * OneOverDeterminant;
100 Inverse[1][2] = -(value[0][0] * value[1][2] - value[1][0] * value[0][2]) * OneOverDeterminant;
101 Inverse[2][2] = +(value[0][0] * value[1][1] - value[1][0] * value[0][1]) * OneOverDeterminant;
102
103 return Inverse;
104 }
105 };
106 template<>
107 class MatrixInverter<4, 4>
108 {
109 public:
110 template<class t_type>
111 static Vector<4, Vector<4, t_type>> invert(const Vector<4, Vector<4, t_type>>& value)
112 {
113 t_type Coef00 = value[2][2] * value[3][3] - value[3][2] * value[2][3];
114 t_type Coef02 = value[1][2] * value[3][3] - value[3][2] * value[1][3];
115 t_type Coef03 = value[1][2] * value[2][3] - value[2][2] * value[1][3];
116
117 t_type Coef04 = value[2][1] * value[3][3] - value[3][1] * value[2][3];
118 t_type Coef06 = value[1][1] * value[3][3] - value[3][1] * value[1][3];
119 t_type Coef07 = value[1][1] * value[2][3] - value[2][1] * value[1][3];
120
121 t_type Coef08 = value[2][1] * value[3][2] - value[3][1] * value[2][2];
122 t_type Coef10 = value[1][1] * value[3][2] - value[3][1] * value[1][2];
123 t_type Coef11 = value[1][1] * value[2][2] - value[2][1] * value[1][2];
124
125 t_type Coef12 = value[2][0] * value[3][3] - value[3][0] * value[2][3];
126 t_type Coef14 = value[1][0] * value[3][3] - value[3][0] * value[1][3];
127 t_type Coef15 = value[1][0] * value[2][3] - value[2][0] * value[1][3];
128
129 t_type Coef16 = value[2][0] * value[3][2] - value[3][0] * value[2][2];
130 t_type Coef18 = value[1][0] * value[3][2] - value[3][0] * value[1][2];
131 t_type Coef19 = value[1][0] * value[2][2] - value[2][0] * value[1][2];
132
133 t_type Coef20 = value[2][0] * value[3][1] - value[3][0] * value[2][1];
134 t_type Coef22 = value[1][0] * value[3][1] - value[3][0] * value[1][1];
135 t_type Coef23 = value[1][0] * value[2][1] - value[2][0] * value[1][1];
136
137 Vector<4, t_type> Fac0(Coef00, Coef00, Coef02, Coef03);
138 Vector<4, t_type> Fac1(Coef04, Coef04, Coef06, Coef07);
139 Vector<4, t_type> Fac2(Coef08, Coef08, Coef10, Coef11);
140 Vector<4, t_type> Fac3(Coef12, Coef12, Coef14, Coef15);
141 Vector<4, t_type> Fac4(Coef16, Coef16, Coef18, Coef19);
142 Vector<4, t_type> Fac5(Coef20, Coef20, Coef22, Coef23);
143
144 Vector<4, t_type> Vec0(value[1][0], value[0][0], value[0][0], value[0][0]);
145 Vector<4, t_type> Vec1(value[1][1], value[0][1], value[0][1], value[0][1]);
146 Vector<4, t_type> Vec2(value[1][2], value[0][2], value[0][2], value[0][2]);
147 Vector<4, t_type> Vec3(value[1][3], value[0][3], value[0][3], value[0][3]);
148
149 Vector<4, t_type> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);
150 Vector<4, t_type> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);
151 Vector<4, t_type> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);
152 Vector<4, t_type> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);
153
154 Vector<4, t_type> SignA(+1, -1, +1, -1);
155 Vector<4, t_type> SignB(-1, +1, -1, +1);
156
157 Vector<4, t_type> Row0(Inv0[0] * SignA[0], Inv1[0] * SignB[0], Inv2[0] * SignA[0], Inv3[0] * SignB[0]);
158
159 Vector<4, t_type> Dot0(Vector<4, t_type>(value[0][0], value[0][1], value[0][2], value[0][3]) * Row0);
160 t_type Dot1 = Dot0.sum();
161
162 lib_assert(std::abs(Dot1) > 0.0, "bad matrix inverse");
163 t_type OneOverDeterminant = static_cast<t_type>(1) / Dot1;
164 Inv0 = Inv0 * SignA * OneOverDeterminant;
165 Inv1 = Inv1 * SignB * OneOverDeterminant;
166 Inv2 = Inv2 * SignA * OneOverDeterminant;
167 Inv3 = Inv3 * SignB * OneOverDeterminant;
168 return Vector<4, Vector<4, t_type>>(
169 { Inv0[0], Inv0[1], Inv0[2], Inv0[3] }
170 , { Inv1[0], Inv1[1], Inv1[2], Inv1[3] }
171 , { Inv2[0], Inv2[1], Inv2[2], Inv2[3]}
172 , { Inv3[0], Inv3[1], Inv3[2], Inv3[3]});
173 }
174 };
180 template<class t_type, uint01 t_row_dims = 4, uint01 t_col_dims = 4>
181 class Matrix : public Vector<t_row_dims, Vector<t_col_dims, t_type>>
182 {
183 public:
184 constexpr Matrix()
185 : Vector<t_row_dims, Vector<t_col_dims, t_type>>()
186 {}
187 constexpr explicit Matrix(const t_type diagonal)
188 : Vector<t_row_dims, Vector<t_col_dims, t_type>>(Vector<t_col_dims, t_type>(0))
189 {
190 for (uint01 i = 0; i < getMin(t_row_dims, t_col_dims); i++)
191 {
192 (*this)[i][i] = diagonal;
193 }
194 }
195
196 constexpr Matrix(
197 const t_type n00, const t_type n10,
198 const t_type n01, const t_type n11)
199 : Vector<2, Vector<2, t_type>>(
200 Vector<2, t_type>(n00, n10)
201 , Vector<2, t_type>(n01, n11))
202 {
203 static_assert(t_row_dims == 2 && t_col_dims == 2, "Bad Transform Constructor, should be 2x2");
204 }
205 constexpr Matrix(
206 const t_type n00, const t_type n10, const t_type n20,
207 const t_type n01, const t_type n11, const t_type n21,
208 const t_type n02, const t_type n12, const t_type n22)
209 : Vector<3, Vector<3, t_type>>(
210 Vector<3, t_type>(n00, n10, n20)
211 , Vector<3, t_type>(n01, n11, n21)
212 , Vector<3, t_type>(n02, n12, n22))
213 {
214 static_assert(t_row_dims == 3 && t_col_dims == 3, "Bad Transform Constructor, should be 3x3");
215 }
216 constexpr Matrix(
217 const t_type n00, const t_type n10, const t_type n20, const t_type n30,
218 const t_type n01, const t_type n11, const t_type n21, const t_type n31,
219 const t_type n02, const t_type n12, const t_type n22, const t_type n32,
220 const t_type n03, const t_type n13, const t_type n23, const t_type n33)
221 : Vector<4, Vector<4, t_type>>(
222 Vector<4, t_type>(n00, n10, n20, n30)
223 , Vector<4, t_type>(n01, n11, n21, n31)
224 , Vector<4, t_type>(n02, n12, n22, n32)
225 , Vector<4, t_type>(n03, n13, n23, n33))
226 {
227 static_assert(t_row_dims == 4 && t_col_dims == 4, "Bad Transform Constructor, should be 4x4");
228 }
229 template<class t_angle_type>
230 constexpr Matrix(const Vector<t_row_dims - 1, t_type>& offset, const Vector<3, Angle<t_angle_type>>& orientation, const Vector<t_row_dims - 1, t_type>& scale)
231 : Vector<t_row_dims, Vector<t_col_dims, t_type>>(Vector<t_col_dims, t_type>(0))
232 {
233 //rotate the matrix
234 *this = RotationMatrix(orientation);
235 //Offset the matrix (Note will not overlap with rotation, so order independent)
236 (*this)[t_row_dims - 1][0] = offset[X];
237 if constexpr (t_col_dims >= 2)
238 (*this)[t_row_dims - 1][1] = offset[Y];
239 if constexpr (t_col_dims >= 3)
240 (*this)[t_row_dims - 1][2] = offset[Z];
241 //scale the matrix
242 *this = this->scale(scale);
243 }
244 constexpr Matrix(const Vector<t_row_dims* t_col_dims, t_type>& vector)
245 {
246 memcpy(this, &vector, sizeof(Vector<t_row_dims* t_col_dims, t_type>));
247 }
248 constexpr Matrix(const Vector<t_row_dims, Vector<t_col_dims, t_type>>& vector)
249 : Vector<t_row_dims, Vector<t_col_dims, t_type>>(vector)
250 {}
251 constexpr Matrix(const Matrix& mat) = default;
252
253 template<class t_new_type>
254 [[nodiscard]] constexpr decltype(auto) as() const
255 {
256 if constexpr (std::is_same_v<t_new_type, t_type>)
257 {
258 return static_cast<const Matrix<t_type>&>(*this);
259 }
260 else
261 {
262 Matrix<t_new_type> mat;
263 for (uint01 row = 0; row < t_row_dims; ++row)
264 {
265 for (uint01 col = 0; col < t_col_dims; ++col)
266 {
267 mat[row][col] = cast<t_new_type>((*this)[row][col]);
268 }
269 }
270 return mat;
271 }
272 }
273 template<class t_new_type, uint01 t_new_row_dims, uint01 t_new_col_dims>
274 [[nodiscard]] constexpr decltype(auto) as() const
275 {
276 if constexpr (t_new_row_dims == t_row_dims && t_new_col_dims == t_col_dims && std::is_same_v<t_new_type, t_type>)
277 {
278 return static_cast<const Matrix<t_type>&>(*this);
279 }
280 else
281 {
282 Matrix<t_new_type, t_new_row_dims, t_new_col_dims> mat;
283 for (uint01 row = 0; row < getMin(t_row_dims, t_new_row_dims); ++row)
284 {
285 for (uint01 col = 0; col < getMin(t_col_dims, t_new_col_dims); ++col)
286 {
287 mat[row][col] = cast<t_new_type>((*this)[row][col]);
288 }
289 }
290 return mat;
291 }
292 }
293 template<uint01 t_i0, uint01 t_i1, uint01 t_j0, uint01 t_j1>
294 [[nodiscard]] constexpr Matrix<t_type, t_i1 - t_i0 + 1, t_j1 - t_j0 + 1> subMatrix() const
295 {
296 Matrix<t_type, t_i1 - t_i0 + 1, t_j1 - t_j0 + 1> mat;
297 for (uint01 i = t_i0; i <= t_i1; i++)
298 {
299 for (uint01 j = t_j0; j <= t_j1; j++)
300 mat[i - t_i0][j - t_j0] = (*this)[i][j];
301 }
302 return mat;
303 }
304 template<uint01 t_j0, uint01 t_j1, uint01 t_i_size>
305 [[nodiscard]] constexpr Matrix<t_type, t_i_size, t_j1 - t_j0 + 1> subMatrix(const Vector<t_i_size, uint01>& r) const
306 {
307 Matrix<t_type, t_i_size, t_j1 - t_j0 + 1> mat;
308 for (uint01 i = 0; i < t_i_size; i++)
309 {
310 for (uint01 j = t_j0; j <= t_j1; j++)
311 {
312 mat[i][j - t_j0] = (*this)[r[i]][j];
313 }
314 }
315 return mat;
316 }
317
318 [[nodiscard]] static constexpr Matrix<t_type> OffsetMatrix(const Vector<3, t_type>& translation)
319 {
320 Matrix<t_type> mat(1);
321 mat[t_row_dims - 1][0] = translation[X];
322 if constexpr (t_col_dims >= 2)
323 mat[t_row_dims - 1][1] = translation[Y];
324 if constexpr (t_col_dims >= 3)
325 mat[t_row_dims - 1][2] = translation[Z];
326 return mat;
327 }
328 [[nodiscard]] static constexpr Matrix<t_type> ScalerMatrix(t_type scale)
329 {
330 Matrix<t_type> mat(1);
331 mat[0][0] = scale;
332 if constexpr (t_col_dims >= 2 && t_row_dims >= 2)
333 mat[1][1] = scale;
334 if constexpr (t_col_dims >= 3 && t_row_dims >= 3)
335 mat[2][2] = scale;
336 return mat;
337 }
338 [[nodiscard]] static constexpr Matrix<t_type> ScalerMatrix(const Vector<2, t_type>& scale)
339 {
340 Matrix mat(1);
341 mat[0][0] = scale[X];
342 if constexpr (t_col_dims >= 2 && t_row_dims >= 2)
343 mat[1][1] = scale[Y];
344 return mat;
345 }
346 [[nodiscard]] static constexpr Matrix<t_type> ScalerMatrix(const Vector<3, t_type>& scale)
347 {
348 Matrix<t_type> mat(1);
349 mat[0][0] = scale[X];
350 if constexpr (t_col_dims >= 2 && t_row_dims >= 2)
351 mat[1][1] = scale[Y];
352 if constexpr (t_col_dims >= 3 && t_row_dims >= 3)
353 mat[2][2] = scale[Z];
354 return mat;
355 }
356
357 static constexpr Matrix<t_type> SwapAxes(uint01 a, uint01 b)
358 {
359 Matrix<t_type> m = Matrix<t_type>(cast<t_type>(1));
360 static_assert(t_row_dims == t_col_dims, "needs to be same size");
361 lib_assert(a < t_row_dims && b < t_col_dims, "dims too high for matrix");
362 if (a == b)
363 return m;
364 m[a][a] = cast<t_type>(0);
365 m[b][b] = cast<t_type>(0);
366 m[a][b] = cast<t_type>(1);
367 m[b][a] = cast<t_type>(1);
368 return m;
369 }
370 template<class t_angle_type>
371 static constexpr Matrix<t_type> RotationMatrix(const Vector<3, Angle<t_angle_type>>& orientation)
372 {
373 t_type ch = t_type(1);
374 t_type sh = t_type(0);
375 t_type ca = t_type(1);
376 t_type sa = t_type(0);
377 t_type cb = t_type(1);
378 t_type sb = t_type(0);
379 if (IsValid(orientation[YAW]))
380 {
381 ch = cos(orientation[YAW]);
382 sh = sin(orientation[YAW]);
383 }
384 if (IsValid(orientation[PITCH]))
385 {
386 ca = cos(orientation[PITCH]);
387 sa = sin(orientation[PITCH]);
388 }
389 if (IsValid(orientation[ROLL]))
390 {
391 cb = cos(orientation[ROLL]);
392 sb = sin(orientation[ROLL]);
393 }
394
395 t_type m00 = ch * ca;
396 t_type m01 = ch * sa * sb - sh * cb;
397 t_type m02 = ch * sa * cb + sh * sb;
398 t_type m10 = sh * ca;
399 t_type m11 = sh * sa * sb + ch * cb;
400 t_type m12 = sh * sa * cb - ch * sb;
401 t_type m20 = -sa;
402 t_type m21 = ca * sb;
403 t_type m22 = ca * cb;
404 return Matrix<t_type>(
405 m00, m10, m20, 0
406 , m01, m11, m21, 0
407 , m02, m12, m22, 0
408 , 0, 0, 0, 1);
409 }
410 template<class t_angle_type>
411 static constexpr Matrix<t_type> RotationMatrix(const Angle<t_angle_type>& phi, const Vector<3, t_type>& axis)
412 {
413 const t_type cos_val = cast<t_type>(cos(phi));
414 const t_type sin_val = cast<t_type>(sin(phi));
415 const t_type x = axis[X];
416 const t_type y = axis[Y];
417 const t_type z = axis[Z];
418 return Matrix<t_type>(
419 (cos_val + x * x * (1 - cos_val)), (z * sin_val + y * x * (1 - cos_val)), (-y * sin_val + z * x * (1 - cos_val)), 0
420 , (-z * sin_val + x * y * (1 - cos_val)), (cos_val + y * y * (1 - cos_val)), (x * sin_val + z * y * (1 - cos_val)), 0
421 , (y * sin_val + x * z * (1 - cos_val)), (-x * sin_val + y * z * (1 - cos_val)), (cos_val + z * z * (1 - cos_val)), 0
422 , 0, 0, 0, 1);
423 }
424 [[nodiscard]] constexpr t_type determinant() const
425 {
426 static_assert(t_col_dims == t_row_dims, "Rows and columns must be equal for determinate");
427 switch (t_col_dims)
428 {
429 case 1:
430 return (*this)[0][0];
431 case 2:
432 return (*this)[0][0] * (*this)[1][1] - (*this)[1][0] * (*this)[0][1];
433 case 3:
434 return
435 +(*this)[0][0] * ((*this)[1][1] * (*this)[2][2] - (*this)[2][1] * (*this)[1][2])
436 - (*this)[1][0] * ((*this)[0][1] * (*this)[2][2] - (*this)[2][1] * (*this)[0][2])
437 + (*this)[2][0] * ((*this)[0][1] * (*this)[1][2] - (*this)[1][1] * (*this)[0][2]);
438 case 4:
439 {
440 t_type SubFactor00 = (*this)[2][2] * (*this)[3][3] - (*this)[3][2] * (*this)[2][3];
441 t_type SubFactor01 = (*this)[2][1] * (*this)[3][3] - (*this)[3][1] * (*this)[2][3];
442 t_type SubFactor02 = (*this)[2][1] * (*this)[3][2] - (*this)[3][1] * (*this)[2][2];
443 t_type SubFactor03 = (*this)[2][0] * (*this)[3][3] - (*this)[3][0] * (*this)[2][3];
444 t_type SubFactor04 = (*this)[2][0] * (*this)[3][2] - (*this)[3][0] * (*this)[2][2];
445 t_type SubFactor05 = (*this)[2][0] * (*this)[3][1] - (*this)[3][0] * (*this)[2][1];
446 Vector<4, t_type> DetCof(
447 +((*this)[1][1] * SubFactor00 - (*this)[1][2] * SubFactor01 + (*this)[1][3] * SubFactor02),
448 -((*this)[1][0] * SubFactor00 - (*this)[1][2] * SubFactor03 + (*this)[1][3] * SubFactor04),
449 +((*this)[1][0] * SubFactor01 - (*this)[1][1] * SubFactor03 + (*this)[1][3] * SubFactor05),
450 -((*this)[1][0] * SubFactor02 - (*this)[1][1] * SubFactor04 + (*this)[1][2] * SubFactor05));
451 return
452 (*this)[0][0] * DetCof[0] + (*this)[0][1] * DetCof[1] +
453 (*this)[0][2] * DetCof[2] + (*this)[0][3] * DetCof[3];
454 }
455 default:
456 return Constant<t_type>::Invalid;
457 }
458 }
459 [[nodiscard]] constexpr Vector<3, t_type> decomposeScale() const
460 {
461 static_assert(t_col_dims >= 4 && t_row_dims >= 4, "Cannot decompose lower dimension matrix");
462 Vector<3, t_type> scaling;
463 Vector<3, t_type> rows[3];
464 for (uint01 i = 0; i < 3; i++)
465 {
466 rows[i] = (*this)[i].template as<3, t_type>();
467 scaling[i] = rows[i].template magnitude<t_type>();
468 }
469 scaling = quantize(scaling, Vector<3, t_type>(.000001));
470 const Vector<3, t_type> temp_z = cross(rows[0], rows[1]);
471 if (dot(temp_z, rows[2]) < 0)
472 {
473 scaling[X] = -scaling[X];
474 rows[0] = -rows[0];
475 }
476 return scaling;
477 }
478 [[nodiscard]] constexpr Vector<3, t_type> decomposeOffset() const
479 {
480 static_assert(t_col_dims >= 3 && t_row_dims >= 3, "Cannot decompose lower dimension matrix");
481 Vector<3, t_type> offset;
482 offset[X] = (*this)[3][0];
483 offset[Y] = (*this)[3][1];
484 offset[Z] = (*this)[3][2];
485 return offset;
486 }
487 /* [[nodiscard]] constexpr Vector<3, Angle> decomposeRotation() const
488 {
489 return decomposeRotation<sint04>();
490 }*/
491 template<class t_angle_type>
492 [[nodiscard]] constexpr Vector<3, Angle<t_angle_type>> decomposeRotation() const
493 {
494 static_assert(t_col_dims >= 3 && t_row_dims >= 3, "Cannot decompose lower dimension matrix");
495 Vector<3, Angle<t_angle_type>> rotation;
496 Vector<3, t_type> rows[3];
497 for (uint01 i = 0; i < 3; i++)
498 {
499 rows[i] = (*this)[i].template as<3, t_type>();
500 }
501 const Vector<3, t_type> temp_z = cross(rows[0], rows[1]);
502 if (dot(temp_z, rows[2]) < 0)
503 {
504 rows[0] = -rows[0];
505 }
506 for (uint04 i = 0; i < 3; i++)
507 {
508 rows[i] = rows[i].template normalized<t_type>();
509 }
510 t_type sy = sqrt(rows[0][0] * rows[0][0] + rows[0][1] * rows[0][1]);
511
512 rotation[PITCH] = Angle<t_angle_type>::atan2(-rows[0][2], sy);
513 if (sy > cast<t_type>(1E-6))
514 {
515 rotation[ROLL] = Angle<t_angle_type>::atan2(rows[1][2], rows[2][2]);
516 rotation[YAW] = Angle<t_angle_type>::atan2(rows[0][1], rows[0][0]);
517 }
518 else
519 {
520 rotation[ROLL] = Angle<t_angle_type>::atan2(-rows[2][1], rows[1][1]);
521 rotation[YAW] = Angle<t_angle_type>(RADIANS, 0.0f);
522 }
523 return rotation;
524 }
525 template<class t_angle_type>
526 constexpr Angle<t_angle_type> angleAbout(const Vector<3, t_type>& axis_unit) const
527 {
528 auto& R = *this;
529 const t_type sin_phi =
530 ((R[2][1] - R[1][2]) * axis_unit[0] +
531 (R[0][2] - R[2][0]) * axis_unit[1] +
532 (R[1][0] - R[0][1]) * axis_unit[2]) * static_cast<t_type>(0.5);
533
534 // Project R*a onto a to extract cos component:
535 Vector<3, t_type> Ra{
536 R[0][0] * axis_unit[0] + R[0][1] * axis_unit[1] + R[0][2] * axis_unit[2],
537 R[1][0] * axis_unit[0] + R[1][1] * axis_unit[1] + R[1][2] * axis_unit[2],
538 R[2][0] * axis_unit[0] + R[2][1] * axis_unit[1] + R[2][2] * axis_unit[2]
539 };
540
541 const t_type cos_phi = dot(axis_unit, Ra);
542
543 return Angle<t_angle_type>::atan2(sin_phi, cos_phi);
544 }
545 [[nodiscard]] constexpr Vector<4, t_type> decomposeRotationQuaternion() const
546 {
547 t_type trace = (*this)[0][0] + (*this)[1][1] + (*this)[2][2];
548 Vector<4, t_type> temp;
549
550 if (trace > t_type(0.0))
551 {
552 t_type s = sqrt(trace + t_type(1.0));
553 temp[3] = (s * t_type(0.5));
554 s = t_type(0.5) / s;
555
556 temp[0] = (((*this)[2][1] - (*this)[1][2]) * s);
557 temp[1] = (((*this)[0][2] - (*this)[2][0]) * s);
558 temp[2] = (((*this)[1][0] - (*this)[0][1]) * s);
559 }
560 else
561 {
562 uint01 i = (*this)[0][0] < (*this)[1][1] ?
563 ((*this)[1][1] < (*this)[2][2] ? 2U : 1U) :
564 ((*this)[0][0] < (*this)[2][2] ? 2U : 0U);
565 uint01 j = (i + 1) % 3;
566 uint01 k = (i + 2) % 3;
567
568 t_type s = t_type((*this)[i][i] - (*this)[j][j] - (*this)[k][k] + t_type(1.0));
569 temp[i] = s * t_type(0.5);
570 s = t_type(0.5) / s;
571
572 temp[3] = ((*this)[k][j] - (*this)[j][k]) * s;
573 temp[j] = ((*this)[j][i] + (*this)[i][j]) * s;
574 temp[k] = ((*this)[k][i] + (*this)[i][k]) * s;
575 }
576 return temp;
577 }
578 template<class t_angle_type>
579 constexpr void decompose(Vector<3, t_type>& scaling, Vector<3, Angle<t_angle_type>>& rotation, Vector<3, t_type>& position) const
580 {
581 static_assert(t_col_dims >= 4 && t_row_dims >= 4, "Cannot decompose lower dimension matrix");
582
583 position[X] = (*this)[3][0];
584 position[Y] = (*this)[3][1];
585 position[Z] = (*this)[3][2];
586
587 Vector<3, t_type> rows[3];
588 for (uint01 i = 0; i < 3; i++)
589 {
590 rows[i] = (*this)[i].template as<3, t_type>();
591 scaling[i] = rows[i].template magnitude<t_type>();
592 }
593 scaling = quantize(scaling, Vector<3, t_type>(.000001));
594 const Vector<3, t_type> temp_z = cross(rows[0], rows[1]);
595 if (dot(temp_z, rows[2]) < 0)
596 {
597 scaling[X] = -scaling[X];
598 rows[0] = -rows[0];
599 }
600 for (uint04 i = 0; i < 3; i++)
601 {
602 rows[i] = rows[i].template normalized<t_type>();
603 }
604 t_type sy = sqrt(rows[0][0] * rows[0][0] + rows[0][1] * rows[0][1]);
605
606 rotation[PITCH] = Angle<t_angle_type>::atan2(-rows[0][2], sy);
607 if (sy > cast<t_type>(1E-6))
608 {
609 rotation[ROLL] = Angle<t_angle_type>::atan2(rows[1][2], rows[2][2]);
610 rotation[YAW] = Angle<t_angle_type>::atan2(rows[0][1], rows[0][0]);
611 }
612 else
613 {
614 rotation[ROLL] = Angle<t_angle_type>::atan2(-rows[2][1], rows[1][1]);
615 rotation[YAW] = Angle<t_angle_type>(RADIANS, 0.0f);
616 }
617 }
618 [[nodiscard]] constexpr Matrix offset(const Vector<2, t_type>& translation) const
619 {
620 Matrix mat(1);
621 mat[t_row_dims - 1][0] = translation[X];
622 if constexpr (t_col_dims >= 2)
623 mat[t_row_dims - 1][1] = translation[Y];
624 if constexpr (t_col_dims >= 3)
625 mat[t_row_dims - 1][2] = 0;
626 return (*this) * mat;
627
628 }
629
630
631 [[nodiscard]] constexpr Matrix offset(const Vector<3, t_type>& translation) const
632 {
633 return (*this) * Matrix::OffsetMatrix(translation);
634 }
635
636 [[nodiscard]] constexpr inline Matrix scale(t_type scale) const
637 {
638 return (*this) * Matrix::ScalerMatrix(scale);
639 }
640
641
642 [[nodiscard]] constexpr Matrix scale(const Vector<2, t_type>& scale) const
643 {
644 return (*this) * Matrix::ScalerMatrix(scale);
645 }
646
647
648 [[nodiscard]] constexpr Matrix scale(const Vector<3, t_type>& scale) const
649 {
650 return (*this) * Matrix::ScalerMatrix(scale);
651 }
652
653 Matrix& correctZeroScale(t_type new_value = 1e-6, t_type epsilon = 1e-9)
654 {
655 for (uint01 i = 0; i < getMin(t_row_dims, t_col_dims); i++)
656 {
657 if (std::abs((*this)[i][i]) < epsilon)
658 (*this)[i][i] = new_value;
659 }
660 return *this;
661 }
662
663 [[nodiscard]] constexpr Matrix scale(const Vector<3, t_type>& direction, t_type scale) const
664 {
665 Matrix mat(1);
666 mat[0][0] += (scale - 1) * direction[X] * direction[X];
667 mat[0][1] = (scale - 1) * direction[Y] * direction[X];
668 mat[0][2] = (scale - 1) * direction[Z] * direction[X];
669
670 mat[1][0] = (scale - 1) * direction[X] * direction[Y];
671 mat[1][1] += (scale - 1) * direction[Y] * direction[Y];
672 mat[1][2] = (scale - 1) * direction[Z] * direction[Y];
673
674 mat[2][0] = (scale - 1) * direction[X] * direction[Z];
675 mat[2][1] = (scale - 1) * direction[Y] * direction[Z];
676 mat[2][2] += (scale - 1) * direction[Z] * direction[Z];
677
678 return (*this) * mat;
679 }
680 template<class t_angle_type>
681 [[nodiscard]] constexpr Matrix rotate(const Vector<3, Angle<t_angle_type>>& orientation) const
682 {
683 return *this * Matrix<t_type>::RotationMatrix(orientation);
684 }
685 template<class t_angle_type>
686 [[nodiscard]] constexpr Matrix<t_type> rotate(const Angle<t_angle_type>& phi, const Vector<3, t_type>& axis) const
687 {
688 return *this * RotationMatrix(phi, axis);
689 }
690 [[nodiscard]] constexpr Matrix shear(t_type dx, t_type dy) const
691 {
692 Matrix mat(1);
693 mat[0][1] = dx;
694 mat[1][0] = dy;
695 return (*this) * mat;
696 }
697 [[nodiscard]] constexpr Matrix<t_type, t_col_dims, t_row_dims> transpose() const
698 {
699 Matrix<t_type, t_col_dims, t_row_dims> mat;
700 for (uint01 row = 0; row < t_row_dims; row++)
701 for (uint01 col = 0; col < t_col_dims; col++)
702 mat[col][row] = (*this)[row][col];
703 return mat;
704 }
705
706 template<uint01 t_cols = t_col_dims, uint01 t_rows = t_row_dims>
707 [[nodiscard]] inline Matrix<t_type, t_cols, t_rows> invert() const
708 {
709 return Matrix<t_type, t_cols, t_rows>(MatrixInverter<t_cols, t_rows>::template invert<t_type>(*this));
710 }
711
712 [[nodiscard]] inline t_type* begin()
713 {
714 return &(*this)[0][0];
715 }
716
717 [[nodiscard]] inline const t_type* begin() const
718 {
719 return &(*this)[0][0];
720 }
721 [[nodiscard]] inline const t_type& inlineGet(uint01 val) const
722 {
723 return (&(*this)[0][0])[val];
724 }
725 [[nodiscard]] inline t_type& inlineGet(uint01 val)
726 {
727 return (&(*this)[0][0])[val];
728 }
729 public:
730 [[nodiscard]] Matrix operator*(const Matrix& right) const
731 {
732 Matrix<t_type, t_row_dims, t_col_dims> product;
733 for(uint01 col = 0; col < t_col_dims; ++col)
734 {
735 for(uint01 row = 0; row < t_row_dims; ++row)
736 {
737 for(uint01 i = 0; i < t_row_dims; ++i)
738 {
739 product[row][col] += ((*this)[i][col] * right[row][i]);
740 }
741 }
742 }
743 return product;
744 }
745 inline Matrix& operator=(const Matrix& right)
746 {
747 for(uint01 col = 0; col < t_col_dims; ++col)
748 {
749 for(uint01 row = 0; row < t_row_dims; ++row)
750 {
751 (*this)[row][col] = right[row][col];
752 }
753 }
754 return *this;
755 }
756 inline Matrix& operator*=(const Matrix& right)
757 {
758 *this = *this * right;
759 return *this;
760 }
761 };
762
772 template<class t_type, uint01 t_row_dims, uint01 t_col_dims>
779
796
797 template<class t_type, uint01 t_row_dims, uint01 t_col_dims>
798 static constexpr bool IsInvalid(const Matrix<t_type, t_row_dims, t_col_dims>& value)
799 {
800 for (uint01 dim_a = 0; dim_a < t_col_dims; ++dim_a)
801 {
802 for (uint01 dim_b = 0; dim_b < t_row_dims; ++dim_b)
803 {
804 if (IsInvalid(value[dim_b][dim_a]))
805 return true;
806 }
807 }
808 return false;
809 }
810 template<class t_type, uint01 t_row_dims, uint01 t_col_dims>
811 static constexpr bool IsValid(const Matrix<t_type, t_row_dims, t_col_dims>& value)
812 {
813 for (uint01 dim_a = 0; dim_a < t_col_dims; ++dim_a)
814 {
815 for (uint01 dim_b = 0; dim_b < t_row_dims; ++dim_b)
816 {
817 if (IsInvalid(value[dim_b][dim_a]))
818 return false;
819 }
820 }
821 return true;
822 }
823}
824
Stores an angle in an optimized internal format with support for efficient trigonometric operations.
Definition Angle.h:83
static Angle atan2(t_value_type x, t_value_type y)
measures the counterclockwise angle between the positive x-axis and the point (x, y)
Definition Angle.h:300
Templated logic for inverting a matrix based on the number of rows and columns.
Definition Matrix.hpp:43
Templated logic for doing matrix multiplication.
Definition Matrix.hpp:182
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
Definition Vector.hpp:62
constexpr t_type product() const
Definition Vector.hpp:510
constexpr decltype(auto) as() const
Definition Vector.hpp:301
constexpr Vector< t_dims, t_norm_type > normalized(Vector< t_dims, t_norm_type > value_if_nan=Constant< Vector< t_dims, t_norm_type > >::Invalid) const
Definition Vector.hpp:486
constexpr t_magnitude_type magnitude() const
Definition Vector.hpp:470
The primary namespace for the NDEVR SDK.
@ YAW
Rotation about the vertical axis (Z).
Definition Angle.h:47
@ PITCH
Rotation about the lateral axis (Y).
Definition Angle.h:46
@ ROLL
Rotation about the forward axis (X).
Definition Angle.h:45
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
constexpr Vector< t_dims, Angle< t_angle_type > > quantize(const Vector< t_dims, Angle< t_angle_type > > &value, Angle< t_angle_type > d=Angle< t_angle_type >(DEGREES, 1.0))
Quantizes a Vector of Angles to the nearest multiple of a given step size.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
@ RADIANS
Angle measured in radians (0 to 2*PI for a full circle).
Definition Angle.h:57
constexpr Vector< 1, t_type > cross(const Vector< 1, t_type > &, const Vector< 1, t_type > &)
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388
t_type sqrt(const t_type &value)
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type sin(const Angle< t_type > &angle)
Performs optimized sine operation on the given angle using pre-computed lookup table for optimal spee...
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type cos(const Angle< t_type > &angle)
Performs optimized cosine operation on the given angle using pre-computed lookup table for optimal sp...
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...