fix bug in Line iterator + comparison cleanup

pull/10/head
Evan Hemsley 2019-12-08 19:46:08 -08:00
parent 056cc843e4
commit 12c9f09229
16 changed files with 256 additions and 235 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
bin/ bin/
obj/ obj/
.vscode .vscode
.vs

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
@ -8,7 +9,7 @@ namespace MoonTools.Core.Bonk
/// <summary> /// <summary>
/// Axis-aligned bounding box. /// Axis-aligned bounding box.
/// </summary> /// </summary>
public struct AABB public struct AABB : IEquatable<AABB>
{ {
public float MinX { get; private set; } public float MinX { get; private set; }
public float MinY { get; private set; } public float MinY { get; private set; }
@ -31,6 +32,24 @@ namespace MoonTools.Core.Bonk
}; };
} }
public override bool Equals(object obj)
{
return obj is AABB aabb && Equals(aabb);
}
public bool Equals(AABB other)
{
return MinX == other.MinX &&
MinY == other.MinY &&
MaxX == other.MaxX &&
MaxY == other.MaxY;
}
public override int GetHashCode()
{
return HashCode.Combine(MinX, MinY, MaxX, MaxY);
}
public AABB(float minX, float minY, float maxX, float maxY) public AABB(float minX, float minY, float maxX, float maxY)
{ {
MinX = minX; MinX = minX;
@ -38,5 +57,15 @@ namespace MoonTools.Core.Bonk
MaxX = maxX; MaxX = maxX;
MaxY = maxY; MaxY = maxY;
} }
public static bool operator ==(AABB left, AABB right)
{
return left.Equals(right);
}
public static bool operator !=(AABB left, AABB right)
{
return !(left == right);
}
} }
} }

View File

