Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/GameUtils/Types/Geometry/AABB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
18 changes: 18 additions & 0 deletions tests/GameUtils.Benchmarks/GameUtils.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\GameUtils\GameUtils.csproj" />
</ItemGroup>

</Project>
64 changes: 64 additions & 0 deletions tests/GameUtils.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -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<AABBIntersectsBenchmark>();
}
}
}
53 changes: 53 additions & 0 deletions tests/GameUtils.Tests/Geometry/AABBTests.cs
Original file line number Diff line number Diff line change
@@ -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));
}
}
Loading