using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
#nullable enable
namespace Avalonia
{
///
/// Defines a vector.
///
#if !BUILDTASK
public
#endif
readonly struct Vector : IEquatable
{
static Vector()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator(prop => typeof(Vector).IsAssignableFrom(prop.PropertyType));
#endif
}
///
/// The X component.
///
private readonly double _x;
///
/// The Y component.
///
private readonly double _y;
///
/// Initializes a new instance of the structure.
///
/// The X component.
/// The Y component.
public Vector(double x, double y)
{
_x = x;
_y = y;
}
///
/// Gets the X component.
///
public double X => _x;
///
/// Gets the Y component.
///
public double Y => _y;
///
/// Converts the to a .
///
/// The vector.
public static explicit operator Point(Vector a)
{
return new Point(a._x, a._y);
}
///
/// Calculates the dot product of two vectors.
///
/// First vector.
/// Second vector.
/// The dot product.
public static double operator *(Vector a, Vector b)
=> Dot(a, b);
///
/// Scales a vector.
///
/// The vector.
/// The scaling factor.
/// The scaled vector.
public static Vector operator *(Vector vector, double scale)
=> Multiply(vector, scale);
///
/// Scales a vector.
///
/// The vector.
/// The scaling factor.
/// The scaled vector.
public static Vector operator *(double scale, Vector vector)
=> Multiply(vector, scale);
///
/// Scales a vector.
///
/// The vector.
/// The divisor.
/// The scaled vector.
public static Vector operator /(Vector vector, double scale)
=> Divide(vector, scale);
///
/// Parses a string.
///
/// The string.
/// The .
public static Vector Parse(string s)
{
using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Vector."))
{
return new Vector(
tokenizer.ReadDouble(),
tokenizer.ReadDouble()
);
}
}
///
/// Length of the vector.
///
public double Length => Math.Sqrt(SquaredLength);
///
/// Squared Length of the vector.
///
public double SquaredLength => _x * _x + _y * _y;
///
/// Negates a vector.
///
/// The vector.
/// The negated vector.
public static Vector operator -(Vector a)
=> Negate(a);
///
/// Adds two vectors.
///
/// The first vector.
/// The second vector.
/// A vector that is the result of the addition.
public static Vector operator +(Vector a, Vector b)
=> Add(a, b);
///
/// Subtracts two vectors.
///
/// The first vector.
/// The second vector.
/// A vector that is the result of the subtraction.
public static Vector operator -(Vector a, Vector b)
=> Subtract(a, b);
///
/// Check if two vectors are equal (bitwise).
///
///
///
public bool Equals(Vector other)
{
// ReSharper disable CompareOfFloatsByEqualityOperator
return _x == other._x && _y == other._y;
// ReSharper restore CompareOfFloatsByEqualityOperator
}
///
/// Check if two vectors are nearly equal (numerically).
///
/// The other vector.
/// True if vectors are nearly equal.
public bool NearlyEquals(Vector other)
{
return MathUtilities.AreClose(_x, other._x) &&
MathUtilities.AreClose(_y, other._y);
}
public override bool Equals(object? obj) => obj is Vector other && Equals(other);
public override int GetHashCode()
{
unchecked
{
return (_x.GetHashCode() * 397) ^ _y.GetHashCode();
}
}
public static bool operator ==(Vector left, Vector right)
{
return left.Equals(right);
}
public static bool operator !=(Vector left, Vector right)
{
return !left.Equals(right);
}
///
/// Returns the string representation of the vector.
///
/// The string representation of the vector.
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y);
}
///
/// Returns a new vector with the specified X component.
///
/// The X component.
/// The new vector.
public Vector WithX(double x)
{
return new Vector(x, _y);
}
///
/// Returns a new vector with the specified Y component.
///
/// The Y component.
/// The new vector.
public Vector WithY(double y)
{
return new Vector(_x, y);
}
///
/// Returns a normalized version of this vector.
///
/// The normalized vector.
public Vector Normalize()
=> Normalize(this);
///
/// Returns a negated version of this vector.
///
/// The negated vector.
public Vector Negate()
=> Negate(this);
///
/// Returns the dot product of two vectors.
///
/// The first vector.
/// The second vector.
/// The dot product.
public static double Dot(Vector a, Vector b)
=> a._x * b._x + a._y * b._y;
///
/// Returns the cross product of two vectors.
///
/// The first vector.
/// The second vector.
/// The cross product.
public static double Cross(Vector a, Vector b)
=> a._x * b._y - a._y * b._x;
///
/// Normalizes the given vector.
///
/// The vector
/// The normalized vector.
public static Vector Normalize(Vector vector)
=> Divide(vector, vector.Length);
///
/// Divides the first vector by the second.
///
/// The first vector.
/// The second vector.
/// The scaled vector.
public static Vector Divide(Vector a, Vector b)
=> new Vector(a._x / b._x, a._y / b._y);
///
/// Divides the vector by the given scalar.
///
/// The vector
/// The scalar value
/// The scaled vector.
public static Vector Divide(Vector vector, double scalar)
=> new Vector(vector._x / scalar, vector._y / scalar);
///
/// Multiplies the first vector by the second.
///
/// The first vector.
/// The second vector.
/// The scaled vector.
public static Vector Multiply(Vector a, Vector b)
=> new Vector(a._x * b._x, a._y * b._y);
///
/// Multiplies the vector by the given scalar.
///
/// The vector
/// The scalar value
/// The scaled vector.
public static Vector Multiply(Vector vector, double scalar)
=> new Vector(vector._x * scalar, vector._y * scalar);
///
/// Adds the second to the first vector
///
/// The first vector.
/// The second vector.
/// The summed vector.
public static Vector Add(Vector a, Vector b)
=> new Vector(a._x + b._x, a._y + b._y);
///
/// Subtracts the second from the first vector
///
/// The first vector.
/// The second vector.
/// The difference vector.
public static Vector Subtract(Vector a, Vector b)
=> new Vector(a._x - b._x, a._y - b._y);
///
/// Negates the vector
///
/// The vector to negate.
/// The scaled vector.
public static Vector Negate(Vector vector)
=> new Vector(-vector._x, -vector._y);
///
/// Returns the vector (0.0, 0.0).
///
public static Vector Zero
=> new Vector(0, 0);
///
/// Returns the vector (1.0, 1.0).
///
public static Vector One
=> new Vector(1, 1);
///
/// Returns the vector (1.0, 0.0).
///
public static Vector UnitX
=> new Vector(1, 0);
///
/// Returns the vector (0.0, 1.0).
///
public static Vector UnitY
=> new Vector(0, 1);
///
/// Deconstructs the vector into its X and Y components.
///
/// The X component.
/// The Y component.
public void Deconstruct(out double x, out double y)
{
x = this._x;
y = this._y;
}
///
/// Gets a value indicating whether the X and Y components are zero.
///
public bool IsDefault
{
get { return (_x == 0) && (_y == 0); }
}
}
}