// Copyright 2005 Keir Mierle. // Licensed under the BSD license #ifndef _VEC_H #define _VEC_H // Reduce code: We use this all over the place. #define DimLoopReturn(op) \ vec ret; \ for (int i=0; icoords[0], (v)->coords[1], (v)->coords[2] #include #include template class vec { public: T coords[dim]; vec() { } vec(const vec& b) { DimLoop(coords[i] = b.coords[i]) } vec(const T b) { DimLoop(coords[i] = b) } T &operator[]( const int ndx ) { return( coords[ndx] ); } const vec& operator= (const vec& param) { DimLoop(coords[i] = param.coords[i]) return *this; } const vec& operator= (const T a) { DimLoop(coords[i] = a) return *this; } // Arithmetic operators vec operator+ (const vec& param) const { DimLoopReturn(coords[i] + param.coords[i]) } void operator+= (const vec& param) { DimLoop(coords[i] += param.coords[i]) } vec operator- (const vec& param) const { DimLoopReturn(coords[i] - param.coords[i]) } void operator-= (const vec& param) { DimLoop(coords[i] -= param.coords[i]) } vec operator- () const { DimLoopReturn(ret[i] = -coords[i]) } vec operator* (const vec& param) const { DimLoopReturn(coords[i] * param.coords[i]) } // Dot product (although please use dot(a,b) for clarity) T dot(const vec& param) { T dp = 0; DimLoop( dp += coords[i] * param.coords[i] ) return dp; } // Magnitude T mag() const { T accum = 0; DimLoop( accum += coords[i] * coords[i] ) return sqrt(accum); } T magsq() const { T accum = 0; DimLoop( accum += coords[i] * coords[i] ) return accum; } // Projection of this onto b, in the direction of b vec proj (const vec& b) { return (b/b.mag()) * (((*this)*b)/b.mag()); } }; // Scalar operations: One glob so we can make this short. #define VEC_SCALAR_OP(op) \ template \ static inline vec operator op (const vec& a, const T b) \ { DimLoopReturn(a.coords[i] op b) } \ template \ static inline vec operator op (const T b, const vec& a) \ { DimLoopReturn(b op a.coords[i]) } \ template \ static inline void operator op##= (vec& a, const T b) \ { DimLoop(a.coords[i] op##= b) } // Now implement those scalar <-> vector operations using the macro above. VEC_SCALAR_OP(+) VEC_SCALAR_OP(-) VEC_SCALAR_OP(*) VEC_SCALAR_OP(/) // Now specialize down to the 3D case template class vec3 : public vec { public: vec3() { } vec3(const vec& b) { vec::operator=(b); } vec3(T x, T y, T z) { this->coords[0] = x; this->coords[1] = y; this->coords[2] = z; } const vec3& operator= (const vec3& b) { vec::operator=(b); return *this; } const vec3& operator= (const vec& b) { vec::operator=(b); return *this; } const vec3& operator= (const T b) { vec::operator=(b); return *this; } // Cross product vec3 cross (const vec3& b) const { vec3 ret; ret[0] = this->coords[1]*b.coords[2] - this->coords[2]*b.coords[1]; ret[1] = this->coords[2]*b.coords[0] - this->coords[0]*b.coords[2]; ret[2] = this->coords[0]*b.coords[1] - this->coords[1]*b.coords[0]; return ret; } T x() const { return this->coords[0]; } T y() const { return this->coords[1]; } T z() const { return this->coords[2]; } }; // Output routines template std::ostream& operator<< (std::ostream& os, vec& v) { os << '(' ; for (int i=0;i vec3f; typedef vec3 vec3d; // It's nicer to write dot(a,b) template inline T dot(vec a,vec b) { return a.dot(b); } // It's nicer to write cross(a,b) template inline vec3 cross(vec3 a,vec3 b) { return a.cross(b); } #endif // _VEC_H