Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: the const collision detection war - strike

File size: 13.7 KB
Line 
1/*
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:
12   main-programmer: Christian Meyer
13   co-programmer: Patrick Boenzli : Vector::scale()
14                                    Vector::abs()
15
16   Quaternion code borrowed from an Gamasutra article by Nick Bobick and Ken Shoemake
17
18   2005-06-02: Benjamin Grauer: speed up, and new Functionality to Vector (mostly inline now)
19*/
20
21#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_MATH
22
23#include "vector.h"
24#ifdef DEBUG
25  #include "debug.h"
26#else
27  #include <stdio.h>
28  #define PRINT(x) printf
29#endif
30
31using namespace std;
32
33/////////////
34/* VECTORS */
35/////////////
36/**
37 *  returns the this-vector normalized to length 1.0
38 * @todo there is some error in this function, that i could not resolve. it just does not, what it is supposed to do.
39 */
40Vector Vector::getNormalized() const
41{
42  float l = this->len();
43  if(unlikely(l == 1.0 || l == 0.0))
44    return *this;
45  else
46    return (*this / l);
47}
48
49/**
50 *  Vector is looking in the positive direction on all axes after this
51*/
52Vector Vector::abs()
53{
54  Vector v(fabs(x), fabs(y), fabs(z));
55  return v;
56}
57
58
59
60/**
61 *  Outputs the values of the Vector
62 */
63void Vector::debug() const
64{
65  PRINT(0)("x: %f; y: %f; z: %f", x, y, z);
66  PRINT(0)(" lenght: %f", len());
67  PRINT(0)("\n");
68}
69
70/////////////////
71/* QUATERNIONS */
72/////////////////
73/**
74 *  calculates a lookAt rotation
75 * @param dir: the direction you want to look
76 * @param up: specify what direction up should be
77
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
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
83   and right should be -x or +x respectively or the mesh wont rotate correctly.
84 *
85 * @TODO !!! OPTIMIZE THIS !!!
86 */
87Quaternion::Quaternion (const Vector& dir, const Vector& up)
88{
89  Vector z = dir.getNormalized();
90  Vector x = up.cross(z).getNormalized();
91  Vector y = z.cross(x);
92
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;
110
111  *this = Quaternion (m);
112}
113
114/**
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
119 */
120Quaternion::Quaternion (float roll, float pitch, float yaw)
121{
122  float cr, cp, cy, sr, sp, sy, cpcy, spsy;
123
124  // calculate trig identities
125  cr = cos(roll/2);
126  cp = cos(pitch/2);
127  cy = cos(yaw/2);
128
129  sr = sin(roll/2);
130  sp = sin(pitch/2);
131  sy = sin(yaw/2);
132
133  cpcy = cp * cy;
134  spsy = sp * sy;
135
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;
140}
141
142/**
143 *  convert the Quaternion to a 4x4 rotational glMatrix
144 * @param m: a buffer to store the Matrix in
145 */
146void Quaternion::matrix (float m[4][4]) const
147{
148  float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
149
150  // calculate coefficients
151  x2 = v.x + v.x;
152  y2 = v.y + v.y;
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;
157
158  m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
159  m[2][0] = xz + wy; m[3][0] = 0.0;
160
161  m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
162  m[2][1] = yz - wx; m[3][1] = 0.0;
163
164  m[0][2] = xz - wy; m[1][2] = yz + wx;
165  m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
166
167  m[0][3] = 0; m[1][3] = 0;
168  m[2][3] = 0; m[3][3] = 1;
169}
170
171/**
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
177 */
178Quaternion Quaternion::quatSlerp(const Quaternion& from, const Quaternion& to, float t)
179{
180  float tol[4];
181  double omega, cosom, sinom, scale0, scale1;
182  //  float DELTA = 0.2;
183
184  cosom = from.v.x * to.v.x + from.v.y * to.v.y + from.v.z * to.v.z + from.w * to.w;
185
186  if( cosom < 0.0 )
187    {
188      cosom = -cosom;
189      tol[0] = -to.v.x;
190      tol[1] = -to.v.y;
191      tol[2] = -to.v.z;
192      tol[3] = -to.w;
193    }
194  else
195    {
196      tol[0] = to.v.x;
197      tol[1] = to.v.y;
198      tol[2] = to.v.z;
199      tol[3] = to.w;
200    }
201
202  omega = acos(cosom);
203  sinom = sin(omega);
204  scale0 = sin((1.0 - t) * omega) / sinom;
205  scale1 = sin(t * omega) / sinom;
206  return Quaternion(Vector(scale0 * from.v.x + scale1 * tol[0],
207                    scale0 * from.v.y + scale1 * tol[1],
208                    scale0 * from.v.z + scale1 * tol[2]),
209                    scale0 * from.w + scale1 * tol[3]);
210}
211
212
213/**
214 *  convert a rotational 4x4 glMatrix into a Quaternion
215 * @param m: a 4x4 matrix in glMatrix order
216 */
217Quaternion::Quaternion (float m[4][4])
218{
219
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
227        // check the diagonal
228  if (tr > 0.0)
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;
236        }
237        else
238        {
239                // diagonal is negative
240        i = 0;
241        if (m[1][1] > m[0][0]) i = 1;
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);
247
248    q[i] = s * 0.5;
249
250    if (s != 0.0) s = 0.5 / s;
251
252          q[3] = (m[j][k] - m[k][j]) * s;
253    q[j] = (m[i][j] + m[j][i]) * s;
254    q[k] = (m[i][k] + m[k][i]) * s;
255
256        v.x = q[0];
257        v.y = q[1];
258        v.z = q[2];
259        w = q[3];
260  }
261}
262
263/**
264 *  outputs some nice formated debug information about this quaternion
265*/
266void Quaternion::debug()
267{
268  PRINT(0)("real a=%f; imag: x=%f y=%f z=%f\n", w, v.x, v.y, v.z);
269}
270
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
277/**
278 *  create a rotation from a vector
279 * @param v: a vector
280*/
281Rotation::Rotation (const Vector& v)
282{
283  Vector x = Vector( 1, 0, 0);
284  Vector axis = x.cross( v);
285  axis.normalize();
286  float angle = angleRad( x, v);
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/**
301 *  creates a rotation from an axis and an angle (radians!)
302 * @param axis: the rotational axis
303 * @param angle: the angle in radians
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/**
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)
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/**
348 *  creates a nullrotation (an identity rotation)
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/**
364 *  fills the specified buffer with a 4x4 glmatrix
365 * @param buffer: Pointer to an array of 16 floats
366
367   Use this to get the rotation in a gl-compatible format
368*/
369void Rotation::glmatrix (float* buffer)
370{
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];
387}
388
389/**
390 *  multiplies two rotational matrices
391 * @param r: another Rotation
392 * @return the matrix product of the Rotations
393
394   Use this to rotate one rotation by another
395*/
396Rotation Rotation::operator* (const Rotation& r)
397{
398        Rotation p;
399
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;
413}
414
415
416/**
417 *  rotates the vector by the given rotation
418 * @param v: a vector
419 * @param r: a rotation
420 * @return the rotated vector
421*/
422Vector rotateVector( const Vector& v, const Rotation& r)
423{
424  Vector t;
425
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/**
434 *  calculate the distance between two lines
435 * @param l: the other line
436 * @return the distance between the lines
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/**
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
452*/
453float Line::distancePoint (const Vector& v) const
454{
455  Vector d = v-r;
456  Vector u = a * d.dot( a);
457  return (d - u).len();
458}
459
460/**
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
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/**
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
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);
482  fp[1] = p.intersectLine (l);
483  p = Plane (fp[1], l.a);
484  fp[0] = p.intersectLine (*this);
485  return fp;
486}
487
488/**
489  \brief calculate the length of a line
490  \return the lenght of the line
491*/
492float Line::len() const
493{
494  return a.len();
495}
496
497/**
498 *  rotate the line by given rotation
499 * @param rot: a rotation
500*/
501void Line::rotate (const Rotation& rot)
502{
503  Vector t = a + r;
504  t = rotateVector( t, rot);
505  r = rotateVector( r, rot),
506  a = t - r;
507}
508
509/**
510 *  create a plane from three points
511 * @param a: first point
512 * @param b: second point
513 * @param c: third point
514*/
515Plane::Plane (const Vector& a, const Vector& b, const Vector& c)
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/**
522 *  create a plane from anchor point and normal
523 * @param norm: normal vector
524 * @param p: anchor point
525*/
526Plane::Plane (const Vector& norm, const Vector& p)
527{
528  n = norm;
529  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
530}
531
532
533/**
534  *  create a plane from anchor point and normal
535  * @param norm: normal vector
536  * @param p: anchor point
537*/
538Plane::Plane (const Vector& norm, const sVec3D& g)
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/**
547 *  returns the intersection point between the plane and a line
548 * @param l: a line
549*/
550Vector Plane::intersectLine (const Line& l) const
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/**
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)
561*/
562float Plane::distancePoint (const Vector& p) const
563{
564  float l = n.len();
565  if( l == 0.0) return 0.0;
566  return (n.dot(p) + k) / n.len();
567}
568
569
570/**
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)
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/**
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
588*/
589float Plane::locatePoint (const Vector& p) const
590{
591  return (n.dot(p) + k);
592}
593
Note: See TracBrowser for help on using the repository browser.