using System; using System.ComponentModel; using System.Globalization; using System.Numerics; #if !BUILDTASK using Avalonia.Animation.Animators; #endif using Avalonia.Utilities; namespace Avalonia { /// /// Defines a point. /// #if !BUILDTASK [TypeConverter(typeof(PointConverter))] public #endif readonly struct Point : IEquatable { static Point() { #if !BUILDTASK Animation.Animation.RegisterAnimator(prop => typeof(Point).IsAssignableFrom(prop.PropertyType)); #endif } /// /// The X position. /// private readonly double _x; /// /// The Y position. /// private readonly double _y; /// /// Initializes a new instance of the structure. /// /// The X position. /// The Y position. public Point(double x, double y) { _x = x; _y = y; } /// /// Gets the X position. /// public double X => _x; /// /// Gets the Y position. /// public double Y => _y; /// /// Converts the to a . /// /// The point. public static implicit operator Vector(Point p) { return new Vector(p._x, p._y); } /// /// Negates a point. /// /// The point. /// The negated point. public static Point operator -(Point a) { return new Point(-a._x, -a._y); } /// /// Checks for equality between two s. /// /// The first point. /// The second point. /// True if the points are equal; otherwise false. public static bool operator ==(Point left, Point right) { return left.Equals(right); } /// /// Checks for inequality between two s. /// /// The first point. /// The second point. /// True if the points are unequal; otherwise false. public static bool operator !=(Point left, Point right) { return !(left == right); } /// /// Adds two points. /// /// The first point. /// The second point. /// A point that is the result of the addition. public static Point operator +(Point a, Point b) { return new Point(a._x + b._x, a._y + b._y); } /// /// Adds a vector to a point. /// /// The point. /// The vector. /// A point that is the result of the addition. public static Point operator +(Point a, Vector b) { return new Point(a._x + b.X, a._y + b.Y); } /// /// Subtracts two points. /// /// The first point. /// The second point. /// A point that is the result of the subtraction. public static Point operator -(Point a, Point b) { return new Point(a._x - b._x, a._y - b._y); } /// /// Subtracts a vector from a point. /// /// The point. /// The vector. /// A point that is the result of the subtraction. public static Point operator -(Point a, Vector b) { return new Point(a._x - b.X, a._y - b.Y); } /// /// Multiplies a point by a factor coordinate-wise /// /// Point to multiply /// Factor /// Points having its coordinates multiplied public static Point operator *(Point p, double k) => new Point(p.X * k, p.Y * k); /// /// Multiplies a point by a factor coordinate-wise /// /// Point to multiply /// Factor /// Points having its coordinates multiplied public static Point operator *(double k, Point p) => new Point(p.X * k, p.Y * k); /// /// Divides a point by a factor coordinate-wise /// /// Point to divide by /// Factor /// Points having its coordinates divided public static Point operator /(Point p, double k) => new Point(p.X / k, p.Y / k); /// /// Applies a matrix to a point. /// /// The point. /// The matrix. /// The resulting point. public static Point operator *(Point point, Matrix matrix) => matrix.Transform(point); /// /// Parses a string. /// /// The string. /// The . public static Point Parse(string s) { using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point.")) { return new Point( tokenizer.ReadDouble(), tokenizer.ReadDouble() ); } } /// /// Returns a boolean indicating whether the point is equal to the other given point (bitwise). /// /// The other point to test equality against. /// True if this point is equal to other; False otherwise. public bool Equals(Point other) { // ReSharper disable CompareOfFloatsByEqualityOperator return _x == other._x && _y == other._y; // ReSharper enable CompareOfFloatsByEqualityOperator } /// /// Returns a boolean indicating whether the point is equal to the other given point /// (numerically). /// /// The other point to test equality against. /// True if this point is equal to other; False otherwise. public bool NearlyEquals(Point other) { return MathUtilities.AreClose(_x, other._x) && MathUtilities.AreClose(_y, other._y); } /// /// Checks for equality between a point and an object. /// /// The object. /// /// True if is a point that equals the current point. /// public override bool Equals(object? obj) => obj is Point other && Equals(other); /// /// Returns a hash code for a . /// /// The hash code. public override int GetHashCode() { unchecked { int hash = 17; hash = (hash * 23) + _x.GetHashCode(); hash = (hash * 23) + _y.GetHashCode(); return hash; } } /// /// Returns the string representation of the point. /// /// The string representation of the point. public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y); } /// /// Transforms the point by a matrix. /// /// The transform. /// The transformed point. public Point Transform(Matrix transform) => transform.Transform(this); /// /// Returns a new point with the specified X coordinate. /// /// The X coordinate. /// The new point. public Point WithX(double x) { return new Point(x, _y); } /// /// Returns a new point with the specified Y coordinate. /// /// The Y coordinate. /// The new point. public Point WithY(double y) { return new Point(_x, y); } /// /// Deconstructs the point into its X and Y coordinates. /// /// The X coordinate. /// The Y coordinate. public void Deconstruct(out double x, out double y) { x = this._x; y = this._y; } /// /// Gets a value indicating whether the X and Y coordinates are zero. /// public bool IsDefault { get { return (_x == 0) && (_y == 0); } } } }