refactor GJK again
parent
2151252d6e
commit
f787a00a91
|
@ -24,7 +24,7 @@ namespace MoonTools.Core.Bonk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="simplex">A simplex returned by the GJK algorithm.</param>
|
/// <param name="simplex">A simplex returned by the GJK algorithm.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex simplex)
|
public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex2D simplex)
|
||||||
{
|
{
|
||||||
var simplexVertices = new PooledList<Vector2>(36, ClearMode.Always);
|
var simplexVertices = new PooledList<Vector2>(36, ClearMode.Always);
|
||||||
|
|
||||||
|
|
|
@ -11,73 +11,135 @@ namespace MoonTools.Core.Bonk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool TestCollision(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
|
public static bool TestCollision(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
|
||||||
{
|
{
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
return FindCollisionSimplex(shapeA, transformA, shapeB, transformB).Item1;
|
||||||
var a = minkowskiDifference.Support(Vector2.UnitX);
|
|
||||||
var b = minkowskiDifference.Support(-a);
|
|
||||||
|
|
||||||
return Vector2.Dot(a, b) > 0 ? false : CheckSimplex(new Simplex(minkowskiDifference, a, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool CheckSimplex(Simplex simplex)
|
|
||||||
{
|
|
||||||
var a = simplex.DirectionA;
|
|
||||||
var b = simplex.DirectionB;
|
|
||||||
|
|
||||||
var axb = a.Cross(b);
|
|
||||||
var c = simplex.Support((b - a).Perpendicular());
|
|
||||||
var axc = a.Cross(c);
|
|
||||||
var bxc = b.Cross(c);
|
|
||||||
var cxb = -bxc;
|
|
||||||
|
|
||||||
return (b - a) == Vector2.Zero || (axb.Y > 0 != bxc.Y > 0 ? CheckSimplex(simplex.WithDirections(b, c)) : (axc.Y > 0 != cxb.Y > 0 ? CheckSimplex(simplex.WithDirections(a, c)) : true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if the two shape-transform pairs are overlapping, and returns a simplex that can be used by the EPA algorithm to determine a miminum separating vector.
|
/// Tests if the two shape-transform pairs are overlapping, and returns a simplex that can be used by the EPA algorithm to determine a miminum separating vector.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static (bool, Simplex) FindCollisionSimplex(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
|
public static (bool, Simplex2D) FindCollisionSimplex(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
|
||||||
{
|
{
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
||||||
var a = minkowskiDifference.Support(Vector2.UnitX);
|
var c = minkowskiDifference.Support(Vector2.UnitX);
|
||||||
var b = minkowskiDifference.Support(-a);
|
var b = minkowskiDifference.Support(-Vector2.UnitX);
|
||||||
|
return Check(minkowskiDifference, c, b);
|
||||||
return Vector2.Dot(a, b) > 0 ? (false, default(Simplex)) : Simplex(new Simplex(minkowskiDifference, a, b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (bool, Simplex) Simplex(Simplex simplex)
|
private static (bool, Simplex2D) Check(MinkowskiDifference minkowskiDifference, Vector2 c, Vector2 b)
|
||||||
{
|
{
|
||||||
var a = simplex.DirectionA;
|
var cb = c - b;
|
||||||
var b = simplex.DirectionB;
|
var c0 = -c;
|
||||||
|
var d = Direction(cb, c0);
|
||||||
|
return DoSimplex(minkowskiDifference, new Simplex2D(b, c), d);
|
||||||
|
}
|
||||||
|
|
||||||
if ((b - a) == Vector2.Zero)
|
private static (bool, Simplex2D) DoSimplex(MinkowskiDifference minkowskiDifference, Simplex2D simplex, Vector2 direction)
|
||||||
{
|
{
|
||||||
return (false, simplex.WithDirections(a, b));
|
var a = minkowskiDifference.Support(direction);
|
||||||
|
var notPastOrigin = Vector2.Dot(a, direction) < 0;
|
||||||
|
var (intersects, newSimplex, newDirection) = EnclosesOrigin(a, simplex);
|
||||||
|
|
||||||
|
if (notPastOrigin)
|
||||||
|
{
|
||||||
|
return (false, default(Simplex2D));
|
||||||
|
}
|
||||||
|
else if (intersects)
|
||||||
|
{
|
||||||
|
return (true, new Simplex2D(simplex.A, simplex.B.Value, a));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var c = simplex.Support((b - a).Perpendicular());
|
return DoSimplex(minkowskiDifference, newSimplex, newDirection);
|
||||||
var axb = a.Cross(b);
|
}
|
||||||
var bxc = b.Cross(c);
|
}
|
||||||
|
|
||||||
if (axb.Y > 0 != bxc.Y > 0)
|
private static (bool, Simplex2D, Vector2) EnclosesOrigin(Vector2 a, Simplex2D simplex)
|
||||||
{
|
{
|
||||||
return Simplex(simplex.WithDirections(b, c));
|
if (simplex.ZeroSimplex)
|
||||||
|
{
|
||||||
|
return HandleZeroSimplex(a, simplex.A);
|
||||||
|
}
|
||||||
|
else if (simplex.OneSimplex)
|
||||||
|
{
|
||||||
|
return HandleOneSimplex(a, simplex.A, simplex.B.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var axc = a.Cross(c);
|
return (false, simplex, Vector2.Zero);
|
||||||
var cxb = -bxc;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (axc.Y > 0 != cxb.Y > 0)
|
private static (bool, Simplex2D, Vector2) HandleZeroSimplex(Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return Simplex(simplex.WithDirections(a, b));
|
var ab = b - a;
|
||||||
|
var a0 = -a;
|
||||||
|
var (newSimplex, newDirection) = SameDirection(ab, a0) ? (new Simplex2D(a, b), Perpendicular(ab, a0)) : (new Simplex2D(a), a0);
|
||||||
|
return (false, newSimplex, newDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (bool, Simplex2D, Vector2) HandleOneSimplex(Vector2 a, Vector2 b, Vector2 c)
|
||||||
|
{
|
||||||
|
var a0 = -a;
|
||||||
|
var ab = b - a;
|
||||||
|
var ac = c - a;
|
||||||
|
var abp = Perpendicular(ab, -ac);
|
||||||
|
var acp = Perpendicular(ac, -ab);
|
||||||
|
|
||||||
|
if (SameDirection(abp, a0))
|
||||||
|
{
|
||||||
|
if (SameDirection(ab, a0))
|
||||||
|
{
|
||||||
|
return (false, new Simplex2D(a, b), abp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (true, simplex.WithDirections(a, b));
|
return (false, new Simplex2D(a), a0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (SameDirection(acp, a0))
|
||||||
|
{
|
||||||
|
if (SameDirection(ac, a0))
|
||||||
|
{
|
||||||
|
return (false, new Simplex2D(a, c), acp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (false, new Simplex2D(a), a0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (true, new Simplex2D(b, c), a0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2 TripleProduct(Vector2 a, Vector2 b, Vector2 c)
|
||||||
|
{
|
||||||
|
var A = new Vector3(a.X, a.Y, 0);
|
||||||
|
var B = new Vector3(b.X, b.Y, 0);
|
||||||
|
var C = new Vector3(c.X, c.Y, 0);
|
||||||
|
|
||||||
|
var first = Vector3.Cross(A, B);
|
||||||
|
var second = Vector3.Cross(first, C);
|
||||||
|
|
||||||
|
return new Vector2(second.X, second.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2 Direction(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
var d = TripleProduct(a, b, a);
|
||||||
|
var collinear = d == Vector2.Zero;
|
||||||
|
return collinear ? new Vector2(a.Y, -a.X) : d;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool SameDirection(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return Vector2.Dot(a, b) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2 Perpendicular(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return TripleProduct(a, b, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,59 @@
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MoonTools.Core.Structs;
|
using MoonTools.Core.Structs;
|
||||||
using MoonTools.Core.Bonk.Extensions;
|
using MoonTools.Core.Bonk.Extensions;
|
||||||
|
using MoreLinq;
|
||||||
|
|
||||||
namespace MoonTools.Core.Bonk
|
namespace MoonTools.Core.Bonk
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simplex is a shape used to calculate overlap. It is defined by a Minkowski difference and two direction vectors.
|
/// A simplex is a shape with up to n - 2 vertices in the nth dimension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct Simplex : IShape2D
|
public struct Simplex2D : IShape2D
|
||||||
{
|
{
|
||||||
MinkowskiDifference minkowskiDifference;
|
Vector2 a;
|
||||||
Vector2 directionA;
|
Vector2? b;
|
||||||
Vector2 directionB;
|
Vector2? c;
|
||||||
|
|
||||||
public Vector2 DirectionA { get { return directionA; } }
|
public Vector2 A => a;
|
||||||
public Vector2 DirectionB { get { return directionB; } }
|
public Vector2? B => b;
|
||||||
|
public Vector2? C => c;
|
||||||
|
|
||||||
public Simplex(MinkowskiDifference minkowskiDifference, Vector2 directionA, Vector2 directionB)
|
public bool ZeroSimplex { get { return !b.HasValue && !c.HasValue; } }
|
||||||
|
public bool OneSimplex { get { return b.HasValue && !c.HasValue; } }
|
||||||
|
public bool TwoSimplex { get { return b.HasValue && c.HasValue; } }
|
||||||
|
|
||||||
|
public int Count => TwoSimplex ? 3 : (OneSimplex ? 2 : 1);
|
||||||
|
|
||||||
|
public Simplex2D(Vector2 a)
|
||||||
{
|
{
|
||||||
this.minkowskiDifference = minkowskiDifference;
|
this.a = a;
|
||||||
this.directionA = directionA;
|
this.b = null;
|
||||||
this.directionB = directionB;
|
this.c = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Simplex WithDirections(Vector2 a, Vector2 b)
|
public Simplex2D(Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return new Simplex(minkowskiDifference, a, b);
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
this.c = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Simplex2D(Vector2 a, Vector2 b, Vector2 c)
|
||||||
|
{
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
this.c = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Position2D> Vertices
|
public IEnumerable<Position2D> Vertices
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return (Position2D)Support(directionA);
|
yield return (Position2D)a;
|
||||||
yield return (Position2D)Support(directionB);
|
if (b.HasValue) { yield return (Position2D)b; }
|
||||||
yield return (Position2D)Support(-(directionB - directionA).Perpendicular());
|
if (c.HasValue) { yield return (Position2D)c; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +64,7 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public Vector2 Support(Vector2 direction)
|
public Vector2 Support(Vector2 direction)
|
||||||
{
|
{
|
||||||
return minkowskiDifference.Support(direction);
|
return Vertices.MaxBy(vertex => Vector2.Dot(vertex, direction)).First();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 Support(Vector2 direction, Transform2D transform)
|
public Vector2 Support(Vector2 direction, Transform2D transform)
|
||||||
|
@ -66,11 +84,10 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public bool Equals(IShape2D other)
|
public bool Equals(IShape2D other)
|
||||||
{
|
{
|
||||||
if (other is Simplex otherSimplex)
|
if (other is Simplex2D otherSimplex)
|
||||||
{
|
{
|
||||||
return minkowskiDifference == otherSimplex.minkowskiDifference &&
|
if (Count != otherSimplex.Count) { return false; }
|
||||||
((directionA == otherSimplex.directionA && directionB == otherSimplex.directionB) ||
|
return Vertices.Intersect(otherSimplex.Vertices).Count() == Count;
|
||||||
(directionA == otherSimplex.directionB && directionB == otherSimplex.directionA));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,22 +95,23 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
var hashCode = 74270316;
|
var hashCode = -495772172;
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<MinkowskiDifference>.Default.GetHashCode(minkowskiDifference);
|
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(a);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(directionA);
|
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(b);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(directionB);
|
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(c);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(DirectionA);
|
hashCode = hashCode * -1521134295 + ZeroSimplex.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(DirectionB);
|
hashCode = hashCode * -1521134295 + OneSimplex.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + TwoSimplex.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
|
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(Simplex a, Simplex b)
|
public static bool operator ==(Simplex2D a, Simplex2D b)
|
||||||
{
|
{
|
||||||
return a.Equals(b);
|
return a.Equals(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator !=(Simplex a, Simplex b)
|
public static bool operator !=(Simplex2D a, Simplex2D b)
|
||||||
{
|
{
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,15 @@ namespace MoonTools.Core.Bonk.Extensions
|
||||||
{
|
{
|
||||||
internal static class Vector2Extensions
|
internal static class Vector2Extensions
|
||||||
{
|
{
|
||||||
internal static Vector2 Cross(this Vector2 a, Vector2 b)
|
internal static float Cross(this Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
var vec3 = Vector3.Cross(new Vector3(a.X, a.Y, 0), new Vector3(b.X, b.Y, 0));
|
return Vector3.Cross(new Vector3(a.X, a.Y, 0), new Vector3(b.X, b.Y, 0)).Z;
|
||||||
return new Vector2(vec3.X, vec3.Y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Vector2 Perpendicular(this Vector2 v)
|
internal static Vector2 Perpendicular(this Vector2 a, Vector2 b)
|
||||||
{
|
{
|
||||||
return new Vector2(v.Y, -v.X);
|
var ab = b - a;
|
||||||
|
return a.Cross(b) > 0 ? Vector2.Normalize(new Vector2(ab.Y, ab.X)) : Vector2.Normalize(new Vector2(ab.Y, -ab.X));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,10 @@ namespace Tests
|
||||||
|
|
||||||
intersection.X.Should().Be(1f);
|
intersection.X.Should().Be(1f);
|
||||||
intersection.Y.Should().Be(0);
|
intersection.Y.Should().Be(0);
|
||||||
|
|
||||||
|
var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
|
||||||
|
|
||||||
|
GJK2D.TestCollision(squareA, movedTransform, squareB, transformB).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -47,6 +51,10 @@ namespace Tests
|
||||||
|
|
||||||
intersection.X.Should().BeApproximately(ix, 0.01f);
|
intersection.X.Should().BeApproximately(ix, 0.01f);
|
||||||
intersection.Y.Should().BeApproximately(iy, 0.01f);
|
intersection.Y.Should().BeApproximately(iy, 0.01f);
|
||||||
|
|
||||||
|
var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
|
||||||
|
|
||||||
|
GJK2D.TestCollision(circleA, movedTransform, circleB, transformB).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -63,8 +71,9 @@ namespace Tests
|
||||||
|
|
||||||
var intersection = EPA2D.Intersect(line, transformA, square, transformB, simplex);
|
var intersection = EPA2D.Intersect(line, transformA, square, transformB, simplex);
|
||||||
|
|
||||||
intersection.X.Should().Be(-1);
|
var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
|
||||||
intersection.Y.Should().Be(1);
|
|
||||||
|
GJK2D.TestCollision(line, movedTransform, square, transformB).Should().BeFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
210
Test/Equality.cs
210
Test/Equality.cs
|
@ -258,169 +258,163 @@ namespace Tests
|
||||||
public class SimplexTests
|
public class SimplexTests
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexEquals()
|
public void ZeroSimplexEquals()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
|
|
||||||
simplexA.Equals(simplexB).Should().BeTrue();
|
simplexA.Equals(simplexB).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexEqualsOperator()
|
public void ZeroSimplexEqualsOperator()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
|
|
||||||
(simplexA == simplexB).Should().BeTrue();
|
(simplexA == simplexB).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexDirectionOutOfOrderEqual()
|
public void ZeroSimplexNotEquals()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.Zero);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
simplexA.Equals(simplexB).Should().BeFalse();
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
var simplexC = new Simplex2D(Vector2.Zero, Vector2.One);
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
simplexA.Equals(simplexC).Should().BeFalse();
|
||||||
var directionB = Vector2.UnitY;
|
}
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
[Test]
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionB, directionA);
|
public void ZeroSimplexNotEqualsOperator()
|
||||||
|
{
|
||||||
|
var simplexA = new Simplex2D(Vector2.Zero);
|
||||||
|
var simplexB = new Simplex2D(Vector2.One);
|
||||||
|
|
||||||
|
(simplexA != simplexB).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OneSimplexEquals()
|
||||||
|
{
|
||||||
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
|
||||||
simplexA.Equals(simplexB).Should().BeTrue();
|
simplexA.Equals(simplexB).Should().BeTrue();
|
||||||
|
|
||||||
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.One);
|
||||||
|
|
||||||
|
simplexC.Equals(simplexD).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexDirectionOutOfOrderEqualOperator()
|
public void OneSimplexEqualsOperator()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionB, directionA);
|
|
||||||
|
|
||||||
(simplexA == simplexB).Should().BeTrue();
|
(simplexA == simplexB).Should().BeTrue();
|
||||||
|
|
||||||
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.One);
|
||||||
|
|
||||||
|
(simplexC == simplexD).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexMinkowskiNotEqual()
|
public void OneSimplexNotEquals()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One, Vector2.UnitX);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifferenceA = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
|
||||||
var minkowskiDifferenceB = new MinkowskiDifference(shapeB, transformB, shapeA, transformA);
|
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifferenceA, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifferenceB, directionA, directionB);
|
|
||||||
|
|
||||||
simplexA.Equals(simplexB).Should().BeFalse();
|
simplexA.Equals(simplexB).Should().BeFalse();
|
||||||
|
|
||||||
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
|
simplexC.Equals(simplexD).Should().BeFalse();
|
||||||
|
|
||||||
|
var simplexE = new Simplex2D(Vector2.Zero);
|
||||||
|
|
||||||
|
simplexA.Equals(simplexE).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexMinkowskiNotEqualOperator()
|
public void OneSimplexNotEqualsOperator()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One, Vector2.UnitX);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
(simplexA == simplexB).Should().BeFalse();
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifferenceA = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero);
|
||||||
var minkowskiDifferenceB = new MinkowskiDifference(shapeB, transformB, shapeA, transformA);
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
(simplexC == simplexD).Should().BeFalse();
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifferenceA, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifferenceB, directionA, directionB);
|
|
||||||
|
|
||||||
(simplexA != simplexB).Should().BeTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexDirectionsNotEqual()
|
public void TwoSimplexEquals()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
simplexA.Equals(simplexB).Should().BeTrue();
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.One, Vector2.UnitX);
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
simplexC.Equals(simplexD).Should().BeTrue();
|
||||||
var directionB = Vector2.UnitY;
|
}
|
||||||
var directionC = -Vector2.UnitX;
|
|
||||||
var directionD = -Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
[Test]
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionC, directionD);
|
public void TwoSimplexEqualsOperator()
|
||||||
|
{
|
||||||
|
var simplexA = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
|
(simplexA == simplexB).Should().BeTrue();
|
||||||
|
|
||||||
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.One, Vector2.UnitX);
|
||||||
|
|
||||||
|
(simplexC == simplexD).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TwoSimplexNotEquals()
|
||||||
|
{
|
||||||
|
var simplexA = new Simplex2D(Vector2.One, Vector2.UnitY, Vector2.UnitX);
|
||||||
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
simplexA.Equals(simplexB).Should().BeFalse();
|
simplexA.Equals(simplexB).Should().BeFalse();
|
||||||
|
|
||||||
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.UnitY, Vector2.UnitX);
|
||||||
|
|
||||||
|
simplexC.Equals(simplexD).Should().BeFalse();
|
||||||
|
|
||||||
|
var simplexE = new Simplex2D(Vector2.Zero);
|
||||||
|
|
||||||
|
simplexA.Equals(simplexE).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SimplexDirectionsNotEqualOperator()
|
public void TwoSimplexNotEqualsOperator()
|
||||||
{
|
{
|
||||||
var shapeA = new Circle(3);
|
var simplexA = new Simplex2D(Vector2.One, Vector2.UnitY, Vector2.UnitX);
|
||||||
var transformA = new Transform2D(new Position2D(1, 2));
|
var simplexB = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
|
||||||
var shapeB = new Circle(2);
|
(simplexA == simplexB).Should().BeFalse();
|
||||||
var transformB = new Transform2D(new Position2D(4, 5));
|
|
||||||
|
|
||||||
var minkowskiDifference = new MinkowskiDifference(shapeA, transformA, shapeB, transformB);
|
var simplexC = new Simplex2D(Vector2.One, Vector2.Zero, Vector2.UnitX);
|
||||||
|
var simplexD = new Simplex2D(Vector2.Zero, Vector2.UnitY, Vector2.UnitX);
|
||||||
|
|
||||||
var directionA = Vector2.UnitX;
|
(simplexC == simplexD).Should().BeFalse();
|
||||||
var directionB = Vector2.UnitY;
|
|
||||||
var directionC = -Vector2.UnitX;
|
|
||||||
var directionD = -Vector2.UnitY;
|
|
||||||
|
|
||||||
var simplexA = new Simplex(minkowskiDifference, directionA, directionB);
|
|
||||||
var simplexB = new Simplex(minkowskiDifference, directionC, directionD);
|
|
||||||
|
|
||||||
(simplexA != simplexB).Should().BeTrue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,18 @@ namespace Tests
|
||||||
GJK2D.TestCollision(circle, circleTransform, square, squareTransform).Should().BeFalse();
|
GJK2D.TestCollision(circle, circleTransform, square, squareTransform).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RectanglesNotOverlapping()
|
||||||
|
{
|
||||||
|
var rectangleA = new MoonTools.Core.Bonk.Rectangle(-6, -6, 6, 6);
|
||||||
|
var transformA = new Transform2D(new Position2D(39, 249));
|
||||||
|
|
||||||
|
var rectangleB = new MoonTools.Core.Bonk.Rectangle(0, 0, 16, 16);
|
||||||
|
var transformB = new Transform2D(new Position2D(16, 240));
|
||||||
|
|
||||||
|
GJK2D.TestCollision(rectangleA, transformA, rectangleB, transformB).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void RotatedRectanglesOverlapping()
|
public void RotatedRectanglesOverlapping()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue