quaternion.cpp

Go to the documentation of this file.
00001 /*
00002     RenderStack  Support library for OpenGL 3+
00003     Copyright (C) 2010  Timo Suoranta
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Lesser General Public
00007     License as published by the Free Software Foundation; either
00008     version 2.1 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public
00016     License along with this library; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 */
00019 
00027 #include "renderstack/matrix.hpp"
00028 #include "renderstack/quaternion.hpp"
00029 
00030 namespace renderstack {
00031 
00032 vec3 quaternion::hpb() const
00033 {
00034     float   sqx = x * x;
00035     float   sqy = y * y;
00036     float   sqz = z * z;
00037 
00038     float   singularity_test        = x * y + z * w;
00039     int     north_pole_singularity  = singularity_test >  (0.5f - RS_EPSILON);
00040     int     south_pole_singularity  = singularity_test < -(0.5f - RS_EPSILON);
00041 
00042     if(north_pole_singularity)
00043     {
00044         return vec3(
00045             -2.0f * atan2f(x, w),
00046             RS_HALF_PI,
00047             0.0f
00048         );
00049     }
00050 
00051     if(south_pole_singularity)
00052     {
00053         return vec3(
00054             2.0f * atan2f(x, w),
00055             RS_HALF_PI,
00056             0
00057         );
00058     }
00059     return vec3(
00060         -atan2f(2.0f * y * w - x * z, 1.0f - 2.0f * (sqy - sqz)),
00061          asinf (2.0f * x * y + z * w),
00062         -atan2f(2.0f * x * w - y * z, 1.0f - 2.0f * (sqx - sqz))
00063     );
00064 }
00065 
00066 
00067 vec3 quaternion::view_axis() const
00068 {
00069     float x2 = 2.0f * x;
00070     float y2 = 2.0f * y;
00071     float z2 = 2.0f * z;
00072     float xx = x * x2;
00073     float xz = x * z2;
00074     float yy = y * y2;
00075     float yz = y * z2;
00076     float wx = w * x2;
00077     float wy = w * y2;
00078 
00079     return vec3(
00080         xz + wy,
00081         yz - wx,
00082         1.0f - (xx + yy)
00083     );
00084 }
00085 
00086 
00087 vec3 quaternion::up_axis() const
00088 {
00089     float x2 = 2.0f * x;
00090     float y2 = 2.0f * y;
00091     float z2 = 2.0f * z;
00092     float xx = x * x2;
00093     float xy = x * y2;
00094     float yz = y * z2;
00095     float zz = y * z2;
00096     float wx = w * x2;
00097     float wz = w * z2;
00098 
00099     return vec3(
00100         xy - wz,
00101         1.0f - (xx + zz),
00102         yz + wx
00103     );
00104 }
00105 
00106 
00107 vec3 quaternion::right_axis() const 
00108 {
00109     float y2 = 2.0f * y;
00110     float z2 = 2.0f * z;
00111     float xy = x * y2;
00112     float xz = x * z2;
00113     float yy = y * y2;
00114     float zz = z * z2;
00115     float wy = w * y2;
00116     float wz = w * z2;
00117 
00118     return vec3(
00119         1.0f - (yy + zz),
00120         xy + wz,
00121         xz - wy
00122     );
00123 }
00124 
00125 
00126 /*  Matrix should be orthonormalized  */ 
00127 quaternion::quaternion(matrix const &mat)
00128 {
00129     /*  Check the sum of the diagonal  */ 
00130     float tr = mat.m[0][0] + mat.m[1][1] + mat.m[2][2];
00131 
00132     if(tr > RS_EPSILON /*1e-6f*/ )
00133     {
00134         /*  The sum is positive  */ 
00135         float s = sqrtf(tr + 1.0f);
00136         w = 0.5f * s;
00137         s = 0.5f / s;
00138         x = (mat.m[1][2] - mat.m[2][1]) * s;
00139         y = (mat.m[2][0] - mat.m[0][2]) * s;
00140         z = (mat.m[0][1] - mat.m[1][0]) * s;
00141     }
00142     else
00143     {
00144         /*  The sum is negative  */ 
00145         float *q[3] = {&y, &z, &x};
00146         int const n_index[3] = {1, 2, 0};
00147         int i = 0;
00148         if(mat.m[1][1] > mat.m[i][i]) i = 1;
00149         if(mat.m[2][2] > mat.m[i][i]) i = 2;
00150         int j = n_index[i];
00151         int k = n_index[j];
00152 
00153         float s = sqrtf(
00154             mat.m[i][i] - (mat.m[j][j] + mat.m[k][k]) + 1.0f
00155         );
00156         *q[i] = 0.5f * s;
00157         if(s != 0)
00158         {
00159             s = 0.5f / s;
00160         }
00161         *q[j] = (mat.m[i][j] + mat.m[j][i]) * s;
00162         *q[k] = (mat.m[i][k] + mat.m[k][i]) * s;
00163         w     = (mat.m[j][k] + mat.m[k][j]) * s;
00164     }
00165 }
00166 
00167 quaternion quaternion::operator*(quaternion const &q2) const
00168 {
00169     float E   = (x + z) * (q2.x + q2.y);
00170     float F   = (z - x) * (q2.x - q2.y);
00171     float G   = (w + y) * (q2.w - q2.z);
00172     float H   = (w - y) * (q2.w + q2.z);
00173     float A   = F - E;
00174     float B   = F + E;
00175     float GmH = G - H;
00176     float GpH = G + H;
00177 
00178     return quaternion(
00179         (w + x) * (q2.w + q2.x) + 0.5f * (A - GpH),
00180         (w - x) * (q2.y + q2.z) + 0.5f * (B + GmH),
00181         (y + z) * (q2.w - q2.x) + 0.5f * (B - GmH),
00182         (z - y) * (q2.y - q2.z) + 0.5f * (A + GpH)
00183     );
00184 }
00185 
00186 }
00187 
Generated on Sun Apr 11 12:23:08 2010 for RenderStack by  doxygen 1.6.3