diff --git a/src/GameUtils/Types/Geometry/AABB.cs b/src/GameUtils/Types/Geometry/AABB.cs
index 77e555b..93615f3 100644
--- a/src/GameUtils/Types/Geometry/AABB.cs
+++ b/src/GameUtils/Types/Geometry/AABB.cs
@@ -148,17 +148,43 @@ public bool Intersects(Line line, out Vector2[] intersectionPoints)
#pragma warning disable S3267 // LINQ would reintroduce allocations on a hot collision path
public bool Intersects(Polygon2D polygon)
{
+ // 1. Fast bounds check: compute polygon bounds on the fly
+ if (polygon.Vertices.Length > 0)
+ {
+ var pMinX = polygon.Vertices[0].X;
+ var pMaxX = polygon.Vertices[0].X;
+ var pMinY = polygon.Vertices[0].Y;
+ var pMaxY = polygon.Vertices[0].Y;
+
+ for (int i = 1; i < polygon.Vertices.Length; i++)
+ {
+ var v = polygon.Vertices[i];
+ if (v.X < pMinX) pMinX = v.X;
+ if (v.X > pMaxX) pMaxX = v.X;
+ if (v.Y < pMinY) pMinY = v.Y;
+ if (v.Y > pMaxY) pMaxY = v.Y;
+ }
+
+ if (pMinX > Max.X || pMaxX < Min.X || pMinY > Max.Y || pMaxY < Min.Y)
+ {
+ return false;
+ }
+ }
+
+ // 2. Check if any polygon vertex is inside the AABB
foreach (var v in polygon.Vertices)
{
if (Contains(v)) return true;
}
+ // 3. Check if any polygon edge intersects the AABB
foreach (var e in polygon.Edges)
{
if (Intersects(e)) return true;
}
- return false;
+ // 4. Check if the AABB is completely inside the polygon
+ return polygon.Contains(Center);
}
#pragma warning restore S3267
diff --git a/tests/GameUtils.Benchmarks/GameUtils.Benchmarks.csproj b/tests/GameUtils.Benchmarks/GameUtils.Benchmarks.csproj
new file mode 100644
index 0000000..1a2a09d
--- /dev/null
+++ b/tests/GameUtils.Benchmarks/GameUtils.Benchmarks.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/GameUtils.Benchmarks/Program.cs b/tests/GameUtils.Benchmarks/Program.cs
new file mode 100644
index 0000000..bbf6ad7
--- /dev/null
+++ b/tests/GameUtils.Benchmarks/Program.cs
@@ -0,0 +1,64 @@
+using BenchmarkDotNet.Running;
+using BenchmarkDotNet.Attributes;
+using GameUtils.Types.Geometry;
+using System.Numerics;
+using System.Linq;
+
+namespace GameUtils.Benchmarks
+{
+ [MemoryDiagnoser]
+ public class AABBIntersectsBenchmark
+ {
+ private AABB _aabb;
+ private Polygon2D _polyInside;
+ private Polygon2D _polyIntersecting;
+ private Polygon2D _polyOutside;
+ private Polygon2D _polyContainsAABB;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _aabb = new AABB(new Vector2(10, 10), new Vector2(20, 20));
+
+ // Polygon completely inside AABB
+ _polyInside = new Polygon2D(new[] {
+ new Vector2(12, 12), new Vector2(18, 12), new Vector2(15, 18)
+ });
+
+ // Polygon intersecting AABB
+ _polyIntersecting = new Polygon2D(new[] {
+ new Vector2(5, 15), new Vector2(15, 15), new Vector2(10, 25)
+ });
+
+ // Polygon completely outside AABB
+ _polyOutside = new Polygon2D(new[] {
+ new Vector2(30, 30), new Vector2(40, 30), new Vector2(35, 40)
+ });
+
+ // Polygon containing the entire AABB
+ _polyContainsAABB = new Polygon2D(new[] {
+ new Vector2(0, 0), new Vector2(30, 0), new Vector2(30, 30), new Vector2(0, 30)
+ });
+ }
+
+ [Benchmark]
+ public bool IntersectsInside() => _aabb.Intersects(_polyInside);
+
+ [Benchmark]
+ public bool IntersectsIntersecting() => _aabb.Intersects(_polyIntersecting);
+
+ [Benchmark]
+ public bool IntersectsOutside() => _aabb.Intersects(_polyOutside);
+
+ [Benchmark]
+ public bool IntersectsContainsAABB() => _aabb.Intersects(_polyContainsAABB);
+ }
+
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ var summary = BenchmarkRunner.Run();
+ }
+ }
+}
diff --git a/tests/GameUtils.Tests/Geometry/AABBTests.cs b/tests/GameUtils.Tests/Geometry/AABBTests.cs
new file mode 100644
index 0000000..039164b
--- /dev/null
+++ b/tests/GameUtils.Tests/Geometry/AABBTests.cs
@@ -0,0 +1,53 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using GameUtils.Types.Geometry;
+using System.Numerics;
+
+namespace GameUtils.Tests.Geometry;
+
+[TestClass]
+public class AABBTests
+{
+ [TestMethod]
+ public void Intersects_PolygonContainsAABB_ReturnsTrue()
+ {
+ var aabb = new AABB(new Vector2(10, 10), new Vector2(20, 20));
+ var polyContainsAABB = new Polygon2D(new[] {
+ new Vector2(0, 0), new Vector2(30, 0), new Vector2(30, 30), new Vector2(0, 30)
+ });
+
+ Assert.IsTrue(aabb.Intersects(polyContainsAABB));
+ }
+
+ [TestMethod]
+ public void Intersects_PolygonInsideAABB_ReturnsTrue()
+ {
+ var aabb = new AABB(new Vector2(10, 10), new Vector2(20, 20));
+ var polyInsideAABB = new Polygon2D(new[] {
+ new Vector2(12, 12), new Vector2(18, 12), new Vector2(15, 18)
+ });
+
+ Assert.IsTrue(aabb.Intersects(polyInsideAABB));
+ }
+
+ [TestMethod]
+ public void Intersects_PolygonIntersectingAABB_ReturnsTrue()
+ {
+ var aabb = new AABB(new Vector2(10, 10), new Vector2(20, 20));
+ var polyIntersectingAABB = new Polygon2D(new[] {
+ new Vector2(5, 15), new Vector2(15, 15), new Vector2(10, 25)
+ });
+
+ Assert.IsTrue(aabb.Intersects(polyIntersectingAABB));
+ }
+
+ [TestMethod]
+ public void Intersects_PolygonOutsideAABB_ReturnsFalse()
+ {
+ var aabb = new AABB(new Vector2(10, 10), new Vector2(20, 20));
+ var polyOutsideAABB = new Polygon2D(new[] {
+ new Vector2(30, 30), new Vector2(40, 30), new Vector2(35, 40)
+ });
+
+ Assert.IsFalse(aabb.Intersects(polyOutsideAABB));
+ }
+}