aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8.1/include/rect.h
blob: 3f3883ea5b037dfa9b89cf0e67565359d6876bc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef __IRR_RECT_H_INCLUDED__
#define __IRR_RECT_H_INCLUDED__

#include "irrTypes.h"
#include "dimension2d.h"
#include "position2d.h"

namespace irr
{
namespace core
{

	//! Rectangle template.
	/** Mostly used by 2D GUI elements and for 2D drawing methods.
	It has 2 positions instead of position and dimension and a fast
	method for collision detection with other rectangles and points.

	Coordinates are (0,0) for top-left corner, and increasing to the right
	and to the bottom.
	*/
	template <class T>
	class rect
	{
	public:

		//! Default constructor creating empty rectangle at (0,0)
		rect() : UpperLeftCorner(0,0), LowerRightCorner(0,0) {}

		//! Constructor with two corners
		rect(T x, T y, T x2, T y2)
			: UpperLeftCorner(x,y), LowerRightCorner(x2,y2) {}

		//! Constructor with two corners
		rect(const position2d<T>& upperLeft, const position2d<T>& lowerRight)
			: UpperLeftCorner(upperLeft), LowerRightCorner(lowerRight) {}

		//! Constructor with upper left corner and dimension
		template <class U>
		rect(const position2d<T>& pos, const dimension2d<U>& size)
			: UpperLeftCorner(pos), LowerRightCorner(pos.X + size.Width, pos.Y + size.Height) {}

		//! move right by given numbers
		rect<T> operator+(const position2d<T>& pos) const
		{
			rect<T> ret(*this);
			return ret+=pos;
		}

		//! move right by given numbers
		rect<T>& operator+=(const position2d<T>& pos)
		{
			UpperLeftCorner += pos;
			LowerRightCorner += pos;
			return *this;
		}

		//! move left by given numbers
		rect<T> operator-(const position2d<T>& pos) const
		{
			rect<T> ret(*this);
			return ret-=pos;
		}

		//! move left by given numbers
		rect<T>& operator-=(const position2d<T>& pos)
		{
			UpperLeftCorner -= pos;
			LowerRightCorner -= pos;
			return *this;
		}

		//! equality operator
		bool operator==(const rect<T>& other) const
		{
			return (UpperLeftCorner == other.UpperLeftCorner &&
				LowerRightCorner == other.LowerRightCorner);
		}

		//! inequality operator
		bool operator!=(const rect<T>& other) const
		{
			return (UpperLeftCorner != other.UpperLeftCorner ||
				LowerRightCorner != other.LowerRightCorner);
		}

		//! compares size of rectangles
		bool operator<(const rect<T>& other) const
		{
			return getArea() < other.getArea();
		}

		//! Returns size of rectangle
		T getArea() const
		{
			return getWidth() * getHeight();
		}

		//! Returns if a 2d point is within this rectangle.
		/** \param pos Position to test if it lies within this rectangle.
		\return True if the position is within the rectangle, false if not. */
		bool isPointInside(const position2d<T>& pos) const
		{
			return (UpperLeftCorner.X <= pos.X &&
				UpperLeftCorner.Y <= pos.Y &&
				LowerRightCorner.X >= pos.X &&
				LowerRightCorner.Y >= pos.Y);
		}

		//! Check if the rectangle collides with another rectangle.
		/** \param other Rectangle to test collision with
		\return True if the rectangles collide. */
		bool isRectCollided(const rect<T>& other) const
		{
			return (LowerRightCorner.Y > other.UpperLeftCorner.Y &&
				UpperLeftCorner.Y < other.LowerRightCorner.Y &&
				LowerRightCorner.X > other.UpperLeftCorner.X &&
				UpperLeftCorner.X < other.LowerRightCorner.X);
		}

		//! Clips this rectangle with another one.
		/** \param other Rectangle to clip with */
		void clipAgainst(const rect<T>& other)
		{
			if (other.LowerRightCorner.X < LowerRightCorner.X)
				LowerRightCorner.X = other.LowerRightCorner.X;
			if (other.LowerRightCorner.Y < LowerRightCorner.Y)
				LowerRightCorner.Y = other.LowerRightCorner.Y;

			if (other.UpperLeftCorner.X > UpperLeftCorner.X)
				UpperLeftCorner.X = other.UpperLeftCorner.X;
			if (other.UpperLeftCorner.Y > UpperLeftCorner.Y)
				UpperLeftCorner.Y = other.UpperLeftCorner.Y;

			// correct possible invalid rect resulting from clipping
			if (UpperLeftCorner.Y > LowerRightCorner.Y)
				UpperLeftCorner.Y = LowerRightCorner.Y;
			if (UpperLeftCorner.X > LowerRightCorner.X)
				UpperLeftCorner.X = LowerRightCorner.X;
		}

