ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

rotation3d.h

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifndef MATH_ROTATION3D_H
00024 #define MATH_ROTATION3D_H
00025 
00026 #include "common/streamdebug.h"
00027 
00028 #include "math/utils.h"
00029 #include "math/transform.h"
00030 #include "math/angle.h"
00031 #include "common/textconsole.h"
00032 
00033 namespace Math {
00034 
00038 enum EulerOrder {
00039     EO_XYX,
00040     EO_XYZ,
00041     EO_XZX,
00042     EO_XZY,
00043     EO_YXY,
00044     EO_YXZ,
00045     EO_YZX,
00046     EO_YZY,
00047     EO_ZXY,     // Original ResidualVM implmentation
00048     EO_ZXZ,
00049     EO_ZYX,
00050     EO_ZYZ
00051 };
00052 
00053 template<class T>
00054 class Rotation3D : public Transform<T> {
00055 public:
00056     Rotation3D();
00057 
00065     Rotation3D(const Angle &first, const Angle &second, const Angle &third, EulerOrder order);
00066 
00074     void buildFromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order);
00075 
00080     void buildAroundX(const Angle &rotX);
00081 
00086     void buildAroundY(const Angle &rotY);
00087 
00092     void buildAroundZ(const Angle &rotZ);
00093 
00101     void getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const;
00102 };
00103 
00104 template<class T>
00105 Rotation3D<T>::Rotation3D() : Transform<T>() {}
00106 
00107 template<class T>
00108 void Rotation3D<T>::buildFromEuler(const Angle &first, const Angle &second, const Angle &third, EulerOrder order) {
00109     // Build a matrix around each rotation angle
00110     T m2, m3;
00111 
00112     // Combine them in the order requested
00113     switch (order) {
00114         case EO_XYX:
00115             this->buildAroundX(first);
00116             m2.buildAroundY(second);
00117             m3.buildAroundX(third);
00118             break;
00119         case EO_XYZ:
00120             this->buildAroundX(first);
00121             m2.buildAroundY(second);
00122             m3.buildAroundZ(third);
00123             break;
00124         case EO_XZX:
00125             this->buildAroundX(first);
00126             m2.buildAroundZ(second);
00127             m3.buildAroundX(third);
00128             break;
00129         case EO_XZY:
00130             this->buildAroundX(first);
00131             m2.buildAroundZ(second);
00132             m3.buildAroundY(third);
00133             break;
00134         case EO_YXY:
00135             this->buildAroundY(first);
00136             m2.buildAroundX(second);
00137             m3.buildAroundY(third);
00138             break;
00139         case EO_YXZ:
00140             this->buildAroundY(first);
00141             m2.buildAroundX(second);
00142             m3.buildAroundZ(third);
00143             break;
00144         case EO_YZX:
00145             this->buildAroundY(first);
00146             m2.buildAroundZ(second);
00147             m3.buildAroundX(third);
00148             break;
00149         case EO_YZY:
00150             this->buildAroundY(first);
00151             m2.buildAroundZ(second);
00152             m3.buildAroundY(third);
00153             break;
00154         // Original ResidualVM Implementation
00155         case EO_ZXY:
00156             this->buildAroundZ(first);
00157             m2.buildAroundX(second);
00158             m3.buildAroundY(third);
00159             break;
00160         case EO_ZXZ:
00161             this->buildAroundZ(first);
00162             m2.buildAroundX(second);
00163             m3.buildAroundZ(third);
00164             break;
00165         case EO_ZYX:
00166             this->buildAroundZ(first);
00167             m2.buildAroundY(second);
00168             m3.buildAroundX(third);
00169             break;
00170         case EO_ZYZ:
00171             this->buildAroundZ(first);
00172             m2.buildAroundY(second);
00173             m3.buildAroundZ(third);
00174             break;
00175         default:
00176             error("Invalid Euler Order");
00177             break;
00178     }
00179     // Combine the rotations
00180     this->getMatrix() = this->getMatrix() * m2 * m3;
00181 }
00182 
00183 // at. Rotates about the +X axis.
00184 // Left Handed (DirectX) Coordinates
00185 template<class T>
00186 void Rotation3D<T>::buildAroundX(const Angle &rotX) {
00187     float cosa = rotX.getCosine();
00188     float sina = rotX.getSine();
00189 
00190     this->getMatrix().getRow(0) << 1.f << 0.f  << 0.f;
00191     this->getMatrix().getRow(1) << 0.f << cosa << -sina;
00192     this->getMatrix().getRow(2) << 0.f << sina << cosa;
00193 }
00194 
00195 // right. Rotates about the +Y axis.
00196 // Left Handed (DirectX) Coordinates
00197 template<class T>
00198 void Rotation3D<T>::buildAroundY(const Angle &rotY) {
00199     float cosa = rotY.getCosine();
00200     float sina = rotY.getSine();
00201 
00202     this->getMatrix().getRow(0) << cosa  << 0.f << sina;
00203     this->getMatrix().getRow(1) << 0.f   << 1.f << 0.f;
00204     this->getMatrix().getRow(2) << -sina << 0.f << cosa;
00205 }
00206 
00207 // up. Rotates about the +Z axis.
00208 // Left Handed (DirectX) Coordinates
00209 template<class T>
00210 void Rotation3D<T>::buildAroundZ(const Angle &rotZ) {
00211     float cosa = rotZ.getCosine();
00212     float sina = rotZ.getSine();
00213 
00214     this->getMatrix().getRow(0) << cosa << -sina << 0.f;
00215     this->getMatrix().getRow(1) << sina << cosa  << 0.f;
00216     this->getMatrix().getRow(2) << 0.f  << 0.f   << 1.f;
00217 }
00218 
00219 template<class T>
00220 void Rotation3D<T>::getEuler(Angle *first, Angle *second, Angle *third, EulerOrder order) const {
00221     // Cast as the matrix type so we can use getValue
00222     const T *m = &(this->getMatrix());
00223 
00224     float f, s, t;
00225     switch (order) {
00226         case EO_XYX:
00227             if (m->getValue(0, 0) < 1.0f) {
00228                 if (m->getValue(0, 0) > -1.0f) {
00229                     f = atan2(m->getValue(1, 0), -(m->getValue(2, 0)));
00230                     s = acos(m->getValue(0, 0));
00231                     t = atan2(m->getValue(0, 1), m->getValue(0, 2));
00232                 } else {
00233                     f = -atan2(-m->getValue(1, 2), m->getValue(1, 1));
00234                     s = (float) M_PI;
00235                     t = 0.0f;
00236                 }
00237             } else {
00238                 f = atan2(-m->getValue(1, 2), m->getValue(1, 1));
00239                 s = 0.0f;
00240                 t = 0.0f;
00241             }
00242             break;
00243         case EO_XYZ:
00244             if (m->getValue(0, 2) < 1.0f) {
00245                 if (m->getValue(0, 2) > -1.0f) {
00246                     f = atan2(-(m->getValue(1, 2)), m->getValue(2, 2));
00247                     s = asin(m->getValue(0, 2));
00248                     t = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
00249                 } else {
00250                     f = -atan2(m->getValue(1, 0), m->getValue(1, 1));
00251                     s = -(float) M_PI / 2.0f;
00252                     t = 0.0f;
00253                 }
00254             } else {
00255                 f = atan2(m->getValue(1, 0), m->getValue(1, 1));
00256                 s = (float) M_PI / 2.0f;
00257                 t = 0.0f;
00258             }
00259             break;
00260         case EO_XZX:
00261             if (m->getValue(0, 0) < 1.0f) {
00262                 if (m->getValue(0, 0) > -1.0f) {
00263                     f = atan2(m->getValue(2, 0), m->getValue(1, 0));
00264                     s = acos(m->getValue(0, 0));
00265                     t = atan2(m->getValue(0, 2), -(m->getValue(0, 1)));
00266                 } else {
00267                     f = -atan2(m->getValue(2, 1), m->getValue(2, 2));
00268                     s = (float) M_PI;
00269                     t = 0.0f;
00270                 }
00271             } else {
00272                 f = atan2(m->getValue(2, 1), m->getValue(2, 2));
00273                 s = 0.0f;
00274                 t = 0.0f;
00275             }
00276             break;
00277         case EO_XZY:
00278             if (m->getValue(0, 1) < 1.0f) {
00279                 if (m->getValue(0, 1) > -1.0f) {
00280                     f = atan2(m->getValue(2, 1), m->getValue(1, 1));
00281                     s = asin(-(m->getValue(0, 1)));
00282                     t = atan2(m->getValue(0, 2), m->getValue(0, 0));
00283                 } else {
00284                     f = -atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
00285                     s = (float) M_PI / 2.0f;
00286                     t = 0.0f;
00287                 }
00288             } else {
00289                 f = atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
00290                 s = -(float) M_PI / 2.0f;
00291                 t = 0.0f;
00292             }
00293             break;
00294         case EO_YXY:
00295             if (m->getValue(1, 1) < 1.0f) {
00296                 if (m->getValue(1, 1) > -1.0f) {
00297                     f = atan2(m->getValue(0, 1), m->getValue(2, 1));
00298                     s = acos(m->getValue(1, 1));
00299                     t = atan2(m->getValue(1, 0), -(m->getValue(1, 2)));
00300                 } else {
00301                     f = -atan2(m->getValue(0, 2), m->getValue(0, 0));
00302                     s = (float) M_PI;
00303                     t = 0.0f;
00304                 }
00305             } else {
00306                 f = atan2(m->getValue(0, 2), m->getValue(0, 0));
00307                 s = 0.0f;
00308                 t = 0.0f;
00309             }
00310             break;
00311         case EO_YXZ:
00312             if (m->getValue(1, 2) < 1.0f) {
00313                 if (m->getValue(1, 2) > -1.0f) {
00314                     f = atan2(m->getValue(0, 2), m->getValue(2, 2));
00315                     s = asin(-(m->getValue(1, 2)));
00316                     t = atan2(m->getValue(1, 0), m->getValue(1, 1));
00317                 } else {
00318                     f = -atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
00319                     s = (float) M_PI / 2.0f;
00320                     t = 0.0f;
00321                 }
00322             } else {
00323                 f = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
00324                 s = -(float) M_PI / 2.0f;
00325                 t = 0.0f;
00326             }
00327             break;
00328         case EO_YZX:
00329             if (m->getValue(1, 0) < 1.0f) {
00330                 if (m->getValue(1, 0) > -1.0f) {
00331                     f = atan2(-(m->getValue(2, 0)), m->getValue(0, 0));
00332                     s = asin(m->getValue(1, 0));
00333                     t = atan2(-(m->getValue(1, 2)), m->getValue(1, 1));
00334                 } else {
00335                     f = -atan2(m->getValue(2, 1), m->getValue(2, 2));
00336                     s = -(float) M_PI / 2.0f;
00337                     t = 0.0f;
00338                 }
00339             } else {
00340                 f = atan2(m->getValue(2, 1), m->getValue(2, 2));
00341                 s = (float) M_PI / 2.0f;
00342                 t = 0.0f;
00343             }
00344             break;
00345         case EO_YZY:
00346             if (m->getValue(1, 1) < 1.0f) {
00347                 if (m->getValue(1, 1) > -1.0f) {
00348                     f = atan2(m->getValue(2, 1), -(m->getValue(0, 1)));
00349                     s = acos(m->getValue(1, 1));
00350                     t = atan2(m->getValue(1, 2), m->getValue(1, 0));
00351                 } else {
00352                     f = -atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
00353                     s = (float) M_PI;
00354                     t = 0.0f;
00355                 }
00356             } else {
00357                 f = atan2(-(m->getValue(2, 0)), m->getValue(2, 2));
00358                 s = 0.0f;
00359                 t = 0.0f;
00360             }
00361             break;
00362         case EO_ZXY:        // Original ResidualVM implmentation
00363             if (m->getValue(2, 1) < 1.0f) {
00364                 if (m->getValue(2, 1) > -1.0f) {
00365                     f = -atan2(m->getValue(0, 1), m->getValue(1, 1));
00366                     s = asin(m->getValue(2, 1));
00367                     t = -atan2(m->getValue(2, 0), m->getValue(2, 2));
00368                 } else {
00369                     f = -atan2(-m->getValue(0, 2), m->getValue(0, 0));
00370                     s = -(float) M_PI / 2.0f;
00371                     t = 0.0f;
00372                 }
00373             } else {
00374                 f = atan2(m->getValue(0, 2), m->getValue(0, 0));
00375                 s = (float) M_PI / 2.0f;
00376                 t = 0.0f;
00377             }
00378             break;
00379         case EO_ZXZ:
00380             if (m->getValue(2, 2) < 1.0f) {
00381                 if (m->getValue(2, 2) > -1.0f) {
00382                     f = atan2(m->getValue(0, 2), -(m->getValue(1, 2)));
00383                     s = acos(m->getValue(2, 2));
00384                     t = atan2(m->getValue(2, 0), m->getValue(2, 1));
00385                 } else {
00386                     f = -atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
00387                     s = (float) M_PI;
00388                     t = 0.0f;
00389                 }
00390             } else {
00391                 f = atan2(-(m->getValue(0, 1)), m->getValue(0, 0));
00392                 s = 0.0f;
00393                 t = 0.0f;
00394             }
00395             break;
00396         case EO_ZYX:
00397             if (m->getValue(2, 0) < 1.0f) {
00398                 if (m->getValue(2, 0) > -1.0f) {
00399                     f = atan2(m->getValue(1, 0), m->getValue(0, 0));
00400                     s = asin(-(m->getValue(2, 0)));
00401                     t = atan2(m->getValue(2, 1), m->getValue(2, 2));
00402                 } else {
00403                     f = -atan2(-m->getValue(1, 2), m->getValue(1, 1));
00404                     s = (float) M_PI / 2.0f;
00405                     t = 0.0f;
00406                 }
00407             } else {
00408                 f = atan2(-m->getValue(1, 2), m->getValue(1, 1));
00409                 s = -(float) M_PI / 2.0f;
00410                 t = 0.0f;
00411             }
00412             break;
00413         case EO_ZYZ:
00414             if (m->getValue(2, 2) < 1.0f) {
00415                 if (m->getValue(2, 2) > -1.0f) {
00416                     f = atan2(m->getValue(1, 2), m->getValue(0, 2));
00417                     s = acos(m->getValue(2, 2));
00418                     t = atan2(m->getValue(2, 1), -(m->getValue(2, 0)));
00419                 } else {
00420                     f = -atan2(m->getValue(1, 0), m->getValue(1, 1));
00421                     s = (float) M_PI;
00422                     t = 0.0f;
00423                 }
00424             } else {
00425                 f = atan2(m->getValue(1, 0), m->getValue(1, 1));
00426                 s = 0.0f;
00427                 t = 0.0f;
00428             }
00429             break;
00430         default:
00431             error("Invalid Euler Order");
00432             break;
00433     }
00434 
00435     if (first) {
00436         *first = Math::Angle::fromRadians(f);
00437     }
00438     if (second) {
00439         *second = Math::Angle::fromRadians(s);
00440     }
00441     if (third) {
00442         *third = Math::Angle::fromRadians(t);
00443     }
00444 }
00445 
00446 }
00447 
00448 #endif


Generated on Sat May 25 2019 05:00:53 for ResidualVM by doxygen 1.7.1
curved edge   curved edge