67 lines
2 KiB
C#
67 lines
2 KiB
C#
using System.Numerics;
|
|
using AcDream.App.Rendering;
|
|
using Xunit;
|
|
|
|
namespace AcDream.App.Tests.Rendering;
|
|
|
|
public class ScreenPolygonClipTests
|
|
{
|
|
// CCW square [min,max]^2.
|
|
private static Vector2[] Square(float min, float max) => new[]
|
|
{
|
|
new Vector2(min, min), new Vector2(max, min), new Vector2(max, max), new Vector2(min, max),
|
|
};
|
|
|
|
private static float Area(Vector2[] poly)
|
|
{
|
|
if (poly.Length < 3) return 0f;
|
|
float a = 0f;
|
|
for (int i = 0; i < poly.Length; i++)
|
|
{
|
|
var p = poly[i]; var q = poly[(i + 1) % poly.Length];
|
|
a += p.X * q.Y - q.X * p.Y;
|
|
}
|
|
return System.MathF.Abs(a) * 0.5f;
|
|
}
|
|
|
|
[Fact]
|
|
public void Intersect_FullyContained_ReturnsSubject()
|
|
{
|
|
var outer = Square(-1f, 1f);
|
|
var inner = Square(-0.5f, 0.5f);
|
|
var r = ScreenPolygonClip.Intersect(inner, outer);
|
|
Assert.Equal(1.0f, Area(r), 3); // inner area = 1x1
|
|
}
|
|
|
|
[Fact]
|
|
public void Intersect_PartialOverlap_ReturnsOverlapArea()
|
|
{
|
|
var a = Square(0f, 2f);
|
|
var b = Square(1f, 3f);
|
|
var r = ScreenPolygonClip.Intersect(a, b);
|
|
Assert.Equal(1.0f, Area(r), 3); // overlap [1,2]^2 = 1
|
|
}
|
|
|
|
[Fact]
|
|
public void Intersect_Disjoint_ReturnsEmpty()
|
|
{
|
|
var a = Square(0f, 1f);
|
|
var b = Square(5f, 6f);
|
|
var r = ScreenPolygonClip.Intersect(a, b);
|
|
Assert.True(r.Length < 3); // empty
|
|
}
|
|
|
|
[Fact]
|
|
public void Intersect_Sliver_PreservesNarrowOverlap()
|
|
{
|
|
// A tall thin clip (the "stairwell") intersected with a wide subject (the "window").
|
|
var window = Square(-1f, 1f);
|
|
var stairwell = new[]
|
|
{
|
|
new Vector2(-0.1f, -1f), new Vector2(0.1f, -1f), new Vector2(0.1f, 1f), new Vector2(-0.1f, 1f),
|
|
};
|
|
var r = ScreenPolygonClip.Intersect(window, stairwell);
|
|
Assert.Equal(0.4f, Area(r), 3); // 0.2 wide x 2 tall
|
|
Assert.True(System.MathF.Abs(r[0].X) <= 0.1001f); // clipped to stairwell width
|
|
}
|
|
}
|