Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: introducing smooth-PNode

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