1 // Copyright (C) 2002-2012 Nikolaus Gebhardt 2 // This file is part of the "Irrlicht Engine". 3 // For conditions of distribution and use, see copyright notice in irrlicht.h 4 5 #ifndef __IRR_POINT_2D_H_INCLUDED__ 6 #define __IRR_POINT_2D_H_INCLUDED__ 7 8 #include "irrMath.h" 9 #include "dimension2d.h" 10 11 namespace irr 12 { 13 namespace core 14 { 15 16 17 //! 2d vector template class with lots of operators and methods. 18 /** As of Irrlicht 1.6, this class supercedes position2d, which should 19 be considered deprecated. */ 20 template <class T> 21 class vector2d 22 { 23 public: 24 //! Default constructor (null vector) vector2d()25 vector2d() : X(0), Y(0) {} 26 //! Constructor with two different values vector2d(T nx,T ny)27 vector2d(T nx, T ny) : X(nx), Y(ny) {} 28 //! Constructor with the same value for both members vector2d(T n)29 explicit vector2d(T n) : X(n), Y(n) {} 30 //! Copy constructor vector2d(const vector2d<T> & other)31 vector2d(const vector2d<T>& other) : X(other.X), Y(other.Y) {} 32 vector2d(const dimension2d<T> & other)33 vector2d(const dimension2d<T>& other) : X(other.Width), Y(other.Height) {} 34 35 // operators 36 37 vector2d<T> operator-() const { return vector2d<T>(-X, -Y); } 38 39 vector2d<T>& operator=(const vector2d<T>& other) { X = other.X; Y = other.Y; return *this; } 40 41 vector2d<T>& operator=(const dimension2d<T>& other) { X = other.Width; Y = other.Height; return *this; } 42 43 vector2d<T> operator+(const vector2d<T>& other) const { return vector2d<T>(X + other.X, Y + other.Y); } 44 vector2d<T> operator+(const dimension2d<T>& other) const { return vector2d<T>(X + other.Width, Y + other.Height); } 45 vector2d<T>& operator+=(const vector2d<T>& other) { X+=other.X; Y+=other.Y; return *this; } 46 vector2d<T> operator+(const T v) const { return vector2d<T>(X + v, Y + v); } 47 vector2d<T>& operator+=(const T v) { X+=v; Y+=v; return *this; } 48 vector2d<T>& operator+=(const dimension2d<T>& other) { X += other.Width; Y += other.Height; return *this; } 49 50 vector2d<T> operator-(const vector2d<T>& other) const { return vector2d<T>(X - other.X, Y - other.Y); } 51 vector2d<T> operator-(const dimension2d<T>& other) const { return vector2d<T>(X - other.Width, Y - other.Height); } 52 vector2d<T>& operator-=(const vector2d<T>& other) { X-=other.X; Y-=other.Y; return *this; } 53 vector2d<T> operator-(const T v) const { return vector2d<T>(X - v, Y - v); } 54 vector2d<T>& operator-=(const T v) { X-=v; Y-=v; return *this; } 55 vector2d<T>& operator-=(const dimension2d<T>& other) { X -= other.Width; Y -= other.Height; return *this; } 56 57 vector2d<T> operator*(const vector2d<T>& other) const { return vector2d<T>(X * other.X, Y * other.Y); } 58 vector2d<T>& operator*=(const vector2d<T>& other) { X*=other.X; Y*=other.Y; return *this; } 59 vector2d<T> operator*(const T v) const { return vector2d<T>(X * v, Y * v); } 60 vector2d<T>& operator*=(const T v) { X*=v; Y*=v; return *this; } 61 62 vector2d<T> operator/(const vector2d<T>& other) const { return vector2d<T>(X / other.X, Y / other.Y); } 63 vector2d<T>& operator/=(const vector2d<T>& other) { X/=other.X; Y/=other.Y; return *this; } 64 vector2d<T> operator/(const T v) const { return vector2d<T>(X / v, Y / v); } 65 vector2d<T>& operator/=(const T v) { X/=v; Y/=v; return *this; } 66 67 //! sort in order X, Y. Equality with rounding tolerance. 68 bool operator<=(const vector2d<T>&other) const 69 { 70 return (X<other.X || core::equals(X, other.X)) || 71 (core::equals(X, other.X) && (Y<other.Y || core::equals(Y, other.Y))); 72 } 73 74 //! sort in order X, Y. Equality with rounding tolerance. 75 bool operator>=(const vector2d<T>&other) const 76 { 77 return (X>other.X || core::equals(X, other.X)) || 78 (core::equals(X, other.X) && (Y>other.Y || core::equals(Y, other.Y))); 79 } 80 81 //! sort in order X, Y. Difference must be above rounding tolerance. 82 bool operator<(const vector2d<T>&other) const 83 { 84 return (X<other.X && !core::equals(X, other.X)) || 85 (core::equals(X, other.X) && Y<other.Y && !core::equals(Y, other.Y)); 86 } 87 88 //! sort in order X, Y. Difference must be above rounding tolerance. 89 bool operator>(const vector2d<T>&other) const 90 { 91 return (X>other.X && !core::equals(X, other.X)) || 92 (core::equals(X, other.X) && Y>other.Y && !core::equals(Y, other.Y)); 93 } 94 95 bool operator==(const vector2d<T>& other) const { return equals(other); } 96 bool operator!=(const vector2d<T>& other) const { return !equals(other); } 97 98 // functions 99 100 //! Checks if this vector equals the other one. 101 /** Takes floating point rounding errors into account. 102 \param other Vector to compare with. 103 \return True if the two vector are (almost) equal, else false. */ equals(const vector2d<T> & other)104 bool equals(const vector2d<T>& other) const 105 { 106 return core::equals(X, other.X) && core::equals(Y, other.Y); 107 } 108 set(T nx,T ny)109 vector2d<T>& set(T nx, T ny) {X=nx; Y=ny; return *this; } set(const vector2d<T> & p)110 vector2d<T>& set(const vector2d<T>& p) { X=p.X; Y=p.Y; return *this; } 111 112 //! Gets the length of the vector. 113 /** \return The length of the vector. */ getLength()114 T getLength() const { return core::squareroot( X*X + Y*Y ); } 115 116 //! Get the squared length of this vector 117 /** This is useful because it is much faster than getLength(). 118 \return The squared length of the vector. */ getLengthSQ()119 T getLengthSQ() const { return X*X + Y*Y; } 120 121 //! Get the dot product of this vector with another. 122 /** \param other Other vector to take dot product with. 123 \return The dot product of the two vectors. */ dotProduct(const vector2d<T> & other)124 T dotProduct(const vector2d<T>& other) const 125 { 126 return X*other.X + Y*other.Y; 127 } 128 129 //! Gets distance from another point. 130 /** Here, the vector is interpreted as a point in 2-dimensional space. 131 \param other Other vector to measure from. 132 \return Distance from other point. */ getDistanceFrom(const vector2d<T> & other)133 T getDistanceFrom(const vector2d<T>& other) const 134 { 135 return vector2d<T>(X - other.X, Y - other.Y).getLength(); 136 } 137 138 //! Returns squared distance from another point. 139 /** Here, the vector is interpreted as a point in 2-dimensional space. 140 \param other Other vector to measure from. 141 \return Squared distance from other point. */ getDistanceFromSQ(const vector2d<T> & other)142 T getDistanceFromSQ(const vector2d<T>& other) const 143 { 144 return vector2d<T>(X - other.X, Y - other.Y).getLengthSQ(); 145 } 146 147 //! rotates the point anticlockwise around a center by an amount of degrees. 148 /** \param degrees Amount of degrees to rotate by, anticlockwise. 149 \param center Rotation center. 150 \return This vector after transformation. */ 151 vector2d<T>& rotateBy(f64 degrees, const vector2d<T>& center=vector2d<T>()) 152 { 153 degrees *= DEGTORAD64; 154 const f64 cs = cos(degrees); 155 const f64 sn = sin(degrees); 156 157 X -= center.X; 158 Y -= center.Y; 159 160 set((T)(X*cs - Y*sn), (T)(X*sn + Y*cs)); 161 162 X += center.X; 163 Y += center.Y; 164 return *this; 165 } 166 167 //! Normalize the vector. 168 /** The null vector is left untouched. 169 \return Reference to this vector, after normalization. */ normalize()170 vector2d<T>& normalize() 171 { 172 f32 length = (f32)(X*X + Y*Y); 173 if ( length == 0 ) 174 return *this; 175 length = core::reciprocal_squareroot ( length ); 176 X = (T)(X * length); 177 Y = (T)(Y * length); 178 return *this; 179 } 180 181 //! Calculates the angle of this vector in degrees in the trigonometric sense. 182 /** 0 is to the right (3 o'clock), values increase counter-clockwise. 183 This method has been suggested by Pr3t3nd3r. 184 \return Returns a value between 0 and 360. */ getAngleTrig()185 f64 getAngleTrig() const 186 { 187 if (Y == 0) 188 return X < 0 ? 180 : 0; 189 else 190 if (X == 0) 191 return Y < 0 ? 270 : 90; 192 193 if ( Y > 0) 194 if (X > 0) 195 return atan((irr::f64)Y/(irr::f64)X) * RADTODEG64; 196 else 197 return 180.0-atan((irr::f64)Y/-(irr::f64)X) * RADTODEG64; 198 else 199 if (X > 0) 200 return 360.0-atan(-(irr::f64)Y/(irr::f64)X) * RADTODEG64; 201 else 202 return 180.0+atan(-(irr::f64)Y/-(irr::f64)X) * RADTODEG64; 203 } 204 205 //! Calculates the angle of this vector in degrees in the counter trigonometric sense. 206 /** 0 is to the right (3 o'clock), values increase clockwise. 207 \return Returns a value between 0 and 360. */ getAngle()208 inline f64 getAngle() const 209 { 210 if (Y == 0) // corrected thanks to a suggestion by Jox 211 return X < 0 ? 180 : 0; 212 else if (X == 0) 213 return Y < 0 ? 90 : 270; 214 215 // don't use getLength here to avoid precision loss with s32 vectors 216 // avoid floating-point trouble as sqrt(y*y) is occasionally larger than y, so clamp 217 const f64 tmp = core::clamp(Y / sqrt((f64)(X*X + Y*Y)), -1.0, 1.0); 218 const f64 angle = atan( core::squareroot(1 - tmp*tmp) / tmp) * RADTODEG64; 219 220 if (X>0 && Y>0) 221 return angle + 270; 222 else 223 if (X>0 && Y<0) 224 return angle + 90; 225 else 226 if (X<0 && Y<0) 227 return 90 - angle; 228 else 229 if (X<0 && Y>0) 230 return 270 - angle; 231 232 return angle; 233 } 234 235 //! Calculates the angle between this vector and another one in degree. 236 /** \param b Other vector to test with. 237 \return Returns a value between 0 and 90. */ getAngleWith(const vector2d<T> & b)238 inline f64 getAngleWith(const vector2d<T>& b) const 239 { 240 f64 tmp = (f64)(X*b.X + Y*b.Y); 241 242 if (tmp == 0.0) 243 return 90.0; 244 245 tmp = tmp / core::squareroot((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y))); 246 if (tmp < 0.0) 247 tmp = -tmp; 248 if ( tmp > 1.0 ) // avoid floating-point trouble 249 tmp = 1.0; 250 251 return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64; 252 } 253 254 //! Returns if this vector interpreted as a point is on a line between two other points. 255 /** It is assumed that the point is on the line. 256 \param begin Beginning vector to compare between. 257 \param end Ending vector to compare between. 258 \return True if this vector is between begin and end, false if not. */ isBetweenPoints(const vector2d<T> & begin,const vector2d<T> & end)259 bool isBetweenPoints(const vector2d<T>& begin, const vector2d<T>& end) const 260 { 261 if (begin.X != end.X) 262 { 263 return ((begin.X <= X && X <= end.X) || 264 (begin.X >= X && X >= end.X)); 265 } 266 else 267 { 268 return ((begin.Y <= Y && Y <= end.Y) || 269 (begin.Y >= Y && Y >= end.Y)); 270 } 271 } 272 273 //! Creates an interpolated vector between this vector and another vector. 274 /** \param other The other vector to interpolate with. 275 \param d Interpolation value between 0.0f (all the other vector) and 1.0f (all this vector). 276 Note that this is the opposite direction of interpolation to getInterpolated_quadratic() 277 \return An interpolated vector. This vector is not modified. */ getInterpolated(const vector2d<T> & other,f64 d)278 vector2d<T> getInterpolated(const vector2d<T>& other, f64 d) const 279 { 280 f64 inv = 1.0f - d; 281 return vector2d<T>((T)(other.X*inv + X*d), (T)(other.Y*inv + Y*d)); 282 } 283 284 //! Creates a quadratically interpolated vector between this and two other vectors. 285 /** \param v2 Second vector to interpolate with. 286 \param v3 Third vector to interpolate with (maximum at 1.0f) 287 \param d Interpolation value between 0.0f (all this vector) and 1.0f (all the 3rd vector). 288 Note that this is the opposite direction of interpolation to getInterpolated() and interpolate() 289 \return An interpolated vector. This vector is not modified. */ getInterpolated_quadratic(const vector2d<T> & v2,const vector2d<T> & v3,f64 d)290 vector2d<T> getInterpolated_quadratic(const vector2d<T>& v2, const vector2d<T>& v3, f64 d) const 291 { 292 // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; 293 const f64 inv = 1.0f - d; 294 const f64 mul0 = inv * inv; 295 const f64 mul1 = 2.0f * d * inv; 296 const f64 mul2 = d * d; 297 298 return vector2d<T> ( (T)(X * mul0 + v2.X * mul1 + v3.X * mul2), 299 (T)(Y * mul0 + v2.Y * mul1 + v3.Y * mul2)); 300 } 301 302 //! Sets this vector to the linearly interpolated vector between a and b. 303 /** \param a first vector to interpolate with, maximum at 1.0f 304 \param b second vector to interpolate with, maximum at 0.0f 305 \param d Interpolation value between 0.0f (all vector b) and 1.0f (all vector a) 306 Note that this is the opposite direction of interpolation to getInterpolated_quadratic() 307 */ interpolate(const vector2d<T> & a,const vector2d<T> & b,f64 d)308 vector2d<T>& interpolate(const vector2d<T>& a, const vector2d<T>& b, f64 d) 309 { 310 X = (T)((f64)b.X + ( ( a.X - b.X ) * d )); 311 Y = (T)((f64)b.Y + ( ( a.Y - b.Y ) * d )); 312 return *this; 313 } 314 315 //! X coordinate of vector. 316 T X; 317 318 //! Y coordinate of vector. 319 T Y; 320 }; 321 322 //! Typedef for f32 2d vector. 323 typedef vector2d<f32> vector2df; 324 325 //! Typedef for integer 2d vector. 326 typedef vector2d<s32> vector2di; 327 328 template<class S, class T> 329 vector2d<T> operator*(const S scalar, const vector2d<T>& vector) { return vector*scalar; } 330 331 // These methods are declared in dimension2d, but need definitions of vector2d 332 template<class T> dimension2d(const vector2d<T> & other)333 dimension2d<T>::dimension2d(const vector2d<T>& other) : Width(other.X), Height(other.Y) { } 334 335 template<class T> 336 bool dimension2d<T>::operator==(const vector2d<T>& other) const { return Width == other.X && Height == other.Y; } 337 338 } // end namespace core 339 } // end namespace irr 340 341 #endif 342 343