Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: sandbox_light/src/external/ogremath/OgreVector3.h @ 6514

Last change on this file since 6514 was 5789, checked in by rgrieder, 15 years ago

Stripped sandbox further down to get a light version that excludes almost all core features.
Also, the Ogre dependency has been removed and a little ogremath library been added.

  • Property svn:eol-style set to native
File size: 24.7 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#ifndef __Vector3_H__
30#define __Vector3_H__
31
32#include "OgrePrerequisites.h"
33#include "OgreMath.h"
34#include "OgreQuaternion.h"
35#include <ostream>
36
37namespace Ogre
38{
39
40    /** Standard 3-dimensional vector.
41        @remarks
42            A direction in 3D space represented as distances along the 3
43            orthogonal axes (x, y, z). Note that positions, directions and
44            scaling factors can be represented by a vector, depending on how
45            you interpret the values.
46    */
47    class _OgreExport Vector3
48    {
49    public:
50                Real x, y, z;
51
52    public:
53        inline Vector3()
54        {
55        }
56
57        inline Vector3( const Real fX, const Real fY, const Real fZ )
58            : x( fX ), y( fY ), z( fZ )
59        {
60        }
61
62        inline explicit Vector3( const Real afCoordinate[3] )
63            : x( afCoordinate[0] ),
64              y( afCoordinate[1] ),
65              z( afCoordinate[2] )
66        {
67        }
68
69        inline explicit Vector3( const int afCoordinate[3] )
70        {
71            x = (Real)afCoordinate[0];
72            y = (Real)afCoordinate[1];
73            z = (Real)afCoordinate[2];
74        }
75
76        inline explicit Vector3( Real* const r )
77            : x( r[0] ), y( r[1] ), z( r[2] )
78        {
79        }
80
81        inline explicit Vector3( const Real scaler )
82            : x( scaler )
83            , y( scaler )
84            , z( scaler )
85        {
86        }
87
88
89                inline Real operator [] ( const size_t i ) const
90        {
91            assert( i < 3 );
92
93            return *(&x+i);
94        }
95
96                inline Real& operator [] ( const size_t i )
97        {
98            assert( i < 3 );
99
100            return *(&x+i);
101        }
102                /// Pointer accessor for direct copying
103                inline Real* ptr()
104                {
105                        return &x;
106                }
107                /// Pointer accessor for direct copying
108                inline const Real* ptr() const
109                {
110                        return &x;
111                }
112
113        /** Assigns the value of the other vector.
114            @param
115                rkVector The other vector
116        */
117        inline Vector3& operator = ( const Vector3& rkVector )
118        {
119            x = rkVector.x;
120            y = rkVector.y;
121            z = rkVector.z;
122
123            return *this;
124        }
125
126        inline Vector3& operator = ( const Real fScaler )
127        {
128            x = fScaler;
129            y = fScaler;
130            z = fScaler;
131
132            return *this;
133        }
134
135        inline bool operator == ( const Vector3& rkVector ) const
136        {
137            return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
138        }
139
140        inline bool operator != ( const Vector3& rkVector ) const
141        {
142            return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
143        }
144
145        // arithmetic operations
146        inline Vector3 operator + ( const Vector3& rkVector ) const
147        {
148            return Vector3(
149                x + rkVector.x,
150                y + rkVector.y,
151                z + rkVector.z);
152        }
153
154        inline Vector3 operator - ( const Vector3& rkVector ) const
155        {
156            return Vector3(
157                x - rkVector.x,
158                y - rkVector.y,
159                z - rkVector.z);
160        }
161
162        inline Vector3 operator * ( const Real fScalar ) const
163        {
164            return Vector3(
165                x * fScalar,
166                y * fScalar,
167                z * fScalar);
168        }
169
170        inline Vector3 operator * ( const Vector3& rhs) const
171        {
172            return Vector3(
173                x * rhs.x,
174                y * rhs.y,
175                z * rhs.z);
176        }
177
178        inline Vector3 operator / ( const Real fScalar ) const
179        {
180            assert( fScalar != 0.0 );
181
182            Real fInv = 1.0 / fScalar;
183
184            return Vector3(
185                x * fInv,
186                y * fInv,
187                z * fInv);
188        }
189
190        inline Vector3 operator / ( const Vector3& rhs) const
191        {
192            return Vector3(
193                x / rhs.x,
194                y / rhs.y,
195                z / rhs.z);
196        }
197
198        inline const Vector3& operator + () const
199        {
200            return *this;
201        }
202
203        inline Vector3 operator - () const
204        {
205            return Vector3(-x, -y, -z);
206        }
207
208        // overloaded operators to help Vector3
209        inline friend Vector3 operator * ( const Real fScalar, const Vector3& rkVector )
210        {
211            return Vector3(
212                fScalar * rkVector.x,
213                fScalar * rkVector.y,
214                fScalar * rkVector.z);
215        }
216
217        inline friend Vector3 operator / ( const Real fScalar, const Vector3& rkVector )
218        {
219            return Vector3(
220                fScalar / rkVector.x,
221                fScalar / rkVector.y,
222                fScalar / rkVector.z);
223        }
224
225        inline friend Vector3 operator + (const Vector3& lhs, const Real rhs)
226        {
227            return Vector3(
228                lhs.x + rhs,
229                lhs.y + rhs,
230                lhs.z + rhs);
231        }
232
233        inline friend Vector3 operator + (const Real lhs, const Vector3& rhs)
234        {
235            return Vector3(
236                lhs + rhs.x,
237                lhs + rhs.y,
238                lhs + rhs.z);
239        }
240
241        inline friend Vector3 operator - (const Vector3& lhs, const Real rhs)
242        {
243            return Vector3(
244                lhs.x - rhs,
245                lhs.y - rhs,
246                lhs.z - rhs);
247        }
248
249        inline friend Vector3 operator - (const Real lhs, const Vector3& rhs)
250        {
251            return Vector3(
252                lhs - rhs.x,
253                lhs - rhs.y,
254                lhs - rhs.z);
255        }
256
257        // arithmetic updates
258        inline Vector3& operator += ( const Vector3& rkVector )
259        {
260            x += rkVector.x;
261            y += rkVector.y;
262            z += rkVector.z;
263
264            return *this;
265        }
266
267        inline Vector3& operator += ( const Real fScalar )
268        {
269            x += fScalar;
270            y += fScalar;
271            z += fScalar;
272            return *this;
273        }
274
275        inline Vector3& operator -= ( const Vector3& rkVector )
276        {
277            x -= rkVector.x;
278            y -= rkVector.y;
279            z -= rkVector.z;
280
281            return *this;
282        }
283
284        inline Vector3& operator -= ( const Real fScalar )
285        {
286            x -= fScalar;
287            y -= fScalar;
288            z -= fScalar;
289            return *this;
290        }
291
292        inline Vector3& operator *= ( const Real fScalar )
293        {
294            x *= fScalar;
295            y *= fScalar;
296            z *= fScalar;
297            return *this;
298        }
299
300        inline Vector3& operator *= ( const Vector3& rkVector )
301        {
302            x *= rkVector.x;
303            y *= rkVector.y;
304            z *= rkVector.z;
305
306            return *this;
307        }
308
309        inline Vector3& operator /= ( const Real fScalar )
310        {
311            assert( fScalar != 0.0 );
312
313            Real fInv = 1.0 / fScalar;
314
315            x *= fInv;
316            y *= fInv;
317            z *= fInv;
318
319            return *this;
320        }
321
322        inline Vector3& operator /= ( const Vector3& rkVector )
323        {
324            x /= rkVector.x;
325            y /= rkVector.y;
326            z /= rkVector.z;
327
328            return *this;
329        }
330
331
332        /** Returns the length (magnitude) of the vector.
333            @warning
334                This operation requires a square root and is expensive in
335                terms of CPU operations. If you don't need to know the exact
336                length (e.g. for just comparing lengths) use squaredLength()
337                instead.
338        */
339        inline Real length () const
340        {
341            return Math::Sqrt( x * x + y * y + z * z );
342        }
343
344        /** Returns the square of the length(magnitude) of the vector.
345            @remarks
346                This  method is for efficiency - calculating the actual
347                length of a vector requires a square root, which is expensive
348                in terms of the operations required. This method returns the
349                square of the length of the vector, i.e. the same as the
350                length but before the square root is taken. Use this if you
351                want to find the longest / shortest vector without incurring
352                the square root.
353        */
354        inline Real squaredLength () const
355        {
356            return x * x + y * y + z * z;
357        }
358
359        /** Returns the distance to another vector.
360            @warning
361                This operation requires a square root and is expensive in
362                terms of CPU operations. If you don't need to know the exact
363                distance (e.g. for just comparing distances) use squaredDistance()
364                instead.
365        */
366        inline Real distance(const Vector3& rhs) const
367        {
368            return (*this - rhs).length();
369        }
370
371        /** Returns the square of the distance to another vector.
372            @remarks
373                This method is for efficiency - calculating the actual
374                distance to another vector requires a square root, which is
375                expensive in terms of the operations required. This method
376                returns the square of the distance to another vector, i.e.
377                the same as the distance but before the square root is taken.
378                Use this if you want to find the longest / shortest distance
379                without incurring the square root.
380        */
381        inline Real squaredDistance(const Vector3& rhs) const
382        {
383            return (*this - rhs).squaredLength();
384        }
385
386        /** Calculates the dot (scalar) product of this vector with another.
387            @remarks
388                The dot product can be used to calculate the angle between 2
389                vectors. If both are unit vectors, the dot product is the
390                cosine of the angle; otherwise the dot product must be
391                divided by the product of the lengths of both vectors to get
392                the cosine of the angle. This result can further be used to
393                calculate the distance of a point from a plane.
394            @param
395                vec Vector with which to calculate the dot product (together
396                with this one).
397            @returns
398                A float representing the dot product value.
399        */
400        inline Real dotProduct(const Vector3& vec) const
401        {
402            return x * vec.x + y * vec.y + z * vec.z;
403        }
404
405        /** Calculates the absolute dot (scalar) product of this vector with another.
406            @remarks
407                This function work similar dotProduct, except it use absolute value
408                of each component of the vector to computing.
409            @param
410                vec Vector with which to calculate the absolute dot product (together
411                with this one).
412            @returns
413                A Real representing the absolute dot product value.
414        */
415        inline Real absDotProduct(const Vector3& vec) const
416        {
417            return Math::Abs(x * vec.x) + Math::Abs(y * vec.y) + Math::Abs(z * vec.z);
418        }
419
420        /** Normalises the vector.
421            @remarks
422                This method normalises the vector such that it's
423                length / magnitude is 1. The result is called a unit vector.
424            @note
425                This function will not crash for zero-sized vectors, but there
426                will be no changes made to their components.
427            @returns The previous length of the vector.
428        */
429        inline Real normalise()
430        {
431            Real fLength = Math::Sqrt( x * x + y * y + z * z );
432
433            // Will also work for zero-sized vectors, but will change nothing
434            if ( fLength > 1e-08 )
435            {
436                Real fInvLength = 1.0 / fLength;
437                x *= fInvLength;
438                y *= fInvLength;
439                z *= fInvLength;
440            }
441
442            return fLength;
443        }
444
445        /** Calculates the cross-product of 2 vectors, i.e. the vector that
446            lies perpendicular to them both.
447            @remarks
448                The cross-product is normally used to calculate the normal
449                vector of a plane, by calculating the cross-product of 2
450                non-equivalent vectors which lie on the plane (e.g. 2 edges
451                of a triangle).
452            @param
453                vec Vector which, together with this one, will be used to
454                calculate the cross-product.
455            @returns
456                A vector which is the result of the cross-product. This
457                vector will <b>NOT</b> be normalised, to maximise efficiency
458                - call Vector3::normalise on the result if you wish this to
459                be done. As for which side the resultant vector will be on, the
460                returned vector will be on the side from which the arc from 'this'
461                to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z)
462                = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X.
463                                This is because OGRE uses a right-handed coordinate system.
464            @par
465                For a clearer explanation, look a the left and the bottom edges
466                of your monitor's screen. Assume that the first vector is the
467                left edge and the second vector is the bottom edge, both of
468                them starting from the lower-left corner of the screen. The
469                resulting vector is going to be perpendicular to both of them
470                and will go <i>inside</i> the screen, towards the cathode tube
471                (assuming you're using a CRT monitor, of course).
472        */
473        inline Vector3 crossProduct( const Vector3& rkVector ) const
474        {
475            return Vector3(
476                y * rkVector.z - z * rkVector.y,
477                z * rkVector.x - x * rkVector.z,
478                x * rkVector.y - y * rkVector.x);
479        }
480
481        /** Returns a vector at a point half way between this and the passed
482            in vector.
483        */
484        inline Vector3 midPoint( const Vector3& vec ) const
485        {
486            return Vector3(
487                ( x + vec.x ) * 0.5,
488                ( y + vec.y ) * 0.5,
489                ( z + vec.z ) * 0.5 );
490        }
491
492        /** Returns true if the vector's scalar components are all greater
493            that the ones of the vector it is compared against.
494        */
495        inline bool operator < ( const Vector3& rhs ) const
496        {
497            if( x < rhs.x && y < rhs.y && z < rhs.z )
498                return true;
499            return false;
500        }
501
502        /** Returns true if the vector's scalar components are all smaller
503            that the ones of the vector it is compared against.
504        */
505        inline bool operator > ( const Vector3& rhs ) const
506        {
507            if( x > rhs.x && y > rhs.y && z > rhs.z )
508                return true;
509            return false;
510        }
511
512        /** Sets this vector's components to the minimum of its own and the
513            ones of the passed in vector.
514            @remarks
515                'Minimum' in this case means the combination of the lowest
516                value of x, y and z from both vectors. Lowest is taken just
517                numerically, not magnitude, so -1 < 0.
518        */
519        inline void makeFloor( const Vector3& cmp )
520        {
521            if( cmp.x < x ) x = cmp.x;
522            if( cmp.y < y ) y = cmp.y;
523            if( cmp.z < z ) z = cmp.z;
524        }
525
526        /** Sets this vector's components to the maximum of its own and the
527            ones of the passed in vector.
528            @remarks
529                'Maximum' in this case means the combination of the highest
530                value of x, y and z from both vectors. Highest is taken just
531                numerically, not magnitude, so 1 > -3.
532        */
533        inline void makeCeil( const Vector3& cmp )
534        {
535            if( cmp.x > x ) x = cmp.x;
536            if( cmp.y > y ) y = cmp.y;
537            if( cmp.z > z ) z = cmp.z;
538        }
539
540        /** Generates a vector perpendicular to this vector (eg an 'up' vector).
541            @remarks
542                This method will return a vector which is perpendicular to this
543                vector. There are an infinite number of possibilities but this
544                method will guarantee to generate one of them. If you need more
545                control you should use the Quaternion class.
546        */
547        inline Vector3 perpendicular(void) const
548        {
549            static const Real fSquareZero = 1e-06 * 1e-06;
550
551            Vector3 perp = this->crossProduct( Vector3::UNIT_X );
552
553            // Check length
554            if( perp.squaredLength() < fSquareZero )
555            {
556                /* This vector is the Y axis multiplied by a scalar, so we have
557                   to use another axis.
558                */
559                perp = this->crossProduct( Vector3::UNIT_Y );
560            }
561                        perp.normalise();
562
563            return perp;
564        }
565        /** Generates a new random vector which deviates from this vector by a
566            given angle in a random direction.
567            @remarks
568                This method assumes that the random number generator has already
569                been seeded appropriately.
570            @param
571                angle The angle at which to deviate
572            @param
573                up Any vector perpendicular to this one (which could generated
574                by cross-product of this vector and any other non-colinear
575                vector). If you choose not to provide this the function will
576                derive one on it's own, however if you provide one yourself the
577                function will be faster (this allows you to reuse up vectors if
578                you call this method more than once)
579            @returns
580                A random vector which deviates from this vector by angle. This
581                vector will not be normalised, normalise it if you wish
582                afterwards.
583        */
584        inline Vector3 randomDeviant(
585            const Radian& angle,
586            const Vector3& up = Vector3::ZERO ) const
587        {
588            Vector3 newUp;
589
590            if (up == Vector3::ZERO)
591            {
592                // Generate an up vector
593                newUp = this->perpendicular();
594            }
595            else
596            {
597                newUp = up;
598            }
599
600            // Rotate up vector by random amount around this
601            Quaternion q;
602            q.FromAngleAxis( Radian(Math::UnitRandom() * Math::TWO_PI), *this );
603            newUp = q * newUp;
604
605            // Finally rotate this by given angle around randomised up
606            q.FromAngleAxis( angle, newUp );
607            return q * (*this);
608        }
609
610                /** Gets the angle between 2 vectors.
611                @remarks
612                        Vectors do not have to be unit-length but must represent directions.
613                */
614                inline Radian angleBetween(const Vector3& dest)
615                {
616                        Real lenProduct = length() * dest.length();
617
618                        // Divide by zero check
619                        if(lenProduct < 1e-6f)
620                                lenProduct = 1e-6f;
621
622                        Real f = dotProduct(dest) / lenProduct;
623
624                        f = Math::Clamp(f, (Real)-1.0, (Real)1.0);
625                        return Math::ACos(f);
626
627                }
628        /** Gets the shortest arc quaternion to rotate this vector to the destination
629            vector.
630        @remarks
631            If you call this with a dest vector that is close to the inverse
632            of this vector, we will rotate 180 degrees around the 'fallbackAxis'
633                        (if specified, or a generated axis if not) since in this case
634                        ANY axis of rotation is valid.
635        */
636        Quaternion getRotationTo(const Vector3& dest,
637                        const Vector3& fallbackAxis = Vector3::ZERO) const
638        {
639            // Based on Stan Melax's article in Game Programming Gems
640            Quaternion q;
641            // Copy, since cannot modify local
642            Vector3 v0 = *this;
643            Vector3 v1 = dest;
644            v0.normalise();
645            v1.normalise();
646
647            Real d = v0.dotProduct(v1);
648            // If dot == 1, vectors are the same
649            if (d >= 1.0f)
650            {
651                return Quaternion::IDENTITY;
652            }
653                        if (d < (1e-6f - 1.0f))
654                        {
655                                if (fallbackAxis != Vector3::ZERO)
656                                {
657                                        // rotate 180 degrees about the fallback axis
658                                        q.FromAngleAxis(Radian(Math::PI), fallbackAxis);
659                                }
660                                else
661                                {
662                                        // Generate an axis
663                                        Vector3 axis = Vector3::UNIT_X.crossProduct(*this);
664                                        if (axis.isZeroLength()) // pick another if colinear
665                                                axis = Vector3::UNIT_Y.crossProduct(*this);
666                                        axis.normalise();
667                                        q.FromAngleAxis(Radian(Math::PI), axis);
668                                }
669                        }
670                        else
671                        {
672                Real s = Math::Sqrt( (1+d)*2 );
673                    Real invs = 1 / s;
674
675                                Vector3 c = v0.crossProduct(v1);
676
677                q.x = c.x * invs;
678                    q.y = c.y * invs;
679                q.z = c.z * invs;
680                q.w = s * 0.5;
681                                q.normalise();
682                        }
683            return q;
684        }
685
686        /** Returns true if this vector is zero length. */
687        inline bool isZeroLength(void) const
688        {
689            Real sqlen = (x * x) + (y * y) + (z * z);
690            return (sqlen < (1e-06 * 1e-06));
691
692        }
693
694        /** As normalise, except that this vector is unaffected and the
695            normalised vector is returned as a copy. */
696        inline Vector3 normalisedCopy(void) const
697        {
698            Vector3 ret = *this;
699            ret.normalise();
700            return ret;
701        }
702
703        /** Calculates a reflection vector to the plane with the given normal .
704        @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
705        */
706        inline Vector3 reflect(const Vector3& normal) const
707        {
708            return Vector3( *this - ( 2 * this->dotProduct(normal) * normal ) );
709        }
710
711                /** Returns whether this vector is within a positional tolerance
712                        of another vector.
713                @param rhs The vector to compare with
714                @param tolerance The amount that each element of the vector may vary by
715                        and still be considered equal
716                */
717                inline bool positionEquals(const Vector3& rhs, Real tolerance = 1e-03) const
718                {
719                        return Math::RealEqual(x, rhs.x, tolerance) &&
720                                Math::RealEqual(y, rhs.y, tolerance) &&
721                                Math::RealEqual(z, rhs.z, tolerance);
722
723                }
724
725                /** Returns whether this vector is within a positional tolerance
726                        of another vector, also take scale of the vectors into account.
727                @param rhs The vector to compare with
728                @param tolerance The amount (related to the scale of vectors) that distance
729            of the vector may vary by and still be considered close
730                */
731                inline bool positionCloses(const Vector3& rhs, Real tolerance = 1e-03f) const
732                {
733                        return squaredDistance(rhs) <=
734                (squaredLength() + rhs.squaredLength()) * tolerance;
735                }
736
737                /** Returns whether this vector is within a directional tolerance
738                        of another vector.
739                @param rhs The vector to compare with
740                @param tolerance The maximum angle by which the vectors may vary and
741                        still be considered equal
742                @note Both vectors should be normalised.
743                */
744                inline bool directionEquals(const Vector3& rhs,
745                        const Radian& tolerance) const
746                {
747                        Real dot = dotProduct(rhs);
748                        Radian angle = Math::ACos(dot);
749
750                        return Math::Abs(angle.valueRadians()) <= tolerance.valueRadians();
751
752                }
753
754        // special points
755        static const Vector3 ZERO;
756        static const Vector3 UNIT_X;
757        static const Vector3 UNIT_Y;
758        static const Vector3 UNIT_Z;
759        static const Vector3 NEGATIVE_UNIT_X;
760        static const Vector3 NEGATIVE_UNIT_Y;
761        static const Vector3 NEGATIVE_UNIT_Z;
762        static const Vector3 UNIT_SCALE;
763
764        /** Function for writing to a stream.
765        */
766        inline _OgreExport friend std::ostream& operator <<
767            ( std::ostream& o, const Vector3& v )
768        {
769            o << "Vector3(" << v.x << ", " << v.y << ", " << v.z << ")";
770            return o;
771        }
772    };
773
774}
775#endif
Note: See TracBrowser for help on using the repository browser.