Rectangle.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. // MIT License - Copyright (C) The Mono.Xna Team
  2. // This file is subject to the terms and conditions defined in
  3. // file 'LICENSE.txt', which is part of this source code package.
  4. using System;
  5. using System.Runtime.Serialization;
  6. using System.Diagnostics;
  7. namespace CommonLang.Geometry
  8. {
  9. /// <summary>
  10. /// Describes a 2D-rectangle.
  11. /// </summary>
  12. public struct Rectangle : IEquatable<Rectangle>
  13. {
  14. #region Private Fields
  15. private static Rectangle emptyRectangle = new Rectangle();
  16. #endregion
  17. #region Public Fields
  18. /// <summary>
  19. /// The x coordinate of the top-left corner of this <see cref="Rectangle"/>.
  20. /// </summary>
  21. public int X;
  22. /// <summary>
  23. /// The y coordinate of the top-left corner of this <see cref="Rectangle"/>.
  24. /// </summary>
  25. public int Y;
  26. /// <summary>
  27. /// The width of this <see cref="Rectangle"/>.
  28. /// </summary>
  29. public int Width;
  30. /// <summary>
  31. /// The height of this <see cref="Rectangle"/>.
  32. /// </summary>
  33. public int Height;
  34. #endregion
  35. #region Public Properties
  36. /// <summary>
  37. /// Returns a <see cref="Rectangle"/> with X=0, Y=0, Width=0, Height=0.
  38. /// </summary>
  39. public static Rectangle Empty
  40. {
  41. get { return emptyRectangle; }
  42. }
  43. /// <summary>
  44. /// Returns the x coordinate of the left edge of this <see cref="Rectangle"/>.
  45. /// </summary>
  46. public int Left
  47. {
  48. get { return this.X; }
  49. }
  50. /// <summary>
  51. /// Returns the x coordinate of the right edge of this <see cref="Rectangle"/>.
  52. /// </summary>
  53. public int Right
  54. {
  55. get { return (this.X + this.Width); }
  56. }
  57. /// <summary>
  58. /// Returns the y coordinate of the top edge of this <see cref="Rectangle"/>.
  59. /// </summary>
  60. public int Top
  61. {
  62. get { return this.Y; }
  63. }
  64. /// <summary>
  65. /// Returns the y coordinate of the bottom edge of this <see cref="Rectangle"/>.
  66. /// </summary>
  67. public int Bottom
  68. {
  69. get { return (this.Y + this.Height); }
  70. }
  71. /// <summary>
  72. /// Whether or not this <see cref="Rectangle"/> has a <see cref="Width"/> and
  73. /// <see cref="Height"/> of 0, and a <see cref="Location"/> of (0, 0).
  74. /// </summary>
  75. public bool IsEmpty
  76. {
  77. get
  78. {
  79. return ((((this.Width == 0) && (this.Height == 0)) && (this.X == 0)) && (this.Y == 0));
  80. }
  81. }
  82. /// <summary>
  83. /// The top-left coordinates of this <see cref="Rectangle"/>.
  84. /// </summary>
  85. public Point Location
  86. {
  87. get
  88. {
  89. return new Point(this.X, this.Y);
  90. }
  91. set
  92. {
  93. X = value.X;
  94. Y = value.Y;
  95. }
  96. }
  97. /// <summary>
  98. /// The width-height coordinates of this <see cref="Rectangle"/>.
  99. /// </summary>
  100. public Point Size
  101. {
  102. get
  103. {
  104. return new Point(this.Width,this.Height);
  105. }
  106. set
  107. {
  108. Width = value.X;
  109. Height = value.Y;
  110. }
  111. }
  112. /// <summary>
  113. /// A <see cref="Point"/> located in the center of this <see cref="Rectangle"/>.
  114. /// </summary>
  115. /// <remarks>
  116. /// If <see cref="Width"/> or <see cref="Height"/> is an odd number,
  117. /// the center point will be rounded down.
  118. /// </remarks>
  119. public Point Center
  120. {
  121. get
  122. {
  123. return new Point(this.X + (this.Width / 2), this.Y + (this.Height / 2));
  124. }
  125. }
  126. #endregion
  127. #region Internal Properties
  128. internal string DebugDisplayString
  129. {
  130. get
  131. {
  132. return string.Concat(
  133. this.X, " ",
  134. this.Y, " ",
  135. this.Width, " ",
  136. this.Height
  137. );
  138. }
  139. }
  140. #endregion
  141. #region Constructors
  142. /// <summary>
  143. /// Creates a new instance of <see cref="Rectangle"/> struct, with the specified
  144. /// position, width, and height.
  145. /// </summary>
  146. /// <param name="x">The x coordinate of the top-left corner of the created <see cref="Rectangle"/>.</param>
  147. /// <param name="y">The y coordinate of the top-left corner of the created <see cref="Rectangle"/>.</param>
  148. /// <param name="width">The width of the created <see cref="Rectangle"/>.</param>
  149. /// <param name="height">The height of the created <see cref="Rectangle"/>.</param>
  150. public Rectangle(int x, int y, int width, int height)
  151. {
  152. this.X = x;
  153. this.Y = y;
  154. this.Width = width;
  155. this.Height = height;
  156. }
  157. /// <summary>
  158. /// Creates a new instance of <see cref="Rectangle"/> struct, with the specified
  159. /// location and size.
  160. /// </summary>
  161. /// <param name="location">The x and y coordinates of the top-left corner of the created <see cref="Rectangle"/>.</param>
  162. /// <param name="size">The width and height of the created <see cref="Rectangle"/>.</param>
  163. public Rectangle(Point location,Point size)
  164. {
  165. this.X = location.X;
  166. this.Y = location.Y;
  167. this.Width = size.X;
  168. this.Height = size.Y;
  169. }
  170. #endregion
  171. #region Operators
  172. /// <summary>
  173. /// Compares whether two <see cref="Rectangle"/> instances are equal.
  174. /// </summary>
  175. /// <param name="a"><see cref="Rectangle"/> instance on the left of the equal sign.</param>
  176. /// <param name="b"><see cref="Rectangle"/> instance on the right of the equal sign.</param>
  177. /// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
  178. public static bool operator ==(Rectangle a, Rectangle b)
  179. {
  180. return ((a.X == b.X) && (a.Y == b.Y) && (a.Width == b.Width) && (a.Height == b.Height));
  181. }
  182. /// <summary>
  183. /// Compares whether two <see cref="Rectangle"/> instances are not equal.
  184. /// </summary>
  185. /// <param name="a"><see cref="Rectangle"/> instance on the left of the not equal sign.</param>
  186. /// <param name="b"><see cref="Rectangle"/> instance on the right of the not equal sign.</param>
  187. /// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
  188. public static bool operator !=(Rectangle a, Rectangle b)
  189. {
  190. return !(a == b);
  191. }
  192. #endregion
  193. #region Public Methods
  194. /// <summary>
  195. /// Gets whether or not the provided coordinates lie within the bounds of this <see cref="Rectangle"/>.
  196. /// </summary>
  197. /// <param name="x">The x coordinate of the point to check for containment.</param>
  198. /// <param name="y">The y coordinate of the point to check for containment.</param>
  199. /// <returns><c>true</c> if the provided coordinates lie inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  200. public bool Contains(int x, int y)
  201. {
  202. return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
  203. }
  204. /// <summary>
  205. /// Gets whether or not the provided coordinates lie within the bounds of this <see cref="Rectangle"/>.
  206. /// </summary>
  207. /// <param name="x">The x coordinate of the point to check for containment.</param>
  208. /// <param name="y">The y coordinate of the point to check for containment.</param>
  209. /// <returns><c>true</c> if the provided coordinates lie inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  210. public bool Contains(float x, float y)
  211. {
  212. return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
  213. }
  214. /// <summary>
  215. /// Gets whether or not the provided <see cref="Point"/> lies within the bounds of this <see cref="Rectangle"/>.
  216. /// </summary>
  217. /// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
  218. /// <returns><c>true</c> if the provided <see cref="Point"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  219. public bool Contains(Point value)
  220. {
  221. return ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
  222. }
  223. /// <summary>
  224. /// Gets whether or not the provided <see cref="Point"/> lies within the bounds of this <see cref="Rectangle"/>.
  225. /// </summary>
  226. /// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
  227. /// <param name="result"><c>true</c> if the provided <see cref="Point"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
  228. public void Contains(ref Point value, out bool result)
  229. {
  230. result = ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
  231. }
  232. /// <summary>
  233. /// Gets whether or not the provided <see cref="Vector2"/> lies within the bounds of this <see cref="Rectangle"/>.
  234. /// </summary>
  235. /// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
  236. /// <returns><c>true</c> if the provided <see cref="Vector2"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  237. public bool Contains(Vector2 value)
  238. {
  239. return ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
  240. }
  241. /// <summary>
  242. /// Gets whether or not the provided <see cref="Vector2"/> lies within the bounds of this <see cref="Rectangle"/>.
  243. /// </summary>
  244. /// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
  245. /// <param name="result"><c>true</c> if the provided <see cref="Vector2"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
  246. public void Contains(ref Vector2 value, out bool result)
  247. {
  248. result = ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
  249. }
  250. /// <summary>
  251. /// Gets whether or not the provided <see cref="Rectangle"/> lies within the bounds of this <see cref="Rectangle"/>.
  252. /// </summary>
  253. /// <param name="value">The <see cref="Rectangle"/> to check for inclusion in this <see cref="Rectangle"/>.</param>
  254. /// <returns><c>true</c> if the provided <see cref="Rectangle"/>'s bounds lie entirely inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  255. public bool Contains(Rectangle value)
  256. {
  257. return ((((this.X <= value.X) && ((value.X + value.Width) <= (this.X + this.Width))) && (this.Y <= value.Y)) && ((value.Y + value.Height) <= (this.Y + this.Height)));
  258. }
  259. /// <summary>
  260. /// Gets whether or not the provided <see cref="Rectangle"/> lies within the bounds of this <see cref="Rectangle"/>.
  261. /// </summary>
  262. /// <param name="value">The <see cref="Rectangle"/> to check for inclusion in this <see cref="Rectangle"/>.</param>
  263. /// <param name="result"><c>true</c> if the provided <see cref="Rectangle"/>'s bounds lie entirely inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
  264. public void Contains(ref Rectangle value,out bool result)
  265. {
  266. result = ((((this.X <= value.X) && ((value.X + value.Width) <= (this.X + this.Width))) && (this.Y <= value.Y)) && ((value.Y + value.Height) <= (this.Y + this.Height)));
  267. }
  268. /// <summary>
  269. /// Compares whether current instance is equal to specified <see cref="Object"/>.
  270. /// </summary>
  271. /// <param name="obj">The <see cref="Object"/> to compare.</param>
  272. /// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
  273. public override bool Equals(object obj)
  274. {
  275. return (obj is Rectangle) && this == ((Rectangle)obj);
  276. }
  277. /// <summary>
  278. /// Compares whether current instance is equal to specified <see cref="Rectangle"/>.
  279. /// </summary>
  280. /// <param name="other">The <see cref="Rectangle"/> to compare.</param>
  281. /// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
  282. public bool Equals(Rectangle other)
  283. {
  284. return this == other;
  285. }
  286. /// <summary>
  287. /// Gets the hash code of this <see cref="Rectangle"/>.
  288. /// </summary>
  289. /// <returns>Hash code of this <see cref="Rectangle"/>.</returns>
  290. public override int GetHashCode()
  291. {
  292. return (X ^ Y ^ Width ^ Height);
  293. }
  294. /// <summary>
  295. /// Adjusts the edges of this <see cref="Rectangle"/> by specified horizontal and vertical amounts.
  296. /// </summary>
  297. /// <param name="horizontalAmount">Value to adjust the left and right edges.</param>
  298. /// <param name="verticalAmount">Value to adjust the top and bottom edges.</param>
  299. public void Inflate(int horizontalAmount, int verticalAmount)
  300. {
  301. X -= horizontalAmount;
  302. Y -= verticalAmount;
  303. Width += horizontalAmount * 2;
  304. Height += verticalAmount * 2;
  305. }
  306. /// <summary>
  307. /// Adjusts the edges of this <see cref="Rectangle"/> by specified horizontal and vertical amounts.
  308. /// </summary>
  309. /// <param name="horizontalAmount">Value to adjust the left and right edges.</param>
  310. /// <param name="verticalAmount">Value to adjust the top and bottom edges.</param>
  311. public void Inflate(float horizontalAmount, float verticalAmount)
  312. {
  313. X -= (int)horizontalAmount;
  314. Y -= (int)verticalAmount;
  315. Width += (int)horizontalAmount * 2;
  316. Height += (int)verticalAmount * 2;
  317. }
  318. /// <summary>
  319. /// Gets whether or not a specified <see cref="Rectangle"/> intersects with this <see cref="Rectangle"/>.
  320. /// </summary>
  321. /// <param name="value">Other <see cref="Rectangle"/>.</param>
  322. /// <returns><c>true</c> if other <see cref="Rectangle"/> intersects with this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
  323. public bool Intersects(Rectangle value)
  324. {
  325. return value.Left < Right &&
  326. Left < value.Right &&
  327. value.Top < Bottom &&
  328. Top < value.Bottom;
  329. }
  330. /// <summary>
  331. /// Gets whether or not a specified <see cref="Rectangle"/> intersects with this <see cref="Rectangle"/>.
  332. /// </summary>
  333. /// <param name="value">Other <see cref="Rectangle"/>.</param>
  334. /// <param name="result"><c>true</c> if other <see cref="Rectangle"/> intersects with this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
  335. public void Intersects(ref Rectangle value, out bool result)
  336. {
  337. result = value.Left < Right &&
  338. Left < value.Right &&
  339. value.Top < Bottom &&
  340. Top < value.Bottom;
  341. }
  342. /// <summary>
  343. /// Creates a new <see cref="Rectangle"/> that contains overlapping region of two other rectangles.
  344. /// </summary>
  345. /// <param name="value1">The first <see cref="Rectangle"/>.</param>
  346. /// <param name="value2">The second <see cref="Rectangle"/>.</param>
  347. /// <returns>Overlapping region of the two rectangles.</returns>
  348. public static Rectangle Intersect(Rectangle value1, Rectangle value2)
  349. {
  350. Rectangle rectangle;
  351. Intersect(ref value1, ref value2, out rectangle);
  352. return rectangle;
  353. }
  354. /// <summary>
  355. /// Creates a new <see cref="Rectangle"/> that contains overlapping region of two other rectangles.
  356. /// </summary>
  357. /// <param name="value1">The first <see cref="Rectangle"/>.</param>
  358. /// <param name="value2">The second <see cref="Rectangle"/>.</param>
  359. /// <param name="result">Overlapping region of the two rectangles as an output parameter.</param>
  360. public static void Intersect(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
  361. {
  362. if (value1.Intersects(value2))
  363. {
  364. int right_side = Math.Min(value1.X + value1.Width, value2.X + value2.Width);
  365. int left_side = Math.Max(value1.X, value2.X);
  366. int top_side = Math.Max(value1.Y, value2.Y);
  367. int bottom_side = Math.Min(value1.Y + value1.Height, value2.Y + value2.Height);
  368. result = new Rectangle(left_side, top_side, right_side - left_side, bottom_side - top_side);
  369. }
  370. else
  371. {
  372. result = new Rectangle(0, 0, 0, 0);
  373. }
  374. }
  375. /// <summary>
  376. /// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
  377. /// </summary>
  378. /// <param name="offsetX">The x coordinate to add to this <see cref="Rectangle"/>.</param>
  379. /// <param name="offsetY">The y coordinate to add to this <see cref="Rectangle"/>.</param>
  380. public void Offset(int offsetX, int offsetY)
  381. {
  382. X += offsetX;
  383. Y += offsetY;
  384. }
  385. /// <summary>
  386. /// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
  387. /// </summary>
  388. /// <param name="offsetX">The x coordinate to add to this <see cref="Rectangle"/>.</param>
  389. /// <param name="offsetY">The y coordinate to add to this <see cref="Rectangle"/>.</param>
  390. public void Offset(float offsetX, float offsetY)
  391. {
  392. X += (int)offsetX;
  393. Y += (int)offsetY;
  394. }
  395. /// <summary>
  396. /// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
  397. /// </summary>
  398. /// <param name="amount">The x and y components to add to this <see cref="Rectangle"/>.</param>
  399. public void Offset(Point amount)
  400. {
  401. X += amount.X;
  402. Y += amount.Y;
  403. }
  404. /// <summary>
  405. /// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
  406. /// </summary>
  407. /// <param name="amount">The x and y components to add to this <see cref="Rectangle"/>.</param>
  408. public void Offset(Vector2 amount)
  409. {
  410. X += (int)amount.X;
  411. Y += (int)amount.Y;
  412. }
  413. /// <summary>
  414. /// Returns a <see cref="String"/> representation of this <see cref="Rectangle"/> in the format:
  415. /// {X:[<see cref="X"/>] Y:[<see cref="Y"/>] Width:[<see cref="Width"/>] Height:[<see cref="Height"/>]}
  416. /// </summary>
  417. /// <returns><see cref="String"/> representation of this <see cref="Rectangle"/>.</returns>
  418. public override string ToString()
  419. {
  420. return "{X:" + X + " Y:" + Y + " Width:" + Width + " Height:" + Height + "}";
  421. }
  422. /// <summary>
  423. /// Creates a new <see cref="Rectangle"/> that completely contains two other rectangles.
  424. /// </summary>
  425. /// <param name="value1">The first <see cref="Rectangle"/>.</param>
  426. /// <param name="value2">The second <see cref="Rectangle"/>.</param>
  427. /// <returns>The union of the two rectangles.</returns>
  428. public static Rectangle Union(Rectangle value1, Rectangle value2)
  429. {
  430. int x = Math.Min(value1.X, value2.X);
  431. int y = Math.Min(value1.Y, value2.Y);
  432. return new Rectangle(x, y,
  433. Math.Max(value1.Right, value2.Right) - x,
  434. Math.Max(value1.Bottom, value2.Bottom) - y);
  435. }
  436. /// <summary>
  437. /// Creates a new <see cref="Rectangle"/> that completely contains two other rectangles.
  438. /// </summary>
  439. /// <param name="value1">The first <see cref="Rectangle"/>.</param>
  440. /// <param name="value2">The second <see cref="Rectangle"/>.</param>
  441. /// <param name="result">The union of the two rectangles as an output parameter.</param>
  442. public static void Union(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
  443. {
  444. result.X = Math.Min(value1.X, value2.X);
  445. result.Y = Math.Min(value1.Y, value2.Y);
  446. result.Width = Math.Max(value1.Right, value2.Right) - result.X;
  447. result.Height = Math.Max(value1.Bottom, value2.Bottom) - result.Y;
  448. }
  449. #endregion
  450. }
  451. }