This appendix implements a class called Vector that encapsulates all of the vector operations that you need when writing 2D or 3D rigid body simulations. Although, Vector represents 3D vectors, you can easily reduce it to handle 2D vectors by eliminating all of the z-terms or simply constraining the z-terms to zero where appropriate in your implementation.
The Vector class is defined with three components, x, y, and z, along with several methods and operators that implement basic vector operations. The class has two constructors, one of which initializes the vector components to zero and the other of which initializes the vector components to those passed to the constructor.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Vector Class and vector functions // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Vector { public: float x; float y; float z; Vector(void); Vector(float xi, float yi, float zi); float Magnitude(void); void Normalize(void); void Reverse(void); Vector& operator+=(Vector u); Vector& operator-=(Vector u); Vector& operator*=(float s); Vector& operator/=(float s); Vector operator-(void); }; // Constructor inline Vector::Vector(void) { x = 0; y = 0; z = 0; } // Constructor inline Vector::Vector(float xi, float yi, float zi) { x = xi; y = yi; z = zi; }
The Magnitude method simply calculates the scalar magnitude of the vector according to the formula
This is for a zero-based vector in which the components are specified relative to the origin. The magnitude of a vector is equal to its length, as illustrated in Figure A-1.
Here’s the code that calculates the vector magnitude for our Vector class:
inline float Vector::Magnitude(void) { return (float) sqrt(x*x + y*y + z*z); }
Note that you can calculate the components of a vector if you know its length and direction angles. Direction angles are the angles between each coordinate axis and the vector, as shown in Figure A-2.
The components of the vector shown in this figure are as follows:
The cosines of the direction angles seen in these equations are known as direction cosines. The sum of the squares of the direction cosines is always equal to 1:
The Normalize method normalizes the vector, or converts it to a unit vector satisfying the following equation:
In other words, the length of the normalized vector is 1 unit. If v is a nonunit vector with components x, y, and z, then the unit vector u can be calculated from v as follows:
Here, |v| is simply the magnitude, or length, of vector v as described earlier.
Here’s the code that converts our Vector class vector to a unit vector:
inline void Vector::Normalize(void) { float m = (float) sqrt(x*x + y*y + z*z); if(m <= tol) m = 1; x /= m; y /= m; z /= m; if (fabs(x) < tol) x = 0.Of; if (fabs(y) < tol) y = 0.Of; if (fabs(z) < tol) z = 0.Of; }
In this function tol is a float type tolerance, for example,
float const tol = O.OOOlf;
The Reverse method reverses the direction of the vector, which is accomplished by simply taking the negative of each component. After calling Reverse, the vector will point in a direction opposite to the direction in which it was pointing before Reverse was called.
inline void Vector::Reverse(void) { x = -x; y = -y; z = -z; }
This operation is illustrated in Figure A-3.
This summation operator is used for vector addition, whereby the passed vector is added to the current vector component by component. Graphically, vectors are added in tip-to-tail fashion as illustrated in Figure A-4.
Here’s the code that adds the vector u to our Vector class vector:
inline Vector& Vector::operator+= (Vector u) { x += u.x; Y += u.y; z += u.z; return *this; }
This subtraction operator is used to subtract the passed vector from the current one, which is performed on a component-by-component basis. Vector subtraction is very similar to vector addition except that you take the reverse of the second vector and add it to the first as illustrated in Figure A-5.
Here’s the code that subtracts vector u from our Vector class vector:
inline Vector& Vector::operator-=(Vector u) { x -= u.x; y -= u.y; z -= u.z; return *this; }
This is the scalar multiplication operator that’s used to multiply a vector by a scalar, effectively scaling the vector’s length. When you multiply a vector by a scalar, you simply multiply each vector component by the scalar quantity to obtain the new vector. The new vector points in the same direction as the unsealed one, but its length will be different (unless the scale factor is 1). This is illustrated in Figure A-6.
Here’s the code that scales our Vector class vector:
inline Vector& Vector::operator*=(float s) { x *=s; y *=s; z *=s; return *this; }
This scalar division operator is similar to the scalar multiplication operator except that each vector component is divided by the passed scalar quantity.
inline Vector& Vector::operator/=(float s) { x /=s; y /=s; z /=s; return *this; }
The conjugate operator simply takes the negative of each vector component and can be used when subtracting one vector from another or for reversing the direction of the vector. Applying the conjugate operator is the same as reversing a vector, as discussed earlier.
inline Vector Vector::operator-(void) { return Vector(-x, -y, -z); }
The functions and overloaded operators that follow are useful in performing operations with two vectors, or with a vector and a scalar, where the vector is based on the Vector class.
This addition operator adds vector v to vector u according to the formula
Here’s the code:
inline Vector operator+ (Vector u, Vector v) { return Vector(u.x + v.x, u.y + v.y, u.z + v.z); }
This subtraction operator subtracts vector v from vector u according to the formula
Here’s the code:
inline Vector operator-(Vector u, Vector v) { return Vector(u.x - v.x, u.y - v.y, u.z - v.z); }
This cross product operator takes the vector cross product between vectors u and v, u × v, and returns a vector perpendicular to both u and v according to the formula
The resulting vector is perpendicular to the plane that contains vectors u and v. The direction in which this resulting vector points can be determined by the righthand rule. If you place the two vectors, u and v, tail to tail as shown in Figure A-7 and curl your fingers (of your right hand) in the direction from u to v, your thumb will point in the direction of the resulting vector.
In this case the resulting vector points out of the page along the z-axis, since the vectors u and v lie in the plane formed by the x- and y-axes.
If two vectors are parallel, then their cross product will be zero. This is useful when you need to determine whether or not two vector are indeed parallel.
The cross product operation is distributive; however, it is not commutative:
Here’s the code that takes the cross product of vectors u and v:
inline Vector operator^ (Vector u, Vector v) { return Vector( u.y*v.z - u.z*v.y, -u.x*v.z + u.z*v.x, u.x*v.y - u.y*v.x ); }
Vector cross products are handy when you need to find normal (perpendicular) vectors. For example, when performing collision detection, you often need to find the vector normal to the face of a polygon. You can construct two vectors in the plane of the polygon using the polygon’s vertices and then take the cross product of these two vectors to get normal vector.
This operator takes the vector dot product between the vectors u and v, according to the formula
The dot product represents the projection of the vector u onto the vector v as illustrated in Figure A-8.
In this figure, P is the result of the dot product, and it is a scalar. You can also calculate the dot product if you the know the angle between the vectors:
Here’s the code that takes the dot product of u and v:
// Vector dot product inline float operator*(Vector u, Vector v) { return (u.x*v.x + u.y*v.y + u.z*v.z); }
Vector dot products are handy when you need to find the magnitude of a vector projected onto another one. Going back to collision detection as an example, you often have to determine the closest distance from a point, which may be a polygon vertex on one body (body 1), to a polygon face on another body (body 2). If you construct a vector from the face under consideration on body 2, using any of its vertices, to the point under consideration from body 1, then you can find the closest distance of that point from the plane of body 2’s face by taking the dot product of that point with the normal vector to the plane. (If the normal vector is not of unit length, you’ll have to divide the result by the magnitude of the normal vector.)
This operator multiplies the vector u by the scalar s on a component-by-component basis. There are two versions of this overloaded operator depending on the order in which the vector and scalar are encountered:
inline Vector operator*(float s, Vector u) { return Vector(u.x*s, u.y*s, u.z*s); } inline Vector operator*(Vector u, float s) { return Vector(u.x*s, u.y*s, u.z*s); }
This operator divides the vector u by the scalar s on a component-by-component basis:
inline Vector operator/(Vector u, float s) { return Vector(u.x/s, u.y/s, u.z/s); }
This function takes the triple scalar product of the vectors u, v, and w according to the formula
Here, the result, s, is a scalar. The code is as follows:
inline float TripleScalarProduct(Vector u, Vector v, Vector w) { return float( (u.x * (v.y*w.z - v.z*w.y)) + (u.y * (-v.x*w.z + v.z*w.x)) + (u.z * (v.x*w.y - v.y*w.x)) ); }
3.149.249.252