Skip to content

Instantly share code, notes, and snippets.

@sbrl
Last active March 10, 2018 22:56
Show Gist options
  • Save sbrl/7f8d31427dfa25af18820306b911b891 to your computer and use it in GitHub Desktop.
Save sbrl/7f8d31427dfa25af18820306b911b891 to your computer and use it in GitHub Desktop.
[Rectangle.cs] A class to represent an arbitrary rectangle in 2D space. Yes, System.Drawing contains one, but I had issues deserializing into it with JSON.NET. #microlibrary
using System;
using System.Collections.Generic;
using System.Linq;
namespace SBRL.Utilities
{
/// <summary>
/// Represents a rectangle in 2D space.
/// </summary>
/// <version>v0.3</version>
/// <changelog>
/// v0.1 - 1st April 2017
/// - Added this changelog!
/// v0.2 - 4th May 2017
/// - Fixed Overlap(Rectangle otherRectangle) method
/// v0.3 - 10th March 2018
/// - Added static Dimensions(IEnumerable{Rectangle}) for calculating bounding boxes
/// - Added Area and Perimeter properties
/// - Added Position alias and Size property
/// </changelog>
public struct Rectangle
{
/// <summary>
/// A rectangle with all it's properties initialised to zero.
/// </summary>
public static readonly Rectangle Zero = new Rectangle() { X = 0, Y = 0, Width = 0, Height = 0 };
#region Core Data
/// <summary>
/// The X coordinate of the rectangle.
/// </summary>
public float X { get; set; }
/// <summary>
/// The Y coordinate of the rectangle.
/// </summary>
/// <value>The y.</value>
public float Y { get; set; }
/// <summary>
/// The width of the rectangle.
/// </summary>
public float Width { get; set; }
/// <summary>
/// The height of the rectangle.
/// </summary>
public float Height { get; set; }
#endregion
#region Corners
/// <summary>
/// The top-left corner of the rectangle.
/// </summary>
public Vector2 TopLeft {
get {
return new Vector2(X, Y);
}
}
/// <summary>
/// The top-right corner of the rectangle.
/// </summary>
public Vector2 TopRight {
get {
return new Vector2(X + Width, Y);
}
}
/// <summary>
/// The bottom-left corner of the rectangle.
/// </summary>
public Vector2 BottomLeft {
get {
return new Vector2(X, Y + Height);
}
}
/// <summary>
/// The bottom-right corner of the rectangle.
/// </summary>
public Vector2 BottomRight {
get {
return new Vector2(X + Width, Y + Height);
}
}
#endregion
#region Edges
/// <summary>
/// The Y coordinate of the top of the rectangle.
/// </summary>
public float Top {
get {
return Y;
}
set {
Y = value;
}
}
/// <summary>
/// The Y coordinate of the bottom of the rectangle.
/// </summary>
public float Bottom {
get {
return Y + Height;
}
set {
Height = value - Y;
}
}
/// <summary>
/// The X coordinate of the left side of the rectangle.
/// </summary>
public float Left {
get {
return X;
}
set {
X = value;
}
}
/// <summary>
/// The X coordinate of the right side of the rectangle.
/// </summary>
public float Right {
get {
return X + Width;
}
set {
Width = value - X;
}
}
#endregion
#region Vectors
/// <summary>
/// Alias to TopLeft.
/// </summary>
public Vector2 Position {
get {
return TopLeft;
}
}
/// <summary>
/// A Vector2 representing the size of this Rectangle.
/// </summary>
public Vector2 Size {
get {
return new Vector2(Width, Height);
}
}
#endregion
#region Statistics
/// <summary>
/// The area that this Rectangle occupies.
/// </summary>
public float Area {
get {
return Width * Height;
}
}
/// <summary>
/// The perimeter of this Rectangle.
/// </summary>
public float Perimeter {
get {
return Width * 2 + Height * 2;
}
}
#endregion
public Rectangle(float x, float y, float width, float height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
public Rectangle(Vector2 position, Vector2 size) : this(position.X, position.Y, size.X, size.Y)
{
}
/// <summary>
/// Figures out whether this rectangle overlaps another rectangle.
/// </summary>
/// <param name="otherRectangle">The other rectangle to check the overlap of.</param>
/// <returns>Whether this rectangle overlaps another rectangle.</returns>
public bool Overlap(Rectangle otherRectangle)
{
if (Top > otherRectangle.Bottom ||
Bottom < otherRectangle.Top ||
Left > otherRectangle.Right ||
Right < otherRectangle.Left)
return false;
return true;
}
/// <summary>
/// Returns a Rectangle representing the area that this rectangle overlaps with another.
/// Returns an empty rectangle if the two don't overlap at all.
/// </summary>
/// <param name="otherRectangle">The other rectangle that overlaps this one.</param>
/// <returns>The area that this rectanagle overlaps with another.</returns>
public Rectangle OverlappingArea(Rectangle otherRectangle)
{
if (!Overlap(otherRectangle))
return Rectangle.Zero;
Rectangle result = new Rectangle();
result.Top = Math.Max(Top, otherRectangle.Top);
result.Left = Math.Max(Left, otherRectangle.Left);
result.Bottom = Math.Max(Bottom, otherRectangle.Bottom);
result.Right = Math.Max(Right, otherRectangle.Right);
return result;
}
public override string ToString()
{
return string.Format("[Rectangle: {1}x{2} @ {0}]", Position, Width, Height);
}
#region Static Methods
/// <summary>
/// Given a list of Rectangles, returns a bounding box of all the given rectangles.
/// </summary>
/// <param name="rectangles">The rectangles to calculate the bounding box for.</param>
/// <returns>A rectangle bounding box that covers all of the specified rectangles.</returns>
public static Rectangle Dimensions(IEnumerable<Rectangle> rectangles)
{
Vector2 topLeft = new Vector2(
rectangles.Min((Rectangle rect) => rect.Left),
rectangles.Min((Rectangle rect) => rect.Top)
);
Vector2 bottomRight = new Vector2(
rectangles.Max((Rectangle rect) => rect.Right),
rectangles.Max((Rectangle rect) => rect.Bottom)
);
return new Rectangle(
topLeft,
bottomRight.Subtract(topLeft)
);
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment