mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			916 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			916 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
 Bullet Continuous Collision Detection and Physics Library
 | 
						|
 Copyright (c) 2019 Google Inc. http://bulletphysics.org
 | 
						|
 This software is provided 'as-is', without any express or implied warranty.
 | 
						|
 In no event will the authors be held liable for any damages arising from the use of this software.
 | 
						|
 Permission is granted to anyone to use this software for any purpose,
 | 
						|
 including commercial applications, and to alter it and redistribute it freely,
 | 
						|
 subject to the following restrictions:
 | 
						|
 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
 | 
						|
 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 | 
						|
 3. This notice may not be removed or altered from any source distribution.
 | 
						|
 
 | 
						|
 Copyright (c) 2016 Theodore Gast, Chuyuan Fu, Chenfanfu Jiang, Joseph Teran
 | 
						|
 
 | 
						|
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
						|
 this software and associated documentation files (the "Software"), to deal in
 | 
						|
 the Software without restriction, including without limitation the rights to
 | 
						|
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
						|
 of the Software, and to permit persons to whom the Software is furnished to do
 | 
						|
 so, subject to the following conditions:
 | 
						|
 
 | 
						|
 The above copyright notice and this permission notice shall be included in all
 | 
						|
 copies or substantial portions of the Software.
 | 
						|
 
 | 
						|
 If the code is used in an article, the following paper shall be cited:
 | 
						|
 @techreport{qrsvd:2016,
 | 
						|
 title={Implicit-shifted Symmetric QR Singular Value Decomposition of 3x3 Matrices},
 | 
						|
 author={Gast, Theodore and Fu, Chuyuan and Jiang, Chenfanfu and Teran, Joseph},
 | 
						|
 year={2016},
 | 
						|
 institution={University of California Los Angeles}
 | 
						|
 }
 | 
						|
 
 | 
						|
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
						|
 SOFTWARE.
 | 
						|
**/
 | 
						|
 | 
						|
#ifndef btImplicitQRSVD_h
 | 
						|
#define btImplicitQRSVD_h
 | 
						|
#include <limits>
 | 
						|
#include "btMatrix3x3.h"
 | 
						|
