1 /*
2     Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4     This file is part of COLLADABaseUtils.
5 
6     Licensed under the MIT Open Source License,
7     for details please see LICENSE file or the website
8     http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #ifndef __COLLADABU_MATH_VECTOR3_H__
12 #define __COLLADABU_MATH_VECTOR3_H__
13 
14 #include "COLLADABUPlatform.h"
15 #include "COLLADABUMathPrerequisites.h"
16 #include "COLLADABUMathQuaternion.h"
17 
18 #include <math.h>
19 
20 namespace COLLADABU
21 {
22     namespace Math
23     {
24         /** Standard 3-dimensional vector.
25             @remarks
26                 A direction in 3D space represented as distances along the 3
27                 orthogonal axes (x, y, z). Note that positions, directions and
28                 scaling factors can be represented by a vector, depending on how
29                 you interpret the values.
30         */
31 
32         class Vector3
33         {
34 
35         public:
36             union {
37 
38                 struct
39                 {
40                     Real x, y, z;
41                 };
42 
43                 Real val[ 3 ];
44             };
45 
46         public:
Vector3()47             inline Vector3() : x(0), y(0), z(0)
48             {}
49 
Vector3(Real fX,Real fY,Real fZ)50             inline Vector3( Real fX, Real fY, Real fZ )
51                     : x( fX ), y( fY ), z( fZ )
52             {}
53 
Vector3(Real afCoordinate[3])54             inline Vector3( Real afCoordinate[ 3 ] )
55                     : x( afCoordinate[ 0 ] ),
56                     y( afCoordinate[ 1 ] ),
57                     z( afCoordinate[ 2 ] )
58             {}
59 
Vector3(int afCoordinate[3])60             inline Vector3( int afCoordinate[ 3 ] )
61             {
62                 x = ( Real ) afCoordinate[ 0 ];
63                 y = ( Real ) afCoordinate[ 1 ];
64                 z = ( Real ) afCoordinate[ 2 ];
65             }
66 
Vector3(const Real * const r)67             inline Vector3( const Real* const r )
68                     : x( r[ 0 ] ), y( r[ 1 ] ), z( r[ 2 ] )
69             {}
70 
Vector3(const Vector3 & rkVector)71             inline Vector3( const Vector3& rkVector )
72                     : x( rkVector.x ), y( rkVector.y ), z( rkVector.z )
73             {}
74 
set(Real fX,Real fY,Real fZ)75 			inline void set( Real fX, Real fY, Real fZ )
76 			{
77 				x = fX;
78 				y = fY;
79 				z = fZ;
80 			}
81 
82             inline Real operator [] ( size_t i ) const
83             {
84 				COLLADABU_ASSERT( i < 3 );
85 
86                 return *( &x + i );
87             }
88 
89             inline Real& operator [] ( size_t i )
90             {
91                 COLLADABU_ASSERT( i < 3 );
92 
93                 return *( &x + i );
94             }
95 
96             /** Assigns the value of the other vector.
97                 @param
98                     rkVector The other vector
99             */
100             inline Vector3& operator = ( const Vector3& rkVector )
101             {
102                 x = rkVector.x;
103                 y = rkVector.y;
104                 z = rkVector.z;
105 
106                 return *this;
107             }
108 
109             inline bool operator == ( const Vector3& rkVector ) const
110             {
111                 return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
112             }
113 
114             inline bool operator != ( const Vector3& rkVector ) const
115             {
116                 return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
117             }
118 
119             // arithmetic operations
120             inline Vector3 operator + ( const Vector3& rkVector ) const
121             {
122                 Vector3 kSum;
123 
124                 kSum.x = x + rkVector.x;
125                 kSum.y = y + rkVector.y;
126                 kSum.z = z + rkVector.z;
127 
128                 return kSum;
129             }
130 
131             inline Vector3 operator - ( const Vector3& rkVector ) const
132             {
133                 Vector3 kDiff;
134 
135                 kDiff.x = x - rkVector.x;
136                 kDiff.y = y - rkVector.y;
137                 kDiff.z = z - rkVector.z;
138 
139                 return kDiff;
140             }
141 
142             inline Vector3 operator * ( Real fScalar ) const
143             {
144                 Vector3 kProd;
145 
146                 kProd.x = fScalar * x;
147                 kProd.y = fScalar * y;
148                 kProd.z = fScalar * z;
149 
150                 return kProd;
151             }
152 
153             inline Vector3 operator * ( const Vector3& rhs ) const
154             {
155                 Vector3 kProd;
156 
157                 kProd.x = rhs.x * x;
158                 kProd.y = rhs.y * y;
159                 kProd.z = rhs.z * z;
160 
161                 return kProd;
162             }
163 
164             inline Vector3 operator / ( Real fScalar ) const
165             {
166                 COLLADABU_ASSERT( fScalar != 0.0 );
167 
168                 Vector3 kDiv;
169 
170                 Real fInv = 1.0 / fScalar;
171                 kDiv.x = x * fInv;
172                 kDiv.y = y * fInv;
173                 kDiv.z = z * fInv;
174 
175                 return kDiv;
176             }
177 
178             inline Vector3 operator / ( const Vector3& rhs ) const
179             {
180                 Vector3 kDiv;
181 
182                 kDiv.x = x / rhs.x;
183                 kDiv.y = y / rhs.y;
184                 kDiv.z = z / rhs.z;
185 
186                 return kDiv;
187             }
188 
189 
190             inline Vector3 operator - () const
191             {
192                 Vector3 kNeg;
193 
194                 kNeg.x = -x;
195                 kNeg.y = -y;
196                 kNeg.z = -z;
197 
198                 return kNeg;
199             }
200 
201             inline friend Vector3 operator * ( Real fScalar, const Vector3& rkVector )
202             {
203                 Vector3 kProd;
204 
205                 kProd.x = fScalar * rkVector.x;
206                 kProd.y = fScalar * rkVector.y;
207                 kProd.z = fScalar * rkVector.z;
208 
209                 return kProd;
210             }
211 
212             // arithmetic updates
213             inline Vector3& operator += ( const Vector3& rkVector )
214             {
215                 x += rkVector.x;
216                 y += rkVector.y;
217                 z += rkVector.z;
218 
219                 return *this;
220             }
221 
222             inline Vector3& operator -= ( const Vector3& rkVector )
223             {
224                 x -= rkVector.x;
225                 y -= rkVector.y;
226                 z -= rkVector.z;
227 
228                 return *this;
229             }
230 
231             inline Vector3& operator *= ( Real fScalar )
232             {
233                 x *= fScalar;
234                 y *= fScalar;
235                 z *= fScalar;
236                 return *this;
237             }
238 
239             inline Vector3& operator *= ( const Vector3& rkVector )
240             {
241                 x *= rkVector.x;
242                 y *= rkVector.y;
243                 z *= rkVector.z;
244 
245                 return *this;
246             }
247 
248             inline Vector3& operator /= ( Real fScalar )
249             {
250                 COLLADABU_ASSERT( fScalar != 0.0 );
251 
252                 Real fInv = 1.0 / fScalar;
253 
254                 x *= fInv;
255                 y *= fInv;
256                 z *= fInv;
257 
258                 return *this;
259             }
260 
261             inline Vector3& operator /= ( const Vector3& rkVector )
262             {
263                 x /= rkVector.x;
264                 y /= rkVector.y;
265                 z /= rkVector.z;
266 
267                 return *this;
268             }
269 
270 
271             /** Returns the length (magnitude) of the vector.
272                 @warning
273                     This operation requires a square root and is expensive in
274                     terms of CPU operations. If you don't need to know the exact
275                     length (e.g. for just comparing lengths) use squaredLength()
276                     instead.
277             */
length()278             inline Real length () const
279             {
280                 return sqrt( x * x + y * y + z * z );
281             }
282 
283             /** Returns the square of the length(magnitude) of the vector.
284                 @remarks
285                     This  method is for efficiency - calculating the actual
286                     length of a vector requires a square root, which is expensive
287                     in terms of the operations required. This method returns the
288                     square of the length of the vector, i.e. the same as the
289                     length but before the square root is taken. Use this if you
290                     want to find the longest / shortest vector without incurring
291                     the square root.
292             */
squaredLength()293             inline Real squaredLength () const
294             {
295                 return x * x + y * y + z * z;
296             }
297 
298             /** Calculates the dot (scalar) product of this vector with another.
299                 @remarks
300                     The dot product can be used to calculate the angle between 2
301                     vectors. If both are unit vectors, the dot product is the
302                     cosine of the angle; otherwise the dot product must be
303                     divided by the product of the lengths of both vectors to get
304                     the cosine of the angle. This result can further be used to
305                     calculate the distance of a point from a plane.
306                 @param
307                     vec Vector with which to calculate the dot product (together
308                     with this one).
309                 @returns
310                     A float representing the dot product value.
311             */
dotProduct(const Vector3 & vec)312             inline Real dotProduct( const Vector3& vec ) const
313             {
314                 return x * vec.x + y * vec.y + z * vec.z;
315             }
316 
317             /** Normalises the vector.
318                 @remarks
319                     This method normalises the vector such that it's
320                     length / magnitude is 1. The result is called a unit vector.
321                 @note
322                     This function will not crash for zero-sized vectors, but there
323                     will be no changes made to their components.
324                 @returns The previous length of the vector.
325             */
normalise()326             inline Real normalise()
327             {
328                 Real fLength = sqrt( x * x + y * y + z * z );
329 
330                 // Will also work for zero-sized vectors, but will change nothing
331 
332                 if ( fLength > 1e-08 )
333                 {
334                     Real fInvLength = 1.0 / fLength;
335                     x *= fInvLength;
336                     y *= fInvLength;
337                     z *= fInvLength;
338                 }
339 
340                 return fLength;
341             }
342 
343             /** Calculates the cross-product of 2 vectors, i.e. the vector that
344                 lies perpendicular to them both.
345                 @remarks
346                     The cross-product is normally used to calculate the normal
347                     vector of a plane, by calculating the cross-product of 2
348                     non-equivalent vectors which lie on the plane (e.g. 2 edges
349                     of a triangle).
350                 @param
351                     rkVector Vector which, together with this one, will be used to
352                     calculate the cross-product.
353                 @returns
354                     A vector which is the result of the cross-product. This
355                     vector will <b>NOT</b> be normalised, to maximise efficiency
356                     - call Vector3::normalise on the result if you wish this to
357                     be done. As for which side the resultant vector will be on, the
358                     returned vector will be on the side from which the arc from 'this'
359                     to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z)
360                     = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X.
361                 @par
362                     For a clearer explanation, look a the left and the bottom edges
363                     of your monitor's screen. Assume that the first vector is the
364                     left edge and the second vector is the bottom edge, both of
365                     them starting from the lower-left corner of the screen. The
366                     resulting vector is going to be perpendicular to both of them
367                     and will go <i>inside</i> the screen, towards the cathode tube
368                     (assuming you're using a CRT monitor, of course).
369             */
crossProduct(const Vector3 & rkVector)370             inline Vector3 crossProduct( const Vector3& rkVector ) const
371             {
372                 Vector3 kCross;
373 
374                 kCross.x = y * rkVector.z - z * rkVector.y;
375                 kCross.y = z * rkVector.x - x * rkVector.z;
376                 kCross.z = x * rkVector.y - y * rkVector.x;
377 
378                 return kCross;
379             }
380 
381             /** Returns a vector at a point half way between this and the passed
382                 in vector.
383             */
midPoint(const Vector3 & vec)384             inline Vector3 midPoint( const Vector3& vec ) const
385             {
386                 return Vector3(
387                            ( x + vec.x ) * 0.5,
388                            ( y + vec.y ) * 0.5,
389                            ( z + vec.z ) * 0.5 );
390             }
391 
392             /** Returns true if the vector's scalar components are all greater
393                 that the ones of the vector it is compared against.
394             */
395             inline bool operator < ( const Vector3& rhs ) const
396             {
397                 if ( x < rhs.x && y < rhs.y && z < rhs.z )
398                     return true;
399 
400                 return false;
401             }
402 
403             /** Returns true if the vector's scalar components are all smaller
404                 that the ones of the vector it is compared against.
405             */
406             inline bool operator > ( const Vector3& rhs ) const
407             {
408                 if ( x > rhs.x && y > rhs.y && z > rhs.z )
409                     return true;
410 
411                 return false;
412             }
413 
414             /** Sets this vector's components to the minimum of its own and the
415                 ones of the passed in vector.
416                 @remarks
417                     'Minimum' in this case means the combination of the lowest
418                     value of x, y and z from both vectors. Lowest is taken just
419                     numerically, not magnitude, so -1 < 0.
420             */
makeFloor(const Vector3 & cmp)421             inline void makeFloor( const Vector3& cmp )
422             {
423                 if ( cmp.x < x )
424                     x = cmp.x;
425 
426                 if ( cmp.y < y )
427                     y = cmp.y;
428 
429                 if ( cmp.z < z )
430                     z = cmp.z;
431             }
432 
433             /** Sets this vector's components to the maximum of its own and the
434                 ones of the passed in vector.
435                 @remarks
436                     'Maximum' in this case means the combination of the highest
437                     value of x, y and z from both vectors. Highest is taken just
438                     numerically, not magnitude, so 1 > -3.
439             */
makeCeil(const Vector3 & cmp)440             inline void makeCeil( const Vector3& cmp )
441             {
442                 if ( cmp.x > x )
443                     x = cmp.x;
444 
445                 if ( cmp.y > y )
446                     y = cmp.y;
447 
448                 if ( cmp.z > z )
449                     z = cmp.z;
450             }
451 
452             /** Generates a vector perpendicular to this vector (eg an 'up' vector).
453                 @remarks
454                     This method will return a vector which is perpendicular to this
455                     vector. There are an infinite number of possibilities but this
456                     method will guarantee to generate one of them. If you need more
457                     control you should use the Quaternion class.
458             */
perpendicular(void)459             inline Vector3 perpendicular( void ) const
460             {
461                 static const Real fSquareZero = 1e-06 * 1e-06;
462 
463                 Vector3 perp = this->crossProduct( Vector3::UNIT_X );
464 
465                 // Check length
466 
467                 if ( perp.squaredLength() < fSquareZero )
468                 {
469                     /* This vector is the Y axis multiplied by a scalar, so we have
470                        to use another axis.
471                     */
472                     perp = this->crossProduct( Vector3::UNIT_Y );
473                 }
474 
475                 return perp;
476             }
477 
478 
479 
480             /** Returns true if this vector is zero length. */
isZeroLength(void)481             inline bool isZeroLength( void ) const
482             {
483                 Real sqlen = ( x * x ) + ( y * y ) + ( z * z );
484                 return ( sqlen < ( 1e-06 * 1e-06 ) );
485 
486             }
487 
488             /** As normalise, except that this vector is unaffected and the
489                 normalised vector is returned as a copy. */
normalisedCopy(void)490             inline Vector3 normalisedCopy( void ) const
491             {
492                 Vector3 ret = *this;
493                 ret.normalise();
494                 return ret;
495             }
496 
497             /** Calculates a reflection vector to the plane with the given normal .
498             @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
499             */
reflect(const Vector3 & normal)500             inline Vector3 reflect( const Vector3& normal ) const
501             {
502                 return Vector3( *this - ( 2 * this->dotProduct( normal ) * normal ) );
503             }
504 
505 
506             /** Returns whether this vector is within a directional tolerance
507              of another vector.
508             @param rhs The vector to compare with
509             @param tolerance_radian The maximum angle by which the vectors may vary and
510              still be considered equal
511             */
directionEquals(const Vector3 & rhs,const Real & tolerance_radian)512             inline bool directionEquals( const Vector3& rhs,
513                                          const Real& tolerance_radian ) const
514             {
515                 Real dot = dotProduct( rhs );
516                 Real angle_radian = acos( dot );
517 
518                 return fabs( angle_radian ) <= tolerance_radian;
519 
520             }
521 
522             // special points
523             static const Vector3 ZERO;
524             static const Vector3 UNIT_X;
525             static const Vector3 UNIT_Y;
526             static const Vector3 UNIT_Z;
527             static const Vector3 NEGATIVE_UNIT_X;
528             static const Vector3 NEGATIVE_UNIT_Y;
529             static const Vector3 NEGATIVE_UNIT_Z;
530             static const Vector3 UNIT_SCALE;
531 
532         };
533 
534     }
535 }
536 
537 #endif //__COLLADABU_MATH_VECTOR3_H__
538