/src/ogre/OgreMain/include/OgreVector.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #ifndef __Vector_H__ |
29 | | #define __Vector_H__ |
30 | | |
31 | | |
32 | | #include "OgrePrerequisites.h" |
33 | | #include "OgreMath.h" |
34 | | #include "OgreQuaternion.h" |
35 | | |
36 | | namespace Ogre |
37 | | { |
38 | | |
39 | | /** \addtogroup Core |
40 | | * @{ |
41 | | */ |
42 | | /** \addtogroup Math |
43 | | * @{ |
44 | | */ |
45 | | /// helper class to implement legacy API. Notably x, y, z access |
46 | | template <int dims, typename T> struct VectorBase |
47 | | { |
48 | | VectorBase() {} |
49 | | constexpr VectorBase(T _x, T _y) |
50 | | { |
51 | | static_assert(dims > 1, "must have at least 2 dimensions"); |
52 | | data[0] = _x; data[1] = _y; |
53 | | } |
54 | | constexpr VectorBase(T _x, T _y, T _z) |
55 | 0 | { |
56 | 0 | static_assert(dims > 2, "must have at least 3 dimensions"); |
57 | 0 | data[0] = _x; data[1] = _y; data[2] = _z; |
58 | 0 | } |
59 | | constexpr VectorBase(T _x, T _y, T _z, T _w) |
60 | | { |
61 | | static_assert(dims > 3, "must have at least 4 dimensions"); |
62 | | data[0] = _x; data[1] = _y; data[2] = _z; data[3] = _w; |
63 | | } |
64 | | T data[dims]; |
65 | | T* ptr() { return data; } |
66 | 0 | const T* ptr() const { return data; } |
67 | | }; |
68 | | template <> struct _OgreExport VectorBase<2, Real> |
69 | | { |
70 | 0 | VectorBase() {} |
71 | 0 | constexpr VectorBase(Real _x, Real _y) : x(_x), y(_y) {} |
72 | | Real x, y; |
73 | 0 | Real* ptr() { return &x; } |
74 | 0 | const Real* ptr() const { return &x; } |
75 | | |
76 | | /** Returns a vector at a point half way between this and the passed |
77 | | in vector. |
78 | | */ |
79 | | Vector2 midPoint( const Vector2& vec ) const; |
80 | | |
81 | | /** Calculates the 2 dimensional cross-product of 2 vectors, which results |
82 | | in a single floating point value which is 2 times the area of the triangle. |
83 | | */ |
84 | | Real crossProduct( const VectorBase& rkVector ) const |
85 | 0 | { |
86 | 0 | return x * rkVector.y - y * rkVector.x; |
87 | 0 | } |
88 | | |
89 | | /** Generates a vector perpendicular to this vector (eg an 'up' vector). |
90 | | |
91 | | This method will return a vector which is perpendicular to this |
92 | | vector. There are an infinite number of possibilities but this |
93 | | method will guarantee to generate one of them. If you need more |
94 | | control you should use the Quaternion class. |
95 | | */ |
96 | | Vector2 perpendicular(void) const; |
97 | | |
98 | | /** Generates a new random vector which deviates from this vector by a |
99 | | given angle in a random direction. |
100 | | |
101 | | This method assumes that the random number generator has already |
102 | | been seeded appropriately. |
103 | | @param angle |
104 | | The angle at which to deviate in radians |
105 | | @return |
106 | | A random vector which deviates from this vector by angle. This |
107 | | vector will not be normalised, normalise it if you wish |
108 | | afterwards. |
109 | | */ |
110 | | Vector2 randomDeviant(Radian angle) const; |
111 | | |
112 | | /** Gets the oriented angle between 2 vectors. |
113 | | |
114 | | Vectors do not have to be unit-length but must represent directions. |
115 | | The angle is comprised between 0 and 2 PI. |
116 | | */ |
117 | | Radian angleTo(const Vector2& other) const; |
118 | | |
119 | | // special points |
120 | | static const Vector2 &ZERO; |
121 | | static const Vector2 &UNIT_X; |
122 | | static const Vector2 &UNIT_Y; |
123 | | static const Vector2 &NEGATIVE_UNIT_X; |
124 | | static const Vector2 &NEGATIVE_UNIT_Y; |
125 | | static const Vector2 &UNIT_SCALE; |
126 | | }; |
127 | | |
128 | | template <> struct _OgreExport VectorBase<3, Real> |
129 | | { |
130 | 8 | VectorBase() {} |
131 | 0 | constexpr VectorBase(Real _x, Real _y, Real _z) : x(_x), y(_y), z(_z) {} |
132 | | Real x, y, z; |
133 | 0 | Real* ptr() { return &x; } |
134 | 0 | const Real* ptr() const { return &x; } |
135 | | |
136 | | /** Calculates the cross-product of 2 vectors, i.e. the vector that |
137 | | lies perpendicular to them both. |
138 | | |
139 | | The cross-product is normally used to calculate the normal |
140 | | vector of a plane, by calculating the cross-product of 2 |
141 | | non-equivalent vectors which lie on the plane (e.g. 2 edges |
142 | | of a triangle). |
143 | | @param rkVector |
144 | | Vector which, together with this one, will be used to |
145 | | calculate the cross-product. |
146 | | @return |
147 | | A vector which is the result of the cross-product. This |
148 | | vector will <b>NOT</b> be normalised, to maximise efficiency |
149 | | - call Vector3::normalise on the result if you wish this to |
150 | | be done. As for which side the resultant vector will be on, the |
151 | | returned vector will be on the side from which the arc from 'this' |
152 | | to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z) |
153 | | = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X. |
154 | | This is because OGRE uses a right-handed coordinate system. |
155 | | @par |
156 | | For a clearer explanation, look a the left and the bottom edges |
157 | | of your monitor's screen. Assume that the first vector is the |
158 | | left edge and the second vector is the bottom edge, both of |
159 | | them starting from the lower-left corner of the screen. The |
160 | | resulting vector is going to be perpendicular to both of them |
161 | | and will go <i>inside</i> the screen, towards the cathode tube |
162 | | (assuming you're using a CRT monitor, of course). |
163 | | */ |
164 | | Vector3 crossProduct( const Vector3& rkVector ) const; |
165 | | |
166 | | /** Generates a vector perpendicular to this vector (eg an 'up' vector). |
167 | | |
168 | | This method will return a vector which is perpendicular to this |
169 | | vector. There are an infinite number of possibilities but this |
170 | | method will guarantee to generate one of them. If you need more |
171 | | control you should use the Quaternion class. |
172 | | */ |
173 | | Vector3 perpendicular(void) const; |
174 | | |
175 | | /** Calculates the absolute dot (scalar) product of this vector with another. |
176 | | |
177 | | This function work similar dotProduct, except it use absolute value |
178 | | of each component of the vector to computing. |
179 | | @param |
180 | | vec Vector with which to calculate the absolute dot product (together |
181 | | with this one). |
182 | | @return |
183 | | A Real representing the absolute dot product value. |
184 | | */ |
185 | | Real absDotProduct(const VectorBase& vec) const |
186 | 0 | { |
187 | 0 | return Math::Abs(x * vec.x) + Math::Abs(y * vec.y) + Math::Abs(z * vec.z); |
188 | 0 | } |
189 | | |
190 | | /** Returns a vector at a point half way between this and the passed |
191 | | in vector. |
192 | | */ |
193 | | Vector3 midPoint( const Vector3& vec ) const; |
194 | | |
195 | | /** Generates a new random vector which deviates from this vector by a |
196 | | given angle in a random direction. |
197 | | |
198 | | This method assumes that the random number generator has already |
199 | | been seeded appropriately. |
200 | | @param |
201 | | angle The angle at which to deviate |
202 | | @param |
203 | | up Any vector perpendicular to this one (which could generated |
204 | | by cross-product of this vector and any other non-colinear |
205 | | vector). If you choose not to provide this the function will |
206 | | derive one on it's own, however if you provide one yourself the |
207 | | function will be faster (this allows you to reuse up vectors if |
208 | | you call this method more than once) |
209 | | @return |
210 | | A random vector which deviates from this vector by angle. This |
211 | | vector will not be normalised, normalise it if you wish |
212 | | afterwards. |
213 | | */ |
214 | | Vector3 randomDeviant(const Radian& angle, const Vector3& up = ZERO) const; |
215 | | |
216 | | /** Gets the shortest arc quaternion to rotate this vector to the destination |
217 | | vector. |
218 | | |
219 | | If you call this with a dest vector that is close to the inverse |
220 | | of this vector, we will rotate 180 degrees around the 'fallbackAxis' |
221 | | (if specified, or a generated axis if not) since in this case |
222 | | ANY axis of rotation is valid. |
223 | | */ |
224 | | Quaternion getRotationTo(const Vector3& dest, const Vector3& fallbackAxis = ZERO) const; |
225 | | |
226 | | /** Returns whether this vector is within a positional tolerance |
227 | | of another vector, also take scale of the vectors into account. |
228 | | @param rhs The vector to compare with |
229 | | @param tolerance The amount (related to the scale of vectors) that distance |
230 | | of the vector may vary by and still be considered close |
231 | | */ |
232 | | bool positionCloses(const Vector3& rhs, Real tolerance = 1e-03f) const; |
233 | | |
234 | | /** Returns whether this vector is within a directional tolerance |
235 | | of another vector. |
236 | | @param rhs The vector to compare with |
237 | | @param tolerance The maximum angle by which the vectors may vary and |
238 | | still be considered equal |
239 | | @note Both vectors should be normalised. |
240 | | */ |
241 | | bool directionEquals(const Vector3& rhs, const Radian& tolerance) const; |
242 | | |
243 | | /// Extract the primary (dominant) axis from this direction vector |
244 | | const Vector3& primaryAxis() const; |
245 | | |
246 | | // special points |
247 | | static const Vector3 &ZERO; |
248 | | static const Vector3 &UNIT_X; |
249 | | static const Vector3 &UNIT_Y; |
250 | | static const Vector3 &UNIT_Z; |
251 | | static const Vector3 &NEGATIVE_UNIT_X; |
252 | | static const Vector3 &NEGATIVE_UNIT_Y; |
253 | | static const Vector3 &NEGATIVE_UNIT_Z; |
254 | | static const Vector3 &UNIT_SCALE; |
255 | | }; |
256 | | |
257 | | template <> struct _OgreExport VectorBase<4, Real> |
258 | | { |
259 | 0 | VectorBase() {} |
260 | 0 | constexpr VectorBase(Real _x, Real _y, Real _z, Real _w) : x(_x), y(_y), z(_z), w(_w) {} |
261 | | Real x, y, z, w; |
262 | 0 | Real* ptr() { return &x; } |
263 | 0 | const Real* ptr() const { return &x; } |
264 | | |
265 | | // special points |
266 | | static const Vector4 &ZERO; |
267 | | }; |
268 | | |
269 | | /** Standard N-dimensional vector. |
270 | | |
271 | | A direction in N-D space represented as distances along the |
272 | | orthogonal axes. Note that positions, directions and |
273 | | scaling factors can be represented by a vector, depending on how |
274 | | you interpret the values. |
275 | | */ |
276 | | template<int dims, typename T> |
277 | | class _OgreMaybeExport Vector : public VectorBase<dims, T> |
278 | | { |
279 | | public: |
280 | | using VectorBase<dims, T>::ptr; |
281 | | |
282 | | /** Default constructor. |
283 | | @note It does <b>NOT</b> initialize the vector for efficiency. |
284 | | */ |
285 | 8 | Vector() {} Ogre::Vector<3, float>::Vector() Line | Count | Source | 285 | 8 | Vector() {} |
Unexecuted instantiation: Ogre::Vector<2, float>::Vector() Unexecuted instantiation: Ogre::Vector<4, float>::Vector() |
286 | 0 | constexpr Vector(T _x, T _y) : VectorBase<dims, T>(_x, _y) {} |
287 | 0 | constexpr Vector(T _x, T _y, T _z) : VectorBase<dims, T>(_x, _y, _z) {} Unexecuted instantiation: Ogre::Vector<3, float>::Vector(float, float, float) Unexecuted instantiation: Ogre::Vector<3, int>::Vector(int, int, int) |
288 | 0 | constexpr Vector(T _x, T _y, T _z, T _w) : VectorBase<dims, T>(_x, _y, _z, _w) {} |
289 | | |
290 | | // use enable_if as function parameter for VC < 2017 compatibility |
291 | | template <int N = dims> |
292 | | explicit Vector(const typename std::enable_if<N == 4, Vector<3, T>>::type& rhs, T fW = 1.0f) : VectorBase<dims, T>(rhs[0], rhs[1], rhs[2], fW) {} |
293 | | |
294 | | template<typename U> |
295 | 0 | explicit Vector(const U* _ptr) { |
296 | 0 | for (int i = 0; i < dims; i++) |
297 | 0 | ptr()[i] = T(_ptr[i]); |
298 | 0 | } Unexecuted instantiation: Ogre::Vector<3, float>::Vector<float>(float const*) Unexecuted instantiation: Ogre::Vector<3, float>::Vector<int>(int const*) |
299 | | |
300 | | template<typename U> |
301 | | explicit Vector(const Vector<dims, U>& o) : Vector(o.ptr()) {} |
302 | | |
303 | | |
304 | | explicit Vector(T s) |
305 | 0 | { |
306 | 0 | for (int i = 0; i < dims; i++) |
307 | 0 | ptr()[i] = s; |
308 | 0 | } |
309 | | |
310 | | /** Swizzle-like narrowing operations |
311 | | */ |
312 | | Vector<3, T> xyz() const |
313 | 0 | { |
314 | 0 | static_assert(dims > 3, "just use assignment"); |
315 | 0 | return Vector<3, T>(ptr()); |
316 | 0 | } |
317 | | Vector<2, T> xy() const |
318 | | { |
319 | | static_assert(dims > 2, "just use assignment"); |
320 | | return Vector<2, T>(ptr()); |
321 | | } |
322 | | |
323 | | T operator[](size_t i) const |
324 | 0 | { |
325 | 0 | assert(i < dims); |
326 | 0 | return ptr()[i]; |
327 | 0 | } Unexecuted instantiation: Ogre::Vector<3, float>::operator[](unsigned long) const Unexecuted instantiation: Ogre::Vector<3, int>::operator[](unsigned long) const Unexecuted instantiation: Ogre::Vector<4, float>::operator[](unsigned long) const |
328 | | |
329 | | T& operator[](size_t i) |
330 | 0 | { |
331 | 0 | assert(i < dims); |
332 | 0 | return ptr()[i]; |
333 | 0 | } Unexecuted instantiation: Ogre::Vector<4, float>::operator[](unsigned long) Unexecuted instantiation: Ogre::Vector<2, float>::operator[](unsigned long) Unexecuted instantiation: Ogre::Vector<3, float>::operator[](unsigned long) |
334 | | |
335 | | bool operator==(const Vector& v) const |
336 | 0 | { |
337 | 0 | for (int i = 0; i < dims; i++) |
338 | 0 | if (ptr()[i] != v[i]) |
339 | 0 | return false; |
340 | 0 | return true; |
341 | 0 | } |
342 | | |
343 | | /** Returns whether this vector is within a positional tolerance |
344 | | of another vector. |
345 | | @param rhs The vector to compare with |
346 | | @param tolerance The amount that each element of the vector may vary by |
347 | | and still be considered equal |
348 | | */ |
349 | | bool positionEquals(const Vector& rhs, Real tolerance = 1e-03f) const |
350 | | { |
351 | | for (int i = 0; i < dims; i++) |
352 | | if (!Math::RealEqual(ptr()[i], rhs[i], tolerance)) |
353 | | return false; |
354 | | return true; |
355 | | } |
356 | | |
357 | 0 | bool operator!=(const Vector& v) const { return !(*this == v); } |
358 | | |
359 | | /** Returns true if the vector's scalar components are all greater |
360 | | that the ones of the vector it is compared against. |
361 | | */ |
362 | | bool operator<(const Vector& rhs) const |
363 | 0 | { |
364 | 0 | for (int i = 0; i < dims; i++) |
365 | 0 | if (!(ptr()[i] < rhs[i])) |
366 | 0 | return false; |
367 | 0 | return true; |
368 | 0 | } |
369 | | |
370 | | /** Returns true if the vector's scalar components are all smaller |
371 | | that the ones of the vector it is compared against. |
372 | | */ |
373 | | bool operator>(const Vector& rhs) const |
374 | 0 | { |
375 | 0 | for (int i = 0; i < dims; i++) |
376 | 0 | if (!(ptr()[i] > rhs[i])) |
377 | 0 | return false; |
378 | 0 | return true; |
379 | 0 | } |
380 | | |
381 | | /** Sets this vector's components to the minimum of its own and the |
382 | | ones of the passed in vector. |
383 | | |
384 | | 'Minimum' in this case means the combination of the lowest |
385 | | value of x, y and z from both vectors. Lowest is taken just |
386 | | numerically, not magnitude, so -1 < 0. |
387 | | */ |
388 | | void makeFloor(const Vector& cmp) |
389 | 0 | { |
390 | 0 | for (int i = 0; i < dims; i++) |
391 | 0 | if (cmp[i] < ptr()[i]) |
392 | 0 | ptr()[i] = cmp[i]; |
393 | 0 | } |
394 | | |
395 | | /** Sets this vector's components to the maximum of its own and the |
396 | | ones of the passed in vector. |
397 | | |
398 | | 'Maximum' in this case means the combination of the highest |
399 | | value of x, y and z from both vectors. Highest is taken just |
400 | | numerically, not magnitude, so 1 > -3. |
401 | | */ |
402 | | void makeCeil(const Vector& cmp) |
403 | 0 | { |
404 | 0 | for (int i = 0; i < dims; i++) |
405 | 0 | if (cmp[i] > ptr()[i]) |
406 | 0 | ptr()[i] = cmp[i]; |
407 | 0 | } |
408 | | |
409 | | /** Calculates the dot (scalar) product of this vector with another. |
410 | | |
411 | | The dot product can be used to calculate the angle between 2 |
412 | | vectors. If both are unit vectors, the dot product is the |
413 | | cosine of the angle; otherwise the dot product must be |
414 | | divided by the product of the lengths of both vectors to get |
415 | | the cosine of the angle. This result can further be used to |
416 | | calculate the distance of a point from a plane. |
417 | | @param |
418 | | vec Vector with which to calculate the dot product (together |
419 | | with this one). |
420 | | @return |
421 | | A float representing the dot product value. |
422 | | */ |
423 | | T dotProduct(const VectorBase<dims, T>& vec) const |
424 | 0 | { |
425 | 0 | T ret = 0; |
426 | 0 | for (int i = 0; i < dims; i++) |
427 | 0 | ret += ptr()[i] * vec.ptr()[i]; |
428 | 0 | return ret; |
429 | 0 | } Unexecuted instantiation: Ogre::Vector<2, float>::dotProduct(Ogre::VectorBase<2, float> const&) const Unexecuted instantiation: Ogre::Vector<3, float>::dotProduct(Ogre::VectorBase<3, float> const&) const |
430 | | |
431 | | /** Returns the square of the length(magnitude) of the vector. |
432 | | |
433 | | This method is for efficiency - calculating the actual |
434 | | length of a vector requires a square root, which is expensive |
435 | | in terms of the operations required. This method returns the |
436 | | square of the length of the vector, i.e. the same as the |
437 | | length but before the square root is taken. Use this if you |
438 | | want to find the longest / shortest vector without incurring |
439 | | the square root. |
440 | | */ |
441 | 0 | T squaredLength() const { return dotProduct(*this); } Unexecuted instantiation: Ogre::Vector<2, float>::squaredLength() const Unexecuted instantiation: Ogre::Vector<3, float>::squaredLength() const |
442 | | |
443 | | /** Returns true if this vector is zero length. */ |
444 | | bool isZeroLength() const |
445 | 0 | { |
446 | 0 | return squaredLength() < 1e-06 * 1e-06; |
447 | 0 | } |
448 | | |
449 | | /** Returns the length (magnitude) of the vector. |
450 | | @warning |
451 | | This operation requires a square root and is expensive in |
452 | | terms of CPU operations. If you don't need to know the exact |
453 | | length (e.g. for just comparing lengths) use squaredLength() |
454 | | instead. |
455 | | */ |
456 | 0 | Real length() const { return Math::Sqrt(squaredLength()); } Unexecuted instantiation: Ogre::Vector<2, float>::length() const Unexecuted instantiation: Ogre::Vector<3, float>::length() const |
457 | | |
458 | | /** Returns the distance to another vector. |
459 | | @warning |
460 | | This operation requires a square root and is expensive in |
461 | | terms of CPU operations. If you don't need to know the exact |
462 | | distance (e.g. for just comparing distances) use squaredDistance() |
463 | | instead. |
464 | | */ |
465 | | Real distance(const Vector& rhs) const |
466 | 0 | { |
467 | 0 | return (*this - rhs).length(); |
468 | 0 | } |
469 | | |
470 | | /** Returns the square of the distance to another vector. |
471 | | |
472 | | This method is for efficiency - calculating the actual |
473 | | distance to another vector requires a square root, which is |
474 | | expensive in terms of the operations required. This method |
475 | | returns the square of the distance to another vector, i.e. |
476 | | the same as the distance but before the square root is taken. |
477 | | Use this if you want to find the longest / shortest distance |
478 | | without incurring the square root. |
479 | | */ |
480 | | T squaredDistance(const Vector& rhs) const |
481 | 0 | { |
482 | 0 | return (*this - rhs).squaredLength(); |
483 | 0 | } |
484 | | |
485 | | /** Normalises the vector. |
486 | | |
487 | | This method normalises the vector such that it's |
488 | | length / magnitude is 1. The result is called a unit vector. |
489 | | @note |
490 | | This function will not crash for zero-sized vectors, but there |
491 | | will be no changes made to their components. |
492 | | @return The previous length of the vector. |
493 | | */ |
494 | | Real normalise() |
495 | 0 | { |
496 | 0 | Real fLength = length(); |
497 | | |
498 | | // Will also work for zero-sized vectors, but will change nothing |
499 | | // We're not using epsilons because we don't need to. |
500 | | // Read http://www.ogre3d.org/forums/viewtopic.php?f=4&t=61259 |
501 | 0 | if (fLength > Real(0.0f)) |
502 | 0 | { |
503 | 0 | Real fInvLength = 1.0f / fLength; |
504 | 0 | for (int i = 0; i < dims; i++) |
505 | 0 | ptr()[i] *= fInvLength; |
506 | 0 | } |
507 | |
|
508 | 0 | return fLength; |
509 | 0 | } |
510 | | |
511 | | /** As normalise, except that this vector is unaffected and the |
512 | | normalised vector is returned as a copy. */ |
513 | | Vector normalisedCopy() const |
514 | 0 | { |
515 | 0 | Vector ret = *this; |
516 | 0 | ret.normalise(); |
517 | 0 | return ret; |
518 | 0 | } |
519 | | |
520 | | #ifndef OGRE_FAST_MATH |
521 | | /// Check whether this vector contains valid values |
522 | | bool isNaN() const |
523 | | { |
524 | | for (int i = 0; i < dims; i++) |
525 | | if (Math::isNaN(ptr()[i])) |
526 | | return true; |
527 | | return false; |
528 | | } |
529 | | #endif |
530 | | |
531 | | /** Gets the angle between 2 vectors. |
532 | | |
533 | | Vectors do not have to be unit-length but must represent directions. |
534 | | */ |
535 | | Radian angleBetween(const Vector& dest) const |
536 | 0 | { |
537 | 0 | Real lenProduct = length() * dest.length(); |
538 | 0 |
|
539 | 0 | // Divide by zero check |
540 | 0 | if(lenProduct < 1e-6f) |
541 | 0 | lenProduct = 1e-6f; |
542 | 0 |
|
543 | 0 | Real f = dotProduct(dest) / lenProduct; |
544 | 0 |
|
545 | 0 | f = Math::Clamp(f, (Real)-1.0, (Real)1.0); |
546 | 0 | return Math::ACos(f); |
547 | 0 |
|
548 | 0 | } |
549 | | |
550 | | /** Calculates a reflection vector to the plane with the given normal . |
551 | | @note assumes 'this' is pointing AWAY FROM the plane, invert if it is not. |
552 | | */ |
553 | | Vector reflect(const Vector& normal) const { return *this - (2 * dotProduct(normal) * normal); } |
554 | | |
555 | | // Vector: arithmetic updates |
556 | | Vector& operator*=(Real s) |
557 | 0 | { |
558 | 0 | for (int i = 0; i < dims; i++) |
559 | 0 | ptr()[i] *= s; |
560 | 0 | return *this; |
561 | 0 | } |
562 | | |
563 | | Vector& operator/=(Real s) |
564 | 0 | { |
565 | 0 | assert( s != 0.0 ); // legacy assert |
566 | 0 | Real fInv = 1.0f/s; |
567 | 0 | for (int i = 0; i < dims; i++) |
568 | 0 | ptr()[i] *= fInv; |
569 | 0 | return *this; |
570 | 0 | } |
571 | | |
572 | | Vector& operator+=(Real s) |
573 | 0 | { |
574 | 0 | for (int i = 0; i < dims; i++) |
575 | 0 | ptr()[i] += s; |
576 | 0 | return *this; |
577 | 0 | } |
578 | | |
579 | | Vector& operator-=(Real s) |
580 | | { |
581 | | for (int i = 0; i < dims; i++) |
582 | | ptr()[i] -= s; |
583 | | return *this; |
584 | | } |
585 | | |
586 | | Vector& operator+=(const Vector& b) |
587 | 0 | { |
588 | 0 | for (int i = 0; i < dims; i++) |
589 | 0 | ptr()[i] += b[i]; |
590 | 0 | return *this; |
591 | 0 | } |
592 | | |
593 | | Vector& operator-=(const Vector& b) |
594 | 0 | { |
595 | 0 | for (int i = 0; i < dims; i++) |
596 | 0 | ptr()[i] -= b[i]; |
597 | 0 | return *this; |
598 | 0 | } |
599 | | |
600 | | Vector& operator*=(const Vector& b) |
601 | 0 | { |
602 | 0 | for (int i = 0; i < dims; i++) |
603 | 0 | ptr()[i] *= b[i]; |
604 | 0 | return *this; |
605 | 0 | } |
606 | | |
607 | | Vector& operator/=(const Vector& b) |
608 | | { |
609 | | for (int i = 0; i < dims; i++) |
610 | | ptr()[i] /= b[i]; |
611 | | return *this; |
612 | | } |
613 | | |
614 | | // Scalar * Vector |
615 | | friend Vector operator*(Real s, Vector v) |
616 | 0 | { |
617 | 0 | v *= s; |
618 | 0 | return v; |
619 | 0 | } |
620 | | |
621 | | friend Vector operator+(Real s, Vector v) |
622 | | { |
623 | | v += s; |
624 | | return v; |
625 | | } |
626 | | |
627 | | friend Vector operator-(Real s, const Vector& v) |
628 | | { |
629 | | Vector ret; |
630 | | for (int i = 0; i < dims; i++) |
631 | | ret[i] = s - v[i]; |
632 | | return ret; |
633 | | } |
634 | | |
635 | | friend Vector operator/(Real s, const Vector& v) |
636 | | { |
637 | | Vector ret; |
638 | | for (int i = 0; i < dims; i++) |
639 | | ret[i] = s / v[i]; |
640 | | return ret; |
641 | | } |
642 | | |
643 | | // Vector * Scalar |
644 | | Vector operator-() const |
645 | 0 | { |
646 | 0 | return -1 * *this; |
647 | 0 | } |
648 | | |
649 | | const Vector& operator+() const |
650 | | { |
651 | | return *this; |
652 | | } |
653 | | |
654 | | Vector operator*(Real s) const |
655 | 0 | { |
656 | 0 | return s * *this; |
657 | 0 | } |
658 | | |
659 | | Vector operator/(Real s) const |
660 | 0 | { |
661 | 0 | assert( s != 0.0 ); // legacy assert |
662 | 0 | Real fInv = 1.0f / s; |
663 | 0 | return fInv * *this; |
664 | 0 | } |
665 | | |
666 | | Vector operator-(Real s) const |
667 | | { |
668 | | return -s + *this; |
669 | | } |
670 | | |
671 | | Vector operator+(Real s) const |
672 | | { |
673 | | return s + *this; |
674 | | } |
675 | | |
676 | | // Vector * Vector |
677 | | Vector operator+(const Vector& b) const |
678 | 0 | { |
679 | 0 | Vector ret = *this; |
680 | 0 | ret += b; |
681 | 0 | return ret; |
682 | 0 | } |
683 | | |
684 | | Vector operator-(const Vector& b) const |
685 | 0 | { |
686 | 0 | Vector ret = *this; |
687 | 0 | ret -= b; |
688 | 0 | return ret; |
689 | 0 | } |
690 | | |
691 | | Vector operator*(const Vector& b) const |
692 | 0 | { |
693 | 0 | Vector ret = *this; |
694 | 0 | ret *= b; |
695 | 0 | return ret; |
696 | 0 | } |
697 | | |
698 | | Vector operator/(const Vector& b) const |
699 | | { |
700 | | Vector ret = *this; |
701 | | ret /= b; |
702 | | return ret; |
703 | | } |
704 | | |
705 | | friend std::ostream& operator<<(std::ostream& o, const Vector& v) |
706 | 0 | { |
707 | 0 | o << "Vector" << dims << "("; |
708 | 0 | for (int i = 0; i < dims; i++) { |
709 | 0 | o << v[i]; |
710 | 0 | if(i != dims - 1) o << ", "; |
711 | 0 | } |
712 | 0 | o << ")"; |
713 | 0 | return o; |
714 | 0 | } |
715 | | }; |
716 | | |
717 | | inline Vector2 VectorBase<2, Real>::midPoint( const Vector2& vec ) const |
718 | 0 | { |
719 | 0 | return Vector2( |
720 | 0 | ( x + vec.x ) * 0.5f, |
721 | 0 | ( y + vec.y ) * 0.5f ); |
722 | 0 | } |
723 | | |
724 | | inline Vector2 VectorBase<2, Real>::randomDeviant(Radian angle) const |
725 | 0 | { |
726 | 0 | angle *= Math::RangeRandom(-1, 1); |
727 | 0 | Real cosa = Math::Cos(angle); |
728 | 0 | Real sina = Math::Sin(angle); |
729 | 0 | return Vector2(cosa * x - sina * y, |
730 | 0 | sina * x + cosa * y); |
731 | 0 | } |
732 | | |
733 | | inline Radian VectorBase<2, Real>::angleTo(const Vector2& other) const |
734 | 0 | { |
735 | 0 | Radian angle = ((const Vector2*)this)->angleBetween(other); |
736 | 0 |
|
737 | 0 | if (crossProduct(other)<0) |
738 | 0 | angle = Radian(Math::TWO_PI) - angle; |
739 | 0 |
|
740 | 0 | return angle; |
741 | 0 | } |
742 | | |
743 | | inline Vector2 VectorBase<2, Real>::perpendicular(void) const |
744 | 0 | { |
745 | 0 | return Vector2(-y, x); |
746 | 0 | } |
747 | | |
748 | | inline Vector3 VectorBase<3, Real>::perpendicular() const |
749 | 0 | { |
750 | 0 | // From Sam Hocevar's article "On picking an orthogonal |
751 | 0 | // vector (and combing coconuts)" |
752 | 0 | Vector3 perp = Math::Abs(x) > Math::Abs(z) |
753 | 0 | ? Vector3(-y, x, 0.0) : Vector3(0.0, -z, y); |
754 | 0 | return perp.normalisedCopy(); |
755 | 0 | } |
756 | | |
757 | | inline Vector3 VectorBase<3, Real>::crossProduct( const Vector3& rkVector ) const |
758 | 0 | { |
759 | 0 | return Vector3( |
760 | 0 | y * rkVector.z - z * rkVector.y, |
761 | 0 | z * rkVector.x - x * rkVector.z, |
762 | 0 | x * rkVector.y - y * rkVector.x); |
763 | 0 | } |
764 | | |
765 | | inline Vector3 VectorBase<3, Real>::midPoint( const Vector3& vec ) const |
766 | 0 | { |
767 | 0 | return Vector3( |
768 | 0 | ( x + vec.x ) * 0.5f, |
769 | 0 | ( y + vec.y ) * 0.5f, |
770 | 0 | ( z + vec.z ) * 0.5f ); |
771 | 0 | } |
772 | | |
773 | | inline Vector3 VectorBase<3, Real>::randomDeviant(const Radian& angle, const Vector3& up) const |
774 | 0 | { |
775 | 0 | Vector3 newUp; |
776 | 0 |
|
777 | 0 | if (up == ZERO) |
778 | 0 | { |
779 | 0 | // Generate an up vector |
780 | 0 | newUp = ((const Vector3*)this)->perpendicular(); |
781 | 0 | } |
782 | 0 | else |
783 | 0 | { |
784 | 0 | newUp = up; |
785 | 0 | } |
786 | 0 |
|
787 | 0 | // Rotate up vector by random amount around this |
788 | 0 | Quaternion q; |
789 | 0 | q.FromAngleAxis( Radian(Math::UnitRandom() * Math::TWO_PI), (const Vector3&)*this ); |
790 | 0 | newUp = q * newUp; |
791 | 0 |
|
792 | 0 | // Finally rotate this by given angle around randomised up |
793 | 0 | q.FromAngleAxis( angle, newUp ); |
794 | 0 | return q * (const Vector3&)(*this); |
795 | 0 | } |
796 | | |
797 | | inline Quaternion VectorBase<3, Real>::getRotationTo(const Vector3& dest, const Vector3& fallbackAxis) const |
798 | 0 | { |
799 | 0 | // From Sam Hocevar's article "Quaternion from two vectors: |
800 | 0 | // the final version" |
801 | 0 | Real a = Math::Sqrt(((const Vector3*)this)->squaredLength() * dest.squaredLength()); |
802 | 0 | Real b = a + dest.dotProduct(*this); |
803 | 0 |
|
804 | 0 | if (Math::RealEqual(b, 2 * a) || a == 0) |
805 | 0 | return Quaternion::IDENTITY; |
806 | 0 |
|
807 | 0 | Vector3 axis; |
808 | 0 |
|
809 | 0 | if (b < (Real)1e-06 * a) |
810 | 0 | { |
811 | 0 | b = (Real)0.0; |
812 | 0 | axis = fallbackAxis != Vector3::ZERO ? fallbackAxis |
813 | 0 | : Math::Abs(x) > Math::Abs(z) ? Vector3(-y, x, (Real)0.0) |
814 | 0 | : Vector3((Real)0.0, -z, y); |
815 | 0 | } |
816 | 0 | else |
817 | 0 | { |
818 | 0 | axis = this->crossProduct(dest); |
819 | 0 | } |
820 | 0 |
|
821 | 0 | Quaternion q(b, axis.x, axis.y, axis.z); |
822 | 0 | q.normalise(); |
823 | 0 | return q; |
824 | 0 | } |
825 | | |
826 | | inline bool VectorBase<3, Real>::positionCloses(const Vector3& rhs, Real tolerance) const |
827 | 0 | { |
828 | 0 | return ((const Vector3*)this)->squaredDistance(rhs) <= |
829 | 0 | (((const Vector3*)this)->squaredLength() + rhs.squaredLength()) * tolerance; |
830 | 0 | } |
831 | | |
832 | | inline bool VectorBase<3, Real>::directionEquals(const Vector3& rhs, const Radian& tolerance) const |
833 | 0 | { |
834 | 0 | Real dot = rhs.dotProduct(*this); |
835 | 0 | Radian angle = Math::ACos(dot); |
836 | 0 |
|
837 | 0 | return Math::Abs(angle.valueRadians()) <= tolerance.valueRadians(); |
838 | 0 | } |
839 | | |
840 | | inline const Vector3& VectorBase<3, Real>::primaryAxis() const |
841 | 0 | { |
842 | 0 | Real absx = Math::Abs(x); |
843 | 0 | Real absy = Math::Abs(y); |
844 | 0 | Real absz = Math::Abs(z); |
845 | 0 | if (absx > absy) |
846 | 0 | if (absx > absz) |
847 | 0 | return x > 0 ? UNIT_X : NEGATIVE_UNIT_X; |
848 | 0 | else |
849 | 0 | return z > 0 ? UNIT_Z : NEGATIVE_UNIT_Z; |
850 | 0 | else // absx <= absy |
851 | 0 | if (absy > absz) |
852 | 0 | return y > 0 ? UNIT_Y : NEGATIVE_UNIT_Y; |
853 | 0 | else |
854 | 0 | return z > 0 ? UNIT_Z : NEGATIVE_UNIT_Z; |
855 | 0 | } |
856 | | |
857 | | // Math functions |
858 | | inline Vector3 Math::calculateBasicFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3) |
859 | 0 | { |
860 | 0 | Vector3 normal = (v2 - v1).crossProduct(v3 - v1); |
861 | 0 | normal.normalise(); |
862 | 0 | return normal; |
863 | 0 | } |
864 | | inline Vector4 Math::calculateFaceNormal(const Vector3& v1, const Vector3& v2, const Vector3& v3) |
865 | 0 | { |
866 | 0 | Vector3 normal = calculateBasicFaceNormal(v1, v2, v3); |
867 | 0 | // Now set up the w (distance of tri from origin |
868 | 0 | return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1))); |
869 | 0 | } |
870 | | inline Vector3 Math::calculateBasicFaceNormalWithoutNormalize( |
871 | | const Vector3& v1, const Vector3& v2, const Vector3& v3) |
872 | 0 | { |
873 | 0 | return (v2 - v1).crossProduct(v3 - v1); |
874 | 0 | } |
875 | | |
876 | | inline Vector4 Math::calculateFaceNormalWithoutNormalize(const Vector3& v1, |
877 | | const Vector3& v2, |
878 | | const Vector3& v3) |
879 | 0 | { |
880 | 0 | Vector3 normal = calculateBasicFaceNormalWithoutNormalize(v1, v2, v3); |
881 | | // Now set up the w (distance of tri from origin) |
882 | 0 | return Vector4(normal.x, normal.y, normal.z, -(normal.dotProduct(v1))); |
883 | 0 | } |
884 | | /** @} */ |
885 | | /** @} */ |
886 | | |
887 | | } |
888 | | #endif |