//
// 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);
}
}
}