Gamedev Framework (gf)  0.3.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 position of the rectangle
151  *
152  * It is a synonym for the `position` member
153  *
154  * @return The position of the rectangle
155  * @sa getSize()
156  */
157  constexpr Vector<T, 2> getPosition() const noexcept {
158  return position;
159  }
160 
161  /**
162  * @brief Get the size of the rectangle
163  *
164  * It is a synonym for the `size` member
165  *
166  * @return The size of the rectangle
167  * @sa getPosition()
168  */
169  constexpr Vector<T, 2> getSize() const noexcept {
170  return size;
171  }
172 
173  /**
174  * @brief Check if the rectangle is empty
175  *
176  * An empty rectangle is a rectangle that has one of its size coordinates
177  * that is zero.
178  *
179  * @return True if the rectangle is empty
180  */
181  constexpr bool isEmpty() const noexcept {
182  return width == 0 || height == 0;
183  }
184 
185  /**
186  * @brief Get the center of the rectangle
187  *
188  * @return The center of the rectangle
189  */
190  constexpr Vector<T, 2> getCenter() const noexcept {
191  return { left + width / 2, top + height / 2 };
192  }
193 
194  /**
195  * @brief Get the top left corner
196  *
197  * @return The top left corner
198  */
199  constexpr Vector<T, 2> getTopLeft() const noexcept {
200  return { left, top };
201  }
202 
203  /**
204  * @brief Get the top right corner
205  *
206  * @return The top right corner
207  */
208  constexpr Vector<T, 2> getTopRight() const noexcept {
209  return { left + width, top };
210  }
211 
212  /**
213  * @brief Get the bottom left corner
214  *
215  * @return The bottom left corner
216  */
217  constexpr Vector<T, 2> getBottomLeft() const noexcept {
218  return { left, top + height };
219  }
220 
221  /**
222  * @brief Get the bottom right corner
223  *
224  * @return The bottom right corner
225  */
226  constexpr Vector<T, 2> getBottomRight() const noexcept {
227  return { left + width, top + height };
228  }
229 
230 
231  /**
232  * @brief Check if a point is inside the rectangle's area
233  *
234  * @param point Point to test
235  * @return True if the point is inside, false otherwise
236  * @sa intersects()
237  */
238  constexpr bool contains(const Vector<T, 2>& point) const noexcept {
239  return left <= point.x && point.x < left + width && top <= point.y && point.y < top + height;
240  }
241 
242  /**
243  * @brief Check if a rectangle is inside the rectangle's area
244  *
245  * @param other Rectangle to test
246  * @return True if the rectangle is inside, false otherwise
247  * @sa intersects()
248  */
249  constexpr bool contains(const Rect<T>& other) const noexcept {
250  return left <= other.left && other.left + other.width <= left + width
251  && top <= other.top && other.top + other.height <= top + height;
252  }
253 
254  /**
255  * @brief Check the intersection between two rectangles
256  *
257  * @param other Rectangle to test
258  * @return True if rectangles overlap, false otherwise
259  * @sa contains()
260  */
261  constexpr bool intersects(const Rect<T>& other) const noexcept {
262  return left + width > other.left && left < other.left + other.width
263  && top + height > other.top && top < other.top + other.height;
264  }
265 
266  /**
267  * @brief Check the intersection between two rectangles
268  *
269  * This overload returns the overlapped rectangle in the
270  * `result` parameter.
271  *
272  * @param other Rectangle to test
273  * @param result Rectangle to be filled with the intersection
274  * @return True if rectangles overlap, false otherwise
275  * @sa contains
276  */
277  bool intersects(const Rect<T>& other, Rect<T>& result) const noexcept {
278  if (!intersects(other)) {
279  result = Rect<T>();
280  return false;
281  }
282 
283  T resultLeft = std::max(left, other.left);
284  T resultTop = std::max(top, other.top);
285  T resultRight = std::min(left + width, other.left + other.width);
286  T resultBottom = std::min(top + height, other.top + other.height);
287 
288  result = Rect<T>(resultLeft, resultTop, resultRight - resultLeft, resultBottom - resultTop);
289  return true;
290  }
291 
292  /**
293  * @brief Extend the rectangle
294  *
295  * @param value The amount to extend
296  * @return A new extended rectangle
297  * @sa shrink()
298  */
299  constexpr Rect<T> extend(T value) const noexcept {
300  return Rect<T>(left - value, top - value, width + 2 * value, height + 2 * value);
301  }
302 
303  /**
304  * @brief Shrink the rectangle
305  *
306  * @param value The amount to shrink
307  * @return A new shrinked rectangle
308  * @sa extend()
309  */
310  constexpr Rect<T> shrink(T value) const noexcept {
311  return Rect<T>(left + value, top + value, width - 2 * value, height - 2 * value);
312  }
313  };
314 
315  /**
316  * @ingroup core
317  * @brief A `float` rectangle
318  */
319  using RectF = Rect<float>;
320 
321  /**
322  * @ingroup core
323  * @brief A `int` rectangle
324  */
325  using RectI = Rect<int>;
326 
327  /**
328  * @ingroup core
329  * @brief A `unsigned` rectangle
330  */
331  using RectU = Rect<unsigned>;
332 
333  /**
334  * @ingroup core
335  * @brief A `std::size_t` rectangle
336  */
337  using RectZ = Rect<std::size_t>;
338 
339 // MSVC does not like extern template
340 #ifndef _MSC_VER
341  extern template struct Rect<float>;
342  extern template struct Rect<int>;
343  extern template struct Rect<unsigned>;
344 #endif
345 
346  /**
347  * @relates Rect
348  * @brief Equality operator
349  *
350  * @param lhs First rectangle
351  * @param rhs Second rectangle
352  * @return True if the two rectangles are the same
353  */
354  template<typename T>
355  inline
356  bool operator==(const Rect<T>& lhs, const Rect<T>& rhs) {
357  return lhs.position == rhs.position && lhs.size == rhs.size;
358  }
359 
360  /**
361  * @relates Rect
362  * @brief Inequality operator
363  *
364  * @param lhs First rectangle
365  * @param rhs Second rectangle
366  * @return True if the two rectangles are different
367  */
368  template<typename T>
369  inline
370  bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs) {
371  return lhs.position != rhs.position || lhs.size != rhs.size;
372  }
373 
374 #ifndef DOXYGEN_SHOULD_SKIP_THIS
375 }
376 #endif
377 }
378 
379 #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:217
bool operator!=(const Rect< T > &lhs, const Rect< T > &rhs)
Inequality operator.
Definition: Rect.h:370
constexpr bool isEmpty() const noexcept
Check if the rectangle is empty.
Definition: Rect.h:181
bool intersects(const Rect< T > &other, Rect< T > &result) const noexcept
Check the intersection between two rectangles.
Definition: Rect.h:277
constexpr Vector< T, 2 > getPosition() const noexcept
Get the position of the rectangle.
Definition: Rect.h:157
constexpr Rect< T > extend(T value) const noexcept
Extend the rectangle.
Definition: Rect.h:299
constexpr bool intersects(const Rect< T > &other) const noexcept
Check the intersection between two rectangles.
Definition: Rect.h:261
constexpr bool contains(const Rect< T > &other) const noexcept
Check if a rectangle is inside the rectangle's area.
Definition: Rect.h:249
constexpr Vector< T, 2 > getTopRight() const noexcept
Get the top right corner.
Definition: Rect.h:208
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:310
constexpr Vector< T, 2 > getCenter() const noexcept
Get the center of the rectangle.
Definition: Rect.h:190
constexpr Rect() noexcept
Default constructor.
Definition: Rect.h:111
constexpr Vector< T, 2 > getTopLeft() const noexcept
Get the top left corner.
Definition: Rect.h:199
constexpr Vector< T, 2 > getBottomRight() const noexcept
Get the bottom right corner.
Definition: Rect.h:226
constexpr bool contains(const Vector< T, 2 > &point) const noexcept
Check if a point is inside the rectangle's area.
Definition: Rect.h:238
constexpr Vector< T, 2 > getSize() const noexcept
Get the size of the rectangle.
Definition: Rect.h:169
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:60
bool operator==(const Rect< T > &lhs, const Rect< T > &rhs)
Equality operator.
Definition: Rect.h:356