| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 1 | /* | 
 | 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 Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 17 | #ifndef UI_TMATHELPERS_H_ | 
 | 18 | #define UI_TMATHELPERS_H_ | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 19 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 20 | #include <math.h> | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 21 | #include <stdint.h> | 
 | 22 | #include <sys/types.h> | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 23 |  | 
 | 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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 41 |  | 
 | 42 | #define PURE __attribute__((pure)) | 
 | 43 |  | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 44 | #if __cplusplus >= 201402L | 
 | 45 | #define CONSTEXPR constexpr | 
 | 46 | #else | 
 | 47 | #define CONSTEXPR | 
 | 48 | #endif | 
 | 49 |  | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 50 | namespace android { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 51 | namespace details { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 52 | // ------------------------------------------------------------------------------------- | 
 | 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 |  | 
 | 65 | namespace matrix { | 
 | 66 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 67 | inline constexpr int     transpose(int v)    { return v; } | 
 | 68 | inline constexpr float   transpose(float v)  { return v; } | 
 | 69 | inline constexpr double  transpose(double v) { return v; } | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 70 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 71 | inline constexpr int     trace(int v)    { return v; } | 
 | 72 | inline constexpr float   trace(float v)  { return v; } | 
 | 73 | inline constexpr double  trace(double v) { return v; } | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 74 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 75 | /* | 
 | 76 |  * Matrix inversion | 
 | 77 |  */ | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 78 | template<typename MATRIX> | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 79 | MATRIX PURE gaussJordanInverse(const MATRIX& src) { | 
 | 80 |     typedef typename MATRIX::value_type T; | 
 | 81 |     static constexpr unsigned int N = MATRIX::NUM_ROWS; | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 82 |     MATRIX tmp(src); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 83 |     MATRIX inverted(1); | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 84 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 85 |     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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 92 |                 swap = j; | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 93 |                 t = t2; | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 94 |             } | 
 | 95 |         } | 
 | 96 |  | 
 | 97 |         if (swap != i) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 98 |             // swap columns. | 
 | 99 |             std::swap(tmp[i], tmp[swap]); | 
 | 100 |             std::swap(inverted[i], inverted[swap]); | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 101 |         } | 
 | 102 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 103 |         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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 107 |         } | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 108 |  | 
 | 109 |         // Factor out the lower triangle | 
 | 110 |         for (size_t j = 0; j < N; ++j) { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 111 |             if (j != i) { | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 112 |                 const T d = tmp[j][i]; | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 113 |                 for (size_t k = 0; k < N; ++k) { | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 114 |                     tmp[j][k] -= tmp[i][k] * d; | 
 | 115 |                     inverted[j][k] -= inverted[i][k] * d; | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 116 |                 } | 
 | 117 |             } | 
 | 118 |         } | 
 | 119 |     } | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 120 |  | 
 | 121 |     return inverted; | 
 | 122 | } | 
 | 123 |  | 
 | 124 |  | 
 | 125 | //------------------------------------------------------------------------------ | 
 | 126 | // 2x2 matrix inverse is easy. | 
 | 127 | template <typename MATRIX> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 128 | CONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 129 |     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 | 
 | 161 | template <typename MATRIX> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 162 | CONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 163 |     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 Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 225 | /** | 
 | 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 |  */ | 
 | 231 | template <typename MATRIX> | 
 | 232 | inline 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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 237 | } | 
 | 238 |  | 
 | 239 | template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 240 | CONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 241 |     // pre-requisite: | 
 | 242 |     //  lhs : D columns, R rows | 
 | 243 |     //  rhs : C columns, D rows | 
 | 244 |     //  res : C columns, R rows | 
 | 245 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 246 |     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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 252 |  | 
 | 253 |     MATRIX_R res(MATRIX_R::NO_INIT); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 254 |     for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) { | 
 | 255 |         res[col] = lhs * rhs[col]; | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 256 |     } | 
 | 257 |     return res; | 
 | 258 | } | 
 | 259 |  | 
 | 260 | // transpose. this handles matrices of matrices | 
 | 261 | template <typename MATRIX> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 262 | CONSTEXPR MATRIX PURE transpose(const MATRIX& m) { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 263 |     // for now we only handle square matrix transpose | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 264 |     static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices"); | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 265 |     MATRIX result(MATRIX::NO_INIT); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 266 |     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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 271 |     return result; | 
 | 272 | } | 
 | 273 |  | 
 | 274 | // trace. this handles matrices of matrices | 
 | 275 | template <typename MATRIX> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 276 | CONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 277 |     static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices"); | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 278 |     typename MATRIX::value_type result(0); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 279 |     for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { | 
 | 280 |         result += trace(m[col][col]); | 
 | 281 |     } | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 282 |     return result; | 
 | 283 | } | 
 | 284 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 285 | // diag. this handles matrices of matrices | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 286 | template <typename MATRIX> | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 287 | CONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 288 |     static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices"); | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 289 |     typename MATRIX::col_type result(MATRIX::col_type::NO_INIT); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 290 |     for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) { | 
 | 291 |         result[col] = m[col][col]; | 
 | 292 |     } | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 293 |     return result; | 
 | 294 | } | 
 | 295 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 296 | //------------------------------------------------------------------------------ | 
 | 297 | // This is taken from the Imath MatrixAlgo code, and is identical to Eigen. | 
 | 298 | template <typename MATRIX> | 
 | 299 | TQuaternion<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 Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 340 | template <typename MATRIX> | 
 | 341 | String8 asString(const MATRIX& m) { | 
 | 342 |     String8 s; | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 343 |     for (size_t c = 0; c < MATRIX::col_size(); c++) { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 344 |         s.append("|  "); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 345 |         for (size_t r = 0; r < MATRIX::row_size(); r++) { | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 346 |             s.appendFormat("%7.2f  ", m[r][c]); | 
 | 347 |         } | 
 | 348 |         s.append("|\n"); | 
 | 349 |     } | 
 | 350 |     return s; | 
 | 351 | } | 
 | 352 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 353 | }  // namespace matrix | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 354 |  | 
 | 355 | // ------------------------------------------------------------------------------------- | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 356 |  | 
 | 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 |  | 
 | 366 | template <template<typename T> class BASE, typename T> | 
 | 367 | class TMatProductOperators { | 
 | 368 | public: | 
 | 369 |     // multiply by a scalar | 
 | 370 |     BASE<T>& operator *= (T v) { | 
 | 371 |         BASE<T>& lhs(static_cast< BASE<T>& >(*this)); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 372 |         for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) { | 
 | 373 |             lhs[col] *= v; | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 374 |         } | 
 | 375 |         return lhs; | 
 | 376 |     } | 
 | 377 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 378 |     //  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 Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 386 |     // divide by a scalar | 
 | 387 |     BASE<T>& operator /= (T v) { | 
 | 388 |         BASE<T>& lhs(static_cast< BASE<T>& >(*this)); | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 389 |         for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) { | 
 | 390 |             lhs[col] /= v; | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 391 |         } | 
 | 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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 397 |     friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) { | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 398 |         return matrix::multiply<BASE<T> >(lhs, rhs); | 
 | 399 |     } | 
 | 400 | }; | 
 | 401 |  | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 402 | /* | 
 | 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 |  | 
 | 416 | template<template<typename U> class BASE, typename T> | 
 | 417 | class TMatSquareFunctions { | 
 | 418 | public: | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 419 |  | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 420 |     /* | 
 | 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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 427 |     friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 428 |         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 Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 436 | }; | 
 | 437 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 438 | template<template<typename U> class BASE, typename T> | 
 | 439 | class TMatHelpers { | 
 | 440 | public: | 
 | 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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 462 |     static CONSTEXPR BASE<T> translate(const VEC& t) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 463 |         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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 473 |     friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 474 |         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 | 
 | 482 | template<template<typename U> class BASE, typename T> | 
 | 483 | class TMatTransform { | 
 | 484 | public: | 
 | 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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 490 |     static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 491 |         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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 541 |     static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 542 |         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 Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 560 |     static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 561 |         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 Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 597 | template <template<typename T> class BASE, typename T> | 
 | 598 | class TMatDebug { | 
 | 599 | public: | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 600 |     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 Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 626 |     String8 asString() const { | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 627 |         return matrix::asString(static_cast<const BASE<T>&>(*this)); | 
| Mathias Agopian | 1d4d8f9 | 2013-09-01 21:35:36 -0700 | [diff] [blame] | 628 |     } | 
 | 629 | }; | 
 | 630 |  | 
 | 631 | // ------------------------------------------------------------------------------------- | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 632 | }  // namespace details | 
 | 633 | }  // namespace android | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 634 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 635 | #undef LIKELY | 
 | 636 | #undef UNLIKELY | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 637 | #undef PURE | 
| Romain Guy | caf2ca4 | 2016-11-10 11:45:58 -0800 | [diff] [blame] | 638 | #undef CONSTEXPR | 
| Mathias Agopian | 595ea77 | 2013-08-21 23:10:41 -0700 | [diff] [blame] | 639 |  | 
| Romain Guy | 5d4bae7 | 2016-11-08 09:49:25 -0800 | [diff] [blame] | 640 | #endif  // UI_TMATHELPERS_H_ |