		//! Moves this rectangle to fit inside another one.
		/** \return True on success, false if not possible */
		bool constrainTo(const rect<T>& other)
		{
			if (other.getWidth() < getWidth() || other.getHeight() < getHeight())
				return false;

			T diff = other.LowerRightCorner.X - LowerRightCorner.X;
			if (diff < 0)
			{
				LowerRightCorner.X += diff;
				UpperLeftCorner.X  += diff;
			}

			diff = other.LowerRightCorner.Y - LowerRightCorner.Y;
			if (diff < 0)
			{
				LowerRightCorner.Y += diff;
				UpperLeftCorner.Y  += diff;
			}

			diff = UpperLeftCorner.X - other.UpperLeftCorner.X;
			if (diff < 0)
			{
				UpperLeftCorner.X  -= diff;
				LowerRightCorner.X -= diff;
			}

			diff = UpperLeftCorner.Y - other.UpperLeftCorner.Y;
			if (diff < 0)
			{
				UpperLeftCorner.Y  -= diff;
				LowerRightCorner.Y -= diff;
			}

			return true;
		}

		//! Get width of rectangle.
		T getWidth() const
		{
			return LowerRightCorner.X - UpperLeftCorner.X;
		}

		//! Get height of rectangle.
		T getHeight() const
		{
			return LowerRightCorner.Y - UpperLeftCorner.Y;
		}

		//! If the lower right corner of the rect is smaller then the upper left, the points are swapped.
		void repair()
		{
			if (LowerRightCorner.X < UpperLeftCorner.X)
			{
				T t = LowerRightCorner.X;
				LowerRightCorner.X = UpperLeftCorner.X;
				UpperLeftCorner.X = t;
			}

			if (LowerRightCorner.Y < UpperLeftCorner.Y)
			{
				T t = LowerRightCorner.Y;
				LowerRightCorner.Y = UpperLeftCorner.Y;
				UpperLeftCorner.Y = t;
			}
		}

		//! Returns if the rect is valid to draw.
		/** It would be invalid if the UpperLeftCorner is lower or more
		right than the LowerRightCorner. */
		bool isValid() const
		{
			return ((LowerRightCorner.X >= UpperLeftCorner.X) &&
				(LowerRightCorner.Y >= UpperLeftCorner.Y));
		}

		//! Get the center of the rectangle
		position2d<T> getCenter() const
		{
			return position2d<T>(
					(UpperLeftCorner.X + LowerRightCorner.X) / 2,
					(UpperLeftCorner.Y + LowerRightCorner.Y) / 2);
		}

		//! Get the dimensions of the rectangle
		dimension2d<T> getSize() const
		{
			return dimension2d<T>(getWidth(), getHeight());
		}


		//! Adds a point to the rectangle
		/** Causes the rectangle to grow bigger if point is outside of
		the box
		\param p Point to add to the box. */
		void addInternalPoint(const position2d<T>& p)
		{
			addInternalPoint(p.X, p.Y);
		}

		//! Adds a point to the bounding rectangle
		/** Causes the rectangle to grow bigger if point is outside of
		the box
		\param x X-Coordinate of the point to add to this box.
		\param y Y-Coordinate of the point to add to this box. */
		void addInternalPoint(T x, T y)
		{
			if (x>LowerRightCorner.X)
				LowerRightCorner.X = x;
			if (y>LowerRightCorner.Y)
				LowerRightCorner.Y = y;

			if (x<UpperLeftCorner.X)
				UpperLeftCorner.X = x;
			if (y<UpperLeftCorner.Y)
				UpperLeftCorner.Y = y;
		}

		//! Upper left corner
		position2d<T> UpperLeftCorner;
		//! Lower right corner
		position2d<T> LowerRightCorner;
	};

	//! Rectangle with float values
	typedef rect<f32> rectf;
	//! Rectangle with int values
	typedef rect<s32> recti;

} // end namespace core
} // end namespace irr

#endif