Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/math/quaternion.cc @ 6784

Last change on this file since 6784 was 6616, checked in by bensch, 19 years ago

orxonox/trunk: taken the quaternion outside of Vector.cc to quaternion.cc/h

File size: 5.7 KB
RevLine 
[4578]1/*
[2043]2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
[4578]12   main-programmer: Christian Meyer
[2551]13   co-programmer: Patrick Boenzli : Vector::scale()
14                                    Vector::abs()
[4578]15
[2190]16   Quaternion code borrowed from an Gamasutra article by Nick Bobick and Ken Shoemake
[5420]17
18   2005-06-02: Benjamin Grauer: speed up, and new Functionality to Vector (mostly inline now)
[2043]19*/
20
[3590]21#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_MATH
[2043]22
[6616]23#include "quaternion.h"
[5662]24#ifdef DEBUG
[5672]25  #include "debug.h"
[5662]26#else
[5672]27  #include <stdio.h>
28  #define PRINT(x) printf
[5662]29#endif
[2043]30
31using namespace std;
32
[4477]33/////////////////
34/* QUATERNIONS */
35/////////////////
[3541]36/**
[4836]37 *  calculates a lookAt rotation
38 * @param dir: the direction you want to look
39 * @param up: specify what direction up should be
[4578]40
[2551]41   Mathematically this determines the rotation a (0,0,1)-Vector has to undergo to point
42   the same way as dir. If you want to use this with cameras, you'll have to reverse the
43   dir Vector (Vector(0,0,0) - your viewing direction) or you'll point the wrong way. You
[4578]44   can use this for meshes as well (then you do not have to reverse the vector), but keep
45   in mind that if you do that, the model's front has to point in +z direction, and left
[2551]46   and right should be -x or +x respectively or the mesh wont rotate correctly.
[5004]47 *
[5005]48 * @TODO !!! OPTIMIZE THIS !!!
[5420]49 */
[2190]50Quaternion::Quaternion (const Vector& dir, const Vector& up)
[2551]51{
[5004]52  Vector z = dir.getNormalized();
53  Vector x = up.cross(z).getNormalized();
[2190]54  Vector y = z.cross(x);
[4578]55
[2190]56  float m[4][4];
57  m[0][0] = x.x;
58  m[0][1] = x.y;
59  m[0][2] = x.z;
60  m[0][3] = 0;
61  m[1][0] = y.x;
62  m[1][1] = y.y;
63  m[1][2] = y.z;
64  m[1][3] = 0;
65  m[2][0] = z.x;
66  m[2][1] = z.y;
67  m[2][2] = z.z;
68  m[2][3] = 0;
69  m[3][0] = 0;
70  m[3][1] = 0;
71  m[3][2] = 0;
72  m[3][3] = 1;
[4578]73
[2190]74  *this = Quaternion (m);
75}
76
77/**
[4836]78 *  calculates a rotation from euler angles
79 * @param roll: the roll in radians
80 * @param pitch: the pitch in radians
81 * @param yaw: the yaw in radians
[5420]82 */
[2190]83Quaternion::Quaternion (float roll, float pitch, float yaw)
84{
[4477]85  float cr, cp, cy, sr, sp, sy, cpcy, spsy;
[4578]86
[4477]87  // calculate trig identities
88  cr = cos(roll/2);
89  cp = cos(pitch/2);
90  cy = cos(yaw/2);
[4578]91
[4477]92  sr = sin(roll/2);
93  sp = sin(pitch/2);
94  sy = sin(yaw/2);
[4578]95
[4477]96  cpcy = cp * cy;
97  spsy = sp * sy;
[4578]98
[4477]99  w = cr * cpcy + sr * spsy;
100  v.x = sr * cpcy - cr * spsy;
101  v.y = cr * sp * cy + sr * cp * sy;
102  v.z = cr * cp * sy - sr * sp * cy;
[2190]103}
104
105/**
[4836]106 *  convert the Quaternion to a 4x4 rotational glMatrix
107 * @param m: a buffer to store the Matrix in
[5420]108 */
[2190]109void Quaternion::matrix (float m[4][4]) const
110{
[4578]111  float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
112
[2551]113  // calculate coefficients
114  x2 = v.x + v.x;
[4578]115  y2 = v.y + v.y;
[2551]116  z2 = v.z + v.z;
117  xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
118  yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
119  wx = w * x2; wy = w * y2; wz = w * z2;
[4578]120
[2551]121  m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
122  m[2][0] = xz + wy; m[3][0] = 0.0;
[4578]123
[2551]124  m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
125  m[2][1] = yz - wx; m[3][1] = 0.0;
[4578]126
[2551]127  m[0][2] = xz - wy; m[1][2] = yz + wx;
128  m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
[4578]129
[2551]130  m[0][3] = 0; m[1][3] = 0;
131  m[2][3] = 0; m[3][3] = 1;
[2190]132}
133
[3449]134/**
[4836]135 *  performs a smooth move.
136 * @param from  where
137 * @param to where
138 * @param t the time this transformation should take value [0..1]
139 * @returns the Result of the smooth move
[5420]140 */
[4998]141Quaternion Quaternion::quatSlerp(const Quaternion& from, const Quaternion& to, float t)
[2551]142{
143  float tol[4];
144  double omega, cosom, sinom, scale0, scale1;
[3971]145  //  float DELTA = 0.2;
[2551]146
[3966]147  cosom = from.v.x * to.v.x + from.v.y * to.v.y + from.v.z * to.v.z + from.w * to.w;
[2551]148
[4578]149  if( cosom < 0.0 )
150    {
151      cosom = -cosom;
[3966]152      tol[0] = -to.v.x;
153      tol[1] = -to.v.y;
154      tol[2] = -to.v.z;
155      tol[3] = -to.w;
[2551]156    }
157  else
158    {
[3966]159      tol[0] = to.v.x;
160      tol[1] = to.v.y;
161      tol[2] = to.v.z;
162      tol[3] = to.w;
[2551]163    }
[4578]164
[3966]165  omega = acos(cosom);
166  sinom = sin(omega);
167  scale0 = sin((1.0 - t) * omega) / sinom;
168  scale1 = sin(t * omega) / sinom;
[3971]169  return Quaternion(Vector(scale0 * from.v.x + scale1 * tol[0],
[5420]170                    scale0 * from.v.y + scale1 * tol[1],
171                    scale0 * from.v.z + scale1 * tol[2]),
[4578]172                    scale0 * from.w + scale1 * tol[3]);
[2551]173}
174
175
[2190]176/**
[4836]177 *  convert a rotational 4x4 glMatrix into a Quaternion
178 * @param m: a 4x4 matrix in glMatrix order
[5420]179 */
[2190]180Quaternion::Quaternion (float m[4][4])
181{
[4578]182
[2551]183  float  tr, s, q[4];
184  int    i, j, k;
185
186  int nxt[3] = {1, 2, 0};
187
188  tr = m[0][0] + m[1][1] + m[2][2];
189
[4578]190        // check the diagonal
191  if (tr > 0.0)
[2551]192  {
193    s = sqrt (tr + 1.0);
194    w = s / 2.0;
195    s = 0.5 / s;
196    v.x = (m[1][2] - m[2][1]) * s;
197    v.y = (m[2][0] - m[0][2]) * s;
198    v.z = (m[0][1] - m[1][0]) * s;
[4578]199        }
200        else
201        {
202                // diagonal is negative
203        i = 0;
204        if (m[1][1] > m[0][0]) i = 1;
[2551]205    if (m[2][2] > m[i][i]) i = 2;
206    j = nxt[i];
207    k = nxt[j];
208
209    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
[4578]210
[2551]211    q[i] = s * 0.5;
[4578]212
[2551]213    if (s != 0.0) s = 0.5 / s;
[4578]214
215          q[3] = (m[j][k] - m[k][j]) * s;
[2551]216    q[j] = (m[i][j] + m[j][i]) * s;
217    q[k] = (m[i][k] + m[k][i]) * s;
218
[4578]219        v.x = q[0];
220        v.y = q[1];
221        v.z = q[2];
222        w = q[3];
[2190]223  }
224}
225
226/**
[4836]227 *  outputs some nice formated debug information about this quaternion
[3541]228*/
[4746]229void Quaternion::debug()
[3541]230{
231  PRINT(0)("real a=%f; imag: x=%f y=%f z=%f\n", w, v.x, v.y, v.z);
232}
233
[5000]234void Quaternion::debug2()
235{
236  Vector axis = this->getSpacialAxis();
237  PRINT(0)("angle = %f, axis: ax=%f, ay=%f, az=%f\n", this->getSpacialAxisAngle(), axis.x, axis.y, axis.z );
238}
Note: See TracBrowser for help on using the repository browser.