1 //-----------------------------------------------------------------------------
3 //-----------------------------------------------------------------------------
4 // GLVU : Copyright 1997 - 2002
5 // The University of North Carolina at Chapel Hill
6 //-----------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software
8 // and its documentation for any purpose is hereby granted without
9 // fee, provided that the above copyright notice appear in all copies
10 // and that both that copyright notice and this permission notice
11 // appear in supporting documentation. Binaries may be compiled with
12 // this software without any royalties or restrictions.
14 // The University of North Carolina at Chapel Hill makes no representations
15 // about the suitability of this software for any purpose. It is provided
16 // "as is" without express or implied warranty.
18 //==========================================================================
19 // Vec3.hpp : 3d vector class template. Works for any integer or real type.
20 //==========================================================================
30 * @brief A templated 3-vector class
32 * Everybody in graphics has to write their own basic 3-vector class.
33 * And we're no exception. This one uses templates, so that with one
34 * definition of the class you can have a 3-vector of floats or doubles
35 * depending on how precise you are, or you can make 3-vectors of ints
36 * or unsigned char, handy for representing colors.
38 * A couple of typedefs for common instatiations are provided by
39 * default: Vec3f, and Vec3d, the float and double versions,
47 Type x, y, z; ///< The storage for the three components of the vector
49 /// Default constructor.
50 /// Note: does \em not initialize x, y, and z!
53 /// Three component constructor
54 Vec3 (const Type X, const Type Y, const Type Z)
58 { x=v.x; y=v.y; z=v.z; };
59 /// Construct from array
60 Vec3 (const Type v[3])
61 { x=v[0]; y=v[1]; z=v[2]; };
62 /// Set from components
63 void Set (const Type X, const Type Y, const Type Z)
66 void Set (const Type v[3])
67 { x=v[0]; y=v[1]; z=v[2]; };
69 operator Type*() /// Type * CONVERSION
70 { return (Type *)&x; }
71 operator const Type*() const /// CONST Type * CONVERSION
74 bool operator == (const Vec3& A) const /// COMPARISON (==)
75 { return (x==A.x && y==A.y && z==A.z); }
76 bool operator != (const Vec3& A) const /// COMPARISON (!=)
77 { return (x!=A.x || y!=A.y || z!=A.z); }
79 Vec3& operator = (const Vec3& A) /// ASSIGNMENT (=)
80 { x=A.x; y=A.y; z=A.z;
82 Vec3 operator + (const Vec3& A) const /// ADDITION (+)
83 { Vec3 Sum(x+A.x, y+A.y, z+A.z);
85 Vec3 operator - (const Vec3& A) const /// SUBTRACTION (-)
86 { Vec3 Diff(x-A.x, y-A.y, z-A.z);
88 Type operator * (const Vec3& A) const /// DOT-PRODUCT (*)
89 { Type DotProd = x*A.x+y*A.y+z*A.z;
91 Vec3 operator / (const Vec3& A) const /// CROSS-PRODUCT (/)
92 { Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
94 Vec3 operator ^ (const Vec3& A) const /// ALSO CROSS-PRODUCT (^)
95 { Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
97 Vec3 operator * (const Type s) const /// MULTIPLY BY SCALAR V*s (*)
98 { Vec3 Scaled(x*s, y*s, z*s);
100 Vec3 operator / (const Type s) const /// DIVIDE BY SCALAR (/)
101 { Vec3 Scaled(x/s, y/s, z/s);
103 Vec3 operator & (const Vec3& A) const /// COMPONENT MULTIPLY (&)
104 { Vec3 CompMult(x*A.x, y*A.y, z*A.z);
107 friend inline Vec3 operator *(Type s, const Vec3& v) /// SCALAR MULT s*V
108 { return Vec3(v.x*s, v.y*s, v.z*s); }
110 Vec3& operator += (const Vec3& A) /// ACCUMULATED VECTOR ADDITION (+=)
111 { x+=A.x; y+=A.y; z+=A.z;
113 Vec3& operator -= (const Vec3& A) /// ACCUMULATED VECTOR SUBTRACTION (-=)
114 { x-=A.x; y-=A.y; z-=A.z;
116 Vec3& operator *= (const Type s) /// ACCUMULATED SCALAR MULT (*=)
119 Vec3& operator /= (const Type s) /// ACCUMULATED SCALAR DIV (/=)
122 Vec3& operator &= (const Vec3& A) /// ACCUMULATED COMPONENT MULTIPLY (&=)
123 { x*=A.x; y*=A.y; z*=A.z; return *this; }
124 Vec3 operator - (void) const /// NEGATION (-)
125 { Vec3 Negated(-x, -y, -z);
129 const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
130 { return( (i==0)?x:((i==1)?y:z) ); };
131 Type & operator [] (const int i)
132 { return( (i==0)?x:((i==1)?y:z) ); };
135 Type Length (void) const /// LENGTH OF VECTOR
136 { return ((Type)sqrt(x*x+y*y+z*z)); };
137 Type LengthSqr (void) const /// LENGTH OF VECTOR (SQUARED)
138 { return (x*x+y*y+z*z); };
139 Vec3& Normalize (void) /// NORMALIZE VECTOR
140 { Type L = Length(); // CALCULATE LENGTH
141 if (L>0) { x/=L; y/=L; z/=L; } // DIV COMPONENTS BY LENGTH
145 /// Returns the 'star' matrix for a vector
146 /** This is the skew-symmetric matrix \b A such that
147 * \b A \b v == \p this x \b v
148 * (the cross-product of \p this and \b v), for any vector \b v.
149 * The matrix looks like this given vector (x,y,z):
156 * Return format is just an array in row-major (OpenGL/Fortran) order.
157 * That is [0, -z, y, z, 0, -x, -y, x, 0].
160 Type s[] = ( 0, -z, y,
166 /// Update \p Min and \p Max to enclose \p this
167 /** A very handy routine for working with min-max or axis aligned
170 void UpdateMinMax(Vec3 &Min, Vec3 &Max) const
172 if (x<Min.x) Min.x=x; else if (x>Max.x) Max.x=x;
173 if (y<Min.y) Min.y=y; else if (y>Max.y) Max.y=y;
174 if (z<Min.z) Min.z=z; else if (z>Max.z) Max.z=z;
177 /// Construct an orthonormal basis from \p this
178 /** Compute two unit vectors \p U and \p V that are orthogonal
179 * to this vector and to each other. Note that \p *this need
180 * not be a unit vector.
182 * The algorithm works as follows:
183 * Find smallest component of L (this), zero it,
184 * negate one of the other two and swap them. Then normalize.
185 * Ex. if x1 is the smallest, assign (x2,y2,z2):=(0,z1,-y1)
186 * Clearly now v1 dot v2 = x1*0 + y1*z1 + z1*-y1 = 0;
187 * Zeroing out the smallest means that the magnitude of
188 * the remaining vector will be as big as possible so that
189 * when we normalize, we are safe from dividing by anything
190 * close to zero (unless *this was near 0 magnitude to
191 * begin with, in which case lack of precision can't be avoided)
193 void CompleteOrthonormalBasis(Vec3 &U, Vec3 &V) const
196 unsigned char s[3] = {0, 1, 2};
198 U.x = U.x < 0 ? -U.x : -U.x;
199 U.y = U.y < 0 ? -U.y : -U.y;
200 U.z = U.z < 0 ? -U.z : -U.z;
207 // xy min in s[0] now.
208 if ( U[s[0]] > U[2] ) {
213 // xyz min in s[0] now
217 // Voila U is now perpendicular to *this
220 // And so it's easy to find a v that is too, with cross product.
222 // Or by removing components projected onto other two...
223 // I think the cross product may be cheaper
224 // V = something - V * (*this.Normalize() + U);
226 V.Normalize(); // wouldn't be necessary if we knew *this were normalized
229 /// Dump the vector to \c stdout in a pretty way
231 { printf("(%.3f, %.3f, %.3f)\n",x, y, z); }
233 /// This is a handy way to get the zero vector just use Vec3<Type>::ZERO
237 typedef Vec3<float> Vec3f;
238 typedef Vec3<double> Vec3d;
240 template<class Type> Vec3<Type> Vec3<Type>::ZERO = Vec3<Type>(0,0,0);