2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.Geometry
|
|
|
|
|
{
|
|
|
|
|
public struct Vector2D
|
|
|
|
|
{
|
|
|
|
|
#region ================== Constants
|
|
|
|
|
|
2020-05-18 16:14:54 +00:00
|
|
|
|
private const double TINY_VALUE = 0.0000000001f;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
|
|
|
|
// Coordinates
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public double x;
|
|
|
|
|
public double y;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Constructors
|
|
|
|
|
|
|
|
|
|
// Constructor
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D(double x, double y)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
this.x = x;
|
|
|
|
|
this.y = y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
|
public Vector2D(Vector3D v)
|
|
|
|
|
{
|
|
|
|
|
this.x = v.x;
|
|
|
|
|
this.y = v.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Statics
|
|
|
|
|
|
|
|
|
|
// Conversion to Vector3D
|
|
|
|
|
public static implicit operator Vector3D(Vector2D a)
|
|
|
|
|
{
|
|
|
|
|
return new Vector3D(a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This adds two vectors
|
|
|
|
|
public static Vector2D operator +(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x + b.x, a.y + b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This adds to a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator +(double a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a + b.x, a + b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This adds to a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator +(Vector2D a, double b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x + b, a.y + b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This subtracts two vectors
|
|
|
|
|
public static Vector2D operator -(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x - b.x, a.y - b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This subtracts from a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator -(Vector2D a, double b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x - b, a.y - b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This subtracts from a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator -(double a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a - b.x, a - b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This reverses a vector
|
|
|
|
|
public static Vector2D operator -(Vector2D a)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(-a.x, -a.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator *(double s, Vector2D a)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x * s, a.y * s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator *(Vector2D a, double s)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x * s, a.y * s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
|
|
|
|
public static Vector2D operator *(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x * b.x, a.y * b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator /(double s, Vector2D a)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x / s, a.y / s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D operator /(Vector2D a, double s)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x / s, a.y / s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales a vector
|
|
|
|
|
public static Vector2D operator /(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(a.x / b.x, a.y / b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the dot product
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static double DotProduct(Vector2D a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Calculate and return the dot product
|
|
|
|
|
return a.x * b.x + a.y * b.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the cross product
|
|
|
|
|
public static Vector2D CrossProduct(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
Vector2D result = new Vector2D();
|
|
|
|
|
|
|
|
|
|
// Calculate and return the dot product
|
|
|
|
|
result.x = a.y * b.x;
|
|
|
|
|
result.y = a.x * b.y;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This compares a vector
|
|
|
|
|
public static bool operator ==(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return (a.x == b.x) && (a.y == b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This compares a vector
|
|
|
|
|
public static bool operator !=(Vector2D a, Vector2D b)
|
|
|
|
|
{
|
|
|
|
|
return (a.x != b.x) || (a.y != b.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This reflects the vector v over mirror m
|
|
|
|
|
// Note that mirror m must be normalized!
|
|
|
|
|
// R = V - 2 * M * (M dot V)
|
|
|
|
|
public static Vector2D Reflect(Vector2D v, Vector2D m)
|
|
|
|
|
{
|
|
|
|
|
// Get the dot product of v and m
|
2020-05-18 16:14:54 +00:00
|
|
|
|
double dp = Vector2D.DotProduct(m, v);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
|
|
// Make the reflected vector
|
|
|
|
|
Vector2D mv = new Vector2D();
|
|
|
|
|
mv.x = v.x - (2f * m.x * dp);
|
|
|
|
|
mv.y = v.y - (2f * m.y * dp);
|
|
|
|
|
|
|
|
|
|
// Return the reflected vector
|
|
|
|
|
return mv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns the reversed vector
|
|
|
|
|
public static Vector2D Reversed(Vector2D v)
|
|
|
|
|
{
|
|
|
|
|
// Return reversed vector
|
|
|
|
|
return new Vector2D(-v.x, -v.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns a vector from an angle
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D FromAngle(double angle)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Return vector from angle
|
2020-05-18 16:14:54 +00:00
|
|
|
|
return new Vector2D(Math.Sin(angle), -Math.Cos(angle));
|
2009-04-19 18:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns a vector from an angle with a given legnth
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static Vector2D FromAngle(double angle, double length)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Return vector from angle
|
|
|
|
|
return FromAngle(angle) * length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the angle
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static double GetAngle(Vector2D a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Calculate and return the angle
|
2020-05-18 16:14:54 +00:00
|
|
|
|
return -Math.Atan2(-(a.y - b.y), (a.x - b.x)) + Angle2D.PIHALF;//mxd //(float)Math.PI * 0.5f;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns the square distance between two points
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static double DistanceSq(Vector2D a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
Vector2D d = a - b;
|
|
|
|
|
return d.GetLengthSq();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns the distance between two points
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static double Distance(Vector2D a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
Vector2D d = a - b;
|
|
|
|
|
return d.GetLength();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns the manhattan distance between two points
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public static double ManhattanDistance(Vector2D a, Vector2D b)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
Vector2D d = a - b;
|
|
|
|
|
return Math.Abs(d.x) + Math.Abs(d.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Methods
|
|
|
|
|
|
|
|
|
|
// This returns the perpendicular vector by simply making a normal
|
|
|
|
|
public Vector2D GetPerpendicular()
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(-y, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns a vector with the sign of all components
|
|
|
|
|
public Vector2D GetSign()
|
|
|
|
|
{
|
|
|
|
|
return new Vector2D(Math.Sign(x), Math.Sign(y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the angle
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public double GetAngle()
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
2016-11-21 13:03:19 +00:00
|
|
|
|
//mxd. Let's make sure the angle is in [0 .. PI2] range...
|
2020-05-18 16:14:54 +00:00
|
|
|
|
double angle = -Math.Atan2(-y, x) + Angle2D.PIHALF;
|
2016-11-21 13:03:19 +00:00
|
|
|
|
if(angle < 0f) angle += Angle2D.PI2;
|
|
|
|
|
return angle;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public double GetLength()
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Calculate and return the length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
return Math.Sqrt(x * x + y * y);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the square length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public double GetLengthSq()
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Calculate and return the square length
|
|
|
|
|
return x * x + y * y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This calculates the length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public double GetManhattanLength()
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Calculate and return the length
|
|
|
|
|
return Math.Abs(x) + Math.Abs(y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This returns a normalized vector
|
|
|
|
|
public Vector2D GetNormal()
|
|
|
|
|
{
|
2020-05-18 16:14:54 +00:00
|
|
|
|
double lensq = this.GetLengthSq();
|
2009-04-19 18:07:22 +00:00
|
|
|
|
if(lensq > TINY_VALUE)
|
|
|
|
|
{
|
|
|
|
|
// Divide each element by the length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
double mul = 1f / Math.Sqrt(lensq);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
return new Vector2D(x * mul, y * mul);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Cannot make normal
|
|
|
|
|
return new Vector2D(0f, 0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This scales the vector
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D GetScaled(double s)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Scale the vector
|
|
|
|
|
return new Vector2D(x * s, y * s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This changes the vector length
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D GetFixedLength(double l)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Normalize, then scale
|
|
|
|
|
return this.GetNormal().GetScaled(l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Output
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return x + ", " + y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Transform
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D GetTransformed(double offsetx, double offsety, double scalex, double scaley)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D((x + offsetx) * scalex, (y + offsety) * scaley);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inverse Transform
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D GetInvTransformed(double invoffsetx, double invoffsety, double invscalex, double invscaley)
|
2009-04-19 18:07:22 +00:00
|
|
|
|
{
|
|
|
|
|
return new Vector2D((x * invscalex) + invoffsetx, (y * invscaley) + invoffsety);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-11 09:47:53 +00:00
|
|
|
|
// Rotate (Added by Anders <20>strand 2008-05-18)
|
2020-05-18 16:14:54 +00:00
|
|
|
|
public Vector2D GetRotated(double theta)
|
2013-09-11 09:47:53 +00:00
|
|
|
|
{
|
2020-05-18 16:14:54 +00:00
|
|
|
|
double cos = Math.Cos(theta);
|
|
|
|
|
double sin = Math.Sin(theta);
|
|
|
|
|
double rx = cos * x - sin * y;
|
|
|
|
|
double ry = sin * x + cos * y;
|
2013-09-11 09:47:53 +00:00
|
|
|
|
return new Vector2D(rx, ry);
|
|
|
|
|
}
|
2010-01-02 22:06:40 +00:00
|
|
|
|
|
|
|
|
|
// Checks if the Vector has valid values for x and y
|
|
|
|
|
public bool IsFinite()
|
|
|
|
|
{
|
2020-05-18 16:14:54 +00:00
|
|
|
|
return !double.IsNaN(x) && !double.IsNaN(y) && !double.IsInfinity(x) && !double.IsInfinity(y);
|
2010-01-02 22:06:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-18 13:52:27 +00:00
|
|
|
|
//mxd. Addeed to make compiler a bit more happy...
|
2014-12-03 23:15:26 +00:00
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
2013-03-18 13:52:27 +00:00
|
|
|
|
return base.GetHashCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mxd. Addeed to make compiler a bit more happy...
|
2014-12-03 23:15:26 +00:00
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
2015-12-28 15:01:53 +00:00
|
|
|
|
if(!(obj is Vector2D)) return false;
|
2013-03-18 13:52:27 +00:00
|
|
|
|
|
|
|
|
|
Vector2D other = (Vector2D)obj;
|
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
if(x != other.x) return false;
|
|
|
|
|
if(y != other.y) return false;
|
2013-03-18 13:52:27 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|