mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
OrientedBoundedRectangle implements ShapeF
In that way the OrientedBoundedRectangle can take part of collision tests.
This commit is contained in:
@@ -13,7 +13,7 @@ namespace MonoGame.Extended
|
||||
/// </summary>
|
||||
/// <seealso cref="IEquatable{T}" />
|
||||
[DebuggerDisplay($"{{{nameof(DebugDisplayString)},nq}}")]
|
||||
public struct OrientedBoundingRectangle : IEquatable<OrientedBoundingRectangle>
|
||||
public struct OrientedBoundingRectangle : IEquatable<OrientedBoundingRectangle>, IShapeF
|
||||
{
|
||||
/// <summary>
|
||||
/// The centre position of this <see cref="OrientedBoundingRectangle" />.
|
||||
@@ -68,6 +68,14 @@ namespace MonoGame.Extended
|
||||
}
|
||||
}
|
||||
|
||||
public Point2 Position
|
||||
{
|
||||
get => Vector2.Transform(-Radii, Orientation) + Center;
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public RectangleF BoundingRectangle => (RectangleF)this;
|
||||
|
||||
/// <summary>
|
||||
/// Computes the <see cref="OrientedBoundingRectangle"/> from the specified <paramref name="rectangle"/>
|
||||
/// transformed by <paramref name="transformMatrix"/>.
|
||||
@@ -87,6 +95,7 @@ namespace MonoGame.Extended
|
||||
ref rectangle.Center,
|
||||
ref rectangle.Orientation,
|
||||
ref transformMatrix);
|
||||
result = new OrientedBoundingRectangle();
|
||||
result.Center = rectangle.Center;
|
||||
result.Radii = rectangle.Radii;
|
||||
result.Orientation = rectangle.Orientation;
|
||||
@@ -141,7 +150,7 @@ namespace MonoGame.Extended
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Returns a hash code for this object instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
@@ -149,6 +158,11 @@ namespace MonoGame.Extended
|
||||
return HashCode.Combine(Center, Radii, Orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an implicit conversion from a <see cref="RectangleF" /> to <see cref="OrientedBoundingRectangle" />.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">The rectangle to convert.</param>
|
||||
/// <returns>The resulting <see cref="OrientedBoundingRectangle" />.</returns>
|
||||
public static explicit operator OrientedBoundingRectangle(RectangleF rectangle)
|
||||
{
|
||||
var radii = new Size2(rectangle.Width * 0.5f, rectangle.Height * 0.5f);
|
||||
@@ -157,6 +171,25 @@ namespace MonoGame.Extended
|
||||
return new OrientedBoundingRectangle(centre, radii, Matrix2.Identity);
|
||||
}
|
||||
|
||||
public static explicit operator RectangleF(OrientedBoundingRectangle orientedBoundingRectangle)
|
||||
{
|
||||
var topLeft = orientedBoundingRectangle.Center - orientedBoundingRectangle.Radii;
|
||||
var rectangle = new RectangleF(topLeft, orientedBoundingRectangle.Radii * 2);
|
||||
return RectangleF.Transform(rectangle, ref orientedBoundingRectangle.Orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="rectangle"></param>
|
||||
/// <param name="otherRectangle"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public static bool Intersects(OrientedBoundingRectangle rectangle, OrientedBoundingRectangle otherRectangle)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this <see cref="OrientedBoundingRectangle" />.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace MonoGame.Extended
|
||||
using System;
|
||||
|
||||
namespace MonoGame.Extended
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for shapes.
|
||||
@@ -32,26 +34,46 @@
|
||||
/// <returns>True if the two shapes intersect.</returns>
|
||||
public static bool Intersects(this IShapeF shapeA, IShapeF shapeB)
|
||||
{
|
||||
var intersects = false;
|
||||
return shapeA switch
|
||||
{
|
||||
CircleF circleA => IntersectsInternal(circleA, shapeB),
|
||||
RectangleF rectangleA => IntersectsInternal(rectangleA, shapeB),
|
||||
OrientedBoundingRectangle orientedBoundingRectangleA => IntersectsInternal(orientedBoundingRectangleA, shapeB),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shapeA))
|
||||
};
|
||||
}
|
||||
|
||||
if (shapeA is RectangleF rectangleA && shapeB is RectangleF rectangleB)
|
||||
{
|
||||
intersects = rectangleA.Intersects(rectangleB);
|
||||
}
|
||||
else if (shapeA is CircleF circleA && shapeB is CircleF circleB)
|
||||
{
|
||||
intersects = circleA.Intersects(circleB);
|
||||
}
|
||||
else if (shapeA is RectangleF rect1 && shapeB is CircleF circ1)
|
||||
{
|
||||
return Intersects(circ1, rect1);
|
||||
}
|
||||
else if (shapeA is CircleF circ2 && shapeB is RectangleF rect2)
|
||||
{
|
||||
return Intersects(circ2, rect2);
|
||||
}
|
||||
private static bool IntersectsInternal(CircleF circle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF otherCircle => CircleF.Intersects(circle, otherCircle),
|
||||
RectangleF otherRectangle => Intersects(circle, otherRectangle),
|
||||
OrientedBoundingRectangle otherOrientedBoundingRectangle => Intersects(circle, otherOrientedBoundingRectangle),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
};
|
||||
}
|
||||
|
||||
return intersects;
|
||||
private static bool IntersectsInternal(RectangleF rectangle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF otherCircle => Intersects(otherCircle, rectangle),
|
||||
RectangleF otherRectangle => RectangleF.Intersects(rectangle, otherRectangle),
|
||||
OrientedBoundingRectangle otherOrientedBoundingRectangle => Intersects(rectangle, otherOrientedBoundingRectangle),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IntersectsInternal(OrientedBoundingRectangle orientedBoundingRectangle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF circleB => Intersects(circleB, orientedBoundingRectangle),
|
||||
RectangleF rectangleB => Intersects(rectangleB, orientedBoundingRectangle),
|
||||
OrientedBoundingRectangle orientedBoundingRectangleB => OrientedBoundingRectangle.Intersects(orientedBoundingRectangle, orientedBoundingRectangleB),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,5 +87,35 @@
|
||||
var closestPoint = rectangle.ClosestPointTo(circle.Center);
|
||||
return circle.Contains(closestPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="circle"></param>
|
||||
/// <param name="orientedBoundingRectangle"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public static bool Intersects(CircleF circle, OrientedBoundingRectangle orientedBoundingRectangle)
|
||||
{
|
||||
var rotation = Matrix2.CreateRotationZ(-orientedBoundingRectangle.Orientation.Rotation);
|
||||
var circleCenterInRectangleSpace = rotation.Transform(orientedBoundingRectangle.Center - circle.Center);
|
||||
var circleInRectangleSpace = new CircleF(circleCenterInRectangleSpace, circle.Radius);
|
||||
var rectangleInLocalSpace = OrientedBoundingRectangle.Transform(orientedBoundingRectangle, ref rotation);
|
||||
rectangleInLocalSpace.Center = Point2.Zero;
|
||||
var rectangle = (BoundingRectangle)new RectangleF(0, 0, rectangleInLocalSpace.Radii.X, rectangleInLocalSpace.Radii.Y);
|
||||
return circleInRectangleSpace.Intersects(rectangle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="rectangleF"></param>
|
||||
/// <param name="orientedBoundingRectangle"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public static bool Intersects(RectangleF rectangleF, OrientedBoundingRectangle orientedBoundingRectangle)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Xunit;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Primitives
|
||||
namespace MonoGame.Extended.Tests.Primitives;
|
||||
|
||||
public class ShapeTests
|
||||
{
|
||||
public class ShapeTests
|
||||
public class CircleFTests
|
||||
{
|
||||
[Fact]
|
||||
public void CircCircIntersectionSameCircleTest()
|
||||
@@ -30,7 +33,10 @@ namespace MonoGame.Extended.Tests.Primitives
|
||||
|
||||
Assert.False(shape1.Intersects(shape2));
|
||||
}
|
||||
}
|
||||
|
||||
public class RectangleFTests
|
||||
{
|
||||
[Fact]
|
||||
public void RectRectSameRectTest()
|
||||
{
|
||||
@@ -68,7 +74,6 @@ namespace MonoGame.Extended.Tests.Primitives
|
||||
Assert.True(shape2.Intersects(shape1));
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void RectCircOnEdgeTest()
|
||||
{
|
||||
@@ -79,4 +84,34 @@ namespace MonoGame.Extended.Tests.Primitives
|
||||
Assert.True(shape2.Intersects(shape1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class OrientedBoundingRectangleTests
|
||||
{
|
||||
[Fact]
|
||||
public void Axis_aligned_rectangle_overlaps_circle()
|
||||
{
|
||||
IShapeF rectangle = new OrientedBoundingRectangle(Point2.Zero, new Size2(1, 1), Matrix2.Identity);
|
||||
var circle = new CircleF(Point2.Zero, 1);
|
||||
|
||||
Assert.True(rectangle.Intersects(circle));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Axis_aligned_rectangle_does_not_intersect_circle_in_top_left()
|
||||
{
|
||||
IShapeF rectangle = new OrientedBoundingRectangle(Point2.Zero, new Size2(1, 1), Matrix2.Identity);
|
||||
var circle = new CircleF(new Point2(1, 1), 1);
|
||||
|
||||
Assert.False(rectangle.Intersects(circle));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rectangle_rotated_45_degrees_does_not_intersect_circle_in_bottom_right()
|
||||
{
|
||||
IShapeF rectangle = new OrientedBoundingRectangle(Point2.Zero, new Size2(1, 1), Matrix2.CreateRotationZ(MathHelper.PiOver4));
|
||||
var circle = new CircleF(new Point2(1, -1), 1.4f);
|
||||
|
||||
Assert.False(rectangle.Intersects(circle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user