PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Datatypes/Rectangle.cs

#
C# | 1481 lines | 890 code | 112 blank | 479 comment | 23 complexity | bfc9aba220937da6f8153edaab1a74cc MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.ComponentModel;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. using Delta.Utilities.Datatypes.Advanced;
  8. using Delta.Utilities.Helpers;
  9. using Delta.Utilities.Profiling;
  10. using NUnit.Framework;
  11. // Disable warnings for some tests where we don't use created values
  12. #pragma warning disable 219
  13. namespace Delta.Utilities.Datatypes
  14. {
  15. /// <summary>
  16. /// Rectangle class, just consists of x, y, width and height (all float
  17. /// values). There is a possibility to rotate rectangles with the Rotate
  18. /// method, but the rotation data is not kept. This is mostly because
  19. /// passing big structures around in the engine is too slow. It is actually
  20. /// faster just to calculate the rotation if really needed (it is not
  21. /// needed much anyway). Performance testing is at the end of this file!
  22. /// </summary>
  23. [Serializable]
  24. [StructLayout(LayoutKind.Explicit)]
  25. [DebuggerDisplay("Rectangle(X={X}, Y={Y}, Width={Width}, Height={Height})")]
  26. [Description("Expand to edit this Rectangle")]
  27. [TypeConverter(typeof(ExpandableObjectConverter))]
  28. public struct Rectangle : ISaveLoadBinary, IEquatable<Rectangle>
  29. {
  30. #region Constants
  31. /// <summary>
  32. /// Returns a rectangle at the position (0,0) with the size (0,0).
  33. /// -> Can be used to determine if a rectangle is "used" or not.
  34. /// </summary>
  35. public static readonly Rectangle Zero =
  36. new Rectangle(0.0f, 0.0f, 0.0f, 0.0f);
  37. /// <summary>
  38. /// Returns a rectangle at the position (0,0) and with the size (1,1).
  39. /// -> Can be used for fullscreen rendering or for the full UV layout.
  40. /// </summary>
  41. public static readonly Rectangle One =
  42. new Rectangle(0.0f, 0.0f, 1.0f, 1.0f);
  43. #endregion
  44. #region FromCenter (Static)
  45. /// <summary>
  46. /// Create a new rectangle from a center position and given size.
  47. /// </summary>
  48. /// <param name="setCenterX">
  49. /// The x coordinate of the rectangle center.
  50. /// </param>
  51. /// <param name="setCenterY">
  52. /// The y coordinate of the rectangle center.
  53. /// </param>
  54. /// <param name="setWidth">Width of the new rectangle.</param>
  55. /// <param name="setHeight">Height of the new rectangle.</param>
  56. /// <returns>Rectangle</returns>
  57. public static Rectangle FromCenter(float setCenterX, float setCenterY,
  58. float setWidth, float setHeight)
  59. {
  60. return new Rectangle(
  61. setCenterX - setWidth * 0.5f,
  62. setCenterY - setHeight * 0.5f,
  63. setWidth,
  64. setHeight);
  65. }
  66. /// <summary>
  67. /// Create a new rectangle from a center position and given size.
  68. /// </summary>
  69. /// <param name="setCenterPosition">
  70. /// The center position of the rectangle.
  71. /// </param>
  72. /// <param name="setDimension">
  73. /// The dimension of the quadratic rectangle.
  74. /// </param>
  75. /// <returns>New rectangle created from center</returns>
  76. public static Rectangle FromCenter(Point setCenterPosition,
  77. float setDimension)
  78. {
  79. return new Rectangle(
  80. setCenterPosition.X - setDimension * 0.5f,
  81. setCenterPosition.Y - setDimension * 0.5f,
  82. setDimension,
  83. setDimension);
  84. }
  85. /// <summary>
  86. /// Create a new rectangle from a center position and given size.
  87. /// </summary>
  88. /// <param name="setCenterPosition">
  89. /// The center position of the rectangle.
  90. /// </param>
  91. /// <param name="setSize">
  92. /// The size of the rectangle.
  93. /// </param>
  94. /// <returns>New rectangle created from center</returns>
  95. public static Rectangle FromCenter(Point setCenterPosition, Size setSize)
  96. {
  97. return new Rectangle(
  98. setCenterPosition.X - setSize.WidthHalf,
  99. setCenterPosition.Y - setSize.HeightHalf,
  100. setSize.Width,
  101. setSize.Height);
  102. }
  103. #endregion
  104. #region FromCorners (Static)
  105. /// <summary>
  106. /// Creates a rectangle based on the given corner coordinates.
  107. /// </summary>
  108. /// <param name="TopLeft">Top left</param>
  109. /// <param name="BottomRight">Bottom right</param>
  110. public static Rectangle FromCorners(Point TopLeft, Point BottomRight)
  111. {
  112. return new Rectangle(
  113. TopLeft.X, TopLeft.Y,
  114. BottomRight.X - TopLeft.X,
  115. BottomRight.Y - TopLeft.Y);
  116. }
  117. #endregion
  118. #region FromColladaString (Static)
  119. /// <summary>
  120. /// From collada string, the opposite of the ToColladaString method.
  121. /// </summary>
  122. public static Rectangle FromColladaString(string colladaString)
  123. {
  124. if (String.IsNullOrEmpty(colladaString))
  125. {
  126. return Zero;
  127. }
  128. string[] splittedValues = colladaString.Split(new[]
  129. {
  130. ' '
  131. });
  132. if (splittedValues.Length != 4)
  133. {
  134. Log.Warning("Unable to convert colladaString=" + colladaString +
  135. " to Rectangle because it does not have 4 values separated by " +
  136. "spaces!");
  137. return Zero;
  138. }
  139. CultureInfo invariantCulture = CultureInfo.InvariantCulture;
  140. return new Rectangle(
  141. Convert.ToSingle(splittedValues[0], invariantCulture),
  142. Convert.ToSingle(splittedValues[1], invariantCulture),
  143. Convert.ToSingle(splittedValues[2], invariantCulture),
  144. Convert.ToSingle(splittedValues[3], invariantCulture));
  145. }
  146. #endregion
  147. #region FromCommaString (Static)
  148. /// <summary>
  149. /// From comma string, the opposite of the ToCommaString method.
  150. /// </summary>
  151. /// <param name="commaString">CommaString</param>
  152. /// <returns>Rectangle created from the commaString</returns>
  153. public static Rectangle FromCommaString(string commaString)
  154. {
  155. if (String.IsNullOrEmpty(commaString))
  156. {
  157. return Zero;
  158. }
  159. string[] splittedValues = commaString.Split(new[]
  160. {
  161. ','
  162. });
  163. if (splittedValues.Length != 4)
  164. {
  165. Log.Warning(
  166. "Unable to convert colladaString=" + commaString +
  167. " to Rectangle because it does not have 4 values separated by " +
  168. "commas!");
  169. return Zero;
  170. }
  171. CultureInfo invariantCulture = CultureInfo.InvariantCulture;
  172. return new Rectangle(
  173. Convert.ToSingle(splittedValues[0], invariantCulture),
  174. Convert.ToSingle(splittedValues[1], invariantCulture),
  175. Convert.ToSingle(splittedValues[2], invariantCulture),
  176. Convert.ToSingle(splittedValues[3], invariantCulture));
  177. }
  178. #endregion
  179. #region BuildUVRectangle (Static)
  180. /// <summary>
  181. /// Build UV rectangle for a given image width and height. Will also
  182. /// take care of 0.5 pixel offseting, which is very important for 2d
  183. /// rendering and font rendering in particular. The offset is to make sure
  184. /// all pixels are offseted by 0.5, 0.5 (a little less actually) to make
  185. /// rendering work fine in XNA and DirectX modes. For OpenTK it works
  186. /// mostly without, but this seems to be driver specific, so with this
  187. /// offset everything still looks fine and won't hurt.
  188. /// </summary>
  189. /// <param name="x">X position</param>
  190. /// <param name="y">Y position</param>
  191. /// <param name="width">Width</param>
  192. /// <param name="height">Heigth</param>
  193. /// <param name="imageHeight">Total image height</param>
  194. /// <param name="imageWidth">Total image width</param>
  195. /// <returns>Created UV Rectangle from the given data</returns>
  196. public static Rectangle BuildUVRectangle(float x, float y, float width,
  197. float height, float imageWidth, float imageHeight)
  198. {
  199. // Warn if wrong or invalid imageWidth or imageHeight
  200. if (imageWidth == 0 ||
  201. imageHeight == 0)
  202. {
  203. Log.Warning("Image size=" + imageWidth + "*" + imageHeight +
  204. " is invalid for BuildUVRectangle, we need a valid image size!");
  205. return One;
  206. }
  207. return new Rectangle(
  208. x / imageWidth,
  209. y / imageHeight,
  210. width / imageWidth,
  211. height / imageHeight);
  212. }
  213. /// <summary>
  214. /// Build UV rectangle for a given uv pixel rect and imageSize. Will also
  215. /// take care of 0.5 pixel offseting, which is very important for 2d
  216. /// rendering and font rendering in particular. The offset is to make sure
  217. /// all pixels are offseted by 0.5, 0.5 (a little less actually) to make
  218. /// rendering work fine in XNA and DirectX modes. For OpenTK it works
  219. /// mostly without, but this seems to be driver specific, so with this
  220. /// offset everything still looks fine and won't hurt.
  221. /// <para>
  222. /// Warning: Do not use that for converting pixel space into quadratic
  223. /// space, use the Screen class for that.
  224. /// </para>
  225. /// </summary>
  226. /// <param name="uvInPixels">UV rectangle in pixels</param>
  227. /// <param name="bitmapSize">Bitmap size (to devide through)</param>
  228. /// <returns>Created UV Rectangle from the given data</returns>
  229. public static Rectangle BuildUVRectangle(Rectangle uvInPixels,
  230. Size bitmapSize)
  231. {
  232. return new Rectangle(
  233. uvInPixels.X / bitmapSize.Width,
  234. uvInPixels.Y / bitmapSize.Height,
  235. uvInPixels.Width / bitmapSize.Width,
  236. uvInPixels.Height / bitmapSize.Height);
  237. }
  238. #endregion
  239. #region X (Public)
  240. /// <summary>
  241. /// X coordinate of the position.
  242. /// </summary>
  243. [FieldOffset(0)]
  244. public float X;
  245. #endregion
  246. #region Y (Public)
  247. /// <summary>
  248. /// Y coordinate of the position.
  249. /// </summary>
  250. [FieldOffset(4)]
  251. public float Y;
  252. #endregion
  253. #region Width (Public)
  254. /// <summary>
  255. /// Width
  256. /// </summary>
  257. [FieldOffset(8)]
  258. public float Width;
  259. #endregion
  260. #region Height (Public)
  261. /// <summary>
  262. /// Height
  263. /// </summary>
  264. [FieldOffset(12)]
  265. public float Height;
  266. #endregion
  267. #region XProperty (Public)
  268. /// <summary>
  269. /// Property-wrapper for using the X field in the editor.
  270. /// </summary>
  271. [Browsable(true)]
  272. [DisplayName("X")]
  273. public float XProperty
  274. {
  275. get
  276. {
  277. return X;
  278. }
  279. set
  280. {
  281. X = value;
  282. }
  283. }
  284. #endregion
  285. #region YProperty (Public)
  286. /// <summary>
  287. /// Property-wrapper for using the Y field in the editor
  288. /// </summary>
  289. [Browsable(true)]
  290. [DisplayName("Y")]
  291. public float YProperty
  292. {
  293. get
  294. {
  295. return Y;
  296. }
  297. set
  298. {
  299. Y = value;
  300. }
  301. }
  302. #endregion
  303. #region WidthProperty (Public)
  304. /// <summary>
  305. /// Property-wrapper for using the X field in the editor.
  306. /// </summary>
  307. [Browsable(true)]
  308. [DisplayName("Width")]
  309. public float WidthProperty
  310. {
  311. get
  312. {
  313. return Width;
  314. }
  315. set
  316. {
  317. Width = value;
  318. }
  319. }
  320. #endregion
  321. #region HeightProperty (Public)
  322. /// <summary>
  323. /// Property-wrapper for using the Y field in the editor
  324. /// </summary>
  325. [Browsable(true)]
  326. [DisplayName("Height")]
  327. public float HeightProperty
  328. {
  329. get
  330. {
  331. return Height;
  332. }
  333. set
  334. {
  335. Height = value;
  336. }
  337. }
  338. #endregion
  339. #region Position (Public)
  340. /// <summary>
  341. /// Position of the rectangle, just X and Y
  342. /// </summary>
  343. [FieldOffset(0)]
  344. public Point Position;
  345. #endregion
  346. #region Size (Public)
  347. /// <summary>
  348. /// Gets or sets the Size of the rectangle, just Width and Height
  349. /// </summary>
  350. [FieldOffset(8)]
  351. public Size Size;
  352. #endregion
  353. #region IsZero (Public)
  354. /// <summary>
  355. /// Is zero
  356. /// </summary>
  357. [Browsable(false)]
  358. public bool IsZero
  359. {
  360. get
  361. {
  362. return Size.IsZero;
  363. }
  364. }
  365. #endregion
  366. #region Left (Public)
  367. /// <summary>
  368. /// Left edge, same as X
  369. /// </summary>
  370. [FieldOffset(0)]
  371. public float Left;
  372. #endregion
  373. #region Right (Public)
  374. /// <summary>
  375. /// Right edge, which is at X+Width
  376. /// </summary>
  377. [Browsable(false)]
  378. public float Right
  379. {
  380. get
  381. {
  382. return X + Width;
  383. }
  384. set
  385. {
  386. X = value - Width;
  387. }
  388. }
  389. #endregion
  390. #region Top (Public)
  391. /// <summary>
  392. /// Top edge, same as Y
  393. /// </summary>
  394. [FieldOffset(4)]
  395. public float Top;
  396. #endregion
  397. #region Bottom (Public)
  398. /// <summary>
  399. /// Bottom edge, which is at Y+Height
  400. /// </summary>
  401. [Browsable(false)]
  402. public float Bottom
  403. {
  404. get
  405. {
  406. return Y + Height;
  407. }
  408. set
  409. {
  410. Y = value - Height;
  411. }
  412. }
  413. #endregion
  414. #region Center (Public)
  415. /// <summary>
  416. /// The center point of the rectangle at X+Width/2, Y+Height/2.
  417. /// </summary>
  418. [Browsable(false)]
  419. public Point Center
  420. {
  421. get
  422. {
  423. return new Point(X + Width * 0.5f, Y + Height * 0.5f);
  424. }
  425. set
  426. {
  427. // Position = Center - HalfSize
  428. X = value.X - Width * 0.5f;
  429. Y = value.Y - Height * 0.5f;
  430. }
  431. }
  432. #endregion
  433. #region TopLeft (Public)
  434. /// <summary>
  435. /// Returns the top left position, which is just X, Y again (as Position)
  436. /// </summary>
  437. [FieldOffset(0)]
  438. public Point TopLeft;
  439. #endregion
  440. #region TopRight (Public)
  441. /// <summary>
  442. /// Returns the top right position.
  443. /// </summary>
  444. [Browsable(false)]
  445. public Point TopRight
  446. {
  447. get
  448. {
  449. return new Point(Right, Top);
  450. }
  451. }
  452. #endregion
  453. #region BottomLeft (Public)
  454. /// <summary>
  455. /// Returns the bottom left position.
  456. /// </summary>
  457. [Browsable(false)]
  458. public Point BottomLeft
  459. {
  460. get
  461. {
  462. return new Point(Left, Bottom);
  463. }
  464. }
  465. #endregion
  466. #region BottomRight (Public)
  467. /// <summary>
  468. /// Returns the bottom right position.
  469. /// </summary>
  470. [Browsable(false)]
  471. public Point BottomRight
  472. {
  473. get
  474. {
  475. return new Point(Right, Bottom);
  476. }
  477. }
  478. #endregion
  479. #region Private
  480. #region lastRotationAngle (Private)
  481. /// <summary>
  482. /// Helpers for the Rotate method.
  483. /// </summary>
  484. private static float lastRotationAngle;
  485. #endregion
  486. #region lastRotationSin (Private)
  487. private static float lastRotationSin;
  488. #endregion
  489. #region lastRotationCos (Private)
  490. private static float lastRotationCos;
  491. #endregion
  492. #endregion
  493. #region Constructors
  494. /// <summary>
  495. /// Creates a rectangle.
  496. /// </summary>
  497. /// <param name="setHeight">setHeight</param>
  498. /// <param name="setLeft">setLeft</param>
  499. /// <param name="setTop">setTop</param>
  500. /// <param name="setWidth">setWidth</param>
  501. public Rectangle(float setLeft, float setTop, float setWidth,
  502. float setHeight)
  503. : this()
  504. {
  505. Left = setLeft;
  506. Top = setTop;
  507. Width = setWidth;
  508. Height = setHeight;
  509. }
  510. /// <summary>
  511. /// Creates a rectangle.
  512. /// </summary>
  513. /// <param name="setPosition">setPosition</param>
  514. /// <param name="setSize">setSize</param>
  515. public Rectangle(Point setPosition, Size setSize)
  516. : this(setPosition.X, setPosition.Y, setSize.Width, setSize.Height)
  517. {
  518. }
  519. /// <summary>
  520. /// Create rectangle
  521. /// </summary>
  522. /// <param name="setData">Set data</param>
  523. public Rectangle(BinaryReader setData)
  524. : this()
  525. {
  526. Load(setData);
  527. }
  528. #endregion
  529. #region IEquatable<Rectangle> Members
  530. /// <summary>
  531. /// Check if two rectangles are nearly equal (using MathHelper.Epsilon).
  532. /// </summary>
  533. /// <param name="other">other</param>
  534. /// <returns>True if the other rectangle has the same values (allowing
  535. /// MathHelper.Espilon difference between the rectangles).</returns>
  536. public bool Equals(Rectangle other)
  537. {
  538. return
  539. other.Left >= (Left - MathHelper.Epsilon) &&
  540. other.Left <= (Left + MathHelper.Epsilon) &&
  541. other.Top >= (Top - MathHelper.Epsilon) &&
  542. other.Top <= (Top + MathHelper.Epsilon) &&
  543. other.Width >= (Width - MathHelper.Epsilon) &&
  544. other.Width <= (Width + MathHelper.Epsilon) &&
  545. other.Height >= (Height - MathHelper.Epsilon) &&
  546. other.Height <= (Height + MathHelper.Epsilon);
  547. }
  548. #endregion
  549. #region ISaveLoadBinary Members
  550. /// <summary>
  551. /// Load rectangle from a binary stream (16 bytes, 4 floats).
  552. /// </summary>
  553. /// <param name="reader">reader</param>
  554. public void Load(BinaryReader reader)
  555. {
  556. X = reader.ReadSingle();
  557. Y = reader.ReadSingle();
  558. Width = reader.ReadSingle();
  559. Height = reader.ReadSingle();
  560. }
  561. /// <summary>
  562. /// Save rectangle to a binary stream (16 bytes, 4 floats).
  563. /// </summary>
  564. /// <param name="writer">writer</param>
  565. public void Save(BinaryWriter writer)
  566. {
  567. writer.Write(X);
  568. writer.Write(Y);
  569. writer.Write(Width);
  570. writer.Write(Height);
  571. }
  572. #endregion
  573. #region op_Equality (Operator)
  574. /// <summary>
  575. /// Check for equality, will check if both rectangles are almost equal.
  576. /// </summary>
  577. /// <param name="value1">Rectangle 1</param>
  578. /// <param name="value2">Rectangle 2</param>
  579. /// <returns>True if both rectangles are almost equal.</returns>
  580. public static bool operator ==(Rectangle value1, Rectangle value2)
  581. {
  582. return
  583. MathHelper.Abs(value1.X - value2.X) <= MathHelper.Epsilon &&
  584. MathHelper.Abs(value1.Y - value2.Y) <= MathHelper.Epsilon &&
  585. MathHelper.Abs(value1.Width - value2.Width) <= MathHelper.Epsilon &&
  586. MathHelper.Abs(value1.Height - value2.Height) <= MathHelper.Epsilon;
  587. }
  588. #endregion
  589. #region op_Inequality (Operator)
  590. /// <summary>
  591. /// Check for inequality, will check if both rectangles are almost equal.
  592. /// </summary>
  593. /// <param name="value1">value1</param>
  594. /// <param name="value2">value2</param>
  595. /// <returns>True if both rectangles are not equal.</returns>
  596. public static bool operator !=(Rectangle value1, Rectangle value2)
  597. {
  598. return
  599. MathHelper.Abs(value1.X - value2.X) > MathHelper.Epsilon ||
  600. MathHelper.Abs(value1.Y - value2.Y) > MathHelper.Epsilon ||
  601. MathHelper.Abs(value1.Width - value2.Width) > MathHelper.Epsilon ||
  602. MathHelper.Abs(value1.Height - value2.Height) > MathHelper.Epsilon;
  603. }
  604. #endregion
  605. #region Equals (Public)
  606. /// <summary>
  607. /// Check for equality, will check if both rectangles are almost equal.
  608. /// </summary>
  609. /// <param name="obj">Object to compare to</param>
  610. /// <returns>True if obj is a rectangle and almost equal</returns>
  611. public override bool Equals(object obj)
  612. {
  613. return (obj is Rectangle)
  614. ? Equals((Rectangle)obj)
  615. : base.Equals(obj);
  616. }
  617. #endregion
  618. #region GetHashCode (Public)
  619. /// <summary>
  620. /// Get hash code for this rectangle
  621. /// </summary>
  622. /// <returns>Hash code, build from X, Y, Width and Height</returns>
  623. public override int GetHashCode()
  624. {
  625. return X.GetHashCode() ^ Y.GetHashCode() ^ Width.GetHashCode() ^
  626. Height.GetHashCode();
  627. }
  628. #endregion
  629. #region Shrink (Public)
  630. /// <summary>
  631. /// Shrinks the rectangle by the given quad space amount, this will
  632. /// reduce the size by quadSpaceValue * 2 (all borders will be reduced
  633. /// by quadSpaceValue). Note that the original rectangle is unchanged,
  634. /// only the returned rectangle has the new size.
  635. /// </summary>
  636. /// <param name="quadSpaceValue">Quad space value for reducing</param>
  637. /// <returns>Reduced rectangle</returns>
  638. public Rectangle Shrink(float quadSpaceValue)
  639. {
  640. return new Rectangle(X + quadSpaceValue, Y + quadSpaceValue,
  641. Width - (quadSpaceValue * 2.0f), Height - (quadSpaceValue * 2.0f));
  642. }
  643. #endregion
  644. #region Grow (Public)
  645. /// <summary>
  646. /// Grows the rectangle by the given quad space amount, this will
  647. /// increase the size by quadSpaceValue * 2 (all borders will be increased
  648. /// by quadSpaceValue). Note that the original rectangle is unchanged,
  649. /// only the returned rectangle has the new size.
  650. /// </summary>
  651. /// <param name="quadSpaceValue">Quad space value for increasing</param>
  652. /// <returns>Increased rectangle</returns>
  653. public Rectangle Grow(float quadSpaceValue)
  654. {
  655. return new Rectangle(X - quadSpaceValue, Y - quadSpaceValue,
  656. Width + (quadSpaceValue * 2.0f), Height + (quadSpaceValue * 2.0f));
  657. }
  658. #endregion
  659. #region ScaleCentered (Public)
  660. /// <summary>
  661. /// Scale a rectangle centered. Note that the original rectangle is
  662. /// unchanged, only the returned rectangle has the new size.
  663. /// </summary>
  664. /// <param name="scaleFactor">Scale factor to increase at all sides</param>
  665. /// <returns>Increased rectangle</returns>
  666. public Rectangle ScaleCentered(float scaleFactor)
  667. {
  668. return ScaleCentered(scaleFactor, scaleFactor);
  669. }
  670. /// <summary>
  671. /// Scale a rectangle centered. Note that the original rectangle is
  672. /// unchanged, only the returned rectangle has the new size.
  673. /// </summary>
  674. /// <param name="scaleHeight">Scale factor to increase height</param>
  675. /// <param name="scaleWidth">Scale factor to increase width</param>
  676. /// <returns>Increased rectangle</returns>
  677. public Rectangle ScaleCentered(float scaleWidth, float scaleHeight)
  678. {
  679. Size orgSize = Size;
  680. Size scaledSize = new Size(orgSize.Width * scaleWidth,
  681. orgSize.Height * scaleHeight);
  682. Size halfOffset = (orgSize - scaledSize) * 0.5f;
  683. return new Rectangle(Position + halfOffset, scaledSize);
  684. }
  685. #endregion
  686. #region Contains (Public)
  687. /// <summary>
  688. /// Determines whether a point lies inside a rectangle or not.
  689. /// </summary>
  690. /// <param name="position">The position we want to check if it
  691. /// intersects with the rectangle.</param>
  692. /// <returns>
  693. /// <c>true</c> if the Rectangle contains the point; otherwise,
  694. /// <c>false</c>.
  695. /// </returns>
  696. public bool Contains(Point position)
  697. {
  698. return
  699. position.X >= Left &&
  700. position.X < Right &&
  701. position.Y >= Top &&
  702. position.Y < Bottom;
  703. }
  704. /// <summary>
  705. /// Intersects with another rectangle? This means rectangle should
  706. /// be inside or touching one border. If not, rectangle is out of
  707. /// our rectangle, which is useful for ScreenArea visibility checks.
  708. /// </summary>
  709. /// <param name="rectangle">The rectangle.</param>
  710. /// <returns>
  711. /// Fully: if the rectangle is inside this Rectangle
  712. /// Partially: if the two rectangles intersect
  713. /// None: The rectangles are far apart
  714. /// </returns>
  715. public ContainmentType Contains(Rectangle rectangle)
  716. {
  717. if (Right < rectangle.X ||
  718. Left > rectangle.Right ||
  719. Bottom < rectangle.Top ||
  720. Top > rectangle.Bottom)
  721. {
  722. return ContainmentType.None;
  723. }
  724. if (Left <= rectangle.X &&
  725. Right >= rectangle.Right &&
  726. Top < rectangle.Top &&
  727. Bottom >= rectangle.Bottom)
  728. {
  729. return ContainmentType.Fully;
  730. }
  731. return ContainmentType.Partial;
  732. }
  733. #endregion
  734. #region Move (Public)
  735. /// <summary>
  736. /// Will return a copy of the current rectangle which is moved by the given
  737. /// offset.
  738. /// </summary>
  739. /// <param name="offset">Offset to move</param>
  740. /// <returns>Moved rectangle</returns>
  741. public Rectangle Move(Point offset)
  742. {
  743. return Move(offset.X, offset.Y);
  744. }
  745. /// <summary>
  746. /// Will return a copy of the current rectangle which is moved by the given
  747. /// offsets.
  748. /// </summary>
  749. /// <param name="xOffset">X offset to move</param>
  750. /// <param name="yOffset">Y offset to move</param>
  751. /// <returns>Moved rectangle</returns>
  752. public Rectangle Move(float xOffset, float yOffset)
  753. {
  754. return new Rectangle(X + xOffset, Y + yOffset, Width, Height);
  755. }
  756. #endregion
  757. #region ToString (Public)
  758. /// <summary>
  759. /// To string, will provide a string about the position and size of this
  760. /// rectangle. Use ToColladaString or ToCommaString for storing this
  761. /// Rectangle as a string in text or xml files (because we have
  762. /// FromColladaString and FromCommaString methods, but we got no
  763. /// FromString method).
  764. /// </summary>
  765. /// <returns>string</returns>
  766. public override string ToString()
  767. {
  768. return "(Position=" + Position + ", Size=" + Size + ")";
  769. }
  770. #endregion
  771. #region ToColladaString (Public)
  772. /// <summary>
  773. /// Returns the vector as a string that can be used in a Collada file.
  774. /// Note: Use FromColladaString to load this Rectangle again.
  775. /// </summary>
  776. /// <returns>
  777. /// String with the X, Y, Width and Height values just separated by spaces.
  778. /// </returns>
  779. public string ToColladaString()
  780. {
  781. return X.ToInvariantString() + " " +
  782. Y.ToInvariantString() + " " +
  783. Width.ToInvariantString() + " " +
  784. Height.ToInvariantString();
  785. }
  786. #endregion
  787. #region ToCommaString (Public)
  788. /// <summary>
  789. /// Returns the vector as a string with commas (x, y, width, height).
  790. /// Note: Use FromCommaString to load this Rectangle again.
  791. /// </summary>
  792. /// <returns>
  793. /// String with the X, Y, Width and Height values separated by commas.
  794. /// </returns>
  795. public string ToCommaString()
  796. {
  797. return X.ToInvariantString() + "," +
  798. Y.ToInvariantString() + "," +
  799. Width.ToInvariantString() + "," +
  800. Height.ToInvariantString();
  801. }
  802. #endregion
  803. #region Rotate (Public)
  804. /// <summary>
  805. /// Rotate rectangle around its center and return the 4 corner points in
  806. /// this order: TopLeft, TopRight, BottomRight, BottomLeft. This way
  807. /// these points can be rendered directly by a shader. Used for material
  808. /// drawing (rendering). Will return the original rectangle if
  809. /// rotationAngle is 0 (then executing this is much faster).
  810. /// Note: This method is not returning anything new, it will only change
  811. /// the content of rotPoints because of performance. Creating an array of
  812. /// 4 points (8 floats) costs a lot of performance on mobile platforms. If
  813. /// you do it hundred or thousands of times per frame you don't want all
  814. /// these newly created point arrays hanging around. Instead each caller
  815. /// uses his own point array (only initialized once).
  816. /// </summary>
  817. /// <param name="rotationAngle">rotationAngle</param>
  818. /// <param name="rotPoints">
  819. /// Preinitialized array of 4 Points used to store the rotation points
  820. /// resulting in the rectangle rotation with rotationAngle.
  821. /// </param>
  822. public void Rotate(float rotationAngle, Point[] rotPoints)
  823. {
  824. // Next we need to do some calculations, but only if rotationAngle is
  825. // used. If rotationAngle is 0, we can just return the rectangle.
  826. if (rotationAngle == 0)
  827. {
  828. float X2 = X + Width;
  829. float Y2 = Y + Height;
  830. rotPoints[0].X = X;
  831. rotPoints[0].Y = Y;
  832. rotPoints[1].X = X2;
  833. rotPoints[1].Y = Y;
  834. rotPoints[2].X = X2;
  835. rotPoints[2].Y = Y2;
  836. rotPoints[3].X = X;
  837. rotPoints[3].Y = Y2;
  838. }
  839. else
  840. {
  841. // Create rotation matrix. Note: This code might look ugly, but it
  842. // is incredibly fast, except for the cos and sin everything else
  843. // is just adding and multiplying some floats, which is very fast!
  844. // Cache the cos/sin results here because we often have rotations
  845. // with the same value, but using many draw calls with different
  846. // rectangles on it (e.g. a font rotating around).
  847. if (lastRotationAngle != rotationAngle)
  848. {
  849. lastRotationAngle = rotationAngle;
  850. lastRotationSin = MathHelper.Sin(rotationAngle);
  851. lastRotationCos = MathHelper.Cos(rotationAngle);
  852. }
  853. // Little Matrix2x2 :)
  854. float m11 = lastRotationCos;
  855. float m12 = lastRotationSin;
  856. float m21 = -lastRotationSin;
  857. //Note: Same as m11: float m22 = lastRotationCos;
  858. // Rotation formula is: X * M11 + Y * M21, X * M12 + Y * M22
  859. // Now transform each point relative to the center of the rectangle!
  860. float centerX = X + Width * 0.5f;
  861. float centerY = Y + Height * 0.5f;
  862. // X1, Y1, X2 and Y2 are all relative to the center and easier to
  863. // rotate this way, but we need to add CenterX and CenterY to the
  864. // results below again.
  865. float x1 = X - centerX;
  866. float y1 = Y - centerY;
  867. float x2 = x1 + Width;
  868. float y2 = y1 + Height;
  869. // X1, Y1, X2 and Y2 are all used multiple times, pre-calculate M11
  870. // to M22 matrix values with them to save even more instructions :)
  871. float x1m11 = x1 * m11;
  872. float x1m12 = x1 * m12;
  873. float y1m21 = y1 * m21;
  874. float y1m22 = y1 * m11; //m22;
  875. float x2m11 = x2 * m11;
  876. float x2m12 = x2 * m12;
  877. float y2m21 = y2 * m21;
  878. float y2m22 = y2 * m11; //m22;
  879. // TopLeft is X1, Y1
  880. rotPoints[0].X = x1m11 + y1m21 + centerX;
  881. rotPoints[0].Y = x1m12 + y1m22 + centerY;
  882. // TopRight is X2, Y1
  883. rotPoints[1].X = x2m11 + y1m21 + centerX;
  884. rotPoints[1].Y = x2m12 + y1m22 + centerY;
  885. // BottomRight is X2, Y1
  886. rotPoints[2].X = x2m11 + y2m21 + centerX;
  887. rotPoints[2].Y = x2m12 + y2m22 + centerY;
  888. // BottomLeft is X1, Y2
  889. rotPoints[3].X = x1m11 + y2m21 + centerX;
  890. rotPoints[3].Y = x1m12 + y2m22 + centerY;
  891. }
  892. }
  893. /// <summary>
  894. /// Rotate rectangle around its center and return the 4 corner points in
  895. /// this order: TopLeft, TopRight, BottomRight, BottomLeft. This way
  896. /// these points can be rendered directly by a shader. Used for material
  897. /// drawing (rendering). Will return the original rectangle if
  898. /// rotationAngle is 0 (then executing this is much faster).
  899. /// Special version of this method with a given center rotation point!
  900. /// </summary>
  901. /// <param name="center">center</param>
  902. /// <param name="rotationAngle">rotationAngle</param>
  903. /// <param name="rotPoints">rotPoints</param>
  904. public void Rotate(float rotationAngle, Point[] rotPoints, Point center)
  905. {
  906. // Next we need to do some calculations, but only if rotationAngle is
  907. // used. If rotationAngle is 0, we can just return the rectangle.
  908. if (rotationAngle == 0)
  909. {
  910. float X2 = X + Width;
  911. float Y2 = Y + Height;
  912. rotPoints[0].X = X;
  913. rotPoints[0].Y = Y;
  914. rotPoints[1].X = X2;
  915. rotPoints[1].Y = Y;
  916. rotPoints[2].X = X2;
  917. rotPoints[2].Y = Y2;
  918. rotPoints[3].X = X;
  919. rotPoints[3].Y = Y2;
  920. }
  921. else
  922. {
  923. // Create rotation matrix. Note: This code might look ugly, but it
  924. // is incredibly fast, except for the cos and sin everything else
  925. // is just adding and multiplying some floats, which is very fast!
  926. // Cache the cos/sin results here because we often have rotations
  927. // with the same value, but using many draw calls with different
  928. // rectangles on it (e.g. a font rotating around).
  929. if (lastRotationAngle != rotationAngle)
  930. {
  931. lastRotationAngle = rotationAngle;
  932. lastRotationSin = MathHelper.Sin(rotationAngle);
  933. lastRotationCos = MathHelper.Cos(rotationAngle);
  934. }
  935. // Little Matrix2x2 :)
  936. float m11 = lastRotationCos;
  937. float m12 = lastRotationSin;
  938. float m21 = -lastRotationSin;
  939. //Note: Same as m11: float m22 = lastRotationCos;
  940. // Rotation formula is: X * M11 + Y * M21, X * M12 + Y * M22
  941. // Now transform each point relative to the center of the rectangle!
  942. float centerX = center.X;
  943. float centerY = center.Y;
  944. // X1, Y1, X2 and Y2 are all relative to the center and easier to
  945. // rotate this way, but we need to add CenterX and CenterY to the
  946. // results below again.
  947. float x1 = X - centerX;
  948. float y1 = Y - centerY;
  949. float x2 = x1 + Width;
  950. float y2 = y1 + Height;
  951. // X1, Y1, X2 and Y2 are all used multiple times, pre-calculate M11
  952. // to M22 matrix values with them to save even more instructions :)
  953. float x1m11 = x1 * m11;
  954. float x1m12 = x1 * m12;
  955. float y1m21 = y1 * m21;
  956. float y1m22 = y1 * m11; //m22;
  957. float x2m11 = x2 * m11;
  958. float x2m12 = x2 * m12;
  959. float y2m21 = y2 * m21;
  960. float y2m22 = y2 * m11; //m22;
  961. // TopLeft is X1, Y1
  962. rotPoints[0].X = x1m11 + y1m21 + centerX;
  963. rotPoints[0].Y = x1m12 + y1m22 + centerY;
  964. // TopRight is X2, Y1
  965. rotPoints[1].X = x2m11 + y1m21 + centerX;
  966. rotPoints[1].Y = x2m12 + y1m22 + centerY;
  967. // BottomRight is X2, Y1
  968. rotPoints[2].X = x2m11 + y2m21 + centerX;
  969. rotPoints[2].Y = x2m12 + y2m22 + centerY;
  970. // BottomLeft is X1, Y2
  971. rotPoints[3].X = x1m11 + y2m21 + centerX;
  972. rotPoints[3].Y = x1m12 + y2m22 + centerY;
  973. }
  974. }
  975. #endregion
  976. #region GetInnerPosition (Public)
  977. /// <summary>
  978. /// Get inner position helper method. Used by FbxFile.GetMeshData to
  979. /// remap UVs from the FBX Model file to our new atlas texture UVs.
  980. /// </summary>
  981. /// <param name="relativePosition">Relative position (0-1)</param>
  982. /// <returns>
  983. /// Point inside this rectangle based on the relative position.
  984. /// </returns>
  985. public Point GetInnerPosition(Point relativePosition)
  986. {
  987. return new Point(
  988. X + Width * relativePosition.X,
  989. Y + Height * relativePosition.Y);
  990. }
  991. #endregion
  992. #region GetInnerRectangle (Public)
  993. /// <summary>
  994. /// Get inner position helper method out of a relative rectangle. This
  995. /// can be used to position stuff inside controls, mini-maps, for aligning
  996. /// and re-mapping UVs from model files and much more.
  997. /// </summary>
  998. /// <param name="relativeRectangle">Relative rectangle, if this is
  999. /// Rectangle.One, the current rectangle will be returned.</param>
  1000. /// <returns>Returns the current rectangle multiplied by the
  1001. /// relativeRectangle (usually smaller, inside of it)</returns>
  1002. public Rectangle GetInnerRectangle(Rectangle relativeRectangle)
  1003. {
  1004. return new Rectangle(
  1005. X + Width * relativeRectangle.X,
  1006. Y + Height * relativeRectangle.Y,
  1007. Width * relativeRectangle.Width,
  1008. Height * relativeRectangle.Height);
  1009. }
  1010. #endregion
  1011. /// <summary>
  1012. /// Rectangle performance class to figure out performance.
  1013. /// </summary>
  1014. public class RectanglePerformance
  1015. {
  1016. #region TestCreation Performance
  1017. /// <summary>
  1018. /// Test the creation of a rectangle.
  1019. /// </summary>
  1020. public static void TestCreation()
  1021. {
  1022. Rectangle testRect;
  1023. PerformanceTester.Profile10MilionTimes("Rectangle constructor",
  1024. delegate
  1025. {
  1026. testRect = new Rectangle(10, 20, 30, 40);
  1027. });
  1028. }
  1029. #endregion
  1030. #region TestCopy Performance
  1031. /// <summary>
  1032. /// Test the copy method of the rectangle struct.
  1033. /// </summary>
  1034. public static void TestCopy()
  1035. {
  1036. Rectangle testRect = new Rectangle(10, 20, 30, 40);
  1037. PerformanceTester.Profile10MilionTimes("Rectangle copy",
  1038. delegate
  1039. {
  1040. Rectangle anotherRect = testRect;
  1041. });
  1042. }
  1043. #endregion
  1044. #region TestMove Performance
  1045. /// <summary>
  1046. /// Test the move method of the rectangle struct.
  1047. /// </summary>
  1048. public static void TestMove()
  1049. {
  1050. Rectangle testRect = new Rectangle(1, 2, 5, 5);
  1051. PerformanceTester.Profile10MilionTimes("Rectangle.Move",
  1052. delegate
  1053. {
  1054. Rectangle anotherRect = testRect.Move(4, 3);
  1055. });
  1056. }
  1057. #endregion
  1058. #region TestIntersects Performance
  1059. /// <summary>
  1060. /// Test the intersects method of the rectangle struct.
  1061. /// </summary>
  1062. public static void TestIntersects()
  1063. {
  1064. Rectangle testRect = One;
  1065. Point testPoint = new Point(1.3f, 0.7f);
  1066. PerformanceTester.Profile10MilionTimes("Rectangle.Intersects",
  1067. delegate
  1068. {
  1069. testRect.Contains(testPoint);
  1070. });
  1071. }
  1072. #endregion
  1073. #region TestRotate Performance
  1074. /// <summary>
  1075. /// Test the rotate method of the rectangle struct.
  1076. /// </summary>
  1077. public static void TestRotate()
  1078. {
  1079. Rectangle testRect = One;
  1080. Point[] rotPoints = new Point[4];
  1081. PerformanceTester.Profile10MilionTimes("Rectangle.Rotate(0)",
  1082. delegate
  1083. {
  1084. testRect.Rotate(0, rotPoints);
  1085. });
  1086. PerformanceTester.Profile10MilionTimes("Rectangle.Rotate(1.4f)",
  1087. delegate
  1088. {
  1089. testRect.Rotate(1.4f, rotPoints);
  1090. });
  1091. int num = 0;
  1092. PerformanceTester.Profile10MilionTimes("Rectangle.Rotate(0.1f*num)",
  1093. delegate
  1094. {
  1095. testRect.Rotate(0.1f * num, rotPoints);
  1096. num++;
  1097. });
  1098. }
  1099. #endregion
  1100. #region ExecuteAllForPerformanceOverview Performance
  1101. /// <summary>
  1102. /// Execute all rectangle tests for a performance overview.
  1103. /// </summary>
  1104. public static void ExecuteAllForPerformanceOverview()
  1105. {
  1106. // Warm up the CPU with some stress testing (for several secs) :)
  1107. TestCreation();
  1108. PerformanceTester.ShowTotalProfileRuns();
  1109. Log.Test("Starting testing again after warming up!");
  1110. Log.Test("Delta Rectangle test:");
  1111. TestCreation();
  1112. TestCopy();
  1113. TestMove();
  1114. TestIntersects();
  1115. TestRotate();
  1116. PerformanceTester.ShowTotalProfileRuns();
  1117. // Result: Rectangle is pretty quick now, even doing rotation is no
  1118. // problem at all, there is no need for RotatableRectangle anymore!
  1119. /* Delta Rectangle test:
  1120. 121ms for Rectangle constructor (10 million calls)
  1121. 34ms for Rectangle copy (10 million calls)
  1122. 93ms for Rectangle.Move (10 million calls)
  1123. 95ms for Rectangle.Intersects (10 million calls)
  1124. 86ms for Rectangle.Rotate(0) (10 million calls)
  1125. 183ms for Rectangle.Rotate(1.4f) (10 million calls)
  1126. 990ms for Rectangle.Rotate(0.1f*num) (10 million calls)
  1127. In total 7 Tests were executed. Total time=1602ms, Average time=228.8ms.
  1128. */
  1129. }
  1130. #endregion
  1131. }
  1132. /// <summary>
  1133. /// Tests
  1134. /// </summary>
  1135. internal class RectangleTests
  1136. {
  1137. #region SizeOf
  1138. /// <summary>
  1139. /// Checks if the size of Point is exactly 8 bytes (2 floats: X and Y)
  1140. /// </summary>
  1141. [Test]
  1142. public void SizeOf()
  1143. {
  1144. // Rectangle has 4 floats: X, Y, Width, Height
  1145. Assert.Equal(4 * 4, Marshal.SizeOf(typeof(Rectangle)));
  1146. }
  1147. #endregion
  1148. #region Properties
  1149. /// <summary>
  1150. /// Properties
  1151. /// </summary>
  1152. [Test]
  1153. public void Properties()
  1154. {
  1155. Rectangle testRect = new Rectangle(5, 5, 20, 10);
  1156. // All edges
  1157. Assert.Equal(5, testRect.X);
  1158. Assert.Equal(5, testRect.Y);
  1159. Assert.Equal(25, testRect.Right);
  1160. Assert.Equal(15, testRect.Bottom);
  1161. // Position and Size
  1162. Assert.Equal(new Point(5, 5), testRect.Position);
  1163. Assert.Equal(new Size(20, 10), testRect.Size);
  1164. }
  1165. #endregion
  1166. #region FromCenter
  1167. /// <summary>
  1168. /// From center
  1169. /// </summary>
  1170. [Test]
  1171. public void FromCenter()
  1172. {
  1173. Rectangle testRect = Rectangle.FromCenter(new Point(20, 10), 10);
  1174. Assert.Equal(new Point(15, 5), testRect.Position);
  1175. Assert.Equal(new Size(10, 10), testRect.Size);
  1176. }
  1177. #endregion
  1178. #region FromCorners
  1179. /// <summary>
  1180. /// From corners
  1181. /// </summary>
  1182. [Test]
  1183. public void FromCorners()
  1184. {
  1185. Assert.Equal(new Rectangle(30, 40, 120, 80),
  1186. Rectangle.FromCorners(new Point(30, 40), new Point(150, 120)));
  1187. }
  1188. #endregion
  1189. #region FromColladaString
  1190. /// <summary>
  1191. /// From collada string
  1192. /// </summary>
  1193. [Test]
  1194. public void FromColladaString()
  1195. {
  1196. Assert.Equal(new Rectangle(30, 40, 150, 120),
  1197. Rectangle.FromColladaString("30 40 150 120"));
  1198. }
  1199. #endregion
  1200. #region FromCommaString
  1201. /// <summary>
  1202. /// From comma string
  1203. /// </summary>
  1204. [Test]
  1205. public void FromCommaString()
  1206. {
  1207. Assert.Equal(new Rectangle(30, 40, 150, 120),
  1208. Rectangle.FromCommaString("30,40,150,120"));
  1209. Assert.Equal(new Rectangle(30, 40, 150, 120),
  1210. Rectangle.FromCommaString("30, 40, 150, 120"));
  1211. }
  1212. #endregion
  1213. #region EqualOperator
  1214. /// <summary>
  1215. /// Equal Operator
  1216. /// </summary>
  1217. [Test]
  1218. public void EqualOperator()
  1219. {
  1220. Rectangle testRect1 = new Rectangle(5, 5, 20, 10);
  1221. Rectangle testRect2 = new Rectangle(5, 5, 20, 10);
  1222. Rectangle testRect3 = new Rectangle(5, 0, 20, 10);
  1223. Assert.True(testRect1 == testRect2);
  1224. Assert.False(testRect1 == testRect3);
  1225. }
  1226. #endregion
  1227. #region InequalOperator
  1228. /// <summary>
  1229. /// Inequal Operator
  1230. /// </summary>
  1231. [Test]
  1232. public void InequalOperator()
  1233. {
  1234. Rectangle testRect1 = new Rectangle(5, 5, 20, 10);
  1235. Rectangle testRect2 = new Rectangle(5, 0, 20, 10);
  1236. Rectangle testRect3 = new Rectangle(5, 5, 20, 10);
  1237. Assert.True(testRect1 != testRect2);
  1238. Assert.False(testRect1 != testRect3);
  1239. }
  1240. #endregion
  1241. #region NearlyEquals
  1242. /// <summary>
  1243. /// Nearly equals
  1244. /// </summary>
  1245. [Test]
  1246. public void NearlyEquals()
  1247. {
  1248. Rectangle testRect = new Rectangle(5, 5, 20, 10);
  1249. // We need here for testing a smaller epsilon, because of the float
  1250. // incorrectness
  1251. const float testEpsilon = MathHelper.Epsilon * 0.99f;
  1252. // Check the point directly
  1253. Assert.True(testRect.Equals(testRect));
  1254. // by the "object" overload from .NET
  1255. Assert.True(testRect.Equals((object)testRect));
  1256. // and the nearly equal check
  1257. Assert.True(testRect.Equals(new Rectangle(
  1258. 5 + testEpsilon, 5 - testEpsilon,
  1259. 20 - testEpsilon, 10 + testEpsilon)));
  1260. // Finally check the "bad" false cases with unequal values
  1261. Assert.False(testRect.Equals(new Rectangle(4, 3, 10, 40)));
  1262. // and a too big epsilon
  1263. Assert.False(testRect.Equals(
  1264. new Rectangle(5 + (2 * testEpsilon), 5, 20, 10)));
  1265. }
  1266. #endregion
  1267. #region ScaleCentered
  1268. /// <summary>
  1269. /// Scale centered
  1270. /// </summary>
  1271. [Test]
  1272. public void ScaleCentered()
  1273. {
  1274. Assert.Equal(new Rectangle(30, 30, 80, 80),
  1275. new Rectangle(20, 20, 100, 100).ScaleCentered(0.8f));
  1276. Assert.Equal(new Rectangle(20, 30, 100, 80),
  1277. new Rectangle(20, 20, 100, 100).ScaleCentered(1.0f, 0.8f));
  1278. Assert.Equal(new Rectangle(10, 20, 120, 100),
  1279. new Rectangle(20, 20, 100, 100).ScaleCentered(1.2f, 1.0f));
  1280. }
  1281. #endregion
  1282. #region TestContains
  1283. /// <summary>
  1284. /// Tests Rectangle.Contains(Point)
  1285. /// </summary>
  1286. [Test]
  1287. public void TestContains()
  1288. {
  1289. // We use here for testing a rect from (0,0) to (1,1)
  1290. Rectangle testRect = One;
  1291. // Check that the border positions of the rectangle still belongs to it
  1292. Assert.False(testRect.Contains(Point.One));
  1293. Assert.True(testRect.Contains(Point.Zero));
  1294. // Now a simple check of a point that is in the rectangle
  1295. Assert.True(testRect.Contains(new Point(0.3f, 0.7f)));
  1296. // and two points which are not in
  1297. Assert.False(testRect.Contains(new Point(0.3f, 1.7f)));
  1298. Assert.False(testRect.Contains(new Point(1.3f, 0.7f)));
  1299. }
  1300. #endregion
  1301. #region TestContiansRectangle
  1302. /// <summary>
  1303. /// Tests rectangle.Contains(rectangle)
  1304. /// </summary>
  1305. [Test]
  1306. public void TestContiansRectangle()
  1307. {
  1308. Rectangle testRect = One;
  1309. Assert.Equal(testRect.Contains(new Rectangle(0.1f, 0.1f, 0.1f, 0.2f))
  1310. , ContainmentType.Fully);
  1311. Assert.Equal(testRect.Contains(new Rectangle(0f, 0f, 2f, 0.2f))
  1312. , ContainmentType.Partial);
  1313. Assert.Equal(testRect.Contains(new Rectangle(1.001f, 1.001f,
  1314. 0.2f, 0.2f)), ContainmentType.None);
  1315. Assert.Equal(testRect.Contains(new Rectangle(2f, 2f,
  1316. 0.2f, 0.2f)), ContainmentType.None);
  1317. }
  1318. #endregion
  1319. #region Move
  1320. /// <summary>
  1321. /// Move
  1322. /// </summary>
  1323. [Test]
  1324. public void Move()
  1325. {
  1326. Assert.Equal(new Rectangle(5, 5, 5, 5),
  1327. new Rectangle(1, 2, 5, 5).Move(4, 3));
  1328. }
  1329. #endregion
  1330. #region ToString
  1331. /// <summary>
  1332. /// To string
  1333. /// </summary>
  1334. [Test]
  1335. public new void ToString()
  1336. {
  1337. Point rectPos = new Point(2, 1);
  1338. Size rectSize = new Size(10, 5);
  1339. Assert.Equal("(Position=" + rectPos + ", Size=" + rectSize + ")",
  1340. new Rectangle(rectPos, rectSize).ToString());
  1341. }
  1342. #endregion
  1343. #region ToColladaString
  1344. /// <summary>
  1345. /// </summary>
  1346. [Test]
  1347. public void ToColladaString()
  1348. {
  1349. Rectangle testRect = new Rectangle(1, 2, 3, 4);
  1350. Assert.Equal("1 2 3 4", testRect.ToColladaString());
  1351. Assert.Equal(testRect,
  1352. Rectangle.FromColladaString(testRect.ToColladaString()));
  1353. }
  1354. #endregion
  1355. #region ToCommaString
  1356. /// <summary>
  1357. /// </summary>
  1358. [Test]
  1359. public void ToCommaString()
  1360. {
  1361. Rectangle testRect = new Rectangle(1, 2, 3, 4);
  1362. Assert.Equal("1,2,3,4", testRect.ToCommaString());
  1363. Assert.Equal(testRect,
  1364. Rectangle.FromCommaString(testRect.ToCommaString()));
  1365. }
  1366. #endregion
  1367. }
  1368. }
  1369. }