source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreVector3.h @ 1812

Revision 1812, 22.7 KB checked in by gumbau, 18 years ago (diff)
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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#ifndef __Vector3_H__
26#define __Vector3_H__
27
28#include "OgrePrerequisites.h"
29#include "OgreMath.h"
30#include "OgreQuaternion.h"
31
32namespace Ogre
33{
34
35    /** Standard 3-dimensional vector.
36        @remarks
37            A direction in 3D space represented as distances along the 3
38            orthoganal axes (x, y, z). Note that positions, directions and
39            scaling factors can be represented by a vector, depending on how
40            you interpret the values.
41    */
42    class _OgreExport Vector3
43    {
44    public:
45        union {
46            struct {
47                Real x, y, z;
48            };
49            Real val[3];
50        };
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 Vector3( const Vector3& rkVector )
90            : x( rkVector.x ), y( rkVector.y ), z( rkVector.z )
91        {
92        }
93
94                inline Real operator [] ( const size_t i ) const
95        {
96            assert( i < 3 );
97
98            return *(&x+i);
99        }
100
101                inline Real& operator [] ( const size_t i )
102        {
103            assert( i < 3 );
104
105            return *(&x+i);
106        }
107
108        /** Assigns the value of the other vector.
109            @param
110                rkVector The other vector
111        */
112        inline Vector3& operator = ( const Vector3& rkVector )
113        {
114            x = rkVector.x;
115            y = rkVector.y;
116            z = rkVector.z;
117
118            return *this;
119        }
120
121        inline Vector3& operator = ( const Real fScaler )
122        {
123            x = fScaler;
124            y = fScaler;
125            z = fScaler;
126
127            return *this;
128        }
129
130        inline bool operator == ( const Vector3& rkVector ) const
131        {
132            return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
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        // arithmetic operations
141        inline Vector3 operator + ( const Vector3& rkVector ) const
142        {
143            return Vector3(
144                x + rkVector.x,
145                y + rkVector.y,
146                z + rkVector.z);
147        }
148
149        inline Vector3 operator - ( const Vector3& rkVector ) const
150        {
151            return Vector3(
152                x - rkVector.x,
153                y - rkVector.y,
154                z - rkVector.z);
155        }
156
157        inline Vector3 operator * ( const Real fScalar ) const
158        {
159            return Vector3(
160                x * fScalar,
161                y * fScalar,
162                z * fScalar);
163        }
164
165        inline Vector3 operator * ( const Vector3& rhs) const
166        {
167            return Vector3(
168                x * rhs.x,
169                y * rhs.y,
170                z * rhs.z);
171        }
172
173        inline Vector3 operator / ( const Real fScalar ) const
174        {
175            assert( fScalar != 0.0 );
176
177            Real fInv = 1.0 / fScalar;
178
179            return Vector3(
180                x * fInv,
181                y * fInv,
182                z * fInv);
183        }
184
185        inline Vector3 operator / ( const Vector3& rhs) const
186        {
187            return Vector3(
188                x / rhs.x,
189                y / rhs.y,
190                z / rhs.z);
191        }
192
193        inline const Vector3& operator + () const
194        {
195            return *this;
196        }
197
198        inline Vector3 operator - () const
199        {
200            return Vector3(-x, -y, -z);
201        }
202
203        // overloaded operators to help Vector3
204        inline friend Vector3 operator * ( const Real fScalar, const Vector3& rkVector )
205        {
206            return Vector3(
207                fScalar * rkVector.x,
208                fScalar * rkVector.y,
209                fScalar * rkVector.z);
210        }
211
212        inline friend Vector3 operator / ( const Real fScalar, const Vector3& rkVector )
213        {
214            return Vector3(
215                fScalar / rkVector.x,
216                fScalar / rkVector.y,
217                fScalar / rkVector.z);
218        }
219
220        inline friend Vector3 operator + (const Vector3& lhs, const Real rhs)
221        {
222            return Vector3(
223                lhs.x + rhs,
224                lhs.y + rhs,
225                lhs.z + rhs);
226        }
227
228        inline friend Vector3 operator + (const Real lhs, const Vector3& rhs)
229        {
230            return Vector3(
231                lhs + rhs.x,
232                lhs + rhs.y,
233                lhs + rhs.z);
234        }
235
236        inline friend Vector3 operator - (const Vector3& lhs, const Real rhs)
237        {
238            return Vector3(
239                lhs.x - rhs,
240                lhs.y - rhs,
241                lhs.z - rhs);
242        }
243
244        inline friend Vector3 operator - (const Real lhs, const Vector3& rhs)
245        {
246            return Vector3(
247                lhs - rhs.x,
248                lhs - rhs.y,
249                lhs - rhs.z);
250        }
251
252        // arithmetic updates
253        inline Vector3& operator += ( const Vector3& rkVector )
254        {
255            x += rkVector.x;
256            y += rkVector.y;
257            z += rkVector.z;
258
259            return *this;
260        }
261
262        inline Vector3& operator += ( const Real fScalar )
263        {
264            x += fScalar;
265            y += fScalar;
266            z += fScalar;
267            return *this;
268        }
269
270        inline Vector3& operator -= ( const Vector3& rkVector )
271        {
272            x -= rkVector.x;
273            y -= rkVector.y;
274            z -= rkVector.z;
275
276            return *this;
277        }
278
279        inline Vector3& operator -= ( const Real fScalar )
280        {
281            x -= fScalar;
282            y -= fScalar;
283            z -= fScalar;
284            return *this;
285        }
286
287        inline Vector3& operator *= ( const Real fScalar )
288        {
289            x *= fScalar;
290            y *= fScalar;
291            z *= fScalar;
292            return *this;
293        }
294
295        inline Vector3& operator *= ( const Vector3& rkVector )
296        {
297            x *= rkVector.x;
298            y *= rkVector.y;
299            z *= rkVector.z;
300
301            return *this;
302        }
303
304        inline Vector3& operator /= ( const Real fScalar )
305        {
306            assert( fScalar != 0.0 );
307
308            Real fInv = 1.0 / fScalar;
309
310            x *= fInv;
311            y *= fInv;
312            z *= fInv;
313
314            return *this;
315        }
316
317        inline Vector3& operator /= ( const Vector3& rkVector )
318        {
319            x /= rkVector.x;
320            y /= rkVector.y;
321            z /= rkVector.z;
322
323            return *this;
324        }
325
326
327        /** Returns the length (magnitude) of the vector.
328            @warning
329                This operation requires a square root and is expensive in
330                terms of CPU operations. If you don't need to know the exact
331                length (e.g. for just comparing lengths) use squaredLength()
332                instead.
333        */
334        inline Real length () const
335        {
336            return Math::Sqrt( x * x + y * y + z * z );
337        }
338
339        /** Returns the square of the length(magnitude) of the vector.
340            @remarks
341                This  method is for efficiency - calculating the actual
342                length of a vector requires a square root, which is expensive
343                in terms of the operations required. This method returns the
344                square of the length of the vector, i.e. the same as the
345                length but before the square root is taken. Use this if you
346                want to find the longest / shortest vector without incurring
347                the square root.
348        */
349        inline Real squaredLength () const
350        {
351            return x * x + y * y + z * z;
352        }
353
354        /** Calculates the dot (scalar) product of this vector with another.
355            @remarks
356                The dot product can be used to calculate the angle between 2
357                vectors. If both are unit vectors, the dot product is the
358                cosine of the angle; otherwise the dot product must be
359                divided by the product of the lengths of both vectors to get
360                the cosine of the angle. This result can further be used to
361                calculate the distance of a point from a plane.
362            @param
363                vec Vector with which to calculate the dot product (together
364                with this one).
365            @returns
366                A float representing the dot product value.
367        */
368        inline Real dotProduct(const Vector3& vec) const
369        {
370            return x * vec.x + y * vec.y + z * vec.z;
371        }
372
373        /** Normalises the vector.
374            @remarks
375                This method normalises the vector such that it's
376                length / magnitude is 1. The result is called a unit vector.
377            @note
378                This function will not crash for zero-sized vectors, but there
379                will be no changes made to their components.
380            @returns The previous length of the vector.
381        */
382        inline Real normalise()
383        {
384            Real fLength = Math::Sqrt( x * x + y * y + z * z );
385
386            // Will also work for zero-sized vectors, but will change nothing
387            if ( fLength > 1e-08 )
388            {
389                Real fInvLength = 1.0 / fLength;
390                x *= fInvLength;
391                y *= fInvLength;
392                z *= fInvLength;
393            }
394
395            return fLength;
396        }
397
398        /** Calculates the cross-product of 2 vectors, i.e. the vector that
399            lies perpendicular to them both.
400            @remarks
401                The cross-product is normally used to calculate the normal
402                vector of a plane, by calculating the cross-product of 2
403                non-equivalent vectors which lie on the plane (e.g. 2 edges
404                of a triangle).
405            @param
406                vec Vector which, together with this one, will be used to
407                calculate the cross-product.
408            @returns
409                A vector which is the result of the cross-product. This
410                vector will <b>NOT</b> be normalised, to maximise efficiency
411                - call Vector3::normalise on the result if you wish this to
412                be done. As for which side the resultant vector will be on, the
413                returned vector will be on the side from which the arc from 'this'
414                to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z)
415                = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X.
416                                This is because OGRE uses a right-handed coordinate system.
417            @par
418                For a clearer explanation, look a the left and the bottom edges
419                of your monitor's screen. Assume that the first vector is the
420                left edge and the second vector is the bottom edge, both of
421                them starting from the lower-left corner of the screen. The
422                resulting vector is going to be perpendicular to both of them
423                and will go <i>inside</i> the screen, towards the cathode tube
424                (assuming you're using a CRT monitor, of course).
425        */
426        inline Vector3 crossProduct( const Vector3& rkVector ) const
427        {
428            return Vector3(
429                y * rkVector.z - z * rkVector.y,
430                z * rkVector.x - x * rkVector.z,
431                x * rkVector.y - y * rkVector.x);
432        }
433
434        /** Returns a vector at a point half way between this and the passed
435            in vector.
436        */
437        inline Vector3 midPoint( const Vector3& vec ) const
438        {
439            return Vector3(
440                ( x + vec.x ) * 0.5,
441                ( y + vec.y ) * 0.5,
442                ( z + vec.z ) * 0.5 );
443        }
444
445        /** Returns true if the vector's scalar components are all greater
446            that the ones of the vector it is compared against.
447        */
448        inline bool operator < ( const Vector3& rhs ) const
449        {
450            if( x < rhs.x && y < rhs.y && z < rhs.z )
451                return true;
452            return false;
453        }
454
455        /** Returns true if the vector's scalar components are all smaller
456            that the ones of the vector it is compared against.
457        */
458        inline bool operator > ( const Vector3& rhs ) const
459        {
460            if( x > rhs.x && y > rhs.y && z > rhs.z )
461                return true;
462            return false;
463        }
464
465        /** Sets this vector's components to the minimum of its own and the
466            ones of the passed in vector.
467            @remarks
468                'Minimum' in this case means the combination of the lowest
469                value of x, y and z from both vectors. Lowest is taken just
470                numerically, not magnitude, so -1 < 0.
471        */
472        inline void makeFloor( const Vector3& cmp )
473        {
474            if( cmp.x < x ) x = cmp.x;
475            if( cmp.y < y ) y = cmp.y;
476            if( cmp.z < z ) z = cmp.z;
477        }
478
479        /** Sets this vector's components to the maximum of its own and the
480            ones of the passed in vector.
481            @remarks
482                'Maximum' in this case means the combination of the highest
483                value of x, y and z from both vectors. Highest is taken just
484                numerically, not magnitude, so 1 > -3.
485        */
486        inline void makeCeil( const Vector3& cmp )
487        {
488            if( cmp.x > x ) x = cmp.x;
489            if( cmp.y > y ) y = cmp.y;
490            if( cmp.z > z ) z = cmp.z;
491        }
492
493        /** Generates a vector perpendicular to this vector (eg an 'up' vector).
494            @remarks
495                This method will return a vector which is perpendicular to this
496                vector. There are an infinite number of possibilities but this
497                method will guarantee to generate one of them. If you need more
498                control you should use the Quaternion class.
499        */
500        inline Vector3 perpendicular(void) const
501        {
502            static const Real fSquareZero = 1e-06 * 1e-06;
503
504            Vector3 perp = this->crossProduct( Vector3::UNIT_X );
505
506            // Check length
507            if( perp.squaredLength() < fSquareZero )
508            {
509                /* This vector is the Y axis multiplied by a scalar, so we have
510                   to use another axis.
511                */
512                perp = this->crossProduct( Vector3::UNIT_Y );
513            }
514
515            return perp;
516        }
517        /** Generates a new random vector which deviates from this vector by a
518            given angle in a random direction.
519            @remarks
520                This method assumes that the random number generator has already
521                been seeded appropriately.
522            @param
523                angle The angle at which to deviate
524            @param
525                up Any vector perpendicular to this one (which could generated
526                by cross-product of this vector and any other non-colinear
527                vector). If you choose not to provide this the function will
528                derive one on it's own, however if you provide one yourself the
529                function will be faster (this allows you to reuse up vectors if
530                you call this method more than once)
531            @returns
532                A random vector which deviates from this vector by angle. This
533                vector will not be normalised, normalise it if you wish
534                afterwards.
535        */
536        inline Vector3 randomDeviant(
537            const Radian& angle,
538            const Vector3& up = Vector3::ZERO ) const
539        {
540            Vector3 newUp;
541
542            if (up == Vector3::ZERO)
543            {
544                // Generate an up vector
545                newUp = this->perpendicular();
546            }
547            else
548            {
549                newUp = up;
550            }
551
552            // Rotate up vector by random amount around this
553            Quaternion q;
554            q.FromAngleAxis( Radian(Math::UnitRandom() * Math::TWO_PI), *this );
555            newUp = q * newUp;
556
557            // Finally rotate this by given angle around randomised up
558            q.FromAngleAxis( angle, newUp );
559            return q * (*this);
560        }
561#ifndef OGRE_FORCE_ANGLE_TYPES
562        inline Vector3 randomDeviant(
563            Real angle,
564            const Vector3& up = Vector3::ZERO ) const
565        {
566            return randomDeviant ( Radian(angle), up );
567        }
568#endif//OGRE_FORCE_ANGLE_TYPES
569
570        /** Gets the shortest arc quaternion to rotate this vector to the destination
571            vector.
572        @remarks
573            If you call this with a dest vector that is close to the inverse
574            of this vector, we will rotate 180 degrees around the 'fallbackAxis'
575                        (if specified, or a generated axis if not) since in this case
576                        ANY axis of rotation is valid.
577        */
578        Quaternion getRotationTo(const Vector3& dest,
579                        const Vector3& fallbackAxis = Vector3::ZERO) const
580        {
581            // Based on Stan Melax's article in Game Programming Gems
582            Quaternion q;
583            // Copy, since cannot modify local
584            Vector3 v0 = *this;
585            Vector3 v1 = dest;
586            v0.normalise();
587            v1.normalise();
588
589            Real d = v0.dotProduct(v1);
590            // If dot == 1, vectors are the same
591            if (d >= 1.0f)
592            {
593                return Quaternion::IDENTITY;
594            }
595            Real s = Math::Sqrt( (1+d)*2 );
596                        if (s < 1e-6f)
597                        {
598                                if (fallbackAxis != Vector3::ZERO)
599                                {
600                                        // rotate 180 degrees about the fallback axis
601                                        q.FromAngleAxis(Radian(Math::PI), fallbackAxis);
602                                }
603                                else
604                                {
605                                        // Generate an axis
606                                        Vector3 axis = Vector3::UNIT_X.crossProduct(*this);
607                                        if (axis.isZeroLength()) // pick another if colinear
608                                                axis = Vector3::UNIT_Y.crossProduct(*this);
609                                        axis.normalise();
610                                        q.FromAngleAxis(Radian(Math::PI), axis);
611                                }
612                        }
613                        else
614                        {
615                    Real invs = 1 / s;
616
617                                Vector3 c = v0.crossProduct(v1);
618
619                q.x = c.x * invs;
620                    q.y = c.y * invs;
621                q.z = c.z * invs;
622                q.w = s * 0.5;
623                                q.normalise();
624                        }
625            return q;
626        }
627
628        /** Returns true if this vector is zero length. */
629        inline bool isZeroLength(void) const
630        {
631            Real sqlen = (x * x) + (y * y) + (z * z);
632            return (sqlen < (1e-06 * 1e-06));
633
634        }
635
636        /** As normalise, except that this vector is unaffected and the
637            normalised vector is returned as a copy. */
638        inline Vector3 normalisedCopy(void) const
639        {
640            Vector3 ret = *this;
641            ret.normalise();
642            return ret;
643        }
644
645        /** Calculates a reflection vector to the plane with the given normal .
646        @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
647        */
648        inline Vector3 reflect(const Vector3& normal) const
649        {
650            return Vector3( *this - ( 2 * this->dotProduct(normal) * normal ) );
651        }
652
653                /** Returns whether this vector is within a positional tolerance
654                        of another vector.
655                @param rhs The vector to compare with
656                @param tolerance The amount that each element of the vector may vary by
657                        and still be considered equal
658                */
659                inline bool positionEquals(const Vector3& rhs, Real tolerance = 1e-03) const
660                {
661                        return Math::RealEqual(x, rhs.x, tolerance) &&
662                                Math::RealEqual(y, rhs.y, tolerance) &&
663                                Math::RealEqual(z, rhs.z, tolerance);
664
665                }
666                /** Returns whether this vector is within a directional tolerance
667                        of another vector.
668                @param rhs The vector to compare with
669                @param tolerance The maximum angle by which the vectors may vary and
670                        still be considered equal
671                */
672                inline bool directionEquals(const Vector3& rhs,
673                        const Radian& tolerance) const
674                {
675                        Real dot = dotProduct(rhs);
676                        Radian angle = Math::ACos(dot);
677
678                        return Math::Abs(angle.valueRadians()) <= tolerance.valueRadians();
679
680                }
681
682        // special points
683        static const Vector3 ZERO;
684        static const Vector3 UNIT_X;
685        static const Vector3 UNIT_Y;
686        static const Vector3 UNIT_Z;
687        static const Vector3 NEGATIVE_UNIT_X;
688        static const Vector3 NEGATIVE_UNIT_Y;
689        static const Vector3 NEGATIVE_UNIT_Z;
690        static const Vector3 UNIT_SCALE;
691
692        /** Function for writing to a stream.
693        */
694        inline _OgreExport friend std::ostream& operator <<
695            ( std::ostream& o, const Vector3& v )
696        {
697            o << "Vector3(" << v.x << ", " << v.y << ", " << v.z << ")";
698            return o;
699        }
700    };
701
702}
703#endif
Note: See TracBrowser for help on using the repository browser.