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