Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: created a simple matrix class

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