PageRenderTime 818ms CodeModel.GetById 153ms app.highlight 201ms RepoModel.GetById 159ms app.codeStats 0ms

/Utilities/Datatypes/Point.cs

#
C# | 1261 lines | 684 code | 103 blank | 474 comment | 16 complexity | ba0c09e8e31902208f30d2c918054ebc MD5 | raw file
   1using System;
   2using System.ComponentModel;
   3using System.Diagnostics;
   4using System.IO;
   5using System.Runtime.InteropServices;
   6using Delta.Utilities.Helpers;
   7using NUnit.Framework;
   8
   9
  10namespace Delta.Utilities.Datatypes
  11{
  12	/// <summary>
  13	/// Point class, can also be used as a Vector2 (because we got floats here).
  14	/// </summary>
  15	[Serializable]
  16	[StructLayout(LayoutKind.Explicit)]
  17	[DebuggerDisplay("Point=({X}, {Y})")]
  18	[Description("Expand to edit this Point")]
  19	[TypeConverter(typeof(ExpandableObjectConverter))]
  20	public struct Point : ISaveLoadBinary, IEquatable<Point>
  21	{
  22		#region Constants
  23		/// <summary>
  24		/// Represents the size in bytes of each Point (2 * 4 = 8 bytes).
  25		/// </summary>
  26		public const int DataSize = 2 * 4;
  27
  28		/// <summary>
  29		/// Invalid point, usually used to indicate invalid cached points.
  30		/// </summary>
  31		public static readonly Point Invalid = new Point(-1, -1);
  32
  33		/// <summary>
  34		/// Returns the zero point (0, 0).
  35		/// </summary>
  36		public static readonly Point Zero = new Point(0);
  37
  38		/// <summary>
  39		/// Returns the point (0.5, 0.5).
  40		/// </summary>
  41		public static readonly Point Half = new Point(0.5f);
  42
  43		/// <summary>
  44		/// Returns the point (1, 1).
  45		/// </summary>
  46		public static readonly Point One = new Point(1);
  47
  48		/// <summary>
  49		/// Unit x vector, returns the point (1, 0)
  50		/// </summary>
  51		public static readonly Point UnitX = new Point(1, 0);
  52
  53		/// <summary>
  54		/// Unit y vector, returns the point (0, 1)
  55		/// </summary>
  56		public static readonly Point UnitY = new Point(0, 1);
  57		#endregion
  58
  59		#region Normalize (Static)
  60		/// <summary>
  61		/// Normalize
  62		/// </summary>
  63		/// <param name="anyPoint">anyPoint</param>
  64		/// <returns>Normalized point</returns>
  65		public static Point Normalize(Point anyPoint)
  66		{
  67			float lengthSquared = anyPoint.LengthSquared;
  68			if (lengthSquared == 0)
  69			{
  70				// and return the original unchanged value
  71				return anyPoint;
  72			} // if
  73			float invLength = 1f / MathHelper.Sqrt(lengthSquared);
  74			return new Point(anyPoint.X * invLength, anyPoint.Y * invLength);
  75		}
  76		#endregion
  77
  78		#region Dot (Static)
  79		/// <summary>
  80		/// Return a scale as result of the dot product from two points
  81		/// </summary>
  82		/// <param name="value1">Point 1</param>
  83		/// <param name="value2">Point 2</param>
  84		/// <returns>Result of the dot product</returns>
  85		public static float Dot(Point value1, Point value2)
  86		{
  87			return value1.X * value2.X + value1.Y * value2.Y;
  88		}
  89
  90		/// <summary>
  91		/// Return a scale as result of the do product from two points
  92		/// </summary>
  93		/// <param name="value1">Point 1</param>
  94		/// <param name="value2">Point 2</param>
  95		/// <param name="result">Result of the dot product</param>
  96		public static void Dot(ref Point value1, ref Point value2,
  97			out float result)
  98		{
  99			result = value1.X * value2.X + value1.Y * value2.Y;
 100		}
 101		#endregion
 102
 103		#region Distance (Static)
 104		/// <summary>
 105		/// Calculate the distance from two points resulting in scale value
 106		/// </summary>
 107		/// <param name="value1">Point 1</param>
 108		/// <param name="value2">Point 2</param>
 109		/// <returns>Distance between points</returns>
 110		public static float Distance(Point value1, Point value2)
 111		{
 112			float result;
 113			DistanceSquared(ref value1, ref value2, out result);
 114			return MathHelper.Sqrt(result);
 115		}
 116
 117		/// <summary>
 118		/// Calculate the distance from two points resulting in scale value
 119		/// </summary>
 120		/// <param name="value1">Point 1</param>
 121		/// <param name="value2">Point 2</param>
 122		/// <param name="result">Distance between points</param>
 123		public static void Distance(ref Point value1, ref Point value2,
 124			out float result)
 125		{
 126			DistanceSquared(ref value1, ref value2, out result);
 127			result = MathHelper.Sqrt(result);
 128		}
 129		#endregion
 130
 131		#region DistanceSquared (Static)
 132		/// <summary>
 133		/// Calculate the squared distance from two points. This is faster than
 134		/// using Distance because we don't need to take the square root.
 135		/// </summary>
 136		/// <param name="value1">Point 1</param>
 137		/// <param name="value2">Point 2</param>
 138		/// <returns>Squared distance between points</returns>
 139		public static float DistanceSquared(Point value1, Point value2)
 140		{
 141			float result;
 142			DistanceSquared(ref value1, ref value2, out result);
 143			return result;
 144		}
 145
 146		/// <summary>
 147		/// Calculate the squared distance from two points resulting in scale value
 148		/// </summary>
 149		/// <param name="value1">Point 1</param>
 150		/// <param name="value2">Point 2</param>
 151		/// <param name="result">Squared distance between points</param>
 152		public static void DistanceSquared(ref Point value1, ref Point value2,
 153			out float result)
 154		{
 155			result =
 156				(value1.X - value2.X) * (value1.X - value2.X) +
 157				(value1.Y - value2.Y) * (value1.Y - value2.Y);
 158		}
 159		#endregion
 160
 161		#region Transform (Static)
 162		/// <summary>
 163		/// Transform point by multiplying it with a matrix.
 164		/// Note: This is slower than using the ref version of Transform.
 165		/// </summary>
 166		/// <param name="matrix">Matrix for the transformation</param>
 167		/// <param name="position">Position to transform</param>
 168		/// <returns>Transformed point resulting from matrix*position</returns>
 169		public static Point Transform(Point position, Matrix matrix)
 170		{
 171			Transform(ref position, ref matrix, out position);
 172			return position;
 173		}
 174
 175		/// <summary>
 176		/// Transform point by multiplying it with a matrix
 177		/// </summary>
 178		/// <param name="matrix">Matrix for the transformation</param>
 179		/// <param name="position">Position to transform</param>
 180		/// <param name="result">Transformed point resulting from matrix*position
 181		/// </param>
 182		public static void Transform(ref Point position, ref Matrix matrix,
 183			out Point result)
 184		{
 185			result = new Point(
 186				position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
 187				position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42);
 188		}
 189		#endregion
 190
 191		#region TransformNormal (Static)
 192		/// <summary>
 193		/// Transform normal by multiplying it with a matrix.
 194		/// Note: This is slower than using the ref version of Transform.
 195		/// </summary>
 196		/// <param name="normal">Position to transform</param>
 197		/// <param name="matrix">Matrix for the transformation</param>
 198		/// <returns>Transformed normal</returns>
 199		public static Point TransformNormal(Point normal, Matrix matrix)
 200		{
 201			TransformNormal(ref normal, ref matrix, out normal);
 202			return normal;
 203		}
 204
 205		/// <summary>
 206		/// Transform normal by multiplying it with a matrix
 207		/// </summary>
 208		/// <param name="normal">Position to transform</param>
 209		/// <param name="matrix">Matrix for the transformation</param>
 210		/// <param name="result">Transformed normal</param>
 211		public static void TransformNormal(ref Point normal, ref Matrix matrix,
 212			out Point result)
 213		{
 214			result = new Point(
 215				(normal.X * matrix.M11) + (normal.Y * matrix.M21),
 216				(normal.X * matrix.M12) + (normal.Y * matrix.M22));
 217		}
 218		#endregion
 219
 220		#region ComputeNormal (Static)
 221		/// <summary>
 222		/// Computes the normal of the given 2D vector. For more information see:
 223		/// http://www.sciface.com/education/data/web/Beschreibung-von-Geraden.html
 224		/// http://www.matheboard.de/archive/23062/thread.html
 225		/// </summary>
 226		/// <param name="vector2D">2D Vector</param>
 227		/// <returns>Normal, which is just (-Y, X)</returns>
 228		public static Point ComputeNormal(Point vector2D)
 229		{
 230			return new Point(-vector2D.Y, vector2D.X);
 231		}
 232		#endregion
 233
 234		#region Lerp (Static)
 235		/// <summary>
 236		/// Performs a linear interpolation between two points. 
 237		/// </summary>
 238		/// <param name="amount">Amount to lerp</param>
 239		/// <param name="value1">Point 1</param>
 240		/// <param name="value2">Point 2</param>
 241		/// <returns>Interpolated point between both points</returns>
 242		public static Point Lerp(Point value1, Point value2, float amount)
 243		{
 244			return new Point(
 245				MathHelper.Lerp(value1.X, value2.X, amount),
 246				MathHelper.Lerp(value1.Y, value2.Y, amount));
 247		}
 248
 249		/// <summary>
 250		/// Performs a linear interpolation between two points. 
 251		/// </summary>
 252		/// <param name="amount">Amount to lerp</param>
 253		/// <param name="value1">Point 1</param>
 254		/// <param name="value2">Point 2</param>
 255		/// <param name="result">Interpolated point between both points</param>
 256		public static void Lerp(ref Point value1, ref Point value2, float amount,
 257			out Point result)
 258		{
 259			result = new Point(
 260				MathHelper.Lerp(value1.X, value2.X, amount),
 261				MathHelper.Lerp(value1.Y, value2.Y, amount));
 262		}
 263		#endregion
 264
 265		#region Min (Static)
 266		/// <summary>
 267		/// Returns the minimum of both points (X and Y are handled seperately).
 268		/// -> A(2,4), B(4,1) => Min(2,1)
 269		/// </summary>
 270		/// <param name="value1">Point 1</param>
 271		/// <param name="value2">Point 2</param>
 272		/// <returns>Minimum value of X and Y</returns>
 273		public static Point Min(Point value1, Point value2)
 274		{
 275			return new Point(MathHelper.Min(value1.X, value2.X),
 276				MathHelper.Min(value1.Y, value2.Y));
 277		}
 278		#endregion
 279
 280		#region Max (Static)
 281		/// <summary>
 282		/// Returns the maximum of both points (X and Y are handled seperately).
 283		/// -> A(2,4), B(4,1) => Max(4,4)
 284		/// </summary>
 285		/// <param name="value1">Point 1</param>
 286		/// <param name="value2">Point 2</param>
 287		/// <returns>Maximum value of X and Y</returns>
 288		public static Point Max(Point value1, Point value2)
 289		{
 290			return new Point(MathHelper.Max(value1.X, value2.X),
 291				MathHelper.Max(value1.Y, value2.Y));
 292		}
 293		#endregion
 294
 295		#region Clamp (Static)
 296		/// <summary>
 297		/// Clamp
 298		/// </summary>
 299		/// <param name="value">Value</param>
 300		/// <param name="min">Minimum</param>
 301		/// <param name="max">Maximum</param>
 302		public static Point Clamp(Point value, Point min, Point max)
 303		{
 304			return new Point(
 305				MathHelper.Clamp(value.X, min.X, max.X),
 306				MathHelper.Clamp(value.Y, min.Y, max.Y));
 307		}
 308		#endregion
 309
 310		#region FromString (Static)
 311		/// <summary>
 312		/// Convert a string to a Point. The expected format is (x.x, y.y), but
 313		/// it works fine with ToColladaString or ToCommaString strings too :)
 314		/// </summary>
 315		/// <param name="pointString">The string in the correct format
 316		/// (with or without brackets, comma or space seperated).</param>
 317		/// <returns>
 318		/// Point from the given string or Zero if parsing failed.
 319		/// </returns>
 320		public static Point FromString(string pointString)
 321		{
 322			// Remove the brackets and split the string up into seperate values
 323			pointString = pointString.Replace("(", "");
 324			pointString = pointString.Replace(")", "");
 325			pointString = pointString.Replace("{", "");
 326			pointString = pointString.Replace("}", "");
 327			string[] pointStrings = pointString.Split(new[]
 328			{
 329				',', ' '
 330			},
 331				StringSplitOptions.RemoveEmptyEntries);
 332
 333			// Then check if the length is 2 for 2 values and return the new point.
 334			// If the length is not 2 than return Point.Zero.
 335			if (pointStrings.Length == 2)
 336			{
 337				return new Point(
 338					pointStrings[0].FromInvariantString(0.0f),
 339					pointStrings[1].FromInvariantString(0.0f));
 340			}
 341
 342			return Zero;
 343		}
 344		#endregion
 345
 346		#region IsPointInside (Static)
 347		/// <summary>
 348		/// Is the given point inside the rectangle?
 349		/// </summary>
 350		/// <param name="point">Point to check</param>
 351		/// <param name="rect">Rectangle to check against</param>
 352		/// <returns>True if the point is inside the rectangle.</returns>
 353		public static bool IsPointInside(ref Point point, ref Rectangle rect)
 354		{
 355			return point.X >= rect.Left &&
 356			       point.X <= rect.Right &&
 357			       point.Y >= rect.Top &&
 358			       point.Y <= rect.Bottom;
 359		}
 360		#endregion
 361
 362		#region IsCircleInside (Static)
 363		/// <summary>
 364		/// Check if a circle is inside a rectangle or not.
 365		/// </summary>
 366		/// <param name="centerPoint">The center point of the circle.</param>
 367		/// <param name="radius">The radius of the cirlce.</param>
 368		/// <param name="rect">The rectangle to check if the circle lays in.</param>
 369		/// <returns>
 370		/// True if the circle is in the rectangle, otherwise False.
 371		/// </returns>
 372		public static bool IsCircleInside(ref Point centerPoint, float radius,
 373			ref Rectangle rect)
 374		{
 375			return centerPoint.X + radius >= rect.Left &&
 376			       centerPoint.X - radius <= rect.Right &&
 377			       centerPoint.Y + radius >= rect.Top &&
 378			       centerPoint.Y - radius <= rect.Bottom;
 379		}
 380		#endregion
 381
 382		#region GetRandomPoint (Static)
 383		/// <summary>
 384		/// Get random point with x and y between 0 and 1.
 385		/// </summary>
 386		/// <returns>Random point with x and y between 0 and 1</returns>
 387		public static Point GetRandomPoint()
 388		{
 389			return GetRandomPoint(0, 1);
 390		}
 391
 392		/// <summary>
 393		/// Get random point with x and y between minValue and maxValue.
 394		/// </summary>
 395		/// <param name="maxValue">Maximum value</param>
 396		/// <param name="minValue">Mininum value</param>
 397		/// <returns>
 398		/// Random point with x and y between minValue and maxValue.
 399		/// </returns>
 400		public static Point GetRandomPoint(float minValue, float maxValue)
 401		{
 402			return new Point(
 403				RandomHelper.RandomFloat(minValue, maxValue),
 404				RandomHelper.RandomFloat(minValue, maxValue));
 405		}
 406		#endregion
 407
 408		#region GetUnitCirclePosition (Static)
 409		/// <summary>
 410		/// Returns the represented position by the given degree on the unit circle
 411		/// (-> degree of: 0/360 = top, 90 = right, 180 = bottom, 270 = left)
 412		/// </summary>
 413		/// <param name="degreeValue">Degree value</param>
 414		/// <returns>Unit vector pointing in the given direction.</returns>
 415		public static Point GetUnitCirclePosition(float degreeValue)
 416		{
 417			return new Point(MathHelper.Sin(degreeValue),
 418				-MathHelper.Cos(degreeValue));
 419		}
 420		#endregion
 421
 422		#region GetRotation (Static)
 423		/// <summary>
 424		/// This will convert the given unit-circle position in an unit-circle
 425		/// rotation (-> top = 0/360, right = 90, bottom = 180, left = 270 degree).
 426		/// If the given position isn't normalized yet, then just set the second
 427		/// parameter to 'true'.
 428		/// <para />
 429		/// Note: When unitCirclePosition is Point.Zero, 0 is returned.
 430		/// </summary>
 431		/// <param name="unitCirclePosition">Unit circle position</param>
 432		/// <param name="isNormalizationNeeded">Is normalization needed</param>
 433		/// <returns>The unit circle rotation (top=0, right=90, etc.)</returns>
 434		public static float GetRotation(Point unitCirclePosition,
 435			bool isNormalizationNeeded)
 436		{
 437			#region Validation
 438			if (unitCirclePosition == Zero)
 439			{
 440				return 0;
 441			}
 442			#endregion
 443
 444			if (isNormalizationNeeded)
 445			{
 446				unitCirclePosition = Normalize(unitCirclePosition);
 447			}
 448
 449			// Will return a value between 0 until 180 and -179 until -1
 450			float rawAngle = MathHelper.Atan(unitCirclePosition.X,
 451				-unitCirclePosition.Y);
 452			// so we have to convert from 0 until 180 and 181 until 359
 453			return (rawAngle < 0.0f)
 454			       	? 360.0f + rawAngle
 455			       	: rawAngle;
 456		}
 457
 458		/// <summary>
 459		/// This will convert the given unit-circle position in an unit-circle
 460		/// rotation (-> top = 0/360, right = 90, bottom = 180, left = 270 degree).
 461		/// The given position will be normalized automatically, if that isn't
 462		/// wished or needed, then just use the other overload with 'false' at the
 463		/// second parameter.
 464		/// </summary>
 465		/// <param name="unitCirclePosition">Unit circle position</param>
 466		/// <returns>Point</returns>
 467		public static float GetRotation(Point unitCirclePosition)
 468		{
 469			return GetRotation(unitCirclePosition, true);
 470		}
 471		#endregion
 472
 473		#region AngleBetweenPoints (Static)
 474		/// <summary>
 475		/// Angle between points in degrees, pretty much the same as
 476		/// AngleBetweenVectors, just in 2D:
 477		/// http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
 478		/// RadiansToDegrees(atan2(a.y,a.x) - atan2(b.y,b.x)) would only give
 479		/// you 0-180 degrees, but we want full 0-360 degrees with Acos :)
 480		/// <para />
 481		/// Note: If one of the points is zero the method we will return 0.0f.
 482		/// </summary>
 483		/// <param name="a">First vector.</param>
 484		/// <param name="b">Second vector.</param>
 485		/// <returns>Angle between the two vectors in the range [0, 360]</returns>
 486		public static float AngleBetweenPoints(Point a, Point b)
 487		{
 488			#region Validation
 489			// Having a single zero vector in this method will cause the calculation
 490			// to return 90 degrees which is not right. So we simply return 0f.
 491			if (a == Zero ||
 492			    b == Zero)
 493			{
 494				return 0f;
 495			}
 496			#endregion
 497
 498			// We need to normalize the vectors so we get the cos from 0 to 1
 499			// the cos is the dot product of the vectors a and b
 500			float cos = Dot(Normalize(a), Normalize(b));
 501			cos = MathHelper.Clamp(cos, -1.0f, 1.0f);
 502
 503			// Note: Special way for 2D vector handling (instead of Vector.Cross)
 504			float cross = MathHelper.Atan(a.Y, a.X) - MathHelper.Atan(b.Y, b.X);
 505			return cross < 0.0f
 506			       	? // cross products directory is upwards
 507			       360 - MathHelper.Acos(cos)
 508			       	: // else
 509			       MathHelper.Acos(cos);
 510		}
 511		#endregion
 512
 513		#region Framework Union Defines (Public)
 514		#endregion
 515
 516		#region X (Public)
 517		/// <summary>
 518		/// X coordinate.
 519		/// </summary>
 520		[FieldOffset(0)]
 521		public float X;
 522		#endregion
 523
 524		#region Y (Public)
 525		/// <summary>
 526		/// Y coordinate.
 527		/// </summary>
 528		[FieldOffset(4)]
 529		public float Y;
 530		#endregion
 531
 532		#region XProperty (Public)
 533		/// <summary>
 534		/// Property-wrapper for using the X field in the editor.
 535		/// </summary>
 536		[Browsable(true)]
 537		[DisplayName("X")]
 538		public float XProperty
 539		{
 540			get
 541			{
 542				return X;
 543			}
 544			set
 545			{
 546				X = value;
 547			}
 548		}
 549		#endregion
 550
 551		#region YProperty (Public)
 552		/// <summary>
 553		/// Property-wrapper for using the Y field in the editor
 554		/// </summary>
 555		[Browsable(true)]
 556		[DisplayName("Y")]
 557		public float YProperty
 558		{
 559			get
 560			{
 561				return Y;
 562			}
 563			set
 564			{
 565				Y = value;
 566			}
 567		}
 568		#endregion
 569
 570		#region Length (Public)
 571		/// <summary>
 572		/// Length
 573		/// </summary>
 574		[Browsable(false)]
 575		public float Length
 576		{
 577			get
 578			{
 579				return MathHelper.Sqrt(X * X + Y * Y);
 580			}
 581		}
 582		#endregion
 583
 584		#region LengthSquared (Public)
 585		/// <summary>
 586		/// Length squared
 587		/// </summary>
 588		[Browsable(false)]
 589		public float LengthSquared
 590		{
 591			get
 592			{
 593				return X * X + Y * Y;
 594			}
 595		}
 596		#endregion
 597
 598		#region Constructors
 599		/// <summary>
 600		/// Creates a 2D point
 601		/// </summary>
 602		/// <param name="setValue">setValue</param>
 603		public Point(float setValue)
 604			: this(setValue, setValue)
 605		{
 606		}
 607
 608		/// <summary>
 609		/// Creates a 2D point
 610		/// </summary>
 611		/// <param name="setX">setX</param>
 612		/// <param name="setY">setY</param>
 613		public Point(float setX, float setY)
 614			: this()
 615		{
 616			X = setX;
 617			Y = setY;
 618		}
 619
 620		/// <summary>
 621		/// Creates a 2D point from a Vector (ignores Z)
 622		/// </summary>
 623		/// <param name="fromVector">fromVector</param>
 624		public Point(Vector fromVector)
 625			: this()
 626		{
 627			X = fromVector.X;
 628			Y = fromVector.Y;
 629		}
 630
 631		/// <summary>
 632		/// Create point
 633		/// </summary>
 634		/// <param name="reader">reader</param>
 635		public Point(BinaryReader reader)
 636			: this()
 637		{
 638			Load(reader);
 639		}
 640		#endregion
 641
 642		#region IEquatable<Point> Members
 643		/// <summary>
 644		/// Equals check will check if the other point is nearly equals (using
 645		/// the MathHelper.Epsilon value, which is close to zero).
 646		/// </summary>
 647		/// <param name="other">Other point to check against</param>
 648		/// <returns>
 649		/// True if both points are almost equal, false if they are apart.
 650		/// </returns>
 651		public bool Equals(Point other)
 652		{
 653			return
 654				// Allow a difference of the Epsilon (in both directions)
 655				// for the X value range
 656				X - MathHelper.Epsilon <= other.X &&
 657				X + MathHelper.Epsilon >= other.X &&
 658				// and Y value range
 659				Y - MathHelper.Epsilon <= other.Y &&
 660				Y + MathHelper.Epsilon >= other.Y;
 661		}
 662		#endregion
 663
 664		#region ISaveLoadBinary Members
 665		/// <summary>
 666		/// Load the point values from a stream.
 667		/// </summary>
 668		/// <param name="reader">The stream that will be used.</param>
 669		public void Load(BinaryReader reader)
 670		{
 671			X = reader.ReadSingle();
 672			Y = reader.ReadSingle();
 673		}
 674
 675		/// <summary>
 676		/// Saves the point to a stream.
 677		/// </summary>
 678		/// <param name="writer">The stream that will be used.</param>
 679		public void Save(BinaryWriter writer)
 680		{
 681			writer.Write(X);
 682			writer.Write(Y);
 683		}
 684		#endregion
 685
 686		#region op_UnaryNegation (Operator)
 687		/// <summary>
 688		/// Operator for negation
 689		/// </summary>
 690		/// <param name="value">Value to subtract</param>
 691		/// <returns>
 692		/// The returned point is the negative version of the input point.
 693		/// </returns>
 694		public static Point operator -(Point value)
 695		{
 696			return new Point(-value.X, -value.Y);
 697		}
 698		#endregion
 699
 700		#region op_Equality (Operator)
 701		/// <summary>
 702		/// Operator for equality
 703		/// </summary>
 704		/// <param name="value1">value1</param>
 705		/// <param name="value2">value2</param>
 706		/// <returns>Returns True if the points are equal, otherwise False.
 707		/// </returns>
 708		public static bool operator ==(Point value1, Point value2)
 709		{
 710			return value1.X == value2.X && value1.Y == value2.Y;
 711		}
 712		#endregion
 713
 714		#region op_Inequality (Operator)
 715		/// <summary>
 716		/// Operator for inequality
 717		/// </summary>
 718		/// <param name="value1">value1</param>
 719		/// <param name="value2">value2</param>
 720		/// <returns>Returns True if the points are unequal, otherwise False.
 721		/// </returns>
 722		public static bool operator !=(Point value1, Point value2)
 723		{
 724			return value1.X != value2.X || value1.Y != value2.Y;
 725		}
 726		#endregion
 727
 728		#region op_Addition (Operator)
 729		/// <summary>
 730		/// Operator for addition
 731		/// </summary>
 732		/// <param name="value1">value1</param>
 733		/// <param name="value2">value2</param>
 734		/// <returns>Returns a point as the result of the addition.</returns>
 735		public static Point operator +(Point value1, Point value2)
 736		{
 737			return new Point(value1.X + value2.X, value1.Y + value2.Y);
 738		}
 739		#endregion
 740
 741		#region op_Subtraction (Operator)
 742		/// <summary>
 743		/// Operator for subtraction
 744		/// </summary>
 745		/// <param name="value1">Point 1</param>
 746		/// <param name="value2">Point 2</param>
 747		/// <returns>Result of the subtraction</returns>
 748		public static Point operator -(Point value1, Point value2)
 749		{
 750			return new Point(value1.X - value2.X, value1.Y - value2.Y);
 751		}
 752		#endregion
 753
 754		#region op_Multiply (Operator)
 755		/// <summary>
 756		/// Operator for multiplication points
 757		/// </summary>
 758		/// <param name="value1">Point 1</param>
 759		/// <param name="value2">Point 2</param>
 760		/// <returns>Result of the multiplication</returns>
 761		public static Point operator *(Point value1, Point value2)
 762		{
 763			return new Point(value1.X * value2.X, value1.Y * value2.Y);
 764		}
 765
 766		/// <summary>
 767		/// Operator for multiplication a point with a float as scaling
 768		/// </summary>
 769		/// <param name="scaleFactor">scaleFactor</param>
 770		/// <param name="value">value</param>
 771		/// <returns>Result of the multiplication</returns>
 772		public static Point operator *(Point value, float scaleFactor)
 773		{
 774			return new Point(value.X * scaleFactor, value.Y * scaleFactor);
 775		}
 776
 777		/// <summary>
 778		/// Operator for multiplication a float as scaling with a point
 779		/// </summary>
 780		/// <param name="scaleFactor">scaleFactor</param>
 781		/// <param name="value">value</param>
 782		/// <returns>Result of the multiplication</returns>
 783		public static Point operator *(float scaleFactor, Point value)
 784		{
 785			return new Point(value.X * scaleFactor, value.Y * scaleFactor);
 786		}
 787		#endregion
 788
 789		#region op_Division (Operator)
 790		/// <summary>
 791		/// Operator to divide a point with a float.
 792		/// </summary>
 793		/// <param name="value">Value</param>
 794		/// <param name="divisor">Divisor</param>
 795		/// <returns>Result of the division</returns>
 796		public static Point operator /(Point value, float divisor)
 797		{
 798			return new Point(value.X / divisor, value.Y / divisor);
 799		}
 800
 801		/// <summary>
 802		/// Operator to divide a point with a float.
 803		/// </summary>
 804		/// <param name="divisor">Divisor</param>
 805		/// <param name="value">Value</param>
 806		/// <returns>Result of the division</returns>
 807		public static Point operator /(float divisor, Point value)
 808		{
 809			return new Point(divisor / value.X, divisor / value.Y);
 810		}
 811		#endregion
 812
 813		#region op_Implicit (Operator)
 814		/// <summary>
 815		/// Operator to implicit convert Size to Point.
 816		/// </summary>
 817		/// <param name="anySize">Any size</param>
 818		/// <returns>
 819		/// Point created from the size (x from width, y from height).
 820		/// </returns>
 821		public static implicit operator Point(Size anySize)
 822		{
 823			return new Point(anySize.Width, anySize.Height);
 824		}
 825		#endregion
 826
 827		#region CloneX (Public)
 828		/// <summary>
 829		/// Returns a new Point with the same X value as before and a new Y
 830		/// changed by the given offset (parameter) value.
 831		/// </summary>
 832		/// <param name="setOffsetOfY">The offset to compute the new Y value
 833		/// for the cloned point.</param>
 834		/// <returns>New cloned Point instance.</returns>
 835		public Point CloneX(float setOffsetOfY)
 836		{
 837			return new Point(X, Y + setOffsetOfY);
 838		}
 839		#endregion
 840
 841		#region CloneY (Public)
 842		/// <summary>
 843		/// Returns a new Point with the same Y value as before and a new X
 844		/// changed by the given offset (parameter) value.
 845		/// </summary>
 846		/// <param name="setOffsetOfX">The offset to compute the new X value for
 847		/// the cloned point.</param>
 848		/// <returns>New cloned Point instance.</returns>
 849		public Point CloneY(float setOffsetOfX)
 850		{
 851			return new Point(X + setOffsetOfX, Y);
 852		}
 853		#endregion
 854
 855		#region Equals (Public)
 856		/// <summary>
 857		/// Check if another object is a point and equals to this point.
 858		/// </summary>
 859		/// <param name="obj">Object to compare with</param>
 860		/// <returns>
 861		/// True if the object is a Point and equal to this point.
 862		/// </returns>
 863		public override bool Equals(object obj)
 864		{
 865			return (obj is Point)
 866			       	? Equals((Point)obj)
 867			       	: base.Equals(obj);
 868		}
 869		#endregion
 870
 871		#region NearlyEquals (Public)
 872		/// <summary>
 873		/// NearlyEquals
 874		/// </summary>
 875		/// <param name="other">Other point we wan't check equality with.</param>
 876		/// <param name="epsilon">A very small value defining the range in which
 877		/// the two points can differ to still be nearly equal enough.</param>
 878		/// <returns>Value indicating the equality of two vectors</returns>
 879		public bool NearlyEquals(Point other, float epsilon)
 880		{
 881			return
 882				// Allow a difference of the Epsilon (in both directions)
 883				// for the X value range
 884				X - epsilon <= other.X &&
 885				X + epsilon >= other.X &&
 886				// and Y value range
 887				Y - epsilon <= other.Y &&
 888				Y + epsilon >= other.Y;
 889		}
 890		#endregion
 891
 892		#region GetHashCode (Public)
 893		/// <summary>
 894		/// Get hash code
 895		/// </summary>
 896		/// <returns>Hash code from X and Y values</returns>
 897		public override int GetHashCode()
 898		{
 899			return X.GetHashCode() ^ Y.GetHashCode();
 900		}
 901		#endregion
 902
 903		#region Resize (Public)
 904		/// <summary>
 905		/// Resize this point to given length and returns the new Point
 906		/// </summary>
 907		/// <param name="length">length</param>
 908		/// <returns>Resized point</returns>
 909		public Point Resize(float length)
 910		{
 911			return Normalize(this) * length;
 912		}
 913		#endregion
 914
 915		#region Rotate (Public)
 916		/// <summary>
 917		/// Rotates this instance around the origin, returns the 
 918		/// </summary>
 919		/// <param name="angle">Angle to rotate in degree</param>
 920		/// <returns>Rotated point with given direction from angle</returns>
 921		public Point Rotate(float angle)
 922		{
 923			float sine = MathHelper.Sin(-angle);
 924			float cosine = MathHelper.Cos(-angle);
 925			float newX = X * cosine + Y * sine;
 926			Y = -X * sine + Y * cosine;
 927			X = newX;
 928			return this;
 929		}
 930		#endregion
 931
 932		#region ToString (Public)
 933		/// <summary>
 934		/// To string
 935		/// </summary>
 936		/// <returns>String with braces, e.g. "(1.0, 2.3)"</returns>
 937		public override string ToString()
 938		{
 939			return ToString("(", ")");
 940		}
 941
 942		/// <summary>
 943		/// To string
 944		/// </summary>
 945		/// <returns>String with custom braces, e.g. "(1.0, 2.3)"</returns>
 946		public string ToString(string openBrace, string closeBrace)
 947		{
 948			return openBrace + X.ToInvariantString("0.000") +
 949			       ", " + Y.ToInvariantString("0.000") + closeBrace;
 950		}
 951		#endregion
 952
 953		/// <summary>
 954		/// Tests
 955		/// </summary>
 956		internal class PointTests
 957		{
 958			#region SizeOf
 959			/// <summary>
 960			/// Checks if the size of Point is exactly 8 bytes (2 floats: X and Y)
 961			/// </summary>
 962			[Test]
 963			public void SizeOf()
 964			{
 965				// Points are 2 floats: X and Y
 966				Assert.Equal(2 * 4, Marshal.SizeOf(typeof(Point)));
 967			}
 968			#endregion
 969
 970			#region DistanceSquared
 971			/// <summary>
 972			/// DistanceSquared
 973			/// </summary>
 974			[Test]
 975			public void DistanceSquared()
 976			{
 977				Assert.Equal(4, Point.DistanceSquared(new Point(2, 0), Zero));
 978			}
 979			#endregion
 980
 981			#region Distance
 982			/// <summary>
 983			/// Distance
 984			/// </summary>
 985			[Test]
 986			public void Distance()
 987			{
 988				Assert.Equal(2, Point.Distance(new Point(2, 0), Zero));
 989			}
 990			#endregion
 991
 992			#region Lerp
 993			/// <summary>
 994			/// Lerp
 995			/// </summary>
 996			[Test]
 997			public void Lerp()
 998			{
 999				Assert.Equal(Zero, Point.Lerp(new Point(2, 2), Zero, 1));
1000			}
1001			#endregion
1002
1003			#region TransformNormal
1004			/// <summary>
1005			/// TransformNormal
1006			/// </summary>
1007			[Test]
1008			public void TransformNormal()
1009			{
1010				Assert.Equal(One, Point.TransformNormal(One,
1011					Matrix.Identity));
1012			}
1013			#endregion
1014
1015			#region Transform
1016			/// <summary>
1017			/// Transform
1018			/// </summary>
1019			[Test]
1020			public void Transform()
1021			{
1022				Assert.Equal(One, Point.Transform(One, Matrix.Identity));
1023			}
1024			#endregion
1025
1026			#region Dot
1027			/// <summary>
1028			/// Dot
1029			/// </summary>
1030			[Test]
1031			public void Dot()
1032			{
1033				Assert.Equal(2, Point.Dot(One, One));
1034			}
1035			#endregion
1036
1037			#region Length
1038			/// <summary>
1039			/// Length
1040			/// </summary>
1041			[Test]
1042			public void Length()
1043			{
1044				Assert.Equal(5, new Point(0, 5).Length);
1045				Assert.Equal(1, new Point(-1, 0).Length);
1046				Assert.Equal(5, new Point(3, 4).Length);
1047			}
1048			#endregion
1049
1050			#region LengthSquared
1051			/// <summary>
1052			/// Length squared
1053			/// </summary>
1054			[Test]
1055			public void LengthSquared()
1056			{
1057				Assert.Equal(25, new Point(0, 5).LengthSquared);
1058				Assert.Equal(1, new Point(-1, 0).LengthSquared);
1059				Assert.Equal(25, new Point(3, 4).LengthSquared);
1060			}
1061			#endregion
1062
1063			#region Negation
1064			/// <summary>
1065			/// Negation
1066			/// </summary>
1067			[Test]
1068			public void Negation()
1069			{
1070				Assert.Equal(new Point(-3, 1), -(new Point(3, -1)));
1071			}
1072			#endregion
1073
1074			#region Equality
1075			/// <summary>
1076			/// Equality
1077			/// </summary>
1078			[Test]
1079			public void Equality()
1080			{
1081				Assert.Equal(new Point(10, 10), new Point(10));
1082				Assert.NotEqual(new Point(10, 5), new Point(10f, 10f));
1083			}
1084			#endregion
1085
1086			#region Addition
1087			/// <summary>
1088			/// Addition
1089			/// </summary>
1090			[Test]
1091			public void Addition()
1092			{
1093				Assert.Equal(new Point(9, 8.8f), new Point(5, 3) + new Point(4, 5.8f));
1094				Assert.Equal(new Point(-1, -2.8f),
1095					new Point(-5, 3) + new Point(4, -5.8f));
1096			}
1097			#endregion
1098
1099			#region Substraction
1100			/// <summary>
1101			/// Substraction
1102			/// </summary>
1103			[Test]
1104			public void Substraction()
1105			{
1106				Assert.Equal(new Point(1, -2.8f), new Point(5, 3) - new Point(4, 5.8f));
1107				Assert.Equal(new Point(-9, 8.8f),
1108					new Point(-5, 3) - new Point(4, -5.8f));
1109			}
1110			#endregion
1111
1112			#region Multiplication
1113			/// <summary>
1114			/// Multiplication
1115			/// </summary>
1116			[Test]
1117			public void Multiplication()
1118			{
1119				// with Points
1120				Assert.Equal(new Point(2, 2), new Point(2, 4) * new Point(1, 0.5f));
1121				Assert.Equal(new Point(-2, -4), new Point(2, 4) * new Point(-1));
1122
1123				// with a scale factor
1124				Assert.Equal(new Point(10, 20), new Point(2, 4) * 5);
1125				Assert.Equal(new Point(-1, -2), new Point(2, 4) * -0.5f);
1126				Assert.Equal(new Point(0.5f, 1), 0.25f * new Point(2, 4));
1127			}
1128			#endregion
1129
1130			#region Division
1131			/// <summary>
1132			/// Division
1133			/// </summary>
1134			[Test]
1135			public void Division()
1136			{
1137				Assert.Equal(new Point(2, 5), new Point(10, 25) / 5.0f);
1138				Assert.Equal(new Point(5, 6), new Point(10, 12) / 2);
1139
1140				Assert.Equal(new Point(0.1f, 0.04f), 1.0f / new Point(10, 25));
1141			}
1142			#endregion
1143
1144			#region NearlyEquals
1145			/// <summary>
1146			/// Nearly equals
1147			/// </summary>
1148			[Test]
1149			public void NearlyEquals()
1150			{
1151				Point testPoint = new Point(2, 3);
1152
1153				// Check the point directly
1154				Assert.True(testPoint.Equals(testPoint), "TODO");
1155				// by the "object" overload from .NET
1156				Assert.True(testPoint.Equals((object)testPoint), "TODO");
1157
1158				// and the nearly equal check
1159				Assert.True(testPoint.Equals(
1160					new Point(2 + MathHelper.Epsilon, 3 - MathHelper.Epsilon)), "TODO");
1161
1162				// Finally check the "bad" false cases with unequal values
1163				Assert.False(testPoint.Equals(new Point(4, 3)), "TODO");
1164				// and a too big epsilon
1165				Assert.False(testPoint.Equals(
1166					new Point(2 + (2 * MathHelper.Epsilon), 3)), "TODO");
1167			}
1168			#endregion
1169
1170			#region Normalize
1171			/// <summary>
1172			/// Normalize
1173			/// </summary>
1174			[Test]
1175			public void Normalize()
1176			{
1177				Assert.Equal(UnitX, Point.Normalize(new Point(13, 0)));
1178				Assert.Equal(-UnitY, Point.Normalize(new Point(0, -7)));
1179			}
1180			#endregion
1181
1182			#region Min
1183			/// <summary>
1184			/// Minimum
1185			/// </summary>
1186			[Test]
1187			public void Min()
1188			{
1189				Assert.Equal(new Point(2, 1),
1190					Point.Min(new Point(2, 4), new Point(4, 1)));
1191			}
1192			#endregion
1193
1194			#region Max
1195			/// <summary>
1196			/// Maximum
1197			/// </summary>
1198			[Test]
1199			public void Max()
1200			{
1201				Assert.Equal(new Point(4, 4),
1202					Point.Max(new Point(2, 4), new Point(4, 1)));
1203			}
1204			#endregion
1205
1206			#region Rotate
1207			/// <summary>
1208			/// Rotate
1209			/// </summary>
1210			[Test]
1211			public void Rotate()
1212			{
1213				Point p = new Point(10, 20);
1214				p.Rotate(90);
1215				Assert.Equal(new Point(-20, 10), p);
1216			}
1217			#endregion
1218
1219			#region GetRotation
1220			/// <summary>
1221			/// Get rotation
1222			/// </summary>
1223			[Test]
1224			public void GetRotation()
1225			{
1226				Assert.NearlyEqual(Point.GetRotation(new Point(0, -1), false), 0);
1227				Assert.NearlyEqual(Point.GetRotation(new Point(1, 0), false), 90);
1228				Assert.NearlyEqual(Point.GetRotation(new Point(0, 1), false), 180);
1229				Assert.NearlyEqual(Point.GetRotation(new Point(-1, 0), false), 270);
1230
1231				Assert.NearlyEqual(Point.GetRotation(new Point(0, -4)), 0);
1232				Assert.NearlyEqual(Point.GetRotation(new Point(2, 0)), 90);
1233				Assert.NearlyEqual(Point.GetRotation(new Point(0, 8)), 180);
1234				Assert.NearlyEqual(Point.GetRotation(new Point(-5, 0)), 270);
1235			}
1236			#endregion
1237
1238			#region ToString
1239			/// <summary>
1240			/// To string
1241			/// </summary>
1242			[Test]
1243			public new void ToString()
1244			{
1245				Assert.Equal("(5.000, 3.500)", new Point(5, 3.5f).ToString());
1246				Assert.Equal("(0.000, 0.000)", new Point().ToString());
1247				Assert.Equal("5.000, 3.500", new Point(5, 3.5f).ToString("", ""));
1248				Assert.Equal("{5.000, 3.700}", new Point(5, 3.7f).ToString("{", "}"));
1249
1250				// And the other way around
1251				Assert.Equal(new Point(5, 3.5f), FromString("(5, 3.5)"));
1252				Assert.Equal(new Point(), FromString("(0, 0)"));
1253				Assert.Equal(new Point(5, 3.5f), FromString("5 3.5"));
1254				Assert.Equal(new Point(), FromString("0 0"));
1255				Assert.Equal(new Point(5, 3.5f), FromString("5, 3.5"));
1256				Assert.Equal(new Point(5, 3.7f), FromString("{5, 3.7}"));
1257			}
1258			#endregion
1259		}
1260	}
1261}