1 // vector.h (Vector<> class definition)
2 //
3 // The WorldForge Project
4 // Copyright (C) 2001 The WorldForge Project
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 //
20 // For information about WorldForge and its authors, please contact
21 // the Worldforge Web Site at http://www.worldforge.org.
22
23 // Author: Ron Steinke
24 // Created: 2001-12-7
25
26 // Extensive amounts of this material come from the Vector2D
27 // and Vector3D classes from stage/math, written by Bryce W.
28 // Harrington, Kosh, and Jari Sundell (Rakshasa).
29
30 #ifndef WFMATH_VECTOR_H
31 #define WFMATH_VECTOR_H
32
33 #include <wfmath/const.h>
34
35 #include <iosfwd>
36
37 #include <cmath>
38
39 namespace WFMath {
40
41 template<int dim>
42 Vector<dim>& operator+=(Vector<dim>& v1, const Vector<dim>& v2);
43 template<int dim>
44 Vector<dim>& operator-=(Vector<dim>& v1, const Vector<dim>& v2);
45 template<int dim>
46 Vector<dim>& operator*=(Vector<dim>& v, CoordType d);
47 template<int dim>
48 Vector<dim>& operator/=(Vector<dim>& v, CoordType d);
49
50 template<int dim>
51 Vector<dim> operator+(const Vector<dim>& v1, const Vector<dim>& v2);
52 template<int dim>
53 Vector<dim> operator-(const Vector<dim>& v1, const Vector<dim>& v2);
54 template<int dim>
55 Vector<dim> operator-(const Vector<dim>& v); // Unary minus
56 template<int dim>
57 Vector<dim> operator*(CoordType d, const Vector<dim>& v);
58 template<int dim>
59 Vector<dim> operator*(const Vector<dim>& v, CoordType d);
60 template<int dim>
61 Vector<dim> operator/(const Vector<dim>& v, CoordType d);
62
63 template<int dim>
64 CoordType Dot(const Vector<dim>& v1, const Vector<dim>& v2);
65
66 template<int dim>
67 CoordType Angle(const Vector<dim>& v, const Vector<dim>& u);
68
69 // The following are defined in rotmatrix_funcs.h
70 /// returns m * v
71 template<int dim> // m * v
72 Vector<dim> Prod(const RotMatrix<dim>& m, const Vector<dim>& v);
73 /// returns m^-1 * v
74 template<int dim> // m^-1 * v
75 Vector<dim> InvProd(const RotMatrix<dim>& m, const Vector<dim>& v);
76 /// returns v * m
77 /**
78 * This is the function to use to rotate a Vector v using a Matrix m
79 **/
80 template<int dim> // v * m
81 Vector<dim> Prod(const Vector<dim>& v, const RotMatrix<dim>& m);
82 /// return v * m^-1
83 template<int dim> // v * m^-1
84 Vector<dim> ProdInv(const Vector<dim>& v, const RotMatrix<dim>& m);
85
86 ///
87 template<int dim>
88 Vector<dim> operator*(const RotMatrix<dim>& m, const Vector<dim>& v);
89 ///
90 template<int dim>
91 Vector<dim> operator*(const Vector<dim>& v, const RotMatrix<dim>& m);
92
93 template<int dim>
94 Vector<dim> operator-(const Point<dim>& c1, const Point<dim>& c2);
95 template<int dim>
96 Point<dim> operator+(const Point<dim>& c, const Vector<dim>& v);
97 template<int dim>
98 Point<dim> operator-(const Point<dim>& c, const Vector<dim>& v);
99 template<int dim>
100 Point<dim> operator+(const Vector<dim>& v, const Point<dim>& c);
101
102 template<int dim>
103 Point<dim>& operator+=(Point<dim>& p, const Vector<dim>& v);
104 template<int dim>
105 Point<dim>& operator-=(Point<dim>& p, const Vector<dim>& v);
106
107 template<int dim>
108 std::ostream& operator<<(std::ostream& os, const Vector<dim>& v);
109 template<int dim>
110 std::istream& operator>>(std::istream& is, Vector<dim>& v);
111
112 template<typename Shape>
113 class ZeroPrimitive;
114
115 /// A dim dimensional vector
116 /**
117 * This class implements the 'generic' subset of the interface in
118 * the fake class Shape.
119 **/
120 template<int dim = 3>
121 class Vector {
122 friend class ZeroPrimitive<Vector<dim> >;
123 public:
124 /// Construct an uninitialized vector
Vector()125 Vector() : m_valid(false) {}
126 /// Construct a copy of a vector
127 Vector(const Vector& v);
128 /// Construct a vector from an object passed by Atlas
129 explicit Vector(const AtlasInType& a);
130 /// Construct a vector from a point.
131 explicit Vector(const Point<dim>& point);
132
133 /**
134 * @brief Provides a global instance preset to zero.
135 */
136 static const Vector<dim>& ZERO();
137
138 friend std::ostream& operator<< <dim>(std::ostream& os, const Vector& v);
139 friend std::istream& operator>> <dim>(std::istream& is, Vector& v);
140
141 /// Create an Atlas object from the vector
142 AtlasOutType toAtlas() const;
143 /// Set the vector's value to that given by an Atlas object
144 void fromAtlas(const AtlasInType& a);
145
146 Vector& operator=(const Vector& v);
147
148 bool isEqualTo(const Vector& v, CoordType epsilon = numeric_constants<CoordType>::epsilon()) const;
149 bool operator==(const Vector& v) const {return isEqualTo(v);}
150 bool operator!=(const Vector& v) const {return !isEqualTo(v);}
151
isValid()152 bool isValid() const {return m_valid;}
153 /// make isValid() return true if you've initialized the vector by hand
154 void setValid(bool valid = true) {m_valid = valid;}
155
156 /// Zero the components of a vector
157 Vector& zero();
158
159 // Math operators
160
161 /// Add the second vector to the first
162 friend Vector& operator+=<dim>(Vector& v1, const Vector& v2);
163 /// Subtract the second vector from the first
164 friend Vector& operator-=<dim>(Vector& v1, const Vector& v2);
165 /// Multiply the magnitude of v by d
166 friend Vector& operator*=<dim>(Vector& v, CoordType d);
167 /// Divide the magnitude of v by d
168 friend Vector& operator/=<dim>(Vector& v, CoordType d);
169
170 /// Take the sum of two vectors
171 friend Vector operator+<dim>(const Vector& v1, const Vector& v2);
172 /// Take the difference of two vectors
173 friend Vector operator-<dim>(const Vector& v1, const Vector& v2);
174 /// Reverse the direction of a vector
175 friend Vector operator-<dim>(const Vector& v); // Unary minus
176 /// Multiply a vector by a scalar
177 friend Vector operator*<dim>(CoordType d, const Vector& v);
178 /// Multiply a vector by a scalar
179 friend Vector operator*<dim>(const Vector& v, CoordType d);
180 /// Divide a vector by a scalar
181 friend Vector operator/<dim>(const Vector& v, CoordType d);
182
183 // documented outside the class definition
184 friend Vector Prod<dim>(const RotMatrix<dim>& m, const Vector& v);
185 friend Vector InvProd<dim>(const RotMatrix<dim>& m, const Vector& v);
186
187 /// Get the i'th element of the vector
188 CoordType operator[](const int i) const {return m_elem[i];}
189 /// Get the i'th element of the vector
190 CoordType& operator[](const int i) {return m_elem[i];}
191
192 /// Find the vector which gives the offset between two points
193 friend Vector operator-<dim>(const Point<dim>& c1, const Point<dim>& c2);
194 /// Find the point at the offset v from the point c
195 friend Point<dim> operator+<dim>(const Point<dim>& c, const Vector& v);
196 /// Find the point at the offset -v from the point c
197 friend Point<dim> operator-<dim>(const Point<dim>& c, const Vector& v);
198 /// Find the point at the offset v from the point c
199 friend Point<dim> operator+<dim>(const Vector& v, const Point<dim>& c);
200
201 /// Shift a point by a vector
202 friend Point<dim>& operator+=<dim>(Point<dim>& p, const Vector& rhs);
203 /// Shift a point by a vector, in the opposite direction
204 friend Point<dim>& operator-=<dim>(Point<dim>& p, const Vector& rhs);
205
206 friend CoordType Cross(const Vector<2>& v1, const Vector<2>& v2);
207 friend Vector<3> Cross(const Vector<3>& v1, const Vector<3>& v2);
208
209 /// The dot product of two vectors
210 friend CoordType Dot<dim>(const Vector& v1, const Vector& v2);
211 /// The angle between two vectors
212 friend CoordType Angle<dim>(const Vector& v, const Vector& u);
213
214 /// The squared magnitude of a vector
215 CoordType sqrMag() const;
216 /// The magnitude of a vector
mag()217 CoordType mag() const {return std::sqrt(sqrMag());}
218 /// Normalize a vector
219 Vector& normalize(CoordType norm = 1.0)
220 {CoordType themag = mag(); return (*this *= norm / themag);}
221
222 /// An approximation to the magnitude of a vector
223 /**
224 * The sloppyMag() function gives a value between
225 * the true magnitude and sloppyMagMax multiplied by the
226 * true magnitude. sloppyNorm() uses sloppyMag() to normalize
227 * the vector. This is currently only implemented for
228 * dim = {1, 2, 3}. For all current implementations,
229 * sloppyMagMax is greater than or equal to one.
230 * The constant sloppyMagMaxSqrt is provided for those
231 * who want to most closely approximate the true magnitude,
232 * without caring whether it's too low or too high.
233 **/
234 CoordType sloppyMag() const;
235 /// Approximately normalize a vector
236 /**
237 * Normalize a vector using sloppyMag() instead of the true magnitude.
238 * The new length of the vector will be between norm/sloppyMagMax()
239 * and norm.
240 **/
241 Vector& sloppyNorm(CoordType norm = 1.0);
242
243 // Can't seem to implement these as constants, implementing
244 // inline lookup functions instead.
245 /// The maximum ratio of the return value of sloppyMag() to the true magnitude
246 static CoordType sloppyMagMax();
247 /// The square root of sloppyMagMax()
248 /**
249 * This is provided for people who want to obtain maximum accuracy from
250 * sloppyMag(), without caring whether the answer is high or low.
251 * The result sloppyMag()/sloppyMagMaxSqrt() will be within sloppyMagMaxSqrt()
252 * of the true magnitude.
253 **/
254 static CoordType sloppyMagMaxSqrt();
255
256 /// Rotate the vector in the (axis1, axis2) plane by the angle theta
257 Vector& rotate(int axis1, int axis2, CoordType theta);
258
259 /// Rotate the vector in the (v1, v2) plane by the angle theta
260 /**
261 * This throws CollinearVectors if v1 and v2 are parallel.
262 **/
263 Vector& rotate(const Vector& v1, const Vector& v2, CoordType theta);
264
265 /// Rotate the vector using a matrix
266 Vector& rotate(const RotMatrix<dim>&);
267
268 // mirror image functions
269
270 /// Reflect a vector in the direction of the i'th axis
mirror(const int i)271 Vector& mirror(const int i) { m_elem[i] *= -1; return *this;}
272 /// Reflect a vector in the direction specified by v
mirror(const Vector & v)273 Vector& mirror(const Vector& v)
274 {return operator-=(*this, 2 * v * Dot(v, *this) / v.sqrMag());}
275 /// Reflect a vector in all directions simultaneously.
276 /**
277 * This is a nice way to implement the parity operation if dim is odd.
278 **/
mirror()279 Vector& mirror() {return operator*=(*this, -1);}
280
281 // Specialized 2D/3D stuff starts here
282
283 // The following functions are defined only for
284 // two dimensional (rotate(CoordType), Vector<>(CoordType, CoordType))
285 // and three dimensional (the rest of them) vectors.
286 // Attempting to call these on any other vector will
287 // result in a linker error.
288
289 /// 2D only: construct a vector from (x, y) coordinates
290 Vector(CoordType x, CoordType y);
291 /// 3D only: construct a vector from (x, y, z) coordinates
292 Vector(CoordType x, CoordType y, CoordType z);
293
294 /// 2D only: rotate a vector by an angle theta
295 Vector& rotate(CoordType theta);
296
297 /// 3D only: rotate a vector about the x axis by an angle theta
298 Vector& rotateX(CoordType theta);
299 /// 3D only: rotate a vector about the y axis by an angle theta
300 Vector& rotateY(CoordType theta);
301 /// 3D only: rotate a vector about the z axis by an angle theta
302 Vector& rotateZ(CoordType theta);
303
304 /// 3D only: rotate a vector about the i'th axis by an angle theta
305 Vector& rotate(const Vector& axis, CoordType theta);
306 /// 3D only: rotate a vector using a Quaternion
307 Vector& rotate(const Quaternion& q);
308
309 // Label the first three components of the vector as (x,y,z) for
310 // 2D/3D convienience
311
312 /// Access the first component of a vector
x()313 CoordType x() const {return m_elem[0];}
314 /// Access the first component of a vector
x()315 CoordType& x() {return m_elem[0];}
316 /// Access the second component of a vector
y()317 CoordType y() const {return m_elem[1];}
318 /// Access the second component of a vector
y()319 CoordType& y() {return m_elem[1];}
320 /// Access the third component of a vector
321 CoordType z() const;
322 /// Access the third component of a vector
323 CoordType& z();
324
325 /// Flip the x component of a vector
mirrorX()326 Vector& mirrorX() {return mirror(0);}
327 /// Flip the y component of a vector
mirrorY()328 Vector& mirrorY() {return mirror(1);}
329 /// Flip the z component of a vector
330 Vector& mirrorZ();
331
332 /// 2D only: construct a vector from polar coordinates
333 Vector& polar(CoordType r, CoordType theta);
334 /// 2D only: convert a vector to polar coordinates
335 void asPolar(CoordType& r, CoordType& theta) const;
336
337 /// 3D only: construct a vector from polar coordinates
338 Vector& polar(CoordType r, CoordType theta, CoordType z);
339 /// 3D only: convert a vector to polar coordinates
340 void asPolar(CoordType& r, CoordType& theta, CoordType& z) const;
341 /// 3D only: construct a vector from shperical coordinates
342 Vector& spherical(CoordType r, CoordType theta, CoordType phi);
343 /// 3D only: convert a vector to shperical coordinates
344 void asSpherical(CoordType& r, CoordType& theta, CoordType& phi) const;
345
elements()346 const CoordType* elements() const {return m_elem;}
347
348 private:
349 double _scaleEpsilon(const Vector& v, CoordType epsilon = numeric_constants<CoordType>::epsilon()) const
350 {return _ScaleEpsilon(m_elem, v.m_elem, dim, epsilon);}
351
352 CoordType m_elem[dim];
353 bool m_valid;
354 };
355
356 template<>
z()357 inline CoordType Vector<3>::z() const
358 {
359 return m_elem[2];
360 }
361
362 template<>
z()363 inline CoordType& Vector<3>::z()
364 {
365 return m_elem[2];
366 }
367
368 template<>
mirrorZ()369 inline Vector<3>& Vector<3>::mirrorZ()
370 {
371 return mirror(2);
372 }
373
374 /// 2D only: get the z component of the cross product of two vectors
375 CoordType Cross(const Vector<2>& v1, const Vector<2>& v2);
376 /// 3D only: get the cross product of two vectors
377 Vector<3> Cross(const Vector<3>& v1, const Vector<3>& v2);
378
379 /// Check if two vectors are parallel
380 /**
381 * Returns true if the vectors are parallel. For parallel
382 * vectors, same_dir is set to true if they point the same
383 * direction, and false if they point opposite directions
384 **/
385 template<int dim>
386 bool Parallel(const Vector<dim>& v1, const Vector<dim>& v2, bool& same_dir);
387
388 /// Check if two vectors are parallel
389 /**
390 * Convienience wrapper if you don't care about same_dir
391 **/
392 template<int dim>
393 bool Parallel(const Vector<dim>& v1, const Vector<dim>& v2);
394
395 /// Check if two vectors are perpendicular
396 template<int dim>
397 bool Perpendicular(const Vector<dim>& v1, const Vector<dim>& v2);
398
399 template <int dim>
400 inline Vector<dim> operator+(const Vector<dim>& v1, const Vector<dim>& v2)
401 {
402 Vector<dim> ans(v1);
403
404 ans += v2;
405
406 return ans;
407 }
408
409 template <int dim>
410 inline Vector<dim> operator-(const Vector<dim>& v1, const Vector<dim>& v2)
411 {
412 Vector<dim> ans(v1);
413
414 ans -= v2;
415
416 return ans;
417 }
418
419 template <int dim>
420 inline Vector<dim> operator*(const Vector<dim>& v, CoordType d)
421 {
422 Vector<dim> ans(v);
423
424 ans *= d;
425
426 return ans;
427 }
428
429 template<int dim>
430 inline Vector<dim> operator*(CoordType d, const Vector<dim>& v)
431 {
432 Vector<dim> ans(v);
433
434 ans *= d;
435
436 return ans;
437 }
438
439 template <int dim>
440 inline Vector<dim> operator/(const Vector<dim>& v, CoordType d)
441 {
442 Vector<dim> ans(v);
443
444 ans /= d;
445
446 return ans;
447 }
448
449 template<int dim>
Parallel(const Vector<dim> & v1,const Vector<dim> & v2,bool & same_dir)450 inline bool Parallel(const Vector<dim>& v1,
451 const Vector<dim>& v2,
452 bool& same_dir)
453 {
454 CoordType dot = Dot(v1, v2);
455
456 same_dir = (dot > 0);
457
458 return Equal(dot * dot, v1.sqrMag() * v2.sqrMag());
459 }
460
461 template<int dim>
Parallel(const Vector<dim> & v1,const Vector<dim> & v2)462 inline bool Parallel(const Vector<dim>& v1, const Vector<dim>& v2)
463 {
464 bool same_dir;
465
466 return Parallel(v1, v2, same_dir);
467 }
468
469 template<>
sloppyMagMax()470 inline CoordType Vector<1>::sloppyMagMax()
471 {
472 return 1.f;
473 }
474
475 template<>
sloppyMagMax()476 inline CoordType Vector<2>::sloppyMagMax()
477 {
478 return 1.082392200292393968799446410733f;
479 }
480
481 template<>
sloppyMagMax()482 inline CoordType Vector<3>::sloppyMagMax()
483 {
484 return 1.145934719303161490541433900265f;
485 }
486
487 template<>
sloppyMagMaxSqrt()488 inline CoordType Vector<1>::sloppyMagMaxSqrt()
489 {
490 return 1.f;
491 }
492
493 template<>
sloppyMagMaxSqrt()494 inline CoordType Vector<2>::sloppyMagMaxSqrt()
495 {
496 return 1.040380795811030899095785063701f;
497 }
498
499 template<>
sloppyMagMaxSqrt()500 inline CoordType Vector<3>::sloppyMagMaxSqrt()
501 {
502 return 1.070483404496847625250328653179f;
503 }
504
505 } // namespace WFMath
506
507 #endif // WFMATH_VECTOR_H
508