PageRenderTime 266ms CodeModel.GetById 101ms app.highlight 105ms RepoModel.GetById 46ms app.codeStats 0ms

/Utilities/Datatypes/Rectangle.cs

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