diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7ab2d6..d858345 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ Additions
- Added ColorExtensions.Multiply
- Added SoundEffectInstanceHandler.Stop
- Added TextureRegion.OffsetCopy
+- Added RectangleF.DistanceSquared and RectangleF.Distance
Improvements
- Generify GenericFont's string drawing
diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs
index bbb691e..9407cdf 100644
--- a/MLEM.Ui/UiControls.cs
+++ b/MLEM.Ui/UiControls.cs
@@ -373,12 +373,11 @@ namespace MLEM.Ui {
foreach (var child in children) {
if (!child.CanBeSelected || child == this.SelectedElement)
continue;
- var distVec = child.Area.Center - this.SelectedElement.Area.Center;
- if (Math.Abs(direction.Angle() - Math.Atan2(distVec.Y, distVec.X)) >= MathHelper.PiOver2 - Element.Epsilon)
+ var (xOffset, yOffset) = child.Area.Center - this.SelectedElement.Area.Center;
+ if (Math.Abs(direction.Angle() - Math.Atan2(yOffset, xOffset)) >= MathHelper.PiOver2 - Element.Epsilon)
continue;
- var distSq = distVec.LengthSquared();
- // prefer navigating to elements that have the same parent as the currently selected element
- if (closest == null || distSq < closestDistSq || closest.Parent != this.SelectedElement.Parent && child.Parent == this.SelectedElement.Parent) {
+ var distSq = child.Area.DistanceSquared(this.SelectedElement.Area);
+ if (closest == null || distSq < closestDistSq) {
closest = child;
closestDistSq = distSq;
}
diff --git a/MLEM/Misc/RectangleF.cs b/MLEM/Misc/RectangleF.cs
index af5122e..7df4440 100644
--- a/MLEM/Misc/RectangleF.cs
+++ b/MLEM/Misc/RectangleF.cs
@@ -105,49 +105,6 @@ namespace MLEM.Misc {
this.Height = size.Y;
}
- ///
- /// Creates a new rectangle based on two corners that form a bounding box.
- /// The resulting rectangle will encompass both corners as well as all of the space between them.
- ///
- /// The first corner to use
- /// The second corner to use
- ///
- public static RectangleF FromCorners(Vector2 corner1, Vector2 corner2) {
- var minX = Math.Min(corner1.X, corner2.X);
- var minY = Math.Min(corner1.Y, corner2.Y);
- var maxX = Math.Max(corner1.X, corner2.X);
- var maxY = Math.Max(corner1.Y, corner2.Y);
- return new RectangleF(minX, minY, maxX - minX, maxY - minY);
- }
-
- ///
- /// Converts a float-based rectangle to an int-based rectangle, flooring each value in the process.
- ///
- /// The rectangle to convert
- /// The resulting rectangle
- public static explicit operator Rectangle(RectangleF rect) {
- return new Rectangle(rect.X.Floor(), rect.Y.Floor(), rect.Width.Floor(), rect.Height.Floor());
- }
-
- ///
- /// Converts an int-based rectangle to a float-based rectangle.
- ///
- /// The rectangle to convert
- /// The resulting rectangle
- public static explicit operator RectangleF(Rectangle rect) {
- return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
- }
-
- ///
- public static bool operator ==(RectangleF a, RectangleF b) {
- return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
- }
-
- ///
- public static bool operator !=(RectangleF a, RectangleF b) {
- return !(a == b);
- }
-
///
public bool Contains(float x, float y) {
return this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;
@@ -196,6 +153,92 @@ namespace MLEM.Misc {
return value.Left < this.Right && this.Left < value.Right && value.Top < this.Bottom && this.Top < value.Bottom;
}
+ ///
+ public void Offset(float offsetX, float offsetY) {
+ this.X += offsetX;
+ this.Y += offsetY;
+ }
+
+ ///
+ public void Offset(Vector2 amount) {
+ this.X += amount.X;
+ this.Y += amount.Y;
+ }
+
+ ///
+ /// Calculates the suqared distance between this rectangle and the .
+ /// The returned value is the smallest squared distance between any two edges or corners of the two rectangles.
+ ///
+ /// The rectangle to calculate the squared distance to.
+ /// The squared distance between the two rectangles.
+ public float DistanceSquared(RectangleF value) {
+ // we calculate the distance based on the quadrants that the other rectangle is in using 8 cases:
+ // 1 7 4
+ // 3 T 6
+ // 2 8 5
+ var valueIsAbove = value.Bottom < this.Top;
+ var valueIsBelow = value.Top > this.Bottom;
+ if (value.Right < this.Left) {
+ if (valueIsAbove) // 1
+ return Vector2.DistanceSquared(new Vector2(value.Right, value.Bottom), new Vector2(this.Left, this.Top));
+ if (valueIsBelow) // 2
+ return Vector2.DistanceSquared(new Vector2(value.Right, value.Top), new Vector2(this.Left, this.Bottom));
+ return (this.Left - value.Right) * (this.Left - value.Right); // 3
+ } else if (value.Left > this.Right) {
+ if (valueIsAbove) // 4
+ return Vector2.DistanceSquared(new Vector2(value.Left, value.Bottom), new Vector2(this.Right, this.Top));
+ if (valueIsBelow) // 5
+ return Vector2.DistanceSquared(new Vector2(value.Left, value.Top), new Vector2(this.Right, this.Bottom));
+ return (value.Left - this.Right) * (value.Left - this.Right); // 6
+ } else if (valueIsAbove) {
+ return (this.Top - value.Bottom) * (this.Top - value.Bottom); // 7
+ } else if (valueIsBelow) {
+ return (value.Top - this.Bottom) * (value.Top - this.Bottom); // 8
+ } else {
+ return 0;
+ }
+ }
+
+ ///
+ /// Calculates the distance between this rectangle and the .
+ /// The returned value is the smallest distance between any two edges or corners of the two rectangles.
+ ///
+ /// The rectangle to calculate the distance to.
+ /// The distance between the two rectangles.
+ public float Distance(RectangleF value) {
+ return (float) Math.Sqrt(this.DistanceSquared(value));
+ }
+
+ /// Returns a string that represents the current object.
+ /// A string that represents the current object.
+ public override string ToString() {
+ return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}";
+ }
+
+ ///
+ public void Deconstruct(out float x, out float y, out float width, out float height) {
+ x = this.X;
+ y = this.Y;
+ width = this.Width;
+ height = this.Height;
+ }
+
+ ///
+ /// Converts a float-based rectangle to an int-based rectangle, flooring each value in the process.
+ ///
+ /// The rectangle to convert
+ /// The resulting rectangle
+ public static explicit operator Rectangle(RectangleF rect) {
+ return new Rectangle(rect.X.Floor(), rect.Y.Floor(), rect.Width.Floor(), rect.Height.Floor());
+ }
+
+ ///
+ public static RectangleF Union(RectangleF value1, RectangleF value2) {
+ var x = Math.Min(value1.X, value2.X);
+ var y = Math.Min(value1.Y, value2.Y);
+ return new RectangleF(x, y, Math.Max(value1.Right, value2.Right) - x, Math.Max(value1.Bottom, value2.Bottom) - y);
+ }
+
///
public static RectangleF Intersect(RectangleF value1, RectangleF value2) {
if (value1.Intersects(value2)) {
@@ -209,37 +252,38 @@ namespace MLEM.Misc {
}
}
- ///
- public void Offset(float offsetX, float offsetY) {
- this.X += offsetX;
- this.Y += offsetY;
+ ///
+ /// Creates a new rectangle based on two corners that form a bounding box.
+ /// The resulting rectangle will encompass both corners as well as all of the space between them.
+ ///
+ /// The first corner to use
+ /// The second corner to use
+ ///
+ public static RectangleF FromCorners(Vector2 corner1, Vector2 corner2) {
+ var minX = Math.Min(corner1.X, corner2.X);
+ var minY = Math.Min(corner1.Y, corner2.Y);
+ var maxX = Math.Max(corner1.X, corner2.X);
+ var maxY = Math.Max(corner1.Y, corner2.Y);
+ return new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
- ///
- public void Offset(Vector2 amount) {
- this.X += amount.X;
- this.Y += amount.Y;
+ ///
+ /// Converts an int-based rectangle to a float-based rectangle.
+ ///
+ /// The rectangle to convert
+ /// The resulting rectangle
+ public static explicit operator RectangleF(Rectangle rect) {
+ return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
}
- /// Returns a string that represents the current object.
- /// A string that represents the current object.
- public override string ToString() {
- return "{X:" + this.X + " Y:" + this.Y + " Width:" + this.Width + " Height:" + this.Height + "}";
+ ///
+ public static bool operator ==(RectangleF a, RectangleF b) {
+ return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
}
- ///
- public static RectangleF Union(RectangleF value1, RectangleF value2) {
- var x = Math.Min(value1.X, value2.X);
- var y = Math.Min(value1.Y, value2.Y);
- return new RectangleF(x, y, Math.Max(value1.Right, value2.Right) - x, Math.Max(value1.Bottom, value2.Bottom) - y);
- }
-
- ///
- public void Deconstruct(out float x, out float y, out float width, out float height) {
- x = this.X;
- y = this.Y;
- width = this.Width;
- height = this.Height;
+ ///
+ public static bool operator !=(RectangleF a, RectangleF b) {
+ return !(a == b);
}
}