ShQuaternionImpl.hpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright 2003-2006 Serious Hack Inc.
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, 
00018 // MA  02110-1301, USA
00020 #include "ShQuaternion.hpp"
00021 
00022 namespace SH {
00023 template<ShBindingType B, typename T>
00024 ShQuaternion<B, T>::ShQuaternion() 
00025 {
00026   if (B == SH_TEMP) 
00027     {
00028       m_data = ShVector4f(1.0, 0.0, 0.0, 0.0);
00029       //m_data.setUnit(true);
00030     }
00031 }
00032 
00033 template<ShBindingType B, typename T>
00034 template<ShBindingType B2>
00035 ShQuaternion<B, T>::ShQuaternion(const ShQuaternion<B2, T>& other)
00036   : m_data(other.getVector())
00037 {
00038 }
00039 
00040 template<ShBindingType B, typename T>
00041 template<ShBindingType B2>
00042 ShQuaternion<B, T>::ShQuaternion(const ShAttrib<4, B2, T, SH_VECTOR>& values)
00043   : m_data(values)
00044 {
00045 }
00046 
00047 template<ShBindingType B, typename T>
00048 template<ShBindingType B2, ShBindingType B3>   
00049 ShQuaternion<B, T>::ShQuaternion(const ShAttrib<1, B2, T>& angle, 
00050                                  const ShAttrib<3, B3, T, SH_VECTOR>& axis)
00051 {
00052   m_data(0) = cos(angle/2.0);
00053   m_data(1,2,3) = SH::normalize(axis);
00054   m_data(1,2,3) *= sin(angle/2.0);
00055   //m_data.setUnit(true);
00056 }
00057 
00058 template<ShBindingType B, typename T>
00059 template<ShBindingType B2>
00060 ShQuaternion<B, T>::ShQuaternion(const ShMatrix<4, 4, B2, T>& mat)
00061 {
00062   ShAttrib1f trace = 1.0 + mat[0](0) + mat[1](1) + mat[2](2);
00063   trace = (trace >= 0.0)*trace + (trace < 0.0)*0.0;
00064   ShAttrib1f c0 = (trace > 0.001);
00065   ShAttrib1f c1 = ((mat[0](0) > mat[1](1))*(mat[0](0) > mat[2](2)));
00066   ShAttrib1f c2 = ( mat[1](1) > mat[2](2) );
00067   ShVector4f res0, res1, res2, res3;
00068   ShAttrib1f S0 = sqrt(trace) * 2.0;
00069   S0 += (S0 == 0.0)*1.0;
00070   
00071   res0(0) = 0.25 * S0;
00072   res0(1) = (mat[1](2) - mat[2](1)) / S0;
00073   res0(2) = (mat[2](0) - mat[0](2)) / S0;
00074   res0(3) = (mat[0](1) - mat[1](0)) / S0;
00075   
00076   trace = 1.0 + mat[0](0) - mat[1](1) - mat[2](2);
00077   trace = (trace >= 0.0)*trace + (trace < 0.0)*0.0;
00078   ShAttrib1f S1 = sqrt(trace) * 2.0;
00079   S1 += (S1 == 0.0)*1.0;
00080   
00081   res1(0) = (mat[2](1) - mat[1](2)) / S1;
00082   res1(1) = 0.25 * S1;
00083   res1(2) = (mat[0](1) + mat[1](0)) / S1;
00084   res1(3) = (mat[2](0) + mat[0](2)) / S1;
00085   
00086   trace = 1.0 - mat[0](0) + mat[1](1) - mat[2](2);
00087   trace = (trace >= 0.0)*trace + (trace < 0.0)*0.0;
00088   ShAttrib1f S2 = sqrt(trace) * 2.0;
00089   S2 += (S2 == 0.0)*1.0;
00090   
00091   res2(0) = (mat[2](0) - mat[0](2)) / S2;
00092   res2(1) = (mat[0](1) + mat[1](0)) / S2;
00093   res2(2) = 0.25 * S2;
00094   res2(3) = (mat[1](2) + mat[2](1)) / S2;
00095   
00096   trace = 1.0 - mat[0](0) - mat[1](1) + mat[2](2);
00097   trace = (trace >= 0.0)*trace + (trace < 0.0)*0.0;
00098   ShAttrib1f S3 = sqrt(trace) * 2.0;
00099   S3 += (S3 == 0.0)*1.0;
00100   
00101   res3(0) = (mat[1](0) - mat[0](1)) / S3;
00102   res3(1) = (mat[2](0) + mat[0](2)) / S3;
00103   res3(2) = (mat[1](2) + mat[2](1)) / S3;
00104   res3(3) = 0.25 * S3;
00105   
00106   m_data = c0*res0 + 
00107     (c0 == 0.0)*(c1*res1 + (c1 == 0.0)*(c2*res2 + (c2 == 0.0)*res3));
00108   //m_data.setUnit(true);
00109 }
00110 
00111 template<ShBindingType B, typename T>
00112 std::ostream& operator<<(std::ostream& out, const ShQuaternion<B, T>& q)
00113 {
00114   float vals[4];
00115   q.m_data.getValues(vals);
00116   out << "ShQuaternion: " << vals[0] << " " << vals[1] << " " << vals[2] 
00117       << " " << vals[3];
00118   return out;
00119 }
00120 
00121 template<ShBindingType B, typename T>
00122 template<ShBindingType B2>
00123 ShQuaternion<B, T>& 
00124 ShQuaternion<B, T>::operator=(const ShQuaternion<B2, T>& other) 
00125 {
00126   m_data = other.getVector();
00127   return *this;
00128 }
00129 
00130 template<ShBindingType B, typename T>
00131 template<ShBindingType B2>
00132 ShQuaternion<B, T>& 
00133 ShQuaternion<B, T>::operator+=(const ShQuaternion<B2, T>& right) 
00134 {
00135   m_data += right.getVector();
00136   return *this;
00137 }
00138 
00139 template<ShBindingType B, typename T>
00140 template<ShBindingType B2>
00141 ShQuaternion<B, T>& 
00142 ShQuaternion<B, T>::operator-=(const ShQuaternion<B2, T>& right) 
00143 {
00144   m_data -= right.getVector();
00145   return *this;
00146 }
00147 
00148 template<ShBindingType B, typename T>
00149 template<ShBindingType B2>
00150 ShQuaternion<B, T>& 
00151 ShQuaternion<B, T>::operator*=(const ShQuaternion<B2, T>& right) 
00152 {
00153   ShVector4f result;
00154   ShVector4f rightData = right.getVector();
00155   result(0) = 
00156     m_data(0)*rightData(0) - SH::dot(m_data(1,2,3), rightData(1,2,3));
00157   result(1,2,3) = 
00158     m_data(0)*rightData(1,2,3) + rightData(0)*m_data(1,2,3) + 
00159     cross(m_data(1,2,3), rightData(1,2,3));
00160 
00161   //result.setUnit(m_data.isUnit() && rightData.isUnit());
00162   m_data = result;
00163   return *this;
00164 }
00165 
00166 template<ShBindingType B, typename T>
00167 template<ShBindingType B2>
00168 ShQuaternion<B, T>& 
00169 ShQuaternion<B, T>::operator*=(const ShAttrib<1, B2, T>& right) 
00170 {
00171   m_data = m_data*right;
00172   return *this;
00173 }
00174 
00175 template<ShBindingType B, typename T>
00176 template<ShBindingType B2>
00177 ShQuaternion<B, T>& 
00178 ShQuaternion<B, T>::operator*=(const ShAttrib<3, B2, T, SH_VECTOR>& right) 
00179 {
00180   ShVector4f v;
00181   v(0) = 0.0;
00182   v(1,2,3) = right;
00183   //v.setUnit(right.isUnit());
00184   *this *= ShQuaternionf(v);
00185   return *this;
00186 }
00187 
00188 template<ShBindingType B, typename T>
00189 template<ShBindingType B2>
00190 ShQuaternion<B, T>& 
00191 ShQuaternion<B, T>::operator*=(const ShAttrib<3, B2, T, SH_NORMAL>& right) 
00192 {
00193   ShVector4f v;
00194   v(0) = 0.0;
00195   v(1,2,3) = right;
00196   //v.setUnit(right.isUnit());
00197   *this *= ShQuaternionf(v);
00198   return *this;
00199 }
00200 
00201 template<ShBindingType B, typename T>
00202 template<ShBindingType B2>
00203 ShAttrib<1, SH_TEMP, T> 
00204 ShQuaternion<B, T>::dot(const ShQuaternion<B2, T>& q) const 
00205 {
00206   return SH::dot(m_data, q.getVector());
00207 }
00208 
00209 template<ShBindingType B, typename T>
00210 ShQuaternion<SH_TEMP, T> ShQuaternion<B, T>::conjugate() const 
00211 {
00212   ShVector4f conjData;
00213   conjData(0) = m_data(0);
00214   conjData(1, 2, 3) = -m_data(1, 2, 3);
00215   //conjData.setUnit(m_data.isUnit());
00216 
00217   return ShQuaternion<SH_TEMP>(conjData);
00218 }
00219 
00220 template<ShBindingType B, typename T>
00221 ShQuaternion<SH_TEMP, T> ShQuaternion<B, T>::inverse() const 
00222 {
00223   //  if (m_data.isUnit()) {
00224   //    return conjugate();
00225   //  } else {
00226   ShAttrib1f norm = SH::dot(m_data, m_data); 
00227   return conjugate() * (1.0 / norm);
00228   //  }
00229 }
00230 
00231 template<ShBindingType B, typename T>
00232 ShMatrix<4, 4, SH_TEMP, T> ShQuaternion<B, T>::getMatrix() const
00233 {
00234   SH::ShMatrix4x4f m;
00235   ShAttrib4f x = m_data(1,1,1,1) * m_data(1,2,3,0);
00236   ShAttrib4f y = m_data(2,2,2,2) * m_data(0,2,3,0);
00237   ShAttrib4f z = m_data(3,3,3,3) * m_data(0,0,3,0);
00238 
00239   m[0](0) = 1 - 2 * (y(1) + z(2));
00240   m[1](0) = 2 * (x(1) - z(3));
00241   m[2](0) = 2 * (x(2) + y(3));
00242 
00243   m[0](1) = 2 * (x(2) + z(3));
00244   m[1](1) = 1 - 2 * (x(0) + z(2));
00245   m[2](1) = 2 * (y(2) - x(3));
00246 
00247   m[0](2) = 2 * (x(2) - y(3));
00248   m[1](2) = 2 * (y(2) + x(3));
00249   m[2](2) = 1 - 2 * (x(0) + y(1));
00250 
00251   return m;
00252 }
00253 
00254 template<ShBindingType B, typename T>
00255 ShAttrib<4, SH_TEMP, T, SH_VECTOR> ShQuaternion<B, T>::getVector() const
00256 {
00257   return m_data;
00258 }
00259 
00260 template<ShBindingType B, typename T>
00261 template<ShBindingType B2>
00262 ShQuaternion<SH_TEMP, T> 
00263 ShQuaternion<B, T>::operator+(const ShQuaternion<B2, T>& q)
00264 {
00265   ShQuaternion<B, T> r = *this;
00266   return (r += q);
00267 }
00268 
00269 template<ShBindingType B, typename T>
00270 template<ShBindingType B2>
00271 ShQuaternion<SH_TEMP, T> 
00272 ShQuaternion<B, T>::operator-(const ShQuaternion<B2, T>& q)
00273 {
00274   ShQuaternion<B, T> r = *this;
00275   return (r -= q);
00276 }
00277   
00278 template<ShBindingType B, typename T>
00279 template<ShBindingType B2>
00280 ShQuaternion<SH_TEMP, T> 
00281 ShQuaternion<B, T>::operator*(const ShQuaternion<B2, T>& q)
00282 {
00283   ShQuaternion<B, T> r = *this;
00284   return (r *= q);
00285 }
00286 
00287 template<ShBindingType B, typename T>
00288 template<ShBindingType B2>
00289 ShQuaternion<SH_TEMP, T> 
00290 ShQuaternion<B, T>::operator*(const ShAttrib<1, B2, T>& c)
00291 {
00292   ShQuaternion<B, T> r = *this;
00293   return (r *= c);
00294 }
00295 
00296 template<ShBindingType B, typename T>
00297 template<ShBindingType B2>
00298 ShQuaternion<SH_TEMP, T> 
00299 ShQuaternion<B, T>::operator*(const ShAttrib<3, B2, T, SH_VECTOR>& v)
00300 {
00301   ShQuaternion<B, T> r = *this;
00302   return (r *= v);
00303 }
00304 
00305 template<ShBindingType B, typename T>
00306 template<ShBindingType B2>
00307 ShQuaternion<SH_TEMP, T> 
00308 ShQuaternion<B, T>::operator*(const ShAttrib<3, B2, T, SH_NORMAL>& v)
00309 {
00310   ShQuaternion<B, T> r = *this;
00311   return (r *= v);
00312 }
00313 
00314 template<ShBindingType B, typename T>
00315 void ShQuaternion<B, T>::normalize()
00316 {
00317   m_data = SH::normalize(m_data);
00318 }
00319 
00320 template<ShBindingType B, typename T>
00321 void ShQuaternion<B, T>::setUnit(bool flag)
00322 {
00323   //m_data.setUnit(flag);
00324 }
00325 
00326 template<ShBindingType B, typename T>
00327 void ShQuaternion<B, T>::getValues(HostType values[]) const
00328 {
00329   m_data.getValues(values);
00330 }
00331 
00332 template<ShBindingType B, typename T, ShBindingType B2>
00333 ShQuaternion<SH_TEMP, T> 
00334 operator*(const ShAttrib<1, B2, T>& c, const ShQuaternion<B, T>& q)
00335 {
00336   ShQuaternion<B, T> r = q;
00337   return (r *= c);
00338 }
00339 
00340 template<ShBindingType B1, ShBindingType B2, typename T>
00341 extern ShQuaternion<SH_TEMP, T>
00342 slerp(const ShQuaternion<B1, T>& q1, const ShQuaternion<B2, T>& q2, const ShAttrib1f& t)
00343 {
00344   //TODO::q1 and q2 must be unit quaternions, we cannot call normalize here
00345   //since it's not a const function.
00346   //TODO: when cosTheta is 1 or -1, we need to fallback to linear interpolation
00347   //not sure how to implement this efficiently yet
00348   ShAttrib<1, SH_TEMP, T> cosTheta = q1.dot(q2);
00349   ShAttrib<1, SH_TEMP, T> sinTheta = sqrt(1.0 - cosTheta*cosTheta);
00350   
00351   ShQuaternion<B2, T> q2prime = (cosTheta >= 0.0)*q2 - (cosTheta < 0.0)*q2;
00352   ShAttrib<1, SH_TEMP, T> theta = asin(sinTheta);
00353 
00354   return (sin((1.0 - t)*theta)/sinTheta)*q1 + (sin(t*theta)/sinTheta)*q2prime;
00355 }
00356 
00357 template<ShBindingType B, typename T>
00358 std::string ShQuaternion<B, T>::name() const
00359 {
00360   return m_data.name();
00361 }
00362 
00363 template<ShBindingType B, typename T>
00364 void ShQuaternion<B, T>::name(const std::string& name)
00365 {
00366   m_data.name(name);
00367 }
00368 
00369 
00370 }

Generated on Thu Feb 16 14:51:37 2006 for Sh by  doxygen 1.4.6