rect.h 7.4 KB

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