Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: created a simple matrix class

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