// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.PolygonClipper {
///
/// Represents a bounding box.
///
public readonly struct Box2 : IEquatable
{
///
/// Gets the minimum xy-coordinate.
///
#pragma warning disable CA1051 // Do not declare visible instance fields
public readonly Vertex Min;
///
/// Gets the maximum xy-coordinate.
///
public readonly Vertex Max;
#pragma warning restore CA1051 // Do not declare visible instance fields
///
/// Initializes a new instance of the struct.
///
/// The xy-coordinate.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Box2(in Vertex vector)
: this(vector, vector)
{
}
///
/// Initializes a new instance of the struct.
///
/// The minimum xy-coordinate.
/// The maximum xy-coordinate.
public Box2(in Vertex min, in Vertex max)
{
this.Min = min;
this.Max = max;
}
///
/// Gets an invalid bounds instance.
///
public static Box2 Invalid { get; } = new(
new Vertex(double.MaxValue, double.MaxValue),
new Vertex(-double.MaxValue, -double.MaxValue));
///
/// Compares two instances for equality.
///
/// The left object.
/// The right object.
/// true if both boxes are equal; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(in Box2 left, in Box2 right)
=> left.Equals(right);
///
/// Determines whether two instances are not equal.
///
/// The left object.
/// The right object.
/// true if the boxes are not equal; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(in Box2 left, in Box2 right)
=> !(left == right);
///
/// Returns true if the box is empty.
///
/// if the box is empty; otherwise, .
public bool IsEmpty() => this.Max.X <= this.Min.X || this.Max.Y <= this.Min.Y;
///
/// Returns true if the point lies within the box.
///
/// The point to test.
/// if the point lies within the box; otherwise, .
public bool Contains(in Vertex point)
=> point.X > this.Min.X && point.X < this.Max.X && point.Y > this.Min.Y && point.Y < this.Max.Y;
///
/// Returns true if the box contains another box.
///
/// The other box.
/// if the box contains the other box; otherwise, .
public bool Contains(in Box2 bounds)
=> bounds.Min.X >= this.Min.X && bounds.Max.X <= this.Max.X &&
bounds.Min.Y >= this.Min.Y && bounds.Max.Y <= this.Max.Y;
///
/// Returns true if the boxes intersect.
///
/// The other box.
/// if the boxes intersect; otherwise, .
public bool Intersects(in Box2 bounds)
=> Math.Max(this.Min.X, bounds.Min.X) <= Math.Min(this.Max.X, bounds.Max.X) &&
Math.Max(this.Min.Y, bounds.Min.Y) <= Math.Min(this.Max.Y, bounds.Max.Y);
///
/// Returns the midpoint of the box.
///
/// The midpoint.
public Vertex MidPoint() => new((this.Min.X + this.Max.X) / 2D, (this.Min.Y + this.Max.Y) / 2D);
///
/// Adds another bounding box to this instance.
///
/// The other box.
/// The summed .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Box2 Add(in Box2 other)
=> new(Vertex.Min(this.Min, other.Min), Vertex.Max(this.Max, other.Max));
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
=> obj is Box2 box
&& this.Equals(box);
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Box2 other)
=> this.Min == other.Min && this.Max == other.Max;
///
public override int GetHashCode() => HashCode.Combine(this.Min, this.Max);
}
}