blob: 8edf5f82e393a3f0b16ab42b91335a0515aafcec [file] [log] [blame]
Mathias Agopian595ea772013-08-21 23:10:41 -07001/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Romain Guy5d4bae72016-11-08 09:49:25 -080017#ifndef UI_TMATHELPERS_H_
18#define UI_TMATHELPERS_H_
Mathias Agopian595ea772013-08-21 23:10:41 -070019
Romain Guy5d4bae72016-11-08 09:49:25 -080020#include <math.h>
Mathias Agopian595ea772013-08-21 23:10:41 -070021#include <stdint.h>
22#include <sys/types.h>
Romain Guy5d4bae72016-11-08 09:49:25 -080023
24#include <cmath>
25#include <exception>
26#include <iomanip>
27#include <stdexcept>
28
29#include <ui/quat.h>
30#include <ui/TVecHelpers.h>
31
32#include <utils/String8.h>
33
34#ifdef __cplusplus
35# define LIKELY( exp ) (__builtin_expect( !!(exp), true ))
36# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
37#else
38# define LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
39# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
40#endif
Mathias Agopian595ea772013-08-21 23:10:41 -070041
42#define PURE __attribute__((pure))
43
Romain Guycaf2ca42016-11-10 11:45:58 -080044#if __cplusplus >= 201402L
45#define CONSTEXPR constexpr
46#else
47#define CONSTEXPR
48#endif
49
Mathias Agopian595ea772013-08-21 23:10:41 -070050namespace android {
Romain Guy5d4bae72016-11-08 09:49:25 -080051namespace details {
Mathias Agopian595ea772013-08-21 23:10:41 -070052// -------------------------------------------------------------------------------------
53
54/*
55 * No user serviceable parts here.
56 *
57 * Don't use this file directly, instead include ui/mat*.h
58 */
59
60
61/*
62 * Matrix utilities
63 */
64
65namespace matrix {
66
Romain Guy5d4bae72016-11-08 09:49:25 -080067inline constexpr int transpose(int v) { return v; }
68inline constexpr float transpose(float v) { return v; }
69inline constexpr double transpose(double v) { return v; }
Mathias Agopian595ea772013-08-21 23:10:41 -070070
Romain Guy5d4bae72016-11-08 09:49:25 -080071inline constexpr int trace(int v) { return v; }
72inline constexpr float trace(float v) { return v; }
73inline constexpr double trace(double v) { return v; }
Mathias Agopian595ea772013-08-21 23:10:41 -070074
Romain Guy5d4bae72016-11-08 09:49:25 -080075/*
76 * Matrix inversion
77 */
Mathias Agopian595ea772013-08-21 23:10:41 -070078template<typename MATRIX>
Romain Guy5d4bae72016-11-08 09:49:25 -080079MATRIX PURE gaussJordanInverse(const MATRIX& src) {
80 typedef typename MATRIX::value_type T;
81 static constexpr unsigned int N = MATRIX::NUM_ROWS;
Mathias Agopian595ea772013-08-21 23:10:41 -070082 MATRIX tmp(src);
Romain Guy5d4bae72016-11-08 09:49:25 -080083 MATRIX inverted(1);
Mathias Agopian595ea772013-08-21 23:10:41 -070084
Romain Guy5d4bae72016-11-08 09:49:25 -080085 for (size_t i = 0; i < N; ++i) {
86 // look for largest element in i'th column
87 size_t swap = i;
88 T t = std::abs(tmp[i][i]);
89 for (size_t j = i + 1; j < N; ++j) {
90 const T t2 = std::abs(tmp[j][i]);
91 if (t2 > t) {
Mathias Agopian595ea772013-08-21 23:10:41 -070092 swap = j;
Romain Guy5d4bae72016-11-08 09:49:25 -080093 t = t2;
Mathias Agopian595ea772013-08-21 23:10:41 -070094 }
95 }
96
97 if (swap != i) {
Romain Guy5d4bae72016-11-08 09:49:25 -080098 // swap columns.
99 std::swap(tmp[i], tmp[swap]);
100 std::swap(inverted[i], inverted[swap]);
Mathias Agopian595ea772013-08-21 23:10:41 -0700101 }
102
Romain Guy5d4bae72016-11-08 09:49:25 -0800103 const T denom(tmp[i][i]);
104 for (size_t k = 0; k < N; ++k) {
105 tmp[i][k] /= denom;
106 inverted[i][k] /= denom;
Mathias Agopian595ea772013-08-21 23:10:41 -0700107 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800108
109 // Factor out the lower triangle
110 for (size_t j = 0; j < N; ++j) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700111 if (j != i) {
Romain Guycaf2ca42016-11-10 11:45:58 -0800112 const T d = tmp[j][i];
Romain Guy5d4bae72016-11-08 09:49:25 -0800113 for (size_t k = 0; k < N; ++k) {
Romain Guycaf2ca42016-11-10 11:45:58 -0800114 tmp[j][k] -= tmp[i][k] * d;
115 inverted[j][k] -= inverted[i][k] * d;
Mathias Agopian595ea772013-08-21 23:10:41 -0700116 }
117 }
118 }
119 }
Romain Guy5d4bae72016-11-08 09:49:25 -0800120
121 return inverted;
122}
123
124
125//------------------------------------------------------------------------------
126// 2x2 matrix inverse is easy.
127template <typename MATRIX>
Romain Guycaf2ca42016-11-10 11:45:58 -0800128CONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800129 typedef typename MATRIX::value_type T;
130
131 // Assuming the input matrix is:
132 // | a b |
133 // | c d |
134 //
135 // The analytic inverse is
136 // | d -b |
137 // | -c a | / (a d - b c)
138 //
139 // Importantly, our matrices are column-major!
140
141 MATRIX inverted(MATRIX::NO_INIT);
142
143 const T a = x[0][0];
144 const T c = x[0][1];
145 const T b = x[1][0];
146 const T d = x[1][1];
147
148 const T det((a * d) - (b * c));
149 inverted[0][0] = d / det;
150 inverted[0][1] = -c / det;
151 inverted[1][0] = -b / det;
152 inverted[1][1] = a / det;
153 return inverted;
154}
155
156
157//------------------------------------------------------------------------------
158// From the Wikipedia article on matrix inversion's section on fast 3x3
159// matrix inversion:
160// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
161template <typename MATRIX>
Romain Guycaf2ca42016-11-10 11:45:58 -0800162CONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800163 typedef typename MATRIX::value_type T;
164
165 // Assuming the input matrix is:
166 // | a b c |
167 // | d e f |
168 // | g h i |
169 //
170 // The analytic inverse is
171 // | A B C |^T
172 // | D E F |
173 // | G H I | / determinant
174 //
175 // Which is
176 // | A D G |
177 // | B E H |
178 // | C F I | / determinant
179 //
180 // Where:
181 // A = (ei - fh), B = (fg - di), C = (dh - eg)
182 // D = (ch - bi), E = (ai - cg), F = (bg - ah)
183 // G = (bf - ce), H = (cd - af), I = (ae - bd)
184 //
185 // and the determinant is a*A + b*B + c*C (The rule of Sarrus)
186 //
187 // Importantly, our matrices are column-major!
188
189 MATRIX inverted(MATRIX::NO_INIT);
190
191 const T a = x[0][0];
192 const T b = x[1][0];
193 const T c = x[2][0];
194 const T d = x[0][1];
195 const T e = x[1][1];
196 const T f = x[2][1];
197 const T g = x[0][2];
198 const T h = x[1][2];
199 const T i = x[2][2];
200
201 // Do the full analytic inverse
202 const T A = e * i - f * h;
203 const T B = f * g - d * i;
204 const T C = d * h - e * g;
205 inverted[0][0] = A; // A
206 inverted[0][1] = B; // B
207 inverted[0][2] = C; // C
208 inverted[1][0] = c * h - b * i; // D
209 inverted[1][1] = a * i - c * g; // E
210 inverted[1][2] = b * g - a * h; // F
211 inverted[2][0] = b * f - c * e; // G
212 inverted[2][1] = c * d - a * f; // H
213 inverted[2][2] = a * e - b * d; // I
214
215 const T det(a * A + b * B + c * C);
216 for (size_t col = 0; col < 3; ++col) {
217 for (size_t row = 0; row < 3; ++row) {
218 inverted[col][row] /= det;
219 }
220 }
221
222 return inverted;
223}
224
Romain Guy5d4bae72016-11-08 09:49:25 -0800225/**
226 * Inversion function which switches on the matrix size.
227 * @warning This function assumes the matrix is invertible. The result is
228 * undefined if it is not. It is the responsibility of the caller to
229 * make sure the matrix is not singular.
230 */
231template <typename MATRIX>
232inline constexpr MATRIX PURE inverse(const MATRIX& matrix) {
233 static_assert(MATRIX::NUM_ROWS == MATRIX::NUM_COLS, "only square matrices can be inverted");
234 return (MATRIX::NUM_ROWS == 2) ? fastInverse2<MATRIX>(matrix) :
235 ((MATRIX::NUM_ROWS == 3) ? fastInverse3<MATRIX>(matrix) :
236 gaussJordanInverse<MATRIX>(matrix));
Mathias Agopian595ea772013-08-21 23:10:41 -0700237}
238
239template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
Romain Guycaf2ca42016-11-10 11:45:58 -0800240CONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700241 // pre-requisite:
242 // lhs : D columns, R rows
243 // rhs : C columns, D rows
244 // res : C columns, R rows
245
Romain Guy5d4bae72016-11-08 09:49:25 -0800246 static_assert(MATRIX_A::NUM_COLS == MATRIX_B::NUM_ROWS,
247 "matrices can't be multiplied. invalid dimensions.");
248 static_assert(MATRIX_R::NUM_COLS == MATRIX_B::NUM_COLS,
249 "invalid dimension of matrix multiply result.");
250 static_assert(MATRIX_R::NUM_ROWS == MATRIX_A::NUM_ROWS,
251 "invalid dimension of matrix multiply result.");
Mathias Agopian595ea772013-08-21 23:10:41 -0700252
253 MATRIX_R res(MATRIX_R::NO_INIT);
Romain Guy5d4bae72016-11-08 09:49:25 -0800254 for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) {
255 res[col] = lhs * rhs[col];
Mathias Agopian595ea772013-08-21 23:10:41 -0700256 }
257 return res;
258}
259
260// transpose. this handles matrices of matrices
261template <typename MATRIX>
Romain Guycaf2ca42016-11-10 11:45:58 -0800262CONSTEXPR MATRIX PURE transpose(const MATRIX& m) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700263 // for now we only handle square matrix transpose
Romain Guy5d4bae72016-11-08 09:49:25 -0800264 static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices");
Mathias Agopian595ea772013-08-21 23:10:41 -0700265 MATRIX result(MATRIX::NO_INIT);
Romain Guy5d4bae72016-11-08 09:49:25 -0800266 for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
267 for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) {
268 result[col][row] = transpose(m[row][col]);
269 }
270 }
Mathias Agopian595ea772013-08-21 23:10:41 -0700271 return result;
272}
273
274// trace. this handles matrices of matrices
275template <typename MATRIX>
Romain Guycaf2ca42016-11-10 11:45:58 -0800276CONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800277 static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices");
Mathias Agopian595ea772013-08-21 23:10:41 -0700278 typename MATRIX::value_type result(0);
Romain Guy5d4bae72016-11-08 09:49:25 -0800279 for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
280 result += trace(m[col][col]);
281 }
Mathias Agopian595ea772013-08-21 23:10:41 -0700282 return result;
283}
284
Romain Guy5d4bae72016-11-08 09:49:25 -0800285// diag. this handles matrices of matrices
Mathias Agopian595ea772013-08-21 23:10:41 -0700286template <typename MATRIX>
Romain Guycaf2ca42016-11-10 11:45:58 -0800287CONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800288 static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices");
Mathias Agopian595ea772013-08-21 23:10:41 -0700289 typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
Romain Guy5d4bae72016-11-08 09:49:25 -0800290 for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
291 result[col] = m[col][col];
292 }
Mathias Agopian595ea772013-08-21 23:10:41 -0700293 return result;
294}
295
Romain Guy5d4bae72016-11-08 09:49:25 -0800296//------------------------------------------------------------------------------
297// This is taken from the Imath MatrixAlgo code, and is identical to Eigen.
298template <typename MATRIX>
299TQuaternion<typename MATRIX::value_type> extractQuat(const MATRIX& mat) {
300 typedef typename MATRIX::value_type T;
301
302 TQuaternion<T> quat(TQuaternion<T>::NO_INIT);
303
304 // Compute the trace to see if it is positive or not.
305 const T trace = mat[0][0] + mat[1][1] + mat[2][2];
306
307 // check the sign of the trace
308 if (LIKELY(trace > 0)) {
309 // trace is positive
310 T s = std::sqrt(trace + 1);
311 quat.w = T(0.5) * s;
312 s = T(0.5) / s;
313 quat.x = (mat[1][2] - mat[2][1]) * s;
314 quat.y = (mat[2][0] - mat[0][2]) * s;
315 quat.z = (mat[0][1] - mat[1][0]) * s;
316 } else {
317 // trace is negative
318
319 // Find the index of the greatest diagonal
320 size_t i = 0;
321 if (mat[1][1] > mat[0][0]) { i = 1; }
322 if (mat[2][2] > mat[i][i]) { i = 2; }
323
324 // Get the next indices: (n+1)%3
325 static constexpr size_t next_ijk[3] = { 1, 2, 0 };
326 size_t j = next_ijk[i];
327 size_t k = next_ijk[j];
328 T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1);
329 quat[i] = T(0.5) * s;
330 if (s != 0) {
331 s = T(0.5) / s;
332 }
333 quat.w = (mat[j][k] - mat[k][j]) * s;
334 quat[j] = (mat[i][j] + mat[j][i]) * s;
335 quat[k] = (mat[i][k] + mat[k][i]) * s;
336 }
337 return quat;
338}
339
Mathias Agopian595ea772013-08-21 23:10:41 -0700340template <typename MATRIX>
341String8 asString(const MATRIX& m) {
342 String8 s;
Romain Guy5d4bae72016-11-08 09:49:25 -0800343 for (size_t c = 0; c < MATRIX::col_size(); c++) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700344 s.append("| ");
Romain Guy5d4bae72016-11-08 09:49:25 -0800345 for (size_t r = 0; r < MATRIX::row_size(); r++) {
Mathias Agopian595ea772013-08-21 23:10:41 -0700346 s.appendFormat("%7.2f ", m[r][c]);
347 }
348 s.append("|\n");
349 }
350 return s;
351}
352
Romain Guy5d4bae72016-11-08 09:49:25 -0800353} // namespace matrix
Mathias Agopian595ea772013-08-21 23:10:41 -0700354
355// -------------------------------------------------------------------------------------
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700356
357/*
358 * TMatProductOperators implements basic arithmetic and basic compound assignments
359 * operators on a vector of type BASE<T>.
360 *
361 * BASE only needs to implement operator[] and size().
362 * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
363 * get all the functionality here.
364 */
365
366template <template<typename T> class BASE, typename T>
367class TMatProductOperators {
368public:
369 // multiply by a scalar
370 BASE<T>& operator *= (T v) {
371 BASE<T>& lhs(static_cast< BASE<T>& >(*this));
Romain Guy5d4bae72016-11-08 09:49:25 -0800372 for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
373 lhs[col] *= v;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700374 }
375 return lhs;
376 }
377
Romain Guy5d4bae72016-11-08 09:49:25 -0800378 // matrix *= matrix
379 template<typename U>
380 const BASE<T>& operator *= (const BASE<U>& rhs) {
381 BASE<T>& lhs(static_cast< BASE<T>& >(*this));
382 lhs = matrix::multiply<BASE<T> >(lhs, rhs);
383 return lhs;
384 }
385
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700386 // divide by a scalar
387 BASE<T>& operator /= (T v) {
388 BASE<T>& lhs(static_cast< BASE<T>& >(*this));
Romain Guy5d4bae72016-11-08 09:49:25 -0800389 for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
390 lhs[col] /= v;
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700391 }
392 return lhs;
393 }
394
395 // matrix * matrix, result is a matrix of the same type than the lhs matrix
396 template<typename U>
Romain Guycaf2ca42016-11-10 11:45:58 -0800397 friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700398 return matrix::multiply<BASE<T> >(lhs, rhs);
399 }
400};
401
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700402/*
403 * TMatSquareFunctions implements functions on a matrix of type BASE<T>.
404 *
405 * BASE only needs to implement:
406 * - operator[]
407 * - col_type
408 * - row_type
409 * - COL_SIZE
410 * - ROW_SIZE
411 *
412 * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
413 * get all the functionality here.
414 */
415
416template<template<typename U> class BASE, typename T>
417class TMatSquareFunctions {
418public:
Romain Guy5d4bae72016-11-08 09:49:25 -0800419
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700420 /*
421 * NOTE: the functions below ARE NOT member methods. They are friend functions
422 * with they definition inlined with their declaration. This makes these
423 * template functions available to the compiler when (and only when) this class
424 * is instantiated, at which point they're only templated on the 2nd parameter
425 * (the first one, BASE<T> being known).
426 */
Romain Guycaf2ca42016-11-10 11:45:58 -0800427 friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800428 return matrix::inverse(matrix);
429 }
430 friend inline constexpr BASE<T> PURE transpose(const BASE<T>& m) {
431 return matrix::transpose(m);
432 }
433 friend inline constexpr T PURE trace(const BASE<T>& m) {
434 return matrix::trace(m);
435 }
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700436};
437
Romain Guy5d4bae72016-11-08 09:49:25 -0800438template<template<typename U> class BASE, typename T>
439class TMatHelpers {
440public:
441 constexpr inline size_t getColumnSize() const { return BASE<T>::COL_SIZE; }
442 constexpr inline size_t getRowSize() const { return BASE<T>::ROW_SIZE; }
443 constexpr inline size_t getColumnCount() const { return BASE<T>::NUM_COLS; }
444 constexpr inline size_t getRowCount() const { return BASE<T>::NUM_ROWS; }
445 constexpr inline size_t size() const { return BASE<T>::ROW_SIZE; } // for TVec*<>
446
447 // array access
448 constexpr T const* asArray() const {
449 return &static_cast<BASE<T> const &>(*this)[0][0];
450 }
451
452 // element access
453 inline constexpr T const& operator()(size_t row, size_t col) const {
454 return static_cast<BASE<T> const &>(*this)[col][row];
455 }
456
457 inline T& operator()(size_t row, size_t col) {
458 return static_cast<BASE<T>&>(*this)[col][row];
459 }
460
461 template <typename VEC>
Romain Guycaf2ca42016-11-10 11:45:58 -0800462 static CONSTEXPR BASE<T> translate(const VEC& t) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800463 BASE<T> r;
464 r[BASE<T>::NUM_COLS-1] = t;
465 return r;
466 }
467
468 template <typename VEC>
469 static constexpr BASE<T> scale(const VEC& s) {
470 return BASE<T>(s);
471 }
472
Romain Guycaf2ca42016-11-10 11:45:58 -0800473 friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800474 for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
475 m[col] = abs(m[col]);
476 }
477 return m;
478 }
479};
480
481// functions for 3x3 and 4x4 matrices
482template<template<typename U> class BASE, typename T>
483class TMatTransform {
484public:
485 inline constexpr TMatTransform() {
486 static_assert(BASE<T>::NUM_ROWS == 3 || BASE<T>::NUM_ROWS == 4, "3x3 or 4x4 matrices only");
487 }
488
489 template <typename A, typename VEC>
Romain Guycaf2ca42016-11-10 11:45:58 -0800490 static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800491 BASE<T> r;
492 T c = std::cos(radian);
493 T s = std::sin(radian);
494 if (about.x == 1 && about.y == 0 && about.z == 0) {
495 r[1][1] = c; r[2][2] = c;
496 r[1][2] = s; r[2][1] = -s;
497 } else if (about.x == 0 && about.y == 1 && about.z == 0) {
498 r[0][0] = c; r[2][2] = c;
499 r[2][0] = s; r[0][2] = -s;
500 } else if (about.x == 0 && about.y == 0 && about.z == 1) {
501 r[0][0] = c; r[1][1] = c;
502 r[0][1] = s; r[1][0] = -s;
503 } else {
504 VEC nabout = normalize(about);
505 typename VEC::value_type x = nabout.x;
506 typename VEC::value_type y = nabout.y;
507 typename VEC::value_type z = nabout.z;
508 T nc = 1 - c;
509 T xy = x * y;
510 T yz = y * z;
511 T zx = z * x;
512 T xs = x * s;
513 T ys = y * s;
514 T zs = z * s;
515 r[0][0] = x*x*nc + c; r[1][0] = xy*nc - zs; r[2][0] = zx*nc + ys;
516 r[0][1] = xy*nc + zs; r[1][1] = y*y*nc + c; r[2][1] = yz*nc - xs;
517 r[0][2] = zx*nc - ys; r[1][2] = yz*nc + xs; r[2][2] = z*z*nc + c;
518
519 // Clamp results to -1, 1.
520 for (size_t col = 0; col < 3; ++col) {
521 for (size_t row = 0; row < 3; ++row) {
522 r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
523 }
524 }
525 }
526 return r;
527 }
528
529 /**
530 * Create a matrix from euler angles using YPR around YXZ respectively
531 * @param yaw about Y axis
532 * @param pitch about X axis
533 * @param roll about Z axis
534 */
535 template <
536 typename Y, typename P, typename R,
537 typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
538 typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
539 typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
540 >
Romain Guycaf2ca42016-11-10 11:45:58 -0800541 static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800542 return eulerZYX(roll, pitch, yaw);
543 }
544
545 /**
546 * Create a matrix from euler angles using YPR around ZYX respectively
547 * @param roll about X axis
548 * @param pitch about Y axis
549 * @param yaw about Z axis
550 *
551 * The euler angles are applied in ZYX order. i.e: a vector is first rotated
552 * about X (roll) then Y (pitch) and then Z (yaw).
553 */
554 template <
555 typename Y, typename P, typename R,
556 typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
557 typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
558 typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
559 >
Romain Guycaf2ca42016-11-10 11:45:58 -0800560 static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
Romain Guy5d4bae72016-11-08 09:49:25 -0800561 BASE<T> r;
562 T cy = std::cos(yaw);
563 T sy = std::sin(yaw);
564 T cp = std::cos(pitch);
565 T sp = std::sin(pitch);
566 T cr = std::cos(roll);
567 T sr = std::sin(roll);
568 T cc = cr * cy;
569 T cs = cr * sy;
570 T sc = sr * cy;
571 T ss = sr * sy;
572 r[0][0] = cp * cy;
573 r[0][1] = cp * sy;
574 r[0][2] = -sp;
575 r[1][0] = sp * sc - cs;
576 r[1][1] = sp * ss + cc;
577 r[1][2] = cp * sr;
578 r[2][0] = sp * cc + ss;
579 r[2][1] = sp * cs - sc;
580 r[2][2] = cp * cr;
581
582 // Clamp results to -1, 1.
583 for (size_t col = 0; col < 3; ++col) {
584 for (size_t row = 0; row < 3; ++row) {
585 r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
586 }
587 }
588 return r;
589 }
590
591 TQuaternion<T> toQuaternion() const {
592 return matrix::extractQuat(static_cast<const BASE<T>&>(*this));
593 }
594};
595
596
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700597template <template<typename T> class BASE, typename T>
598class TMatDebug {
599public:
Romain Guy5d4bae72016-11-08 09:49:25 -0800600 friend std::ostream& operator<<(std::ostream& stream, const BASE<T>& m) {
601 for (size_t row = 0; row < BASE<T>::NUM_ROWS; ++row) {
602 if (row != 0) {
603 stream << std::endl;
604 }
605 if (row == 0) {
606 stream << "/ ";
607 } else if (row == BASE<T>::NUM_ROWS-1) {
608 stream << "\\ ";
609 } else {
610 stream << "| ";
611 }
612 for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
613 stream << std::setw(10) << std::to_string(m[col][row]);
614 }
615 if (row == 0) {
616 stream << " \\";
617 } else if (row == BASE<T>::NUM_ROWS-1) {
618 stream << " /";
619 } else {
620 stream << " |";
621 }
622 }
623 return stream;
624 }
625
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700626 String8 asString() const {
Romain Guy5d4bae72016-11-08 09:49:25 -0800627 return matrix::asString(static_cast<const BASE<T>&>(*this));
Mathias Agopian1d4d8f92013-09-01 21:35:36 -0700628 }
629};
630
631// -------------------------------------------------------------------------------------
Romain Guy5d4bae72016-11-08 09:49:25 -0800632} // namespace details
633} // namespace android
Mathias Agopian595ea772013-08-21 23:10:41 -0700634
Romain Guy5d4bae72016-11-08 09:49:25 -0800635#undef LIKELY
636#undef UNLIKELY
Mathias Agopian595ea772013-08-21 23:10:41 -0700637#undef PURE
Romain Guycaf2ca42016-11-10 11:45:58 -0800638#undef CONSTEXPR
Mathias Agopian595ea772013-08-21 23:10:41 -0700639
Romain Guy5d4bae72016-11-08 09:49:25 -0800640#endif // UI_TMATHELPERS_H_