Merge remote-tracking branch 'origin/master' into optimization_merge
						commit
						1998612d6f
					
				
							
								
								
									
										22
									
								
								Bonk/AABB.cs
								
								
								
								
							
							
						
						
									
										22
									
								
								Bonk/AABB.cs
								
								
								
								
							|  | @ -8,13 +8,13 @@ namespace MoonTools.Core.Bonk | ||||||
| { | { | ||||||
|     public struct AABB |     public struct AABB | ||||||
|     { |     { | ||||||
|         public int MinX { get; private set; } |         public float MinX { get; private set; } | ||||||
|         public int MinY { get; private set; } |         public float MinY { get; private set; } | ||||||
|         public int MaxX { get; private set; } |         public float MaxX { get; private set; } | ||||||
|         public int MaxY { get; private set; } |         public float MaxY { get; private set; } | ||||||
| 
 | 
 | ||||||
|         public int Width { get { return MaxX - MinX; } } |         public float Width { get { return MaxX - MinX; } } | ||||||
|         public int Height { get { return MaxY - MinY; } } |         public float Height { get { return MaxY - MinY; } } | ||||||
| 
 | 
 | ||||||
|         public static AABB FromTransformedVertices(IEnumerable<Position2D> vertices, Transform2D transform) |         public static AABB FromTransformedVertices(IEnumerable<Position2D> vertices, Transform2D transform) | ||||||
|         { |         { | ||||||
|  | @ -22,14 +22,14 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|             return new AABB |             return new AABB | ||||||
|             { |             { | ||||||
|                 MinX = (int)Math.Round(TransformedVertices.Min(vertex => vertex.X)), |                 MinX = TransformedVertices.Min(vertex => vertex.X), | ||||||
|                 MinY = (int)Math.Round(TransformedVertices.Min(vertex => vertex.Y)), |                 MinY = TransformedVertices.Min(vertex => vertex.Y), | ||||||
|                 MaxX = (int)Math.Round(TransformedVertices.Max(vertex => vertex.X)), |                 MaxX = TransformedVertices.Max(vertex => vertex.X), | ||||||
|                 MaxY = (int)Math.Round(TransformedVertices.Max(vertex => vertex.Y)) |                 MaxY = TransformedVertices.Max(vertex => vertex.Y) | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public AABB(int minX, int minY, int maxX, int maxY) |         public AABB(float minX, float minY, float maxX, float maxY) | ||||||
|         { |         { | ||||||
|             MinX = minX; |             MinX = minX; | ||||||
|             MinY = minY; |             MinY = minY; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| <Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <Version>1.0.2</Version> |     <Version>1.1.0</Version> | ||||||
|     <TargetFramework>netstandard2.0</TargetFramework> |     <TargetFramework>netstandard2.0</TargetFramework> | ||||||
|     <Description>.NET Core Collision Detection for MonoGame</Description> |     <Description>.NET Core Collision Detection for MonoGame</Description> | ||||||
|     <PackageId>MoonTools.Core.Bonk</PackageId> |     <PackageId>MoonTools.Core.Bonk</PackageId> | ||||||
|  |  | ||||||
|  | @ -8,22 +8,22 @@ namespace MoonTools.Core.Bonk | ||||||
|     { |     { | ||||||
|         private readonly int cellSize; |         private readonly int cellSize; | ||||||
| 
 | 
 | ||||||
|         private readonly Dictionary<int, Dictionary<int, HashSet<(IShape2D, Transform2D)>>> hashDictionary = new Dictionary<int, Dictionary<int, HashSet<(IShape2D, Transform2D)>>>(); |         private readonly Dictionary<int, Dictionary<int, HashSet<T>>> hashDictionary = new Dictionary<int, Dictionary<int, HashSet<T>>>(); | ||||||
|         private readonly Dictionary<(IShape2D, Transform2D), T> IDLookup = new Dictionary<(IShape2D, Transform2D), T>(); |         private readonly Dictionary<T, (IShape2D, Transform2D)> IDLookup = new Dictionary<T, (IShape2D, Transform2D)>(); | ||||||
| 
 | 
 | ||||||
|         public SpatialHash(int cellSize) |         public SpatialHash(int cellSize) | ||||||
|         { |         { | ||||||
|             this.cellSize = cellSize; |             this.cellSize = cellSize; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private (int, int) Hash(int x, int y) |         private (int, int) Hash(float x, float y) | ||||||
|         { |         { | ||||||
|             return ((int)Math.Floor((float)x / cellSize), (int)Math.Floor((float)y / cellSize)); |             return ((int)Math.Floor(x / cellSize), (int)Math.Floor(y / cellSize)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Insert(T id, IShape2D shape, Transform2D Transform2D) |         public void Insert(T id, IShape2D shape, Transform2D transform2D) | ||||||
|         { |         { | ||||||
|             var box = shape.AABB(Transform2D); |             var box = shape.AABB(transform2D); | ||||||
|             var minHash = Hash(box.MinX, box.MinY); |             var minHash = Hash(box.MinX, box.MinY); | ||||||
|             var maxHash = Hash(box.MaxX, box.MaxY); |             var maxHash = Hash(box.MaxX, box.MaxY); | ||||||
| 
 | 
 | ||||||
|  | @ -33,23 +33,23 @@ namespace MoonTools.Core.Bonk | ||||||
|                 { |                 { | ||||||
|                     if (!hashDictionary.ContainsKey(i)) |                     if (!hashDictionary.ContainsKey(i)) | ||||||
|                     { |                     { | ||||||
|                         hashDictionary.Add(i, new Dictionary<int, HashSet<(IShape2D, Transform2D)>>()); |                         hashDictionary.Add(i, new Dictionary<int, HashSet<T>>()); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (!hashDictionary[i].ContainsKey(j)) |                     if (!hashDictionary[i].ContainsKey(j)) | ||||||
|                     { |                     { | ||||||
|                         hashDictionary[i].Add(j, new HashSet<(IShape2D, Transform2D)>()); |                         hashDictionary[i].Add(j, new HashSet<T>()); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     hashDictionary[i][j].Add((shape, Transform2D)); |                     hashDictionary[i][j].Add(id); | ||||||
|                     IDLookup[(shape, Transform2D)] = id; |                     IDLookup[id] = (shape, transform2D); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(T, IShape2D, Transform2D)> Retrieve(T id, IShape2D shape, Transform2D Transform2D) |         public IEnumerable<(T, IShape2D, Transform2D)> Retrieve(T id, IShape2D shape, Transform2D transform2D) | ||||||
|         { |         { | ||||||
|             var box = shape.AABB(Transform2D); |             var box = shape.AABB(transform2D); | ||||||
|             var minHash = Hash(box.MinX, box.MinY); |             var minHash = Hash(box.MinX, box.MinY); | ||||||
|             var maxHash = Hash(box.MaxX, box.MaxY); |             var maxHash = Hash(box.MaxX, box.MaxY); | ||||||
| 
 | 
 | ||||||
|  | @ -59,10 +59,10 @@ namespace MoonTools.Core.Bonk | ||||||
|                 { |                 { | ||||||
|                     if (hashDictionary.ContainsKey(i) && hashDictionary[i].ContainsKey(j)) |                     if (hashDictionary.ContainsKey(i) && hashDictionary[i].ContainsKey(j)) | ||||||
|                     { |                     { | ||||||
|                         foreach (var (otherShape, otherTransform2D) in hashDictionary[i][j]) |                         foreach (var t in hashDictionary[i][j]) | ||||||
|                         { |                         { | ||||||
|                             var otherID = IDLookup[(otherShape, otherTransform2D)]; |                             var (otherShape, otherTransform) = IDLookup[t]; | ||||||
|                             if (!id.Equals(otherID)) { yield return (otherID, otherShape, otherTransform2D); } |                             if (!id.Equals(t)) { yield return (t, otherShape, otherTransform); } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -18,13 +18,13 @@ namespace MoonTools.Core.Bonk | ||||||
|             return Vector2.Transform(Vector2.Normalize(direction) * Radius, transform.TransformMatrix); |             return Vector2.Transform(Vector2.Normalize(direction) * Radius, transform.TransformMatrix); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public AABB AABB(Transform2D Transform2D) |         public AABB AABB(Transform2D transform2D) | ||||||
|         { |         { | ||||||
|             return new AABB( |             return new AABB( | ||||||
|                 Transform2D.Position.X - Radius, |                 transform2D.Position.X - Radius * transform2D.Scale.X, | ||||||
|                 Transform2D.Position.Y - Radius, |                 transform2D.Position.Y - Radius * transform2D.Scale.Y, | ||||||
|                 Transform2D.Position.X + Radius, |                 transform2D.Position.X + Radius * transform2D.Scale.X, | ||||||
|                 Transform2D.Position.Y + Radius |                 transform2D.Position.Y + Radius * transform2D.Scale.Y | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | # MoonTools.Core.Bonk | ||||||
|  | .NET Core Collision Detection for MonoGame | ||||||
|  | 
 | ||||||
|  | ## Documentation | ||||||
|  | Detailed docs can be found here: https://moontools-docs.github.io/bonk/ | ||||||
|  | @ -17,6 +17,17 @@ namespace Tests | ||||||
|             GJK2D.TestCollision(lineA, Transform2D.DefaultTransform, lineB, Transform2D.DefaultTransform).Should().BeTrue(); |             GJK2D.TestCollision(lineA, Transform2D.DefaultTransform, lineB, Transform2D.DefaultTransform).Should().BeTrue(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledLinesOverlapping() | ||||||
|  |         { | ||||||
|  |             var lineA = new Line(new Position2D(-1, -1), new Position2D(1, 1)); | ||||||
|  |             var lineB = new Line(new Position2D(-1, 1), new Position2D(1, -1)); | ||||||
|  | 
 | ||||||
|  |             var transform = new Transform2D(new Position2D(0, 0), 0f, new Vector2(2, 2)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsTrue(GJK2D.TestCollision(lineA, transform, lineB, transform).Item1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void LineLineNotOverlapping() |         public void LineLineNotOverlapping() | ||||||
|         { |         { | ||||||
|  | @ -26,6 +37,17 @@ namespace Tests | ||||||
|             GJK2D.TestCollision(lineA, Transform2D.DefaultTransform, lineB, Transform2D.DefaultTransform).Should().BeFalse(); |             GJK2D.TestCollision(lineA, Transform2D.DefaultTransform, lineB, Transform2D.DefaultTransform).Should().BeFalse(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledLinesNotOverlapping() | ||||||
|  |         { | ||||||
|  |             var lineA = new Line(new Position2D(0, 1), new Position2D(1, 0)); | ||||||
|  |             var lineB = new Line(new Position2D(-1, -1), new Position2D(-2, -2)); | ||||||
|  | 
 | ||||||
|  |             var transform = new Transform2D(new Position2D(0, 0), 0f, new Vector2(2, 2)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsFalse(GJK2D.TestCollision(lineA, transform, lineB, transform).Item1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void CircleCircleOverlapping() |         public void CircleCircleOverlapping() | ||||||
|         { |         { | ||||||
|  | @ -37,6 +59,17 @@ namespace Tests | ||||||
|             Assert.IsTrue(GJK2D.TestCollision(circleA, transformA, circleB, transformB)); |             Assert.IsTrue(GJK2D.TestCollision(circleA, transformA, circleB, transformB)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledCirclesOverlapping() | ||||||
|  |         { | ||||||
|  |             var circleA = new Circle(2); | ||||||
|  |             var transformA = new Transform2D(new Vector2(-3, 0), 0f, new Vector2(2, 2)); | ||||||
|  |             var circleB = new Circle(2); | ||||||
|  |             var transformB = new Transform2D(new Vector2(3, 0), 0f, new Vector2(2, 2)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsTrue(GJK2D.TestCollision(circleA, transformA, circleB, transformB).Item1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void CircleCircleNotOverlapping() |         public void CircleCircleNotOverlapping() | ||||||
|         { |         { | ||||||
|  | @ -48,6 +81,17 @@ namespace Tests | ||||||
|             Assert.IsFalse(GJK2D.TestCollision(circleA, transformA, circleB, transformB)); |             Assert.IsFalse(GJK2D.TestCollision(circleA, transformA, circleB, transformB)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledCirclesNotOverlapping() | ||||||
|  |         { | ||||||
|  |             var circleA = new Circle(2); | ||||||
|  |             var transformA = new Transform2D(new Vector2(-5, -5), 0, new Vector2(0.2f, 0.2f)); | ||||||
|  |             var circleB = new Circle(2); | ||||||
|  |             var transformB = new Transform2D(new Vector2(5, 5), 0, new Vector2(0.2f, 0.2f)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsFalse(GJK2D.TestCollision(circleA, transformA, circleB, transformB).Item1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void PolygonPolygonOverlapping() |         public void PolygonPolygonOverlapping() | ||||||
|         { |         { | ||||||
|  | @ -68,6 +112,26 @@ namespace Tests | ||||||
|             Assert.IsTrue(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB)); |             Assert.IsTrue(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledPolygonsOverlapping() | ||||||
|  |         { | ||||||
|  |             var shapeA = new Polygon( | ||||||
|  |                 new Position2D(-1, 1), new Position2D(1, 1), | ||||||
|  |                 new Position2D(-1, -1), new Position2D(1, -1) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             var transformA = Transform2D.DefaultTransform; | ||||||
|  | 
 | ||||||
|  |             var shapeB = new Polygon( | ||||||
|  |                 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)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsTrue(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB).Item1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void PolygonPolygonNotOverlapping() |         public void PolygonPolygonNotOverlapping() | ||||||
|         { |         { | ||||||
|  | @ -88,6 +152,26 @@ namespace Tests | ||||||
|             Assert.IsFalse(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB)); |             Assert.IsFalse(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void ScaledPolygonsNotOverlapping() | ||||||
|  |         { | ||||||
|  |             var shapeA = new Polygon( | ||||||
|  |                 new Position2D(-1, 1), new Position2D(1, 1), | ||||||
|  |                 new Position2D(-1, -1), new Position2D(1, -1) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             var transformA = Transform2D.DefaultTransform; | ||||||
|  | 
 | ||||||
|  |             var shapeB = new Polygon( | ||||||
|  |                 new Position2D(-1, 1), new Position2D(1, 1), | ||||||
|  |                 new Position2D(-1, -1), new Position2D(1, -1) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             var transformB = new Transform2D(new Vector2(2f, 0), 0f, new Vector2(0.2f, 0.2f)); | ||||||
|  | 
 | ||||||
|  |             Assert.IsFalse(GJK2D.TestCollision(shapeA, transformA, shapeB, transformB).Item1);   | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void LinePolygonOverlapping() |         public void LinePolygonOverlapping() | ||||||
|         { |         { | ||||||
|  |  | ||||||
|  | @ -53,6 +53,27 @@ namespace Tests | ||||||
|             spatialHash.Retrieve(6, line, lineTransform).Should().Contain((4, circleA, circleATransform)).And.Contain((2, rectC, rectCTransform)); |             spatialHash.Retrieve(6, line, lineTransform).Should().Contain((4, circleA, circleATransform)).And.Contain((2, rectC, rectCTransform)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void InsertAndRetrieveSameValues() | ||||||
|  |         { | ||||||
|  |             var spatialHash = new SpatialHash<int>(16); | ||||||
|  | 
 | ||||||
|  |             var rectA = new MoonTools.Core.Bonk.Rectangle(-2, -2, 2, 2); | ||||||
|  |             var rectATransform = new Transform2D(new Vector2(-8, -8)); | ||||||
|  | 
 | ||||||
|  |             var rectB = new MoonTools.Core.Bonk.Rectangle(-2, -2, 2, 2); | ||||||
|  |             var rectBTransform = new Transform2D(new Vector2(-8, -8)); | ||||||
|  | 
 | ||||||
|  |             var rectC = new MoonTools.Core.Bonk.Rectangle(-1, -1, 1, 1); | ||||||
|  |             var rectCTransform = new Transform2D(new Vector2(-8, -8)); | ||||||
|  | 
 | ||||||
|  |             spatialHash.Insert(0, rectA, rectATransform); | ||||||
|  |             spatialHash.Insert(1, rectB, rectBTransform); | ||||||
|  |             spatialHash.Insert(2, rectC, rectCTransform); | ||||||
|  | 
 | ||||||
|  |             spatialHash.Retrieve(2, rectC, rectCTransform).Should().HaveCount(2); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void Clear() |         public void Clear() | ||||||
|         { |         { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue