Gamedev Framework (gf)  0.1.0
A C++11 framework for 2D games
Rect.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016 Julien Bernard
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  *
21  * Part of this file comes from SFML, with the same license:
22  * Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org)
23  */
24 #ifndef GF_RECT_H
25 #define GF_RECT_H
26 
27 #include <cstddef>
28 #include <algorithm>
29 
30 #include "Portability.h"
31 #include "Vector.h"
32 
33 namespace gf {
34 #ifndef DOXYGEN_SHOULD_SKIP_THIS
35 inline namespace v1 {
36 #endif
37 
38  /**
39  * @ingroup core
40  * @brief Utility class for manipulating 2D axis aligned rectangles
41  *
42  * A rectangle is defined by its top-left corner and its size.
43  * It is a very simple class defined for convenience, so
44  * its member variables (`left`, `top`, `width` and `height`) are public
45  * and can be accessed directly. You can also access the `position`
46  * and the `size` of the rectangle directly as gf::Vector.
47  *
48  * gf::Rect uses the usual rules for its boundaries:
49  *
50  * - The left and top edges are included in the rectangle's area
51  * - The right (left + width) and bottom (top + height) edges are excluded from the rectangle's area
52  *
53  * This means that gf::RectI(0, 0, 1, 1) and gf::RectI(1, 1, 1, 1)
54  * don't intersect.
55  *
56  * gf::Rect is a template and may be used with any numeric type, but
57  * for simplicity, some common typedef are defined:
58  *
59  * - gf::RectI with `int` as `T`
60  * - gf::RectU with `unsigned` as `T`
61  * - gf::RectZ with `std::size_t` as `T`
62  * - gf::RectF with `float` as `T`
63  *
64  * So that you don't have to care about the template syntax.
65  *
66  * Usage example:
67  *
68  * ~~~{.cc}
69  * // Define a rectangle, located at (0, 0) with a size of 20x5
70  * gf::RectI r1(0, 0, 20, 5);
71  *
72  * // Define another rectangle, located at (4, 2) with a size of 18x10
73  * gf::Vector2i position(4, 2);
74  * gf::Vector2i size(18, 10);
75  * gf::RectI r2(position, size);
76  *
77  * // Test intersections with the point (3, 1)
78  * bool b1 = r1.contains({ 3, 1 }); // true
79  * bool b2 = r2.contains({ 3, 1 }); // false
80  *
81  * // Test the intersection between r1 and r2
82  * gf::RectI result;
83  * bool b3 = r1.intersects(r2, result); // true
84  * // result == (4, 2, 16, 3)
85  * ~~~
86  */
87  template<typename T>
88  struct Rect {
89  /**
90  * An anonymous union to handle the various representations
91  */
92  union {
93  struct {
94  T left; ///< Left coordinate of the rectangle
95  T top; ///< Top coordinate of the rectangle
96  T width; ///< Width of the rectangle
97  T height; ///< Height of the rectangle
98  };
99  struct {
100  Vector<T, 2> position; ///< Position of the rectangle
101  Vector<T, 2> size; ///< Size of the rectangle
102  };
103  };
104 
105  /**
106  * @brief Default constructor
107  *
108  * Creates an empty rectangle (it is equivalent to calling
109  * `Rect(0, 0, 0, 0)`).
110  */
111  constexpr Rect() noexcept
112  : left{0}, top{0}, width{0}, height{0}
113  {
114 
115  }
116 
117  /**
118  * @brief Construct the rectangle from its coordinates
119  *
120  * Be careful, the last two parameters are the width
121  * and height, not the right and bottom coordinates!
122  *
123  * @param rectLeft Left coordinate of the rectangle
124  * @param rectTop Top coordinate of the rectangle
125  * @param rectWidth Width of the rectangle
126  * @param rectHeight Height of the rectangle
127  */
128  constexpr Rect(T rectLeft, T rectTop, T rectWidth, T rectHeight) noexcept
129  : left{rectLeft}, top{rectTop}, width{rectWidth}, height{rectHeight}
130  {
131 
132  }
133 
134  /**
135  * @brief Construct the rectangle from position and size
136  *
137  * Be careful, the last parameter is the size,
138  * not the bottom-right corner!
139  *
140  * @param rectPosition Position of the top left corner of the rectangle
141  * @param rectSize Size of the rectangle
142  */
143  Rect(const Vector<T, 2>& rectPosition, const Vector<T, 2>& rectSize) noexcept
144  : position(rectPosition), size(rectSize)
145  {
146 
147  }
148 
149  /**
150  * @brief Get the size of the rectangle
151  *
152  * It is a synonym for the `size` member
153  *
154  * @return The size of the rectangle
155  */
156  constexpr Vector<T, 2> getSize() const noexcept {
157  return size;
158  }
159 
160  /**
161  * @brief Check if the rectangle is empty
162  *
163  * An empty rectangle is a rectangle that has one of its size coordinates
164  * that is zero.
165  *
166  * @return True if the rectangle is empty
167  */
168  constexpr bool isEmpty() const noexcept {
169  return width == 0 || height == 0;
170  }
171 
172  /**
173  * @brief Get the center of the rectangle
174  *
175  * @return The center of the rectangle
176  */
177  constexpr Vector<T, 2> getCenter() const noexcept {
178  return { left + width / 2, top + height / 2 };
179  }
180 
181  /**
182  * @brief Get the top left corner
183  *
184  * @return The top left corner
185  */
186  constexpr Vector<T, 2> getTopLeft() const noexcept {
187  return { left, top };
188  }
189 
190  /**
191  * @brief Get the top right corner
192  *
193  * @return The top right corner
194  */
195  constexpr Vector<T, 2> getTopRight() const noexcept {
196  return { left + width, top };
197  }
198 
199  /**
200  * @brief Get the bottom left corner
201  *
202  * @return The bottom left corner
203  */
204  constexpr Vector<T, 2> getBottomLeft() const noexcept {
205  return { left, top + height };
206  }
207 
208  /**
209  * @brief Get the bottom right corner
210  *
211  * @return The bottom right corner
212  */
213  constexpr Vector<T, 2> getBottomRight() const noexcept {
214  return { left + width, top + height };
215  }
216 
217 
218  /**
219  * @brief Check if a point is inside the rectangle's area
220  *
221  * @param point Point to test
222  * @return True if the point is inside, false otherwise
223  * @sa intersects()
224  */
225  constexpr bool contains(const Vector<T, 2>& point) const noexcept {
226  return left <= point.x && point.x < left + width && top <= point.y && point.y < top + height;
227  }
228 
229  /**
230  * @brief Check if a rectangle is inside the rectangle's area
231  *
232  * @param other Rectangle to test
233  * @return True if the rectangle is inside, false otherwise
234  * @sa intersects()
235  */
236  constexpr bool contains(const Rect<T>& other) const noexcept {
237  return left <= other.left && other.left + other.width <= left + width
238  && top <= other.top && other.top + other.height <= top + height;
239  }
240 
241  /**
242  * @brief Check the intersection between two rectangles
243  *
244  * @param other Rectangle to test
245  * @return True if rectangles overlap, false otherwise
246  * @sa contains()
247  */
248  constexpr bool intersects(const Rect<T>& other) const noexcept {
249  return left + width > other.left && left < other.left + other.width
250  && top + height > other.top && top < other.top + other.height;
251  }
252 
253  /**
254  * @brief Check the intersection between two rectangles
255  *
256  * This overload returns the overlapped rectangle in the
257  * `result` parameter.
258  *
259  * @param other Rectangle to test
260  * @param result Rectangle to be filled with the intersection
261  * @return True if rectangles overlap, false otherwise
262  * @sa contains
263  */
264  bool intersects(const Rect<T>& other, Rect<T>& result) const noexcept {
265  if (!intersects(other)) {
266  result = Rect<T>();
267  return false;
268  }
269 
270  T resultLeft = std::max(left, other.left);
271  T resultTop = std::max(top, other.top);
272  T resultRight = std::min(left + width, other.left + other.width);
273  T resultBottom = std::min(top + height, other.top + other.height);
274 
275  result = Rect<T>(resultLeft, resultTop, resultRight - resultLeft, resultBottom - resultTop);
276  return true;
277  }
278 
279  /**
280  * @brief Extend the rectangle
281  *
282  * @param value The amount to extend
283  * @return A new extended rectangle
284  * @sa shrink()
285  */
286  constexpr Rect<T> extend(T value) const noexcept {
287  return Rect<T>(left - value, top - value, width + 2 * value, height + 2 * value);
288  }
289 
290  /**
291  * @brief Shrink the rectangle
292  *
293  * @param value The amount to shrink
294  * @return A new shrinked rectangle
295  * @sa extend()
296  */
297  constexpr Rect<T> shrink(T value) const noexcept {
298  return Rect<T>(left + value, top + value, width - 2 * value, height - 2 * value);
299  }
300  };
301 
302  /**
303  * @ingroup core
304  * @brief A `float` rectangle
305  */
306  typedef Rect<float> RectF;
307 
308  /**
309  * @ingroup core
310  * @brief A `int` rectangle
311  */
312  typedef Rect<int> RectI;
313 
314  /**
315  * @ingroup core
316  * @brief A `unsigned` rectangle
317  */
318  typedef Rect<unsigned> RectU;
319 
320  /**
321  * @ingroup core
322  * @brief A `std::size_t` rectangle
323  */
324  typedef Rect<std::size_t> RectZ;
325 
326 // MSVC does not like extern template
327 #ifndef _MSC_VER
328  extern template struct Rect<float>;
329  extern template struct Rect<int>;
330  extern template struct Rect<unsigned>;
331  extern template struct Rect<std::size_t>;
332 #endif
333 
334  /**
335  * @relates Rect
336  * @brief Equality operator
337  *
338  * @param lhs First rectangle
339  * @param rhs Second rectangle
340  * @return True if the two rectangle are the same
341  */
342  template<typename T>
343  inline
344  bool operator==(const Rect<T>& lhs, const Rect<T>& rhs) {
345  return lhs.position == rhs.position && lhs.size == rhs.size;
346  }
347 
348  /**
349  * @relates Rect
350  * @brief Inequality operator
351  *
352  * @param lhs First rectangle
353  * @param rhs Second rectangle
354  * @return True if the two rectangle are different
355  */
356  template<typename T>
357  inline
358  bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs) {
359  return lhs.position != rhs.position || lhs.size != rhs.size;
360  }
361 
362 #ifndef DOXYGEN_SHOULD_SKIP_THIS
363 }
364 #endif
365 }
366 
367 #endif // GF_RECT_H
Rect(const Vector< T, 2 > &rectPosition, const Vector< T, 2 > &rectSize) noexcept
Construct the rectangle from position and size.
Definition: Rect.h:143
constexpr Vector< T, 2 > getBottomLeft() const noexcept
Get the bottom left corner.
Definition: Rect.h:204
Rect< unsigned > RectU
A unsigned rectangle.
Definition: Rect.h:318
bool operator!=(const Rect< T > &lhs, const Rect< T > &rhs)
Inequality operator.
Definition: Rect.h:358
constexpr bool isEmpty() const noexcept
Check if the rectangle is empty.
Definition: Rect.h:168
bool intersects(const Rect< T > &other, Rect< T > &result) const noexcept
Check the intersection between two rectangles.
Definition: Rect.h:264
Rect< int > RectI
A int rectangle.
Definition: Rect.h:312
constexpr Rect< T > extend(T value) const noexcept
Extend the rectangle.
Definition: Rect.h:286
constexpr bool intersects(const Rect< T > &other) const noexcept
Check the intersection between two rectangles.
Definition: Rect.h:248
constexpr bool contains(const Rect< T > &other) const noexcept
Check if a rectangle is inside the rectangle's area.
Definition: Rect.h:236
Rect< float > RectF
A float rectangle.
Definition: Rect.h:306
constexpr Vector< T, 2 > getTopRight() const noexcept
Get the top right corner.
Definition: Rect.h:195
Utility class for manipulating 2D axis aligned rectangles.
Definition: Rect.h:88
Definition: Action.h:34
constexpr Rect< T > shrink(T value) const noexcept
Shrink the rectangle.
Definition: Rect.h:297
constexpr Vector< T, 2 > getCenter() const noexcept
Get the center of the rectangle.
Definition: Rect.h:177
constexpr Rect() noexcept
Default constructor.
Definition: Rect.h:111
constexpr Vector< T, 2 > getTopLeft() const noexcept
Get the top left corner.
Definition: Rect.h:186
constexpr Vector< T, 2 > getBottomRight() const noexcept
Get the bottom right corner.
Definition: Rect.h:213
constexpr bool contains(const Vector< T, 2 > &point) const noexcept
Check if a point is inside the rectangle's area.
Definition: Rect.h:225
constexpr Vector< T, 2 > getSize() const noexcept
Get the size of the rectangle.
Definition: Rect.h:156
constexpr Rect(T rectLeft, T rectTop, T rectWidth, T rectHeight) noexcept
Construct the rectangle from its coordinates.
Definition: Rect.h:128
General purpose math vector.
Definition: Vector.h:61
bool operator==(const Rect< T > &lhs, const Rect< T > &rhs)
Equality operator.
Definition: Rect.h:344
Rect< std::size_t > RectZ
A std::size_t rectangle.
Definition: Rect.h:324