Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2115 was 2112, checked in by chris, 20 years ago

orxonox/branches/chris: Implemented quaternion class… but something is still f up… the camera keeps pointing into the wrong direction… matrix rotation calculation seems not to be my strenght…

File size: 13.6 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
183Quaternion::Quaternion ()
184{
185        w = 1;
186        v = Vector(0,0,0);
187}
188
189Quaternion::Quaternion (float angle, const Vector& axis)
190{
191        w = cos(angle/2);
192        v = axis * sin(angle/2);
193}
194
195Quaternion::Quaternion (const Vector& dir, const Vector& up)
196{
197        Vector z = dir;
198  z.normalize(); 
199  Vector x = up.cross(z);
200  x.normalize(); 
201  Vector y = z.cross(x);
202 
203  float m[4][4];
204  m[0][0] = x.x;
205  m[0][1] = x.y;
206  m[0][2] = x.z;
207  m[0][3] = 0;
208  m[1][0] = y.x;
209  m[1][1] = y.y;
210  m[1][2] = y.z;
211  m[1][3] = 0;
212  m[2][0] = z.x;
213  m[2][1] = z.y;
214  m[2][2] = z.z;
215  m[2][3] = 0;
216  m[3][0] = 0;
217  m[3][1] = 0;
218  m[3][2] = 0;
219  m[3][3] = 1;
220 
221  *this = Quaternion (m);
222}
223
224Quaternion::Quaternion (float roll, float pitch, float yaw)
225{
226        float cr, cp, cy, sr, sp, sy, cpcy, spsy;
227       
228        // calculate trig identities
229        cr = cos(roll/2);
230        cp = cos(pitch/2);
231        cy = cos(yaw/2);
232       
233        sr = sin(roll/2);
234        sp = sin(pitch/2);
235        sy = sin(yaw/2);
236       
237        cpcy = cp * cy;
238        spsy = sp * sy;
239       
240        w = cr * cpcy + sr * spsy;
241        v.x = sr * cpcy - cr * spsy;
242        v.y = cr * sp * cy + sr * cp * sy;
243        v.z = cr * cp * sy - sr * sp * cy;
244}
245
246Quaternion Quaternion::operator*(const Quaternion& q) const
247{
248        float A, B, C, D, E, F, G, H;
249        Quaternion r;
250       
251        A = (w   + v.x)*(q.w   + q.v.x);
252        B = (v.z - v.y)*(q.v.y - q.v.z);
253        C = (w   - v.x)*(q.v.y + q.v.z); 
254        D = (v.y + v.z)*(q.w   - q.v.x);
255        E = (v.x + v.z)*(q.v.x + q.v.y);
256        F = (v.x - v.z)*(q.v.x - q.v.y);
257        G = (w   + v.y)*(q.w   - q.v.z);
258        H = (w   - v.y)*(q.w   + q.v.z);
259       
260        r.w = B +  (-E - F + G + H)/2;
261        r.v.x = A - (E + F + G + H)/2; 
262        r.v.y = C + (E - F + G - H)/2; 
263        r.v.z = D + (E - F - G + H)/2;
264       
265        return r;
266}
267
268Quaternion Quaternion::operator+(const Quaternion& q) const
269{
270        Quaternion r(*this);
271        r.w = r.w + q.w;
272        r.v = r.v + q.v;
273        return r;
274}
275
276Quaternion Quaternion::operator- (const Quaternion& q) const
277{
278        Quaternion r(*this);
279        r.w = r.w - q.w;
280        r.v = r.v - q.v;
281        return r;
282}
283
284Vector Quaternion::apply (Vector& v) const
285{
286        Quaternion q;
287        q.v = v;
288        q.w = 0;
289        q = *this * q * conjugate();
290        return q.v;
291}
292
293Quaternion Quaternion::operator*(const float& f) const
294{
295        Quaternion r(*this);
296        r.w = r.w*f;
297        r.v = r.v*f;
298        return r;
299}
300
301Quaternion Quaternion::operator/(const float& f) const
302{
303        if( f == 0) return Quaternion();
304        Quaternion r(*this);
305        r.w = r.w/f;
306        r.v = r.v/f;
307        return r;
308}
309
310Quaternion Quaternion::conjugate() const
311{
312        Quaternion r(*this);
313        r.v = Vector() - r.v;
314        return r;
315}
316
317float Quaternion::norm() const
318{
319        return w*w + v.x*v.x + v.y*v.y + v.z*v.z;
320}
321
322Quaternion Quaternion::inverse() const
323{
324        float n = norm();
325        if (n != 0)
326        {
327                return conjugate() / norm();
328        }
329        else return Quaternion();
330}
331
332void Quaternion::matrix (float m[4][4]) const
333{
334        float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; 
335
336        // calculate coefficients
337        x2 = v.x + v.x;
338  y2 = v.y + v.y; 
339        z2 = v.z + v.z;
340        xx = v.x * x2; xy = v.x * y2; xz = v.x * z2;
341        yy = v.y * y2; yz = v.y * z2; zz = v.z * z2;
342        wx = w * x2; wy = w * y2; wz = w * z2;
343       
344        m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz;
345        m[2][0] = xz + wy; m[3][0] = 0.0;
346       
347        m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz);
348        m[2][1] = yz - wx; m[3][1] = 0.0;
349       
350        m[0][2] = xz - wy; m[1][2] = yz + wx;
351        m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0;
352       
353        m[0][3] = 0; m[1][3] = 0;
354        m[2][3] = 0; m[3][3] = 1;
355}
356
357Quaternion::Quaternion (float m[4][4])
358{
359       
360  float  tr, s, q[4];
361  int    i, j, k;
362
363  int nxt[3] = {1, 2, 0};
364
365  tr = m[0][0] + m[1][1] + m[2][2];
366
367        // check the diagonal
368  if (tr > 0.0) 
369  {
370    s = sqrt (tr + 1.0);
371    w = s / 2.0;
372    s = 0.5 / s;
373    v.x = (m[1][2] - m[2][1]) * s;
374    v.y = (m[2][0] - m[0][2]) * s;
375    v.z = (m[0][1] - m[1][0]) * s;
376        } 
377        else 
378        {
379                // diagonal is negative
380        i = 0;
381        if (m[1][1] > m[0][0]) i = 1;
382    if (m[2][2] > m[i][i]) i = 2;
383    j = nxt[i];
384    k = nxt[j];
385
386    s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
387     
388    q[i] = s * 0.5;
389           
390    if (s != 0.0) s = 0.5 / s;
391       
392          q[3] = (m[j][k] - m[k][j]) * s;
393    q[j] = (m[i][j] + m[j][i]) * s;
394    q[k] = (m[i][k] + m[k][i]) * s;
395
396        v.x = q[0];
397        v.y = q[1];
398        v.z = q[2];
399        w = q[3];
400  }
401}
402
403/**
404   \brief create a rotation from a vector
405   \param v: a vector
406*/
407Rotation::Rotation (const Vector& v)
408{
409  Vector x = Vector( 1, 0, 0);
410  Vector axis = x.cross( v);
411  axis.normalize();
412  float angle = angle_rad( x, v);
413  float ca = cos(angle);
414  float sa = sin(angle);
415  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
416  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
417  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
418  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
419  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
420  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
421  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
422  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
423  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
424}
425
426/**
427   \brief creates a rotation from an axis and an angle (radians!)
428   \param axis: the rotational axis
429   \param angle: the angle in radians
430*/
431Rotation::Rotation (const Vector& axis, float angle)
432{
433  float ca, sa;
434  ca = cos(angle);
435  sa = sin(angle);
436  m[0] = 1.0f+(1.0f-ca)*(axis.x*axis.x-1.0f);
437  m[1] = -axis.z*sa+(1.0f-ca)*axis.x*axis.y;
438  m[2] = axis.y*sa+(1.0f-ca)*axis.x*axis.z;
439  m[3] = axis.z*sa+(1.0f-ca)*axis.x*axis.y;
440  m[4] = 1.0f+(1.0f-ca)*(axis.y*axis.y-1.0f);
441  m[5] = -axis.x*sa+(1.0f-ca)*axis.y*axis.z;
442  m[6] = -axis.y*sa+(1.0f-ca)*axis.x*axis.z;
443  m[7] = axis.x*sa+(1.0f-ca)*axis.y*axis.z;
444  m[8] = 1.0f+(1.0f-ca)*(axis.z*axis.z-1.0f);
445}
446
447/**
448   \brief creates a rotation from euler angles (pitch/yaw/roll)
449   \param pitch: rotation around z (in radians)
450   \param yaw: rotation around y (in radians)
451   \param roll: rotation around x (in radians)
452*/
453Rotation::Rotation ( float pitch, float yaw, float roll)
454{
455  float cy, sy, cr, sr, cp, sp;
456  cy = cos(yaw);
457  sy = sin(yaw);
458  cr = cos(roll);
459  sr = sin(roll);
460  cp = cos(pitch);
461  sp = sin(pitch);
462  m[0] = cy*cr;
463  m[1] = -cy*sr;
464  m[2] = sy;
465  m[3] = cp*sr+sp*sy*cr;
466  m[4] = cp*cr-sp*sr*sy;
467  m[5] = -sp*cy;
468  m[6] = sp*sr-cp*sy*cr;
469  m[7] = sp*cr+cp*sy*sr;
470  m[8] = cp*cy;
471}
472
473/**
474   \brief creates a nullrotation (an identity rotation)
475*/
476Rotation::Rotation ()
477{
478  m[0] = 1.0f;
479  m[1] = 0.0f;
480  m[2] = 0.0f;
481  m[3] = 0.0f;
482  m[4] = 1.0f;
483  m[5] = 0.0f;
484  m[6] = 0.0f;
485  m[7] = 0.0f;
486  m[8] = 1.0f;
487}
488
489/**
490   \brief fills the specified buffer with a 4x4 glmatrix
491   \param buffer: Pointer to an array of 16 floats
492   
493   Use this to get the rotation in a gl-compatible format
494*/
495void Rotation::glmatrix (float* buffer)
496{
497        buffer[0] = m[0];
498        buffer[1] = m[3];
499        buffer[2] = m[6];
500        buffer[3] = m[0];
501        buffer[4] = m[1];
502        buffer[5] = m[4];
503        buffer[6] = m[7];
504        buffer[7] = m[0];
505        buffer[8] = m[2];
506        buffer[9] = m[5];
507        buffer[10] = m[8];
508        buffer[11] = m[0];
509        buffer[12] = m[0];
510        buffer[13] = m[0];
511        buffer[14] = m[0];
512        buffer[15] = m[1];
513}
514
515/**
516   \brief multiplies two rotational matrices
517   \param r: another Rotation
518   \return the matrix product of the Rotations
519   
520   Use this to rotate one rotation by another
521*/
522Rotation Rotation::operator* (const Rotation& r)
523{
524        Rotation p;
525       
526        p.m[0] = m[0]*r.m[0] + m[1]*r.m[3] + m[2]*r.m[6];
527        p.m[1] = m[0]*r.m[1] + m[1]*r.m[4] + m[2]*r.m[7];
528        p.m[2] = m[0]*r.m[2] + m[1]*r.m[5] + m[2]*r.m[8];
529       
530        p.m[3] = m[3]*r.m[0] + m[4]*r.m[3] + m[5]*r.m[6];
531        p.m[4] = m[3]*r.m[1] + m[4]*r.m[4] + m[5]*r.m[7];
532        p.m[5] = m[3]*r.m[2] + m[4]*r.m[5] + m[5]*r.m[8];
533
534        p.m[6] = m[6]*r.m[0] + m[7]*r.m[3] + m[8]*r.m[6];
535        p.m[7] = m[6]*r.m[1] + m[7]*r.m[4] + m[8]*r.m[7];
536        p.m[8] = m[6]*r.m[2] + m[7]*r.m[5] + m[8]*r.m[8];
537       
538        return p;
539}
540
541
542/**
543   \brief rotates the vector by the given rotation
544   \param v: a vector
545   \param r: a rotation
546   \return the rotated vector
547*/
548Vector rotate_vector( const Vector& v, const Rotation& r)
549{
550  Vector t;
551 
552  t.x = v.x * r.m[0] + v.y * r.m[1] + v.z * r.m[2];
553  t.y = v.x * r.m[3] + v.y * r.m[4] + v.z * r.m[5];
554  t.z = v.x * r.m[6] + v.y * r.m[7] + v.z * r.m[8];
555
556  return t;
557}
558
559/**
560   \brief calculate the distance between two lines
561   \param l: the other line
562   \return the distance between the lines
563*/
564float Line::distance (const Line& l) const
565{
566  float q, d;
567  Vector n = a.cross(l.a);
568  q = n.dot(r-l.r);
569  d = n.len();
570  if( d == 0.0) return 0.0;
571  return q/d;
572}
573
574/**
575   \brief calculate the distance between a line and a point
576   \param v: the point
577   \return the distance between the Line and the point
578*/
579float Line::distance_point (const Vector& v) const
580{
581  Vector d = v-r;
582  Vector u = a * d.dot( a);
583  return (d - u).len();
584}
585
586/**
587   \brief calculate the two points of minimal distance of two lines
588   \param l: the other line
589   \return a Vector[2] (!has to be deleted after use!) containing the two points of minimal distance
590*/
591Vector* Line::footpoints (const Line& l) const
592{
593  Vector* fp = new Vector[2];
594  Plane p = Plane (r + a.cross(l.a), r, r + a);
595  fp[1] = p.intersect_line (l);
596  p = Plane (fp[1], l.a);
597  fp[0] = p.intersect_line (*this);
598  return fp;
599}
600
601/**
602  \brief calculate the length of a line
603  \return the lenght of the line
604*/
605float Line::len() const
606{
607  return a.len();
608}
609
610/**
611   \brief rotate the line by given rotation
612   \param rot: a rotation
613*/
614void Line::rotate (const Rotation& rot)
615{
616  Vector t = a + r;
617  t = rotate_vector( t, rot);
618  r = rotate_vector( r, rot),
619  a = t - r;
620}
621
622/**
623   \brief create a plane from three points
624   \param a: first point
625   \param b: second point
626   \param c: third point
627*/
628Plane::Plane (Vector a, Vector b, Vector c)
629{
630  n = (a-b).cross(c-b);
631  k = -(n.x*b.x+n.y*b.y+n.z*b.z);
632}
633
634/**
635   \brief create a plane from anchor point and normal
636   \param n: normal vector
637   \param p: anchor point
638*/
639Plane::Plane (Vector norm, Vector p)
640{
641  n = norm;
642  k = -(n.x*p.x+n.y*p.y+n.z*p.z);
643}
644
645/**
646   \brief returns the intersection point between the plane and a line
647   \param l: a line
648*/
649Vector Plane::intersect_line (const Line& l) const
650{
651  if (n.x*l.a.x+n.y*l.a.y+n.z*l.a.z == 0.0) return Vector(0,0,0);
652  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);
653  return l.r + (l.a * t);
654}
655
656/**
657   \brief returns the distance between the plane and a point
658   \param p: a Point
659   \return the distance between the plane and the point (can be negative)
660*/
661float Plane::distance_point (const Vector& p) const
662{
663  float l = n.len();
664  if( l == 0.0) return 0.0;
665  return (n.dot(p) + k) / n.len();
666}
667
668/**
669   \brief returns the side a point is located relative to a Plane
670   \param p: a Point
671   \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
672*/
673float Plane::locate_point (const Vector& p) const
674{
675  return (n.dot(p) + k);
676}
Note: See TracBrowser for help on using the repository browser.