class btMatrix2x2
 | 
						|
{
 | 
						|
public:
 | 
						|
    btScalar m_00, m_01, m_10, m_11;
 | 
						|
    btMatrix2x2(): m_00(0), m_10(0), m_01(0), m_11(0)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    btMatrix2x2(const btMatrix2x2& other): m_00(other.m_00),m_01(other.m_01),m_10(other.m_10),m_11(other.m_11)
 | 
						|
    {}
 | 
						|
    btScalar& operator()(int i, int j)
 | 
						|
    {
 | 
						|
        if (i == 0 && j == 0)
 | 
						|
            return m_00;
 | 
						|
        if (i == 1 && j == 0)
 | 
						|
            return m_10;
 | 
						|
        if (i == 0 && j == 1)
 | 
						|
            return m_01;
 | 
						|
        if (i == 1 && j == 1)
 | 
						|
            return m_11;
 | 
						|
        btAssert(false);
 | 
						|
        return m_00;
 | 
						|
    }
 | 
						|
    const btScalar& operator()(int i, int j) const
 | 
						|
    {
 | 
						|
        if (i == 0 && j == 0)
 | 
						|
            return m_00;
 | 
						|
        if (i == 1 && j == 0)
 | 
						|
            return m_10;
 | 
						|
        if (i == 0 && j == 1)
 | 
						|
            return m_01;
 | 
						|
        if (i == 1 && j == 1)
 | 
						|
            return m_11;
 | 
						|
        btAssert(false);
 | 
						|
        return m_00;
 | 
						|
    }
 | 
						|
    void setIdentity()
 | 
						|
    {
 | 
						|
        m_00 = 1;
 | 
						|
        m_11 = 1;
 | 
						|
        m_01 = 0;
 | 
						|
        m_10 = 0;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
static inline btScalar copySign(btScalar x, btScalar y) {
 | 
						|
    if ((x < 0 && y > 0) || (x > 0 && y < 0))
 | 
						|
        return -x;
 | 
						|
    return x;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 Class for givens rotation.
 | 
						|
 Row rotation G*A corresponds to something like
 | 
						|
 c -s  0
 | 
						|
 ( s  c  0 ) A
 | 
						|
 0  0  1
 | 
						|
 Column rotation A G' corresponds to something like
 | 
						|
 c -s  0
 | 
						|
 A ( s  c  0 )
 | 
						|
 0  0  1
 | 
						|
 
 | 
						|
 c and s are always computed so that
 | 
						|
 ( c -s ) ( a )  =  ( * )
 | 
						|
 s  c     b       ( 0 )
 | 
						|
 
 | 
						|
 Assume rowi<rowk.
 | 
						|
 */
 | 
						|
 | 
						|
class GivensRotation {
 | 
						|
public:
 | 
						|
    int rowi;
 | 
						|
    int rowk;
 | 
						|
    btScalar c;
 | 
						|
    btScalar s;
 | 
						|
    
 | 
						|
    inline GivensRotation(int rowi_in, int rowk_in)
 | 
						|
    : rowi(rowi_in)
 | 
						|
    , rowk(rowk_in)
 | 
						|
    , c(1)
 | 
						|
    , s(0)
 | 
						|
    {
 | 
						|
    }
 | 
						|
    
 | 
						|
    inline GivensRotation(btScalar a, btScalar b, int rowi_in, int rowk_in)
 | 
						|
    : rowi(rowi_in)
 | 
						|
    , rowk(rowk_in)
 | 
						|
    {
 | 
						|
        compute(a, b);
 | 
						|
    }
 | 
						|
    
 | 
						|
    ~GivensRotation() {}
 | 
						|
    
 | 
						|
    inline void transposeInPlace()
 | 
						|
    {
 | 
						|
        s = -s;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Compute c and s from a and b so that
 | 
						|
     ( c -s ) ( a )  =  ( * )
 | 
						|
     s  c     b       ( 0 )
 | 
						|
     */
 | 
						|
    inline void compute(const btScalar a, const btScalar b)
 | 
						|
    {
 | 
						|
        btScalar d = a * a + b * b;
 | 
						|
        c = 1;
 | 
						|
        s = 0;
 | 
						|
        if (d > SIMD_EPSILON) {
 | 
						|
            btScalar sqrtd = btSqrt(d);
 | 
						|
            if (sqrtd>SIMD_EPSILON)
 | 
						|
            {
 | 
						|
              btScalar t = btScalar(1.0)/sqrtd;
 | 
						|
              c = a * t;
 | 
						|
              s = -b * t;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     This function computes c and s so that
 | 
						|
     ( c -s ) ( a )  =  ( 0 )
 | 
						|
     s  c     b       ( * )
 | 
						|
     */
 | 
						|
    inline void computeUnconventional(const btScalar a, const btScalar b)
 | 
						|
    {
 | 
						|
        btScalar d = a * a + b * b;
 | 
						|
        c = 0;
 | 
						|
        s = 1;
 | 
						|
        if (d > SIMD_EPSILON) {
 | 
						|
            btScalar t = btScalar(1.0)/btSqrt(d);
 | 
						|
            s = a * t;
 | 
						|
            c = b * t;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Fill the R with the entries of this rotation
 | 
						|
     */
 | 
						|
    inline void fill(const btMatrix3x3& R) const
 | 
						|
    {
 | 
						|
        btMatrix3x3& A = const_cast<btMatrix3x3&>(R);
 | 
						|
        A.setIdentity();
 | 
						|
        A[rowi][rowi] = c;
 | 
						|
        A[rowk][rowi] = -s;
 | 
						|
        A[rowi][rowk] = s;
 | 
						|
        A[rowk][rowk] = c;
 | 
						|
    }
 | 
						|
    
 | 
						|
    inline void fill(const btMatrix2x2& R) const
 | 
						|
    {
 | 
						|
        btMatrix2x2& A = const_cast<btMatrix2x2&>(R);
 | 
						|
        A(rowi,rowi) = c;
 | 
						|
        A(rowk,rowi) = -s;
 | 
						|
        A(rowi,rowk) = s;
 | 
						|
        A(rowk,rowk) = c;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     This function does something like
 | 
						|
     c -s  0
 | 
						|
     ( s  c  0 ) A -> A
 | 
						|
     0  0  1
 | 
						|
     It only affects row i and row k of A.
 | 
						|
     */
 | 
						|
    inline void rowRotation(btMatrix3x3& A) const
 | 
						|
    {
 | 
						|
        for (int j = 0; j < 3; j++) {
 | 
						|
            btScalar tau1 = A[rowi][j];
 | 
						|
            btScalar tau2 = A[rowk][j];
 | 
						|
            A[rowi][j] = c * tau1 - s * tau2;
 | 
						|
            A[rowk][j] = s * tau1 + c * tau2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    inline void rowRotation(btMatrix2x2& A) const
 | 
						|
    {
 | 
						|
        for (int j = 0; j < 2; j++) {
 | 
						|
            btScalar tau1 = A(rowi,j);
 | 
						|
            btScalar tau2 = A(rowk,j);
 | 
						|
            A(rowi,j) = c * tau1 - s * tau2;
 | 
						|
            A(rowk,j) = s * tau1 + c * tau2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     This function does something like
 | 
						|
     c  s  0
 | 
						|
     A ( -s  c  0 )  -> A
 | 
						|
     0  0  1
 | 
						|
     It only affects column i and column k of A.
 | 
						|
     */
 | 
						|
    inline void columnRotation(btMatrix3x3& A) const
 | 
						|
    {
 | 
						|
        for (int j = 0; j < 3; j++) {
 | 
						|
            btScalar tau1 = A[j][rowi];
 | 
						|
            btScalar tau2 = A[j][rowk];
 | 
						|
            A[j][rowi] = c * tau1 - s * tau2;
 | 
						|
            A[j][rowk] = s * tau1 + c * tau2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    inline void columnRotation(btMatrix2x2& A) const
 | 
						|
    {
 | 
						|
        for (int j = 0; j < 2; j++) {
 | 
						|
            btScalar tau1 = A(j,rowi);
 | 
						|
            btScalar tau2 = A(j,rowk);
 | 
						|
            A(j,rowi) = c * tau1 - s * tau2;
 | 
						|
            A(j,rowk) = s * tau1 + c * tau2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Multiply givens must be for same row and column
 | 
						|
     **/
 | 
						|
    inline void operator*=(const GivensRotation& A)
 | 
						|
    {
 | 
						|
        btScalar new_c = c * A.c - s * A.s;
 | 
						|
        btScalar new_s = s * A.c + c * A.s;
 | 
						|
        c = new_c;
 | 
						|
        s = new_s;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Multiply givens must be for same row and column
 | 
						|
     **/
 | 
						|
    inline GivensRotation operator*(const GivensRotation& A) const
 | 
						|
    {
 | 
						|
        GivensRotation r(*this);
 | 
						|
        r *= A;
 | 
						|
        return r;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 \brief zero chasing the 3X3 matrix to bidiagonal form
 | 
						|
 original form of H:   x x 0
 | 
						|
 x x x
 | 
						|
 0 0 x
 | 
						|
 after zero chase:
 | 
						|
 x x 0
 | 
						|
 0 x x
 | 
						|
 0 0 x
 | 
						|
 */
 | 
						|
inline void zeroChase(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
 | 
						|
{
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     x x +
 | 
						|
     0 x x
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    GivensRotation r1(H[0][0], H[1][0], 0, 1);
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     x x 0
 | 
						|
     0 x x
 | 
						|
     0 + x
 | 
						|
     Can calculate r2 without multiplying by r1 since both entries are in first two
 | 
						|
     rows thus no need to divide by sqrt(a^2+b^2)
 | 
						|
     */
 | 
						|
    GivensRotation r2(1, 2);
 | 
						|
    if (H[1][0] != 0)
 | 
						|
        r2.compute(H[0][0] * H[0][1] + H[1][0] * H[1][1], H[0][0] * H[0][2] + H[1][0] * H[1][2]);
 | 
						|
    else
 | 
						|
        r2.compute(H[0][1], H[0][2]);
 | 
						|
    
 | 
						|
    r1.rowRotation(H);
 | 
						|
    
 | 
						|
    /* GivensRotation<T> r2(H(0, 1), H(0, 2), 1, 2); */
 | 
						|
    r2.columnRotation(H);
 | 
						|
    r2.columnRotation(V);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     x x 0
 | 
						|
     0 x x
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    GivensRotation r3(H[1][1], H[2][1], 1, 2);
 | 
						|
    r3.rowRotation(H);
 | 
						|
    
 | 
						|
    // Save this till end for better cache coherency
 | 
						|
    // r1.rowRotation(u_transpose);
 | 
						|
    // r3.rowRotation(u_transpose);
 | 
						|
    r1.columnRotation(U);
 | 
						|
    r3.columnRotation(U);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief make a 3X3 matrix to upper bidiagonal form
 | 
						|
 original form of H:   x x x
 | 
						|
 x x x
 | 
						|
 x x x
 | 
						|
 after zero chase:
 | 
						|
 x x 0
 | 
						|
 0 x x
 | 
						|
 0 0 x
 | 
						|
 */
 | 
						|
inline void makeUpperBidiag(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
 | 
						|
{
 | 
						|
    U.setIdentity();
 | 
						|
    V.setIdentity();
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     x x x
 | 
						|
     x x x
 | 
						|
     0 x x
 | 
						|
     */
 | 
						|
    
 | 
						|
    GivensRotation r(H[1][0], H[2][0], 1, 2);
 | 
						|
    r.rowRotation(H);
 | 
						|
    // r.rowRotation(u_transpose);
 | 
						|
    r.columnRotation(U);
 | 
						|
    // zeroChase(H, u_transpose, V);
 | 
						|
    zeroChase(H, U, V);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief make a 3X3 matrix to lambda shape
 | 
						|
 original form of H:   x x x
 | 
						|
 *                     x x x
 | 
						|
 *                     x x x
 | 
						|
 after :
 | 
						|
 *                     x 0 0
 | 
						|
 *                     x x 0
 | 
						|
 *                     x 0 x
 | 
						|
 */
 | 
						|
inline void makeLambdaShape(btMatrix3x3& H, btMatrix3x3& U, btMatrix3x3& V)
 | 
						|
{
 | 
						|
    U.setIdentity();
 | 
						|
    V.setIdentity();
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     *                    x x 0
 | 
						|
     *                    x x x
 | 
						|
     *                    x x x
 | 
						|
     */
 | 
						|
    
 | 
						|
    GivensRotation r1(H[0][1], H[0][2], 1, 2);
 | 
						|
    r1.columnRotation(H);
 | 
						|
    r1.columnRotation(V);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     *                    x x 0
 | 
						|
     *                    x x 0
 | 
						|
     *                    x x x
 | 
						|
     */
 | 
						|
    
 | 
						|
    r1.computeUnconventional(H[1][2], H[2][2]);
 | 
						|
    r1.rowRotation(H);
 | 
						|
    r1.columnRotation(U);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     *                    x x 0
 | 
						|
     *                    x x 0
 | 
						|
     *                    x 0 x
 | 
						|
     */
 | 
						|
    
 | 
						|
    GivensRotation r2(H[2][0], H[2][1], 0, 1);
 | 
						|
    r2.columnRotation(H);
 | 
						|
    r2.columnRotation(V);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     Reduce H to of form
 | 
						|
     *                    x 0 0
 | 
						|
     *                    x x 0
 | 
						|
     *                    x 0 x
 | 
						|
     */
 | 
						|
    r2.computeUnconventional(H[0][1], H[1][1]);
 | 
						|
    r2.rowRotation(H);
 | 
						|
    r2.columnRotation(U);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief 2x2 polar decomposition.
 | 
						|
 \param[in] A matrix.
 | 
						|
 \param[out] R Robustly a rotation matrix.
 | 
						|
 \param[out] S_Sym Symmetric. Whole matrix is stored
 | 
						|
 
 | 
						|
 Polar guarantees negative sign is on the small magnitude singular value.
 | 
						|
 S is guaranteed to be the closest one to identity.
 | 
						|
 R is guaranteed to be the closest rotation to A.
 | 
						|
 */
 | 
						|
inline void polarDecomposition(const btMatrix2x2& A,
 | 
						|
                   GivensRotation& R,
 | 
						|
                   const btMatrix2x2& S_Sym)
 | 
						|
{
 | 
						|
    btScalar a = (A(0, 0) + A(1, 1)),  b = (A(1, 0) - A(0, 1));
 | 
						|
    btScalar denominator = btSqrt(a*a+b*b);
 | 
						|
    R.c = (btScalar)1;
 | 
						|
    R.s = (btScalar)0;
 | 
						|
    if (denominator > SIMD_EPSILON) { 
 | 
						|
        /*
 | 
						|
         No need to use a tolerance here because x(0) and x(1) always have
 | 
						|
         smaller magnitude then denominator, therefore overflow never happens.
 | 
						|
         In Bullet, we use a tolerance anyway.
 | 
						|
         */
 | 
						|
        R.c = a / denominator;
 | 
						|
        R.s = -b / denominator;
 | 
						|
    }
 | 
						|
    btMatrix2x2& S = const_cast<btMatrix2x2&>(S_Sym);
 | 
						|
    S = A;
 | 
						|
    R.rowRotation(S);
 | 
						|
}
 | 
						|
 | 
						|
inline void polarDecomposition(const btMatrix2x2& A,
 | 
						|
                   const btMatrix2x2& R,
 | 
						|
                   const btMatrix2x2& S_Sym)
 | 
						|
{
 | 
						|
    GivensRotation r(0, 1);
 | 
						|
    polarDecomposition(A, r, S_Sym);
 | 
						|
    r.fill(R);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief 2x2 SVD (singular value decomposition) A=USV'
 | 
						|
 \param[in] A Input matrix.
 | 
						|
 \param[out] U Robustly a rotation matrix in Givens form
 | 
						|
 \param[out] Sigma matrix of singular values sorted with decreasing magnitude. The second one can be negative.
 | 
						|
 \param[out] V Robustly a rotation matrix in Givens form
 | 
						|
 */
 | 
						|
inline void singularValueDecomposition(
 | 
						|
                           const btMatrix2x2& A,
 | 
						|
                           GivensRotation& U,
 | 
						|
                           const btMatrix2x2& Sigma,
 | 
						|
                           GivensRotation& V,
 | 
						|
                           const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
 | 
						|
{
 | 
						|
    btMatrix2x2& sigma = const_cast<btMatrix2x2&>(Sigma);
 | 
						|
    sigma.setIdentity();
 | 
						|
    btMatrix2x2 S_Sym;
 | 
						|
    polarDecomposition(A, U, S_Sym);
 | 
						|
    btScalar cosine, sine;
 | 
						|
    btScalar x = S_Sym(0, 0);
 | 
						|
    btScalar y = S_Sym(0, 1);
 | 
						|
    btScalar z = S_Sym(1, 1);
 | 
						|
    if (y == 0) {
 | 
						|
        // S is already diagonal
 | 
						|
        cosine = 1;
 | 
						|
        sine = 0;
 | 
						|
        sigma(0,0) = x;
 | 
						|
        sigma(1,1) = z;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        btScalar tau = 0.5 * (x - z);
 | 
						|
        btScalar val = tau * tau + y * y;
 | 
						|
        if (val > SIMD_EPSILON)
 | 
						|
        {
 | 
						|
        btScalar w = btSqrt(val);
 | 
						|
        // w > y > 0
 | 
						|
        btScalar t;
 | 
						|
        if (tau > 0) {
 | 
						|
            // tau + w > w > y > 0 ==> division is safe
 | 
						|
            t = y / (tau + w);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            // tau - w < -w < -y < 0 ==> division is safe
 | 
						|
            t = y / (tau - w);
 | 
						|
        }
 | 
						|
        cosine = btScalar(1) / btSqrt(t * t + btScalar(1));
 | 
						|
        sine = -t * cosine;
 | 
						|
        /*
 | 
						|
         V = [cosine -sine; sine cosine]
 | 
						|
         Sigma = V'SV. Only compute the diagonals for efficiency.
 | 
						|
         Also utilize symmetry of S and don't form V yet.
 | 
						|
         */
 | 
						|
        btScalar c2 = cosine * cosine;
 | 
						|
        btScalar csy = 2 * cosine * sine * y;
 | 
						|
        btScalar s2 = sine * sine;
 | 
						|
        sigma(0,0) = c2 * x - csy + s2 * z;
 | 
						|
        sigma(1,1) = s2 * x + csy + c2 * z;
 | 
						|
      } else
 | 
						|
      	{
 | 
						|
      		cosine = 1;
 | 
						|
        sine = 0;
 | 
						|
        sigma(0,0) = x;
 | 
						|
        sigma(1,1) = z;
 | 
						|
      	}
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Sorting
 | 
						|
    // Polar already guarantees negative sign is on the small magnitude singular value.
 | 
						|
    if (sigma(0,0) < sigma(1,1)) {
 | 
						|
        std::swap(sigma(0,0), sigma(1,1));
 | 
						|
        V.c = -sine;
 | 
						|
        V.s = cosine;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        V.c = cosine;
 | 
						|
        V.s = sine;
 | 
						|
    }
 | 
						|
    U *= V;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief 2x2 SVD (singular value decomposition) A=USV'
 | 
						|
 \param[in] A Input matrix.
 | 
						|
 \param[out] U Robustly a rotation matrix.
 | 
						|
 \param[out] Sigma Vector of singular values sorted with decreasing magnitude. The second one can be negative.
 | 
						|
 \param[out] V Robustly a rotation matrix.
 | 
						|
 */
 | 
						|
inline void singularValueDecomposition(
 | 
						|
                           const btMatrix2x2& A,
 | 
						|
                           const btMatrix2x2& U,
 | 
						|
                           const btMatrix2x2& Sigma,
 | 
						|
                           const btMatrix2x2& V,
 | 
						|
                           const btScalar tol = 64 * std::numeric_limits<btScalar>::epsilon())
 | 
						|
{
 | 
						|
    GivensRotation gv(0, 1);
 | 
						|
    GivensRotation gu(0, 1);
 | 
						|
    singularValueDecomposition(A, gu, Sigma, gv);
 | 
						|
    
 | 
						|
    gu.fill(U);
 | 
						|
    gv.fill(V);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief compute wilkinsonShift of the block
 | 
						|
 a1     b1
 | 
						|
 b1     a2
 | 
						|
 based on the wilkinsonShift formula
 | 
						|
 mu = c + d - sign (d) \ sqrt (d*d + b*b), where d = (a-c)/2
 | 
						|
 
 | 
						|
 */
 | 
						|
inline btScalar wilkinsonShift(const btScalar a1, const btScalar b1, const btScalar a2)
 | 
						|
{
 | 
						|
	btScalar d = (btScalar)0.5 * (a1 - a2);
 | 
						|
	btScalar bs = b1 * b1;
 | 
						|
	btScalar val = d * d + bs;
 | 
						|
	if (val>SIMD_EPSILON)
 | 
						|
	{
 | 
						|
		btScalar denom = btFabs(d) + btSqrt(val);
 | 
						|
 | 
						|
		btScalar mu = a2 - copySign(bs / (denom), d);
 | 
						|
		// T mu = a2 - bs / ( d + sign_d*sqrt (d*d + bs));
 | 
						|
		return mu;
 | 
						|
	}
 | 
						|
	return a2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief Helper function of 3X3 SVD for processing 2X2 SVD
 | 
						|
 */
 | 
						|
template <int t>
 | 
						|
inline void process(btMatrix3x3& B, btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V)
 | 
						|
{
 | 
						|
    int other = (t == 1) ? 0 : 2;
 | 
						|
    GivensRotation u(0, 1);
 | 
						|
    GivensRotation v(0, 1);
 | 
						|
    sigma[other] = B[other][other];
 | 
						|
    
 | 
						|
    btMatrix2x2 B_sub, sigma_sub;
 | 
						|
    if (t == 0)
 | 
						|
    {
 | 
						|
        B_sub.m_00 = B[0][0];
 | 
						|
        B_sub.m_10 = B[1][0];
 | 
						|
        B_sub.m_01 = B[0][1];
 | 
						|
        B_sub.m_11 = B[1][1];
 | 
						|
        sigma_sub.m_00 = sigma[0];
 | 
						|
        sigma_sub.m_11 = sigma[1];
 | 
						|
//        singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
 | 
						|
        singularValueDecomposition(B_sub, u, sigma_sub, v);
 | 
						|
        B[0][0] = B_sub.m_00;
 | 
						|
        B[1][0] = B_sub.m_10;
 | 
						|
        B[0][1] = B_sub.m_01;
 | 
						|
        B[1][1] = B_sub.m_11;
 | 
						|
        sigma[0] = sigma_sub.m_00;
 | 
						|
        sigma[1] = sigma_sub.m_11;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        B_sub.m_00 = B[1][1];
 | 
						|
        B_sub.m_10 = B[2][1];
 | 
						|
        B_sub.m_01 = B[1][2];
 | 
						|
        B_sub.m_11 = B[2][2];
 | 
						|
        sigma_sub.m_00 = sigma[1];
 | 
						|
        sigma_sub.m_11 = sigma[2];
 | 
						|
        //        singularValueDecomposition(B.template block<2, 2>(t, t), u, sigma.template block<2, 1>(t, 0), v);
 | 
						|
        singularValueDecomposition(B_sub, u, sigma_sub, v);
 | 
						|
        B[1][1] = B_sub.m_00;
 | 
						|
        B[2][1] = B_sub.m_10;
 | 
						|
        B[1][2] = B_sub.m_01;
 | 
						|
        B[2][2] = B_sub.m_11;
 | 
						|
        sigma[1] = sigma_sub.m_00;
 | 
						|
        sigma[2] = sigma_sub.m_11;
 | 
						|
    }
 | 
						|
    u.rowi += t;
 | 
						|
    u.rowk += t;
 | 
						|
    v.rowi += t;
 | 
						|
    v.rowk += t;
 | 
						|
    u.columnRotation(U);
 | 
						|
    v.columnRotation(V);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief Helper function of 3X3 SVD for flipping signs due to flipping signs of sigma
 | 
						|
 */
 | 
						|
inline void flipSign(int i, btMatrix3x3& U, btVector3& sigma)
 | 
						|
{
 | 
						|
    sigma[i] = -sigma[i];
 | 
						|
    U[0][i] = -U[0][i];
 | 
						|
    U[1][i] = -U[1][i];
 | 
						|
    U[2][i] = -U[2][i];
 | 
						|
}
 | 
						|
 | 
						|
inline void flipSign(int i, btMatrix3x3& U)
 | 
						|
{
 | 
						|
    U[0][i] = -U[0][i];
 | 
						|
    U[1][i] = -U[1][i];
 | 
						|
    U[2][i] = -U[2][i];
 | 
						|
}
 | 
						|
 | 
						|
inline void swapCol(btMatrix3x3& A, int i, int j)
 | 
						|
{
 | 
						|
    for (int d = 0; d < 3; ++d)
 | 
						|
        std::swap(A[d][i], A[d][j]);
 | 
						|
}
 | 
						|
/**
 | 
						|
 \brief Helper function of 3X3 SVD for sorting singular values
 | 
						|
 */
 | 
						|
inline void sort(btMatrix3x3& U, btVector3& sigma, btMatrix3x3& V, int t)
 | 
						|
{
 | 
						|
    if (t == 0)
 | 
						|
    {
 | 
						|
        // Case: sigma(0) > |sigma(1)| >= |sigma(2)|
 | 
						|
        if (btFabs(sigma[1]) >= btFabs(sigma[2])) {
 | 
						|
            if (sigma[1] < 0) {
 | 
						|
                flipSign(1, U, sigma);
 | 
						|
                flipSign(2, U, sigma);
 | 
						|
            }
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //fix sign of sigma for both cases
 | 
						|
        if (sigma[2] < 0) {
 | 
						|
            flipSign(1, U, sigma);
 | 
						|
            flipSign(2, U, sigma);
 | 
						|
        }
 | 
						|
        
 | 
						|
        //swap sigma(1) and sigma(2) for both cases
 | 
						|
        std::swap(sigma[1], sigma[2]);
 | 
						|
        // swap the col 1 and col 2 for U,V
 | 
						|
        swapCol(U,1,2);
 | 
						|
        swapCol(V,1,2);
 | 
						|
        
 | 
						|
        // Case: |sigma(2)| >= sigma(0) > |simga(1)|
 | 
						|
        if (sigma[1] > sigma[0]) {
 | 
						|
            std::swap(sigma[0], sigma[1]);
 | 
						|
            swapCol(U,0,1);
 | 
						|
            swapCol(V,0,1);
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Case: sigma(0) >= |sigma(2)| > |simga(1)|
 | 
						|
        else {
 | 
						|
            flipSign(2, U);
 | 
						|
            flipSign(2, V);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else if (t == 1)
 | 
						|
    {
 | 
						|
        // Case: |sigma(0)| >= sigma(1) > |sigma(2)|
 | 
						|
        if (btFabs(sigma[0]) >= sigma[1]) {
 | 
						|
            if (sigma[0] < 0) {
 | 
						|
                flipSign(0, U, sigma);
 | 
						|
                flipSign(2, U, sigma);
 | 
						|
            }
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        //swap sigma(0) and sigma(1) for both cases
 | 
						|
        std::swap(sigma[0], sigma[1]);
 | 
						|
        swapCol(U, 0, 1);
 | 
						|
        swapCol(V, 0, 1);
 | 
						|
        
 | 
						|
        // Case: sigma(1) > |sigma(2)| >= |sigma(0)|
 | 
						|
        if (btFabs(sigma[1]) < btFabs(sigma[2])) {
 | 
						|
            std::swap(sigma[1], sigma[2]);
 | 
						|
            swapCol(U, 1, 2);
 | 
						|
            swapCol(V, 1, 2);
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Case: sigma(1) >= |sigma(0)| > |sigma(2)|
 | 
						|
        else {
 | 
						|
            flipSign(1, U);
 | 
						|
            flipSign(1, V);
 | 
						|
        }
 | 
						|
        
 | 
						|
        // fix sign for both cases
 | 
						|
        if (sigma[1] < 0) {
 | 
						|
            flipSign(1, U, sigma);
 | 
						|
            flipSign(2, U, sigma);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 \brief 3X3 SVD (singular value decomposition) A=USV'
 | 
						|
 \param[in] A Input matrix.
 | 
						|
 \param[out] U is a rotation matrix.
 | 
						|
 \param[out] sigma Diagonal matrix, sorted with decreasing magnitude. The third one can be negative.
 | 
						|
 \param[out] V is a rotation matrix.
 | 
						|
 */
 | 
						|
inline int singularValueDecomposition(const btMatrix3x3& A,
 | 
						|
                                     btMatrix3x3& U,
 | 
						|
                                     btVector3& sigma,
 | 
						|
                                     btMatrix3x3& V,
 | 
						|
                                     btScalar tol = 128*std::numeric_limits<btScalar>::epsilon())
 | 
						|
{
 | 
						|
//    using std::fabs;
 | 
						|
    btMatrix3x3 B = A;
 | 
						|
    U.setIdentity();
 | 
						|
    V.setIdentity();
 | 
						|
    
 | 
						|
    makeUpperBidiag(B, U, V);
 | 
						|
    
 | 
						|
    int count = 0;
 | 
						|
    btScalar mu = (btScalar)0;
 | 
						|
    GivensRotation r(0, 1);
 | 
						|
    
 | 
						|
    btScalar alpha_1 = B[0][0];
 | 
						|
    btScalar beta_1 = B[0][1];
 | 
						|
    btScalar alpha_2 = B[1][1];
 | 
						|
    btScalar alpha_3 = B[2][2];
 | 
						|
    btScalar beta_2 = B[1][2];
 | 
						|
    btScalar gamma_1 = alpha_1 * beta_1;
 | 
						|
    btScalar gamma_2 = alpha_2 * beta_2;
 | 
						|
    btScalar val = alpha_1 * alpha_1 + alpha_2 * alpha_2 + alpha_3 * alpha_3 + beta_1 * beta_1 + beta_2 * beta_2;
 | 
						|
    if (val > SIMD_EPSILON)
 | 
						|
    {
 | 
						|
	    tol *= btMax((btScalar)0.5 * btSqrt(val), (btScalar)1);
 | 
						|
		}    
 | 
						|
    /**
 | 
						|
     Do implicit shift QR until A^T A is block diagonal
 | 
						|
     */
 | 
						|
    int max_count = 100;
 | 
						|
    
 | 
						|
    while (btFabs(beta_2) > tol && btFabs(beta_1) > tol
 | 
						|
           && btFabs(alpha_1) > tol && btFabs(alpha_2) > tol
 | 
						|
           && btFabs(alpha_3) > tol
 | 
						|
           && count < max_count) {
 | 
						|
        mu = wilkinsonShift(alpha_2 * alpha_2 + beta_1 * beta_1, gamma_2, alpha_3 * alpha_3 + beta_2 * beta_2);
 | 
						|
        
 | 
						|
        r.compute(alpha_1 * alpha_1 - mu, gamma_1);
 | 
						|
        r.columnRotation(B);
 | 
						|
        
 | 
						|
        r.columnRotation(V);
 | 
						|
        zeroChase(B, U, V);
 | 
						|
        
 | 
						|
        alpha_1 = B[0][0];
 | 
						|
        beta_1 = B[0][1];
 | 
						|
        alpha_2 = B[1][1];
 | 
						|
        alpha_3 = B[2][2];
 | 
						|
        beta_2 = B[1][2];
 | 
						|
        gamma_1 = alpha_1 * beta_1;
 | 
						|
        gamma_2 = alpha_2 * beta_2;
 | 
						|
        count++;
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     Handle the cases of one of the alphas and betas being 0
 | 
						|
     Sorted by ease of handling and then frequency
 | 
						|
     of occurrence
 | 
						|
     
 | 
						|
     If B is of form
 | 
						|
     x x 0
 | 
						|
     0 x 0
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    if (btFabs(beta_2) <= tol) {
 | 
						|
        process<0>(B, U, sigma, V);
 | 
						|
        sort(U, sigma, V,0);
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     If B is of form
 | 
						|
     x 0 0
 | 
						|
     0 x x
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    else if (btFabs(beta_1) <= tol) {
 | 
						|
        process<1>(B, U, sigma, V);
 | 
						|
        sort(U, sigma, V,1);
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     If B is of form
 | 
						|
     x x 0
 | 
						|
     0 0 x
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    else if (btFabs(alpha_2) <= tol) {
 | 
						|
        /**
 | 
						|
         Reduce B to
 | 
						|
         x x 0
 | 
						|
         0 0 0
 | 
						|
         0 0 x
 | 
						|
         */
 | 
						|
        GivensRotation r1(1, 2);
 | 
						|
        r1.computeUnconventional(B[1][2], B[2][2]);
 | 
						|
        r1.rowRotation(B);
 | 
						|
        r1.columnRotation(U);
 | 
						|
        
 | 
						|
        process<0>(B, U, sigma, V);
 | 
						|
        sort(U, sigma, V, 0);
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     If B is of form
 | 
						|
     x x 0
 | 
						|
     0 x x
 | 
						|
     0 0 0
 | 
						|
     */
 | 
						|
    else if (btFabs(alpha_3) <= tol) {
 | 
						|
        /**
 | 
						|
         Reduce B to
 | 
						|
         x x +
 | 
						|
         0 x 0
 | 
						|
         0 0 0
 | 
						|
         */
 | 
						|
        GivensRotation r1(1, 2);
 | 
						|
        r1.compute(B[1][1], B[1][2]);
 | 
						|
        r1.columnRotation(B);
 | 
						|
        r1.columnRotation(V);
 | 
						|
        /**
 | 
						|
         Reduce B to
 | 
						|
         x x 0
 | 
						|
         + x 0
 | 
						|
         0 0 0
 | 
						|
         */
 | 
						|
        GivensRotation r2(0, 2);
 | 
						|
        r2.compute(B[0][0], B[0][2]);
 | 
						|
        r2.columnRotation(B);
 | 
						|
        r2.columnRotation(V);
 | 
						|
        
 | 
						|
        process<0>(B, U, sigma, V);
 | 
						|
        sort(U, sigma, V, 0);
 | 
						|
    }
 | 
						|
    /**
 | 
						|
     If B is of form
 | 
						|
     0 x 0
 | 
						|
     0 x x
 | 
						|
     0 0 x
 | 
						|
     */
 | 
						|
    else if (btFabs(alpha_1) <= tol) {
 | 
						|
        /**
 | 
						|
         Reduce B to
 | 
						|
         0 0 +
 | 
						|
         0 x x
 | 
						|
         0 0 x
 | 
						|
         */
 | 
						|
        GivensRotation r1(0, 1);
 | 
						|
        r1.computeUnconventional(B[0][1], B[1][1]);
 | 
						|
        r1.rowRotation(B);
 | 
						|
        r1.columnRotation(U);
 | 
						|
        
 | 
						|
        /**
 | 
						|
         Reduce B to
 | 
						|
         0 0 0
 | 
						|
         0 x x
 | 
						|
         0 + x
 | 
						|
         */
 | 
						|
        GivensRotation r2(0, 2);
 | 
						|
        r2.computeUnconventional(B[0][2], B[2][2]);
 | 
						|
        r2.rowRotation(B);
 | 
						|
        r2.columnRotation(U);
 | 
						|
        
 | 
						|
        process<1>(B, U, sigma, V);
 | 
						|
        sort(U, sigma, V, 1);
 | 
						|
    }
 | 
						|
    
 | 
						|
    return count;
 | 
						|
}
 | 
						|
#endif /* btImplicitQRSVD_h */
 |