rect.h 7.2 KB

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