// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace SixLabors.PolygonClipper {
///
/// Represents a two-dimensional vertex with X and Y coordinates.
///
public readonly struct Vertex : IEquatable
{
///
/// Gets the X-coordinate of the vertex.
///
#pragma warning disable CA1051 // Do not declare visible instance fields
public readonly double X;
///
/// Gets the Y-coordinate of the vertex.
///
public readonly double Y;
#pragma warning restore CA1051 // Do not declare visible instance fields
///
/// Initializes a new instance of the struct.
///
/// The X and Y coordinates of the vertex.
public Vertex(double xy)
{
this.X = xy;
this.Y = xy;
}
///
/// Initializes a new instance of the struct.
///
/// The X-coordinate of the vertex.
/// The Y-coordinate of the vertex.
public Vertex(double x, double y)
{
this.X = x;
this.Y = y;
}
///
/// Adds two vectors together.
///
/// The first vector to add.
/// The second vector to add.
/// The summed vector.
/// The method defines the addition operation for objects.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator +(in Vertex left, in Vertex right)
=> AsVertexUnsafe(AsVector128Unsafe(left) + AsVector128Unsafe(right));
///
/// Subtracts the second vector from the first.
///
/// The first vector.
/// The second vector.
/// The vector that results from subtracting from .
/// The method defines the subtraction operation for objects.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator -(in Vertex left, in Vertex right)
=> AsVertexUnsafe(AsVector128Unsafe(left) - AsVector128Unsafe(right));
///
/// Returns a new vector whose values are the product of each pair of elements in two specified vertices.
///
/// The first vertex.
/// The second vertex.
/// The element-wise product vertex.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator *(in Vertex left, in Vertex right) => AsVertexUnsafe(AsVector128Unsafe(left) * AsVector128Unsafe(right));
///
/// Multiplies the specified vertex by the specified scalar value.
///
/// The first vertex.
/// The scalar value.
/// The scaled vertex.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator *(in Vertex left, double right) => AsVertexUnsafe(AsVector128Unsafe(left) * right);
///
/// Multiplies the specified vertex by the specified scalar value.
///
/// The first vertex.
/// The scalar value.
/// The scaled vertex.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator *(double left, in Vertex right) => right * left;
///
/// Divides the first vertex by the second.
///
/// The first vertex.
/// The second vertex.
/// The vertex that results from dividing by .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator /(in Vertex left, in Vertex right)
=> AsVertexUnsafe(AsVector128Unsafe(left) / AsVector128Unsafe(right));
///
/// Divides the specified vertex by a specified scalar value.
///
/// The first vertex.
/// The scalar value.
/// The result of the division.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator /(in Vertex left, double right)
=> AsVertexUnsafe(AsVector128Unsafe(left) / right);
///
/// Divides the specified vertex by the specified scalar value.
///
/// The first vertex.
/// The scalar value.
/// The result of the division.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex operator /(double left, in Vertex right) => right / left;
///
/// Determines whether two vertices are equal.
///
/// The first vertex.
/// The second vertex.
/// if the vertices are equal; otherwise, .
public static bool operator ==(in Vertex left, in Vertex right) => left.Equals(right);
///
/// Determines whether two vertices are not equal.
///
/// The first vertex.
/// The second vertex.
/// if the vertices are not equal; otherwise, .
public static bool operator !=(in Vertex left, in Vertex right) => !left.Equals(right);
///
/// Returns the dot product of two vertices.
///
/// The first vertex.
/// The second vertex.
/// The dot product.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(in Vertex a, in Vertex b)
{
Vector128 a128 = AsVector128Unsafe(a);
Vector128 b128 = AsVector128Unsafe(b);
return Vector128.Dot(a128, b128);
}
///
/// Returns the cross product of two vertices.
///
/// The first vertex.
/// The second vertex.
/// The cross product.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Cross(in Vertex a, in Vertex b)
=> (a.X * b.Y) - (a.Y * b.X);
/// Computes the Euclidean distance between the two given vertices.
/// The first vertex.
/// The second vertex.
/// The distance.
public static double Distance(in Vertex a, in Vertex b)
=> double.Sqrt(DistanceSquared(a, b));
/// Returns the Euclidean distance squared between two specified vertices.
/// The first vertex.
/// The second vertex.
/// The distance squared.
public static double DistanceSquared(in Vertex a, in Vertex b)
=> (a - b).LengthSquared();
///
/// Returns the length of the vertex.
///
/// The vertex's length.
///
public double Length()
=> double.Sqrt(this.LengthSquared());
/// Returns the length of the vertex squared.
/// The vertex's length squared.
/// This operation offers better performance than a call to the method.
///
public double LengthSquared()
=> Dot(this, this);
///
/// Returns a vertex whose elements are the minimum of each of the pairs of elements in two specified vertices.
///
/// The first vertex.
/// The second vertex.
/// The minimized .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex Min(in Vertex a, in Vertex b)
=> AsVertexUnsafe(Vector128.Min(AsVector128Unsafe(a), AsVector128Unsafe(b)));
///
/// Returns a vertex whose elements are the maximum of each of the pairs of elements in two specified vertices.
///
/// The first vertex.
/// The second vertex.
/// The maximized .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex Max(in Vertex a, in Vertex b)
=> AsVertexUnsafe(Vector128.Max(AsVector128Unsafe(a), AsVector128Unsafe(b)));
///
/// Computes the absolute value of each element in a specified vertex.
///
/// The vertex that will have its absolute value computed.
///
/// A vertex with the absolute value of each of the elements in .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vertex Abs(in Vertex value)
=> AsVertexUnsafe(Vector128.Abs(AsVector128Unsafe(value)));
///
public bool Equals(Vertex other)
=> this.X == other.X && this.Y == other.Y;
///
public override bool Equals(object? obj) =>
obj is Vertex vertex && this.Equals(vertex);
///
public override int GetHashCode() => HashCode.Combine(this.X, this.Y);
///
public override string ToString() => $"Vertex [ X={this.X}, Y={this.Y} ]";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128 AsVector128Unsafe(in Vertex value)
=> Unsafe.BitCast>(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vertex AsVertexUnsafe(Vector128 value)
=> Unsafe.BitCast, Vertex>(value);
}
}