2015-05-29 07:47:32 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
2015-05-29 16:03:08 +00:00
|
|
|
|
using System.Xml.Serialization;
|
2015-05-29 07:47:32 +00:00
|
|
|
|
|
|
|
|
|
namespace TransportGame.Model
|
|
|
|
|
{
|
|
|
|
|
public struct Vector2
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Zero vector
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly Vector2 Zero = new Vector2(0, 0);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Unit vector
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly Vector2 Unit = new Vector2(1, 0);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the X component
|
|
|
|
|
/// </summary>
|
2015-05-29 16:03:08 +00:00
|
|
|
|
[XmlAttribute("x")]
|
|
|
|
|
public float X { get; set; }
|
2015-05-29 07:47:32 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the Y component
|
|
|
|
|
/// </summary>
|
2015-05-29 16:03:08 +00:00
|
|
|
|
[XmlAttribute("y")]
|
|
|
|
|
public float Y { get; set; }
|
2015-05-29 07:47:32 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a vector2
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="x">X component</param>
|
|
|
|
|
/// <param name="y">Y component</param>
|
|
|
|
|
public Vector2(float x, float y)
|
|
|
|
|
: this()
|
|
|
|
|
{
|
|
|
|
|
X = x;
|
|
|
|
|
Y = y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the length of the vector
|
|
|
|
|
/// </summary>
|
|
|
|
|
public float Length
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (float)Math.Sqrt(LengthSq);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the length of the vector squared
|
|
|
|
|
/// </summary>
|
|
|
|
|
public float LengthSq
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return X * X + Y * Y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the normalized vector
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Normalized vector</returns>
|
|
|
|
|
public Vector2 Normalized
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
float len = Length;
|
|
|
|
|
return new Vector2(X / len, Y / len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 17:50:59 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the normalized vector raised to second power
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// This is less computationally expensive (no need to calculate square root).
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <returns>Normalized vector</returns>
|
|
|
|
|
public Vector2 NormalizedSq
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
float len2 = LengthSq;
|
|
|
|
|
return new Vector2(X * X / len2, Y * Y / len2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-29 07:47:32 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Rotates vector by given number of radians
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="radians"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public Vector2 Rotate(float radians)
|
|
|
|
|
{
|
|
|
|
|
float sin = (float)Math.Sin(radians);
|
|
|
|
|
float cos = (float)Math.Cos(radians);
|
|
|
|
|
|
|
|
|
|
return new Vector2(X * cos - Y * sin, X * sin + Y * cos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Rotates vector by given number of degrees
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="degrees"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public Vector2 RotateDeg(float degrees)
|
|
|
|
|
{
|
|
|
|
|
return Rotate(degrees * (float)Math.PI / 180f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sum operator
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>Result of addition</returns>
|
|
|
|
|
public static Vector2 operator +(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(a.X + b.X, a.Y + b.Y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Subtract operator
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>Result of subtraction</returns>
|
|
|
|
|
public static Vector2 operator -(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(a.X - b.X, a.Y - b.Y);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 17:50:59 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Negation operator
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">Vector</param>
|
|
|
|
|
/// <returns>Negated vector</returns>
|
|
|
|
|
public static Vector2 operator -(Vector2 a)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(-a.X, -a.Y);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-29 07:47:32 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Multiply by constant
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">Vector</param>
|
|
|
|
|
/// <param name="c">Constant</param>
|
|
|
|
|
/// <returns>Result</returns>
|
|
|
|
|
public static Vector2 operator *(Vector2 a, float c)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(a.X * c, a.Y * c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Multiply by constant
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="c">Constant</param>
|
|
|
|
|
/// <param name="a">Vector</param>
|
|
|
|
|
/// <returns>Result</returns>
|
|
|
|
|
public static Vector2 operator *(float c, Vector2 a)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(a.X * c, a.Y * c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Divide by constant
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">Vector</param>
|
|
|
|
|
/// <param name="c">Constant</param>
|
|
|
|
|
/// <returns>Result</returns>
|
|
|
|
|
public static Vector2 operator /(Vector2 a, float c)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2(a.X / c, a.Y / c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Equality operator
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>True if vectors are equal</returns>
|
|
|
|
|
public static bool operator ==(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return a.X == b.X && a.Y == b.Y;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Inequality operator
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>True if vectors are not equal</returns>
|
|
|
|
|
public static bool operator !=(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return a.X != b.X || a.Y != b.Y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Calculates dot product of two vectors
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>Dot product</returns>
|
|
|
|
|
public static float Dot(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return a.X * b.X + a.Y * b.Y;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 17:50:59 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the magnitude of the cross product between the two vectors (z considered 0)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">First vector</param>
|
|
|
|
|
/// <param name="b">Second vector</param>
|
|
|
|
|
/// <returns>Magnitude of cross product</returns>
|
|
|
|
|
public static float Cross(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return (a.X * b.Y) - (a.Y * b.X);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Tests if two vectors are colliniar
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="a">a</param>
|
|
|
|
|
/// <param name="b">b</param>
|
|
|
|
|
/// <returns>True if vectors are colliniar</returns>
|
|
|
|
|
public static bool AreColliniar(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
return Math.Abs(Cross(a, b)) < 1e-12;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-29 07:47:32 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the vector corresponding with specified angle (in radians)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="rads">Radians</param>
|
|
|
|
|
/// <returns>Vector</returns>
|
|
|
|
|
public static Vector2 FromRadians(float rads)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2((float)Math.Cos(rads), (float)Math.Sin(rads));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the vector corresponding with specified angle (in degrees)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="degs">Degrees</param>
|
|
|
|
|
/// <returns>Vector</returns>
|
|
|
|
|
public static Vector2 FromDegrees(float degs)
|
|
|
|
|
{
|
|
|
|
|
float rads = (degs * (float)Math.PI / 180f);
|
|
|
|
|
return FromRadians(rads);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return String.Format("({0}, {1})", X, Y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj is Vector2)
|
|
|
|
|
{
|
|
|
|
|
Vector2 other = (Vector2)obj;
|
|
|
|
|
return X == other.X && Y == other.Y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
return X.GetHashCode() * 7 + Y.GetHashCode();
|
|
|
|
|
}
|
2015-06-13 18:36:32 +00:00
|
|
|
|
|
|
|
|
|
private class LengthComparerImpl : IComparer<Vector2>
|
|
|
|
|
{
|
|
|
|
|
public int Compare(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
if (a.LengthSq > b.LengthSq)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (a.LengthSq < b.LengthSq)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class TrigonometricComparerImpl : IComparer<Vector2>
|
|
|
|
|
{
|
|
|
|
|
private int Quad(Vector2 v)
|
|
|
|
|
{
|
|
|
|
|
if (v.Y >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (v.X >= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (v.X < 0)
|
|
|
|
|
return 2;
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Compare(Vector2 a, Vector2 b)
|
|
|
|
|
{
|
|
|
|
|
// If vectors are in different quadrants, we can use quadrant number
|
|
|
|
|
int qa = Quad(a), qb = Quad(b);
|
|
|
|
|
|
|
|
|
|
if (qa != qb)
|
|
|
|
|
{
|
|
|
|
|
return qa - qb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In same quadrant. Compute cross product which gives us sin(ab)*len(a)*len(b)
|
|
|
|
|
// Vectors are in same quadrant, so angle should be less than 90deg
|
|
|
|
|
float cross = Cross(a, b);
|
|
|
|
|
if (cross < 0) // Angle > 180 degrees => a > b
|
|
|
|
|
return 1;
|
|
|
|
|
if (cross > 0) // Angle < 180 degrees => a < b
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// Points are on the same line. Use distance
|
|
|
|
|
if (a.LengthSq > b.LengthSq)
|
|
|
|
|
return 1;
|
|
|
|
|
else if (a.LengthSq < b.LengthSq)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// Points are equal
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IComparer<Vector2> LengthComparer = new LengthComparerImpl();
|
|
|
|
|
public static IComparer<Vector2> TrigonomicComparer = new TrigonometricComparerImpl();
|
2015-05-29 07:47:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|