polygon with immutable array
parent
b1a3e37a9d
commit
1430047327
|
@ -17,6 +17,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MoonTools.Core.Structs" Version="2.0.0"/>
|
<PackageReference Include="MoonTools.Core.Structs" Version="2.0.0"/>
|
||||||
<PackageReference Include="morelinq" Version="3.2.0"/>
|
<PackageReference Include="morelinq" Version="3.2.0"/>
|
||||||
<PackageReference Include="Collections.Pooled" Version="1.0.82"/>
|
<PackageReference Include="System.Collections.Immutable" Version="1.6.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -4,9 +4,10 @@
|
||||||
* https://blog.hamaluik.ca/posts/building-a-collision-engine-part-2-2d-penetration-vectors/
|
* https://blog.hamaluik.ca/posts/building-a-collision-engine-part-2-2d-penetration-vectors/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Collections.Pooled;
|
|
||||||
using MoonTools.Core.Structs;
|
using MoonTools.Core.Structs;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace MoonTools.Core.Bonk
|
namespace MoonTools.Core.Bonk
|
||||||
|
@ -26,12 +27,7 @@ namespace MoonTools.Core.Bonk
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex2D 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 = simplex.Vertices.Select(vertex => vertex.ToVector2()).ToImmutableArray();
|
||||||
|
|
||||||
foreach (var vertex in simplex.Vertices)
|
|
||||||
{
|
|
||||||
simplexVertices.Add(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
var e0 = (simplexVertices[1].X - simplexVertices[0].X) * (simplexVertices[1].Y + simplexVertices[0].Y);
|
var e0 = (simplexVertices[1].X - simplexVertices[0].X) * (simplexVertices[1].Y + simplexVertices[0].Y);
|
||||||
var e1 = (simplexVertices[2].X - simplexVertices[1].X) * (simplexVertices[2].Y + simplexVertices[1].Y);
|
var e1 = (simplexVertices[2].X - simplexVertices[1].X) * (simplexVertices[2].Y + simplexVertices[1].Y);
|
||||||
|
@ -55,25 +51,23 @@ namespace MoonTools.Core.Bonk
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
simplexVertices.Insert(edge.index, support);
|
simplexVertices = simplexVertices.Insert(edge.index, support);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simplexVertices.Dispose();
|
|
||||||
|
|
||||||
return intersection;
|
return intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Edge FindClosestEdge(PolygonWinding winding, PooledList<Vector2> simplexVertices)
|
private static Edge FindClosestEdge(PolygonWinding winding, ImmutableArray<Vector2> simplexVertices)
|
||||||
{
|
{
|
||||||
var closestDistance = float.PositiveInfinity;
|
var closestDistance = float.PositiveInfinity;
|
||||||
var closestNormal = Vector2.Zero;
|
var closestNormal = Vector2.Zero;
|
||||||
var closestIndex = 0;
|
var closestIndex = 0;
|
||||||
|
|
||||||
for (int i = 0; i < simplexVertices.Count; i++)
|
for (int i = 0; i < simplexVertices.Length; i++)
|
||||||
{
|
{
|
||||||
var j = i + 1;
|
var j = i + 1;
|
||||||
if (j >= simplexVertices.Count) { j = 0; }
|
if (j >= simplexVertices.Length) { j = 0; }
|
||||||
Vector2 edge = simplexVertices[j] - simplexVertices[i];
|
Vector2 edge = simplexVertices[j] - simplexVertices[i];
|
||||||
|
|
||||||
Vector2 norm;
|
Vector2 norm;
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MoonTools.Core.Bonk
|
||||||
private Position2D v0;
|
private Position2D v0;
|
||||||
private Position2D v1;
|
private Position2D v1;
|
||||||
|
|
||||||
private IEnumerable<Position2D> vertices
|
private IEnumerable<Position2D> Vertices
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public AABB AABB(Transform2D Transform2D)
|
public AABB AABB(Transform2D Transform2D)
|
||||||
{
|
{
|
||||||
return Bonk.AABB.FromTransformedVertices(vertices, Transform2D);
|
return Bonk.AABB.FromTransformedVertices(Vertices, Transform2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
|
@ -67,7 +67,7 @@ namespace MoonTools.Core.Bonk
|
||||||
var hashCode = -851829407;
|
var hashCode = -851829407;
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v0);
|
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v0);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v1);
|
hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v1);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(vertices);
|
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Collections.Pooled;
|
|
||||||
using MoonTools.Core.Structs;
|
using MoonTools.Core.Structs;
|
||||||
using MoreLinq;
|
using MoreLinq;
|
||||||
|
|
||||||
namespace MoonTools.Core.Bonk
|
namespace MoonTools.Core.Bonk
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A Shape defined by an arbitrary collection of vertices. WARNING: Polygon must use an Array internally and therefore will create GC pressure.
|
/// A Shape defined by an arbitrary collection of vertices.
|
||||||
|
/// NOTE: A Polygon must have more than 2 vertices and should not have duplicate vertices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct Polygon : IShape2D, IEquatable<IShape2D>
|
public struct Polygon : IShape2D, IEquatable<IShape2D>
|
||||||
{
|
{
|
||||||
private PooledSet<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 == null ? Enumerable.Empty<Position2D>() : vertices; } }
|
||||||
|
|
||||||
// vertices are local to the origin
|
// vertices are local to the origin
|
||||||
public Polygon(params Position2D[] vertices)
|
public Polygon(params Position2D[] vertices)
|
||||||
{
|
{
|
||||||
this.vertices = new PooledSet<Position2D>(vertices, ClearMode.Always);
|
this.vertices = ImmutableArray.Create<Position2D>(vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Polygon(ImmutableArray<Position2D> vertices)
|
||||||
|
{
|
||||||
|
this.vertices = vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 Support(Vector2 direction, Transform2D transform)
|
public Vector2 Support(Vector2 direction, Transform2D transform)
|
||||||
|
@ -47,7 +53,19 @@ namespace MoonTools.Core.Bonk
|
||||||
{
|
{
|
||||||
if (other is Polygon otherPolygon)
|
if (other is Polygon otherPolygon)
|
||||||
{
|
{
|
||||||
return vertices.SetEquals(otherPolygon.vertices);
|
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;
|
return false;
|
||||||
|
@ -55,10 +73,7 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
var hashCode = -1404792980;
|
return HashCode.Combine(vertices, Vertices);
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<PooledSet<Position2D>>.Default.GetHashCode(vertices);
|
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
|
|
||||||
return hashCode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(Polygon a, Polygon b)
|
public static bool operator ==(Polygon a, Polygon b)
|
||||||
|
@ -70,5 +85,15 @@ namespace MoonTools.Core.Bonk
|
||||||
{
|
{
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Polygon a, Rectangle b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Polygon a, Rectangle b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace MoonTools.Core.Bonk
|
||||||
public int MaxX { get; }
|
public int MaxX { get; }
|
||||||
public int MaxY { get; }
|
public int MaxY { get; }
|
||||||
|
|
||||||
private IEnumerable<Position2D> vertices
|
public IEnumerable<Position2D> Vertices
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -38,12 +38,12 @@ namespace MoonTools.Core.Bonk
|
||||||
|
|
||||||
public Vector2 Support(Vector2 direction, Transform2D transform)
|
public Vector2 Support(Vector2 direction, Transform2D transform)
|
||||||
{
|
{
|
||||||
return vertices.Select(vertex => Vector2.Transform(vertex, transform.TransformMatrix)).MaxBy(transformed => Vector2.Dot(transformed, direction)).First();
|
return Vertices.Select(vertex => Vector2.Transform(vertex, transform.TransformMatrix)).MaxBy(transformed => Vector2.Dot(transformed, direction)).First();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AABB AABB(Transform2D Transform2D)
|
public AABB AABB(Transform2D Transform2D)
|
||||||
{
|
{
|
||||||
return Bonk.AABB.FromTransformedVertices(vertices, Transform2D);
|
return Bonk.AABB.FromTransformedVertices(Vertices, Transform2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
|
@ -76,7 +76,7 @@ namespace MoonTools.Core.Bonk
|
||||||
hashCode = hashCode * -1521134295 + MinY.GetHashCode();
|
hashCode = hashCode * -1521134295 + MinY.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + MaxX.GetHashCode();
|
hashCode = hashCode * -1521134295 + MaxX.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + MaxY.GetHashCode();
|
hashCode = hashCode * -1521134295 + MaxY.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(vertices);
|
hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,66 @@ namespace Tests
|
||||||
|
|
||||||
(a != b).Should().BeTrue();
|
(a != b).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PolygonRectangleEqual()
|
||||||
|
{
|
||||||
|
var a = new Polygon(
|
||||||
|
new Position2D(1, 1),
|
||||||
|
new Position2D(1, -1),
|
||||||
|
new Position2D(-1, -1),
|
||||||
|
new Position2D(-1, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
var b = new Rectangle(-1, -1, 1, 1);
|
||||||
|
|
||||||
|
a.Should().BeEquivalentTo(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PolygonRectangleNotEqual()
|
||||||
|
{
|
||||||
|
var a = new Polygon(
|
||||||
|
new Position2D(2, 1),
|
||||||
|
new Position2D(1, -1),
|
||||||
|
new Position2D(-1, -1),
|
||||||
|
new Position2D(-2, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
var b = new Rectangle(-1, -1, 1, 1);
|
||||||
|
|
||||||
|
a.Should().NotBeEquivalentTo(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PolygonRectangleEqualOperator()
|
||||||
|
{
|
||||||
|
var a = new Polygon(
|
||||||
|
new Position2D(1, 1),
|
||||||
|
new Position2D(1, -1),
|
||||||
|
new Position2D(-1, -1),
|
||||||
|
new Position2D(-1, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
var b = new Rectangle(-1, -1, 1, 1);
|
||||||
|
|
||||||
|
(a == b).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PolygonRectangleNotEqualOperator()
|
||||||
|
{
|
||||||
|
var a = new Polygon(
|
||||||
|
new Position2D(2, 1),
|
||||||
|
new Position2D(1, -1),
|
||||||
|
new Position2D(-1, -1),
|
||||||
|
new Position2D(-2, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
var b = new Rectangle(-1, -1, 1, 1);
|
||||||
|
|
||||||
|
(a != b).Should().BeTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SimplexTests
|
public class SimplexTests
|
||||||
|
|
Loading…
Reference in New Issue