Irrlicht 3D Engine
vector2d.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2012 Nikolaus Gebhardt
00002 // This file is part of the "Irrlicht Engine".
00003 // For conditions of distribution and use, see copyright notice in irrlicht.h
00004 
00005 #ifndef __IRR_POINT_2D_H_INCLUDED__
00006 #define __IRR_POINT_2D_H_INCLUDED__
00007 
00008 #include "irrMath.h"
00009 #include "dimension2d.h"
00010 
00011 namespace irr
00012 {
00013 namespace core
00014 {
00015 
00016 
00018 
00020 template <class T>
00021 class vector2d
00022 {
00023 public:
00025     vector2d() : X(0), Y(0) {}
00027     vector2d(T nx, T ny) : X(nx), Y(ny) {}
00029     explicit vector2d(T n) : X(n), Y(n) {}
00031     vector2d(const vector2d<T>& other) : X(other.X), Y(other.Y) {}
00032 
00033     vector2d(const dimension2d<T>& other) : X(other.Width), Y(other.Height) {}
00034 
00035     // operators
00036 
00037     vector2d<T> operator-() const { return vector2d<T>(-X, -Y); }
00038 
00039     vector2d<T>& operator=(const vector2d<T>& other) { X = other.X; Y = other.Y; return *this; }
00040 
00041     vector2d<T>& operator=(const dimension2d<T>& other) { X = other.Width; Y = other.Height; return *this; }
00042 
00043     vector2d<T> operator+(const vector2d<T>& other) const { return vector2d<T>(X + other.X, Y + other.Y); }
00044     vector2d<T> operator+(const dimension2d<T>& other) const { return vector2d<T>(X + other.Width, Y + other.Height); }
00045     vector2d<T>& operator+=(const vector2d<T>& other) { X+=other.X; Y+=other.Y; return *this; }
00046     vector2d<T> operator+(const T v) const { return vector2d<T>(X + v, Y + v); }
00047     vector2d<T>& operator+=(const T v) { X+=v; Y+=v; return *this; }
00048     vector2d<T>& operator+=(const dimension2d<T>& other) { X += other.Width; Y += other.Height; return *this;  }
00049 
00050     vector2d<T> operator-(const vector2d<T>& other) const { return vector2d<T>(X - other.X, Y - other.Y); }
00051     vector2d<T> operator-(const dimension2d<T>& other) const { return vector2d<T>(X - other.Width, Y - other.Height); }
00052     vector2d<T>& operator-=(const vector2d<T>& other) { X-=other.X; Y-=other.Y; return *this; }
00053     vector2d<T> operator-(const T v) const { return vector2d<T>(X - v, Y - v); }
00054     vector2d<T>& operator-=(const T v) { X-=v; Y-=v; return *this; }
00055     vector2d<T>& operator-=(const dimension2d<T>& other) { X -= other.Width; Y -= other.Height; return *this;  }
00056 
00057     vector2d<T> operator*(const vector2d<T>& other) const { return vector2d<T>(X * other.X, Y * other.Y); }
00058     vector2d<T>& operator*=(const vector2d<T>& other) { X*=other.X; Y*=other.Y; return *this; }
00059     vector2d<T> operator*(const T v) const { return vector2d<T>(X * v, Y * v); }
00060     vector2d<T>& operator*=(const T v) { X*=v; Y*=v; return *this; }
00061 
00062     vector2d<T> operator/(const vector2d<T>& other) const { return vector2d<T>(X / other.X, Y / other.Y); }
00063     vector2d<T>& operator/=(const vector2d<T>& other) { X/=other.X; Y/=other.Y; return *this; }
00064     vector2d<T> operator/(const T v) const { return vector2d<T>(X / v, Y / v); }
00065     vector2d<T>& operator/=(const T v) { X/=v; Y/=v; return *this; }
00066 
00068     bool operator<=(const vector2d<T>&other) const
00069     {
00070         return  (X<other.X || core::equals(X, other.X)) ||
00071                 (core::equals(X, other.X) && (Y<other.Y || core::equals(Y, other.Y)));
00072     }
00073 
00075     bool operator>=(const vector2d<T>&other) const
00076     {
00077         return  (X>other.X || core::equals(X, other.X)) ||
00078                 (core::equals(X, other.X) && (Y>other.Y || core::equals(Y, other.Y)));
00079     }
00080 
00082     bool operator<(const vector2d<T>&other) const
00083     {
00084         return  (X<other.X && !core::equals(X, other.X)) ||
00085                 (core::equals(X, other.X) && Y<other.Y && !core::equals(Y, other.Y));
00086     }
00087 
00089     bool operator>(const vector2d<T>&other) const
00090     {
00091         return  (X>other.X && !core::equals(X, other.X)) ||
00092                 (core::equals(X, other.X) && Y>other.Y && !core::equals(Y, other.Y));
00093     }
00094 
00095     bool operator==(const vector2d<T>& other) const { return equals(other); }
00096     bool operator!=(const vector2d<T>& other) const { return !equals(other); }
00097 
00098     // functions
00099 
00101 
00104     bool equals(const vector2d<T>& other) const
00105     {
00106         return core::equals(X, other.X) && core::equals(Y, other.Y);
00107     }
00108 
00109     vector2d<T>& set(T nx, T ny) {X=nx; Y=ny; return *this; }
00110     vector2d<T>& set(const vector2d<T>& p) { X=p.X; Y=p.Y; return *this; }
00111 
00113 
00114     T getLength() const { return core::squareroot( X*X + Y*Y ); }
00115 
00117 
00119     T getLengthSQ() const { return X*X + Y*Y; }
00120 
00122 
00124     T dotProduct(const vector2d<T>& other) const
00125     {
00126         return X*other.X + Y*other.Y;
00127     }
00128 
00130 
00133     T getDistanceFrom(const vector2d<T>& other) const
00134     {
00135         return vector2d<T>(X - other.X, Y - other.Y).getLength();
00136     }
00137 
00139 
00142     T getDistanceFromSQ(const vector2d<T>& other) const
00143     {
00144         return vector2d<T>(X - other.X, Y - other.Y).getLengthSQ();
00145     }
00146 
00148 
00151     vector2d<T>& rotateBy(f64 degrees, const vector2d<T>& center=vector2d<T>())
00152     {
00153         degrees *= DEGTORAD64;
00154         const f64 cs = cos(degrees);
00155         const f64 sn = sin(degrees);
00156 
00157         X -= center.X;
00158         Y -= center.Y;
00159 
00160         set((T)(X*cs - Y*sn), (T)(X*sn + Y*cs));
00161 
00162         X += center.X;
00163         Y += center.Y;
00164         return *this;
00165     }
00166 
00168 
00170     vector2d<T>& normalize()
00171     {
00172         f32 length = (f32)(X*X + Y*Y);
00173         if ( length == 0 )
00174             return *this;
00175         length = core::reciprocal_squareroot ( length );
00176         X = (T)(X * length);
00177         Y = (T)(Y * length);
00178         return *this;
00179     }
00180 
00182 
00185     f64 getAngleTrig() const
00186     {
00187         if (Y == 0)
00188             return X < 0 ? 180 : 0;
00189         else
00190         if (X == 0)
00191             return Y < 0 ? 270 : 90;
00192 
00193         if ( Y > 0)
00194             if (X > 0)
00195                 return atan((irr::f64)Y/(irr::f64)X) * RADTODEG64;
00196             else
00197                 return 180.0-atan((irr::f64)Y/-(irr::f64)X) * RADTODEG64;
00198         else
00199             if (X > 0)
00200                 return 360.0-atan(-(irr::f64)Y/(irr::f64)X) * RADTODEG64;
00201             else
00202                 return 180.0+atan(-(irr::f64)Y/-(irr::f64)X) * RADTODEG64;
00203     }
00204 
00206 
00208     inline f64 getAngle() const
00209     {
00210         if (Y == 0) // corrected thanks to a suggestion by Jox
00211             return X < 0 ? 180 : 0;
00212         else if (X == 0)
00213             return Y < 0 ? 90 : 270;
00214 
00215         // don't use getLength here to avoid precision loss with s32 vectors
00216         // avoid floating-point trouble as sqrt(y*y) is occasionally larger than y, so clamp
00217         const f64 tmp = core::clamp(Y / sqrt((f64)(X*X + Y*Y)), -1.0, 1.0);
00218         const f64 angle = atan( core::squareroot(1 - tmp*tmp) / tmp) * RADTODEG64;
00219 
00220         if (X>0 && Y>0)
00221             return angle + 270;
00222         else
00223         if (X>0 && Y<0)
00224             return angle + 90;
00225         else
00226         if (X<0 && Y<0)
00227             return 90 - angle;
00228         else
00229         if (X<0 && Y>0)
00230             return 270 - angle;
00231 
00232         return angle;
00233     }
00234 
00236 
00238     inline f64 getAngleWith(const vector2d<T>& b) const
00239     {
00240         f64 tmp = (f64)(X*b.X + Y*b.Y);
00241 
00242         if (tmp == 0.0)
00243             return 90.0;
00244 
00245         tmp = tmp / core::squareroot((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y)));
00246         if (tmp < 0.0)
00247             tmp = -tmp;
00248         if ( tmp > 1.0 ) //   avoid floating-point trouble
00249             tmp = 1.0;
00250 
00251         return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64;
00252     }
00253 
00255 
00259     bool isBetweenPoints(const vector2d<T>& begin, const vector2d<T>& end) const
00260     {
00261         if (begin.X != end.X)
00262         {
00263             return ((begin.X <= X && X <= end.X) ||
00264                 (begin.X >= X && X >= end.X));
00265         }
00266         else
00267         {
00268             return ((begin.Y <= Y && Y <= end.Y) ||
00269                 (begin.Y >= Y && Y >= end.Y));
00270         }
00271     }
00272 
00274 
00278     vector2d<T> getInterpolated(const vector2d<T>& other, f64 d) const
00279     {
00280         f64 inv = 1.0f - d;
00281         return vector2d<T>((T)(other.X*inv + X*d), (T)(other.Y*inv + Y*d));
00282     }
00283 
00285 
00290     vector2d<T> getInterpolated_quadratic(const vector2d<T>& v2, const vector2d<T>& v3, f64 d) const
00291     {
00292         // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d;
00293         const f64 inv = 1.0f - d;
00294         const f64 mul0 = inv * inv;
00295         const f64 mul1 = 2.0f * d * inv;
00296         const f64 mul2 = d * d;
00297 
00298         return vector2d<T> ( (T)(X * mul0 + v2.X * mul1 + v3.X * mul2),
00299                     (T)(Y * mul0 + v2.Y * mul1 + v3.Y * mul2));
00300     }
00301 
00303 
00308     vector2d<T>& interpolate(const vector2d<T>& a, const vector2d<T>& b, f64 d)
00309     {
00310         X = (T)((f64)b.X + ( ( a.X - b.X ) * d ));
00311         Y = (T)((f64)b.Y + ( ( a.Y - b.Y ) * d ));
00312         return *this;
00313     }
00314 
00316     T X;
00317 
00319     T Y;
00320 };
00321 
00323     typedef vector2d<f32> vector2df;
00324 
00326     typedef vector2d<s32> vector2di;
00327 
00328     template<class S, class T>
00329     vector2d<T> operator*(const S scalar, const vector2d<T>& vector) { return vector*scalar; }
00330 
00331     // These methods are declared in dimension2d, but need definitions of vector2d
00332     template<class T>
00333     dimension2d<T>::dimension2d(const vector2d<T>& other) : Width(other.X), Height(other.Y) { }
00334 
00335     template<class T>
00336     bool dimension2d<T>::operator==(const vector2d<T>& other) const { return Width == other.X && Height == other.Y; }
00337 
00338 } // end namespace core
00339 } // end namespace irr
00340 
00341 #endif
00342