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.
7 #ifndef CAFU_MATH_VECTOR3_HPP_INCLUDED
8 #define CAFU_MATH_VECTOR3_HPP_INCLUDED
19 /// This class represents a polymorphic 3-dimensional vector.
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.
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.
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.
46 /// The default constructor. It initializes all components to zero.
47 Vector3T() : x(0), y(0), z(0) { }
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_
) { }
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])) { }
57 /// Returns true if the vector is valid, that is, all components are non-NANs.
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
)
73 default: throw InvalidOperationE();
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
87 default: throw InvalidOperationE();
93 /// Gets this Vector3T<T> as a Vector3T<float>, so that the cast is explicitly visible in user code.
94 Vector3T
<float> AsVectorOfFloat() const
97 assert(typeid(T
)!=typeid(float));
100 return Vector3T
<float>(float(x
), float(y
), float(z
));
103 /// Gets this Vector3T<T> as a Vector3T<double>, so that the cast is explicitly visible in user code.
104 Vector3T
<double> AsVectorOfDouble() const
107 assert(typeid(T
)!=typeid(double));
110 return Vector3T
<double>(double(x
), double(y
), double(z
));
113 /// Gets this Vector3T<T> as a Vector3T<int>, so that the cast is explicitly visible in user code.
114 Vector3T
<int> AsVectorOfInt() const
116 return Vector3T
<int>(int(x
), int(y
), int(z
));
121 /// @name Group of const inspector methods. They are all const and thus do not modify this object.
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()); }
130 /// Returns the square of the length of this vector.
131 T
GetLengthSqr() const { return x
*x
+ y
*y
+ z
*z
; }
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.
137 bool IsEqual(const Vector3T
<T
>& B
, const T Epsilon
) const
139 return (*this-B
).GetLengthSqr() <= Epsilon
*Epsilon
;
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
147 return Vector3T
<T
>(x
*s
, y
*s
, z
*s
);
150 /// Returns a copy of this vector non-uniformely scaled by S.
151 Vector3T
<T
> GetScaled(const Vector3T
<T
>& S
) const
153 return Vector3T
<T
>(x
*S
.x
, y
*S
.y
, z
*S
.z
);
156 /// Returns a copy of this vector rotated around the x-axis by Angle degrees.
157 Vector3T
<T
> GetRotX(const T Angle
) const
159 const T RadAngle
=Angle
*T(3.14159265358979323846/180.0);
160 const T SinAngle
=sin(RadAngle
);
161 const T CosAngle
=cos(RadAngle
);
163 return Vector3T
<T
>(x
,
164 CosAngle
*y
-SinAngle
*z
,
165 SinAngle
*y
+CosAngle
*z
);
168 /// Returns a copy of this vector rotated around the y-axis by Angle degrees.
169 Vector3T
<T
> GetRotY(const T Angle
) const
171 const T RadAngle
=Angle
*T(3.14159265358979323846/180.0);
172 const T SinAngle
=sin(RadAngle
);
173 const T CosAngle
=cos(RadAngle
);
175 return Vector3T
<T
>(CosAngle
*x
+SinAngle
*z
,
177 -SinAngle
*x
+CosAngle
*z
);
180 /// Returns a copy of this vector rotated around the z-axis by Angle degrees.
181 Vector3T
<T
> GetRotZ(const T Angle
) const
183 const T RadAngle
=Angle
*T(3.14159265358979323846/180.0);
184 const T SinAngle
=sin(RadAngle
);
185 const T CosAngle
=cos(RadAngle
);
187 return Vector3T
<T
>(CosAngle
*x
-SinAngle
*y
,
188 SinAngle
*x
+CosAngle
*y
,
192 /// Returns two vectors that are orthogonal to this vector and to each other.
193 void CreateOrthoVectors(Vector3T
<T
>& Left
, Vector3T
<T
>& Down
) const
195 const T DistSqr
=x
*x
+y
*y
;
205 const T Dist
=sqrt(DistSqr
);
212 Down
=Left
.cross(*this);
219 /// @name Group of (constructive) binary operators that do not modify their operands.
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.
226 bool operator == (const Vector3T
<T
>& B
) const
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.
237 bool operator != (const Vector3T
<T
>& B
) const
244 /// Returns the sum of this Vector3T<T> and B.
245 Vector3T
<T
> operator + (const Vector3T
<T
>& B
) const
247 return Vector3T
<T
>(x
+B
.x
, y
+B
.y
, z
+B
.z
);
250 /// Returns the difference between this Vector3T<T> and B.
251 Vector3T
<T
> operator - (const Vector3T
<T
>& B
) const
253 return Vector3T
<T
>(x
-B
.x
, y
-B
.y
, z
-B
.z
);
256 /// The unary minus operator. B=-A is quasi identical with B=A.GetScaled(-1).
257 Vector3T
<T
> operator - () const
259 return Vector3T
<T
>(-x
, -y
, -z
);
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
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
273 // Cannot multiply by the reciprocal, because that won't work with integers.
274 return Vector3T
<T
>(x
/s
, y
/s
, z
/s
);
277 /// Returns the dot product (Skalarprodukt) of this vector and B.
278 T
dot(const Vector3T
<T
>& B
) const
280 return x
*B
.x
+ y
*B
.y
+ z
*B
.z
;
283 /// Returns the cross product (Vektorprodukt) of this vector and B.
284 Vector3T
<T
> cross(const Vector3T
<T
>& B
) const
286 return Vector3T
<T
>(y
*B
.z
- z
*B
.y
,
295 /// @name Group of operators that modify this vector.
298 /// Adds B to this vector.
299 Vector3T
<T
>& operator += (const Vector3T
<T
>& B
)
308 /// Subtracts B from this vector.
309 Vector3T
<T
>& operator -= (const Vector3T
<T
>& B
)
318 /// Scales this vector by s.
319 Vector3T
<T
>& operator *= (const T s
)
328 /// Divides this vector by s. Assumes that s is not 0.
329 Vector3T
<T
>& operator /= (const T s
)
331 // Cannot multiply by the reciprocal, because that won't work with integers.
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
)
346 return Vector3T
<T
>(A
.x
*r
, A
.y
*r
, A
.z
*r
);
349 /// Returns A, non-uniformely scaled by R.
350 template<class T
> inline Vector3T
<T
> scale(const Vector3T
<T
>& A
, const Vector3T
<T
>& R
)
352 return Vector3T
<T
>(A
.x
*R
.x
, A
.y
*R
.y
, A
.z
*R
.z
);
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
)
358 return A
.x
*B
.x
+ A
.y
*B
.y
+ A
.z
*B
.z
;
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
)
364 return Vector3T
<T
>(A
.y
*B
.z
-A
.z
*B
.y
,
369 /// Returns the length of A.
370 template<class T
> inline T
length(const Vector3T
<T
>& A
)
372 return sqrt(dot(A
, A
));
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
)
378 return sqrtf(dot(A
, A
));
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
)
385 const T Length
=length(A
);
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();
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)
396 const T Length
=length(A
);
398 return (Length
>Epsilon
) ? scale(A
, T(1.0)/Length
) : Vector3T
<T
>(0, 0, 0);
401 template<class T
> inline std::string
convertToString(const Vector3T
<T
>& A
)
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;
408 std::ostringstream out
;
410 out
<< std::setprecision(sigdigits
) << "(" << A
.x
<< ", " << A
.y
<< ", " << A
.z
<< ")";
416 template<class T
> inline std::ostream
& operator << (std::ostream
& os
, const Vector3T
<T
>& A
)
418 return os
<< "(" << A
.x
<< ", " << A
.y
<< ", " << A
.z
<< ")";
422 /// Typedef for a Vector3T of floats.
423 typedef Vector3T
<float> Vector3fT
;
425 /// Typedef for a Vector3T of doubles.
426 typedef Vector3T
<double> Vector3dT
;
427 typedef Vector3T
<double> VectorT
; // For compatibility with the old VectorT class.
429 /// Typedef for a Vector3T of ints.
430 typedef Vector3T
<int> Vector3iT
;