Vector.inl

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   Vector.inl
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @date   Fall 2008
00005    
00006    @brief
00007       Provides basic functionality for a constant-sized Vector
00008    <!-------------------------------------------------------------------->**/
00009 
00010 #ifndef VECTOR_INL_
00011 #define VECTOR_INL_
00012 
00013 
00014 // Constructors
00015 // ------------
00016 
00017 // Expects N arguments of type T
00018 // (srcData is a pointer to an N-length array of type T)
00019 template <unsigned N, typename T>
00020 inline Vector<N, T>::Vector(const T *srcData) {
00021    memcpy(data, srcData, VECTOR_SIZE);
00022 }
00023 
00024 // Constructs an zero Vector
00025 template <unsigned N, typename T>
00026 inline Vector<N, T>::Vector() {
00027    bzero(data, VECTOR_SIZE);
00028 }
00029 
00030 // Copy Constructor; copies the underlying data from v to this vector
00031 template <unsigned N, typename T>
00032 inline Vector<N, T>::Vector(const Vector<N, T> &v) {
00033    memcpy(data, v.data, VECTOR_SIZE);
00034 }
00035 
00036 
00037 // Accessor Operators
00038 // ------------------
00039 
00040 // @returns a const reference to the element at the given index
00041 template <unsigned N, typename T>
00042 inline const T &Vector<N, T>::operator[](const unsigned index) const {
00043    ASSERT(index < N);
00044    
00045    return data[index];
00046 }
00047 
00048 // @returns a reference to the element at the given index
00049 // @note changes to the returned element will affect this vector
00050 template <unsigned N, typename T>
00051 inline       T &Vector<N, T>::operator[](const unsigned index) {
00052    ASSERT(index < N);
00053    
00054    return data[index];
00055 }
00056 
00057 // @returns a pointer to the underlying data (N-length array of type T)
00058 template <unsigned N, typename T>
00059 inline const T *Vector<N, T>::operator* () const {
00060    return (T*)this;
00061 }
00062 
00063 // @returns a pointer to the underlying data (N-length array of type T)
00064 template <unsigned N, typename T>
00065 inline       T *Vector<N, T>::operator* () {
00066    return (T*)this;
00067 }
00068 
00069 
00070 // Equality Operators
00071 // ------------------
00072 template <unsigned N, typename T>
00073 inline       bool       Vector<N, T>::operator==(const Vector<N, T> &v) const
00074 {
00075    for(unsigned i = N; i--;)
00076       if (NEQ(data[i], v.data[i]))
00077          return false;
00078    
00079    return true;
00080 }
00081 
00082 template <unsigned N, typename T>
00083 inline       bool       Vector<N, T>::operator!=(const Vector<N, T> &v) const 
00084 {
00085    return !((*this) == v);
00086 }
00087 
00088 // Mutator Operators
00089 // -----------------
00090 
00091 template <unsigned N, typename T>
00092 inline       Vector<N, T> &Vector<N, T>::operator =(const Vector<N, T> &v)
00093 {
00094    memcpy(data, v.data, VECTOR_SIZE);
00095    
00096    return *this;
00097 }
00098 
00099 template <unsigned N, typename T>
00100 inline       Vector<N, T> &Vector<N, T>::operator+=(const Vector<N, T> &rhs)
00101 {
00102    for(unsigned i = N; i--;)
00103       data[i] += rhs.data[i];
00104    
00105    return *this;
00106 }
00107 
00108 template <unsigned N, typename T>
00109 inline       Vector<N, T> &Vector<N, T>::operator-=(const Vector<N, T> &rhs)
00110 {
00111    return (*this += -rhs);
00112 }
00113 
00114 
00115 // Scalar Mutator Operators
00116 // ------------------------
00117 template <unsigned N, typename T>
00118 inline       Vector<N, T> &Vector<N, T>::operator*=(const T &scale) {
00119    for(unsigned i = N; i--;)
00120       data[i] *= scale;
00121    
00122    return *this;
00123 }
00124 
00125 template <unsigned N, typename T>
00126 inline       Vector<N, T> &Vector<N, T>::operator/=(const T &scale) {
00127    if (scale != 0) {
00128       for(unsigned i = N; i--;)
00129          data[i] /= scale;
00130    } else {
00131       std::cerr << "Error: Attempting to divide Vector by zero" << std::endl << std::endl;
00132       ASSERT(0);
00133    }
00134    
00135    return *this;
00136 }
00137 
00138 
00139 // Arithmetic Operators
00140 // --------------------
00141 
00142 template <unsigned N, typename T>
00143 inline       Vector<N, T>  Vector<N, T>::operator+ (const Vector<N, T> &rhs) const
00144 {
00145    T d[VECTOR_NO_ELEMENTS];
00146    
00147    for(unsigned i = N; i--;)
00148       d[i] = data[i] + rhs.data[i];
00149    
00150    return Vector<N, T>(d);
00151 }
00152 
00153 template <unsigned N, typename T>
00154 inline       Vector<N, T>  Vector<N, T>::operator- (const Vector<N, T> &rhs) const
00155 {
00156    T d[VECTOR_NO_ELEMENTS];
00157    
00158    for(unsigned i = N; i--;)
00159       d[i] = data[i] - rhs.data[i];
00160    
00161    return Vector<N, T>(d);
00162 }
00163 
00164 template <unsigned N, typename T>
00165 inline       Vector<N, T>  Vector<N, T>::operator* (const Vector<N, T> &rhs) const
00166 {
00167    T d[VECTOR_NO_ELEMENTS];
00168    
00169    for(unsigned i = N; i--;)
00170       d[i] = data[i] * rhs.data[i];
00171    
00172    return Vector<N, T>(d);
00173 }
00174 
00175 // Scalar Arithmetic Operators
00176 template <unsigned N, typename T>
00177 inline       Vector<N, T>  Vector<N, T>::operator* (const T &scale) const {
00178    T d[VECTOR_NO_ELEMENTS];
00179    
00180    for(unsigned i = N; i--;)
00181       d[i] = data[i] * scale;
00182    
00183    return Vector<N, T>(d);
00184 }
00185 
00186 template <unsigned N, typename T>
00187 inline       Vector<N, T>  Vector<N, T>::operator/ (const T &scale) const {
00188    if (scale != 0) {
00189       return (*this * (create_real(1.0) / scale));
00190    } else {
00191       std::cerr << "Error: Attempting to divide Vector by zero" << std::endl << std::endl;
00192       ASSERT(0);
00193       
00194       return Vector<N, T>();
00195    }
00196 }
00197 
00198 
00199 // More Complex Functionality
00200 // --------------------------
00201 
00202 // @returns whether or not this Vector is unitized
00203 template <unsigned N, typename T>
00204 inline bool Vector<N, T>::isUnit() const {
00205    return (EQ(getMagnitude2(), 1));
00206 }
00207 
00208 // @returns whether or not this Vector is the zero vector
00209 template <unsigned N, typename T>
00210 inline bool Vector<N, T>::isZero() const {
00211    for(unsigned i = N; i--;) {
00212       if (data[i] != 0)
00213          return false;
00214    }
00215    
00216    return true;
00217 }
00218 
00219 // @returns a normalized version of this vector
00220 template <unsigned N, typename T>
00221 inline Vector<N, T> Vector<N, T>::getNormalized() const {
00222    const T &magnitude = getMagnitude();
00223    
00224    if (magnitude == 0) {
00225       //std::cerr << "Error: Attempting to normalize vector with magnitude zero" << std::endl << std::endl;
00226       //ASSERT(0);
00227       
00228       // TODO: how to handle this; apparently lots of meshes contain zero-ish data
00229       // which gets truncated to zero and we get here..
00230       
00231       return Vector<N, T>();
00232    } else {
00233       const real_t &inv  = create_real(1.0) / magnitude;
00234       T d[VECTOR_NO_ELEMENTS]; 
00235       
00236       for(unsigned i = N; i--;)
00237          d[i] = data[i] * inv;
00238       
00239       return Vector<N, T>(d);
00240    }
00241 }
00242 
00243 // @returns the reciprocal version of this vector (1.0 / this)
00244 template <unsigned N, typename T>
00245 inline Vector<N, T> Vector<N, T>::getReciprocal() const {
00246    T d[VECTOR_NO_ELEMENTS];
00247    
00248    for(unsigned i = N; i--;)
00249       d[i] = create_real(1.0) / data[i];
00250    
00251    return Vector<N, T>(d);
00252 }
00253 
00254 // Normalizes this Vector and returns the old magnitude
00255 template <unsigned N, typename T>
00256 inline T Vector<N, T>::normalize() {
00257    const T &magnitude = getMagnitude();
00258    
00259    if (magnitude != 0) {
00260       const real_t &inv  = 1.0 / magnitude;
00261       
00262       for(unsigned i = N; i--;)
00263          data[i] *= inv;
00264    } else {
00265       //std::cerr << "Error: Attempting to normalize vector with magnitude zero" << std::endl << std::endl;
00266       //ASSERT(0);
00267       // TODO: how to handle this; apparently lots of meshes contain zero-ish data
00268       // which gets truncated to zero and we get here..
00269    }
00270    
00271    return magnitude;
00272 }
00273 
00274 // @returns the magnitude of this vector
00275 template <unsigned N, typename T>
00276 inline T Vector<N, T>::getMagnitude() const {
00277    return sqrt(getMagnitude2());
00278 }
00279 
00280 // @returns the squared magnitude of this vector
00281 template <unsigned N, typename T>
00282 inline T Vector<N, T>::getMagnitude2() const {
00283    T magnitude2 = 0;
00284    
00285    for(unsigned i = N; i--;)
00286       magnitude2 += data[i] * data[i];
00287    
00288    return magnitude2;
00289 }
00290 
00291 // @returns the magnitude of the vector connecting this vector to the one 
00292 //    passed in
00293 template <unsigned N, typename T>
00294 inline T Vector<N, T>::getDistance(const Vector<N, T> &v) const {
00295    return sqrt(getDistance2(v));
00296 }
00297 
00298 // @returns the squared magnitude of the vector connecting this vector to 
00299 //    the one passed in
00300 template <unsigned N, typename T>
00301 inline T Vector<N, T>::getDistance2(const Vector<N, T> &v) const {
00302    return (v - *this).getMagnitude2();
00303 }
00304 
00305 // @returns the sum of the components in this Vector
00306 template <unsigned N, typename T>
00307 inline T Vector<N, T>::getSum() const {
00308    T sum = 0;
00309    
00310    for(unsigned i = N; i--;)
00311       sum += data[i];
00312    
00313    return sum;
00314 }
00315 
00316 // @returns the average of the components in this Vector
00317 template <unsigned N, typename T>
00318 inline T Vector<N, T>::getAverage() const {
00319    return (getSum() / N);
00320 }
00321 
00322 // @returns the dot (inner) product of two vectors
00323 template <unsigned N, typename T>
00324 inline T Vector<N, T>::dot(const Vector<N, T> &rhs) const {
00325    T result = 0;
00326    
00327    for(unsigned i = N; i--;)
00328       result += data[i] * rhs[i];
00329    
00330    return result;
00331 }
00332 
00333 
00334 // Specialized Vector Functionality
00335 // --------------------------------
00336 
00337 // Convenience Constructor
00338 template <unsigned N, typename T>
00339 inline Vector<N, T>::Vector(const T &v0, const T &v1, const T &v2) {
00340    if (N > 0)
00341       data[0] = v0;
00342    if (N > 1)
00343       data[1] = v1;
00344    if (N > 2)
00345       data[2] = v2;
00346 }
00347 
00348 // @returns the cross product of two vectors
00349 // @note only have to implement for 3 or 4 dimensions
00350 //    (in either case, just use hardcoded cross product for 3 dimensions and 
00351 //     if N is 4, set 'w' to 0)
00352 template <unsigned N, typename T>
00353 inline Vector<N, T> Vector<N, T>::cross(const Vector<N, T> &v) const
00354 {
00355    const Vector<N, T> &u = *this;
00356    
00357    if (N == 3 || N == 4) {
00358       return Vector<N, T>(u[1] * v[2] - u[2] * v[1], 
00359                           u[2] * v[0] - u[0] * v[2], 
00360                           u[0] * v[1] - u[1] * v[0]);
00361    }
00362    
00363    ASSERT(0 && "cross products are only implemented for N=3 and N=4\n");
00364    return Vector<N, T>();
00365 }
00366 
00367 
00368 // Extra operators where Vector is on right-hand side
00369 // --------------------------------------------------
00370 
00371 // @returns the N-length vector resulting from multiplying a scalar by an 
00372 //    N-length vector
00373 template <unsigned N, typename T>
00374 inline       Vector<N, T>  operator* (const real_t &scale, 
00375                                       const Vector<N, T> &rhs)
00376 {
00377    return rhs * scale;
00378 }
00379 
00380 // @returns (-1) * rhs, which is a negated version of the original right 
00381 //    hand side vector
00382 template <unsigned N, typename T>
00383 inline       Vector<N, T> operator- (const Vector<N, T> &rhs) {
00384    return rhs * (-1);
00385 }
00386 
00387 // Prints a Vector to an output stream
00388 template <unsigned N, typename T>
00389 inline       std::ostream      &operator<<(std::ostream &os, 
00390                                            const Vector<N, T> &v)
00391 {
00392    os << "[ ";
00393    
00394    for(unsigned i = 0; i < N; ++i)
00395       os << v.data[i] << (i < N - 1 ? ", " : "");
00396 
00397    os << " ]";
00398    return os;
00399 }
00400 
00401 // @returns dimension (0,1,...,N) of maximum length
00402 template <unsigned N, typename T>
00403 inline unsigned Vector<N, T>::getMaxDimension() const {
00404    unsigned max = 0;
00405    T maxVal = 0;
00406    
00407    for(unsigned i = N; i--;) {
00408       const T &val = ABS(data[i]);
00409       
00410       if (val > maxVal) {
00411          max = i;
00412          maxVal = val;
00413       }
00414    }
00415    
00416    return max;
00417 }
00418 
00419 // @returns dimension (0,1,...,N) of minimum length
00420 template <unsigned N, typename T>
00421 inline unsigned Vector<N, T>::getMinDimension() const {
00422     unsigned min = N - 1;
00423    
00424    for(unsigned i = N - 1; i--;)
00425       if (data[i] < data[min])
00426          min = i;
00427    
00428    return min;
00429 }
00430 
00431 
00432 // Cleans up vector (0's out entries that are less than epsilon)
00433 template <unsigned N, typename T>
00434 void Vector<N, T>::cleanup() {
00435    for(unsigned i = N; i--;) {
00436       if (EQ(data[i], 0)) {
00437          data[i] = 0;
00438       }
00439    }
00440 }
00441 
00442 /* Assume normal is normalized, incident vector is incoming and
00443  * resultant vector is exiting */
00444 template <unsigned N, typename T>
00445 Vector<N, T> Vector<N, T>::reflectVector(const Vector<N, T> &normal) const {
00446    return -2 * normal * dot(normal) + *this;
00447    //const Vector<N, T> &n = (dot(normal) < 0 ? normal : -normal);
00448    
00449    //return -2 * n * dot(n) + *this;
00450 }
00451 
00452 template <unsigned N, typename T>
00453 Vector<N, T> Vector<N, T>::refractVector(const Vector<N, T> &normal, 
00454                                          real_t in, real_t out) const
00455 {
00456    const Vector3 &w = -*this;
00457    Vector3 norm;
00458    real_t n;
00459    
00460    if (dot(normal) < 0) {  // wi incident on front-side of surface
00461       ASSERT(out != 0);
00462       norm = normal;
00463       n = in / out;
00464    } else {                // wi incident on back-side  of surface
00465       ASSERT(in != 0);
00466       norm = -normal;
00467       n = out / in;
00468    }
00469    
00470    const real_t d   = w.dot(norm);
00471    const real_t det = 1 - n * n * (1 - d * d);
00472    
00473    if (det < 0)
00474       return Vector3::zero();
00475    
00476    const Vector3 &wo = -n * w + norm * (n * d - sqrt(det));
00477    ASSERT(wo.isUnit());
00478    
00479    return wo;
00480 }
00481 
00482 #if 0
00483 template <unsigned N, typename T>
00484 Vector<N, T> Vector<N, T>::refractVector(const Vector<N, T> &normal, 
00485                                          real_t in, real_t out) const
00486 {
00487    const Vector3 &dir = -*this;
00488    Vector3 norm;
00489    real_t n;
00490    
00491    if (dot(normal) < 0) {  // wi incident on front-side of surface
00492       ASSERT(in != 0);
00493       norm = normal;
00494       n = out / in;
00495    } else {                // wi incident on back-side  of surface
00496       ASSERT(out != 0);
00497       norm = -normal;
00498       n = in / out;
00499    }
00500    
00501    const real_t d = dir.dot(norm);
00502    const real_t det = 1 - n * n * (1 - d * d);
00503    
00504    if (det < 0)
00505       return Vector<3, T>::zero();
00506    
00507    return -n * (dir - d * norm) - norm * sqrt(det); 
00508 }
00509 #endif
00510 
00511 template <unsigned N, typename T>
00512 void Vector<N, T>::getOrthonormalBasis(Vector<N, T> &U, Vector<N, T> &V) 
00513 {
00514    normalize();
00515    const Vector3 &normal = *this;
00516    Vector3 up = Vector3(0, 1, 0);
00517    
00518    if (ABS(up.dot(normal)) > create_real(0.8))
00519       up = Vector3(1, 0, 0);
00520    
00521    U = up.cross(normal).getNormalized();
00522    V = normal.cross(U).getNormalized();
00523 }
00524 
00525 inline Vector3 convertHemisphere(const real_t theta, const real_t phi, 
00526                                  const Vector3 &N)
00527 {
00528    ASSERT(theta >= -EPSILON && theta <= M_PI / 2 + EPSILON);
00529    ASSERT(phi   >= -EPSILON && phi   <= M_PI * 2 + EPSILON);
00530    
00531    const Vector3 &w = Vector3::fromSpherical(theta, phi);
00532    
00533    return convertHemisphere(w, N);
00534 }
00535 
00536 #endif // VECTOR_INL_
00537 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6