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