| |
|
|
||||
![]() |
||||||
| |
|
|||||
|
The VECTOR type
A vector is an ordered set of numbers that represents a magnitude and a direction. Vectors can be added, subtracted, multiplied and divided by scalars, and have special operations such as the dot and cross product. They are used to represent almost every non-scalar quantity in physics and math: velocity, acceleration, surface normal, unit direction, etc. Since most of the physics in games is only in three dimensions, the VECTOR type has only x, y and z components. All basic vector operations are implemented as overloaded operators or inline member functions. The VECTOR type will also be the building block for the MATRIX class. In Listing 1, notice that the members of VECTOR are public. Object-oriented purists may freak out, but having the ability to directly access the components of the vector makes math and physics programming much easier in the long run. Also, you might notice the const keyword permeates the member functions. The const in front of the return type means that the return value cannot be assigned. The const in front of the arguments means that the arguments are not changed within the function. The const after the argument list means that none of the members of the calling object are changed within that function. In my opinion, const should be used liberally since it will generate a compile error on a statement like: if( (a + b) = c ) { printf( "Typos are easy to overlook.\n" ); } Points have pretty much the same operations as vectors, so they are simply typedef’ed as a VECTOR (see Listing 1). #include <cmath> // A floating point number // typedef float SCALAR;
// // A 3D vector // class VECTOR { public: SCALAR x,y,z; //x,y,z coordinates public: VECTOR() : x(0), y(0), z(0) {} VECTOR( const SCALAR& a, const SCALAR& b, const SCALAR& c ) : x(a), y(b), z(c) {} //index a component //NOTE: returning a reference allows //you to assign the indexed element SCALAR& operator [] ( const long i ) { return *((&x) + i); } //compare const bool operator == ( const VECTOR& v ) const { return (v.x==x && v.y==y && v.z==z); } const bool operator != ( const VECTOR& v ) const { return !(v == *this); } //negate const VECTOR operator - () const { return VECTOR( -x, -y, -z ); } //assign const VECTOR& operator = ( const VECTOR& v ) { x = v.x; y = v.y; z = v.z; return *this; } //increment const VECTOR& operator += ( const VECTOR& v ) { x+=v.x; y+=v.y; z+=v.z; return *this; } //decrement const VECTOR& operator -= ( const VECTOR& v ) { x-=v.x; y-=v.y; z-=v.z; return *this; } //self-multiply const VECTOR& operator *= ( const SCALAR& s ) { x*=s; y*=s; z*=s; return *this; } //self-divide const VECTOR& operator /= ( const SCALAR& s ) { const SCALAR r = 1 / s; x *= r; y *= r; z *= r; return *this; } //add const VECTOR operator + ( const VECTOR& v ) const { return VECTOR(x + v.x, y + v.y, z + v.z); } //subtract const VECTOR operator - ( const VECTOR& v ) const { return VECTOR(x - v.x, y - v.y, z - v.z); } //post-multiply by a scalar const VECTOR operator * ( const SCALAR& s ) const { return VECTOR( x*s, y*s, z*s ); } //pre-multiply by a scalar friend inline const VECTOR operator * ( const SCALAR& s, const VECTOR& v ) { return v * s; } //divide const VECTOR operator / (SCALAR s) const { s = 1/s; return VECTOR( s*x, s*y, s*z ); } //cross product const VECTOR cross( const VECTOR& v ) const { //Davis, Snider, "Introduction to Vector Analysis", p. 44 return VECTOR( y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x ); } //scalar dot product const SCALAR dot( const VECTOR& v ) const { return x*v.x + y*v.y + z*v.z; } //length const SCALAR length() const { return (SCALAR)sqrt( (double)this->dot(*this) ); } //unit vector const VECTOR unit() const { return (*this) / length(); } //make this a unit vector void normalize() { (*this) /= length(); } //equal within an error ‘e’ const bool nearlyEquals( const VECTOR& v, const SCALAR e ) const { return fabs(x-v.x)<e && fabs(y-v.y)<e && fabs(z-v.z)<e; } }; // // A 3D position // typedef VECTOR POINT; |
|
|