Cafu Engine
Vector3.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_MATH_VECTOR3_HPP_INCLUDED
8 #define CAFU_MATH_VECTOR3_HPP_INCLUDED
9 
10 #include "Errors.hpp"
11 
12 #include <cassert>
13 #include <cmath>
14 #include <iomanip>
15 #include <limits>
16 #include <sstream>
17 
18 
19 /// This class represents a polymorphic 3-dimensional vector.
20 ///
21 /// In order to clearly distinguish between methods that modify their "this" Vector3T<T> and those that don't,
22 /// the general idea is that all const, non-modifying methods start with "Get", e.g. GetLength().
23 /// However the dot() and cross() methods are exceptions for increased readability of user code.
24 /// Semantically and intuitively, we prefer to treat them as special binary infix operators as we do in
25 /// hand-written math -- its just the C++ language that doesn't provide us with appropriate symbols.
26 ///
27 /// For operators, it is intuitively clear whether they modify the this object or not.
28 /// E.g. the += operator modifies the this object, the + operator does not.
29 /// Note that there is no need to define "constructive", binary infix operators (like the + operator)
30 /// outside (that is, not as members) of this class, because promotion of the left-hand argument as described
31 /// in the C++ FAQs does not occur in and thus is not relevant for this class (we have no constructor to
32 /// promote a built-in type to a Vector3T<T>).
33 /// See http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.9 items 5 to 7 (especially 7)
34 /// and http://www.parashift.com/c++-faq-lite/friends.html#faq-14.5 for details about this.
35 template<class T>
36 class Vector3T
37 {
38  public:
39 
40  T x; ///< The x-component of this vector.
41  T y; ///< The y-component of this vector.
42  T z; ///< The z-component of this vector.
43 
44 
45 
46  /// The default constructor. It initializes all components to zero.
47  Vector3T() : x(0), y(0), z(0) { }
48 
49  /// This constructor initializes the components from x_, y_ and z_ respectively.
50  Vector3T(T x_, T y_, T z_) : x(x_), y(y_), z(z_) { }
51 
52  /// This constructor initializes the components from an array of (at least) three Ts.
53  template<class C> explicit Vector3T(const C Values[]) : x(T(Values[0])), y(T(Values[1])), z(T(Values[2])) { }
54 
55 
56 
57  /// Returns true if the vector is valid, that is, all components are non-NANs.
58  bool IsValid() const
59  {
60  return true;
61  }
62 
63  /// Component access by index number (0 to 2) rather than by name.
64  /// @param Index Index of the component to access. Can only be 0, 1 or 2 (for x, y, z).
65  /// @throws InvalidOperationE if Index is not 0, 1 or 2.
66  T& operator [] (unsigned int Index)
67  {
68  switch (Index)
69  {
70  case 0: return x;
71  case 1: return y;
72  case 2: return z;
73  default: throw InvalidOperationE();
74  }
75  }
76 
77  /// Component access by index number (0 to 2) rather than by name.
78  /// @param Index Index of the component to access. Can only be 0, 1 or 2 (for x, y, z).
79  /// @throws InvalidOperationE if Index is not 0, 1 or 2.
80  const T& operator [] (unsigned int Index) const
81  {
82  switch (Index)
83  {
84  case 0: return x;
85  case 1: return y;
86  case 2: return z;
87  default: throw InvalidOperationE();
88  }
89  }
90 
91 
92 
93  /// Gets this Vector3T<T> as a Vector3T<float>, so that the cast is explicitly visible in user code.
95  {
96 #ifdef _WIN32
97  assert(typeid(T)!=typeid(float));
98 #endif
99 
100  return Vector3T<float>(float(x), float(y), float(z));
101  }
102 
103  /// Gets this Vector3T<T> as a Vector3T<double>, so that the cast is explicitly visible in user code.
105  {
106 #ifdef _WIN32
107  assert(typeid(T)!=typeid(double));
108 #endif
109 
110  return Vector3T<double>(double(x), double(y), double(z));
111  }
112 
113  /// Gets this Vector3T<T> as a Vector3T<int>, so that the cast is explicitly visible in user code.
115  {
116  return Vector3T<int>(int(x), int(y), int(z));
117  }
118 
119 
120 
121  /// @name Group of const inspector methods. They are all const and thus do not modify this object.
122  //@{
123 
124  // I've commented out this method because class methods of a template cannot be indivially specialized.
125  // That it, the GetLength() method cannot be individually be specialized for floats.
126  // Use the global length() function (defined below) instead!
127  // /// Returns the length of this vector.
128  // T GetLength() const { return sqrt(GetLengthSqr()); }
129 
130  /// Returns the square of the length of this vector.
131  T GetLengthSqr() const { return x*x + y*y + z*z; }
132 
133  /// Returns whether this vector is equal to B within tolerance Epsilon, that is, whether it is geometrically closer to B than Epsilon.
134  /// @param B Vector to compare to.
135  /// @param Epsilon Tolerance value.
136  /// @see operator ==
137  bool IsEqual(const Vector3T<T>& B, const T Epsilon) const
138  {
139  return (*this-B).GetLengthSqr() <= Epsilon*Epsilon;
140  }
141 
142  /// Returns a copy of this vector scaled by s, that is, the scalar product (Skalarmultiplikation) of this vector and s.
143  /// @param s Scale factor to scale this vector by.
144  /// @see Also see the operator *, which does exactly the same.
145  Vector3T<T> GetScaled(const T s) const
146  {
147  return Vector3T<T>(x*s, y*s, z*s);
148  }
149 
150  /// Returns a copy of this vector non-uniformely scaled by S.
152  {
153  return Vector3T<T>(x*S.x, y*S.y, z*S.z);
154  }
155 
156  /// Returns a copy of this vector rotated around the x-axis by Angle degrees.
157  Vector3T<T> GetRotX(const T Angle) const
158  {
159  const T RadAngle=Angle*T(3.14159265358979323846/180.0);
160  const T SinAngle=sin(RadAngle);
161  const T CosAngle=cos(RadAngle);
162 
163  return Vector3T<T>(x,
164  CosAngle*y-SinAngle*z,
165  SinAngle*y+CosAngle*z);
166  }
167 
168  /// Returns a copy of this vector rotated around the y-axis by Angle degrees.
169  Vector3T<T> GetRotY(const T Angle) const
170  {
171  const T RadAngle=Angle*T(3.14159265358979323846/180.0);
172  const T SinAngle=sin(RadAngle);
173  const T CosAngle=cos(RadAngle);
174 
175  return Vector3T<T>(CosAngle*x+SinAngle*z,
176  y,
177  -SinAngle*x+CosAngle*z);
178  }
179 
180  /// Returns a copy of this vector rotated around the z-axis by Angle degrees.
181  Vector3T<T> GetRotZ(const T Angle) const
182  {
183  const T RadAngle=Angle*T(3.14159265358979323846/180.0);
184  const T SinAngle=sin(RadAngle);
185  const T CosAngle=cos(RadAngle);
186 
187  return Vector3T<T>(CosAngle*x-SinAngle*y,
188  SinAngle*x+CosAngle*y,
189  z);
190  }
191 
192  /// Returns two vectors that are orthogonal to this vector and to each other.
193  void CreateOrthoVectors(Vector3T<T>& Left, Vector3T<T>& Down) const
194  {
195  const T DistSqr=x*x+y*y;
196 
197  if (DistSqr==0)
198  {
199  Left.x=1;
200  Left.y=0;
201  Left.z=0;
202  }
203  else
204  {
205  const T Dist=sqrt(DistSqr);
206 
207  Left.x=-y/Dist;
208  Left.y=x/Dist;
209  Left.z=0;
210  }
211 
212  Down=Left.cross(*this);
213  }
214 
215  //@}
216 
217 
218 
219  /// @name Group of (constructive) binary operators that do not modify their operands.
220  //@{
221 
222  /// Returns whether this vector and B are truly (bit-wise) identical.
223  /// Use this operator with care, as it comes *without* any epsilon threshold for taking rounding errors into account.
224  /// @param B Vector to compare to.
225  /// @see IsEqual()
226  bool operator == (const Vector3T<T>& B) const
227  {
228  return x==B.x &&
229  y==B.y &&
230  z==B.z;
231  }
232 
233  /// Returns whether this vector and B are not equal (bit-wise).
234  /// Use this operator with care, as it comes *without* any epsilon threshold for taking rounding errors into account.
235  /// @param B Vector to compare to.
236  /// @see IsEqual()
237  bool operator != (const Vector3T<T>& B) const
238  {
239  return x!=B.x ||
240  y!=B.y ||
241  z!=B.z;
242  }
243 
244  /// Returns the sum of this Vector3T<T> and B.
246  {
247  return Vector3T<T>(x+B.x, y+B.y, z+B.z);
248  }
249 
250  /// Returns the difference between this Vector3T<T> and B.
252  {
253  return Vector3T<T>(x-B.x, y-B.y, z-B.z);
254  }
255 
256  /// The unary minus operator. B=-A is quasi identical with B=A.GetScaled(-1).
258  {
259  return Vector3T<T>(-x, -y, -z);
260  }
261 
262  /// Returns a copy of this vector scaled by s, that is, the scalar product (Skalarmultiplikation) of this vector and s.
263  /// @param s Factor to multiply this vector with.
264  /// @see GetScaled(), which does exactly the same.
265  Vector3T<T> operator * (const T s) const
266  {
267  return GetScaled(s);
268  }
269 
270  /// Returns a copy of this vector divided by s, that is, the scalar product (Skalarmultiplikation) of this vector and 1/s.
271  Vector3T<T> operator / (const T s) const
272  {
273  // Cannot multiply by the reciprocal, because that won't work with integers.
274  return Vector3T<T>(x/s, y/s, z/s);
275  }
276 
277  /// Returns the dot product (Skalarprodukt) of this vector and B.
278  T dot(const Vector3T<T>& B) const
279  {
280  return x*B.x + y*B.y + z*B.z;
281  }
282 
283  /// Returns the cross product (Vektorprodukt) of this vector and B.
284  Vector3T<T> cross(const Vector3T<T>& B) const
285  {
286  return Vector3T<T>(y*B.z - z*B.y,
287  z*B.x - x*B.z,
288  x*B.y - y*B.x);
289  }
290 
291  //@}
292 
293 
294 
295  /// @name Group of operators that modify this vector.
296  //@{
297 
298  /// Adds B to this vector.
300  {
301  x+=B.x;
302  y+=B.y;
303  z+=B.z;
304 
305  return *this;
306  }
307 
308  /// Subtracts B from this vector.
310  {
311  x-=B.x;
312  y-=B.y;
313  z-=B.z;
314 
315  return *this;
316  }
317 
318  /// Scales this vector by s.
320  {
321  x*=s;
322  y*=s;
323  z*=s;
324 
325  return *this;
326  }
327 
328  /// Divides this vector by s. Assumes that s is not 0.
330  {
331  // Cannot multiply by the reciprocal, because that won't work with integers.
332  x/=s;
333  y/=s;
334  z/=s;
335 
336  return *this;
337  }
338 
339  //@}
340 };
341 
342 
343 /// Returns A scaled by r, that is, the scalar product (Skalarmultiplikation) of A and r.
344 template<class T> inline Vector3T<T> scale(const Vector3T<T>& A, const T r)
345 {
346  return Vector3T<T>(A.x*r, A.y*r, A.z*r);
347 }
348 
349 /// Returns A, non-uniformely scaled by R.
350 template<class T> inline Vector3T<T> scale(const Vector3T<T>& A, const Vector3T<T>& R)
351 {
352  return Vector3T<T>(A.x*R.x, A.y*R.y, A.z*R.z);
353 }
354 
355 /// Returns the dot product (Skalarprodukt) of A and B.
356 template<class T> inline T dot(const Vector3T<T>& A, const Vector3T<T>& B)
357 {
358  return A.x*B.x + A.y*B.y + A.z*B.z;
359 }
360 
361 /// Returns the cross product (Vektorprodukt) of A and B.
362 template<class T> inline Vector3T<T> cross(const Vector3T<T>& A, const Vector3T<T>& B)
363 {
364  return Vector3T<T>(A.y*B.z-A.z*B.y,
365  A.z*B.x-A.x*B.z,
366  A.x*B.y-A.y*B.x);
367 }
368 
369 /// Returns the length of A.
370 template<class T> inline T length(const Vector3T<T>& A)
371 {
372  return sqrt(dot(A, A));
373 }
374 
375 /// Returns the length of A. This is a specialized version of the generic length<T> function for floats.
376 template<> inline float length(const Vector3T<float>& A)
377 {
378  return sqrtf(dot(A, A));
379 }
380 
381 /// Returns the normalized (unit length) version of A.
382 /// @throws DivisionByZeroE if length(A)<=Epsilon.
383 template<class T> inline Vector3T<T> normalize(const Vector3T<T>& A, const T Epsilon)
384 {
385  const T Length=length(A);
386 
387  // I'm using <= here rather than only <, so that Epsilon==0 yields a meaningful test (e.g. if T==int).
388  if (Length<=Epsilon) throw DivisionByZeroE();
389 
390  return A/Length;
391 }
392 
393 /// Returns the normalized (unit length) version of A if length(A)>Epsilon, or the (0, 0, 0) vector otherwise.
394 template<class T> inline Vector3T<T> normalizeOr0(const Vector3T<T>& A, const T Epsilon=0)
395 {
396  const T Length=length(A);
397 
398  return (Length>Epsilon) ? scale(A, T(1.0)/Length) : Vector3T<T>(0, 0, 0);
399 }
400 
401 template<class T> inline std::string convertToString(const Vector3T<T>& A)
402 {
403  // From MSDN documentation: "digits10 returns the number of decimal digits that the type can represent without loss of precision."
404  // For floats, that's usually 6, for doubles, that's usually 15. However, we want to use the number of *significant* decimal digits here,
405  // see http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2006/n2005.pdf for details.
406  const int sigdigits=std::numeric_limits<T>::digits10 + 3;
407 
408  std::ostringstream out;
409 
410  out << std::setprecision(sigdigits) << "(" << A.x << ", " << A.y << ", " << A.z << ")";
411 
412  return out.str();
413 }
414 
415 
416 template<class T> inline std::ostream& operator << (std::ostream& os, const Vector3T<T>& A)
417 {
418  return os << "(" << A.x << ", " << A.y << ", " << A.z << ")";
419 }
420 
421 
422 /// Typedef for a Vector3T of floats.
423 typedef Vector3T<float> Vector3fT;
424 
425 /// Typedef for a Vector3T of doubles.
427 typedef Vector3T<double> VectorT; // For compatibility with the old VectorT class.
428 
429 /// Typedef for a Vector3T of ints.
430 typedef Vector3T<int> Vector3iT;
431 
432 #endif
Vector3T< T > & operator/=(const T s)
Divides this vector by s. Assumes that s is not 0.
Definition: Vector3.hpp:329
Vector3T< double > AsVectorOfDouble() const
Gets this Vector3T<T> as a Vector3T<double>, so that the cast is explicitly visible in user code...
Definition: Vector3.hpp:104
Vector3T< T > & operator+=(const Vector3T< T > &B)
Adds B to this vector.
Definition: Vector3.hpp:299
Vector3T< T > & operator*=(const T s)
Scales this vector by s.
Definition: Vector3.hpp:319
Vector3T< float > AsVectorOfFloat() const
Gets this Vector3T<T> as a Vector3T<float>, so that the cast is explicitly visible in user code...
Definition: Vector3.hpp:94
Vector3T< T > operator*(const T s) const
Returns a copy of this vector scaled by s, that is, the scalar product (Skalarmultiplikation) of this...
Definition: Vector3.hpp:265
Vector3T< T > GetRotX(const T Angle) const
Returns a copy of this vector rotated around the x-axis by Angle degrees.
Definition: Vector3.hpp:157
T y
The y-component of this vector.
Definition: Vector3.hpp:41
This class represents a polymorphic 3-dimensional vector.
Definition: Misc.hpp:11
Vector3T< int > AsVectorOfInt() const
Gets this Vector3T<T> as a Vector3T<int>, so that the cast is explicitly visible in user code...
Definition: Vector3.hpp:114
void CreateOrthoVectors(Vector3T< T > &Left, Vector3T< T > &Down) const
Returns two vectors that are orthogonal to this vector and to each other.
Definition: Vector3.hpp:193
Vector3T< T > operator-() const
The unary minus operator. B=-A is quasi identical with B=A.GetScaled(-1).
Definition: Vector3.hpp:257
Vector3T< T > cross(const Vector3T< T > &B) const
Returns the cross product (Vektorprodukt) of this vector and B.
Definition: Vector3.hpp:284
T GetLengthSqr() const
Returns the square of the length of this vector.
Definition: Vector3.hpp:131
Invalid operation (invalid use of method, etc.).
Definition: Errors.hpp:33
bool IsEqual(const Vector3T< T > &B, const T Epsilon) const
Returns whether this vector is equal to B within tolerance Epsilon, that is, whether it is geometrica...
Definition: Vector3.hpp:137
Vector3T(const C Values[])
This constructor initializes the components from an array of (at least) three Ts. ...
Definition: Vector3.hpp:53
Vector3T< T > operator/(const T s) const
Returns a copy of this vector divided by s, that is, the scalar product (Skalarmultiplikation) of thi...
Definition: Vector3.hpp:271
bool IsValid() const
Returns true if the vector is valid, that is, all components are non-NANs.
Definition: Vector3.hpp:58
Vector3T< T > & operator-=(const Vector3T< T > &B)
Subtracts B from this vector.
Definition: Vector3.hpp:309
Vector3T()
The default constructor. It initializes all components to zero.
Definition: Vector3.hpp:47
Vector3T< T > GetRotZ(const T Angle) const
Returns a copy of this vector rotated around the z-axis by Angle degrees.
Definition: Vector3.hpp:181
bool operator==(const Vector3T< T > &B) const
Returns whether this vector and B are truly (bit-wise) identical.
Definition: Vector3.hpp:226
Vector3T(T x_, T y_, T z_)
This constructor initializes the components from x_, y_ and z_ respectively.
Definition: Vector3.hpp:50
Vector3T< T > GetScaled(const Vector3T< T > &S) const
Returns a copy of this vector non-uniformely scaled by S.
Definition: Vector3.hpp:151
T dot(const Vector3T< T > &B) const
Returns the dot product (Skalarprodukt) of this vector and B.
Definition: Vector3.hpp:278
T z
The z-component of this vector.
Definition: Vector3.hpp:42
bool operator!=(const Vector3T< T > &B) const
Returns whether this vector and B are not equal (bit-wise).
Definition: Vector3.hpp:237
Vector3T< T > operator+(const Vector3T< T > &B) const
Returns the sum of this Vector3T<T> and B.
Definition: Vector3.hpp:245
T x
The x-component of this vector.
Definition: Vector3.hpp:40
Vector3T< T > GetRotY(const T Angle) const
Returns a copy of this vector rotated around the y-axis by Angle degrees.
Definition: Vector3.hpp:169
Vector3T< T > GetScaled(const T s) const
Returns a copy of this vector scaled by s, that is, the scalar product (Skalarmultiplikation) of this...
Definition: Vector3.hpp:145
Division by zero error.
Definition: Errors.hpp:24
T & operator[](unsigned int Index)
Component access by index number (0 to 2) rather than by name.
Definition: Vector3.hpp:66