1595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian/*
2595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * Copyright 2013 The Android Open Source Project
3595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian *
4595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
5595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * you may not use this file except in compliance with the License.
6595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * You may obtain a copy of the License at
7595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian *
8595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
9595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian *
10595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * Unless required by applicable law or agreed to in writing, software
11595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
12595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * See the License for the specific language governing permissions and
14595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * limitations under the License.
15595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian */
16595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
171d77b719d51a01cbd6954a048fb64e79d50a950eMathias Agopian#pragma once
18595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
195d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include <math.h>
20595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian#include <stdint.h>
21595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian#include <sys/types.h>
225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include <cmath>
245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include <exception>
255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include <iomanip>
265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include <stdexcept>
275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
281d77b719d51a01cbd6954a048fb64e79d50a950eMathias Agopian#include <math/quat.h>
291d77b719d51a01cbd6954a048fb64e79d50a950eMathias Agopian#include <math/TVecHelpers.h>
305d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#include  <utils/String8.h>
325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3347df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#ifndef LIKELY
3447df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#define LIKELY_DEFINED_LOCAL
355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#ifdef __cplusplus
365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#   define LIKELY( exp )    (__builtin_expect( !!(exp), true ))
375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#else
395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#   define LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#   define UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
415d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#endif
4247df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#endif
43595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
44595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian#define PURE __attribute__((pure))
45595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
46caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#if __cplusplus >= 201402L
47caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#define CONSTEXPR constexpr
48caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#else
49caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#define CONSTEXPR
50caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#endif
51caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy
52595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiannamespace android {
535d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guynamespace details {
54595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian// -------------------------------------------------------------------------------------
55595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
56595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian/*
57595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * No user serviceable parts here.
58595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian *
59595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * Don't use this file directly, instead include ui/mat*.h
60595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian */
61595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
62595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
63595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian/*
64595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian * Matrix utilities
65595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian */
66595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
67595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiannamespace matrix {
68595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
695d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr int     transpose(int v)    { return v; }
705d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr float   transpose(float v)  { return v; }
715d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr double  transpose(double v) { return v; }
72595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
735d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr int     trace(int v)    { return v; }
745d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr float   trace(float v)  { return v; }
755d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr double  trace(double v) { return v; }
76595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
775d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy/*
785d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy * Matrix inversion
795d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy */
80595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate<typename MATRIX>
815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain GuyMATRIX PURE gaussJordanInverse(const MATRIX& src) {
825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typedef typename MATRIX::value_type T;
835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static constexpr unsigned int N = MATRIX::NUM_ROWS;
84595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    MATRIX tmp(src);
855d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    MATRIX inverted(1);
865d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t i = 0; i < N; ++i) {
885d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // look for largest element in i'th column
895d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        size_t swap = i;
905d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T t = std::abs(tmp[i][i]);
915d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t j = i + 1; j < N; ++j) {
925d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            const T t2 = std::abs(tmp[j][i]);
935d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            if (t2 > t) {
94595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian                swap = j;
955d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                t = t2;
96595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian            }
97595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        }
98595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
99595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        if (swap != i) {
1005d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            // swap columns.
1015d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            std::swap(tmp[i], tmp[swap]);
1025d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            std::swap(inverted[i], inverted[swap]);
103595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        }
104595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
1055d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        const T denom(tmp[i][i]);
1065d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t k = 0; k < N; ++k) {
1075d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            tmp[i][k] /= denom;
1085d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            inverted[i][k] /= denom;
109595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        }
1105d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1115d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // Factor out the lower triangle
1125d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t j = 0; j < N; ++j) {
113595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian            if (j != i) {
114caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy                const T d = tmp[j][i];
1155d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                for (size_t k = 0; k < N; ++k) {
116caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy                    tmp[j][k] -= tmp[i][k] * d;
117caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy                    inverted[j][k] -= inverted[i][k] * d;
118595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian                }
119595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian            }
120595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        }
121595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    }
1225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    return inverted;
1245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}
1255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy//------------------------------------------------------------------------------
1285d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// 2x2 matrix inverse is easy.
1295d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate <typename MATRIX>
130caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) {
1315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typedef typename MATRIX::value_type T;
1325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1335d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Assuming the input matrix is:
1345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | a b |
1355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | c d |
1365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // The analytic inverse is
1385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | d -b |
1395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | -c a | / (a d - b c)
1405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1415d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Importantly, our matrices are column-major!
1425d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1435d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    MATRIX inverted(MATRIX::NO_INIT);
1445d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1455d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T a = x[0][0];
1465d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T c = x[0][1];
1475d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T b = x[1][0];
1485d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T d = x[1][1];
1495d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1505d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T det((a * d) - (b * c));
1515d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[0][0] =  d / det;
1525d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[0][1] = -c / det;
1535d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[1][0] = -b / det;
1545d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[1][1] =  a / det;
1555d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    return inverted;
1565d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}
1575d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1585d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1595d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy//------------------------------------------------------------------------------
1605d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// From the Wikipedia article on matrix inversion's section on fast 3x3
1615d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// matrix inversion:
1625d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
1635d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate <typename MATRIX>
164caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) {
1655d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typedef typename MATRIX::value_type T;
1665d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1675d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Assuming the input matrix is:
1685d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | a b c |
1695d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | d e f |
1705d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | g h i |
1715d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1725d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // The analytic inverse is
1735d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | A B C |^T
1745d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | D E F |
1755d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | G H I | / determinant
1765d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1775d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Which is
1785d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | A D G |
1795d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | B E H |
1805d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // | C F I | / determinant
1815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Where:
1835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // A = (ei - fh), B = (fg - di), C = (dh - eg)
1845d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // D = (ch - bi), E = (ai - cg), F = (bg - ah)
1855d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // G = (bf - ce), H = (cd - af), I = (ae - bd)
1865d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // and the determinant is a*A + b*B + c*C (The rule of Sarrus)
1885d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //
1895d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Importantly, our matrices are column-major!
1905d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1915d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    MATRIX inverted(MATRIX::NO_INIT);
1925d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
1935d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T a = x[0][0];
1945d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T b = x[1][0];
1955d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T c = x[2][0];
1965d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T d = x[0][1];
1975d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T e = x[1][1];
1985d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T f = x[2][1];
1995d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T g = x[0][2];
2005d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T h = x[1][2];
2015d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T i = x[2][2];
2025d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
2035d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Do the full analytic inverse
2045d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T A = e * i - f * h;
2055d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T B = f * g - d * i;
2065d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T C = d * h - e * g;
2075d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[0][0] = A;                 // A
2085d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[0][1] = B;                 // B
2095d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[0][2] = C;                 // C
2105d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[1][0] = c * h - b * i;     // D
2115d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[1][1] = a * i - c * g;     // E
2125d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[1][2] = b * g - a * h;     // F
2135d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[2][0] = b * f - c * e;     // G
2145d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[2][1] = c * d - a * f;     // H
2155d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inverted[2][2] = a * e - b * d;     // I
2165d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
2175d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T det(a * A + b * B + c * C);
2185d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t col = 0; col < 3; ++col) {
2195d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t row = 0; row < 3; ++row) {
2205d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            inverted[col][row] /= det;
2215d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
2225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
2235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
2245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    return inverted;
2255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}
2265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
2275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy/**
2285d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy * Inversion function which switches on the matrix size.
2295d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy * @warning This function assumes the matrix is invertible. The result is
2305d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy * undefined if it is not. It is the responsibility of the caller to
2315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy * make sure the matrix is not singular.
2325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy */
2335d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate <typename MATRIX>
2345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyinline constexpr MATRIX PURE inverse(const MATRIX& matrix) {
2355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX::NUM_ROWS == MATRIX::NUM_COLS, "only square matrices can be inverted");
2365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    return (MATRIX::NUM_ROWS == 2) ? fastInverse2<MATRIX>(matrix) :
2375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy          ((MATRIX::NUM_ROWS == 3) ? fastInverse3<MATRIX>(matrix) :
2385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                    gaussJordanInverse<MATRIX>(matrix));
239595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
240595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
241595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
242caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
243595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    // pre-requisite:
244595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    //  lhs : D columns, R rows
245595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    //  rhs : C columns, D rows
246595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    //  res : C columns, R rows
247595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
2485d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX_A::NUM_COLS == MATRIX_B::NUM_ROWS,
2495d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            "matrices can't be multiplied. invalid dimensions.");
2505d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX_R::NUM_COLS == MATRIX_B::NUM_COLS,
2515d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            "invalid dimension of matrix multiply result.");
2525d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX_R::NUM_ROWS == MATRIX_A::NUM_ROWS,
2535d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            "invalid dimension of matrix multiply result.");
254595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
255595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    MATRIX_R res(MATRIX_R::NO_INIT);
2565d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) {
2575d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        res[col] = lhs * rhs[col];
258595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    }
259595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    return res;
260595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
261595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
262595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian// transpose. this handles matrices of matrices
263595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate <typename MATRIX>
264caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR MATRIX PURE transpose(const MATRIX& m) {
265595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    // for now we only handle square matrix transpose
2665d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices");
267595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    MATRIX result(MATRIX::NO_INIT);
2685d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
2695d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) {
2705d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            result[col][row] = transpose(m[row][col]);
2715d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
2725d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
273595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    return result;
274595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
275595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
276595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian// trace. this handles matrices of matrices
277595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate <typename MATRIX>
278caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) {
2795d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices");
280595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    typename MATRIX::value_type result(0);
2815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
2825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        result += trace(m[col][col]);
2835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
284595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    return result;
285595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
286595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
2875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// diag. this handles matrices of matrices
288595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate <typename MATRIX>
289caf2ca414f69d460c516e2370cf42bcf49178d95Romain GuyCONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) {
2905d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices");
291595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
2925d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
2935d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        result[col] = m[col][col];
2945d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
295595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    return result;
296595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
297595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
2985d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy//------------------------------------------------------------------------------
2995d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// This is taken from the Imath MatrixAlgo code, and is identical to Eigen.
3005d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate <typename MATRIX>
3015d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain GuyTQuaternion<typename MATRIX::value_type> extractQuat(const MATRIX& mat) {
3025d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typedef typename MATRIX::value_type T;
3035d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3045d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    TQuaternion<T> quat(TQuaternion<T>::NO_INIT);
3055d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3065d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // Compute the trace to see if it is positive or not.
3075d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const T trace = mat[0][0] + mat[1][1] + mat[2][2];
3085d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3095d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // check the sign of the trace
3105d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    if (LIKELY(trace > 0)) {
3115d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // trace is positive
3125d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T s = std::sqrt(trace + 1);
3135d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat.w = T(0.5) * s;
3145d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        s = T(0.5) / s;
3155d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat.x = (mat[1][2] - mat[2][1]) * s;
3165d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat.y = (mat[2][0] - mat[0][2]) * s;
3175d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat.z = (mat[0][1] - mat[1][0]) * s;
3185d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    } else {
3195d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // trace is negative
3205d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3215d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // Find the index of the greatest diagonal
3225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        size_t i = 0;
3235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        if (mat[1][1] > mat[0][0]) { i = 1; }
3245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        if (mat[2][2] > mat[i][i]) { i = 2; }
3255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // Get the next indices: (n+1)%3
3275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        static constexpr size_t next_ijk[3] = { 1, 2, 0 };
3285d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        size_t j = next_ijk[i];
3295d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        size_t k = next_ijk[j];
3305d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1);
3315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat[i] = T(0.5) * s;
3325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        if (s != 0) {
3335d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            s = T(0.5) / s;
3345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
3355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat.w  = (mat[j][k] - mat[k][j]) * s;
3365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat[j] = (mat[i][j] + mat[j][i]) * s;
3375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        quat[k] = (mat[i][k] + mat[k][i]) * s;
3385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
3395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    return quat;
3405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}
3415d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
342595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopiantemplate <typename MATRIX>
343595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias AgopianString8 asString(const MATRIX& m) {
344595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    String8 s;
3455d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    for (size_t c = 0; c < MATRIX::col_size(); c++) {
346595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        s.append("|  ");
3475d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t r = 0; r < MATRIX::row_size(); r++) {
348595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian            s.appendFormat("%7.2f  ", m[r][c]);
349595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        }
350595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian        s.append("|\n");
351595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    }
352595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian    return s;
353595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian}
354595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
3555d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}  // namespace matrix
356595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
357595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian// -------------------------------------------------------------------------------------
3581d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
3591d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian/*
3601d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * TMatProductOperators implements basic arithmetic and basic compound assignments
3611d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * operators on a vector of type BASE<T>.
3621d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *
3631d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * BASE only needs to implement operator[] and size().
3641d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
3651d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * get all the functionality here.
3661d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian */
3671d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
3681d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopiantemplate <template<typename T> class BASE, typename T>
3691d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianclass TMatProductOperators {
3701d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianpublic:
3711d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    // multiply by a scalar
3721d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    BASE<T>& operator *= (T v) {
3731d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
3745d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
3755d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            lhs[col] *= v;
3761d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        }
3771d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        return lhs;
3781d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    }
3791d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
3805d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    //  matrix *= matrix
3815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template<typename U>
3825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    const BASE<T>& operator *= (const BASE<U>& rhs) {
3835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
3845d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        lhs = matrix::multiply<BASE<T> >(lhs, rhs);
3855d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return lhs;
3865d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
3875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
3881d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    // divide by a scalar
3891d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    BASE<T>& operator /= (T v) {
3901d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        BASE<T>& lhs(static_cast< BASE<T>& >(*this));
3915d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
3925d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            lhs[col] /= v;
3931d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        }
3941d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        return lhs;
3951d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    }
3961d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
3971d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    // matrix * matrix, result is a matrix of the same type than the lhs matrix
3981d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    template<typename U>
399caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
4001d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian        return matrix::multiply<BASE<T> >(lhs, rhs);
4011d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    }
4021d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian};
4031d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
4041d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian/*
4051d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * TMatSquareFunctions implements functions on a matrix of type BASE<T>.
4061d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *
4071d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * BASE only needs to implement:
4081d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *  - operator[]
4091d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *  - col_type
4101d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *  - row_type
4111d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *  - COL_SIZE
4121d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *  - ROW_SIZE
4131d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian *
4141d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
4151d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian * get all the functionality here.
4161d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian */
4171d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
4181d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopiantemplate<template<typename U> class BASE, typename T>
4191d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianclass TMatSquareFunctions {
4201d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianpublic:
4215d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4221d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    /*
4231d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     * NOTE: the functions below ARE NOT member methods. They are friend functions
4241d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     * with they definition inlined with their declaration. This makes these
4251d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     * template functions available to the compiler when (and only when) this class
4261d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     * is instantiated, at which point they're only templated on the 2nd parameter
4271d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     * (the first one, BASE<T> being known).
4281d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian     */
429caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) {
4305d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return matrix::inverse(matrix);
4315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    friend inline constexpr BASE<T> PURE transpose(const BASE<T>& m) {
4335d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return matrix::transpose(m);
4345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    friend inline constexpr T PURE trace(const BASE<T>& m) {
4365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return matrix::trace(m);
4375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy};
4395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate<template<typename U> class BASE, typename T>
4415d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyclass TMatHelpers {
4425d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guypublic:
4435d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr inline size_t getColumnSize() const   { return BASE<T>::COL_SIZE; }
4445d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr inline size_t getRowSize() const      { return BASE<T>::ROW_SIZE; }
4455d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr inline size_t getColumnCount() const  { return BASE<T>::NUM_COLS; }
4465d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr inline size_t getRowCount() const     { return BASE<T>::NUM_ROWS; }
4475d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr inline size_t size()  const           { return BASE<T>::ROW_SIZE; }  // for TVec*<>
4485d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4495d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // array access
4505d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    constexpr T const* asArray() const {
4515d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return &static_cast<BASE<T> const &>(*this)[0][0];
4525d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4535d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4545d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    // element access
4555d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inline constexpr T const& operator()(size_t row, size_t col) const {
4565d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return static_cast<BASE<T> const &>(*this)[col][row];
4575d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4585d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4595d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inline T& operator()(size_t row, size_t col) {
4605d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return static_cast<BASE<T>&>(*this)[col][row];
4615d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4625d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4635d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template <typename VEC>
464caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    static CONSTEXPR BASE<T> translate(const VEC& t) {
4655d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        BASE<T> r;
4665d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[BASE<T>::NUM_COLS-1] = t;
4675d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return r;
4685d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4695d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4705d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template <typename VEC>
4715d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    static constexpr BASE<T> scale(const VEC& s) {
4725d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return BASE<T>(s);
4735d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4745d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
475caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) {
4765d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
4775d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            m[col] = abs(m[col]);
4785d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
4795d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return m;
4805d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy};
4825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy// functions for 3x3 and 4x4 matrices
4845d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guytemplate<template<typename U> class BASE, typename T>
4855d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guyclass TMatTransform {
4865d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guypublic:
4875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    inline constexpr TMatTransform() {
4885d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        static_assert(BASE<T>::NUM_ROWS == 3 || BASE<T>::NUM_ROWS == 4, "3x3 or 4x4 matrices only");
4895d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
4905d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
4915d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template <typename A, typename VEC>
492caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) {
4935d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        BASE<T> r;
4945d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T c = std::cos(radian);
4955d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T s = std::sin(radian);
4965d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        if (about.x == 1 && about.y == 0 && about.z == 0) {
4975d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[1][1] = c;   r[2][2] = c;
4985d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[1][2] = s;   r[2][1] = -s;
4995d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        } else if (about.x == 0 && about.y == 1 && about.z == 0) {
5005d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][0] = c;   r[2][2] = c;
5015d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[2][0] = s;   r[0][2] = -s;
5025d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        } else if (about.x == 0 && about.y == 0 && about.z == 1) {
5035d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][0] = c;   r[1][1] = c;
5045d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][1] = s;   r[1][0] = -s;
5055d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        } else {
5065d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            VEC nabout = normalize(about);
5075d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            typename VEC::value_type x = nabout.x;
5085d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            typename VEC::value_type y = nabout.y;
5095d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            typename VEC::value_type z = nabout.z;
5105d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T nc = 1 - c;
5115d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T xy = x * y;
5125d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T yz = y * z;
5135d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T zx = z * x;
5145d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T xs = x * s;
5155d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T ys = y * s;
5165d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            T zs = z * s;
5175d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][0] = x*x*nc +  c;    r[1][0] =  xy*nc - zs;    r[2][0] =  zx*nc + ys;
5185d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][1] =  xy*nc + zs;    r[1][1] = y*y*nc +  c;    r[2][1] =  yz*nc - xs;
5195d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            r[0][2] =  zx*nc - ys;    r[1][2] =  yz*nc + xs;    r[2][2] = z*z*nc +  c;
5205d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5215d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            // Clamp results to -1, 1.
5225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            for (size_t col = 0; col < 3; ++col) {
5235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                for (size_t row = 0; row < 3; ++row) {
5245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                    r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
5255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                }
5265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
5275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
5285d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return r;
5295d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
5305d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5315d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    /**
5325d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * Create a matrix from euler angles using YPR around YXZ respectively
5335d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param yaw about Y axis
5345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param pitch about X axis
5355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param roll about Z axis
5365d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     */
5375d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template <
5385d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        typename Y, typename P, typename R,
5395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
5405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
5415d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
5425d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    >
543caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
5445d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return eulerZYX(roll, pitch, yaw);
5455d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
5465d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5475d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    /**
5485d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * Create a matrix from euler angles using YPR around ZYX respectively
5495d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param roll about X axis
5505d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param pitch about Y axis
5515d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * @param yaw about Z axis
5525d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     *
5535d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * The euler angles are applied in ZYX order. i.e: a vector is first rotated
5545d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     * about X (roll) then Y (pitch) and then Z (yaw).
5555d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy     */
5565d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    template <
5575d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typename Y, typename P, typename R,
5585d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typename = typename std::enable_if<std::is_arithmetic<Y>::value >::type,
5595d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
5605d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
5615d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    >
562caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy    static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
5635d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        BASE<T> r;
5645d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T cy = std::cos(yaw);
5655d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T sy = std::sin(yaw);
5665d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T cp = std::cos(pitch);
5675d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T sp = std::sin(pitch);
5685d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T cr = std::cos(roll);
5695d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T sr = std::sin(roll);
5705d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T cc = cr * cy;
5715d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T cs = cr * sy;
5725d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T sc = sr * cy;
5735d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        T ss = sr * sy;
5745d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[0][0] = cp * cy;
5755d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[0][1] = cp * sy;
5765d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[0][2] = -sp;
5775d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[1][0] = sp * sc - cs;
5785d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[1][1] = sp * ss + cc;
5795d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[1][2] = cp * sr;
5805d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[2][0] = sp * cc + ss;
5815d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[2][1] = sp * cs - sc;
5825d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        r[2][2] = cp * cr;
5835d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5845d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        // Clamp results to -1, 1.
5855d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t col = 0; col < 3; ++col) {
5865d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            for (size_t row = 0; row < 3; ++row) {
5875d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
5885d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
5895d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
5905d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return r;
5915d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
5925d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5935d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    TQuaternion<T> toQuaternion() const {
5945d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return matrix::extractQuat(static_cast<const BASE<T>&>(*this));
5955d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
5961d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian};
5971d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
5985d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
5991d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopiantemplate <template<typename T> class BASE, typename T>
6001d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianclass TMatDebug {
6011d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopianpublic:
6025d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    friend std::ostream& operator<<(std::ostream& stream, const BASE<T>& m) {
6035d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        for (size_t row = 0; row < BASE<T>::NUM_ROWS; ++row) {
6045d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            if (row != 0) {
6055d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << std::endl;
6065d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
6075d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            if (row == 0) {
6085d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << "/ ";
6095d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            } else if (row == BASE<T>::NUM_ROWS-1) {
6105d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << "\\ ";
6115d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            } else {
6125d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << "| ";
6135d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
6145d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
6155d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << std::setw(10) << std::to_string(m[col][row]);
6165d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
6175d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            if (row == 0) {
6185d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << " \\";
6195d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            } else if (row == BASE<T>::NUM_ROWS-1) {
6205d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << " /";
6215d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            } else {
6225d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy                stream << " |";
6235d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy            }
6245d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        }
6255d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return stream;
6265d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy    }
6275d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy
6281d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    String8 asString() const {
6295d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy        return matrix::asString(static_cast<const BASE<T>&>(*this));
6301d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian    }
6311d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian};
6321d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian
6331d4d8f94e2989b7c8667602304df9059d2701653Mathias Agopian// -------------------------------------------------------------------------------------
6345d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}  // namespace details
6355d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy}  // namespace android
636595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian
63747df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#ifdef LIKELY_DEFINED_LOCAL
63847df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#undef LIKELY_DEFINED_LOCAL
6395d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#undef LIKELY
6405d4bae7f170640e0e280b3ca8a22b18e80801a8aRomain Guy#undef UNLIKELY
64147df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee#endif //LIKELY_DEFINED_LOCAL
64247df7e3817badac69c6a875d6c230f930bf73b47Jaesoo Lee
643595ea77f6bdb5e9d0ddd3305da7a44b56f326b2cMathias Agopian#undef PURE
644caf2ca414f69d460c516e2370cf42bcf49178d95Romain Guy#undef CONSTEXPR
645