Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/chris/src/vector.cc @ 2624

Last change on this file since 2624 was 2141, checked in by chris, 20 years ago

orxonox/branches/chris: added lots and lots of doxygen tags

File size: 16.1 KB
Line 
1
2
3/*
4   orxonox - the future of 3D-vertical-scrollers
5
6   Copyright (C) 2004 orx
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   ### File Specific:
14   main-programmer: Christian Meyer
15   co-programmer: ...
16   
17   Quaternion code borrowed from an Gamasutra article by Nick Bobick and Ken Shoemake
18*/
19
20
21#include "vector.h"
22
23
24using namespace std;
25
26/**
27   \brief add two vectors
28   \param v: the other vector
29   \return the sum of both vectors
30*/
31Vector Vector::operator+ (const Vector& v) const
32{
33  Vector r;
34 
35  r.x = x + v.x;
36  r.y = y + v.y;
37  r.z = z + v.z;
38 
39  return r;
40}
41
42/**
43   \brief subtract a vector from another
44   \param v: the other vector
45   \return the difference between the vectors
46*/
47Vector Vector::operator- (const Vector& v) const
48{
49  Vector r;
50 
51  r.x = x - v.x;
52  r.y = y - v.y;
53  r.z = z - v.z;
54 
55  return r;
56}
57
58/**
59   \brief calculate the dot product of two vectors
60   \param v: the other vector
61   \return the dot product of the vectors
62*/
63float Vector::operator* (const Vector& v) const
64{
65  return x*v.x+y*v.y+z*v.z;
66}
67
68/**
69   \brief multiply a vector with a float
70   \param f: the factor
71   \return the vector multipied by f
72*/
73Vector Vector::operator* (float f) const
74{ 
75  Vector r;
76 
77  r.x = x * f;
78  r.y = y * f;
79  r.z = z * f;
80 
81  return r;
82}
83
84/**
85   \brief divide a vector with a float
86   \param f: the divisor
87   \return the vector divided by f   
88*/
89Vector Vector::operator/ (float f) const
90{
91  Vector r;
92 
93  if( f == 0.0)
94  {
95    // Prevent divide by zero
96    return Vector (0,0,0);
97  }
98 
99  r.x = x / f;
100  r.y = y / f;
101  r.z = z / f;
102 
103  return r;
104}
105
106/**
107   \brief calculate the dot product of two vectors
108   \param v: the other vector
109   \return the dot product of the vectors
110*/
111float Vector::dot (const Vector& v) const
112{
113  return x*v.x+y*v.y+z*v.z;
114}
115
116/**
117  \brief calculate the cross product of two vectors
118  \param v: the other vector
119        \return the cross product of the vectors
120*/
121Vector Vector::cross (const Vector& v) const
122{
123  Vector r;
124 
125  r.x = y * v.z - z * v.y;
126  r.y = z * v.x - x * v.z;
127  r.z = x * v.y - y * v.x;
128 
129  return r;
130}
131 
132/**
133   \brief normalizes the vector to lenght 1.0
134*/
135void Vector::normalize ()
136{
137  float l = len();
138 
139  if( l == 0.0)
140  {
141    // Prevent divide by zero
142    return;
143  }
144 
145  x = x / l;
146  y = y / l;
147  z = z / l;
148}
149 
150/**
151   \brief calculates the lenght of the vector
152   \return the lenght of the vector
153*/
154float Vector::len () const
155{
156  return sqrt (x*x+y*y+z*z);
157}
158
159/**
160   \brief calculate the angle between two vectors in radiances
161   \param v1: a vector
162   \param v2: another vector
163   \return the angle between the vectors in radians
164*/
165float angle_rad (const Vector& v1, const Vector& v2)
166{
167  return acos( v1 * v2 / (v1.len() * v2.len()));
168}
169
170/**
171   \brief calculate the angle between two vectors in degrees
172   \param v1: a vector
173   \param v2: another vector
174   \return the angle between the vectors in degrees
175*/
176float angle_deg (const Vector& v1, const Vector& v2)
177{
178  float f;
179  f = acos( v1 * v2 / (v1.len() * v2.len()));
180  return f * 180 / PI;
181}
182
183/**
184        \brief creates a multiplicational identity Quaternion
185*/
186Quaternion::Quaternion ()
187{
188        w = 1;
189        v = Vector(0,0,0);
190}
191
192/**
193        \brief turns a rotation along an axis into a Quaternion
194        \param angle: the amount of radians to rotate
195        \param axis: the axis to rotate around
196*/
197Quaternion::Quaternion (float angle, const Vector& axis)
198{
199        w = cos(angle/2);
200        v = axis * sin(angle/2);
201}
202
203/**
204        \brief calculates a look_at rotation
205        \param dir: the direction you want to look
206        \param up: specify what direction up should be
207       
208        Mathematically this determines the rotation a (0,0,1)-Vector has to undergo to point the same way as dir.
209        If you want to use this with cameras, you'll have to reverse the dir Vector (Vector(0,0,0) - your viewing direction)
210        or you'll point the wrong way. You can use this for meshes as well (then you do not have to reverse the vector), but keep in mind that if you do that, the model's front
211        has to point in +z direction, and left and right should be -x or +x respectively or the mesh wont rotate correctly.
212*/
213Quaternion::Quaternion (const Vector& dir, const Vector& up)
214{
215        Vector z = dir;
216  z.normalize(); 
217  Vector x = up.cross(z);
218  x.normalize(); 
219  Vector y = z.cross(x);
220 
221  float m[4][4];
222  m[0][0] = x.x;
223  m[0][1] = x.y;
224  m[0][2] = x.z;
225  m[0][3] = 0;
226  m[1][0] = y.x;
227  m[1][1] = y.y;
228  m[1][2] = y.z;
229  m[1][3] = 0;
230  m[2][0] = z.x;
231  m[2][1] = z.y;
232  m[2][2] = z.z;
233  m[2][3] = 0;
234  m[3][0] = 0;
235  m[3][1] = 0;
236  m[3][2] = 0;
237  m[3][3] = 1;
238 
239  *this = Quaternion (m);
240}
241
242/**
243        \brief calculates a rotation from euler angles
244        \param roll: the roll in radians
245        \param pitch: the pitch in radians
246        \param yaw: the yaw in radians
247       
248        I DO HONESTLY NOT EXACTLY KNOW WHICH ANGLE REPRESENTS WHICH ROTATION. And I do not know in what order they are applied,
249        I just copy-pasted the code.
250*/
251Quaternion::Quaternion (float roll, float pitch, float yaw)
252{
253        float cr, cp, cy, sr, sp, sy, cpcy, spsy;
254       
255        // calculate trig identities
256        cr = cos(roll/2);
257        cp = cos(pitch/2);
258        cy = cos(yaw/2);
259       
260        sr = sin(roll/2);
261        sp = sin(pitch/2);
262        sy = sin(yaw/2);
263       
264        cpcy = cp * cy;
265        spsy = sp * sy;
266       
267        w = cr * cpcy + sr * spsy;
268        v.x = sr * cpcy - cr * spsy;
269        v.y = cr * sp * cy + sr * cp * sy;
270        v.z = cr * cp * sy - sr * sp * cy;
271}
272
273/**
274        \brief rotates one Quaternion by another
275        \param q: another Quaternion to rotate this by
276        \return a quaternion that represents the first one rotated by the second one (WARUNING: this operation is not commutative! e.g. (A*B) != (B*A))
277*/
278Quaternion Quaternion::operator*(const Quaternion& q) const
279{
280        float A, B, C, D, E, F, G, H;
281        Quaternion r;
282       
283        A = (w   + v.x)*(q.w   + q.v.x);
284        B = (v.z - v.y)*(q.v.y - q.v.z);
285        C = (w   - v.x)*(q.v.y + q.v.z); 
286        D = (v.y + v.z)*(q.w   - q.v.x);
287        E = (v.x + v.z)*(q.v.x + q.v.y);
288        F = (v.x - v.z)*(q.v.x - q.v.y);
289        G = (w   + v.y)*(q.w   - q.v.z);
290        H = (w   - v.y)*(q.w   + q.v.z);
291       
292        r.w = B +  (-E - F + G + H)/2;
293        r.v.x = A - (E + F + G + H)/2; 
294        r.v.y = C + (E - F + G - H)/2; 
295        r.v.z = D + (E - F - G + H)/2;
296       
297        return r;
298}
299
300/**
301        \brief add two Quaternions
302        \param q: another Quaternion
303        \return the sum of both Quaternions
304*/
305Quaternion Quaternion::operator+(const Quaternion& q) const
306{
307        Quaternion r(*this);
308        r.w = r.w + q.w;
309        r.v = r.v + q.v;
310        return r;
311}
312
313/**
314        \brief subtract two Quaternions
315        \param q: another Quaternion
316        \return the difference of both Quaternions
317*/
318Quaternion Quaternion::operator- (const Quaternion& q) const
319{
320        Quaternion r(*this);
321        r.w = r.w - q.w;
322        r.v = r.v - q.v;
323        return r;
324}
325
326/**
327        \brief rotate a Vector by a Quaternion
328        \param v: the Vector
329        \return a new Vector representing v rotated by the Quaternion
330*/
331Vector Quaternion::apply (Vector& v) const
332{
333        Quaternion q;
334        q.v = v;
335        q.w = 0;
336        q = *this * q * conjugate();
337        return q.v;
338}
339
340/**
341        \brief multiply a Quaternion with a real value
342        \param f: a real value
343        \return a new Quaternion containing the product
344*/
345Quaternion Quaternion::operator*(const float& f) const
346{
347        Quaternion r(*this);
348        r.w = r.w*f;
349        r.v = r.v*f;
350        return r;
351}
352
353/**
354        \brief divide a Quaternion by a real value
355        \param f: a real value
356        \return a new Quaternion containing the quotient
357*/
358Quaternion Quaternion::operator/(const float& f) const
359{
360        if( f == 0) return Quaternion();
361        Quaternion r(*this);
362        r.w = r.w/f;
363        r.v = r.v/f;
364        return r;
365}
366
367/**
368        \brief calculate the conjugate value of the Quaternion
369        \return the conjugate Quaternion
370*/
371Quaternion Quaternion::conjugate() const
372{
373        Quaternion r(*this);
374        r.v = Vector() - r.v;
375        return r;
376}
377
378/**
379        \brief calculate the norm of the Quaternion
380        \return the norm of The Quaternion
381*/
382float Quaternion::norm() const
383{
384        return w*w + v.x*v.x + v.y*v.y + v.z*v.z;
385}
386
387/**
388        \brief calculate the inverse value of the Quaternion
389        \return the inverse Quaternion
390       
391        Note that this is equal to conjugate() if the Quaternion's norm is 1
392*/
393Quaternion Quaternion::inverse() const
394{
395        float n = norm();
396        if (n != 0)
397        {
398                return conjugate() / norm();
399        }
400        else return Quaternion();
401}
402
403/**
404        \brief convert the Quaternion to a 4x4 rotational glMatrix
405        \param m: a buffer to store the Matrix in
406*/
407void Quaternion::matrix (float m[4][4]) const
408{
409        float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; 
410
411        // calculate coefficients
412        x2 = v.x + v.x;
413  y2 = v.y + v.y; 
414        z2 = v.z + v.z;
415        xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
416        yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
417        wx = w * x2; wy = w * y2; wz = w * z2;
418       
419        m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
420        m[2][0] = xz + wy; m[3][0] = 0.0;
421       
422        m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
423        m[2][1] = yz - wx; m[3][1] = 0.0;
424       
425        m[0][2] = xz - wy; m[1][2] = yz + wx;
426        m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
427       
428        m[0][3] = 0; m[1][3] = 0;
429        m[2][3] = 0; m[3][3] = 1;
430}
431
432/**
433        \brief convert a rotational 4x4 glMatrix into a Quaternion
434        \param m: a 4x4 matrix in glMatrix order
435*/
436Quaternion::Quaternion (float m[4][4])
437{
438       
439  float  tr, s, q[4];
440  int    i, j, k;
441
442  int nxt[3] = {1, 2, 0};
443
444  tr = m[0][0] + m[1][1] + m[2][2];
445
446        // check the diagonal
447  if (tr > 0.0) 
448  {
449    s = sqrt (tr + 1.0);
450    w = s / 2.0;
451    s = 0.5 / s;
452    v.x = (m[1][2] - m[2][1]) * s;
453    v.y = (m[2][0] - m[0][2]) * s;
454    v.z = (m[0][1] - m[1][0]) * s;
455        } 
456        else 
457        {
458                // diagonal is negative
459        i = 0;
460        if (m[1][1] > m[0][0]) i = 1;
461    if (m[2][2] > m[i][i]) i = 2;
462    j = nxt[i];
463    k = nxt[j];
464
465    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
466     
467    q[i] = s * 0.5;
468           
469    if (s != 0.0) s = 0.5 / s;
470       
471          q[3] = (m[j][k] - m[k][j]) * s;
472    q[j] = (m[i][j] + m[j][i]) * s;
473    q[k] = (m[i][k] + m[k][i]) * s;
474
475        v.x = q[0];
476        v.y = q[1];
477        v.z = q[2];
478        w = q[3];
479  }
480}
481
482/**
483   \brief create a rotation from a vector
484   \param v: a vector
485*/
486Rotation::Rotation (const Vector& v)
487{
488  Vector x = Vector( 1, 0, 0);
489  Vector axis = x.cross( v);
490  axis.normalize();
491  float angle = angle_rad( x, v);
492  float ca = cos(angle);
493  float sa = sin(angle);
494  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
495  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
496  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
497  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
498  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
499  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
500  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
501  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
502  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
503}
504
505/**
506   \brief creates a rotation from an axis and an angle (radians!)
507   \param axis: the rotational axis
508   \param angle: the angle in radians
509*/
510Rotation::Rotation (const Vector& axis, float angle)
511{
512  float ca, sa;
513  ca = cos(angle);
514  sa = sin(angle);
515  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
516  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
517  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
518  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
519  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
520  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
521  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
522  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
523  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
524}
525
526/**
527   \brief creates a rotation from euler angles (pitch/yaw/roll)
528   \param pitch: rotation around z (in radians)
529   \param yaw: rotation around y (in radians)
530   \param roll: rotation around x (in radians)
531*/
532Rotation::Rotation ( float pitch, float yaw, float roll)
533{
534  float cy, sy, cr, sr, cp, sp;
535  cy = cos(yaw);
536  sy = sin(yaw);
537  cr = cos(roll);
538  sr = sin(roll);
539  cp = cos(pitch);
540  sp = sin(pitch);
541  m[0] = cy*cr;
542  m[1] = -cy*sr;
543  m[2] = sy;
544  m[3] = cp*sr+sp*sy*cr;
545  m[4] = cp*cr-sp*sr*sy;
546  m[5] = -sp*cy;
547  m[6] = sp*sr-cp*sy*cr;
548  m[7] = sp*cr+cp*sy*sr;
549  m[8] = cp*cy;
550}
551
552/**
553   \brief creates a nullrotation (an identity rotation)
554*/
555Rotation::Rotation ()
556{
557  m[0] = 1.0f;
558  m[1] = 0.0f;
559  m[2] = 0.0f;
560  m[3] = 0.0f;
561  m[4] = 1.0f;
562  m[5] = 0.0f;
563  m[6] = 0.0f;
564  m[7] = 0.0f;
565  m[8] = 1.0f;
566}
567
568/**
569   \brief fills the specified buffer with a 4x4 glmatrix
570   \param buffer: Pointer to an array of 16 floats
571   
572   Use this to get the rotation in a gl-compatible format
573*/
574void Rotation::glmatrix (float* buffer)
575{
576        buffer[0] = m[0];
577        buffer[1] = m[3];
578        buffer[2] = m[6];
579        buffer[3] = m[0];
580        buffer[4] = m[1];
581        buffer[5] = m[4];
582        buffer[6] = m[7];
583        buffer[7] = m[0];
584        buffer[8] = m[2];
585        buffer[9] = m[5];
586        buffer[10] = m[8];
587        buffer[11] = m[0];
588        buffer[12] = m[0];
589        buffer[13] = m[0];
590        buffer[14] = m[0];
591        buffer[15] = m[1];
592}
593
594/**
595   \brief multiplies two rotational matrices
596   \param r: another Rotation
597   \return the matrix product of the Rotations
598   
599   Use this to rotate one rotation by another
600*/
601Rotation Rotation::operator* (const Rotation& r)
602{
603        Rotation p;
604       
605        p.m[0] = m[0]*r.m[0] + m[1]*r.m[3] + m[2]*r.m[6];
606        p.m[1] = m[0]*r.m[1] + m[1]*r.m[4] + m[2]*r.m[7];
607        p.m[2] = m[0]*r.m[2] + m[1]*r.m[5] + m[2]*r.m[8];
608       
609        p.m[3] = m[3]*r.m[0] + m[4]*r.m[3] + m[5]*r.m[6];
610        p.m[4] = m[3]*r.m[1] + m[4]*r.m[4] + m[5]*r.m[7];
611        p.m[5] = m[3]*r.m[2] + m[4]*r.m[5] + m[5]*r.m[8];
612
613        p.m[6] = m[6]*r.m[0] + m[7]*r.m[3] + m[8]*r.m[6];
614        p.m[7] = m[6]*r.m[1] + m[7]*r.m[4] + m[8]*r.m[7];
615        p.m[8] = m[6]*r.m[2] + m[7]*r.m[5] + m[8]*r.m[8];
616       
617        return p;
618}
619
620
621/**
622   \brief rotates the vector by the given rotation
623   \param v: a vector
624   \param r: a rotation
625   \return the rotated vector
626*/
627Vector rotate_vector( const Vector& v, const Rotation& r)
628{
629  Vector t;
630 
631  t.x = v.x * r.m[0] + v.y * r.m[1] + v.z * r.m[2];
632  t.y = v.x * r.m[3] + v.y * r.m[4] + v.z * r.m[5];
633  t.z = v.x * r.m[6] + v.y * r.m[7] + v.z * r.m[8];
634
635  return t;
636}
637
638/**
639   \brief calculate the distance between two lines
640   \param l: the other line
641   \return the distance between the lines
642*/
643float Line::distance (const Line& l) const
644{
645  float q, d;
646  Vector n = a.cross(l.a);
647  q = n.dot(r-l.r);
648  d = n.len();
649  if( d == 0.0) return 0.0;
650  return q/d;
651}
652
653/**
654   \brief calculate the distance between a line and a point
655   \param v: the point
656   \return the distance between the Line and the point
657*/
658float Line::distance_point (const Vector& v) const
659{
660  Vector d = v-r;
661  Vector u = a * d.dot( a);
662  return (d - u).len();
663}
664
665/**
666   \brief calculate the two points of minimal distance of two lines
667   \param l: the other line
668   \return a Vector[2] (!has to be deleted after use!) containing the two points of minimal distance
669*/
670Vector* Line::footpoints (const Line& l) const
671{
672  Vector* fp = new Vector[2];
673  Plane p = Plane (r + a.cross(l.a), r, r + a);
674  fp[1] = p.intersect_line (l);
675  p = Plane (fp[1], l.a);
676  fp[0] = p.intersect_line (*this);
677  return fp;
678}
679
680/**
681  \brief calculate the length of a line
682  \return the lenght of the line
683*/
684float Line::len() const
685{
686  return a.len();
687}
688
689/**
690   \brief rotate the line by given rotation
691   \param rot: a rotation
692*/
693void Line::rotate (const Rotation& rot)
694{
695  Vector t = a + r;
696  t = rotate_vector( t, rot);
697  r = rotate_vector( r, rot),
698  a = t - r;
699}
700
701/**
702   \brief create a plane from three points
703   \param a: first point
704   \param b: second point
705   \param c: third point
706*/
707Plane::Plane (Vector a, Vector b, Vector c)
708{
709  n = (a-b).cross(c-b);
710  k = -(n.x*b.x+n.y*b.y+n.z*b.z);
711}
712
713/**
714   \brief create a plane from anchor point and normal
715   \param n: normal vector
716   \param p: anchor point
717*/
718Plane::Plane (Vector norm, Vector p)
719{
720  n = norm;
721  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
722}
723
724/**
725   \brief returns the intersection point between the plane and a line
726   \param l: a line
727*/
728Vector Plane::intersect_line (const Line& l) const
729{
730  if (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z == 0.0) return Vector(0,0,0);
731  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);
732  return l.r + (l.a * t);
733}
734
735/**
736   \brief returns the distance between the plane and a point
737   \param p: a Point
738   \return the distance between the plane and the point (can be negative)
739*/
740float Plane::distance_point (const Vector& p) const
741{
742  float l = n.len();
743  if( l == 0.0) return 0.0;
744  return (n.dot(p) + k) / n.len();
745}
746
747/**
748   \brief returns the side a point is located relative to a Plane
749   \param p: a Point
750   \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
751*/
752float Plane::locate_point (const Vector& p) const
753{
754  return (n.dot(p) + k);
755}
Note: See TracBrowser for help on using the repository browser.