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_RECT_H_INCLUDED__
6 #define __IRR_RECT_H_INCLUDED__
7 
8 #include "irrTypes.h"
9 #include "dimension2d.h"
10 #include "position2d.h"
11 
12 namespace irr
13 {
14 namespace core
15 {
16 
17 	//! Rectangle template.
18 	/** Mostly used by 2D GUI elements and for 2D drawing methods.
19 	It has 2 positions instead of position and dimension and a fast
20 	method for collision detection with other rectangles and points.
21 
22 	Coordinates are (0,0) for top-left corner, and increasing to the right
23 	and to the bottom.
24 	*/
25 	template <class T>
26 	class rect
27 	{
28 	public:
29 
30 		//! Default constructor creating empty rectangle at (0,0)
rect()31 		rect() : UpperLeftCorner(0,0), LowerRightCorner(0,0) {}
32 
33 		//! Constructor with two corners
rect(T x,T y,T x2,T y2)34 		rect(T x, T y, T x2, T y2)
35 			: UpperLeftCorner(x,y), LowerRightCorner(x2,y2) {}
36 
37 		//! Constructor with two corners
rect(const position2d<T> & upperLeft,const position2d<T> & lowerRight)38 		rect(const position2d<T>& upperLeft, const position2d<T>& lowerRight)
39 			: UpperLeftCorner(upperLeft), LowerRightCorner(lowerRight) {}
40 
41 		//! Constructor with upper left corner and dimension
42 		template <class U>
rect(const position2d<T> & pos,const dimension2d<U> & size)43 		rect(const position2d<T>& pos, const dimension2d<U>& size)
44 			: UpperLeftCorner(pos), LowerRightCorner(pos.X + size.Width, pos.Y + size.Height) {}
45 
46 		//! move right by given numbers
47 		rect<T> operator+(const position2d<T>& pos) const
48 		{
49 			rect<T> ret(*this);
50 			return ret+=pos;
51 		}
52 
53 		//! move right by given numbers
54 		rect<T>& operator+=(const position2d<T>& pos)
55 		{
56 			UpperLeftCorner += pos;
57 			LowerRightCorner += pos;
58 			return *this;
59 		}
60 
61 		//! move left by given numbers
62 		rect<T> operator-(const position2d<T>& pos) const
63 		{
64 			rect<T> ret(*this);
65 			return ret-=pos;
66 		}
67 
68 		//! move left by given numbers
69 		rect<T>& operator-=(const position2d<T>& pos)
70 		{
71 			UpperLeftCorner -= pos;
72 			LowerRightCorner -= pos;
73 			return *this;
74 		}
75 
76 		//! equality operator
77 		bool operator==(const rect<T>& other) const
78 		{
79 			return (UpperLeftCorner == other.UpperLeftCorner &&
80 				LowerRightCorner == other.LowerRightCorner);
81 		}
82 
83 		//! inequality operator
84 		bool operator!=(const rect<T>& other) const
85 		{
86 			return (UpperLeftCorner != other.UpperLeftCorner ||
87 				LowerRightCorner != other.LowerRightCorner);
88 		}
89 
90 		//! compares size of rectangles
91 		bool operator<(const rect<T>& other) const
92 		{
93 			return getArea() < other.getArea();
94 		}
95 
96 		//! Returns size of rectangle
getArea()97 		T getArea() const
98 		{
99 			return getWidth() * getHeight();
100 		}
101 
102 		//! Returns if a 2d point is within this rectangle.
103 		/** \param pos Position to test if it lies within this rectangle.
104 		\return True if the position is within the rectangle, false if not. */
isPointInside(const position2d<T> & pos)105 		bool isPointInside(const position2d<T>& pos) const
106 		{
107 			return (UpperLeftCorner.X <= pos.X &&
108 				UpperLeftCorner.Y <= pos.Y &&
109 				LowerRightCorner.X >= pos.X &&
110 				LowerRightCorner.Y >= pos.Y);
111 		}
112 
113 		//! Check if the rectangle collides with another rectangle.
114 		/** \param other Rectangle to test collision with
115 		\return True if the rectangles collide. */
isRectCollided(const rect<T> & other)116 		bool isRectCollided(const rect<T>& other) const
117 		{
118 			return (LowerRightCorner.Y > other.UpperLeftCorner.Y &&
119 				UpperLeftCorner.Y < other.LowerRightCorner.Y &&
120 				LowerRightCorner.X > other.UpperLeftCorner.X &&
121 				UpperLeftCorner.X < other.LowerRightCorner.X);
122 		}
123 
124 		//! Clips this rectangle with another one.
125 		/** \param other Rectangle to clip with */
clipAgainst(const rect<T> & other)126 		void clipAgainst(const rect<T>& other)
127 		{
128 			if (other.LowerRightCorner.X < LowerRightCorner.X)
129 				LowerRightCorner.X = other.LowerRightCorner.X;
130 			if (other.LowerRightCorner.Y < LowerRightCorner.Y)
131 				LowerRightCorner.Y = other.LowerRightCorner.Y;
132 
133 			if (other.UpperLeftCorner.X > UpperLeftCorner.X)
134 				UpperLeftCorner.X = other.UpperLeftCorner.X;
135 			if (other.UpperLeftCorner.Y > UpperLeftCorner.Y)
136 				UpperLeftCorner.Y = other.UpperLeftCorner.Y;
137 
138 			// correct possible invalid rect resulting from clipping
139 			if (UpperLeftCorner.Y > LowerRightCorner.Y)
140 				UpperLeftCorner.Y = LowerRightCorner.Y;
141 			if (UpperLeftCorner.X > LowerRightCorner.X)
142 				UpperLeftCorner.X = LowerRightCorner.X;
143 		}
144 
145 		//! Moves this rectangle to fit inside another one.
146 		/** \return True on success, false if not possible */
constrainTo(const rect<T> & other)147 		bool constrainTo(const rect<T>& other)
148 		{
149 			if (other.getWidth() < getWidth() || other.getHeight() < getHeight())
150 				return false;
151 
152 			T diff = other.LowerRightCorner.X - LowerRightCorner.X;
153 			if (diff < 0)
154 			{
155 				LowerRightCorner.X += diff;
156 				UpperLeftCorner.X  += diff;
157 			}
158 
159 			diff = other.LowerRightCorner.Y - LowerRightCorner.Y;
160 			if (diff < 0)
161 			{
162 				LowerRightCorner.Y += diff;
163 				UpperLeftCorner.Y  += diff;
164 			}
165 
166 			diff = UpperLeftCorner.X - other.UpperLeftCorner.X;
167 			if (diff < 0)
168 			{
169 				UpperLeftCorner.X  -= diff;
170 				LowerRightCorner.X -= diff;
171 			}
172 
173 			diff = UpperLeftCorner.Y - other.UpperLeftCorner.Y;
174 			if (diff < 0)
175 			{
176 				UpperLeftCorner.Y  -= diff;
177 				LowerRightCorner.Y -= diff;
178 			}
179 
180 			return true;
181 		}
182 
183 		//! Get width of rectangle.
getWidth()184 		T getWidth() const
185 		{
186 			return LowerRightCorner.X - UpperLeftCorner.X;
187 		}
188 
189 		//! Get height of rectangle.
getHeight()190 		T getHeight() const
191 		{
192 			return LowerRightCorner.Y - UpperLeftCorner.Y;
193 		}
194 
195 		//! If the lower right corner of the rect is smaller then the upper left, the points are swapped.
repair()196 		void repair()
197 		{
198 			if (LowerRightCorner.X < UpperLeftCorner.X)
199 			{
200 				T t = LowerRightCorner.X;
201 				LowerRightCorner.X = UpperLeftCorner.X;
202 				UpperLeftCorner.X = t;
203 			}
204 
205 			if (LowerRightCorner.Y < UpperLeftCorner.Y)
206 			{
207 				T t = LowerRightCorner.Y;
208 				LowerRightCorner.Y = UpperLeftCorner.Y;
209 				UpperLeftCorner.Y = t;
210 			}
211 		}
212 
213 		//! Returns if the rect is valid to draw.
214 		/** It would be invalid if the UpperLeftCorner is lower or more
215 		right than the LowerRightCorner. */
isValid()216 		bool isValid() const
217 		{
218 			return ((LowerRightCorner.X >= UpperLeftCorner.X) &&
219 				(LowerRightCorner.Y >= UpperLeftCorner.Y));
220 		}
221 
222 		//! Get the center of the rectangle
getCenter()223 		position2d<T> getCenter() const
224 		{
225 			return position2d<T>(
226 					(UpperLeftCorner.X + LowerRightCorner.X) / 2,
227 					(UpperLeftCorner.Y + LowerRightCorner.Y) / 2);
228 		}
229 
230 		//! Get the dimensions of the rectangle
getSize()231 		dimension2d<T> getSize() const
232 		{
233 			return dimension2d<T>(getWidth(), getHeight());
234 		}
235 
236 
237 		//! Adds a point to the rectangle
238 		/** Causes the rectangle to grow bigger if point is outside of
239 		the box
240 		\param p Point to add to the box. */
addInternalPoint(const position2d<T> & p)241 		void addInternalPoint(const position2d<T>& p)
242 		{
243 			addInternalPoint(p.X, p.Y);
244 		}
245 
246 		//! Adds a point to the bounding rectangle
247 		/** Causes the rectangle to grow bigger if point is outside of
248 		the box
249 		\param x X-Coordinate of the point to add to this box.
250 		\param y Y-Coordinate of the point to add to this box. */
addInternalPoint(T x,T y)251 		void addInternalPoint(T x, T y)
252 		{
253 			if (x>LowerRightCorner.X)
254 				LowerRightCorner.X = x;
255 			if (y>LowerRightCorner.Y)
256 				LowerRightCorner.Y = y;
257 
258 			if (x<UpperLeftCorner.X)
259 				UpperLeftCorner.X = x;
260 			if (y<UpperLeftCorner.Y)
261 				UpperLeftCorner.Y = y;
262 		}
263 
264 		//! Upper left corner
265 		position2d<T> UpperLeftCorner;
266 		//! Lower right corner
267 		position2d<T> LowerRightCorner;
268 	};
269 
270 	//! Rectangle with float values
271 	typedef rect<f32> rectf;
272 	//! Rectangle with int values
273 	typedef rect<s32> recti;
274 
275 } // end namespace core
276 } // end namespace irr
277 
278 #endif
279 
280