using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 77
///
/// An axis-aligned, four sided, two dimensional box defined by a centre and a radii
/// .
///
///
///
/// An is categorized by having its faces oriented in such a way that its
/// face normals are at all times parallel with the axes of the given coordinate system.
///
///
/// The of a rotated will be equivalent or larger
/// in size
/// than the original depending on the angle of rotation.
///
///
///
///
[DebuggerDisplay("{" + nameof(DebugDisplayString) + ",nq}")]
public struct BoundingRectangle : IEquatable,
IEquatableByRef
{
///
/// The with and
/// set to .
///
public static readonly BoundingRectangle Empty = new BoundingRectangle();
///
/// The centre position of this .
///
public Vector2 Center;
///
/// The distance from the point along both axes to any point on the boundary of this
/// .
///
public Vector2 HalfExtents;
///
/// Initializes a new instance of the structure from the specified centre
/// and the radii .
///
/// The centre .
/// The radii .
public BoundingRectangle(Vector2 center, SizeF halfExtents)
{
Center = center;
HalfExtents = halfExtents;
}
///
/// Computes the from a minimum and maximum
/// .
///
/// The minimum point.
/// The maximum point.
/// The resulting bounding rectangle.
public static void CreateFrom(Vector2 minimum, Vector2 maximum, out BoundingRectangle result)
{
result.Center = new Vector2((maximum.X + minimum.X) * 0.5f, (maximum.Y + minimum.Y) * 0.5f);
result.HalfExtents = new Vector2((maximum.X - minimum.X) * 0.5f, (maximum.Y - minimum.Y) * 0.5f);
}
///
/// Computes the from a minimum and maximum
/// .
///
/// The minimum point.
/// The maximum point.
/// The resulting .
public static BoundingRectangle CreateFrom(Vector2 minimum, Vector2 maximum)
{
BoundingRectangle result;
CreateFrom(minimum, maximum, out result);
return result;
}
///
/// Computes the from a list of structures.
///
/// The points.
/// The resulting bounding rectangle.
public static void CreateFrom(IReadOnlyList points, out BoundingRectangle result)
{
Vector2 minimum;
Vector2 maximum;
PrimitivesHelper.CreateRectangleFromPoints(points, out minimum, out maximum);
CreateFrom(minimum, maximum, out result);
}
///
/// Computes the from a list of structures.
///
/// The points.
/// The resulting .
public static BoundingRectangle CreateFrom(IReadOnlyList points)
{
BoundingRectangle result;
CreateFrom(points, out result);
return result;
}
///
/// Computes the from the specified transformed by
/// the
/// specified .
///
/// The bounding rectangle.
/// The transform matrix.
/// The resulting bounding rectangle.
///
/// The from the transformed by the
/// .
///
///
///
/// If a transformed is used for then the
/// resulting will have the compounded transformation, which most likely is
/// not desired.
///
///
public static void Transform(ref BoundingRectangle boundingRectangle,
ref Matrix3x2 transformMatrix, out BoundingRectangle result)
{
PrimitivesHelper.TransformRectangle(ref boundingRectangle.Center, ref boundingRectangle.HalfExtents, ref transformMatrix);
result.Center = boundingRectangle.Center;
result.HalfExtents = boundingRectangle.HalfExtents;
}
///
/// Computes the from the specified transformed by
/// the
/// specified .
///
/// The bounding rectangle.
/// The transform matrix.
///
/// The from the transformed by the
/// .
///
///
///
/// If a transformed is used for then the
/// resulting will have the compounded transformation, which most likely is
/// not desired.
///
///
public static BoundingRectangle Transform(BoundingRectangle boundingRectangle,
ref Matrix3x2 transformMatrix)
{
BoundingRectangle result;
Transform(ref boundingRectangle, ref transformMatrix, out result);
return result;
}
///
/// Computes the that contains the two specified
/// structures.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
/// The resulting bounding rectangle that contains both the and the
/// .
public static void Union(ref BoundingRectangle first, ref BoundingRectangle second, out BoundingRectangle result)
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 6.5; Bounding Volume Hierarchies - Merging Bounding Volumes. pg 267
var firstMinimum = first.Center - first.HalfExtents;
var firstMaximum = first.Center + first.HalfExtents;
var secondMinimum = second.Center - second.HalfExtents;
var secondMaximum = second.Center + second.HalfExtents;
var minimum = MathExtended.CalculateMinimumVector2(firstMinimum, secondMinimum);
var maximum = MathExtended.CalculateMaximumVector2(firstMaximum, secondMaximum);
result = CreateFrom(minimum, maximum);
}
///
/// Computes the that contains the two specified
/// structures.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// A that contains both the and the
/// .
///
public static BoundingRectangle Union(BoundingRectangle first, BoundingRectangle second)
{
BoundingRectangle result;
Union(ref first, ref second, out result);
return result;
}
///
/// Computes the that contains both the specified
/// and this .
///
/// The bounding rectangle.
///
/// A that contains both the and
/// this
/// .
///
public BoundingRectangle Union(BoundingRectangle boundingRectangle)
{
return Union(this, boundingRectangle);
}
///
/// Computes the that is in common between the two specified
/// structures.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
/// The resulting bounding rectangle that is in common between both the and
/// the , if they intersect; otherwise, .
public static void Intersection(ref BoundingRectangle first,
ref BoundingRectangle second, out BoundingRectangle result)
{
var firstMinimum = first.Center - first.HalfExtents;
var firstMaximum = first.Center + first.HalfExtents;
var secondMinimum = second.Center - second.HalfExtents;
var secondMaximum = second.Center + second.HalfExtents;
var minimum = MathExtended.CalculateMaximumVector2(firstMinimum, secondMinimum);
var maximum = MathExtended.CalculateMinimumVector2(firstMaximum, secondMaximum);
if ((maximum.X < minimum.X) || (maximum.Y < minimum.Y))
result = new BoundingRectangle();
else
result = CreateFrom(minimum, maximum);
}
///
/// Computes the that is in common between the two specified
/// structures.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// A that is in common between both the and
/// the , if they intersect; otherwise, .
///
public static BoundingRectangle Intersection(BoundingRectangle first,
BoundingRectangle second)
{
BoundingRectangle result;
Intersection(ref first, ref second, out result);
return result;
}
///
/// Computes the that is in common between the specified
/// and this .
///
/// The bounding rectangle.
///
/// A that is in common between both the and
/// this , if they intersect; otherwise, .
///
public BoundingRectangle Intersection(BoundingRectangle boundingRectangle)
{
BoundingRectangle result;
Intersection(ref this, ref boundingRectangle, out result);
return result;
}
///
/// Determines whether the two specified structures intersect.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// true if the intersects with the ; otherwise, false.
///
public static bool Intersects(ref BoundingRectangle first, ref BoundingRectangle second)
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 80
var distance = first.Center - second.Center;
var radii = first.HalfExtents + second.HalfExtents;
return Math.Abs(distance.X) <= radii.X && Math.Abs(distance.Y) <= radii.Y;
}
///
/// Determines whether the two specified structures intersect.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// true if the intersects with the ; otherwise, false.
///
public static bool Intersects(BoundingRectangle first, BoundingRectangle second)
{
return Intersects(ref first, ref second);
}
///
/// Determines whether the specified intersects with this
/// .
///
/// The bounding rectangle.
///
/// true if the intersects with this
/// ; otherwise,
/// false.
///
public bool Intersects(ref BoundingRectangle boundingRectangle)
{
return Intersects(ref this, ref boundingRectangle);
}
///
/// Determines whether the specified intersects with this
/// .
///
/// The bounding rectangle.
///
/// true if the intersects with this
/// ; otherwise,
/// false.
///
public bool Intersects(BoundingRectangle boundingRectangle)
{
return Intersects(ref this, ref boundingRectangle);
}
///
/// Updates this from a list of structures.
///
/// The points.
public void UpdateFromPoints(IReadOnlyList points)
{
var boundingRectangle = CreateFrom(points);
Center = boundingRectangle.Center;
HalfExtents = boundingRectangle.HalfExtents;
}
///
/// Determines whether the specified contains the specified
/// .
///
/// The bounding rectangle.
/// The point.
///
/// true if the contains the ; otherwise,
/// false.
///
public static bool Contains(ref BoundingRectangle boundingRectangle, ref Vector2 point)
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 78
var distance = boundingRectangle.Center - point;
var radii = boundingRectangle.HalfExtents;
return (Math.Abs(distance.X) <= radii.X) && (Math.Abs(distance.Y) <= radii.Y);
}
///
/// Determines whether the specified contains the specified
/// .
///
/// The bounding rectangle.
/// The point.
///
/// true if the contains the ; otherwise,
/// false.
///
public static bool Contains(BoundingRectangle boundingRectangle, Vector2 point)
{
return Contains(ref boundingRectangle, ref point);
}
///
/// Determines whether this contains the specified .
///
/// The point.
///
/// true if this contains the ; otherwise,
/// false.
///
public bool Contains(Vector2 point)
{
return Contains(this, point);
}
///
/// Computes the squared distance from this to a .
///
/// The point.
/// The squared distance from this to the .
public float SquaredDistanceTo(Vector2 point)
{
return PrimitivesHelper.SquaredDistanceToPointFromRectangle(Center - HalfExtents, Center + HalfExtents, point);
}
///
/// Computes the closest on this to a specified
/// .
///
/// The point.
/// The closest on this to the .
public Vector2 ClosestPointTo(Vector2 point)
{
Vector2 result;
PrimitivesHelper.ClosestPointToPointFromRectangle(Center - HalfExtents, Center + HalfExtents, point, out result);
return result;
}
///
/// Compares two structures. The result specifies whether the values of the
/// and fields of the two structures
/// are equal.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// true if the and fields of the two
/// structures are equal; otherwise, false.
///
public static bool operator ==(BoundingRectangle first, BoundingRectangle second)
{
return first.Equals(ref second);
}
///
/// Compares two structures. The result specifies whether the values of the
/// and fields of the two structures
/// are unequal.
///
/// The first bounding rectangle.
/// The second bounding rectangle.
///
/// true if the and fields of the two
/// structures are unequal; otherwise, false.
///
public static bool operator !=(BoundingRectangle first, BoundingRectangle second)
{
return !(first == second);
}
///
/// Indicates whether this is equal to another
/// .
///
/// The bounding rectangle.
///
/// true if this is equal to the ;
/// otherwise, false.
///
public bool Equals(BoundingRectangle boundingRectangle)
{
return Equals(ref boundingRectangle);
}
///
/// Indicates whether this is equal to another .
///
/// The bounding rectangle.
///
/// true if this is equal to the ;
/// otherwise,
/// false.
///
public bool Equals(ref BoundingRectangle boundingRectangle)
{
return (boundingRectangle.Center == Center) && (boundingRectangle.HalfExtents == HalfExtents);
}
///
/// Returns a value indicating whether this is equal to a specified object.
///
/// The object to make the comparison with.
///
/// true if this is equal to ; otherwise, false.
///
public override bool Equals(object obj)
{
if (obj is BoundingRectangle)
return Equals((BoundingRectangle)obj);
return false;
}
///
/// Returns a hash code of this suitable for use in hashing algorithms and data
/// structures like a hash table.
///
///
/// A hash code of this .
///
public override int GetHashCode()
{
unchecked
{
return (Center.GetHashCode() * 397) ^ HalfExtents.GetHashCode();
}
}
///
/// Performs an implicit conversion from a to a .
///
/// The rectangle.
///
/// The resulting .
///
public static implicit operator BoundingRectangle(Rectangle rectangle)
{
var radii = new SizeF(rectangle.Width * 0.5f, rectangle.Height * 0.5f);
var centre = new Vector2(rectangle.X + radii.Width, rectangle.Y + radii.Height);
return new BoundingRectangle(centre, radii);
}
///
/// Performs an implicit conversion from a to a .
///
/// The bounding rectangle.
///
/// The resulting .
///
public static implicit operator Rectangle(BoundingRectangle boundingRectangle)
{
var minimum = boundingRectangle.Center - boundingRectangle.HalfExtents;
return new Rectangle((int)minimum.X, (int)minimum.Y, (int)boundingRectangle.HalfExtents.X * 2,
(int)boundingRectangle.HalfExtents.Y * 2);
}
///
/// Performs an implicit conversion from a to a .
///
/// The rectangle.
///
/// The resulting .
///
public static implicit operator BoundingRectangle(RectangleF rectangle)
{
var radii = new SizeF(rectangle.Width * 0.5f, rectangle.Height * 0.5f);
var centre = new Vector2(rectangle.X + radii.Width, rectangle.Y + radii.Height);
return new BoundingRectangle(centre, radii);
}
///
/// Performs an implicit conversion from a to a .
///
/// The bounding rectangle.
///
/// The resulting .
///
public static implicit operator RectangleF(BoundingRectangle boundingRectangle)
{
var minimum = boundingRectangle.Center - boundingRectangle.HalfExtents;
return new RectangleF(minimum.X, minimum.Y, boundingRectangle.HalfExtents.X * 2,
boundingRectangle.HalfExtents.Y * 2);
}
///
/// Returns a that represents this .
///
///
/// A that represents this .
///
public override string ToString()
{
return $"Centre: {Center}, Radii: {HalfExtents}";
}
internal string DebugDisplayString => ToString();
}
}