mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
Properly intersect circle and oriented rect
This commit is contained in:
@@ -175,44 +175,22 @@ namespace MonoGame.Extended.Collisions
|
||||
/// <returns>The distance vector from the edge of b to a's Position</returns>
|
||||
private static Vector2 CalculatePenetrationVector(IShapeF a, IShapeF b)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case RectangleF rectA when b is RectangleF rectB:
|
||||
return PenetrationVector(rectA, rectB);
|
||||
case CircleF circA when b is CircleF circB:
|
||||
return PenetrationVector(circA, circB);
|
||||
case CircleF circA when b is RectangleF rectB:
|
||||
return PenetrationVector(circA, rectB);
|
||||
case RectangleF rectA when b is CircleF circB:
|
||||
return PenetrationVector(rectA, circB);
|
||||
}
|
||||
return a switch
|
||||
{
|
||||
CircleF circleA when b is CircleF circleB => PenetrationVector(circleA, circleB),
|
||||
CircleF circleA when b is RectangleF rectangleB => PenetrationVector(circleA, rectangleB),
|
||||
CircleF circleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(circleA, orientedRectangleB),
|
||||
|
||||
throw new NotSupportedException("Shapes must be either a CircleF or RectangleF");
|
||||
}
|
||||
RectangleF rectangleA when b is CircleF circleB => PenetrationVector(rectangleA, circleB),
|
||||
RectangleF rectangleA when b is RectangleF rectangleB => PenetrationVector(rectangleA, rectangleB),
|
||||
RectangleF rectangleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(rectangleA, orientedRectangleB),
|
||||
|
||||
private static Vector2 PenetrationVector(RectangleF rect1, RectangleF rect2)
|
||||
{
|
||||
var intersectingRectangle = RectangleF.Intersection(rect1, rect2);
|
||||
Debug.Assert(!intersectingRectangle.IsEmpty,
|
||||
"Violation of: !intersect.IsEmpty; Rectangles must intersect to calculate a penetration vector.");
|
||||
OrientedRectangle orientedRectangleA when b is CircleF circleB => PenetrationVector(orientedRectangleA, circleB),
|
||||
OrientedRectangle orientedRectangleA when b is RectangleF rectangleB => PenetrationVector(orientedRectangleA, rectangleB),
|
||||
OrientedRectangle orientedRectangleA when b is OrientedRectangle orientedRectangleB => PenetrationVector(orientedRectangleA, orientedRectangleB),
|
||||
|
||||
Vector2 penetration;
|
||||
if (intersectingRectangle.Width < intersectingRectangle.Height)
|
||||
{
|
||||
var d = rect1.Center.X < rect2.Center.X
|
||||
? intersectingRectangle.Width
|
||||
: -intersectingRectangle.Width;
|
||||
penetration = new Vector2(d, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var d = rect1.Center.Y < rect2.Center.Y
|
||||
? intersectingRectangle.Height
|
||||
: -intersectingRectangle.Height;
|
||||
penetration = new Vector2(0, d);
|
||||
}
|
||||
|
||||
return penetration;
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(a))
|
||||
};
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(CircleF circ1, CircleF circ2)
|
||||
@@ -287,11 +265,64 @@ namespace MonoGame.Extended.Collisions
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(CircleF circleA, OrientedRectangle orientedRectangleB)
|
||||
{
|
||||
return new Vector2();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(RectangleF rect, CircleF circ)
|
||||
{
|
||||
return -PenetrationVector(circ, rect);
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(RectangleF rect1, RectangleF rect2)
|
||||
{
|
||||
var intersectingRectangle = RectangleF.Intersection(rect1, rect2);
|
||||
Debug.Assert(!intersectingRectangle.IsEmpty,
|
||||
"Violation of: !intersect.IsEmpty; Rectangles must intersect to calculate a penetration vector.");
|
||||
|
||||
Vector2 penetration;
|
||||
if (intersectingRectangle.Width < intersectingRectangle.Height)
|
||||
{
|
||||
var d = rect1.Center.X < rect2.Center.X
|
||||
? intersectingRectangle.Width
|
||||
: -intersectingRectangle.Width;
|
||||
penetration = new Vector2(d, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var d = rect1.Center.Y < rect2.Center.Y
|
||||
? intersectingRectangle.Height
|
||||
: -intersectingRectangle.Height;
|
||||
penetration = new Vector2(0, d);
|
||||
}
|
||||
|
||||
return penetration;
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(RectangleF rectangleA, OrientedRectangle orientedRectangleB)
|
||||
{
|
||||
return new Vector2();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, CircleF circleB)
|
||||
{
|
||||
return -PenetrationVector(circleB, orientedRectangleA);
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, RectangleF rectangleB)
|
||||
{
|
||||
return -PenetrationVector(rectangleB, orientedRectangleA);
|
||||
}
|
||||
|
||||
private static Vector2 PenetrationVector(OrientedRectangle orientedRectangleA, OrientedRectangle orientedRectangleB)
|
||||
{
|
||||
return new Vector2();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +173,10 @@ namespace MonoGame.Extended
|
||||
|
||||
public static explicit operator RectangleF(OrientedRectangle orientedRectangle)
|
||||
{
|
||||
var topLeft = orientedRectangle.Center - orientedRectangle.Radii;
|
||||
var topLeft = -orientedRectangle.Radii;
|
||||
var rectangle = new RectangleF(topLeft, orientedRectangle.Radii * 2);
|
||||
return RectangleF.Transform(rectangle, ref orientedRectangle.Orientation);
|
||||
var orientation = orientedRectangle.Orientation * Matrix2.CreateTranslation(orientedRectangle.Center);
|
||||
return RectangleF.Transform(rectangle, ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,50 +29,27 @@ namespace MonoGame.Extended
|
||||
/// <summary>
|
||||
/// Check if two shapes intersect.
|
||||
/// </summary>
|
||||
/// <param name="shapeA">The first shape.</param>
|
||||
/// <param name="shapeB">The second shape.</param>
|
||||
/// <param name="a">The first shape.</param>
|
||||
/// <param name="b">The second shape.</param>
|
||||
/// <returns>True if the two shapes intersect.</returns>
|
||||
public static bool Intersects(this IShapeF shapeA, IShapeF shapeB)
|
||||
public static bool Intersects(this IShapeF a, IShapeF b)
|
||||
{
|
||||
return shapeA switch
|
||||
return a switch
|
||||
{
|
||||
CircleF circleA => IntersectsInternal(circleA, shapeB),
|
||||
RectangleF rectangleA => IntersectsInternal(rectangleA, shapeB),
|
||||
OrientedRectangle orientedRectangleA => IntersectsInternal(orientedRectangleA, shapeB),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shapeA))
|
||||
};
|
||||
}
|
||||
CircleF circleA when b is CircleF circleB => circleA.Intersects(circleB),
|
||||
CircleF circleA when b is RectangleF rectangleB => circleA.Intersects(rectangleB),
|
||||
CircleF circleA when b is OrientedRectangle orientedRectangleB => Intersects(circleA, orientedRectangleB),
|
||||
|
||||
private static bool IntersectsInternal(CircleF circle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF otherCircle => CircleF.Intersects(circle, otherCircle),
|
||||
RectangleF otherRectangle => Intersects(circle, otherRectangle),
|
||||
OrientedRectangle otherOrientedRectangle => Intersects(circle, otherOrientedRectangle),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
};
|
||||
}
|
||||
RectangleF rectangleA when b is CircleF circleB => Intersects(circleB, rectangleA),
|
||||
RectangleF rectangleA when b is RectangleF rectangleB => Intersects(rectangleA, rectangleB),
|
||||
RectangleF rectangleA when b is OrientedRectangle orientedRectangleB => Intersects(rectangleA, orientedRectangleB),
|
||||
|
||||
private static bool IntersectsInternal(RectangleF rectangle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF otherCircle => Intersects(otherCircle, rectangle),
|
||||
RectangleF otherRectangle => RectangleF.Intersects(rectangle, otherRectangle),
|
||||
OrientedRectangle otherOrientedRectangle => Intersects(rectangle, otherOrientedRectangle),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
};
|
||||
}
|
||||
OrientedRectangle orientedRectangleA when b is CircleF circleB => Intersects(circleB, orientedRectangleA),
|
||||
OrientedRectangle orientedRectangleA when b is RectangleF rectangleB => Intersects(rectangleB, orientedRectangleA),
|
||||
OrientedRectangle orientedRectangleA when b is OrientedRectangle orientedRectangleB
|
||||
=> OrientedRectangle.Intersects(orientedRectangleA, orientedRectangleB),
|
||||
|
||||
private static bool IntersectsInternal(OrientedRectangle orientedRectangle, IShapeF shape)
|
||||
{
|
||||
return shape switch
|
||||
{
|
||||
CircleF circleB => Intersects(circleB, orientedRectangle),
|
||||
RectangleF rectangleB => Intersects(rectangleB, orientedRectangle),
|
||||
OrientedRectangle orientedRectangleB => OrientedRectangle.Intersects(orientedRectangle, orientedRectangleB),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shape))
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(a))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -96,11 +73,10 @@ namespace MonoGame.Extended
|
||||
/// <returns>True if the circle and oriented bounded rectangle intersects, otherwise false.</returns>
|
||||
public static bool Intersects(CircleF circle, OrientedRectangle orientedRectangle)
|
||||
{
|
||||
var rotation = Matrix2.CreateRotationZ(-orientedRectangle.Orientation.Rotation);
|
||||
var rotation = Matrix2.CreateRotationZ(orientedRectangle.Orientation.Rotation);
|
||||
var circleCenterInRectangleSpace = rotation.Transform(circle.Center - orientedRectangle.Center);
|
||||
var circleInRectangleSpace = new CircleF(circleCenterInRectangleSpace, circle.Radius);
|
||||
var rectangleInLocalSpace = OrientedRectangle.Transform(orientedRectangle, ref rotation);
|
||||
var boundingRectangle = new BoundingRectangle(rectangleInLocalSpace.Center, rectangleInLocalSpace.Radii);
|
||||
var boundingRectangle = new BoundingRectangle(new Point2(), orientedRectangle.Radii);
|
||||
return circleInRectangleSpace.Intersects(boundingRectangle);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ public class ShapeTests
|
||||
* * *
|
||||
* :* *
|
||||
*/
|
||||
IShapeF rectangle = new OrientedRectangle(new Point2(-1, 1), new Size2(2.8f, 2.8f), Matrix2.CreateRotationZ(MathHelper.PiOver4));
|
||||
IShapeF rectangle = new OrientedRectangle(new Point2(-1, 1), new Size2(1.42f, 1.42f), 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