namespace GeometriCS
{
///
/// Two-dimensional vector with double precision.
///
public class Vector2d : ICloneable
{
///
/// Vector with 0 length.
///
public static readonly Vector2d ZeroVector = new(0d, 0d);
///
/// Unit vector following the X axis, or (1; 0)
///
public static readonly Vector2d XAxis = new(1d, 0d);
///
/// Unit vector following the Y axis, or (0; 1)
///
public static readonly Vector2d YAxis = new(0d, 1d);
///
/// X component of the vector.
///
public double X { get; set; }
///
/// Y component of the vector.
///
public double Y { get; set; }
///
/// Length of the vector.
///
public double Length
{
get
{
return Math.Sqrt(X*X + Y*Y);
}
set
{
// If desired length is 0, set the components to 0 manually.
if(IsZero)
{
X = 0;
Y = 0;
return;
}
// New length divided by the old Length.
// Or, the scalar we need to apply to the vector in order for it to reach the desired length.
double scaleDelta = value / Length;
// Scale the vector by the scalar delta.
X *= scaleDelta;
Y *= scaleDelta;
}
}
///
/// Is this a zero vecor?
///
public bool IsZero => Utils.DoubleEquals(Length, 0);
///
/// Is this a unit vector?
///
public bool IsUnit => Utils.DoubleEquals(Length, 1);
///
/// Normalized, or unit version of the vector.
///
/// Calling this method does not affect the source vector.
/// Normalized vector, or (0; 0) if original is (0; 0).
public Vector2d Normalized()
{
// If this is a zero vector, return a zero vector.
if(IsZero)
{
return new Vector2d(0, 0);
}
// Get the inverse of the length of the vector,
// Or the scalar we need to apply to the vector in order for it to reach the desired length.
double scaleDelta = 1 / Length;
// Return this vector scaled to have its Length equal to 1
return new Vector2d(X * scaleDelta, Y * scaleDelta);
}
///
/// Compute the cross product between this and another vector.
///
///
/// Determinant of a matrix made of the two vectors.
///
/// Other vector.
/// The cross product of the two vectors.
public double CrossProduct(Vector2d other)
{
// Compute the determinant by the rule of Sarrus
return (X * other.Y) - (Y * other.X);
}
///
/// Compute the dot product between this and another vector.
///
/// Other vector.
/// The dot product of the two vectors.
public double DotProduct(Vector2d other)
{
return X * other.X + Y * other.Y;
}
///
/// Get the vector needed to get from the point at the end of this vector to the end of another vector.
///
/// The vector to get to the end of.
/// Vector leading from the tip of this vector to the tip of the other vector.
public Vector2d GetVectorTo(Vector2d other)
{
return new Vector2d(-X + other.Y, -Y + other.Y);
}
///
/// Constructor.
///
/// X component of the vector.
/// Y component of the vector.
public Vector2d(double x, double y)
{
X = x;
Y = y;
}
///
/// String representation of the vector.
///
/// (X; Y)
public override string ToString()
{
return $"({X}; {Y})";
}
///
/// Do the two objects represent the same vector?
///
/// Object to compare.
/// true if the vectors are equal. Otherwise false
public override bool Equals(object? obj)
{
if (obj is Vector2d asVect)
{
return this == asVect;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
///
/// Deep copy the vector.
///
/// Deep copy of the vector.
public object Clone()
{
return new Vector2d(X, Y);
}
///
/// Negation of the vector.
///
/// Vector to negate.
/// Negated vector.
public static Vector2d operator -(Vector2d vect)
{
return new Vector2d(-vect.X, -vect.Y);
}
///
/// Are the vectors equal?
///
/// First vector.
/// Second vector.
/// true if the vectors are equal. Otherwise false
public static bool operator ==(Vector2d a, Vector2d b)
{
return Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y);
}
///
/// Are the vectors different?
///
/// First vector.
/// Second vector.
/// true if the vectors are different. Otherwise false
public static bool operator !=(Vector2d a, Vector2d b)
{
return !(Utils.DoubleEquals(a.X, b.X) && Utils.DoubleEquals(a.Y, b.Y));
}
///
/// Add the vectors together.
///
/// First vector.
/// Second vector.
/// a + b
public static Vector2d operator +(Vector2d a, Vector2d b)
{
return new Vector2d(a.X + b.X, a.Y + b.Y);
}
///
/// Add the first vector and the negation of the second negation.
///
/// First vector.
/// Second vector.
/// a + (-b)
public static Vector2d operator -(Vector2d a, Vector2d b)
{
return new Vector2d(a.X - b.X, a.Y - b.Y);
}
///
/// Scale the vector by the scalar.
///
/// Vector.
/// Scalar.
/// vect * scalar
public static Vector2d operator *(Vector2d vect, double scalar)
{
return new Vector2d(vect.X * scalar, vect.Y * scalar);
}
///
/// Scale the vector by the inverse of the scalar.
///
/// Vector.
/// Scalar.
/// vect * (1 / scalar)
public static Vector2d operator /(Vector2d vect, double scalar)
{
if(Utils.DoubleEquals(scalar, 0))
{
throw new DivideByZeroException("Cannot divide by zero, silly.");
}
return new Vector2d(vect.X / scalar, vect.Y / scalar);
}
}
}