Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk :documented the vector class

File size: 15.6 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
19#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_MATH
20
21#include "vector.h"
22#include "debug.h"
23
24using namespace std;
25
26/**
27   \brief returns the this-vector normalized to length 1.0
28*/
29Vector Vector::getNormalized() const
30{
31  float l = len();
32  if(unlikely(l != 1.0))
33    {
34      return *this;
35    }
36  else if(unlikely(l == 0.0))
37    {
38      return *this;
39    }
40
41  return *this / l;
42}
43
44/**
45   \brief Outputs the values of the Vector
46*/
47void Vector::debug(void) const
48{
49  PRINT(0)("Vector Debug information\n");
50  PRINT(0)("x: %f; y: %f; z: %f", x, y, z);
51  PRINT(3)(" lenght: %f", len());
52  PRINT(0)("\n");
53}
54
55/**
56        \brief creates a multiplicational identity Quaternion
57*/
58//Quaternion::Quaternion ()
59
60
61/**
62        \brief turns a rotation along an axis into a Quaternion
63        \param angle: the amount of radians to rotate
64        \param axis: the axis to rotate around
65*/
66//Quaternion::Quaternion (float angle, const Vector& axis)
67
68
69/**
70   \brief calculates a lookAt rotation
71   \param dir: the direction you want to look
72   \param up: specify what direction up should be
73   
74   Mathematically this determines the rotation a (0,0,1)-Vector has to undergo to point
75   the same way as dir. If you want to use this with cameras, you'll have to reverse the
76   dir Vector (Vector(0,0,0) - your viewing direction) or you'll point the wrong way. You
77   can use this for meshes as well (then you do not have to reverse the vector), but keep
78   in mind that if you do that, the model's front has to point in +z direction, and left
79   and right should be -x or +x respectively or the mesh wont rotate correctly.
80*/
81Quaternion::Quaternion (const Vector& dir, const Vector& up)
82{
83  Vector z = dir;
84  z.normalize(); 
85  Vector x = up.cross(z);
86  x.normalize(); 
87  Vector y = z.cross(x);
88 
89  float m[4][4];
90  m[0][0] = x.x;
91  m[0][1] = x.y;
92  m[0][2] = x.z;
93  m[0][3] = 0;
94  m[1][0] = y.x;
95  m[1][1] = y.y;
96  m[1][2] = y.z;
97  m[1][3] = 0;
98  m[2][0] = z.x;
99  m[2][1] = z.y;
100  m[2][2] = z.z;
101  m[2][3] = 0;
102  m[3][0] = 0;
103  m[3][1] = 0;
104  m[3][2] = 0;
105  m[3][3] = 1;
106 
107  *this = Quaternion (m);
108}
109
110/**
111        \brief calculates a rotation from euler angles
112        \param roll: the roll in radians
113        \param pitch: the pitch in radians
114        \param yaw: the yaw in radians
115       
116        I DO HONESTLY NOT EXACTLY KNOW WHICH ANGLE REPRESENTS WHICH ROTATION. And I do not know
117        in what order they are applied, I just copy-pasted the code.
118*/
119Quaternion::Quaternion (float roll, float pitch, float yaw)
120{
121        float cr, cp, cy, sr, sp, sy, cpcy, spsy;
122       
123        // calculate trig identities
124        cr = cos(roll/2);
125        cp = cos(pitch/2);
126        cy = cos(yaw/2);
127       
128        sr = sin(roll/2);
129        sp = sin(pitch/2);
130        sy = sin(yaw/2);
131       
132        cpcy = cp * cy;
133        spsy = sp * sy;
134       
135        w = cr * cpcy + sr * spsy;
136        v.x = sr * cpcy - cr * spsy;
137        v.y = cr * sp * cy + sr * cp * sy;
138        v.z = cr * cp * sy - sr * sp * cy;
139}
140
141/**
142        \brief rotates one Quaternion by another
143        \param q: another Quaternion to rotate this by
144        \return a quaternion that represents the first one rotated by the second one (WARUNING: this operation is not commutative! e.g. (A*B) != (B*A))
145*/
146Quaternion Quaternion::operator*(const Quaternion& q) const
147{
148  float A, B, C, D, E, F, G, H;
149 
150  A = (w   + v.x)*(q.w   + q.v.x);
151  B = (v.z - v.y)*(q.v.y - q.v.z);
152  C = (w   - v.x)*(q.v.y + q.v.z); 
153  D = (v.y + v.z)*(q.w   - q.v.x);
154  E = (v.x + v.z)*(q.v.x + q.v.y);
155  F = (v.x - v.z)*(q.v.x - q.v.y);
156  G = (w   + v.y)*(q.w   - q.v.z);
157  H = (w   - v.y)*(q.w   + q.v.z);
158 
159  Quaternion r;
160  r.v.x = A - (E + F + G + H)/2;
161  r.v.y = C + (E - F + G - H)/2;
162  r.v.z = D + (E - F - G + H)/2;
163  r.w = B +  (-E - F + G + H)/2;
164
165  return r;
166}
167
168/**
169   \brief add two Quaternions
170   \param q: another Quaternion
171   \return the sum of both Quaternions
172*/
173/*
174Quaternion Quaternion::operator+(const Quaternion& q) const
175{
176  Quaternion r(*this);
177  r.w = r.w + q.w;
178  r.v = r.v + q.v;
179  return r;
180}
181*/
182
183/**
184   \brief subtract two Quaternions
185   \param q: another Quaternion
186   \return the difference of both Quaternions
187*/
188/*
189Quaternion Quaternion::operator- (const Quaternion& q) const
190{
191  Quaternion r(*this);
192  r.w = r.w - q.w;
193  r.v = r.v - q.v;
194  return r;
195}
196*/
197
198/**
199   \brief rotate a Vector by a Quaternion
200   \param v: the Vector
201   \return a new Vector representing v rotated by the Quaternion
202*/
203
204Vector Quaternion::apply (const Vector& v) const
205{
206  Quaternion q;
207  q.v = v;
208  q.w = 0;
209  q = *this * q * conjugate();
210  return q.v;
211}
212
213
214/**
215   \brief multiply a Quaternion with a real value
216   \param f: a real value
217   \return a new Quaternion containing the product
218*/
219Quaternion Quaternion::operator*(const float& f) const
220{
221  Quaternion r(*this);
222  r.w = r.w*f;
223  r.v = r.v*f;
224  return r;
225}
226
227/**
228   \brief divide a Quaternion by a real value
229   \param f: a real value
230   \return a new Quaternion containing the quotient
231*/
232Quaternion Quaternion::operator/(const float& f) const
233{
234  if( f == 0) return Quaternion();
235  Quaternion r(*this);
236  r.w = r.w/f;
237  r.v = r.v/f;
238  return r;
239}
240
241/**
242   \brief calculate the conjugate value of the Quaternion
243   \return the conjugate Quaternion
244*/
245/*
246Quaternion Quaternion::conjugate() const
247{
248  Quaternion r(*this);
249  r.v = Vector() - r.v;
250  return r;
251}
252*/
253
254/**
255   \brief calculate the norm of the Quaternion
256   \return the norm of The Quaternion
257*/
258float Quaternion::norm() const
259{
260  return w*w + v.x*v.x + v.y*v.y + v.z*v.z;
261}
262
263/**
264   \brief calculate the inverse value of the Quaternion
265   \return the inverse Quaternion
266   
267        Note that this is equal to conjugate() if the Quaternion's norm is 1
268*/
269Quaternion Quaternion::inverse() const
270{
271  float n = norm();
272  if (n != 0)
273    {
274      return conjugate() / norm();
275    }
276  else return Quaternion();
277}
278
279/**
280   \brief convert the Quaternion to a 4x4 rotational glMatrix
281   \param m: a buffer to store the Matrix in
282*/
283void Quaternion::matrix (float m[4][4]) const
284{
285  float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; 
286 
287  // calculate coefficients
288  x2 = v.x + v.x;
289  y2 = v.y + v.y; 
290  z2 = v.z + v.z;
291  xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
292  yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
293  wx = w * x2; wy = w * y2; wz = w * z2;
294 
295  m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
296  m[2][0] = xz + wy; m[3][0] = 0.0;
297       
298  m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
299  m[2][1] = yz - wx; m[3][1] = 0.0;
300 
301  m[0][2] = xz - wy; m[1][2] = yz + wx;
302  m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
303 
304  m[0][3] = 0; m[1][3] = 0;
305  m[2][3] = 0; m[3][3] = 1;
306}
307
308/**
309   \brief performs a smooth move.
310   \param from  where
311   \param to where
312   \param t the time this transformation should take value [0..1]
313
314   \returns the Result of the smooth move
315*/
316Quaternion quatSlerp(const Quaternion& from, const Quaternion& to, float t)
317{
318  float tol[4];
319  double omega, cosom, sinom, scale0, scale1;
320  //  float DELTA = 0.2;
321
322  cosom = from.v.x * to.v.x + from.v.y * to.v.y + from.v.z * to.v.z + from.w * to.w;
323
324  if( cosom < 0.0 ) 
325    { 
326      cosom = -cosom; 
327      tol[0] = -to.v.x;
328      tol[1] = -to.v.y;
329      tol[2] = -to.v.z;
330      tol[3] = -to.w;
331    }
332  else
333    {
334      tol[0] = to.v.x;
335      tol[1] = to.v.y;
336      tol[2] = to.v.z;
337      tol[3] = to.w;
338    }
339 
340  //if( (1.0 - cosom) > DELTA )
341  //{
342  omega = acos(cosom);
343  sinom = sin(omega);
344  scale0 = sin((1.0 - t) * omega) / sinom;
345  scale1 = sin(t * omega) / sinom;
346  //}
347  /*
348    else
349    {
350    scale0 = 1.0 - t;
351    scale1 = t;
352    }
353  */
354
355
356  /*
357    Quaternion res;
358    res.v.x = scale0 * from.v.x + scale1 * tol[0];
359    res.v.y = scale0 * from.v.y + scale1 * tol[1];
360    res.v.z = scale0 * from.v.z + scale1 * tol[2];
361    res.w = scale0 * from.w + scale1 * tol[3];
362  */
363  return Quaternion(Vector(scale0 * from.v.x + scale1 * tol[0],
364                           scale0 * from.v.y + scale1 * tol[1],
365                           scale0 * from.v.z + scale1 * tol[2]),
366                    scale0 * from.w + scale1 * tol[3]);
367}
368
369
370/**
371   \brief convert a rotational 4x4 glMatrix into a Quaternion
372   \param m: a 4x4 matrix in glMatrix order
373*/
374Quaternion::Quaternion (float m[4][4])
375{
376       
377  float  tr, s, q[4];
378  int    i, j, k;
379
380  int nxt[3] = {1, 2, 0};
381
382  tr = m[0][0] + m[1][1] + m[2][2];
383
384        // check the diagonal
385  if (tr > 0.0) 
386  {
387    s = sqrt (tr + 1.0);
388    w = s / 2.0;
389    s = 0.5 / s;
390    v.x = (m[1][2] - m[2][1]) * s;
391    v.y = (m[2][0] - m[0][2]) * s;
392    v.z = (m[0][1] - m[1][0]) * s;
393        } 
394        else 
395        {
396                // diagonal is negative
397        i = 0;
398        if (m[1][1] > m[0][0]) i = 1;
399    if (m[2][2] > m[i][i]) i = 2;
400    j = nxt[i];
401    k = nxt[j];
402
403    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
404     
405    q[i] = s * 0.5;
406           
407    if (s != 0.0) s = 0.5 / s;
408       
409          q[3] = (m[j][k] - m[k][j]) * s;
410    q[j] = (m[i][j] + m[j][i]) * s;
411    q[k] = (m[i][k] + m[k][i]) * s;
412
413        v.x = q[0];
414        v.y = q[1];
415        v.z = q[2];
416        w = q[3];
417  }
418}
419
420/**
421   \brief outputs some nice formated debug information about this quaternion
422*/
423void Quaternion::debug(void)
424{
425  PRINT(0)("Quaternion Debug Information\n");
426  PRINT(0)("real a=%f; imag: x=%f y=%f z=%f\n", w, v.x, v.y, v.z);
427}
428
429/**
430   \brief create a rotation from a vector
431   \param v: a vector
432*/
433Rotation::Rotation (const Vector& v)
434{
435  Vector x = Vector( 1, 0, 0);
436  Vector axis = x.cross( v);
437  axis.normalize();
438  float angle = angleRad( x, v);
439  float ca = cos(angle);
440  float sa = sin(angle);
441  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
442  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
443  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
444  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
445  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
446  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
447  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
448  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
449  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
450}
451
452/**
453   \brief creates a rotation from an axis and an angle (radians!)
454   \param axis: the rotational axis
455   \param angle: the angle in radians
456*/
457Rotation::Rotation (const Vector& axis, float angle)
458{
459  float ca, sa;
460  ca = cos(angle);
461  sa = sin(angle);
462  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
463  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
464  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
465  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
466  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
467  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
468  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
469  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
470  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
471}
472
473/**
474   \brief creates a rotation from euler angles (pitch/yaw/roll)
475   \param pitch: rotation around z (in radians)
476   \param yaw: rotation around y (in radians)
477   \param roll: rotation around x (in radians)
478*/
479Rotation::Rotation ( float pitch, float yaw, float roll)
480{
481  float cy, sy, cr, sr, cp, sp;
482  cy = cos(yaw);
483  sy = sin(yaw);
484  cr = cos(roll);
485  sr = sin(roll);
486  cp = cos(pitch);
487  sp = sin(pitch);
488  m[0] = cy*cr;
489  m[1] = -cy*sr;
490  m[2] = sy;
491  m[3] = cp*sr+sp*sy*cr;
492  m[4] = cp*cr-sp*sr*sy;
493  m[5] = -sp*cy;
494  m[6] = sp*sr-cp*sy*cr;
495  m[7] = sp*cr+cp*sy*sr;
496  m[8] = cp*cy;
497}
498
499/**
500   \brief creates a nullrotation (an identity rotation)
501*/
502Rotation::Rotation ()
503{
504  m[0] = 1.0f;
505  m[1] = 0.0f;
506  m[2] = 0.0f;
507  m[3] = 0.0f;
508  m[4] = 1.0f;
509  m[5] = 0.0f;
510  m[6] = 0.0f;
511  m[7] = 0.0f;
512  m[8] = 1.0f;
513}
514
515/**
516   \brief fills the specified buffer with a 4x4 glmatrix
517   \param buffer: Pointer to an array of 16 floats
518   
519   Use this to get the rotation in a gl-compatible format
520*/
521void Rotation::glmatrix (float* buffer)
522{
523        buffer[0] = m[0];
524        buffer[1] = m[3];
525        buffer[2] = m[6];
526        buffer[3] = m[0];
527        buffer[4] = m[1];
528        buffer[5] = m[4];
529        buffer[6] = m[7];
530        buffer[7] = m[0];
531        buffer[8] = m[2];
532        buffer[9] = m[5];
533        buffer[10] = m[8];
534        buffer[11] = m[0];
535        buffer[12] = m[0];
536        buffer[13] = m[0];
537        buffer[14] = m[0];
538        buffer[15] = m[1];
539}
540
541/**
542   \brief multiplies two rotational matrices
543   \param r: another Rotation
544   \return the matrix product of the Rotations
545   
546   Use this to rotate one rotation by another
547*/
548Rotation Rotation::operator* (const Rotation& r)
549{
550        Rotation p;
551       
552        p.m[0] = m[0]*r.m[0] + m[1]*r.m[3] + m[2]*r.m[6];
553        p.m[1] = m[0]*r.m[1] + m[1]*r.m[4] + m[2]*r.m[7];
554        p.m[2] = m[0]*r.m[2] + m[1]*r.m[5] + m[2]*r.m[8];
555       
556        p.m[3] = m[3]*r.m[0] + m[4]*r.m[3] + m[5]*r.m[6];
557        p.m[4] = m[3]*r.m[1] + m[4]*r.m[4] + m[5]*r.m[7];
558        p.m[5] = m[3]*r.m[2] + m[4]*r.m[5] + m[5]*r.m[8];
559
560        p.m[6] = m[6]*r.m[0] + m[7]*r.m[3] + m[8]*r.m[6];
561        p.m[7] = m[6]*r.m[1] + m[7]*r.m[4] + m[8]*r.m[7];
562        p.m[8] = m[6]*r.m[2] + m[7]*r.m[5] + m[8]*r.m[8];
563       
564        return p;
565}
566
567
568/**
569   \brief rotates the vector by the given rotation
570   \param v: a vector
571   \param r: a rotation
572   \return the rotated vector
573*/
574Vector rotateVector( const Vector& v, const Rotation& r)
575{
576  Vector t;
577 
578  t.x = v.x * r.m[0] + v.y * r.m[1] + v.z * r.m[2];
579  t.y = v.x * r.m[3] + v.y * r.m[4] + v.z * r.m[5];
580  t.z = v.x * r.m[6] + v.y * r.m[7] + v.z * r.m[8];
581
582  return t;
583}
584
585/**
586   \brief calculate the distance between two lines
587   \param l: the other line
588   \return the distance between the lines
589*/
590float Line::distance (const Line& l) const
591{
592  float q, d;
593  Vector n = a.cross(l.a);
594  q = n.dot(r-l.r);
595  d = n.len();
596  if( d == 0.0) return 0.0;
597  return q/d;
598}
599
600/**
601   \brief calculate the distance between a line and a point
602   \param v: the point
603   \return the distance between the Line and the point
604*/
605float Line::distancePoint (const Vector& v) const
606{
607  Vector d = v-r;
608  Vector u = a * d.dot( a);
609  return (d - u).len();
610}
611
612/**
613   \brief calculate the two points of minimal distance of two lines
614   \param l: the other line
615   \return a Vector[2] (!has to be deleted after use!) containing the two points of minimal distance
616*/
617Vector* Line::footpoints (const Line& l) const
618{
619  Vector* fp = new Vector[2];
620  Plane p = Plane (r + a.cross(l.a), r, r + a);
621  fp[1] = p.intersectLine (l);
622  p = Plane (fp[1], l.a);
623  fp[0] = p.intersectLine (*this);
624  return fp;
625}
626
627/**
628  \brief calculate the length of a line
629  \return the lenght of the line
630*/
631float Line::len() const
632{
633  return a.len();
634}
635
636/**
637   \brief rotate the line by given rotation
638   \param rot: a rotation
639*/
640void Line::rotate (const Rotation& rot)
641{
642  Vector t = a + r;
643  t = rotateVector( t, rot);
644  r = rotateVector( r, rot),
645  a = t - r;
646}
647
648/**
649   \brief create a plane from three points
650   \param a: first point
651   \param b: second point
652   \param c: third point
653*/
654Plane::Plane (Vector a, Vector b, Vector c)
655{
656  n = (a-b).cross(c-b);
657  k = -(n.x*b.x+n.y*b.y+n.z*b.z);
658}
659
660/**
661   \brief create a plane from anchor point and normal
662   \param norm: normal vector
663   \param p: anchor point
664*/
665Plane::Plane (Vector norm, Vector p)
666{
667  n = norm;
668  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
669}
670
671/**
672   \brief returns the intersection point between the plane and a line
673   \param l: a line
674*/
675Vector Plane::intersectLine (const Line& l) const
676{
677  if (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z == 0.0) return Vector(0,0,0);
678  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);
679  return l.r + (l.a * t);
680}
681
682/**
683   \brief returns the distance between the plane and a point
684   \param p: a Point
685   \return the distance between the plane and the point (can be negative)
686*/
687float Plane::distancePoint (const Vector& p) const
688{
689  float l = n.len();
690  if( l == 0.0) return 0.0;
691  return (n.dot(p) + k) / n.len();
692}
693
694/**
695   \brief returns the side a point is located relative to a Plane
696   \param p: a Point
697   \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
698*/
699float Plane::locatePoint (const Vector& p) const
700{
701  return (n.dot(p) + k);
702}
703
Note: See TracBrowser for help on using the repository browser.