Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: Font is now Right, and the Rendering 'should be' faster.

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