Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/math/vector.cc @ 6474

Last change on this file since 6474 was 5688, checked in by patrick, 19 years ago

orxonox/trunk: the const collision detection war - strike

File size: 13.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
23#include "vector.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/* VECTORS */
35/////////////
[2043]36/**
[4836]37 *  returns the this-vector normalized to length 1.0
[4966]38 * @todo there is some error in this function, that i could not resolve. it just does not, what it is supposed to do.
[5420]39 */
[4372]40Vector Vector::getNormalized() const
[2551]41{
[4966]42  float l = this->len();
43  if(unlikely(l == 1.0 || l == 0.0))
44    return *this;
45  else
46    return (*this / l);
[2551]47}
48
[3449]49/**
[4836]50 *  Vector is looking in the positive direction on all axes after this
[4477]51*/
[4578]52Vector Vector::abs()
[4477]53{
54  Vector v(fabs(x), fabs(y), fabs(z));
55  return v;
56}
57
58
59
60/**
[4836]61 *  Outputs the values of the Vector
[5420]62 */
[4746]63void Vector::debug() const
[3541]64{
65  PRINT(0)("x: %f; y: %f; z: %f", x, y, z);
[4987]66  PRINT(0)(" lenght: %f", len());
[3541]67  PRINT(0)("\n");
68}
69
[4477]70/////////////////
71/* QUATERNIONS */
72/////////////////
[3541]73/**
[4836]74 *  calculates a lookAt rotation
75 * @param dir: the direction you want to look
76 * @param up: specify what direction up should be
[4578]77
[2551]78   Mathematically this determines the rotation a (0,0,1)-Vector has to undergo to point
79   the same way as dir. If you want to use this with cameras, you'll have to reverse the
80   dir Vector (Vector(0,0,0) - your viewing direction) or you'll point the wrong way. You
[4578]81   can use this for meshes as well (then you do not have to reverse the vector), but keep
82   in mind that if you do that, the model's front has to point in +z direction, and left
[2551]83   and right should be -x or +x respectively or the mesh wont rotate correctly.
[5004]84 *
[5005]85 * @TODO !!! OPTIMIZE THIS !!!
[5420]86 */
[2190]87Quaternion::Quaternion (const Vector& dir, const Vector& up)
[2551]88{
[5004]89  Vector z = dir.getNormalized();
90  Vector x = up.cross(z).getNormalized();
[2190]91  Vector y = z.cross(x);
[4578]92
[2190]93  float m[4][4];
94  m[0][0] = x.x;
95  m[0][1] = x.y;
96  m[0][2] = x.z;
97  m[0][3] = 0;
98  m[1][0] = y.x;
99  m[1][1] = y.y;
100  m[1][2] = y.z;
101  m[1][3] = 0;
102  m[2][0] = z.x;
103  m[2][1] = z.y;
104  m[2][2] = z.z;
105  m[2][3] = 0;
106  m[3][0] = 0;
107  m[3][1] = 0;
108  m[3][2] = 0;
109  m[3][3] = 1;
[4578]110
[2190]111  *this = Quaternion (m);
112}
113
114/**
[4836]115 *  calculates a rotation from euler angles
116 * @param roll: the roll in radians
117 * @param pitch: the pitch in radians
118 * @param yaw: the yaw in radians
[5420]119 */
[2190]120Quaternion::Quaternion (float roll, float pitch, float yaw)
121{
[4477]122  float cr, cp, cy, sr, sp, sy, cpcy, spsy;
[4578]123
[4477]124  // calculate trig identities
125  cr = cos(roll/2);
126  cp = cos(pitch/2);
127  cy = cos(yaw/2);
[4578]128
[4477]129  sr = sin(roll/2);
130  sp = sin(pitch/2);
131  sy = sin(yaw/2);
[4578]132
[4477]133  cpcy = cp * cy;
134  spsy = sp * sy;
[4578]135
[4477]136  w = cr * cpcy + sr * spsy;
137  v.x = sr * cpcy - cr * spsy;
138  v.y = cr * sp * cy + sr * cp * sy;
139  v.z = cr * cp * sy - sr * sp * cy;
[2190]140}
141
142/**
[4836]143 *  convert the Quaternion to a 4x4 rotational glMatrix
144 * @param m: a buffer to store the Matrix in
[5420]145 */
[2190]146void Quaternion::matrix (float m[4][4]) const
147{
[4578]148  float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
149
[2551]150  // calculate coefficients
151  x2 = v.x + v.x;
[4578]152  y2 = v.y + v.y;
[2551]153  z2 = v.z + v.z;
154  xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
155  yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
156  wx = w * x2; wy = w * y2; wz = w * z2;
[4578]157
[2551]158  m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
159  m[2][0] = xz + wy; m[3][0] = 0.0;
[4578]160
[2551]161  m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
162  m[2][1] = yz - wx; m[3][1] = 0.0;
[4578]163
[2551]164  m[0][2] = xz - wy; m[1][2] = yz + wx;
165  m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
[4578]166
[2551]167  m[0][3] = 0; m[1][3] = 0;
168  m[2][3] = 0; m[3][3] = 1;
[2190]169}
170
[3449]171/**
[4836]172 *  performs a smooth move.
173 * @param from  where
174 * @param to where
175 * @param t the time this transformation should take value [0..1]
176 * @returns the Result of the smooth move
[5420]177 */
[4998]178Quaternion Quaternion::quatSlerp(const Quaternion& from, const Quaternion& to, float t)
[2551]179{
180  float tol[4];
181  double omega, cosom, sinom, scale0, scale1;
[3971]182  //  float DELTA = 0.2;
[2551]183
[3966]184  cosom = from.v.x * to.v.x + from.v.y * to.v.y + from.v.z * to.v.z + from.w * to.w;
[2551]185
[4578]186  if( cosom < 0.0 )
187    {
188      cosom = -cosom;
[3966]189      tol[0] = -to.v.x;
190      tol[1] = -to.v.y;
191      tol[2] = -to.v.z;
192      tol[3] = -to.w;
[2551]193    }
194  else
195    {
[3966]196      tol[0] = to.v.x;
197      tol[1] = to.v.y;
198      tol[2] = to.v.z;
199      tol[3] = to.w;
[2551]200    }
[4578]201
[3966]202  omega = acos(cosom);
203  sinom = sin(omega);
204  scale0 = sin((1.0 - t) * omega) / sinom;
205  scale1 = sin(t * omega) / sinom;
[3971]206  return Quaternion(Vector(scale0 * from.v.x + scale1 * tol[0],
[5420]207                    scale0 * from.v.y + scale1 * tol[1],
208                    scale0 * from.v.z + scale1 * tol[2]),
[4578]209                    scale0 * from.w + scale1 * tol[3]);
[2551]210}
211
212
[2190]213/**
[4836]214 *  convert a rotational 4x4 glMatrix into a Quaternion
215 * @param m: a 4x4 matrix in glMatrix order
[5420]216 */
[2190]217Quaternion::Quaternion (float m[4][4])
218{
[4578]219
[2551]220  float  tr, s, q[4];
221  int    i, j, k;
222
223  int nxt[3] = {1, 2, 0};
224
225  tr = m[0][0] + m[1][1] + m[2][2];
226
[4578]227        // check the diagonal
228  if (tr > 0.0)
[2551]229  {
230    s = sqrt (tr + 1.0);
231    w = s / 2.0;
232    s = 0.5 / s;
233    v.x = (m[1][2] - m[2][1]) * s;
234    v.y = (m[2][0] - m[0][2]) * s;
235    v.z = (m[0][1] - m[1][0]) * s;
[4578]236        }
237        else
238        {
239                // diagonal is negative
240        i = 0;
241        if (m[1][1] > m[0][0]) i = 1;
[2551]242    if (m[2][2] > m[i][i]) i = 2;
243    j = nxt[i];
244    k = nxt[j];
245
246    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
[4578]247
[2551]248    q[i] = s * 0.5;
[4578]249
[2551]250    if (s != 0.0) s = 0.5 / s;
[4578]251
252          q[3] = (m[j][k] - m[k][j]) * s;
[2551]253    q[j] = (m[i][j] + m[j][i]) * s;
254    q[k] = (m[i][k] + m[k][i]) * s;
255
[4578]256        v.x = q[0];
257        v.y = q[1];
258        v.z = q[2];
259        w = q[3];
[2190]260  }
261}
262
263/**
[4836]264 *  outputs some nice formated debug information about this quaternion
[3541]265*/
[4746]266void Quaternion::debug()
[3541]267{
268  PRINT(0)("real a=%f; imag: x=%f y=%f z=%f\n", w, v.x, v.y, v.z);
269}
270
[5000]271void Quaternion::debug2()
272{
273  Vector axis = this->getSpacialAxis();
274  PRINT(0)("angle = %f, axis: ax=%f, ay=%f, az=%f\n", this->getSpacialAxisAngle(), axis.x, axis.y, axis.z );
275}
276
[3541]277/**
[4836]278 *  create a rotation from a vector
279 * @param v: a vector
[2043]280*/
281Rotation::Rotation (const Vector& v)
282{
283  Vector x = Vector( 1, 0, 0);
284  Vector axis = x.cross( v);
285  axis.normalize();
[3234]286  float angle = angleRad( x, v);
[2043]287  float ca = cos(angle);
288  float sa = sin(angle);
289  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
290  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
291  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
292  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
293  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
294  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
295  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
296  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
297  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
298}
299
300/**
[4836]301 *  creates a rotation from an axis and an angle (radians!)
302 * @param axis: the rotational axis
303 * @param angle: the angle in radians
[2043]304*/
305Rotation::Rotation (const Vector& axis, float angle)
306{
307  float ca, sa;
308  ca = cos(angle);
309  sa = sin(angle);
310  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
311  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
312  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
313  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
314  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
315  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
316  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
317  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
318  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
319}
320
321/**
[4836]322 *  creates a rotation from euler angles (pitch/yaw/roll)
323 * @param pitch: rotation around z (in radians)
324 * @param yaw: rotation around y (in radians)
325 * @param roll: rotation around x (in radians)
[2043]326*/
327Rotation::Rotation ( float pitch, float yaw, float roll)
328{
329  float cy, sy, cr, sr, cp, sp;
330  cy = cos(yaw);
331  sy = sin(yaw);
332  cr = cos(roll);
333  sr = sin(roll);
334  cp = cos(pitch);
335  sp = sin(pitch);
336  m[0] = cy*cr;
337  m[1] = -cy*sr;
338  m[2] = sy;
339  m[3] = cp*sr+sp*sy*cr;
340  m[4] = cp*cr-sp*sr*sy;
341  m[5] = -sp*cy;
342  m[6] = sp*sr-cp*sy*cr;
343  m[7] = sp*cr+cp*sy*sr;
344  m[8] = cp*cy;
345}
346
347/**
[4836]348 *  creates a nullrotation (an identity rotation)
[2043]349*/
350Rotation::Rotation ()
351{
352  m[0] = 1.0f;
353  m[1] = 0.0f;
354  m[2] = 0.0f;
355  m[3] = 0.0f;
356  m[4] = 1.0f;
357  m[5] = 0.0f;
358  m[6] = 0.0f;
359  m[7] = 0.0f;
360  m[8] = 1.0f;
361}
362
363/**
[4836]364 *  fills the specified buffer with a 4x4 glmatrix
365 * @param buffer: Pointer to an array of 16 floats
[4578]366
[2190]367   Use this to get the rotation in a gl-compatible format
368*/
369void Rotation::glmatrix (float* buffer)
370{
[4578]371        buffer[0] = m[0];
372        buffer[1] = m[3];
373        buffer[2] = m[6];
374        buffer[3] = m[0];
375        buffer[4] = m[1];
376        buffer[5] = m[4];
377        buffer[6] = m[7];
378        buffer[7] = m[0];
379        buffer[8] = m[2];
380        buffer[9] = m[5];
381        buffer[10] = m[8];
382        buffer[11] = m[0];
383        buffer[12] = m[0];
384        buffer[13] = m[0];
385        buffer[14] = m[0];
386        buffer[15] = m[1];
[2190]387}
388
389/**
[4836]390 *  multiplies two rotational matrices
391 * @param r: another Rotation
392 * @return the matrix product of the Rotations
[4578]393
[2190]394   Use this to rotate one rotation by another
395*/
396Rotation Rotation::operator* (const Rotation& r)
397{
[4578]398        Rotation p;
[2190]399
[4578]400        p.m[0] = m[0]*r.m[0] + m[1]*r.m[3] + m[2]*r.m[6];
401        p.m[1] = m[0]*r.m[1] + m[1]*r.m[4] + m[2]*r.m[7];
402        p.m[2] = m[0]*r.m[2] + m[1]*r.m[5] + m[2]*r.m[8];
403
404        p.m[3] = m[3]*r.m[0] + m[4]*r.m[3] + m[5]*r.m[6];
405        p.m[4] = m[3]*r.m[1] + m[4]*r.m[4] + m[5]*r.m[7];
406        p.m[5] = m[3]*r.m[2] + m[4]*r.m[5] + m[5]*r.m[8];
407
408        p.m[6] = m[6]*r.m[0] + m[7]*r.m[3] + m[8]*r.m[6];
409        p.m[7] = m[6]*r.m[1] + m[7]*r.m[4] + m[8]*r.m[7];
410        p.m[8] = m[6]*r.m[2] + m[7]*r.m[5] + m[8]*r.m[8];
411
412        return p;
[2190]413}
414
415
416/**
[4836]417 *  rotates the vector by the given rotation
418 * @param v: a vector
419 * @param r: a rotation
420 * @return the rotated vector
[2043]421*/
[3228]422Vector rotateVector( const Vector& v, const Rotation& r)
[2043]423{
424  Vector t;
[4578]425
[2043]426  t.x = v.x * r.m[0] + v.y * r.m[1] + v.z * r.m[2];
427  t.y = v.x * r.m[3] + v.y * r.m[4] + v.z * r.m[5];
428  t.z = v.x * r.m[6] + v.y * r.m[7] + v.z * r.m[8];
429
430  return t;
431}
432
433/**
[4836]434 *  calculate the distance between two lines
435 * @param l: the other line
436 * @return the distance between the lines
[2043]437*/
438float Line::distance (const Line& l) const
439{
440  float q, d;
441  Vector n = a.cross(l.a);
442  q = n.dot(r-l.r);
443  d = n.len();
444  if( d == 0.0) return 0.0;
445  return q/d;
446}
447
448/**
[4836]449 *  calculate the distance between a line and a point
450 * @param v: the point
451 * @return the distance between the Line and the point
[2043]452*/
[3228]453float Line::distancePoint (const Vector& v) const
[2043]454{
455  Vector d = v-r;
456  Vector u = a * d.dot( a);
457  return (d - u).len();
458}
459
460/**
[4836]461 *  calculate the distance between a line and a point
462 * @param v: the point
463 * @return the distance between the Line and the point
[4578]464 */
465float Line::distancePoint (const sVec3D& v) const
466{
467  Vector s(v[0], v[1], v[2]);
468  Vector d = s - r;
469  Vector u = a * d.dot( a);
470  return (d - u).len();
471}
472
473/**
[4836]474 *  calculate the two points of minimal distance of two lines
475 * @param l: the other line
476 * @return a Vector[2] (!has to be deleted after use!) containing the two points of minimal distance
[2043]477*/
478Vector* Line::footpoints (const Line& l) const
479{
480  Vector* fp = new Vector[2];
481  Plane p = Plane (r + a.cross(l.a), r, r + a);
[3234]482  fp[1] = p.intersectLine (l);
[2043]483  p = Plane (fp[1], l.a);
[3234]484  fp[0] = p.intersectLine (*this);
[2043]485  return fp;
486}
487
488/**
489  \brief calculate the length of a line
[4578]490  \return the lenght of the line
[2043]491*/
492float Line::len() const
493{
494  return a.len();
495}
496
497/**
[4836]498 *  rotate the line by given rotation
499 * @param rot: a rotation
[2043]500*/
501void Line::rotate (const Rotation& rot)
502{
503  Vector t = a + r;
[3234]504  t = rotateVector( t, rot);
505  r = rotateVector( r, rot),
[2043]506  a = t - r;
507}
508
509/**
[4836]510 *  create a plane from three points
511 * @param a: first point
512 * @param b: second point
513 * @param c: third point
[2043]514*/
[5688]515Plane::Plane (const Vector& a, const Vector& b, const Vector& c)
[2043]516{
517  n = (a-b).cross(c-b);
518  k = -(n.x*b.x+n.y*b.y+n.z*b.z);
519}
520
521/**
[4836]522 *  create a plane from anchor point and normal
523 * @param norm: normal vector
524 * @param p: anchor point
[2043]525*/
[5688]526Plane::Plane (const Vector& norm, const Vector& p)
[2043]527{
528  n = norm;
529  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
530}
531
[4611]532
[2043]533/**
[4836]534  *  create a plane from anchor point and normal
535  * @param norm: normal vector
536  * @param p: anchor point
[4611]537*/
[5688]538Plane::Plane (const Vector& norm, const sVec3D& g)
[4611]539{
540  Vector p(g[0], g[1], g[2]);
541  n = norm;
542  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
543}
544
545
546/**
[4836]547 *  returns the intersection point between the plane and a line
548 * @param l: a line
[2043]549*/
[3228]550Vector Plane::intersectLine (const Line& l) const
[2043]551{
552  if (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z == 0.0) return Vector(0,0,0);
553  float t = (n.x*l.r.x+n.y*l.r.y+n.z*l.r.z+k) / (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z);
554  return l.r + (l.a * t);
555}
556
557/**
[4836]558 *  returns the distance between the plane and a point
559 * @param p: a Point
560 * @return the distance between the plane and the point (can be negative)
[2043]561*/
[3228]562float Plane::distancePoint (const Vector& p) const
[2043]563{
564  float l = n.len();
565  if( l == 0.0) return 0.0;
566  return (n.dot(p) + k) / n.len();
567}
568
[4585]569
[2043]570/**
[4836]571 *  returns the distance between the plane and a point
572 * @param p: a Point
573 * @return the distance between the plane and the point (can be negative)
[4585]574 */
575float Plane::distancePoint (const sVec3D& p) const
576{
577  Vector s(p[0], p[1], p[2]);
578  float l = n.len();
579  if( l == 0.0) return 0.0;
580  return (n.dot(s) + k) / n.len();
581}
582
583
584/**
[4836]585 *  returns the side a point is located relative to a Plane
586 * @param p: a Point
587 * @return 0 if the point is contained within the Plane, positive(negative) if the point is in the positive(negative) semi-space of the Plane
[2043]588*/
[3228]589float Plane::locatePoint (const Vector& p) const
[2043]590{
591  return (n.dot(p) + k);
592}
[3000]593
Note: See TracBrowser for help on using the repository browser.