PolarDecompose.h

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #ifndef SOFA_HELPER_POLARDECOMPOSE_H
00028 #define SOFA_HELPER_POLARDECOMPOSE_H
00029 
00030 #include <sofa/defaulttype/Mat.h>
00031 
00032 namespace sofa
00033 {
00034 
00035 namespace helper
00036 {
00037 
00038 /**** FROM Decompose.c ****/
00039 /* Ken Shoemake, 1993     */
00040 
00041 /******* Matrix Preliminaries *******/
00042 
00044 template<class Real>
00045 void adjoint_transpose(const defaulttype::Mat<3,3,Real>& M, defaulttype::Mat<3,3,Real>& MadjT)
00046 {
00047     MadjT[0] = cross(M[1],M[2]);
00048     MadjT[1] = cross(M[2],M[0]);
00049     MadjT[2] = cross(M[0],M[1]);
00050 }
00051 
00053 template<class Real>
00054 Real norm_inf(const defaulttype::Mat<3,3,Real>& M)
00055 {
00056     Real sum, max = 0;
00057     for (int i=0;i<3;i++)
00058     {
00059         sum = (Real)(fabs(M[i][0])+fabs(M[i][1])+fabs(M[i][2]));
00060         if (max<sum) max = sum;
00061     }
00062     return max;
00063 }
00064 
00066 template<class Real>
00067 Real norm_one(const defaulttype::Mat<3,3,Real>& M)
00068 {
00069     Real sum, max = 0;
00070     for (int i=0;i<3;i++)
00071     {
00072         sum = (Real)(fabs(M[0][i])+fabs(M[1][i])+fabs(M[2][i]));
00073         if (max<sum) max = sum;
00074     }
00075     return max;
00076 }
00077 
00079 template<class Real>
00080 int find_max_col(const defaulttype::Mat<3,3,Real>& M)
00081 {
00082     Real abs, max = 0;
00083     int col = -1;
00084     for (int i=0; i<3; i++)
00085         for (int j=0; j<3; j++) {
00086             abs = M[i][j]; if (abs<0.0) abs = -abs;
00087             if (abs>max) {max = abs; col = j;}
00088         }
00089     return col;
00090 }
00091 
00093 template<class Real>
00094 void make_reflector(const defaulttype::Vec<3,Real>& v, defaulttype::Vec<3,Real>& u)
00095 {
00096     Real s = (Real)sqrt(dot(v, v));
00097     u[0] = v[0]; u[1] = v[1];
00098     u[2] = v[2] + ((v[2]<0.0) ? -s : s);
00099     s = (Real)sqrt(2.0/dot(u, u));
00100     u[0] = u[0]*s; u[1] = u[1]*s; u[2] = u[2]*s;
00101 }
00102 
00104 template<class Real>
00105 void reflect_cols(defaulttype::Mat<3,3,Real>& M, const defaulttype::Vec<3,Real>& u)
00106 {
00107     for (int i=0; i<3; i++)
00108     {
00109         Real s = u[0]*M[0][i] + u[1]*M[1][i] + u[2]*M[2][i];
00110         for (int j=0; j<3; j++)
00111             M[j][i] -= u[j]*s;
00112     }
00113 }
00115 template<class Real>
00116 void reflect_rows(defaulttype::Mat<3,3,Real>& M, const defaulttype::Vec<3,Real>& u)
00117 {
00118     for (int i=0; i<3; i++)
00119     {
00120         Real s = dot(u, M[i]);
00121         for (int j=0; j<3; j++)
00122             M[i][j] -= u[j]*s;
00123     }
00124 }
00125 
00127 template<class Real>
00128 void do_rank1(defaulttype::Mat<3,3,Real>& M, defaulttype::Mat<3,3,Real>& Q)
00129 {
00130     defaulttype::Vec<3,Real> v1, v2;
00131     Real s;
00132     int col;
00133     Q.identity();
00134     /* If rank(M) is 1, we should find a non-zero column in M */
00135     col = find_max_col(M);
00136     if (col<0) return; /* Rank is 0 */
00137     v1[0] = M[0][col]; v1[1] = M[1][col]; v1[2] = M[2][col];
00138     make_reflector(v1, v1); reflect_cols(M, v1);
00139     v2[0] = M[2][0]; v2[1] = M[2][1]; v2[2] = M[2][2];
00140     make_reflector(v2, v2); reflect_rows(M, v2);
00141     s = M[2][2];
00142     if (s<0.0) Q[2][2] = -1.0;
00143     reflect_cols(Q, v1); reflect_rows(Q, v2);
00144 }
00145 
00147 template<class Real>
00148 void do_rank2(defaulttype::Mat<3,3,Real>& M, defaulttype::Mat<3,3,Real>& MadjT, defaulttype::Mat<3,3,Real>& Q)
00149 {
00150     defaulttype::Vec<3,Real> v1, v2;
00151     Real w, x, y, z, c, s, d;
00152     int col;
00153     /* If rank(M) is 2, we should find a non-zero column in MadjT */
00154     col = find_max_col(MadjT);
00155     if (col<0) {do_rank1(M, Q); return;} /* Rank<2 */
00156     v1[0] = MadjT[0][col]; v1[1] = MadjT[1][col]; v1[2] = MadjT[2][col];
00157     make_reflector(v1, v1); reflect_cols(M, v1);
00158     v2 = cross(M[0], M[1]);
00159     make_reflector(v2, v2); reflect_rows(M, v2);
00160     w = M[0][0]; x = M[0][1]; y = M[1][0]; z = M[1][1];
00161     if (w*z>x*y)
00162     {
00163         c = z+w; s = y-x; d = sqrt(c*c+s*s); c = c/d; s = s/d;
00164         Q[0][0] = Q[1][1] = c; Q[0][1] = -(Q[1][0] = s);
00165     }
00166     else
00167     {
00168         c = z-w; s = y+x; d = sqrt(c*c+s*s); c = c/d; s = s/d;
00169         Q[0][0] = -(Q[1][1] = c); Q[0][1] = Q[1][0] = s;
00170     }
00171     Q[0][2] = Q[2][0] = Q[1][2] = Q[2][1] = 0.0; Q[2][2] = 1.0;
00172     reflect_cols(Q, v1); reflect_rows(Q, v2);
00173 }
00174 
00175 /******* Polar Decomposition *******/
00176 
00177 /* Polar Decomposition of 3x3 matrix,
00178  * M = QS.  See Nicholas Higham and Robert S. Schreiber,
00179  * Fast Polar Decomposition of An Arbitrary Matrix,
00180  * Technical Report 88-942, October 1988,
00181  * Department of Computer Science, Cornell University.
00182  */
00183 template<class Real>
00184 Real polar_decomp(const defaulttype::Mat<3,3,Real>& M, defaulttype::Mat<3,3,Real>& Q, defaulttype::Mat<3,3,Real>& S)
00185 {
00186     defaulttype::Mat<3,3,Real> Mk, MadjTk, Ek;
00187     Real det, M_one, M_inf, MadjT_one, MadjT_inf, E_one, gamma, g1, g2;
00188     Mk.transpose(M);
00189     M_one = norm_one(Mk);  M_inf = norm_inf(Mk);
00190     do
00191     {
00192         adjoint_transpose(Mk, MadjTk);
00193         det = dot(Mk[0], MadjTk[0]);
00194         if (det==0.0)
00195         {
00196             do_rank2(Mk, MadjTk, Mk);
00197             break;
00198         }
00199         MadjT_one = norm_one(MadjTk); MadjT_inf = norm_inf(MadjTk);
00200         gamma = (Real)sqrt(sqrt((MadjT_one*MadjT_inf)/(M_one*M_inf))/fabs(det));
00201         g1 = gamma*((Real)0.5);
00202         g2 = ((Real)0.5)/(gamma*det);
00203         Ek = Mk;
00204         Mk = Mk*g1 + MadjTk*g2;
00205         Ek -= Mk;
00206         E_one = norm_one(Ek);
00207         M_one = norm_one(Mk);  M_inf = norm_inf(Mk);
00208     }
00209     while (E_one>(M_one*1.0e-6));
00210     Q.transpose(Mk);
00211     S = Mk*M;
00212     for (int i=0; i<3; i++)
00213         for (int j=i+1; j<3; j++)
00214             S[i][j] = S[j][i] = ((Real)0.5)*(S[i][j]+S[j][i]);
00215     return (det);
00216 
00217 }
00218 
00219 
00220 } // namespace helper
00221 
00222 } // namespace sofa
00223 
00224 #endif

Generated on Sun Nov 23 02:29:30 2008 for Sofa by  doxygen 1.5.7.1