diff --git a/SS14.Shared.Maths/UIBox2i.cs b/SS14.Shared.Maths/UIBox2i.cs index cfcb349cf..d1307ab08 100644 --- a/SS14.Shared.Maths/UIBox2i.cs +++ b/SS14.Shared.Maths/UIBox2i.cs @@ -62,6 +62,31 @@ namespace SS14.Shared.Maths return new UIBox2i(Left + point.X, Top + point.Y, Right + point.X, Bottom + point.Y); } + /// + /// Calculates the "intersection" of this and another box. + /// Basically, the smallest region that fits in both boxes. + /// + /// The box to calculate the intersection with. + /// + /// null if there is no intersection, otherwise the smallest region that fits in both boxes. + /// + public UIBox2i? Intersection(in UIBox2i other) + { + if (!Intersects(other)) + { + return null; + } + return new UIBox2i( + Vector2i.ComponentMax(TopLeft, other.TopLeft), + Vector2i.ComponentMin(BottomRight, other.BottomRight)); + } + + public bool Intersects(in UIBox2i other) + { + return other.Bottom >= this.Top && other.Top <= this.Bottom && other.Right >= this.Left && + other.Left <= this.Right; + } + // override object.Equals public override bool Equals(object obj) { diff --git a/SS14.UnitTesting/Shared/Maths/UIBox2i_Test.cs b/SS14.UnitTesting/Shared/Maths/UIBox2i_Test.cs index 46d43508b..bedfe5ec6 100644 --- a/SS14.UnitTesting/Shared/Maths/UIBox2i_Test.cs +++ b/SS14.UnitTesting/Shared/Maths/UIBox2i_Test.cs @@ -65,6 +65,15 @@ namespace SS14.UnitTesting.Shared.Maths 10 }; + private static IEnumerable<(UIBox2i a, UIBox2i b, UIBox2i? expected)> Intersections => + new (UIBox2i, UIBox2i, UIBox2i?)[] + { + (new UIBox2i(0, 0, 5, 5), new UIBox2i(2, 2, 4, 4), new UIBox2i(2, 2, 4, 4)), + (new UIBox2i(0, 0, 5, 5), new UIBox2i(3, 3, 7, 7), new UIBox2i(3, 3, 5, 5)), + (new UIBox2i(2, 0, 5, 5), new UIBox2i(0, 3, 4, 7), new UIBox2i(2, 3, 4, 5)), + (new UIBox2i(2, 0, 5, 5), new UIBox2i(6, 6, 10, 10), null), + }; + [Test] public void Box2iVectorConstructor([ValueSource(nameof(Sources))] (int, int, int, int) test) { @@ -177,7 +186,8 @@ namespace SS14.UnitTesting.Shared.Maths } [Test] - public void Box2iContains([ValueSource(nameof(SmallTranslations))] (int, int) test) + public void Box2iContains([ValueSource(nameof(SmallTranslations))] + (int, int) test) { var (x, y) = test; var vec = new Vector2i(x, y); @@ -190,7 +200,8 @@ namespace SS14.UnitTesting.Shared.Maths } [Test] - public void Box2iNotContains([ValueSource(nameof(LargeTranslations))] (int, int) test) + public void Box2iNotContains([ValueSource(nameof(LargeTranslations))] + (int, int) test) { var (x, y) = test; var vec = new Vector2i(x, y); @@ -203,7 +214,8 @@ namespace SS14.UnitTesting.Shared.Maths } [Test] - public void Box2iTranslated([ValueSource(nameof(LargeTranslations))] (int, int) test) + public void Box2iTranslated([ValueSource(nameof(LargeTranslations))] + (int, int) test) { var (x, y) = test; var vec = new Vector2i(x, y); @@ -236,5 +248,16 @@ namespace SS14.UnitTesting.Shared.Maths Assert.That(controlBox.Equals(nullBox), Is.False); Assert.That(controlBox.Equals(notBox), Is.False); } + + [Test] + public void UIBox2iIntersection( + [ValueSource(nameof(Intersections))] (UIBox2i a, UIBox2i b, UIBox2i? expected) value) + { + var (a, b, expected) = value; + + // This should be a symmetric operation. + Assert.That(a.Intersection(b), Is.EqualTo(expected)); + Assert.That(b.Intersection(a), Is.EqualTo(expected)); + } } }