Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: fixed the axis length bug

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