Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: the Quaternion multiplication-code is much faster now.
The previous approach was to brute force, and the new one is inlined :)

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
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 *  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
284/**
285 *  create a rotation from a vector
286 * @param v: a vector
287*/
288Rotation::Rotation (const Vector& v)
289{
290  Vector x = Vector( 1, 0, 0);
291  Vector axis = x.cross( v);
292  axis.normalize();
293  float angle = angleRad( x, v);
294  float ca = cos(angle);
295  float sa = sin(angle);
296  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
297  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
298  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
299  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
300  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
301  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
302  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
303  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
304  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
305}
306
307/**
308 *  creates a rotation from an axis and an angle (radians!)
309 * @param axis: the rotational axis
310 * @param angle: the angle in radians
311*/
312Rotation::Rotation (const Vector& axis, float angle)
313{
314  float ca, sa;
315  ca = cos(angle);
316  sa = sin(angle);
317  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
318  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
319  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
320  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
321  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
322  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
323  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
324  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
325  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
326}
327
328/**
329 *  creates a rotation from euler angles (pitch/yaw/roll)
330 * @param pitch: rotation around z (in radians)
331 * @param yaw: rotation around y (in radians)
332 * @param roll: rotation around x (in radians)
333*/
334Rotation::Rotation ( float pitch, float yaw, float roll)
335{
336  float cy, sy, cr, sr, cp, sp;
337  cy = cos(yaw);
338  sy = sin(yaw);
339  cr = cos(roll);
340  sr = sin(roll);
341  cp = cos(pitch);
342  sp = sin(pitch);
343  m[0] = cy*cr;
344  m[1] = -cy*sr;
345  m[2] = sy;
346  m[3] = cp*sr+sp*sy*cr;
347  m[4] = cp*cr-sp*sr*sy;
348  m[5] = -sp*cy;
349  m[6] = sp*sr-cp*sy*cr;
350  m[7] = sp*cr+cp*sy*sr;
351  m[8] = cp*cy;
352}
353
354/**
355 *  creates a nullrotation (an identity rotation)
356*/
357Rotation::Rotation ()
358{
359  m[0] = 1.0f;
360  m[1] = 0.0f;
361  m[2] = 0.0f;
362  m[3] = 0.0f;
363  m[4] = 1.0f;
364  m[5] = 0.0f;
365  m[6] = 0.0f;
366  m[7] = 0.0f;
367  m[8] = 1.0f;
368}
369
370/**
371 *  fills the specified buffer with a 4x4 glmatrix
372 * @param buffer: Pointer to an array of 16 floats
373
374   Use this to get the rotation in a gl-compatible format
375*/
376void Rotation::glmatrix (float* buffer)
377{
378        buffer[0] = m[0];
379        buffer[1] = m[3];
380        buffer[2] = m[6];
381        buffer[3] = m[0];
382        buffer[4] = m[1];
383        buffer[5] = m[4];
384        buffer[6] = m[7];
385        buffer[7] = m[0];
386        buffer[8] = m[2];
387        buffer[9] = m[5];
388        buffer[10] = m[8];
389        buffer[11] = m[0];
390        buffer[12] = m[0];
391        buffer[13] = m[0];
392        buffer[14] = m[0];
393        buffer[15] = m[1];
394}
395
396/**
397 *  multiplies two rotational matrices
398 * @param r: another Rotation
399 * @return the matrix product of the Rotations
400
401   Use this to rotate one rotation by another
402*/
403Rotation Rotation::operator* (const Rotation& r)
404{
405        Rotation p;
406
407        p.m[0] = m[0]*r.m[0] + m[1]*r.m[3] + m[2]*r.m[6];
408        p.m[1] = m[0]*r.m[1] + m[1]*r.m[4] + m[2]*r.m[7];
409        p.m[2] = m[0]*r.m[2] + m[1]*r.m[5] + m[2]*r.m[8];
410
411        p.m[3] = m[3]*r.m[0] + m[4]*r.m[3] + m[5]*r.m[6];
412        p.m[4] = m[3]*r.m[1] + m[4]*r.m[4] + m[5]*r.m[7];
413        p.m[5] = m[3]*r.m[2] + m[4]*r.m[5] + m[5]*r.m[8];
414
415        p.m[6] = m[6]*r.m[0] + m[7]*r.m[3] + m[8]*r.m[6];
416        p.m[7] = m[6]*r.m[1] + m[7]*r.m[4] + m[8]*r.m[7];
417        p.m[8] = m[6]*r.m[2] + m[7]*r.m[5] + m[8]*r.m[8];
418
419        return p;
420}
421
422
423/**
424 *  rotates the vector by the given rotation
425 * @param v: a vector
426 * @param r: a rotation
427 * @return the rotated vector
428*/
429Vector rotateVector( const Vector& v, const Rotation& r)
430{
431  Vector t;
432
433  t.x = v.x * r.m[0] + v.y * r.m[1] + v.z * r.m[2];
434  t.y = v.x * r.m[3] + v.y * r.m[4] + v.z * r.m[5];
435  t.z = v.x * r.m[6] + v.y * r.m[7] + v.z * r.m[8];
436
437  return t;
438}
439
440/**
441 *  calculate the distance between two lines
442 * @param l: the other line
443 * @return the distance between the lines
444*/
445float Line::distance (const Line& l) const
446{
447  float q, d;
448  Vector n = a.cross(l.a);
449  q = n.dot(r-l.r);
450  d = n.len();
451  if( d == 0.0) return 0.0;
452  return q/d;
453}
454
455/**
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
459*/
460float Line::distancePoint (const Vector& v) const
461{
462  Vector d = v-r;
463  Vector u = a * d.dot( a);
464  return (d - u).len();
465}
466
467/**
468 *  calculate the distance between a line and a point
469 * @param v: the point
470 * @return the distance between the Line and the point
471 */
472float Line::distancePoint (const sVec3D& v) const
473{
474  Vector s(v[0], v[1], v[2]);
475  Vector d = s - r;
476  Vector u = a * d.dot( a);
477  return (d - u).len();
478}
479
480/**
481 *  calculate the two points of minimal distance of two lines
482 * @param l: the other line
483 * @return a Vector[2] (!has to be deleted after use!) containing the two points of minimal distance
484*/
485Vector* Line::footpoints (const Line& l) const
486{
487  Vector* fp = new Vector[2];
488  Plane p = Plane (r + a.cross(l.a), r, r + a);
489  fp[1] = p.intersectLine (l);
490  p = Plane (fp[1], l.a);
491  fp[0] = p.intersectLine (*this);
492  return fp;
493}
494
495/**
496  \brief calculate the length of a line
497  \return the lenght of the line
498*/
499float Line::len() const
500{
501  return a.len();
502}
503
504/**
505 *  rotate the line by given rotation
506 * @param rot: a rotation
507*/
508void Line::rotate (const Rotation& rot)
509{
510  Vector t = a + r;
511  t = rotateVector( t, rot);
512  r = rotateVector( r, rot),
513  a = t - r;
514}
515
516/**
517 *  create a plane from three points
518 * @param a: first point
519 * @param b: second point
520 * @param c: third point
521*/
522Plane::Plane (Vector a, Vector b, Vector c)
523{
524  n = (a-b).cross(c-b);
525  k = -(n.x*b.x+n.y*b.y+n.z*b.z);
526}
527
528/**
529 *  create a plane from anchor point and normal
530 * @param norm: normal vector
531 * @param p: anchor point
532*/
533Plane::Plane (Vector norm, Vector p)
534{
535  n = norm;
536  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
537}
538
539
540/**
541  *  create a plane from anchor point and normal
542  * @param norm: normal vector
543  * @param p: anchor point
544*/
545Plane::Plane (Vector norm, sVec3D g)
546{
547  Vector p(g[0], g[1], g[2]);
548  n = norm;
549  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
550}
551
552
553/**
554 *  returns the intersection point between the plane and a line
555 * @param l: a line
556*/
557Vector Plane::intersectLine (const Line& l) const
558{
559  if (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z == 0.0) return Vector(0,0,0);
560  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);
561  return l.r + (l.a * t);
562}
563
564/**
565 *  returns the distance between the plane and a point
566 * @param p: a Point
567 * @return the distance between the plane and the point (can be negative)
568*/
569float Plane::distancePoint (const Vector& p) const
570{
571  float l = n.len();
572  if( l == 0.0) return 0.0;
573  return (n.dot(p) + k) / n.len();
574}
575
576
577/**
578 *  returns the distance between the plane and a point
579 * @param p: a Point
580 * @return the distance between the plane and the point (can be negative)
581 */
582float Plane::distancePoint (const sVec3D& p) const
583{
584  Vector s(p[0], p[1], p[2]);
585  float l = n.len();
586  if( l == 0.0) return 0.0;
587  return (n.dot(s) + k) / n.len();
588}
589
590
591/**
592 *  returns the side a point is located relative to a Plane
593 * @param p: a Point
594 * @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
595*/
596float Plane::locatePoint (const Vector& p) const
597{
598  return (n.dot(p) + k);
599}
600
Note: See TracBrowser for help on using the repository browser.