// // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // namespace SixLabors.Primitives { using System; using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; /// /// Represents an ordered pair of single precision floating point x- and y-coordinates that defines a point in /// a two-dimensional plane. /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// public struct PointF : IEquatable { /// /// Represents a that has X and Y values set to zero. /// public static readonly PointF Empty = default(PointF); /// /// Represents a that has X and Y values set to zero. /// public static readonly PointF Zero = new PointF(0, 0); /// /// Initializes a new instance of the struct. /// /// The horizontal position of the point. /// The vertical position of the point. public PointF(float x, float y) : this() { this.X = x; this.Y = y; } /// /// Initializes a new instance of the struct from the given . /// /// The size public PointF(SizeF size) { this.X = size.Width; this.Y = size.Height; } /// /// Gets or sets the x-coordinate of this . /// public float X { get; set; } /// /// Gets or sets the y-coordinate of this . /// public float Y { get; set; } /// /// Gets a value indicating whether this is empty. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool IsEmpty => this.Equals(Empty); /// /// Creates a with the coordinates of the specified . /// /// The vector. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator PointF(Vector2 vector) => new PointF(vector.X, vector.Y); /// /// Creates a with the coordinates of the specified . /// /// The point. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vector2(PointF point) => new Vector2(point.X, point.Y); /// /// Creates a with the coordinates of the specified by truncating each of the coordinates. /// /// The point. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Point(PointF point) => Point.Truncate(point); /// /// Negates the given point by multiplying all values by -1. /// /// The source point. /// The negated point. public static PointF operator -(PointF value) => new PointF(-value.X, -value.Y); /// /// Translates a by a given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// /// The /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF operator +(PointF point, SizeF size) => Add(point, size); /// /// Translates a by the negative of a given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF operator -(PointF point, PointF size) => Subtract(point, size); /// /// Translates a by a given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// /// The /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF operator +(PointF point, PointF size) => Add(point, size); /// /// Translates a by the negative of a given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF operator -(PointF point, SizeF size) => Subtract(point, size); /// /// Compares two objects for equality. /// /// /// The on the left side of the operand. /// /// /// The on the right side of the operand. /// /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(PointF left, PointF right) => left.Equals(right); /// /// Compares two objects for inequality. /// /// /// The on the left side of the operand. /// /// /// The on the right side of the operand. /// /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(PointF left, PointF right) => !left.Equals(right); /// /// Translates a by the given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height); /// /// Translates a by the given . /// /// The point on the left hand of the operand. /// The point on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Add(PointF point, PointF pointb) => new PointF(point.X + pointb.X, point.Y + pointb.Y); /// /// Translates a by the negative of a given . /// /// The point on the left hand of the operand. /// The size on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height); /// /// Translates a by the negative of a given . /// /// The point on the left hand of the operand. /// The point on the right hand of the operand. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Subtract(PointF point, PointF pointb) => new PointF(point.X - pointb.X, point.Y - pointb.Y); /// /// Rotates a point around the given rotation matrix. /// /// The point to rotate /// Rotation matrix used /// The rotated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Rotate(PointF point, Matrix3x2 rotation) => Vector2.Transform(new Vector2(point.X, point.Y), rotation); /// /// Skews a point using the given skew matrix. /// /// The point to rotate /// Rotation matrix used /// The rotated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PointF Skew(PointF point, Matrix3x2 skew) => Vector2.Transform(new Vector2(point.X, point.Y), skew); /// /// Translates this by the specified amount. /// /// The amount to offset the x-coordinate. /// The amount to offset the y-coordinate. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Offset(float dx, float dy) { this.X += dx; this.Y += dy; } /// /// Translates this by the specified amount. /// /// The used offset this . [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Offset(PointF point) => this.Offset(point.X, point.Y); /// public override int GetHashCode() => this.GetHashCode(this); /// public override string ToString() { if (this.IsEmpty) { return "PointF [ Empty ]"; } return $"PointF [ X={this.X}, Y={this.Y} ]"; } /// public override bool Equals(object obj) => obj is PointF && this.Equals((PointF)obj); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); /// /// Returns the hash code for this instance. /// /// /// The instance of to return the hash code for. /// /// /// A 32-bit signed integer that is the hash code for this instance. /// private int GetHashCode(PointF point) => HashHelpers.Combine(point.X.GetHashCode(), point.Y.GetHashCode()); /// /// Transforms a point by the given matrix. /// /// The source point /// The transformation matrix. /// public static PointF Transform(PointF position, Matrix3x2 matrix) { return Vector2.Transform(position, matrix); } } }