メインページ | ネームスペース一覧 | クラス階層 | 構成 | Directories | ファイル一覧 | ネームスペースメンバ | 構成メンバ | ファイルメンバ | 関連ページ

TQuaternion.h

00001 #ifndef TQUATERNION_H
00002 #define TQUATERNION_H
00003 
00004 #include <Base/TinyVec.h>
00005 #include <Base/TinyMat.h>
00006 
00007 namespace Spr{;
00008 
00009 /** そのうち入れたい,オイラー角への変換.
00010 heading = atan2(2*qy*qw-2*qx*qz , 1 - 2*qy2 - 2*qz2)
00011 attitude = asin(2*qx*qy + 2*qz*qw) 
00012 bank = atan2(2*qx*qw-2*qy*qz , 1 - 2*qx2 - 2*qz2)
00013 
00014 except when qx*qy + qz*qw = 0.5 (north pole)
00015 which gives:
00016 heading = 2 * atan2(x,w)
00017 bank = 0
00018 and when qx*qy + qz*qw = -0.5 (south pole)
00019 which gives:
00020 heading = -2 * atan2(x,w)
00021 bank = 0 
00022 */
00023 
00024 //-----------------------------------------------------------------------------
00025 //      TQuaternion
00026 ///     4元数クラス.
00027 template<class ET>
00028 class TQuaternion:public PTM::TVectorBase<DIMENC(4), TVecDesc<TQuaternion<ET>, ET> >{
00029 public:
00030     typedef TVecDesc<TQuaternion<ET>, ET> desc;
00031     typedef PTM::TVectorBase<DIMENC(4), desc> base_type;
00032     /// 継承されない基本的なメンバの定義.   @see ::DEF_TVECTOR_BASIC_MEMBER
00033     DEF_TVECTOR_BASIC_MEMBER(TQuaternion);
00034     union{
00035         ET data[4];
00036         struct{
00037             ET w,x,y,z;
00038         };
00039     };
00040     /// 要素のアクセス
00041     ET& item_impl(size_t i){ return data[i]; }
00042     /// 要素のアクセス
00043     const ET& item_impl(size_t i) const { return data[i]; }
00044     /// ストライド
00045     size_t stride_impl() const { return 1; }
00046 
00047     /// 3次元の部分ベクトル
00048     typedef PTM::TSubVector<3, desc> vector_type;
00049     ///@name 変数アクセス
00050     //@{
00051     /// w成分
00052     const element_type& W() const { return w; }
00053     /// x成分
00054     const element_type& X() const { return x; }
00055     /// y成分
00056     const element_type& Y() const { return y; }
00057     /// z成分
00058     const element_type& Z() const { return z; }
00059     ///
00060     const vector_type& V() const {return sub_vector(vector_type());}
00061 
00062     /// z成分
00063     element_type& W(){ return w; }
00064     /// x成分
00065     element_type& X(){ return x; }
00066     /// y成分
00067     element_type& Y(){ return y; }
00068     /// z成分
00069     element_type& Z(){ return z; }
00070     /// 
00071     vector_type& V() {return sub_vector(1,vector_type());}
00072     /// 回転ベクトル.0..PIの範囲で回転ベクトルを返す.
00073     TVec3<ET> rotation_half() {
00074         TQuaternion<ET> tmp;
00075         if (tmp.W() < 0) tmp = -*this;
00076         else tmp = *this;
00077         TVec3<ET> r;
00078         if (tmp.W() > 1) tmp.W() = 1;
00079         ET theta = (ET)( acos(tmp.W()) * 2 );
00080         r = tmp.sub_vector(1, vector_type());
00081         ET len = r.norm();
00082         if (len > 1e-20){
00083             r = r/len;
00084         }
00085         r *= theta;
00086         return r;
00087     }
00088     /// 回転ベクトル2. 0..2PIの範囲で回転ベクトルを返す.  angle から関数名変更
00089     TVec3<ET> rotation() {
00090         //  W() = cos(theta/2) なので
00091         TVec3<ET> r;
00092         if (W() < -1) W() = -1;
00093         if (W() > 1) W() = 1;
00094         ET theta = (ET)( acos(W()) * 2 );
00095         r = sub_vector(1, vector_type());
00096         ET len = r.norm();
00097         if (len > 1e-20){
00098             r = r/len;
00099         }
00100         r *= theta;
00101         return r;
00102     }
00103 
00104     /// 回転軸
00105     TVec3<ET> axis(){
00106         TVec3<ET> r;
00107         r = sub_vector(1, vector_type());
00108         ET len = r.norm();
00109         if (len > 1e-20){
00110             r = r/len;
00111         }
00112         return r;
00113     }
00114 
00115     /// 回転角度 (angleに関数名を変更する予定)
00116     ET theta(){
00117         return (ET)( acos(W()) * 2 );
00118     }
00119     //@}
00120 
00121     ///@name 初期化・構築
00122     //@{
00123     /// コンストラクタ
00124     void set_default(){ W() = 1; X() = 0; Y() = 0; Z() = 0;}
00125 
00126     /// コンストラクタ
00127     TQuaternion(element_type wi, element_type xi, element_type yi, element_type zi){ W() = wi; X() = xi; Y() = yi; Z() = zi;}
00128     template <class B>
00129     void InitDirect(element_type a, const PTM::TVectorBase<DIMENC(3), B> v){
00130         W() = a; V() = v;
00131     }
00132     template <class B>
00133     void InitDirect(element_type a, const PTM::TVectorBase<DIMENC(4), B> v){
00134         W() = v[0]; X() = v[1]; Y() = v[2]; Z() = v[3];
00135     }
00136     static TQuaternion<ET> Rot(element_type angle, const TVec3<element_type>& axis){
00137         TQuaternion<ET> quat;
00138         PTM::init_quaternion(quat, angle, axis);
00139         return quat;
00140     }
00141     static TQuaternion<ET> Rot(element_type angle, char axis){
00142         TQuaternion<ET> quat;
00143         PTM::init_quaternion(quat, angle, axis);
00144         return quat;
00145     }
00146     static TQuaternion<ET> Rot(const TVec3<element_type>& rot){
00147         TQuaternion<ET> quat;
00148         PTM::init_quaternion(quat, rot);
00149         return quat;
00150     }
00151 
00152     //@}
00153     ///共役
00154     void conjugate() { V() = -V(); }
00155     /// 
00156     TQuaternion conjugated() const { TQuaternion rv(*this); rv.conjugate(); return rv;}
00157     ///逆
00158     TQuaternion inv() const { return conjugated() / square(); }
00159 
00160     ///回転行列変換
00161     template<class AM> void from_matrix(const AM& m)
00162     {
00163         ET tr = m[0][0] + m[1][1] + m[2][2] + 1;
00164         if (tr > 1e-6f){
00165             ET s = ET( 0.5/sqrt(tr) );
00166             W() = ET( 0.25 / s );
00167             X() = ET( (m[2][1] - m[1][2]) * s );
00168             Y() = ET( (m[0][2] - m[2][0]) * s );
00169             Z() = ET( (m[1][0] - m[0][1]) * s );
00170         }else if (m[0][0] > m[1][1] && m[0][0] > m[2][2]) { 
00171             ET s = ET(sqrt( 1.0 + m[0][0] - m[1][1] - m[2][2] ) * 2);
00172             X() = ET(0.25) * s;
00173             Y() = (m[0][1] + m[1][0]) / s; 
00174             Z() = (m[0][2] + m[2][0]) / s; 
00175             W() = (m[1][2] - m[2][1]) / s;
00176         } else if (m[1][1] > m[2][2]) {
00177             ET s = ET( sqrt(1.0 + m[1][1] - m[0][0] - m[2][2] ) * 2);
00178             X() = (m[0][1] + m[1][0] ) / s;
00179             Y() = ET(0.25) * s;
00180             Z() = (m[1][2] + m[2][1] ) / s; 
00181             W() = (m[0][2] - m[2][0] ) / s;
00182         } else { 
00183             ET s = ET( sqrt( 1.0 + m[2][2] - m[0][0] - m[1][1] ) * 2); 
00184             X() = (m[0][2] + m[2][0] ) / s;
00185             Y() = (m[1][2] + m[2][1] ) / s;
00186             Z() = ET(0.25) * s;
00187             W() = (m[0][1] - m[1][0] ) / s;
00188         }
00189         unitize();
00190     }
00191     template<class AM> void to_matrix(AM& mat) const
00192     {
00193         typedef TYPENAME AM::element_type AMET;
00194         mat[0][0] = AMET( 1.0 - 2.0 * (Y()*Y() + Z()*Z()) );
00195         mat[1][0] = AMET( 2.0 * (X()*Y() + Z()*W()) );
00196         mat[2][0] = AMET( 2.0 * (X()*Z() - Y()*W()) );
00197         mat[0][1] = AMET( 2.0 * (Y()*X() - Z()*W()) );
00198         mat[1][1] = AMET( 1.0 - 2.0 * (X()*X() + Z()*Z()) );
00199         mat[2][1] = AMET( 2.0 * (Y()*Z() + X()*W()) );
00200         mat[0][2] = AMET( 2.0 * (X()*Z() + Y()*W()) );
00201         mat[1][2] = AMET( 2.0 * (Y()*Z() - X()*W()) );
00202         mat[2][2] = AMET( 1.0 - 2.0 * (X()*X() + Y()*Y()) );
00203     }
00204     /// オイラー角へ変換
00205     template <class ET> void to_eular(TVec3<ET>& v){
00206         ET poleCheck = X()*Y() + Z()*W();
00207         ET& heading = v[0];
00208         ET& attitude = v[1];
00209         ET& bank = v[2];
00210         if (poleCheck == 0.5){              //  north pole
00211             heading = 2 * atan2(X(),W());
00212             bank = 0;
00213         }else if(poleCheck == -0.5){        //  south pole
00214             heading = -2 * atan2(X(),W());
00215             bank = 0;
00216         }else{
00217             heading = atan2(2*Y()*W()-2*X()*Z() , 1 - 2*Y()2 - 2*Z()2);
00218             attitude = asin(2*X()*Y() + 2*Z()*W());
00219             bank = atan2(2*X()*W()-2*Y()*Z() , 1 - 2*X()2 - 2*Z()2);
00220         }
00221     }
00222     ///
00223     template <class ET> void from_eular(const TVec3<ET>& v){
00224         ET& heading = v[0];
00225         ET& attitude = v[1];
00226         ET& bank = v[2];
00227 
00228         ET c1 = cos(heading / 2);
00229         ET c2 = cos(attitude / 2);
00230         ET c3 = cos(bank / 2);
00231         ET s1 = sin(heading / 2);
00232         ET s2 = sin(attitude / 2);
00233         ET s3 = sin(bank / 2);
00234         
00235         W() = c1 c2 c3 - s1 s2 s3;
00236         X() = s1 s2 c3 + c1 c2 s3;
00237         Y() = s1 c2 c3 + c1 s2 s3;
00238         Z() = c1 s2 c3 - s1 c2 s3;
00239     }
00240     ///lhsを回転してrhsに一致させるクウォータニオン
00241     void rotation_arc(const TVec3<ET>& lhs, const TVec3<ET>& rhs)
00242     {
00243         TVec3<ET> v0, v1, c;
00244         ET d, s;
00245         v0 = lhs.unit();
00246         v1 = rhs.unit();
00247         c = PTM::cross(v0, v1);
00248         d = PTM::dot(v0, v1);
00249         s = sqrt((1.0 + d) * 2.0);
00250         W() = s / 2.0;
00251         V() = c / s;
00252     }
00253 
00254     ///オイラー角で指定
00255     void euler(ET yaw, ET pitch, ET roll) {
00256         ET cosYaw   = cos(yaw / 2);
00257         ET sinYaw   = sin(yaw / 2);
00258         ET cosPitch = cos(pitch / 2);
00259         ET sinPitch = sin(pitch / 2);
00260         ET cosRoll  = cos(roll / 2);
00261         ET sinRoll  = sin(roll / 2);
00262         W() = cosRoll * cosPitch * cosYaw - sinRoll * sinPitch * sinYaw;
00263         X() = cosRoll * sinPitch * sinYaw + sinRoll * cosPitch * cosYaw;
00264         Y() = cosRoll * cosPitch * sinYaw + sinRoll * sinPitch * cosYaw;
00265         Z() = cosRoll * sinPitch * cosYaw - sinRoll * cosPitch * sinYaw;
00266     }
00267 
00268     //角速度からクウォータニオンの時間微分を計算
00269     //w : 角速度(ワールド)
00270     //q : クウォータニオン
00271     TQuaternion<ET> derivative(const TVec3<ET>& w){
00272         return 0.5 * TQuaternion<ET>(0.0, w.X(), w.Y(), w.Z()) * *this;
00273     }
00274 };
00275 
00276 /// TQuaternion 同士の掛け算.回転変換としては,合成になる.
00277 template <class A, class B>
00278 TQuaternion<A> operator*(const TQuaternion<A>& q1, const TQuaternion<B>& q2){
00279     TQuaternion<A> rv;
00280     rv.W() = q1.W() * q2.W() - q1.X() * q2.X() - q1.Y() * q2.Y() - q1.Z() * q2.Z();
00281     rv.X() = q1.W() * q2.X() + q1.X() * q2.W() + q1.Y() * q2.Z() - q1.Z() * q2.Y();
00282     rv.Y() = q1.W() * q2.Y() + q1.Y() * q2.W() + q1.Z() * q2.X() - q1.X() * q2.Z();
00283     rv.Z() = q1.W() * q2.Z() + q1.Z() * q2.W() + q1.X() * q2.Y() - q1.Y() * q2.X();
00284     return rv;
00285 }
00286 
00287 /// TQuaternionでベクトルを回転. TQuaternion * vector * TQuaternion.conjugated() と同じ.
00288 template <class ET, class BD>
00289 inline TYPENAME BD::ret_type operator*(const TQuaternion<ET>& q, const PTM::TVectorBase<DIMENC(3), BD>& v){
00290     TQuaternion<ET> qv(1, ET(v[0]), ET(v[1]), ET(v[2]));
00291     TYPENAME BD::ret_type r = (q * qv * q.conjugated()).sub_vector(PTM::TSubVectorDim<1,3>());
00292     return r;
00293 }
00294 /// TQuaternion の内積.
00295 template <class T1, class T2>
00296 inline T1 dot(const TQuaternion<T1>& q1, const TQuaternion<T2>& q2) {
00297     return q1.X() * q2.X() + q1.Y() * q2.Y() + q1.Z() * q2.Z() + q1.W() * q2.W();
00298 }
00299 template <class T1, class T2>
00300 TQuaternion<T1> interpolate(T1 t, const TQuaternion<T1>& q1, const TQuaternion<T2>& q2){
00301     TQuaternion<T1> ret;
00302     TQuaternion<T1> q3 ;
00303     float      dot;
00304 
00305     dot = q1.X() * q2.X() + q1.Y() * q2.Y() + q1.Z() * q2.Z() + q1.W() * q2.W();
00306     
00307     // dot < 0.0fの時、反転する
00308     if (dot < 0.0f){
00309         dot = -dot;
00310         q3 = TQuaternion<T1>(-q2.W(), -q2.X(), -q2.Y(), -q2.Z());
00311     }
00312     else q3 = q2;
00313     
00314     if (dot >  1.0f) dot = 1.0f;
00315     if (dot < -1.0f) dot = -1.0f;
00316     
00317     float angle = acos(dot);
00318     float sina, sinat, sinaomt;
00319     
00320     sina    = sin(angle          );
00321     sinat   = sin(angle *      t );
00322     sinaomt = sin(angle * (1 - t));
00323     
00324     if (sina){
00325         ret.X() = (q1.X() * sinaomt + q3.X() * sinat) / sina;
00326         ret.Y() = (q1.Y() * sinaomt + q3.Y() * sinat) / sina;
00327         ret.Z() = (q1.Z() * sinaomt + q3.Z() * sinat) / sina;
00328         ret.W() = (q1.W() * sinaomt + q3.W() * sinat) / sina;
00329     }else{
00330         ret = q1;
00331     }
00332     return ret;
00333 }
00334 
00335 /// float版TQuaternion.
00336 typedef TQuaternion<float> Quaternionf;
00337 /// double版TQuaternion.
00338 typedef TQuaternion<double> Quaterniond;
00339 
00340 }
00341 
00342 #endif

Springheadに対してSun Apr 16 01:57:57 2006に生成されました。  doxygen 1.4.1