@ -15,8 +15,12 @@
<PackageProjectUrl>https://github.com/MoonsideGames/MoonTools.Core.Bonk</PackageProjectUrl> <PackageProjectUrl>https://github.com/MoonsideGames/MoonTools.Core.Bonk</PackageProjectUrl>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MoonTools.Core.Structs" Version="2.0.0"/> <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PackageReference Include="morelinq" Version="3.2.0"/> <PrivateAssets>all</PrivateAssets>
<PackageReference Include="System.Collections.Immutable" Version="1.6.0"/> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MoonTools.Core.Structs" Version="2.0.0" />
<PackageReference Include="morelinq" Version="3.2.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.6.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -31,7 +31,7 @@ namespace MoonTools.Core.Bonk
/// <param name="id">A unique ID for the shape-transform pair.</param> /// <param name="id">A unique ID for the shape-transform pair.</param>
/// <param name="shape"></param> /// <param name="shape"></param>
/// <param name="transform2D"></param> /// <param name="transform2D"></param>
public void Insert(T id, IShape2D shape, Transform2D transform2D) public void Insert<TShape2D>(T id, TShape2D shape, Transform2D transform2D) where TShape2D : struct, IShape2D
{ {
var box = shape.AABB(transform2D); var box = shape.AABB(transform2D);
var minHash = Hash(box.MinX, box.MinY); var minHash = Hash(box.MinX, box.MinY);
@ -60,7 +60,7 @@ namespace MoonTools.Core.Bonk
/// <summary> /// <summary>
/// Retrieves all the potential collisions of a shape-transform pair. Excludes any shape-transforms with the given ID. /// Retrieves all the potential collisions of a shape-transform pair. Excludes any shape-transforms with the given ID.
/// </summary> /// </summary>
public IEnumerable<(T, IShape2D, Transform2D)> Retrieve(T id, IShape2D shape, Transform2D transform2D) public IEnumerable<(T, IShape2D, Transform2D)> Retrieve<TShape2D>(T id, TShape2D shape, Transform2D transform2D) where TShape2D : struct, IShape2D
{ {
var box = shape.AABB(transform2D); var box = shape.AABB(transform2D);
var minHash = Hash(box.MinX, box.MinY); var minHash = Hash(box.MinX, box.MinY);

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using MoonTools.Core.Structs; using MoonTools.Core.Structs;
@ -10,51 +9,41 @@ namespace MoonTools.Core.Bonk
/// </summary> /// </summary>
public struct MinkowskiDifference : IEquatable<MinkowskiDifference> public struct MinkowskiDifference : IEquatable<MinkowskiDifference>
{ {
private IShape2D shapeA; private IShape2D ShapeA { get; }
private Transform2D transformA; private Transform2D TransformA { get; }
private IShape2D shapeB; private IShape2D ShapeB { get; }
private Transform2D transformB; private Transform2D TransformB { get; }
public MinkowskiDifference(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB) public MinkowskiDifference(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
{ {
this.shapeA = shapeA; ShapeA = shapeA;
this.transformA = transformA; TransformA = transformA;
this.shapeB = shapeB; ShapeB = shapeB;
this.transformB = transformB; TransformB = transformB;
} }
public Vector2 Support(Vector2 direction) public Vector2 Support(Vector2 direction)
{ {
return shapeA.Support(direction, transformA) - shapeB.Support(-direction, transformB); return ShapeA.Support(direction, TransformA) - ShapeB.Support(-direction, TransformB);
} }
public override bool Equals(object other) public override bool Equals(object other)
{ {
if (other is MinkowskiDifference otherMinkowskiDifference) return other is MinkowskiDifference minkowskiDifference && Equals(minkowskiDifference);
{
return Equals(otherMinkowskiDifference);
}
return false;
} }
public bool Equals(MinkowskiDifference other) public bool Equals(MinkowskiDifference other)
{ {
return return
shapeA == other.shapeA && ShapeA == other.ShapeA &&
transformA == other.transformA && TransformA == other.TransformA &&
shapeB == other.shapeB && ShapeB == other.ShapeB &&
transformB == other.transformB; TransformB == other.TransformB;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
var hashCode = 974363698; return HashCode.Combine(ShapeA, TransformA, ShapeB, TransformB);
hashCode = hashCode * -1521134295 + EqualityComparer<IShape2D>.Default.GetHashCode(shapeA);
hashCode = hashCode * -1521134295 + EqualityComparer<Transform2D>.Default.GetHashCode(transformA);
hashCode = hashCode * -1521134295 + EqualityComparer<IShape2D>.Default.GetHashCode(shapeB);
hashCode = hashCode * -1521134295 + EqualityComparer<Transform2D>.Default.GetHashCode(transformB);
return hashCode;
} }
public static bool operator ==(MinkowskiDifference a, MinkowskiDifference b) public static bool operator ==(MinkowskiDifference a, MinkowskiDifference b)

View File

@ -12,7 +12,7 @@ using System.Numerics;
namespace MoonTools.Core.Bonk namespace MoonTools.Core.Bonk
{ {
enum PolygonWinding internal enum PolygonWinding
{ {
Clockwise, Clockwise,
CounterClockwise CounterClockwise
@ -24,8 +24,7 @@ namespace MoonTools.Core.Bonk
/// Returns a minimum separating vector in the direction from A to B. /// Returns a minimum separating vector in the direction from A to B.
/// </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> public static Vector2 Intersect<TShapeA, TShapeB>(TShapeA shapeA, Transform2D Transform2DA, TShapeB shapeB, Transform2D Transform2DB, Simplex2D simplex) where TShapeA : struct, IShape2D where TShapeB : struct, IShape2D
public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex2D simplex)
{ {
var simplexVertices = simplex.Vertices.Select(vertex => vertex.ToVector2()).ToImmutableArray(); var simplexVertices = simplex.Vertices.Select(vertex => vertex.ToVector2()).ToImmutableArray();

View File

@ -7,9 +7,9 @@ namespace MoonTools.Core.Bonk
/// <summary> /// <summary>
/// A Circle is a shape defined by a radius. /// A Circle is a shape defined by a radius.
/// </summary> /// </summary>
public struct Circle : IShape2D, IEquatable<IShape2D> public struct Circle : IShape2D, IEquatable<Circle>
{ {
public int Radius { get; private set; } public int Radius { get; }
public Circle(int radius) public Circle(int radius)
{ {
@ -24,36 +24,31 @@ namespace MoonTools.Core.Bonk
public AABB AABB(Transform2D transform2D) public AABB AABB(Transform2D transform2D)
{ {
return new AABB( return new AABB(
transform2D.Position.X - Radius * transform2D.Scale.X, transform2D.Position.X - (Radius * transform2D.Scale.X),
transform2D.Position.Y - Radius * transform2D.Scale.Y, transform2D.Position.Y - (Radius * transform2D.Scale.Y),
transform2D.Position.X + Radius * transform2D.Scale.X, transform2D.Position.X + (Radius * transform2D.Scale.X),
transform2D.Position.Y + Radius * transform2D.Scale.Y transform2D.Position.Y + (Radius * transform2D.Scale.Y)
); );
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is Circle other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Circle circle) return other is Circle circle && Equals(circle);
{
return Radius == circle.Radius;
} }
return false; public bool Equals(Circle other)
{
return Radius == other.Radius;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return 598075851 + Radius.GetHashCode(); return HashCode.Combine(Radius);
} }
public static bool operator ==(Circle a, Circle b) public static bool operator ==(Circle a, Circle b)

View File

@ -8,7 +8,7 @@ namespace MoonTools.Core.Bonk
/// <summary> /// <summary>
/// A line is a shape defined by exactly two points in space. /// A line is a shape defined by exactly two points in space.
/// </summary> /// </summary>
public struct Line : IShape2D, IEquatable<IShape2D> public struct Line : IShape2D, IEquatable<Line>
{ {
private Position2D v0; private Position2D v0;
private Position2D v1; private Position2D v1;
@ -18,7 +18,7 @@ namespace MoonTools.Core.Bonk
get get
{ {
yield return v0; yield return v0;
yield return v0; yield return v1;
} }
} }
@ -44,31 +44,22 @@ namespace MoonTools.Core.Bonk
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is IShape2D other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Line otherLine) return other is Line otherLine && Equals(otherLine);
{
return (v0 == otherLine.v0 && v1 == otherLine.v1) || (v1 == otherLine.v0 && v0 == otherLine.v1);
} }
return false; public bool Equals(Line other)
{
return (v0 == other.v0 && v1 == other.v1) || (v1 == other.v0 && v0 == other.v1);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
var hashCode = -851829407; return HashCode.Combine(v0, v1);
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v0);
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v1);
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
return hashCode;
} }
public static bool operator ==(Line a, Line b) public static bool operator ==(Line a, Line b)

View File

@ -5,7 +5,7 @@ using MoonTools.Core.Structs;
namespace MoonTools.Core.Bonk namespace MoonTools.Core.Bonk
{ {
public struct Point : IShape2D, IEquatable<IShape2D> public struct Point : IShape2D, IEquatable<Point>
{ {
private Position2D position; private Position2D position;
@ -31,22 +31,17 @@ namespace MoonTools.Core.Bonk
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is IShape2D other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Point otherPoint) return other is Point otherPoint && Equals(otherPoint);
{
return position == otherPoint.position;
} }
return false; public bool Equals(Point other)
{
return position == other.position;
} }
public override int GetHashCode() public override int GetHashCode()

View File

@ -12,16 +12,18 @@ namespace MoonTools.Core.Bonk
/// A Shape defined by an arbitrary collection of vertices. /// A Shape defined by an arbitrary collection of vertices.
/// NOTE: A Polygon must have more than 2 vertices, be convex, and should not have duplicate vertices. /// NOTE: A Polygon must have more than 2 vertices, be convex, and should not have duplicate vertices.
/// </summary> /// </summary>
public struct Polygon : IShape2D, IEquatable<IShape2D> public struct Polygon : IShape2D, IEquatable<Polygon>
{ {
private ImmutableArray<Position2D> vertices; private ImmutableArray<Position2D> vertices;
public IEnumerable<Position2D> Vertices { get { return vertices == null ? Enumerable.Empty<Position2D>() : vertices; } } public IEnumerable<Position2D> Vertices { get { return vertices; } }
public int VertexCount { get { return vertices.Length; } }
// vertices are local to the origin // vertices are local to the origin
public Polygon(params Position2D[] vertices) // TODO: remove this, params is bad because it allocates an array public Polygon(IEnumerable<Position2D> vertices) // TODO: remove this, params is bad because it allocates an array
{ {
this.vertices = ImmutableArray.Create<Position2D>(vertices); this.vertices = vertices.ToImmutableArray();
} }
public Polygon(ImmutableArray<Position2D> vertices) public Polygon(ImmutableArray<Position2D> vertices)
@ -41,39 +43,31 @@ namespace MoonTools.Core.Bonk
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is IShape2D other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Polygon otherPolygon) return (other is Polygon otherPolygon && Equals(otherPolygon)) || (other is Rectangle rectangle && Equals(rectangle));
{
var q = from a in vertices
join b in otherPolygon.vertices on a equals b
select a;
return vertices.Length == otherPolygon.vertices.Length && q.Count() == vertices.Length;
}
else if (other is Rectangle rectangle)
{
var q = from a in vertices
join b in rectangle.Vertices on a equals b
select a;
return vertices.Length == 4 && q.Count() == vertices.Length;
} }
return false; public bool Equals(Polygon other)
{
var q = from a in vertices
join b in other.Vertices on a equals b
select a;
return vertices.Length == other.VertexCount && q.Count() == vertices.Length;
}
public bool Equals(Rectangle rectangle)
{
return RectanglePolygonComparison.Equals(this, rectangle);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return HashCode.Combine(vertices, Vertices); return HashCode.Combine(Vertices);
} }
public static bool operator ==(Polygon a, Polygon b) public static bool operator ==(Polygon a, Polygon b)

View File

@ -10,7 +10,7 @@ namespace MoonTools.Core.Bonk
/// <summary> /// <summary>
/// A rectangle is a shape defined by a minimum and maximum X value and a minimum and maximum Y value. /// A rectangle is a shape defined by a minimum and maximum X value and a minimum and maximum Y value.
/// </summary> /// </summary>
public struct Rectangle : IShape2D, IEquatable<IShape2D> public struct Rectangle : IShape2D, IEquatable<Rectangle>
{ {
public int MinX { get; } public int MinX { get; }
public int MinY { get; } public int MinY { get; }
@ -48,36 +48,30 @@ namespace MoonTools.Core.Bonk
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is IShape2D other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Rectangle rectangle) return (other is Rectangle rectangle && Equals(rectangle)) || (other is Polygon polygon && Equals(polygon));
{
return MinX == rectangle.MinX &&
MinY == rectangle.MinY &&
MaxX == rectangle.MaxX &&
MaxY == rectangle.MaxY;
} }
return false; public bool Equals(Rectangle other)
{
return MinX == other.MinX &&
MinY == other.MinY &&
MaxX == other.MaxX &&
MaxY == other.MaxY;
}
public bool Equals(Polygon other)
{
return RectanglePolygonComparison.Equals(other, this);
} }
public override int GetHashCode() public override int GetHashCode()
{ {
var hashCode = -1260800952; return HashCode.Combine(MinX, MinY, MaxX, MaxY);
hashCode = hashCode * -1521134295 + MinX.GetHashCode();
hashCode = hashCode * -1521134295 + MinY.GetHashCode();
hashCode = hashCode * -1521134295 + MaxX.GetHashCode();
hashCode = hashCode * -1521134295 + MaxY.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
return hashCode;
} }
public static bool operator ==(Rectangle a, Rectangle b) public static bool operator ==(Rectangle a, Rectangle b)

View File

@ -0,0 +1,16 @@
using System.Linq;
namespace MoonTools.Core.Bonk
{
internal static class RectanglePolygonComparison
{
public static bool Equals(Polygon polygon, Rectangle rectangle)
{
var q = from a in polygon.Vertices
join b in rectangle.Vertices on a equals b
select a;
return polygon.VertexCount == 4 && q.Count() == 4;
}
}
}

View File

@ -3,17 +3,18 @@ using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using MoonTools.Core.Structs; using MoonTools.Core.Structs;
using MoreLinq; using MoreLinq;
using System;
namespace MoonTools.Core.Bonk namespace MoonTools.Core.Bonk
{ {
/// <summary> /// <summary>
/// A simplex is a shape with up to n - 2 vertices in the nth dimension. /// A simplex is a shape with up to n - 2 vertices in the nth dimension.
/// </summary> /// </summary>
public struct Simplex2D : IShape2D public struct Simplex2D : IShape2D, IEquatable<Simplex2D>
{ {
Vector2 a; private Vector2 a;
Vector2? b; private Vector2? b;
Vector2? c; private Vector2? c;
public Vector2 A => a; public Vector2 A => a;
public Vector2? B => b; public Vector2? B => b;
@ -28,15 +29,15 @@ namespace MoonTools.Core.Bonk
public Simplex2D(Vector2 a) public Simplex2D(Vector2 a)
{ {
this.a = a; this.a = a;
this.b = null; b = null;
this.c = null; c = null;
} }
public Simplex2D(Vector2 a, Vector2 b) public Simplex2D(Vector2 a, Vector2 b)
{ {
this.a = a; this.a = a;
this.b = b; this.b = b;
this.c = null; c = null;
} }
public Simplex2D(Vector2 a, Vector2 b, Vector2 c) public Simplex2D(Vector2 a, Vector2 b, Vector2 c)
@ -73,36 +74,26 @@ namespace MoonTools.Core.Bonk
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj is IShape2D other) return obj is IShape2D other && Equals(other);
{
return Equals(other);
}
return false;
} }
public bool Equals(IShape2D other) public bool Equals(IShape2D other)
{ {
if (other is Simplex2D otherSimplex) return other is Simplex2D otherSimplex && Equals(otherSimplex);
{
if (Count != otherSimplex.Count) { return false; }
return Vertices.Intersect(otherSimplex.Vertices).Count() == Count;
} }
return false; public bool Equals(Simplex2D other)
{
var q = from a in Vertices
join b in other.Vertices on a equals b
select a;
return Count == other.Count && q.Count() == Count;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
var hashCode = -495772172; return HashCode.Combine(Vertices);
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(a);
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(b);
hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(c);
hashCode = hashCode * -1521134295 + ZeroSimplex.GetHashCode();
hashCode = hashCode * -1521134295 + OneSimplex.GetHashCode();
hashCode = hashCode * -1521134295 + TwoSimplex.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
return hashCode;
} }
public static bool operator ==(Simplex2D a, Simplex2D b) public static bool operator ==(Simplex2D a, Simplex2D b)

View File

@ -27,7 +27,7 @@ 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 var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
GJK2D.TestCollision(squareA, movedTransform, squareB, transformB).Should().BeFalse(); GJK2D.TestCollision(squareA, movedTransform, squareB, transformB).Should().BeFalse();
} }
@ -46,13 +46,13 @@ namespace Tests
var intersection = EPA2D.Intersect(circleA, transformA, circleB, transformB, simplex); var intersection = EPA2D.Intersect(circleA, transformA, circleB, transformB, simplex);
var ix = circleA.Radius * (float)Math.Cos(Math.PI / 4) - (circleB.Radius * (float)Math.Cos(5 * Math.PI / 4) + transformB.Position.X); var ix = (circleA.Radius * (float)Math.Cos(Math.PI / 4)) - ((circleB.Radius * (float)Math.Cos(5 * Math.PI / 4)) + transformB.Position.X);
var iy = circleA.Radius * (float)Math.Sin(Math.PI / 4) - (circleB.Radius * (float)Math.Sin(5 * Math.PI / 4) + transformB.Position.Y); var iy = (circleA.Radius * (float)Math.Sin(Math.PI / 4)) - ((circleB.Radius * (float)Math.Sin(5 * Math.PI / 4)) + transformB.Position.Y);
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 var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
GJK2D.TestCollision(circleA, movedTransform, circleB, transformB).Should().BeFalse(); GJK2D.TestCollision(circleA, movedTransform, circleB, transformB).Should().BeFalse();
} }
@ -71,7 +71,7 @@ namespace Tests
var intersection = EPA2D.Intersect(line, transformA, square, transformB, simplex); var intersection = EPA2D.Intersect(line, transformA, square, transformB, simplex);
var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
GJK2D.TestCollision(line, movedTransform, square, transformB).Should().BeFalse(); GJK2D.TestCollision(line, movedTransform, square, transformB).Should().BeFalse();
} }

View File

@ -4,10 +4,11 @@ using FluentAssertions;
using MoonTools.Core.Bonk; using MoonTools.Core.Bonk;
using MoonTools.Core.Structs; using MoonTools.Core.Structs;
using System.Numerics; using System.Numerics;
using System.Collections.Immutable;
namespace Tests namespace Tests
{ {
public class EqualityTests public static class EqualityTests
{ {
public class PointTests public class PointTests
{ {
@ -148,8 +149,8 @@ namespace Tests
[Test] [Test]
public void RectangleEqual() public void RectangleEqual()
{ {
var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var a = new Rectangle(0, 0, 3, 3);
var b = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var b = new Rectangle(0, 0, 3, 3);
a.Equals(b).Should().BeTrue(); a.Equals(b).Should().BeTrue();
} }
@ -157,8 +158,8 @@ namespace Tests
[Test] [Test]
public void RectangleEqualOperator() public void RectangleEqualOperator()
{ {
var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var a = new Rectangle(0, 0, 3, 3);
var b = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var b = new Rectangle(0, 0, 3, 3);
(a == b).Should().BeTrue(); (a == b).Should().BeTrue();
} }
@ -166,8 +167,8 @@ namespace Tests
[Test] [Test]
public void RectangleNotEqual() public void RectangleNotEqual()
{ {
var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var a = new Rectangle(0, 0, 3, 3);
var b = new MoonTools.Core.Bonk.Rectangle(-1, -1, 5, 5); var b = new Rectangle(-1, -1, 5, 5);
a.Equals(b).Should().BeFalse(); a.Equals(b).Should().BeFalse();
} }
@ -175,8 +176,8 @@ namespace Tests
[Test] [Test]
public void RectangleNotEqualOperator() public void RectangleNotEqualOperator()
{ {
var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3); var a = new Rectangle(0, 0, 3, 3);
var b = new MoonTools.Core.Bonk.Rectangle(-1, -1, 5, 5); var b = new Rectangle(-1, -1, 5, 5);
(a != b).Should().BeTrue(); (a != b).Should().BeTrue();
} }
@ -187,17 +188,17 @@ namespace Tests
[Test] [Test]
public void PolygonEqual() public void PolygonEqual()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
a.Equals(b).Should().BeTrue(); a.Equals(b).Should().BeTrue();
} }
@ -205,17 +206,17 @@ namespace Tests
[Test] [Test]
public void PolygonEqualOperator() public void PolygonEqualOperator()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
(a == b).Should().BeTrue(); (a == b).Should().BeTrue();
} }
@ -223,17 +224,17 @@ namespace Tests
[Test] [Test]
public void PolygonDifferentOrderEqual() public void PolygonDifferentOrderEqual()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(0, 1) new Position2D(0, 1)
); ));
a.Equals(b).Should().BeTrue(); a.Equals(b).Should().BeTrue();
} }
@ -241,17 +242,17 @@ namespace Tests
[Test] [Test]
public void PolygonDifferentOrderEqualOperator() public void PolygonDifferentOrderEqualOperator()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(0, 1) new Position2D(0, 1)
); ));
(a == b).Should().BeTrue(); (a == b).Should().BeTrue();
} }
@ -259,17 +260,17 @@ namespace Tests
[Test] [Test]
public void PolygonNotEqual() public void PolygonNotEqual()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(1, 0), new Position2D(1, 0),
new Position2D(2, 1), new Position2D(2, 1),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
a.Equals(b).Should().BeFalse(); a.Equals(b).Should().BeFalse();
} }
@ -277,17 +278,17 @@ namespace Tests
[Test] [Test]
public void PolygonNotEqualOperator() public void PolygonNotEqualOperator()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(0, 1), new Position2D(0, 1),
new Position2D(1, 2), new Position2D(1, 2),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
var b = new Polygon( var b = new Polygon(ImmutableArray.Create(
new Position2D(1, 0), new Position2D(1, 0),
new Position2D(2, 1), new Position2D(2, 1),
new Position2D(-1, -1) new Position2D(-1, -1)
); ));
(a != b).Should().BeTrue(); (a != b).Should().BeTrue();
} }
@ -295,12 +296,12 @@ namespace Tests
[Test] [Test]
public void PolygonRectangleEqual() public void PolygonRectangleEqual()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(1, 1), new Position2D(1, 1),
new Position2D(1, -1), new Position2D(1, -1),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(-1, 1) new Position2D(-1, 1)
); ));
var b = new Rectangle(-1, -1, 1, 1); var b = new Rectangle(-1, -1, 1, 1);
@ -310,12 +311,12 @@ namespace Tests
[Test] [Test]
public void PolygonRectangleNotEqual() public void PolygonRectangleNotEqual()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(2, 1), new Position2D(2, 1),
new Position2D(1, -1), new Position2D(1, -1),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(-2, 1) new Position2D(-2, 1)
); ));
var b = new Rectangle(-1, -1, 1, 1); var b = new Rectangle(-1, -1, 1, 1);
@ -325,12 +326,12 @@ namespace Tests
[Test] [Test]
public void PolygonRectangleEqualOperator() public void PolygonRectangleEqualOperator()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(1, 1), new Position2D(1, 1),
new Position2D(1, -1), new Position2D(1, -1),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(-1, 1) new Position2D(-1, 1)
); ));
var b = new Rectangle(-1, -1, 1, 1); var b = new Rectangle(-1, -1, 1, 1);
@ -340,12 +341,12 @@ namespace Tests
[Test] [Test]
public void PolygonRectangleNotEqualOperator() public void PolygonRectangleNotEqualOperator()
{ {
var a = new Polygon( var a = new Polygon(ImmutableArray.Create(
new Position2D(2, 1), new Position2D(2, 1),
new Position2D(1, -1), new Position2D(1, -1),
new Position2D(-1, -1), new Position2D(-1, -1),
new Position2D(-2, 1) new Position2D(-2, 1)
); ));
var b = new Rectangle(-1, -1, 1, 1); var b = new Rectangle(-1, -1, 1, 1);
@ -515,5 +516,26 @@ namespace Tests
(simplexC == simplexD).Should().BeFalse(); (simplexC == simplexD).Should().BeFalse();
} }
} }
public class AABBTests
{
[Test]
public void Equal()
{
var aabb = new AABB(0, 0, 3, 3);
var other = new AABB(0, 0, 3, 3);
(aabb == other).Should().BeTrue();
}
[Test]
public void NotEqual()
{
var aabb = new AABB(0, 0, 3, 3);
var other = new AABB(0, 0, 6, 6);
(aabb != other).Should().BeTrue();
}
}
} }
} }

