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