mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-26 00:45:20 +00:00
498 lines
21 KiB
C#
498 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.Serialization;
|
|
using Microsoft.Xna.Framework;
|
|
|
|
namespace MonoGame.Extended
|
|
{
|
|
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.3; Bounding Volumes - Spheres. pg 88
|
|
|
|
/// <summary>
|
|
/// A two dimensional circle defined by a centre <see cref="Point2" /> and a radius <see cref="float" />.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// An <see cref="CircleF" /> is categorized by the set of all points in a plane that are at equal distance from
|
|
/// the
|
|
/// centre.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <seealso cref="IEquatable{T}" />
|
|
/// <seealso cref="IEquatableByRef{T}" />
|
|
[DataContract]
|
|
public struct CircleF : IEquatable<CircleF>, IEquatableByRef<CircleF>
|
|
{
|
|
/// <summary>
|
|
/// The centre position of this <see cref="CircleF" />.
|
|
/// </summary>
|
|
[DataMember] public Point2 Center;
|
|
|
|
/// <summary>
|
|
/// The distance from the <see cref="Center" /> point to any point on the boundary of this <see cref="CircleF" />.
|
|
/// </summary>
|
|
[DataMember] public float Radius;
|
|
|
|
/// <summary>
|
|
/// Gets the distance from a point to the opposite point, both on the boundary of this <see cref="CircleF" />.
|
|
/// </summary>
|
|
public float Diameter => 2 * Radius;
|
|
|
|
/// <summary>
|
|
/// Gets the distance around the boundary of this <see cref="CircleF" />.
|
|
/// </summary>
|
|
public float Circumference => 2 * MathHelper.Pi * Radius;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CircleF" /> structure from the specified centre
|
|
/// <see cref="Point2" /> and the radius <see cref="float" />.
|
|
/// </summary>
|
|
/// <param name="center">The centre point.</param>
|
|
/// <param name="radius">The radius.</param>
|
|
public CircleF(Point2 center, float radius)
|
|
{
|
|
Center = center;
|
|
Radius = radius;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the bounding <see cref="CircleF" /> from a minimum <see cref="Point2" /> and maximum
|
|
/// <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="minimum">The minimum point.</param>
|
|
/// <param name="maximum">The maximum point.</param>
|
|
/// <param name="result">The resulting circle.</param>
|
|
public static void CreateFrom(Point2 minimum, Point2 maximum, out CircleF result)
|
|
{
|
|
result.Center = new Point2((maximum.X + minimum.X) * 0.5f, (maximum.Y + minimum.Y) * 0.5f);
|
|
var distanceVector = maximum - minimum;
|
|
result.Radius = distanceVector.X > distanceVector.Y ? distanceVector.X * 0.5f : distanceVector.Y * 0.5f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the bounding <see cref="CircleF" /> from a minimum <see cref="Point2" /> and maximum
|
|
/// <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="minimum">The minimum point.</param>
|
|
/// <param name="maximum">The maximum point.</param>
|
|
/// <returns>An <see cref="CircleF" />.</returns>
|
|
public static CircleF CreateFrom(Point2 minimum, Point2 maximum)
|
|
{
|
|
CircleF result;
|
|
CreateFrom(minimum, maximum, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the bounding <see cref="CircleF" /> from a list of <see cref="Point2" /> structures.
|
|
/// </summary>
|
|
/// <param name="points">The points.</param>
|
|
/// <param name="result">The resulting circle.</param>
|
|
public static void CreateFrom(IReadOnlyList<Point2> points, out CircleF result)
|
|
{
|
|
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.3; Bounding Volumes - Spheres. pg 89-90
|
|
|
|
if (points == null || points.Count == 0)
|
|
{
|
|
result = default(CircleF);
|
|
return;
|
|
}
|
|
|
|
var minimum = new Point2(float.MaxValue, float.MaxValue);
|
|
var maximum = new Point2(float.MinValue, float.MinValue);
|
|
|
|
// ReSharper disable once ForCanBeConvertedToForeach
|
|
for (var index = points.Count - 1; index >= 0; --index)
|
|
{
|
|
var point = points[index];
|
|
minimum = Point2.Minimum(minimum, point);
|
|
maximum = Point2.Maximum(maximum, point);
|
|
}
|
|
|
|
CreateFrom(minimum, maximum, out result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the bounding <see cref="CircleF" /> from a list of <see cref="Point2" /> structures.
|
|
/// </summary>
|
|
/// <param name="points">The points.</param>
|
|
/// <returns>An <see cref="CircleF" />.</returns>
|
|
public static CircleF CreateFrom(IReadOnlyList<Point2> points)
|
|
{
|
|
CircleF result;
|
|
CreateFrom(points, out result);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the two specified <see cref="CircleF" /> structures intersect.
|
|
/// </summary>
|
|
/// <param name="first">The first circle.</param>
|
|
/// <param name="second">The second circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="first" /> intersects with the <see cref="second" />; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public static bool Intersects(ref CircleF first, ref CircleF second)
|
|
{
|
|
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.3; Bounding Volumes - Spheres. pg 88
|
|
|
|
// Calculate squared distance between centers
|
|
var distanceVector = first.Center - second.Center;
|
|
var distanceSquared = distanceVector.Dot(distanceVector);
|
|
var radiusSum = first.Radius + second.Radius;
|
|
return distanceSquared <= radiusSum * radiusSum;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the two specified <see cref="CircleF" /> structures intersect.
|
|
/// </summary>
|
|
/// <param name="first">The first circle.</param>
|
|
/// <param name="second">The second circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="first" /> intersects with the <see cref="second" />; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public static bool Intersects(CircleF first, CircleF second)
|
|
{
|
|
return Intersects(ref first, ref second);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> intersects with this <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> intersects with this <see cref="CircleF" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public bool Intersects(ref CircleF circle)
|
|
{
|
|
return Intersects(ref this, ref circle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> intersects with this <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> intersects with this <see cref="CircleF" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public bool Intersects(CircleF circle)
|
|
{
|
|
return Intersects(ref this, ref circle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> and <see cref="BoundingRectangle" /> structures intersect.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> intersects with the <see cref="rectangle" />; otherwise, <c>false</c>
|
|
/// .
|
|
/// </returns>
|
|
public static bool Intersects(ref CircleF circle, ref BoundingRectangle rectangle)
|
|
{
|
|
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.25; Basic Primitives Test - Testing Sphere Against AABB. pg 165-166
|
|
|
|
// Compute squared distance between sphere center and AABB boundary
|
|
var distanceSquared = rectangle.SquaredDistanceTo(circle.Center);
|
|
// Circle and AABB intersect if the (squared) distance between the AABB's boundary and the circle is less than the (squared) circle's radius
|
|
return distanceSquared <= circle.Radius * circle.Radius;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> and <see cref="BoundingRectangle" /> structures intersect.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> intersects with the <see cref="rectangle" />; otherwise, <c>false</c>
|
|
/// .
|
|
/// </returns>
|
|
public static bool Intersects(CircleF circle, BoundingRectangle rectangle)
|
|
{
|
|
return Intersects(ref circle, ref rectangle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> intersects with this <see cref="BoundingRectangle" />.
|
|
/// </summary>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="rectangle" /> intersects with this <see cref="CircleF" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public bool Intersects(ref BoundingRectangle rectangle)
|
|
{
|
|
return Intersects(ref this, ref rectangle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> intersects with this <see cref="BoundingRectangle" />.
|
|
/// </summary>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="rectangle" /> intersects with this <see cref="CircleF" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public bool Intersects(BoundingRectangle rectangle)
|
|
{
|
|
return Intersects(ref this, ref rectangle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> contains the specified
|
|
/// <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <param name="point">The point.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> contains the <paramref name="point" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public static bool Contains(ref CircleF circle, Point2 point)
|
|
{
|
|
var distance = circle.Center - point;
|
|
return Math.Abs(distance.X) <= circle.Radius && Math.Abs(distance.Y) <= circle.Radius;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether the specified <see cref="CircleF" /> contains the specified
|
|
/// <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <param name="point">The point.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <paramref name="circle" /> contains the <paramref name="point" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public static bool Contains(CircleF circle, Point2 point)
|
|
{
|
|
return Contains(ref circle, point);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether this <see cref="CircleF" /> contains the specified <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="point">The point.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if this <see cref="BoundingRectangle" /> contains the <paramref name="point" />; otherwise,
|
|
/// <c>false</c>.
|
|
/// </returns>
|
|
public bool Contains(Point2 point)
|
|
{
|
|
return Contains(ref this, point);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the closest <see cref="Point2" /> on this <see cref="CircleF" /> to a specified
|
|
/// <see cref="Point2" />.
|
|
/// </summary>
|
|
/// <param name="point">The point.</param>
|
|
/// <returns>The closest <see cref="Point2" /> on this <see cref="CircleF" /> to the <paramref name="point" />.</returns>
|
|
public Point2 ClosestPointTo(Point2 point)
|
|
{
|
|
var distanceVector = point - Center;
|
|
var lengthSquared = distanceVector.Dot(distanceVector);
|
|
if (lengthSquared <= Radius * Radius)
|
|
return point;
|
|
distanceVector.Normalize();
|
|
return Center + Radius * distanceVector;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the <see cref="Point2" /> on the boundary of of this <see cref="CircleF" /> using the specified angle.
|
|
/// </summary>
|
|
/// <param name="angle">The angle in radians.</param>
|
|
/// <returns>The <see cref="Point2" /> on the boundary of this <see cref="CircleF" /> using <paramref name="angle" />.</returns>
|
|
public Point2 BoundaryPointAt(float angle)
|
|
{
|
|
var direction = new Vector2((float) Math.Cos(angle), (float) Math.Sin(angle));
|
|
return Center + Radius * direction;
|
|
}
|
|
|
|
[Obsolete("Circle.GetPointAlongEdge() may be removed in the future. Use BoundaryPointAt() instead.")]
|
|
public Point2 GetPointAlongEdge(float angle)
|
|
{
|
|
return Center + new Vector2(Radius * (float) Math.Cos(angle), Radius * (float) Math.Sin(angle));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two <see cref="CircleF" /> structures. The result specifies whether the values of the
|
|
/// <see cref="Center" /> and <see cref="Radius" /> fields of the two <see cref="CircleF" /> structures
|
|
/// are equal.
|
|
/// </summary>
|
|
/// <param name="first">The first circle.</param>
|
|
/// <param name="second">The second circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <see cref="Center" /> and <see cref="Radius" /> fields of the two
|
|
/// <see cref="BoundingRectangle" /> structures are equal; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public static bool operator ==(CircleF first, CircleF second)
|
|
{
|
|
return first.Equals(ref second);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares two <see cref="CircleF" /> structures. The result specifies whether the values of the
|
|
/// <see cref="Center" /> and <see cref="Radius" /> fields of the two <see cref="CircleF" /> structures
|
|
/// are unequal.
|
|
/// </summary>
|
|
/// <param name="first">The first circle.</param>
|
|
/// <param name="second">The second circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if the <see cref="Center" /> and <see cref="Radius" /> fields of the two
|
|
/// <see cref="CircleF" /> structures are unequal; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public static bool operator !=(CircleF first, CircleF second)
|
|
{
|
|
return !(first == second);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indicates whether this <see cref="CircleF" /> is equal to another <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if this <see cref="CircleF" /> is equal to the <paramref name="circle" />; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public bool Equals(CircleF circle)
|
|
{
|
|
return Equals(ref circle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indicates whether this <see cref="CircleF" /> is equal to another <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="circle">The bounding rectangle.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if this <see cref="CircleF" /> is equal to the <paramref name="circle" />;
|
|
/// otherwise,<c>false</c>.
|
|
/// </returns>
|
|
public bool Equals(ref CircleF circle)
|
|
{
|
|
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|
return circle.Center == Center && circle.Radius == Radius;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a value indicating whether this <see cref="CircleF" /> is equal to a specified object.
|
|
/// </summary>
|
|
/// <param name="obj">The object to make the comparison with.</param>
|
|
/// <returns>
|
|
/// <c>true</c> if this <see cref="CircleF" /> is equal to <paramref name="obj" />; otherwise, <c>false</c>.
|
|
/// </returns>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is CircleF && Equals((CircleF) obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a hash code of this <see cref="CircleF" /> suitable for use in hashing algorithms and data
|
|
/// structures like a hash table.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A hash code of this <see cref="CircleF" />.
|
|
/// </returns>
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
return (Center.GetHashCode() * 397) ^ Radius.GetHashCode();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from a <see cref="CircleF" /> to a <see cref="Rectangle" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <returns>
|
|
/// The resulting <see cref="Rectangle" />.
|
|
/// </returns>
|
|
public static implicit operator Rectangle(CircleF circle)
|
|
{
|
|
var diameter = (int) circle.Diameter;
|
|
return new Rectangle((int) (circle.Center.X - circle.Radius), (int) (circle.Center.Y - circle.Radius),
|
|
diameter, diameter);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a conversion from a specified <see cref="CircleF" /> to a <see cref="Rectangle" />.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// The resulting <see cref="Rectangle" />.
|
|
/// </returns>
|
|
public Rectangle ToRectangle()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from a <see cref="Rectangle" /> to a <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// The resulting <see cref="CircleF" />.
|
|
/// </returns>
|
|
public static implicit operator CircleF(Rectangle rectangle)
|
|
{
|
|
var halfWidth = rectangle.Width / 2;
|
|
var halfHeight = rectangle.Height / 2;
|
|
return new CircleF(new Point2(rectangle.X + halfWidth, rectangle.Y + halfHeight),
|
|
halfWidth > halfHeight ? halfWidth : halfHeight);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from a <see cref="CircleF" /> to a <see cref="RectangleF" />.
|
|
/// </summary>
|
|
/// <param name="circle">The circle.</param>
|
|
/// <returns>
|
|
/// The resulting <see cref="RectangleF" />.
|
|
/// </returns>
|
|
public static implicit operator RectangleF(CircleF circle)
|
|
{
|
|
var diameter = circle.Diameter;
|
|
return new RectangleF(circle.Center.X - circle.Radius, circle.Center.Y - circle.Radius, diameter, diameter);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a conversion from a specified <see cref="CircleF" /> to a <see cref="RectangleF" />.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// The resulting <see cref="RectangleF" />.
|
|
/// </returns>
|
|
public RectangleF ToRectangleF()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs an implicit conversion from a <see cref="RectangleF" /> to a <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <param name="rectangle">The rectangle.</param>
|
|
/// <returns>
|
|
/// The resulting <see cref="CircleF" />.
|
|
/// </returns>
|
|
public static implicit operator CircleF(RectangleF rectangle)
|
|
{
|
|
var halfWidth = rectangle.Width * 0.5f;
|
|
var halfHeight = rectangle.Height * 0.5f;
|
|
return new CircleF(new Point2(rectangle.X + halfWidth, rectangle.Y + halfHeight),
|
|
halfWidth > halfHeight ? halfWidth : halfHeight);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string" /> that represents this <see cref="CircleF" />.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A <see cref="string" /> that represents this <see cref="CircleF" />.
|
|
/// </returns>
|
|
public override string ToString()
|
|
{
|
|
return $"Centre: {Center}, Radius: {Radius}";
|
|
}
|
|
|
|
internal string DebugDisplayString => ToString();
|
|
}
|
|
}
|