Rectangle.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. //
  2. // Derived from System.Drawing.Rectangle.cs
  3. //
  4. // Author:
  5. // Mike Kestner ([email protected])
  6. //
  7. // Copyright (C) 2001 Mike Kestner
  8. // Copyright (C) 2004 Novell, Inc. http://www.novell.com
  9. //
  10. namespace Terminal.Gui;
  11. /// <summary>Stores a set of four integers that represent the location and size of a rectangle</summary>
  12. public struct Rectangle
  13. {
  14. private int width;
  15. private int height;
  16. /// <summary>Gets or sets the x-coordinate of the upper-left corner of this Rectangle structure.</summary>
  17. public int X;
  18. /// <summary>Gets or sets the y-coordinate of the upper-left corner of this Rectangle structure.</summary>
  19. public int Y;
  20. /// <summary>Gets or sets the width of this Rect structure.</summary>
  21. public int Width
  22. {
  23. get => width;
  24. set
  25. {
  26. if (value < 0)
  27. {
  28. throw new ArgumentException ("Width must be greater or equal to 0.");
  29. }
  30. width = value;
  31. }
  32. }
  33. /// <summary>Gets or sets the height of this Rectangle structure.</summary>
  34. public int Height
  35. {
  36. get => height;
  37. set
  38. {
  39. if (value < 0)
  40. {
  41. throw new ArgumentException ("Height must be greater or equal to 0.");
  42. }
  43. height = value;
  44. }
  45. }
  46. /// <summary>Empty Shared Field</summary>
  47. /// <remarks>An uninitialized Rectangle Structure.</remarks>
  48. public static readonly Rectangle Empty;
  49. /// <summary>FromLTRB Shared Method</summary>
  50. /// <remarks>Produces a Rectangle structure from left, top, right and bottom coordinates.</remarks>
  51. public static Rectangle FromLTRB (
  52. int left,
  53. int top,
  54. int right,
  55. int bottom
  56. )
  57. {
  58. return new Rectangle (
  59. left,
  60. top,
  61. right - left,
  62. bottom - top
  63. );
  64. }
  65. /// <summary>Produces a new Rect by inflating an existing Rect by the specified coordinate values.</summary>
  66. /// <remarks>
  67. /// Produces a new Rect by inflating an existing Rect by the specified coordinate values. The rectangle is
  68. /// enlarged in both directions along an axis.
  69. /// </remarks>
  70. public static Rectangle Inflate (Rectangle rect, int x, int y)
  71. {
  72. var r = new Rectangle (rect.Location, rect.Size);
  73. r.Inflate (x, y);
  74. return r;
  75. }
  76. /// <summary>Inflates an existing Rect by the specified coordinate values.</summary>
  77. /// <remarks>
  78. /// This method enlarges this rectangle, not a copy of it. The rectangle is enlarged in both directions along an
  79. /// axis.
  80. /// </remarks>
  81. public void Inflate (int width, int height)
  82. {
  83. // Set dims first so we don't lose the original values on exception
  84. Width += width * 2;
  85. Height += height * 2;
  86. X -= width;
  87. Y -= height;
  88. }
  89. /// <summary>Inflates an existing Rect by the specified Sizwe.</summary>
  90. /// <remarks>
  91. /// This method enlarges this rectangle, not a copy of it. The rectangle is enlarged in both directions along an
  92. /// axis.
  93. /// </remarks>
  94. public void Inflate (Size size) { Inflate (size.Width, size.Height); }
  95. /// <summary>Intersect Shared Method</summary>
  96. /// <remarks>Produces a new Rectangle by intersecting 2 existing Rectangles. Returns Empty if there is no intersection.</remarks>
  97. public static Rectangle Intersect (Rectangle a, Rectangle b)
  98. {
  99. // MS.NET returns a non-empty rectangle if the two rectangles
  100. // touch each other
  101. if (!a.IntersectsWithInclusive (b))
  102. {
  103. return Empty;
  104. }
  105. return FromLTRB (
  106. Math.Max (a.Left, b.Left),
  107. Math.Max (a.Top, b.Top),
  108. Math.Min (a.Right, b.Right),
  109. Math.Min (a.Bottom, b.Bottom)
  110. );
  111. }
  112. /// <summary>Intersect Method</summary>
  113. /// <remarks>Replaces the Rectangle with the intersection of itself and another Rectangle.</remarks>
  114. public void Intersect (Rectangle rect) { this = Intersect (this, rect); }
  115. /// <summary>Produces the uninion of two rectangles.</summary>
  116. /// <remarks>Produces a new Rectangle from the union of 2 existing Rectangles.</remarks>
  117. public static Rectangle Union (Rectangle a, Rectangle b)
  118. {
  119. //int x1 = Math.Min (a.X, b.X);
  120. //int x2 = Math.Max (a.X + a.Width, b.X + b.Width);
  121. //int y1 = Math.Min (a.Y, b.Y);oS
  122. //int y2 = Math.Max (a.Y + a.Height, b.Y + b.Height);
  123. //return new Rect (x1, y1, x2 - x1, y2 - y1);
  124. int x1 = Math.Min (a.X, b.X);
  125. int x2 = Math.Max (a.X + Math.Abs (a.Width), b.X + Math.Abs (b.Width));
  126. int y1 = Math.Min (a.Y, b.Y);
  127. int y2 = Math.Max (a.Y + Math.Abs (a.Height), b.Y + Math.Abs (b.Height));
  128. return new Rectangle (x1, y1, x2 - x1, y2 - y1);
  129. }
  130. /// <summary>Equality Operator</summary>
  131. /// <remarks>
  132. /// Compares two Rectangle objects. The return value is based on the equivalence of the Location and Size
  133. /// properties of the two Rectangles.
  134. /// </remarks>
  135. public static bool operator == (Rectangle left, Rectangle right) { return left.Location == right.Location && left.Size == right.Size; }
  136. /// <summary>Inequality Operator</summary>
  137. /// <remarks>
  138. /// Compares two Rectangle objects. The return value is based on the equivalence of the Location and Size
  139. /// properties of the two Rectangles.
  140. /// </remarks>
  141. public static bool operator != (Rectangle left, Rectangle right) { return left.Location != right.Location || left.Size != right.Size; }
  142. // -----------------------
  143. // Public Constructors
  144. // -----------------------
  145. /// <summary>Rectangle Constructor</summary>
  146. /// <remarks>Creates a Rectangle from Point and Size values.</remarks>
  147. public Rectangle (Point location, Size size)
  148. {
  149. X = location.X;
  150. Y = location.Y;
  151. width = size.Width;
  152. height = size.Height;
  153. Width = width;
  154. Height = height;
  155. }
  156. /// <summary>Rectangle Constructor</summary>
  157. /// <remarks>Creates a Rectangle from a specified x,y location and width and height values.</remarks>
  158. public Rectangle (int x, int y, int width, int height)
  159. {
  160. X = x;
  161. Y = y;
  162. this.width = width;
  163. this.height = height;
  164. Width = this.width;
  165. Height = this.height;
  166. }
  167. /// <summary>Bottom Property</summary>
  168. /// <remarks>The Y coordinate of the bottom edge of the Rectangle. Read only.</remarks>
  169. public int Bottom => Y + Height;
  170. /// <summary>IsEmpty Property</summary>
  171. /// <remarks>Indicates if the width or height are zero. Read only.</remarks>
  172. public bool IsEmpty => X == 0 && Y == 0 && Width == 0 && Height == 0;
  173. /// <summary>Left Property</summary>
  174. /// <remarks>The X coordinate of the left edge of the Rectangle. Read only.</remarks>
  175. public int Left => X;
  176. /// <summary>Location Property</summary>
  177. /// <remarks>The Location of the top-left corner of the Rectangle.</remarks>
  178. public Point Location
  179. {
  180. get => new (X, Y);
  181. set
  182. {
  183. X = value.X;
  184. Y = value.Y;
  185. }
  186. }
  187. /// <summary>Right Property</summary>
  188. /// <remarks>The X coordinate of the right edge of the Rectangle. Read only.</remarks>
  189. public int Right => X + Width;
  190. /// <summary>Size Property</summary>
  191. /// <remarks>The Size of the Rectangle.</remarks>
  192. public Size Size
  193. {
  194. get => new (Width, Height);
  195. set
  196. {
  197. Width = value.Width;
  198. Height = value.Height;
  199. }
  200. }
  201. /// <summary>Top Property</summary>
  202. /// <remarks>The Y coordinate of the top edge of the Rectangle. Read only.</remarks>
  203. public int Top => Y;
  204. /// <summary>Contains Method</summary>
  205. /// <remarks>Checks if an x,y coordinate lies within this Rectangle.</remarks>
  206. public bool Contains (int x, int y) { return x >= Left && x < Right && y >= Top && y < Bottom; }
  207. /// <summary>Contains Method</summary>
  208. /// <remarks>Checks if a Point lies within this Rectangle.</remarks>
  209. public bool Contains (Point pt) { return Contains (pt.X, pt.Y); }
  210. /// <summary>Contains Method</summary>
  211. /// <remarks>Checks if a Rectangle lies entirely within this Rectangle.</remarks>
  212. public bool Contains (Rectangle rect) { return rect == Intersect (this, rect); }
  213. /// <summary>Equals Method</summary>
  214. /// <remarks>Checks equivalence of this Rectangle and another object.</remarks>
  215. public override bool Equals (object obj)
  216. {
  217. if (!(obj is Rectangle))
  218. {
  219. return false;
  220. }
  221. return this == (Rectangle)obj;
  222. }
  223. /// <summary>GetHashCode Method</summary>
  224. /// <remarks>Calculates a hashing value.</remarks>
  225. public override int GetHashCode () { return (Height + Width) ^ (X + Y); }
  226. /// <summary>IntersectsWith Method</summary>
  227. /// <remarks>Checks if a Rectangle intersects with this one.</remarks>
  228. public bool IntersectsWith (Rectangle rect) { return !(Left >= rect.Right || Right <= rect.Left || Top >= rect.Bottom || Bottom <= rect.Top); }
  229. private bool IntersectsWithInclusive (Rectangle r) { return !(Left > r.Right || Right < r.Left || Top > r.Bottom || Bottom < r.Top); }
  230. /// <summary>Offset Method</summary>
  231. /// <remarks>Moves the Rectangle a specified distance.</remarks>
  232. public void Offset (int x, int y)
  233. {
  234. X += x;
  235. Y += y;
  236. }
  237. /// <summary>Offset Method</summary>
  238. /// <remarks>Moves the Rectangle a specified distance.</remarks>
  239. public void Offset (Point pos)
  240. {
  241. X += pos.X;
  242. Y += pos.Y;
  243. }
  244. /// <summary>ToString Method</summary>
  245. /// <remarks>Formats the Rectangle as a string in (x,y,w,h) notation.</remarks>
  246. public override string ToString () { return $"{{X={X},Y={Y},Width={Width},Height={Height}}}"; }
  247. }