View File

@ -3,6 +3,7 @@ using MoonTools.Core.Bonk;
using MoonTools.Core.Structs; using MoonTools.Core.Structs;
using System.Numerics; using System.Numerics;
using FluentAssertions; using FluentAssertions;
using System.Collections.Immutable;
namespace Tests namespace Tests
{ {
@ -15,7 +16,7 @@ namespace Tests
var pointTransform = new Transform2D(new Position2D(4, 4)); var pointTransform = new Transform2D(new Position2D(4, 4));
var line = new Line(new Position2D(-2, -2), new Position2D(2, 2)); var line = new Line(new Position2D(-2, -2), new Position2D(2, 2));
GJK2D.TestCollision(point, Transform2D.DefaultTransform, line, Transform2D.DefaultTransform).Should().BeTrue(); GJK2D.TestCollision(point, pointTransform, line, Transform2D.DefaultTransform).Should().BeTrue();
} }
[Test] [Test]
@ -71,12 +72,12 @@ namespace Tests
public void PointPolygonOverlapping() public void PointPolygonOverlapping()
{ {
var point = new Point(1, 1); var point = new Point(1, 1);
var polygon = new Polygon( var polygon = new Polygon(ImmutableArray.Create(
new Position2D(-2, -2), new Position2D(-2, -2),
new Position2D(-3, 2), new Position2D(-3, 2),
new Position2D(3, 2), new Position2D(3, 2),
new Position2D(3, -2) new Position2D(3, -2)
); ));
GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeTrue(); GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeTrue();
} }
@ -85,12 +86,12 @@ namespace Tests
public void PointPolygonNotOverlapping() public void PointPolygonNotOverlapping()
{ {
var point = new Point(5, 5); var point = new Point(5, 5);
var polygon = new Polygon( var polygon = new Polygon(ImmutableArray.Create(
new Position2D(-2, -2), new Position2D(-2, -2),
new Position2D(-3, 2), new Position2D(-3, 2),
new Position2D(3, 2), new Position2D(3, 2),
new Position2D(3, -2) new Position2D(3, -2)
); ));
GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeFalse(); GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeFalse();
} }
@ -182,17 +183,17 @@ namespace Tests
[Test] [Test]
public void PolygonPolygonOverlapping() public void PolygonPolygonOverlapping()
{ {
var shapeA = new Polygon( var shapeA = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var shapeB = new Polygon( var shapeB = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformB = new Transform2D(new Vector2(0.5f, 0.5f)); var transformB = new Transform2D(new Vector2(0.5f, 0.5f));
@ -202,17 +203,17 @@ namespace Tests
[Test] [Test]
public void ScaledPolygonsOverlapping() public void ScaledPolygonsOverlapping()
{ {
var shapeA = new Polygon( var shapeA = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var shapeB = new Polygon( var shapeB = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformB = new Transform2D(new Vector2(3f, 0f), 0f, new Vector2(3f, 3f)); var transformB = new Transform2D(new Vector2(3f, 0f), 0f, new Vector2(3f, 3f));
@ -222,17 +223,17 @@ namespace Tests
[Test] [Test]
public void PolygonPolygonNotOverlapping() public void PolygonPolygonNotOverlapping()
{ {
var shapeA = new Polygon( var shapeA = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var shapeB = new Polygon( var shapeB = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformB = new Transform2D(new Vector2(5, 0)); var transformB = new Transform2D(new Vector2(5, 0));
@ -242,17 +243,17 @@ namespace Tests
[Test] [Test]
public void ScaledPolygonsNotOverlapping() public void ScaledPolygonsNotOverlapping()
{ {
var shapeA = new Polygon( var shapeA = new Polygon(ImmutableArray.Create(
new Position2D(-1, 1), new Position2D(1, 1), new Position2D(-1, 1), new Position2D(1, 1),
new Position2D(-1, -1), new Position2D(1, -1) new Position2D(-1, -1), new Position2D(1, -1)
); ));
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var shapeB = new Polygon( var shapeB = new Polygon(ImmutableArray.Create(
new Position2D(-2, 2), new Position2D(2, 2), new Position2D(-2, 2), new Position2D(2, 2),
new Position2D(-2, -2), new Position2D(2, -2) new Position2D(-2, -2), new Position2D(2, -2)
); ));
var transformB = new Transform2D(new Vector2(3f, 0), 0f, new Vector2(0.5f, 0.5f)); var transformB = new Transform2D(new Vector2(3f, 0), 0f, new Vector2(0.5f, 0.5f));
@ -266,10 +267,10 @@ namespace Tests
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var polygon = new Polygon( var polygon = new Polygon(ImmutableArray.Create(
new Position2D(-1, -1), new Position2D(1, -1), new Position2D(-1, -1), new Position2D(1, -1),
new Position2D(1, 1), new Position2D(-1, 1) new Position2D(1, 1), new Position2D(-1, 1)
); ));
var transformB = Transform2D.DefaultTransform; var transformB = Transform2D.DefaultTransform;
@ -283,10 +284,10 @@ namespace Tests
var transformA = Transform2D.DefaultTransform; var transformA = Transform2D.DefaultTransform;
var polygon = new Polygon( var polygon = new Polygon(ImmutableArray.Create(
new Position2D(-1, -1), new Position2D(1, -1), new Position2D(-1, -1), new Position2D(1, -1),
new Position2D(1, 1), new Position2D(-1, 1) new Position2D(1, 1), new Position2D(-1, 1)
); ));
var transformB = Transform2D.DefaultTransform; var transformB = Transform2D.DefaultTransform;
@ -321,10 +322,10 @@ namespace Tests
var circle = new Circle(1); var circle = new Circle(1);
var transformA = new Transform2D(new Vector2(0.25f, 0)); var transformA = new Transform2D(new Vector2(0.25f, 0));
var square = new Polygon( var square = new Polygon(ImmutableArray.Create(
new Position2D(-1, -1), new Position2D(1, -1), new Position2D(-1, -1), new Position2D(1, -1),
new Position2D(1, 1), new Position2D(-1, 1) new Position2D(1, 1), new Position2D(-1, 1)
); ));
var transformB = Transform2D.DefaultTransform; var transformB = Transform2D.DefaultTransform;
@ -337,10 +338,10 @@ namespace Tests
var circle = new Circle(1); var circle = new Circle(1);
var circleTransform = new Transform2D(new Vector2(5, 0)); var circleTransform = new Transform2D(new Vector2(5, 0));
var square = new Polygon( var square = new Polygon(ImmutableArray.Create(
new Position2D(-1, -1), new Position2D(1, -1), new Position2D(-1, -1), new Position2D(1, -1),
new Position2D(1, 1), new Position2D(-1, 1) new Position2D(1, 1), new Position2D(-1, 1)
); ));
var squareTransform = Transform2D.DefaultTransform; var squareTransform = Transform2D.DefaultTransform;
GJK2D.TestCollision(circle, circleTransform, square, squareTransform).Should().BeFalse(); GJK2D.TestCollision(circle, circleTransform, square, squareTransform).Should().BeFalse();