Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: quatSchlarp works

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