csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
10 KiB
309 lines
10 KiB
using System;
|
|
using System.Globalization;
|
|
#if !BUILDTASK
|
|
using Avalonia.Animation.Animators;
|
|
#endif
|
|
using Avalonia.Utilities;
|
|
|
|
namespace Avalonia
|
|
{
|
|
/// <summary>
|
|
/// Defines a point.
|
|
/// </summary>
|
|
#if !BUILDTASK
|
|
public
|
|
#endif
|
|
readonly struct Point : IEquatable<Point>
|
|
{
|
|
static Point()
|
|
{
|
|
#if !BUILDTASK
|
|
Animation.Animation.RegisterAnimator<PointAnimator>(prop => typeof(Point).IsAssignableFrom(prop.PropertyType));
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// The X position.
|
|
/// </summary>
|
|
private readonly double _x;
|
|
|
|
/// <summary>
|
|
/// The Y position.
|
|
/// </summary>
|
|
private readonly double _y;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Point"/> structure.
|
|
/// </summary>
|
|
/// <param name="x">The X position.</param>
|
|
/// <param name="y">The Y position.</param>
|
|
public Point(double x, double y)
|
|
{
|
|
_x = x;
|
|
_y = y;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the X position.
|
|
/// </summary>
|
|
public double X => _x;
|
|
|
|
/// <summary>
|
|
/// Gets the Y position.
|
|
/// </summary>
|
|
public double Y => _y;
|
|
|
|
/// <summary>
|
|
/// Converts the <see cref="Point"/> to a <see cref="Vector"/>.
|
|
/// </summary>
|
|
/// <param name="p">The point.</param>
|
|
public static implicit operator Vector(Point p)
|
|
{
|
|
return new Vector(p._x, p._y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Negates a point.
|
|
/// </summary>
|
|
/// <param name="a">The point.</param>
|
|
/// <returns>The negated point.</returns>
|
|
public static Point operator -(Point a)
|
|
{
|
|
return new Point(-a._x, -a._y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for equality between two <see cref="Point"/>s.
|
|
/// </summary>
|
|
/// <param name="left">The first point.</param>
|
|
/// <param name="right">The second point.</param>
|
|
/// <returns>True if the points are equal; otherwise false.</returns>
|
|
public static bool operator ==(Point left, Point right)
|
|
{
|
|
return left.Equals(right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for inequality between two <see cref="Point"/>s.
|
|
/// </summary>
|
|
/// <param name="left">The first point.</param>
|
|
/// <param name="right">The second point.</param>
|
|
/// <returns>True if the points are unequal; otherwise false.</returns>
|
|
public static bool operator !=(Point left, Point right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds two points.
|
|
/// </summary>
|
|
/// <param name="a">The first point.</param>
|
|
/// <param name="b">The second point.</param>
|
|
/// <returns>A point that is the result of the addition.</returns>
|
|
public static Point operator +(Point a, Point b)
|
|
{
|
|
return new Point(a._x + b._x, a._y + b._y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a vector to a point.
|
|
/// </summary>
|
|
/// <param name="a">The point.</param>
|
|
/// <param name="b">The vector.</param>
|
|
/// <returns>A point that is the result of the addition.</returns>
|
|
public static Point operator +(Point a, Vector b)
|
|
{
|
|
return new Point(a._x + b.X, a._y + b.Y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subtracts two points.
|
|
/// </summary>
|
|
/// <param name="a">The first point.</param>
|
|
/// <param name="b">The second point.</param>
|
|
/// <returns>A point that is the result of the subtraction.</returns>
|
|
public static Point operator -(Point a, Point b)
|
|
{
|
|
return new Point(a._x - b._x, a._y - b._y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subtracts a vector from a point.
|
|
/// </summary>
|
|
/// <param name="a">The point.</param>
|
|
/// <param name="b">The vector.</param>
|
|
/// <returns>A point that is the result of the subtraction.</returns>
|
|
public static Point operator -(Point a, Vector b)
|
|
{
|
|
return new Point(a._x - b.X, a._y - b.Y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiplies a point by a factor coordinate-wise
|
|
/// </summary>
|
|
/// <param name="p">Point to multiply</param>
|
|
/// <param name="k">Factor</param>
|
|
/// <returns>Points having its coordinates multiplied</returns>
|
|
public static Point operator *(Point p, double k) => new Point(p.X * k, p.Y * k);
|
|
|
|
/// <summary>
|
|
/// Multiplies a point by a factor coordinate-wise
|
|
/// </summary>
|
|
/// <param name="p">Point to multiply</param>
|
|
/// <param name="k">Factor</param>
|
|
/// <returns>Points having its coordinates multiplied</returns>
|
|
public static Point operator *(double k, Point p) => new Point(p.X * k, p.Y * k);
|
|
|
|
/// <summary>
|
|
/// Divides a point by a factor coordinate-wise
|
|
/// </summary>
|
|
/// <param name="p">Point to divide by</param>
|
|
/// <param name="k">Factor</param>
|
|
/// <returns>Points having its coordinates divided</returns>
|
|
public static Point operator /(Point p, double k) => new Point(p.X / k, p.Y / k);
|
|
|
|
/// <summary>
|
|
/// Applies a matrix to a point.
|
|
/// </summary>
|
|
/// <param name="point">The point.</param>
|
|
/// <param name="matrix">The matrix.</param>
|
|
/// <returns>The resulting point.</returns>
|
|
public static Point operator *(Point point, Matrix matrix)
|
|
{
|
|
return new Point(
|
|
(point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.M31,
|
|
(point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.M32);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses a <see cref="Point"/> string.
|
|
/// </summary>
|
|
/// <param name="s">The string.</param>
|
|
/// <returns>The <see cref="Point"/>.</returns>
|
|
public static Point Parse(string s)
|
|
{
|
|
using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point."))
|
|
{
|
|
return new Point(
|
|
tokenizer.ReadDouble(),
|
|
tokenizer.ReadDouble()
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a boolean indicating whether the point is equal to the other given point (bitwise).
|
|
/// </summary>
|
|
/// <param name="other">The other point to test equality against.</param>
|
|
/// <returns>True if this point is equal to other; False otherwise.</returns>
|
|
public bool Equals(Point other)
|
|
{
|
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
|
return _x == other._x &&
|
|
_y == other._y;
|
|
// ReSharper enable CompareOfFloatsByEqualityOperator
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a boolean indicating whether the point is equal to the other given point
|
|
/// (numerically).
|
|
/// </summary>
|
|
/// <param name="other">The other point to test equality against.</param>
|
|
/// <returns>True if this point is equal to other; False otherwise.</returns>
|
|
public bool NearlyEquals(Point other)
|
|
{
|
|
return MathUtilities.AreClose(_x, other._x) &&
|
|
MathUtilities.AreClose(_y, other._y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks for equality between a point and an object.
|
|
/// </summary>
|
|
/// <param name="obj">The object.</param>
|
|
/// <returns>
|
|
/// True if <paramref name="obj"/> is a point that equals the current point.
|
|
/// </returns>
|
|
public override bool Equals(object? obj) => obj is Point other && Equals(other);
|
|
|
|
/// <summary>
|
|
/// Returns a hash code for a <see cref="Point"/>.
|
|
/// </summary>
|
|
/// <returns>The hash code.</returns>
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
int hash = 17;
|
|
hash = (hash * 23) + _x.GetHashCode();
|
|
hash = (hash * 23) + _y.GetHashCode();
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the point.
|
|
/// </summary>
|
|
/// <returns>The string representation of the point.</returns>
|
|
public override string ToString()
|
|
{
|
|
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms the point by a matrix.
|
|
/// </summary>
|
|
/// <param name="transform">The transform.</param>
|
|
/// <returns>The transformed point.</returns>
|
|
public Point Transform(Matrix transform)
|
|
{
|
|
var x = X;
|
|
var y = Y;
|
|
var xadd = y * transform.M21 + transform.M31;
|
|
var yadd = x * transform.M12 + transform.M32;
|
|
x *= transform.M11;
|
|
x += xadd;
|
|
y *= transform.M22;
|
|
y += yadd;
|
|
return new Point(x, y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a new point with the specified X coordinate.
|
|
/// </summary>
|
|
/// <param name="x">The X coordinate.</param>
|
|
/// <returns>The new point.</returns>
|
|
public Point WithX(double x)
|
|
{
|
|
return new Point(x, _y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a new point with the specified Y coordinate.
|
|
/// </summary>
|
|
/// <param name="y">The Y coordinate.</param>
|
|
/// <returns>The new point.</returns>
|
|
public Point WithY(double y)
|
|
{
|
|
return new Point(_x, y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deconstructs the point into its X and Y coordinates.
|
|
/// </summary>
|
|
/// <param name="x">The X coordinate.</param>
|
|
/// <param name="y">The Y coordinate.</param>
|
|
public void Deconstruct(out double x, out double y)
|
|
{
|
|
x = this._x;
|
|
y = this._y;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the X and Y coordinates are zero.
|
|
/// </summary>
|
|
public bool IsDefault
|
|
{
|
|
get { return (_x == 0) && (_y == 0); }
|
|
}
|
|
}
|
|
}
|
|
|