Rect.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #pragma once
  4. #include "../Math/Vector4.h"
  5. namespace Urho3D
  6. {
  7. /// Two-dimensional bounding rectangle.
  8. /// @allfloats
  9. class URHO3D_API Rect
  10. {
  11. public:
  12. /// Construct an undefined rect.
  13. Rect() noexcept :
  14. min_(M_INFINITY, M_INFINITY),
  15. max_(-M_INFINITY, -M_INFINITY)
  16. {
  17. }
  18. /// Construct from minimum and maximum vectors.
  19. Rect(const Vector2& min, const Vector2& max) noexcept :
  20. min_(min),
  21. max_(max)
  22. {
  23. }
  24. /// Construct from coordinates.
  25. Rect(float left, float top, float right, float bottom) noexcept :
  26. min_(left, top),
  27. max_(right, bottom)
  28. {
  29. }
  30. /// Construct from a Vector4.
  31. explicit Rect(const Vector4& vector) noexcept :
  32. min_(vector.x_, vector.y_),
  33. max_(vector.z_, vector.w_)
  34. {
  35. }
  36. /// Construct from a float array.
  37. explicit Rect(const float* data) noexcept :
  38. min_(data[0], data[1]),
  39. max_(data[2], data[3])
  40. {
  41. }
  42. /// Copy-construct from another rect.
  43. Rect(const Rect& rect) noexcept = default;
  44. /// Assign from another rect.
  45. Rect& operator =(const Rect& rhs) noexcept = default;
  46. /// Test for equality with another rect.
  47. bool operator ==(const Rect& rhs) const { return min_ == rhs.min_ && max_ == rhs.max_; }
  48. /// Test for inequality with another rect.
  49. bool operator !=(const Rect& rhs) const { return min_ != rhs.min_ || max_ != rhs.max_; }
  50. /// Add another rect to this one inplace.
  51. Rect& operator +=(const Rect& rhs)
  52. {
  53. min_ += rhs.min_;
  54. max_ += rhs.max_;
  55. return *this;
  56. }
  57. /// Subtract another rect from this one inplace.
  58. Rect& operator -=(const Rect& rhs)
  59. {
  60. min_ -= rhs.min_;
  61. max_ -= rhs.max_;
  62. return *this;
  63. }
  64. /// Divide by scalar inplace.
  65. Rect& operator /=(float value)
  66. {
  67. min_ /= value;
  68. max_ /= value;
  69. return *this;
  70. }
  71. /// Multiply by scalar inplace.
  72. Rect& operator *=(float value)
  73. {
  74. min_ *= value;
  75. max_ *= value;
  76. return *this;
  77. }
  78. /// Divide by scalar.
  79. Rect operator /(float value) const
  80. {
  81. return Rect(min_ / value, max_ / value);
  82. }
  83. /// Multiply by scalar.
  84. Rect operator *(float value) const
  85. {
  86. return Rect(min_ * value, max_ * value);
  87. }
  88. /// Add another rect.
  89. Rect operator +(const Rect& rhs) const
  90. {
  91. return Rect(min_ + rhs.min_, max_ + rhs.max_);
  92. }
  93. /// Subtract another rect.
  94. Rect operator -(const Rect& rhs) const
  95. {
  96. return Rect(min_ - rhs.min_, max_ - rhs.max_);
  97. }
  98. /// Define from another rect.
  99. void Define(const Rect& rect)
  100. {
  101. min_ = rect.min_;
  102. max_ = rect.max_;
  103. }
  104. /// Define from minimum and maximum vectors.
  105. void Define(const Vector2& min, const Vector2& max)
  106. {
  107. min_ = min;
  108. max_ = max;
  109. }
  110. /// Define from a point.
  111. void Define(const Vector2& point)
  112. {
  113. min_ = max_ = point;
  114. }
  115. /// Merge a point.
  116. void Merge(const Vector2& point)
  117. {
  118. if (point.x_ < min_.x_)
  119. min_.x_ = point.x_;
  120. if (point.x_ > max_.x_)
  121. max_.x_ = point.x_;
  122. if (point.y_ < min_.y_)
  123. min_.y_ = point.y_;
  124. if (point.y_ > max_.y_)
  125. max_.y_ = point.y_;
  126. }
  127. /// Merge a rect.
  128. void Merge(const Rect& rect)
  129. {
  130. if (rect.min_.x_ < min_.x_)
  131. min_.x_ = rect.min_.x_;
  132. if (rect.min_.y_ < min_.y_)
  133. min_.y_ = rect.min_.y_;
  134. if (rect.max_.x_ > max_.x_)
  135. max_.x_ = rect.max_.x_;
  136. if (rect.max_.y_ > max_.y_)
  137. max_.y_ = rect.max_.y_;
  138. }
  139. /// Clear to undefined state.
  140. void Clear()
  141. {
  142. min_ = Vector2(M_INFINITY, M_INFINITY);
  143. max_ = Vector2(-M_INFINITY, -M_INFINITY);
  144. }
  145. /// Clip with another rect.
  146. void Clip(const Rect& rect);
  147. /// Return true if this rect is defined via a previous call to Define() or Merge().
  148. bool Defined() const
  149. {
  150. return min_.x_ != M_INFINITY;
  151. }
  152. /// Return center.
  153. /// @property
  154. Vector2 Center() const { return (max_ + min_) * 0.5f; }
  155. /// Return size.
  156. /// @property
  157. Vector2 Size() const { return max_ - min_; }
  158. /// Return half-size.
  159. /// @property
  160. Vector2 HalfSize() const { return (max_ - min_) * 0.5f; }
  161. /// Test for equality with another rect with epsilon.
  162. bool Equals(const Rect& rhs) const { return min_.Equals(rhs.min_) && max_.Equals(rhs.max_); }
  163. /// Test whether a point is inside.
  164. Intersection IsInside(const Vector2& point) const
  165. {
  166. if (point.x_ < min_.x_ || point.y_ < min_.y_ || point.x_ > max_.x_ || point.y_ > max_.y_)
  167. return OUTSIDE;
  168. else
  169. return INSIDE;
  170. }
  171. /// Test if another rect is inside, outside or intersects.
  172. Intersection IsInside(const Rect& rect) const
  173. {
  174. if (rect.max_.x_ < min_.x_ || rect.min_.x_ > max_.x_ || rect.max_.y_ < min_.y_ || rect.min_.y_ > max_.y_)
  175. return OUTSIDE;
  176. else if (rect.min_.x_ < min_.x_ || rect.max_.x_ > max_.x_ || rect.min_.y_ < min_.y_ || rect.max_.y_ > max_.y_)
  177. return INTERSECTS;
  178. else
  179. return INSIDE;
  180. }
  181. /// Return float data.
  182. const float* Data() const { return &min_.x_; }
  183. /// Return as a vector.
  184. Vector4 ToVector4() const { return Vector4(min_.x_, min_.y_, max_.x_, max_.y_); }
  185. /// Return as string.
  186. String ToString() const;
  187. /// Return left-top corner position.
  188. Vector2 Min() const { return min_; }
  189. /// Return right-bottom corner position.
  190. Vector2 Max() const { return max_; }
  191. /// Return left coordinate.
  192. /// @property
  193. float Left() const { return min_.x_; }
  194. /// Return top coordinate.
  195. /// @property
  196. float Top() const { return min_.y_; }
  197. /// Return right coordinate.
  198. /// @property
  199. float Right() const { return max_.x_; }
  200. /// Return bottom coordinate.
  201. /// @property
  202. float Bottom() const { return max_.y_; }
  203. /// Minimum vector.
  204. Vector2 min_;
  205. /// Maximum vector.
  206. Vector2 max_;
  207. /// Rect in the range (-1, -1) - (1, 1).
  208. static const Rect FULL;
  209. /// Rect in the range (0, 0) - (1, 1).
  210. static const Rect POSITIVE;
  211. /// Zero-sized rect.
  212. static const Rect ZERO;
  213. };
  214. /// Two-dimensional bounding rectangle with integer values.
  215. class URHO3D_API IntRect
  216. {
  217. public:
  218. /// Construct a zero rect.
  219. IntRect() noexcept :
  220. left_(0),
  221. top_(0),
  222. right_(0),
  223. bottom_(0)
  224. {
  225. }
  226. /// Construct from minimum and maximum vectors.
  227. IntRect(const IntVector2& min, const IntVector2& max) noexcept :
  228. left_(min.x_),
  229. top_(min.y_),
  230. right_(max.x_),
  231. bottom_(max.y_)
  232. {
  233. }
  234. /// Construct from coordinates.
  235. IntRect(int left, int top, int right, int bottom) noexcept :
  236. left_(left),
  237. top_(top),
  238. right_(right),
  239. bottom_(bottom)
  240. {
  241. }
  242. /// Construct from an int array.
  243. explicit IntRect(const int* data) noexcept :
  244. left_(data[0]),
  245. top_(data[1]),
  246. right_(data[2]),
  247. bottom_(data[3])
  248. {
  249. }
  250. /// Test for equality with another rect.
  251. bool operator ==(const IntRect& rhs) const
  252. {
  253. return left_ == rhs.left_ && top_ == rhs.top_ && right_ == rhs.right_ && bottom_ == rhs.bottom_;
  254. }
  255. /// Test for inequality with another rect.
  256. bool operator !=(const IntRect& rhs) const
  257. {
  258. return left_ != rhs.left_ || top_ != rhs.top_ || right_ != rhs.right_ || bottom_ != rhs.bottom_;
  259. }
  260. /// Add another rect to this one inplace.
  261. IntRect& operator +=(const IntRect& rhs)
  262. {
  263. left_ += rhs.left_;
  264. top_ += rhs.top_;
  265. right_ += rhs.right_;
  266. bottom_ += rhs.bottom_;
  267. return *this;
  268. }
  269. /// Subtract another rect from this one inplace.
  270. IntRect& operator -=(const IntRect& rhs)
  271. {
  272. left_ -= rhs.left_;
  273. top_ -= rhs.top_;
  274. right_ -= rhs.right_;
  275. bottom_ -= rhs.bottom_;
  276. return *this;
  277. }
  278. /// Divide by scalar inplace.
  279. IntRect& operator /=(float value)
  280. {
  281. left_ = static_cast<int>(left_ / value);
  282. top_ = static_cast<int>(top_ / value);
  283. right_ = static_cast<int>(right_ / value);
  284. bottom_ = static_cast<int>(bottom_ / value);
  285. return *this;
  286. }
  287. /// Multiply by scalar inplace.
  288. IntRect& operator *=(float value)
  289. {
  290. left_ = static_cast<int>(left_ * value);
  291. top_ = static_cast<int>(top_ * value);
  292. right_ = static_cast<int>(right_ * value);
  293. bottom_ = static_cast<int>(bottom_ * value);
  294. return *this;
  295. }
  296. /// Divide by scalar.
  297. IntRect operator /(float value) const
  298. {
  299. return {
  300. static_cast<int>(left_ / value), static_cast<int>(top_ / value),
  301. static_cast<int>(right_ / value), static_cast<int>(bottom_ / value)
  302. };
  303. }
  304. /// Multiply by scalar.
  305. IntRect operator *(float value) const
  306. {
  307. return {
  308. static_cast<int>(left_ * value), static_cast<int>(top_ * value),
  309. static_cast<int>(right_ * value), static_cast<int>(bottom_ * value)
  310. };
  311. }
  312. /// Add another rect.
  313. IntRect operator +(const IntRect& rhs) const
  314. {
  315. return {
  316. left_ + rhs.left_, top_ + rhs.top_,
  317. right_ + rhs.right_, bottom_ + rhs.bottom_
  318. };
  319. }
  320. /// Subtract another rect.
  321. IntRect operator -(const IntRect& rhs) const
  322. {
  323. return {
  324. left_ - rhs.left_, top_ - rhs.top_,
  325. right_ - rhs.right_, bottom_ - rhs.bottom_
  326. };
  327. }
  328. /// Return size.
  329. /// @property
  330. IntVector2 Size() const { return IntVector2(Width(), Height()); }
  331. /// Return width.
  332. /// @property
  333. int Width() const { return right_ - left_; }
  334. /// Return height.
  335. /// @property
  336. int Height() const { return bottom_ - top_; }
  337. /// Test whether a point is inside.
  338. Intersection IsInside(const IntVector2& point) const
  339. {
  340. if (point.x_ < left_ || point.y_ < top_ || point.x_ >= right_ || point.y_ >= bottom_)
  341. return OUTSIDE;
  342. else
  343. return INSIDE;
  344. }
  345. /// Test if another rect is inside, outside or intersects.
  346. Intersection IsInside(const IntRect& rect) const
  347. {
  348. if (rect.right_ < left_ || rect.left_ >= right_ || rect.bottom_ < top_ || rect.top_ >= bottom_)
  349. return OUTSIDE;
  350. else if (rect.left_ < left_ || rect.right_ > right_ || rect.top_ < top_ || rect.bottom_ > bottom_)
  351. return INTERSECTS;
  352. else
  353. return INSIDE;
  354. }
  355. /// Clip with another rect. Since IntRect does not have an undefined state
  356. /// like Rect, return (0, 0, 0, 0) if the result is empty.
  357. void Clip(const IntRect& rect);
  358. /// Merge a rect. If this rect was empty, become the other rect. If the
  359. /// other rect is empty, do nothing.
  360. void Merge(const IntRect& rect);
  361. /// Return integer data.
  362. const int* Data() const { return &left_; }
  363. /// Return as string.
  364. String ToString() const;
  365. /// Return left-top corner position.
  366. IntVector2 Min() const { return {left_, top_}; }
  367. /// Return right-bottom corner position.
  368. IntVector2 Max() const { return {right_, bottom_}; }
  369. /// Return left coordinate.
  370. int Left() const { return left_; }
  371. /// Return top coordinate.
  372. int Top() const { return top_; }
  373. /// Return right coordinate.
  374. int Right() const { return right_; }
  375. /// Return bottom coordinate.
  376. int Bottom() const { return bottom_; }
  377. /// Left coordinate.
  378. int left_;
  379. /// Top coordinate.
  380. int top_;
  381. /// Right coordinate.
  382. int right_;
  383. /// Bottom coordinate.
  384. int bottom_;
  385. /// Zero-sized rect.
  386. static const IntRect ZERO;
  387. };
  388. }