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