From f62c855c373e2b6f8ef22c1c0c18c8a60c9128a1 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Tue, 31 Dec 2019 18:23:06 -0800 Subject: [PATCH] optimization for circle overlap + remove position data from point --- Bonk/NarrowPhase/NarrowPhase.cs | 52 ++++++++++++++++++++++++++++++++- Bonk/Shapes/Point.cs | 24 ++++----------- Test/Equality.cs | 23 +++++---------- Test/GJK2DTest.cs | 28 ++++++++++-------- Test/SpatialHashTest.cs | 8 ++--- 5 files changed, 84 insertions(+), 51 deletions(-) diff --git a/Bonk/NarrowPhase/NarrowPhase.cs b/Bonk/NarrowPhase/NarrowPhase.cs index 7cb65ca..4e7fc9a 100644 --- a/Bonk/NarrowPhase/NarrowPhase.cs +++ b/Bonk/NarrowPhase/NarrowPhase.cs @@ -65,11 +65,23 @@ namespace MoonTools.Core.Bonk { return TestRectangleOverlap(rectangleA, transformA, rectangleB, transformB); } + else if (shapeA is Point && shapeB is Rectangle && transformB.Rotation == 0) + { + return TestPointRectangleOverlap((Point)shapeA, transformA, (Rectangle)shapeB, transformB); + } + else if (shapeA is Rectangle && shapeB is Point && transformA.Rotation == 0) + { + return TestPointRectangleOverlap((Point)shapeB, transformB, (Rectangle)shapeA, transformA); + } + else if (shapeA is Circle circleA && shapeB is Circle circleB && transformA.Scale.X == transformA.Scale.Y && transformB.Scale.X == transformB.Scale.Y) + { + return TestCircleOverlap(circleA, transformA, circleB, transformB); + } return FindCollisionSimplex(shapeA, transformA, shapeB, transformB).Item1; } /// - /// Fast path for overlapping rectangles. If the transforms have non-zero rotation this will be inaccurate. + /// Fast path for axis-aligned rectangles. If the transforms have non-zero rotation this will be inaccurate. /// /// /// @@ -84,6 +96,44 @@ namespace MoonTools.Core.Bonk return firstAABB.Left <= secondAABB.Right && firstAABB.Right >= secondAABB.Left && firstAABB.Top <= secondAABB.Bottom && firstAABB.Bottom >= secondAABB.Top; } + /// + /// Fast path for overlapping point and axis-aligned rectangle. The rectangle transform must have non-zero rotation. + /// + /// + /// + /// + /// + /// + public static bool TestPointRectangleOverlap(Point point, Transform2D pointTransform, Rectangle rectangle, Transform2D rectangleTransform) + { + var transformedPoint = pointTransform.Position; + var AABB = rectangle.TransformedAABB(rectangleTransform); + + return transformedPoint.X >= AABB.Left && transformedPoint.X <= AABB.Right && transformedPoint.Y <= AABB.Bottom && transformedPoint.Y >= AABB.Top; + } + + /// + /// Fast path for overlapping circles. The circles must have uniform scaling. + /// + /// + /// + /// + /// + /// + public static bool TestCircleOverlap(Circle circleA, Transform2D transformA, Circle circleB, Transform2D transformB) + { + var radiusA = circleA.Radius * transformA.Scale.X; + var radiusB = circleB.Radius * transformB.Scale.Y; + + var centerA = transformA.Position; + var centerB = transformB.Position; + + var distanceSquared = (centerA - centerB).LengthSquared(); + var radiusSumSquared = (radiusA + radiusB) * (radiusA + radiusB); + + return distanceSquared <= radiusSumSquared; + } + /// /// 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. /// diff --git a/Bonk/Shapes/Point.cs b/Bonk/Shapes/Point.cs index eca1eee..79f8ee3 100644 --- a/Bonk/Shapes/Point.cs +++ b/Bonk/Shapes/Point.cs @@ -6,21 +6,9 @@ namespace MoonTools.Core.Bonk { public struct Point : IShape2D, IEquatable { - private Position2D _position; + private Position2D Position { get; } public AABB AABB { get; } - public Point(Position2D position) - { - _position = position; - AABB = new AABB(position, position); - } - - public Point(int x, int y) - { - _position = new Position2D(x, y); - AABB = new AABB(x, y, x, y); - } - public AABB TransformedAABB(Transform2D transform) { return AABB.Transformed(AABB, transform); @@ -28,7 +16,7 @@ namespace MoonTools.Core.Bonk public Vector2 Support(Vector2 direction, Transform2D transform) { - return Vector2.Transform(_position.ToVector2(), transform.TransformMatrix); + return Vector2.Transform(Position.ToVector2(), transform.TransformMatrix); } public override bool Equals(object obj) @@ -43,22 +31,22 @@ namespace MoonTools.Core.Bonk public bool Equals(Point other) { - return _position == other._position; + return Position == other.Position; } public override int GetHashCode() { - return HashCode.Combine(_position); + return HashCode.Combine(Position); } public static bool operator ==(Point a, Point b) { - return a.Equals(b); + return true; } public static bool operator !=(Point a, Point b) { - return !(a == b); + return false; } } } diff --git a/Test/Equality.cs b/Test/Equality.cs index 15fe666..bf303dd 100644 --- a/Test/Equality.cs +++ b/Test/Equality.cs @@ -15,36 +15,27 @@ namespace Tests [Test] public void PointEqual() { - var a = new Point(1, 1); - var b = new Point(1, 1); + var a = new Point(); + var b = new Point(); a.Equals(b).Should().BeTrue(); } - [Test] - public void PointNotEqual() - { - var a = new Point(1, 1); - var b = new Point(-1, 1); - - a.Equals(b).Should().BeFalse(); - } - [Test] public void PointEqualOperator() { - var a = new Point(1, 1); - var b = new Point(1, 1); + var a = new Point(); + var b = new Point(); (a == b).Should().BeTrue(); } [Test] public void PointNotEqualOperator() { - var a = new Point(1, 1); - var b = new Point(-1, 1); + var a = new Point(); + var b = new Point(); - (a != b).Should().BeTrue(); + (a != b).Should().BeFalse(); } } diff --git a/Test/GJK2DTest.cs b/Test/GJK2DTest.cs index ef83851..540d08b 100644 --- a/Test/GJK2DTest.cs +++ b/Test/GJK2DTest.cs @@ -12,8 +12,8 @@ namespace Tests [Test] public void PointLineOverlapping() { - var point = new Point(-3, -3); - var pointTransform = new Transform2D(new Position2D(4, 4)); + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(1, 1)); var line = new Line(new Position2D(-2, -2), new Position2D(2, 2)); NarrowPhase.TestCollision(point, pointTransform, line, Transform2D.DefaultTransform).Should().BeTrue(); @@ -22,10 +22,11 @@ namespace Tests [Test] public void PointLineNotOverlapping() { - var point = new Point(1, 1); + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(1, 1)); var line = new Line(new Position2D(-3, -2), new Position2D(-9, -5)); - NarrowPhase.TestCollision(point, Transform2D.DefaultTransform, line, Transform2D.DefaultTransform).Should().BeFalse(); + NarrowPhase.TestCollision(point, pointTransform, line, Transform2D.DefaultTransform).Should().BeFalse(); } [Test] @@ -43,7 +44,7 @@ namespace Tests [Test] public void PointCircleNotOverlapping() { - var point = new Point(0, 0); + var point = new Point(); var pointTransform = new Transform2D(new Position2D(3, 0)); var circle = new Circle(1); @@ -53,7 +54,7 @@ namespace Tests [Test] public void PointRectangleOverlapping() { - var point = new Point(1, 1); + var point = new Point(); var rectangle = new Rectangle(-2, -2, 2, 2); NarrowPhase.TestCollision(point, Transform2D.DefaultTransform, rectangle, Transform2D.DefaultTransform).Should().BeTrue(); @@ -62,16 +63,18 @@ namespace Tests [Test] public void PointRectangleNotOverlapping() { - var point = new Point(5, 5); + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(5, 5)); var rectangle = new Rectangle(-2, -2, 2, 2); - NarrowPhase.TestCollision(point, Transform2D.DefaultTransform, rectangle, Transform2D.DefaultTransform).Should().BeFalse(); + NarrowPhase.TestCollision(point, pointTransform, rectangle, Transform2D.DefaultTransform).Should().BeFalse(); } [Test] public void PointPolygonOverlapping() { - var point = new Point(1, 1); + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(1, 1)); var polygon = new Polygon(ImmutableArray.Create( new Position2D(-2, -2), new Position2D(-3, 2), @@ -79,13 +82,14 @@ namespace Tests new Position2D(3, -2) )); - NarrowPhase.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeTrue(); + NarrowPhase.TestCollision(point, pointTransform, polygon, Transform2D.DefaultTransform).Should().BeTrue(); } [Test] public void PointPolygonNotOverlapping() { - var point = new Point(5, 5); + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(5, 5)); var polygon = new Polygon(ImmutableArray.Create( new Position2D(-2, -2), new Position2D(-3, 2), @@ -93,7 +97,7 @@ namespace Tests new Position2D(3, -2) )); - NarrowPhase.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeFalse(); + NarrowPhase.TestCollision(point, pointTransform, polygon, Transform2D.DefaultTransform).Should().BeFalse(); } [Test] diff --git a/Test/SpatialHashTest.cs b/Test/SpatialHashTest.cs index 6e9661c..2d4b153 100644 --- a/Test/SpatialHashTest.cs +++ b/Test/SpatialHashTest.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; using MoonTools.Core.Structs; using MoonTools.Core.Bonk; @@ -34,8 +34,8 @@ namespace Tests var line = new Line(new Position2D(20, -4), new Position2D(22, -12)); var lineTransform = new Transform2D(new Vector2(0, 0)); - var point = new Point(8, 8); - var pointTransform = Transform2D.DefaultTransform; + var point = new Point(); + var pointTransform = new Transform2D(new Position2D(8, 8)); spatialHash.Insert(0, rectA, rectATransform); spatialHash.Insert(1, rectB, rectBTransform); @@ -98,4 +98,4 @@ namespace Tests spatialHash.Retrieve(0, rectA, rectATransform).Should().HaveCount(0); } } -} \ No newline at end of file +}