mRect.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _MRECT_H_
  23. #define _MRECT_H_
  24. #ifndef _MPOINT2_H_
  25. #include "math/mPoint2.h"
  26. #endif
  27. class RectI
  28. {
  29. public:
  30. Point2I point;
  31. Point2I extent;
  32. public:
  33. RectI() { }
  34. RectI(const Point2I& in_rMin,
  35. const Point2I& in_rExtent);
  36. RectI(const S32 in_left, const S32 in_top,
  37. const S32 in_width, const S32 in_height);
  38. void set(const Point2I& in_rMin, const Point2I& in_rExtent);
  39. void set(const S32 in_left, const S32 in_top,
  40. const S32 in_width, const S32 in_height);
  41. bool intersect(const RectI& clipRect);
  42. bool pointInRect(const Point2I& pt) const;
  43. bool overlaps(RectI R) const;
  44. bool contains(const RectI& R) const;
  45. void inset(S32 x, S32 y);
  46. void unionRects(const RectI&);
  47. S32 len_x() const;
  48. S32 len_y() const;
  49. /// Returns the area of the rectangle.
  50. S32 area() const { return extent.x * extent.y; }
  51. bool operator==(const RectI&) const;
  52. bool operator!=(const RectI&) const;
  53. bool isValidRect() const { return (extent.x > 0 && extent.y > 0); }
  54. public:
  55. /// A rect of zero extent.
  56. static const RectI Zero;
  57. /// A rect of 1,1 extent.
  58. static const RectI One;
  59. };
  60. class RectF
  61. {
  62. public:
  63. Point2F point;
  64. Point2F extent;
  65. public:
  66. RectF() { }
  67. RectF(const Point2F& in_rMin,
  68. const Point2F& in_rExtent);
  69. RectF(const F32 in_left, const F32 in_top,
  70. const F32 in_width, const F32 in_height);
  71. void set(const Point2F& in_rMin, const Point2F& in_rExtent);
  72. void set(const F32 in_left, const F32 in_top,
  73. const F32 in_width, const F32 in_height);
  74. void inset(F32 x, F32 y);
  75. /// Return distance of the reference point to the rectangle.
  76. F32 getDistanceToPoint( const Point2F &refPt ) const;
  77. /// Return the squared distance of the reference point to the rectangle.
  78. F32 getSqDistanceToPoint( const Point2F &refPt ) const;
  79. bool intersect(const RectF& clipRect);
  80. bool pointInRect(const Point2F& pt) const;
  81. bool overlaps(const RectF&) const;
  82. bool contains(const Point2F &p) const
  83. {
  84. Point2F minkowskiP = p - point;
  85. // If we're beyond origin...
  86. if(minkowskiP.x < 0 || minkowskiP.y < 0)
  87. return false;
  88. // Or past extent...
  89. if(minkowskiP.x > extent.x || minkowskiP.y > extent.y)
  90. return false;
  91. // Otherwise we're ok.
  92. return true;
  93. }
  94. bool contains(const RectF& R) const;
  95. void unionRects( const RectF &rect );
  96. F32 len_x() const;
  97. F32 len_y() const;
  98. bool isValidRect() const { return (extent.x > 0.0f && extent.y > 0.0f); }
  99. inline bool intersectTriangle(const Point2F &a, const Point2F &b, const Point2F &c);
  100. };
  101. class RectD
  102. {
  103. public:
  104. Point2D point;
  105. Point2D extent;
  106. public:
  107. RectD() { }
  108. RectD(const Point2D& in_rMin,
  109. const Point2D& in_rExtent);
  110. RectD(const F64 in_left, const F64 in_top,
  111. const F64 in_width, const F64 in_height);
  112. void inset(F64 x, F64 y);
  113. bool intersect(const RectD& clipRect);
  114. F64 len_x() const;
  115. F64 len_y() const;
  116. bool isValidRect() const { return (extent.x > 0 && extent.y > 0); }
  117. };
  118. //------------------------------------------------------------------------------
  119. //-------------------------------------- INLINES (RectI)
  120. //
  121. inline
  122. RectI::RectI(const Point2I& in_rMin,
  123. const Point2I& in_rExtent)
  124. : point(in_rMin),
  125. extent(in_rExtent)
  126. {
  127. //
  128. }
  129. inline
  130. RectI::RectI(const S32 in_left, const S32 in_top,
  131. const S32 in_width, const S32 in_height)
  132. : point(in_left, in_top),
  133. extent(in_width, in_height)
  134. {
  135. //
  136. }
  137. inline void RectI::set(const Point2I& in_rMin, const Point2I& in_rExtent)
  138. {
  139. point = in_rMin;
  140. extent = in_rExtent;
  141. }
  142. inline void RectI::set(const S32 in_left, const S32 in_top,
  143. const S32 in_width, const S32 in_height)
  144. {
  145. point.set(in_left, in_top);
  146. extent.set(in_width, in_height);
  147. }
  148. inline bool RectI::intersect(const RectI& clipRect)
  149. {
  150. Point2I bottomL;
  151. bottomL.x = getMin(point.x + extent.x - 1, clipRect.point.x + clipRect.extent.x - 1);
  152. bottomL.y = getMin(point.y + extent.y - 1, clipRect.point.y + clipRect.extent.y - 1);
  153. point.x = getMax(point.x, clipRect.point.x);
  154. point.y = getMax(point.y, clipRect.point.y);
  155. extent.x = bottomL.x - point.x + 1;
  156. extent.y = bottomL.y - point.y + 1;
  157. return isValidRect();
  158. }
  159. inline bool RectI::pointInRect(const Point2I &pt) const
  160. {
  161. return (pt.x >= point.x && pt.x < point.x + extent.x && pt.y >= point.y && pt.y < point.y + extent.y);
  162. }
  163. inline bool RectI::contains(const RectI& R) const
  164. {
  165. if (point.x <= R.point.x && point.y <= R.point.y)
  166. if (R.point.x + R.extent.x <= point.x + extent.x)
  167. if (R.point.y + R.extent.y <= point.y + extent.y)
  168. return true;
  169. return false;
  170. }
  171. inline bool RectI::overlaps(RectI R) const
  172. {
  173. return R.intersect (* this);
  174. }
  175. inline void RectI::inset(S32 x, S32 y)
  176. {
  177. point.x += x;
  178. point.y += y;
  179. extent.x -= 2 * x;
  180. extent.y -= 2 * y;
  181. }
  182. inline void RectF::inset(F32 x, F32 y)
  183. {
  184. point.x += x;
  185. point.y += y;
  186. extent.x -= 2.0f * x;
  187. extent.y -= 2.0f * y;
  188. }
  189. inline void RectD::inset(F64 x, F64 y)
  190. {
  191. point.x += x;
  192. point.y += y;
  193. extent.x -= 2.0 * x;
  194. extent.y -= 2.0 * y;
  195. }
  196. inline void RectI::unionRects(const RectI& u)
  197. {
  198. S32 minx = point.x < u.point.x ? point.x : u.point.x;
  199. S32 miny = point.y < u.point.y ? point.y : u.point.y;
  200. S32 maxx = (point.x + extent.x) > (u.point.x + u.extent.x) ? (point.x + extent.x) : (u.point.x + u.extent.x);
  201. S32 maxy = (point.y + extent.y) > (u.point.y + u.extent.y) ? (point.y + extent.y) : (u.point.y + u.extent.y);
  202. point.x = minx;
  203. point.y = miny;
  204. extent.x = maxx - minx;
  205. extent.y = maxy - miny;
  206. }
  207. inline S32
  208. RectI::len_x() const
  209. {
  210. return extent.x;
  211. }
  212. inline S32
  213. RectI::len_y() const
  214. {
  215. return extent.y;
  216. }
  217. inline bool
  218. RectI::operator==(const RectI& in_rCompare) const
  219. {
  220. return (point == in_rCompare.point) && (extent == in_rCompare.extent);
  221. }
  222. inline bool
  223. RectI::operator!=(const RectI& in_rCompare) const
  224. {
  225. return (operator==(in_rCompare) == false);
  226. }
  227. //------------------------------------------------------------------------------
  228. //-------------------------------------- INLINES (RectF)
  229. //
  230. inline
  231. RectF::RectF(const Point2F& in_rMin,
  232. const Point2F& in_rExtent)
  233. : point(in_rMin),
  234. extent(in_rExtent)
  235. {
  236. //
  237. }
  238. inline
  239. RectF::RectF(const F32 in_left, const F32 in_top,
  240. const F32 in_width, const F32 in_height)
  241. : point(in_left, in_top),
  242. extent(in_width, in_height)
  243. {
  244. //
  245. }
  246. inline F32
  247. RectF::len_x() const
  248. {
  249. return extent.x;
  250. }
  251. inline F32
  252. RectF::len_y() const
  253. {
  254. return extent.y;
  255. }
  256. inline void RectF::set(const Point2F& in_rMin, const Point2F& in_rExtent)
  257. {
  258. point = in_rMin;
  259. extent = in_rExtent;
  260. }
  261. inline void RectF::set(const F32 in_left, const F32 in_top,
  262. const F32 in_width, const F32 in_height)
  263. {
  264. point.set(in_left, in_top);
  265. extent.set(in_width, in_height);
  266. }
  267. inline F32 RectF::getDistanceToPoint( const Point2F &refPt ) const
  268. {
  269. return mSqrt( getSqDistanceToPoint( refPt ) );
  270. }
  271. inline F32 RectF::getSqDistanceToPoint( const Point2F &refPt ) const
  272. {
  273. const Point2F maxPoint( point + extent );
  274. F32 sqDist = 0.0f;
  275. for ( U32 i=0; i < 2; i++ )
  276. {
  277. const F32 v = refPt[i];
  278. if ( v < point[i] )
  279. sqDist += mSquared( point[i] - v );
  280. else if ( v > maxPoint[i] )
  281. sqDist += mSquared( v - maxPoint[i] );
  282. }
  283. return sqDist;
  284. }
  285. inline bool RectF::intersect(const RectF& clipRect)
  286. {
  287. Point2F bottomL;
  288. bottomL.x = getMin(point.x + extent.x, clipRect.point.x + clipRect.extent.x);
  289. bottomL.y = getMin(point.y + extent.y, clipRect.point.y + clipRect.extent.y);
  290. point.x = getMax(point.x, clipRect.point.x);
  291. point.y = getMax(point.y, clipRect.point.y);
  292. extent.x = bottomL.x - point.x;
  293. extent.y = bottomL.y - point.y;
  294. return isValidRect();
  295. }
  296. inline bool RectF::pointInRect(const Point2F &pt) const
  297. {
  298. return (pt.x >= point.x && pt.x < point.x + extent.x && pt.y >= point.y && pt.y < point.y + extent.y);
  299. }
  300. inline bool RectF::overlaps(const RectF& clipRect) const
  301. {
  302. RectF test = *this;
  303. return test.intersect(clipRect);
  304. }
  305. inline bool lineToLineIntersect(const Point2F & a1, const Point2F & a2, const Point2F & b1, const Point2F & b2)
  306. {
  307. const F32 ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
  308. const F32 ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
  309. const F32 u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
  310. if(u_b != 0)
  311. {
  312. const F32 ua = ua_t / u_b;
  313. const F32 ub = ub_t / u_b;
  314. return ( 0.0f <= ua && ua <= 1.0f && 0.0f <= ub && ub <= 1.0f );
  315. }
  316. else
  317. {
  318. return ( ua_t == 0 || ub_t == 0 );
  319. }
  320. }
  321. inline bool RectF::intersectTriangle(const Point2F &a, const Point2F &b, const Point2F &c)
  322. {
  323. const Point2F topLeft = point;
  324. const Point2F topRight = Point2F( point.x + extent.x, point.y );
  325. const Point2F bottomLeft = Point2F( point.x, point.y + extent.y );
  326. const Point2F bottomRight = point + extent;
  327. // 3 point plus 12 edge tests.
  328. // Check each triangle point to see if it's in us.
  329. if(contains(a) || contains(b) || contains(c))
  330. return true;
  331. // Check a-b against the rect.
  332. if(lineToLineIntersect(topLeft, topRight, a, b))
  333. return true;
  334. if(lineToLineIntersect(topRight, bottomRight, a, b))
  335. return true;
  336. if(lineToLineIntersect(bottomRight, bottomLeft, a, b))
  337. return true;
  338. if(lineToLineIntersect(bottomLeft, topLeft, a, b))
  339. return true;
  340. // Check b-c
  341. if(lineToLineIntersect(topLeft, topRight, b, c))
  342. return true;
  343. if(lineToLineIntersect(topRight, bottomRight, b, c))
  344. return true;
  345. if(lineToLineIntersect(bottomRight, bottomLeft, b, c))
  346. return true;
  347. if(lineToLineIntersect(bottomLeft, topLeft, b, c))
  348. return true;
  349. // Check c-a
  350. if(lineToLineIntersect(topLeft, topRight, c, a))
  351. return true;
  352. if(lineToLineIntersect(topRight, bottomRight, c, a))
  353. return true;
  354. if(lineToLineIntersect(bottomRight, bottomLeft, c, a))
  355. return true;
  356. if(lineToLineIntersect(bottomLeft, topLeft, c, a))
  357. return true;
  358. return false;
  359. }
  360. inline bool RectF::contains(const RectF& R) const
  361. {
  362. if (point.x <= R.point.x && point.y <= R.point.y)
  363. if (R.point.x + R.extent.x <= point.x + extent.x)
  364. if (R.point.y + R.extent.y <= point.y + extent.y)
  365. return true;
  366. return false;
  367. }
  368. inline void RectF::unionRects( const RectF &r )
  369. {
  370. F32 minx = point.x < r.point.x ? point.x : r.point.x;
  371. F32 miny = point.y < r.point.y ? point.y : r.point.y;
  372. F32 maxx = (point.x + extent.x) > (r.point.x + r.extent.x) ? (point.x + extent.x) : (r.point.x + r.extent.x);
  373. F32 maxy = (point.y + extent.y) > (r.point.y + r.extent.y) ? (point.y + extent.y) : (r.point.y + r.extent.y);
  374. point.x = minx;
  375. point.y = miny;
  376. extent.x = maxx - minx;
  377. extent.y = maxy - miny;
  378. }
  379. //------------------------------------------------------------------------------
  380. //-------------------------------------- INLINES (RectD)
  381. //
  382. inline
  383. RectD::RectD(const Point2D& in_rMin,
  384. const Point2D& in_rExtent)
  385. : point(in_rMin),
  386. extent(in_rExtent)
  387. {
  388. //
  389. }
  390. inline
  391. RectD::RectD(const F64 in_left, const F64 in_top,
  392. const F64 in_width, const F64 in_height)
  393. : point(in_left, in_top),
  394. extent(in_width, in_height)
  395. {
  396. //
  397. }
  398. inline F64
  399. RectD::len_x() const
  400. {
  401. return extent.x;
  402. }
  403. inline F64
  404. RectD::len_y() const
  405. {
  406. return extent.y;
  407. }
  408. inline bool RectD::intersect(const RectD& clipRect)
  409. {
  410. Point2D bottomL;
  411. bottomL.x = getMin(point.x + extent.x, clipRect.point.x + clipRect.extent.x);
  412. bottomL.y = getMin(point.y + extent.y, clipRect.point.y + clipRect.extent.y);
  413. point.x = getMax(point.x, clipRect.point.x);
  414. point.y = getMax(point.y, clipRect.point.y);
  415. extent.x = bottomL.x - point.x;
  416. extent.y = bottomL.y - point.y;
  417. return isValidRect();
  418. }
  419. #endif //_RECT_H_