RectangleF.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Runtime.Serialization;
  5. using Microsoft.Xna.Framework;
  6. namespace MonoGame.Extended;
  7. /// <summary>
  8. /// An axis-aligned rectangular volume defined by position, width, and height.
  9. /// </summary>
  10. [DataContract]
  11. [DebuggerDisplay("{DebugDisplayString,nq}")]
  12. public struct RectangleF : IEquatable<RectangleF>
  13. {
  14. #region Fields
  15. private static readonly RectangleF s_empty = new RectangleF(0.0f, 0.0f, 0.0f, 0.0f);
  16. /// <summary>
  17. /// The x-coordinate of the rectangle's top-left corner.
  18. /// </summary>
  19. [DataMember]
  20. public float X;
  21. /// <summary>
  22. /// The y-coordinate of the rectangle's top-left corner.
  23. /// </summary>
  24. [DataMember]
  25. public float Y;
  26. /// <summary>
  27. /// The horizontal extent of the rectangle.
  28. /// </summary>
  29. [DataMember]
  30. public float Width;
  31. /// <summary>
  32. /// The vertical extent of the rectangle.
  33. /// </summary>
  34. [DataMember]
  35. public float Height;
  36. #endregion
  37. #region Properties
  38. /// <summary>
  39. /// A rectangle with all components set to zero.
  40. /// </summary>
  41. public static RectangleF Empty => s_empty;
  42. /// <summary>
  43. /// Whether this rectangle has zero position, width, and height.
  44. /// </summary>
  45. public readonly bool IsEmpty => Width.Equals(0) && Height.Equals(0) && X.Equals(0) && Y.Equals(0);
  46. /// <summary>
  47. /// The horizontal position of the rectangle's left edge.
  48. /// </summary>
  49. public readonly float Left => X;
  50. /// <summary>
  51. /// The horizontal position of the rectangle's right edge.
  52. /// </summary>
  53. public readonly float Right => X + Width;
  54. /// <summary>
  55. /// The vertical position of the rectangle's top edge.
  56. /// </summary>
  57. public readonly float Top => Y;
  58. /// <summary>
  59. /// The vertical position of the rectangle's bottom edge.
  60. /// </summary>
  61. public readonly float Bottom => Y + Height;
  62. /// <summary>
  63. /// The position of the rectangle's top-left corner.
  64. /// </summary>
  65. public Vector2 Location
  66. {
  67. readonly get
  68. {
  69. return new Vector2(X, Y);
  70. }
  71. set
  72. {
  73. X = value.X;
  74. Y = value.Y;
  75. }
  76. }
  77. /// <summary>
  78. /// The dimensions of the rectangle.
  79. /// </summary>
  80. public SizeF Size
  81. {
  82. readonly get
  83. {
  84. return new SizeF(Width, Height);
  85. }
  86. set
  87. {
  88. Width = value.Width;
  89. Height = value.Height;
  90. }
  91. }
  92. /// <summary>
  93. /// The position of the rectangle's geometric center.
  94. /// </summary>
  95. public readonly Vector2 Center => new Vector2(X + Width * 0.5f, Y + Height * 0.5f);
  96. /// <summary>
  97. /// The position of the rectangle's top-left corner.
  98. /// </summary>
  99. public readonly Vector2 TopLeft => new Vector2(X, Y);
  100. /// <summary>
  101. /// The position of the rectangle's top-right corner.
  102. /// </summary>
  103. public readonly Vector2 TopRight => new Vector2(X + Width, Y);
  104. /// <summary>
  105. /// The position of the rectangle's bottom-left corner.
  106. /// </summary>
  107. public readonly Vector2 BottomLeft => new Vector2(X, Y + Height);
  108. /// <summary>
  109. /// The position of the rectangle's bottom-right corner.
  110. /// </summary>
  111. public readonly Vector2 BottomRight => new Vector2(X + Width, Y + Height);
  112. #endregion
  113. #region Constructors
  114. /// <summary>
  115. /// Initializes a rectangle from position and dimensions.
  116. /// </summary>
  117. /// <param name="x">The x-coordinate of the rectangle's top-left corner.</param>
  118. /// <param name="y">The y-coordinate of the rectangle's top-left corner.</param>
  119. /// <param name="width">The horizontal extent of the rectangle.</param>
  120. /// <param name="height">The vertical extent of the rectangle.</param>
  121. public RectangleF(float x, float y, float width, float height)
  122. {
  123. X = x;
  124. Y = y;
  125. Width = width;
  126. Height = height;
  127. }
  128. /// <summary>
  129. /// Initializes a rectangle from position and size components.
  130. /// </summary>
  131. /// <param name="position">The position of the rectangle's top-left corner.</param>
  132. /// <param name="size">The dimensions of the rectangle.</param>
  133. public RectangleF(Vector2 position, SizeF size)
  134. {
  135. X = position.X;
  136. Y = position.Y;
  137. Width = size.Width;
  138. Height = size.Height;
  139. }
  140. #endregion
  141. #region Create From Methods
  142. /// <summary>
  143. /// Creates a rectangle from two corner points.
  144. /// </summary>
  145. /// <param name="minimum">The minimum corner coordinates (typically top-left).</param>
  146. /// <param name="maximum">The maximum corner coordinates (typically bottom-right).</param>
  147. /// <returns>A rectangle spanning from the minimum to maximum points.</returns>
  148. public static RectangleF CreateFrom(Vector2 minimum, Vector2 maximum)
  149. {
  150. return new RectangleF(
  151. minimum.X,
  152. minimum.Y,
  153. maximum.X - minimum.X,
  154. maximum.Y - minimum.Y
  155. );
  156. }
  157. /// <summary>
  158. /// Creates the smallest rectangle that contains all specified points.
  159. /// </summary>
  160. /// <param name="points">The collection of points to enclose.</param>
  161. /// <returns>
  162. /// The axis-aligned bounding rectangle containing all points, or <see cref="Empty"/> if no points are provided.
  163. /// </returns>
  164. /// <remarks>
  165. /// Computes the axis-aligned bounding box by finding the minimum and maximum x and y coordinates
  166. /// among all provided points. The resulting rectangle will have the smallest area that contains
  167. /// all input points.
  168. /// </remarks>
  169. public static RectangleF CreateFrom(IReadOnlyList<Vector2> points)
  170. {
  171. if (points == null || points.Count == 0)
  172. {
  173. return Empty;
  174. }
  175. float minX = points[0].X;
  176. float minY = points[0].Y;
  177. float maxX = minX;
  178. float maxY = minY;
  179. for (int i = 1; i < points.Count; i++)
  180. {
  181. Vector2 point = points[i];
  182. if (point.X < minX) minX = point.X;
  183. if (point.Y < minY) minY = point.Y;
  184. if (point.X > maxX) maxX = point.X;
  185. if (point.Y > maxY) maxY = point.Y;
  186. }
  187. return new RectangleF(minX, minY, maxX - minX, maxY - minY);
  188. }
  189. #endregion
  190. #region Union Methods
  191. /// <summary>
  192. /// Expands this rectangle to contain the specified rectangle.
  193. /// </summary>
  194. /// <param name="rectangle">The rectangle to include.</param>
  195. public void Union(RectangleF rectangle)
  196. {
  197. X = Math.Min(X, rectangle.X);
  198. Y = Math.Min(Y, rectangle.Y);
  199. Width = Math.Max(Right, rectangle.Right) - X;
  200. Height = Math.Max(Bottom, rectangle.Bottom) - Y;
  201. }
  202. /// <summary>
  203. /// Computes the <see cref="RectangleF" /> that contains the two specified
  204. /// <see cref="RectangleF" /> structures.
  205. /// </summary>
  206. /// <param name="first">The first rectangle.</param>
  207. /// <param name="second">The second rectangle.</param>
  208. /// <returns>
  209. /// An <see cref="RectangleF" /> that contains both the <paramref name="first" /> and the
  210. /// <paramref name="second" />.
  211. /// </returns>
  212. public static RectangleF Union(ref RectangleF first, ref RectangleF second)
  213. {
  214. float x = Math.Min(first.X, second.X);
  215. float y = Math.Min(first.Y, second.Y);
  216. float width = Math.Max(first.Right, second.Right) - x;
  217. float height = Math.Max(first.Bottom, second.Bottom) - y;
  218. return new RectangleF(x, y, width, height);
  219. }
  220. #endregion
  221. #region Normalize Methods
  222. /// <summary>
  223. /// Normalizes this <see cref="RectangleF"/> so that the <see cref="Width"/> and <see cref="Height"/> are
  224. /// positive without changing the location of the rectangle.
  225. /// </summary>
  226. public void Normalize()
  227. {
  228. if (Width < 0)
  229. {
  230. X += Width;
  231. Width = -Width;
  232. }
  233. if (Height < 0)
  234. {
  235. Y += Height;
  236. Height = -Height;
  237. }
  238. }
  239. /// <summary>
  240. /// Normalizes the specified <see cref="RectangleF"/> so that the <see cref="Width"/> and <see cref="Height"/>
  241. /// are positive without changing the location of the rectangle.
  242. /// </summary>
  243. /// <param name="rectangle">The <see cref="RectangleF"/> to normalize.</param>
  244. /// <returns>A <see cref="RectangleF"/> with positive width and height.</returns>
  245. public static RectangleF Normalize(RectangleF rectangle)
  246. {
  247. if (rectangle.Width < 0)
  248. {
  249. rectangle.X += rectangle.Width;
  250. rectangle.Width = -rectangle.Width;
  251. }
  252. if (rectangle.Height < 0)
  253. {
  254. rectangle.Y += rectangle.Height;
  255. rectangle.Height = -rectangle.Height;
  256. }
  257. return rectangle;
  258. }
  259. #endregion
  260. #region Containment Methods
  261. /// <summary>
  262. /// Determines whether this <see cref="RectangleF" /> contains the specified
  263. /// <see cref="Vector2" />.
  264. /// </summary>
  265. /// <param name="point">The point.</param>
  266. /// <returns>
  267. /// <c>true</c> if the this <see cref="RectangleF"/> contains the <paramref name="point" />; otherwise,
  268. /// <c>false</c>.
  269. /// </returns>
  270. public bool Contains(Vector2 point)
  271. {
  272. return Left <= point.X
  273. && point.X < Right
  274. && Top <= point.Y
  275. && point.Y < Bottom;
  276. }
  277. /// <summary>
  278. /// Determines whether the specified <see cref="RectangleF" /> contains the specified
  279. /// <see cref="Vector2" />.
  280. /// </summary>
  281. /// <param name="rectangle">The rectangle.</param>
  282. /// <param name="point">The point.</param>
  283. /// <returns>
  284. /// <c>true</c> if the <paramref name="rectangle" /> contains the <paramref name="point" />; otherwise,
  285. /// <c>false</c>.
  286. /// </returns>
  287. public static bool Contains(RectangleF rectangle, Vector2 point)
  288. {
  289. return rectangle.Left <= point.X
  290. && point.X < rectangle.Right
  291. && rectangle.Top <= point.Y
  292. && point.Y < rectangle.Bottom;
  293. }
  294. #endregion
  295. #region Intersection Methods
  296. /// <summary>
  297. /// Modifies this rectangle to represent the intersection with the specified rectangle.
  298. /// </summary>
  299. /// <param name="rectangle">The rectangle to intersect with.</param>
  300. public void Intersect(RectangleF rectangle)
  301. {
  302. float left = Math.Max(Left, rectangle.Left);
  303. float top = Math.Max(Top, rectangle.Top);
  304. float right = Math.Min(Right, rectangle.Right);
  305. float bottom = Math.Min(Bottom, rectangle.Bottom);
  306. if (right < left || bottom < top)
  307. {
  308. this = Empty;
  309. return;
  310. }
  311. X = left;
  312. Y = top;
  313. Width = right - left;
  314. Height = bottom - top;
  315. }
  316. /// <summary>
  317. /// Computes the <see cref="RectangleF"/> that represents the intersection of two <see cref="RectangleF"/>
  318. /// structures.
  319. /// </summary>
  320. /// <param name="value1">The first rectangle to intersect.</param>
  321. /// <param name="value2">The second rectangle to intersect.</param>
  322. /// <returns>
  323. /// A <see cref="RectangleF"/> that represents the intersection of <paramref name="value1"/> and
  324. /// <paramref name="value2"/>, if there is an intersection; otherwise, <see cref="RectangleF.Empty"/>.
  325. /// </returns>
  326. public static RectangleF Intersect(RectangleF value1, RectangleF value2)
  327. {
  328. float left = Math.Max(value1.Left, value2.Left);
  329. float top = Math.Max(value1.Top, value2.Top);
  330. float right = Math.Min(value1.Right, value2.Right);
  331. float bottom = Math.Min(value1.Bottom, value2.Bottom);
  332. if (right < left || bottom < top)
  333. {
  334. return Empty;
  335. }
  336. return new RectangleF(left, top, right - left, bottom - top);
  337. }
  338. /// <summary>
  339. /// Determines whether this rectangle intersects with another rectangle.
  340. /// </summary>
  341. /// <param name="other">The other rectangle to test for intersection.</param>
  342. /// <returns>
  343. /// <see langword="true"/> if this rectangle intersects the other; otherwise, <see langword="false"/>.
  344. /// </returns>
  345. public readonly bool Intersects(RectangleF other) => IntersectionTests.RectangleFRectangleF(in this, in other);
  346. /// <summary>
  347. /// Determines whether this rectangle intersects with a circle.
  348. /// </summary>
  349. /// <param name="circle">The circle to test for intersection.</param>
  350. /// <returns>
  351. /// <see langword="true"/> if this rectangle intersects the circle; otherwise, <see langword="false"/>.
  352. /// </returns>
  353. public readonly bool Intersects(Circle circle) => IntersectionTests.CircleRectangleF(in circle, in this);
  354. /// <summary>
  355. /// Determines whether this rectangle intersects with an ellipse.
  356. /// </summary>
  357. /// <param name="ellipse">The ellipse to test for intersection.</param>
  358. /// <returns>
  359. /// <see langword="true"/> if this rectangle intersects the ellipse; otherwise, <see langword="false"/>.
  360. /// </returns>
  361. public readonly bool Intersects(Ellipse ellipse) => IntersectionTests.EllipseRectangleF(in ellipse, in this);
  362. /// <summary>
  363. /// Determines whether this rectangle intersects with a ray.
  364. /// </summary>
  365. /// <param name="ray">The ray to test for intersection.</param>
  366. /// <returns>
  367. /// <see langword="true"/> if this rectangle intersects the ray; otherwise, <see langword="false"/>.
  368. /// </returns>
  369. public readonly bool Intersects(Ray ray) => IntersectionTests.RectangleFRay(in this, in ray);
  370. /// <summary>
  371. /// Determines whether this rectangle intersects with a line segment.
  372. /// </summary>
  373. /// <param name="lineSegment">The line segment to test for intersection.</param>
  374. /// <returns>
  375. /// <see langword="true"/> if this rectangle intersects the line segment; otherwise, <see langword="false"/>.
  376. /// </returns>
  377. public readonly bool Intersects(LineSegment lineSegment) => IntersectionTests.RectangleFLineSegment(in this, in lineSegment);
  378. #endregion
  379. #region Closest Point To Methods
  380. /// <summary>
  381. /// Computes the closest <see cref="Vector2" /> on this <see cref="RectangleF" /> to a specified
  382. /// <see cref="Vector2" />.
  383. /// </summary>
  384. /// <param name="point">The point.</param>
  385. /// <returns>The closest <see cref="Vector2" /> on this <see cref="RectangleF" /> to the <paramref name="point" />.</returns>
  386. public readonly Vector2 ClosestPointTo(Vector2 point)
  387. {
  388. Vector2 result = point;
  389. if (result.X < Left)
  390. {
  391. result.X = Left;
  392. }
  393. else if (result.X > Right)
  394. {
  395. result.X = Right;
  396. }
  397. if (result.Y < Top)
  398. {
  399. result.Y = Top;
  400. }
  401. else if (result.Y > Bottom)
  402. {
  403. result.Y = Bottom;
  404. }
  405. return result;
  406. }
  407. #endregion
  408. #region Distance Methods
  409. /// <summary>
  410. /// Calculates the distance from this rectangle to the specified point.
  411. /// </summary>
  412. /// <param name="point">The point to measure distance to.</param>
  413. /// <returns>The distance to the point, or zero if the point is inside the rectangle.</returns>
  414. public readonly float DistanceTo(Vector2 point)
  415. {
  416. return MathF.Sqrt(DistanceToSquared(point));
  417. }
  418. /// <summary>
  419. /// Calculates the squared distance from this rectangle to the specified point.
  420. /// </summary>
  421. /// <param name="point">The point to measure distance to.</param>
  422. /// <returns>The squared distance to the point, or zero if the point is inside the rectangle.</returns>
  423. public readonly float DistanceToSquared(Vector2 point)
  424. {
  425. float squaredDistance = 0.0f;
  426. if (point.X < Left)
  427. {
  428. float distance = Left - point.X;
  429. squaredDistance += distance * distance;
  430. }
  431. else if (point.X > Right)
  432. {
  433. float distance = point.X - Right;
  434. squaredDistance += distance * distance;
  435. }
  436. if (point.Y < Top)
  437. {
  438. float distance = Top - point.Y;
  439. squaredDistance += distance * distance;
  440. }
  441. else if (point.Y > Bottom)
  442. {
  443. float distance = point.Y - Bottom;
  444. squaredDistance += distance * distance;
  445. }
  446. return squaredDistance;
  447. }
  448. #endregion
  449. #region Offset Methods
  450. /// <summary>
  451. /// Moves this rectangle by the specified offset.
  452. /// </summary>
  453. /// <param name="amount">The amount to move horizontally and vertically.</param>
  454. public void Offset(Vector2 amount)
  455. {
  456. X += amount.X;
  457. Y += amount.Y;
  458. }
  459. /// <summary>
  460. /// Returns a rectangle moved by the specified offset.
  461. /// </summary>
  462. /// <param name="rectangle">The rectangle to move.</param>
  463. /// <param name="amount">The amount to move horizontally and vertically.</param>
  464. /// <returns>The moved rectangle.</returns>
  465. public static RectangleF Offset(RectangleF rectangle, Vector2 amount)
  466. {
  467. return rectangle with { X = rectangle.X + amount.X, Y = rectangle.Y + amount.Y };
  468. }
  469. #endregion
  470. #region Inflate Methods
  471. /// <summary>
  472. /// Inflates this rectangle by the specified amount in both directions.
  473. /// </summary>
  474. /// <param name="amount">The amount to inflate horizontally and vertically.</param>
  475. public void Inflate(Vector2 amount)
  476. {
  477. X -= amount.X;
  478. Y -= amount.Y;
  479. Width += amount.X * 2.0f;
  480. Height += amount.Y * 2.0f;
  481. }
  482. /// <summary>
  483. /// Returns an inflated rectangle from the specified rectangle and amount.
  484. /// </summary>
  485. /// <param name="rectangle">The rectangle to inflate.</param>
  486. /// <param name="amount">The amount to inflate horizontally and vertically.</param>
  487. /// <returns>The inflated rectangle.</returns>
  488. public static RectangleF Inflate(RectangleF rectangle, Vector2 amount)
  489. {
  490. return new RectangleF(
  491. rectangle.X - amount.X,
  492. rectangle.Y - amount.Y,
  493. rectangle.Width + amount.X * 2.0f,
  494. rectangle.Height + amount.Y * 2.0f
  495. );
  496. }
  497. #endregion
  498. #region Transform Methods
  499. /// <summary>
  500. /// Transforms this rectangle using the specified matrix.
  501. /// </summary>
  502. /// <param name="matrix">The transformation matrix.</param>
  503. public void Transform(Matrix3x2 matrix)
  504. {
  505. Transform(ref matrix);
  506. }
  507. /// <summary>
  508. /// Transforms this rectangle using the specified matrix.
  509. /// </summary>
  510. /// <param name="matrix">The transformation matrix.</param>
  511. public void Transform(ref Matrix3x2 matrix)
  512. {
  513. Vector2 center = Center;
  514. Vector2 halfExtents = Size * 0.5f;
  515. PrimitivesHelper.TransformRectangle(ref center, ref halfExtents, ref matrix);
  516. X = center.X + halfExtents.X;
  517. Y = center.Y + halfExtents.Y;
  518. Width = halfExtents.X * 2.0f;
  519. Height = halfExtents.Y * 2.0f;
  520. }
  521. /// <summary>
  522. /// Transforms the specified rectangle using the given matrix.
  523. /// </summary>
  524. /// <param name="rectangle">The rectangle to transform.</param>
  525. /// <param name="transformMatrix">The transformation matrix.</param>
  526. /// <returns>The transformed rectangle.</returns>
  527. /// <remarks>
  528. /// <para>
  529. /// If a previously transformed rectangle is used, the resulting rectangle will have compounded transformations.
  530. /// </para>
  531. /// </remarks>
  532. public static RectangleF Transform(RectangleF rectangle, Matrix3x2 transformMatrix)
  533. {
  534. return Transform(rectangle, ref transformMatrix);
  535. }
  536. /// <summary>
  537. /// Transforms the specified rectangle using the given matrix.
  538. /// </summary>
  539. /// <param name="rectangle">The rectangle to transform.</param>
  540. /// <param name="transformMatrix">The transformation matrix.</param>
  541. /// <returns>The transformed rectangle.</returns>
  542. public static RectangleF Transform(RectangleF rectangle, ref Matrix3x2 transformMatrix)
  543. {
  544. Vector2 center = rectangle.Center;
  545. Vector2 halfExtents = (Vector2)rectangle.Size * 0.5f;
  546. PrimitivesHelper.TransformRectangle(ref center, ref halfExtents, ref transformMatrix);
  547. float x = center.X - halfExtents.X;
  548. float y = center.Y - halfExtents.Y;
  549. float width = halfExtents.X * 2;
  550. float height = halfExtents.Y * 2;
  551. return new RectangleF(x, y, width, height);
  552. }
  553. #endregion
  554. #region Equality Methods
  555. /// <summary>
  556. /// Returns a value indicating whether this <see cref="RectangleF" /> is equal to a specified object.
  557. /// </summary>
  558. /// <param name="obj">The object to make the comparison with.</param>
  559. /// <returns>
  560. /// <c>true</c> if this <see cref="RectangleF" /> is equal to <paramref name="obj" />; otherwise, <c>false</c>.
  561. /// </returns>
  562. public readonly override bool Equals(object obj)
  563. {
  564. return obj is RectangleF other && Equals(other);
  565. }
  566. /// <summary>
  567. /// Indicates whether this <see cref="RectangleF" /> is equal to another <see cref="RectangleF" />.
  568. /// </summary>
  569. /// <param name="rectangle">The rectangle.</param>
  570. /// <returns>
  571. /// <c>true</c> if this <see cref="RectangleF" /> is equal to the <paramref name="rectangle" />; otherwise, <c>false</c>.
  572. /// </returns>
  573. public readonly bool Equals(RectangleF rectangle)
  574. {
  575. return X == rectangle.X
  576. && Y == rectangle.Y
  577. && Width == rectangle.Width
  578. && Height == rectangle.Height;
  579. }
  580. #endregion
  581. /// <summary>
  582. /// Returns a hash code of this <see cref="RectangleF" /> suitable for use in hashing algorithms and data
  583. /// structures like a hash table.
  584. /// </summary>
  585. /// <returns>
  586. /// A hash code of this <see cref="RectangleF" />.
  587. /// </returns>
  588. public override int GetHashCode()
  589. {
  590. return HashCode.Combine(X, Y, Width, Height);
  591. }
  592. /// <summary>
  593. /// Returns a <see cref="string" /> that represents this <see cref="RectangleF" />.
  594. /// </summary>
  595. /// <returns>
  596. /// A <see cref="string" /> that represents this <see cref="RectangleF" />.
  597. /// </returns>
  598. public override string ToString()
  599. {
  600. return $"X: {X}, Y: {Y}, Width: {Width}, Height: {Height}";
  601. }
  602. internal string DebugDisplayString => string.Concat(X, " ", Y, " ", Width, " ", Height);
  603. #region Operators
  604. /// <summary>
  605. /// Compares two <see cref="RectangleF" /> structures. The result specifies whether the values of the
  606. /// <see cref="X" />, <see cref="Y"/>, <see cref="Width"/> and <see cref="Height" /> fields of the two <see cref="RectangleF" /> structures
  607. /// are equal.
  608. /// </summary>
  609. /// <param name="left">The first rectangle.</param>
  610. /// <param name="right">The second rectangle.</param>
  611. /// <returns>
  612. /// <c>true</c> if the values of the
  613. /// <see cref="X" />, <see cref="Y"/>, <see cref="Width"/> and <see cref="Height" /> fields of the two <see cref="RectangleF" /> structures
  614. /// are equal; otherwise, <c>false</c>.
  615. /// </returns>
  616. public static bool operator ==(RectangleF left, RectangleF right)
  617. {
  618. return left.Equals(right);
  619. }
  620. /// <summary>
  621. /// Compares two <see cref="RectangleF" /> structures. The result specifies whether the values of the
  622. /// <see cref="X" />, <see cref="Y"/>, <see cref="Width"/> and <see cref="Height" /> fields of the two <see cref="RectangleF" /> structures
  623. /// are unequal.
  624. /// </summary>
  625. /// <param name="left">The first rectangle.</param>
  626. /// <param name="right">The second rectangle.</param>
  627. /// <returns>
  628. /// <c>true</c> if the values of the
  629. /// <see cref="X" />, <see cref="Y"/>, <see cref="Width"/> and <see cref="Height" /> fields of the two <see cref="RectangleF" /> structures
  630. /// are unequal; otherwise, <c>false</c>.
  631. /// </returns>
  632. public static bool operator !=(RectangleF left, RectangleF right)
  633. {
  634. return !left.Equals(right);
  635. }
  636. /// <summary>
  637. /// Performs an implicit conversion from a <see cref="Rectangle" /> to a <see cref="RectangleF" />.
  638. /// </summary>
  639. /// <param name="rectangle">The rectangle.</param>
  640. /// <returns>
  641. /// The resulting <see cref="RectangleF" />.
  642. /// </returns>
  643. public static implicit operator RectangleF(Rectangle rectangle)
  644. {
  645. return new RectangleF(
  646. rectangle.X,
  647. rectangle.Y,
  648. rectangle.Width,
  649. rectangle.Height
  650. );
  651. }
  652. /// <summary>
  653. /// Performs an explicit conversion from a <see cref="Rectangle" /> to a <see cref="RectangleF" />.
  654. /// </summary>
  655. /// <param name="rectangle">The rectangle.</param>
  656. /// <returns>
  657. /// The resulting <see cref="RectangleF" />.
  658. /// </returns>
  659. /// <remarks>
  660. /// <para>A loss of precision may occur due to the truncation from <see cref="float" /> to <see cref="int" />.</para>
  661. /// </remarks>
  662. public static explicit operator Rectangle(RectangleF rectangle)
  663. {
  664. return new Rectangle(
  665. (int)rectangle.X,
  666. (int)rectangle.Y,
  667. (int)rectangle.Width,
  668. (int)rectangle.Height
  669. );
  670. }
  671. #endregion
  672. }