Skip to content

Representing Rectangles

Chris3606 edited this page Jul 22, 2018 · 26 revisions

The Rectangle class provides a convenient way to represent a bounded rectangular section of a grid (for example, the bounds of a map), as well as perform operations on those areas.

Although Rectangle instances are immutable (as is generally recommended for value-types), since Rectangle is a value-type, creation is quick and efficient.

Table of Contents

Code Examples

Code examples in this section show only code in the Main function. The code provided assumes that the following "using" statements are at the top of the code file:

using GoRogue;
using GoRogue.MapGeneration;

Position of a Rectangle

It is worthy of note that internally, a rectangle is defined as an x-value and y-value (which together constitute the Rectangle's position), a width, and a height. As such, the position is defined as the corner with the minimum x and y values.

Creating a Rectangle

There are numerous constructors provided to create a rectangle that define them in different ways.

Here, we create a rectangle using 4 integers -- a starting x coordinate, a starting y coordinate, a width, and a height. This rectangle has a starting position of (0, 0), a width of 50, and a height of 25. Thus, it encompasses everything from (0, 0) to (49, 24), inclusive:

Rectangle myRect = new Rectangle(0, 0, 50, 25);
// Prints out (X, Y) -> (MaxX, MaxY) -- in this case (0, 0) -> (49, 24)
System.Console.WriteLine(myRect);

We can also create a rectangle using 2 Coords - in this case, the first is the corner with the minimum x and y values, and the second is interpreted as the opposing corner (the one with the maximum x and y values). The below rectangle is identical to the one above, but we create it by specifying the "minimum" and "maximum" corners, more formally called the minimum and maximum extents:

Rectangle myRect2 = new Rectangle(Coord.Get(0, 0), Coord.Get(49, 24));
System.Console.WriteLine(myRect2);

Finally, we can create a rectangle by defining a Coord and two ints -- in this case, the Coord is the center point, and the two integers are the horizontal and vertical radius -- that is, the number of units away from the center to include in the rectangle, in the horizontal and vertical directions. The below rectangle is centered on (10, 5), and has a horizontal "radius" of 10, and vertical "radius" of 5. This rectangle encompasses everything from (0, 0) to (20, 10):

Rectangle myRect3 = new Rectangle(Coord.Get(10, 5), 10, 5);
System.Console.WriteLine(myRect3);

The Empty Rectangle

For cases when the empty rectangle (a rectangle containing no space) is desired, it is inconvenient to attempt to use null, because Rectangle is a value type. Thus, a static field Rectangle.EMPTY is provided, which is defined as a rectangle starting at (0, 0) and having a width and height of 0:

// Width and height of 0.  This yields a rectangle with one corner (0, 0),
// and opposite corner (-1, -1). Note how the second corner has a lesser
// x and y  value than the first in ONLY this case.
System.Console.WriteLine(Rectangle.EMPTY);

Although this static field is provided for convenience and efficiency when an empty rectangle is desired, the IsEmpty field will return true for any rectangle with a width and height of 0, regardless of its Position value, or whether or not it is the Rectangle.EMPTY instance.

Data About Rectangles

Once we have created a Rectangle instance, it exposes a number of useful properties containing various pieces of information.

Center Point

We can easily retrieve the center point of the rectangle, rounded down to the nearest integer value in the case that the center point is between two grid locations:

Rectangle myRect = new Rectangle(0, 0, 50, 25);
System.Console.WriteLine(myRect.Center);

IsEmpty

The IsEmpty property retrieves whether or not the rectangle is empty -- eg. whether or not it has an width and height of 0:

System.Console.WriteLine("EMPTY is empty: " + Rectangle.EMPTY.IsEmpty); // Clearly empty

// Although the empty rectangle is (obviously) empty, so is any rectangle that has
// a width and height of 0
Rectangle myRect = new Rectangle(100, 50, 0, 0);
System.Console.WriteLine("Another empty rectangle IsEmpty: " + myRect.IsEmpty);

Position and Extents

We can also easily access a rectangle's position, and its extent. Its minimum extent is the lowest x and y values that are encompassed by the rectangle, and its maximum extent is the highest x and y values that are included in the Rectangle. As stated previously, a Rectangle's position is defined as its minimum x and y values, so its position is always equal to its minimum extent. These properties are accessible as Rectangle.MinExtent, Rectangle.MaxExtent, and Rectangle.Position. The individual x and y values for these are also accessible via Rectangle.MinExtentX/Rectangle.MinExtentY, Rectangle.MaxExtentX/Rectangle.MaxExtentY, and Rectangle.X/Rectangle.Y:

Rectangle myRect = new Rectangle(0, 0, 50, 25);
System.Console.WriteLine(myRect.MinExtent);
System.Console.WriteLine(myRect.Position); // Equal to MinExtent
System.Console.WriteLine(myRect.MaxExtent);

Size

The width and height of the rectangle are also available as properties, as well as a Coord size whose X-value is the Width and Y-value is the height:

Rectangle myRect = new Rectangle(0, 0, 50, 25);
System.Console.WriteLine("Width: " + myRect.Width + ", Height: " + myRect.Height);
System.Console.WriteLine("Size: " + myRect.Size);

Pseudo-Modification of Rectangles

Although the Rectangle class is immutable (none of its properties can be changed), it is a value type and as such may be re-allocated frequently without significant performance concern, and it provides a number of functions that return new Rectangles, that are modified in certain ways.

Modifying Position

We can modify position by specifying a new position, or only a new x/new y value. We may also specify a delta-change, instead of an absolute value. In addition, we can specify a direction to move a new Rectangle in. Finally, we may specify a new center point:

Rectangle myRect = new Rectangle(0, 0, 10, 10);

// Specify the position as either a Coord or x and y values; these
// moves are equivalent
myRect = myRect.Move(Coord.Get(1, 1));
// myRect = myRect.Move(1, 1);
System.Console.WriteLine(myRect); // Moved to (1, 1) -> (10, 10)

// You can also specify only a new x value, or only a new y-value.
myRect = myRect.MoveX(2);
myRect = myRect.MoveY(3);
System.Console.WriteLine(myRect); // Moved to (2, 3) -> (11, 12)

// In addition, we can specify delta-change values using Translate.  Again,
// the following 2 statements are equivalent
myRect = myRect.Translate(-1, -2); // Subtracts 1 from the x-value, and subtracts 2 from the y-value
// myRect = myRect.Translate(Coord.Get(-1, -2));
System.Console.WriteLine(myRect); // Moved back to (1, 1) -> (10, 10)

// Similarly, we can specify only delta-x values, or only delta-y values.
myRect = myRect.TranslateX(1);
myRect = myRect.TranslateY(2);
System.Console.WriteLine(myRect); // Moved back to (2, 3) -> (11, 12)

// Here we move the Rectangle in the specified direction
myRect = myRect.MoveIn(Direction.UP);
System.Console.WriteLine(myRect); // Moved to (2, 2) -> (11, 11)

// We can also specify a center point
myRect = myRect.CenterOn(5, 5);
// myRect = myRect.CenterOn(Coord.Get(5, 5));
System.Console.WriteLine(myRect);

Resizing

We can also resize the a Rectangle by specifying a width/height/size value, or delta change values for width, height or size:

Rectangle myRect = new Rectangle(0, 0, 10, 10);

// Set rectangle to width and height of 9
myRect = myRect.SetSize(9, 9);
// myRect = myRect.SetSize(Coord.Get(9, 9);
System.Console.WriteLine(myRect); // Changed to (0, 0) -> (8, 8)

// We can also specify width/height by themselves
myRect = myRect.SetWidth(10);
myRect = myRect.SetHeight(10);
System.Console.WriteLine(myRect); // Changed back to (0, 0) -> (9, 9)

// In addition, we can specify delta-change values for width, height, or both at once
myRect = myRect.ChangeSize(-1, -1);
// myRect = myRect.ChangeSize(Coord.Get(-1, -1));
System.Console.WriteLine(myRect); // Back to (0, 0) -> (8, 8)

// We can also specify a delta-value for width/height separately
myRect = myRect.ChangeWidth(1);
myRect = myRect.ChangeHeight(1);
System.Console.WriteLine(myRect); // Back to (0, 0) -> (9, 9)

In addition, we can also resize a rectangle by specifying a new minimum/maximum extent. This moves the appropriate corner to the specified extent, without moving the other corner; effectively resizing the rectangle:

Rectangle myRect = new Rectangle(0, 0, 10, 10);

// Here we resize by moving the max-extent to be a new point -- the position does not change, but the width
// and height do
myRect = myRect.SetMaxExtent(10, 10);
// myRect = myRect.SetMaxExtent(Coord.Get(10, 10));
System.Console.WriteLine(myRect); // Resized to (0, 0) -> (10, 10)

// We can also specify x and y values separately
myRect = myRect.SetMaxExtentX(9);
myRect = myRect.SetMaxExtentY(9);
System.Console.WriteLine(myRect); // Resized to (0, 0) -> (9, 9)

// Similarly, we can resize the rectangle by specifying the minimum extent
myRect = myRect.SetMinExtent(1, 1);
// myRect = myRect.SetMinExtent(Coord.Get(1, 1));
System.Console.WriteLine(myRect); // Resized to (1, 1) -> (9, 9)

// We can also specify x and y values separately
myRect = myRect.SetMinExtentX(0);
myRect = myRect.SetMinExtentY(0);
System.Console.WriteLine(myRect); // Resized to (0, 0) -> (9, 9)

Operations on Rectangles

Numerous functions are provided to allow operations on rectangles.

Rectangle Equality

Rectangles implement IEquatable, and can be compared for equality. Two rectangles are equal if and only if their X value, Y value, Width, and Height are all equivalent.

Rectangle rect1 = new Rectangle(0, 0, 50, 25);
Rectangle rect2 = new Rectangle(0, 0, 50, 25);

System.Console.WriteLine("Equal Rectangles: " + (rect1 == rect2));
System.Console.WriteLine("Can also use Equals function: " + rect1.Equals(rect2));

// This rectangle is defined in a different way but is the same rectangle --
// has a starting corner of (0, 0), width of 50, height of 25.  Thus
// it is still considered equal to the other two.
Rectangle rect3 = new Rectangle(Coord.Get(0, 0), Coord.Get(49, 24));
System.Console.WriteLine("Rect 3 still equal: " + (rect3 == rect1));

Contains

Functions are also provided to determine whether or not a point is contained within the bounds of a rectangle, or rather a rectangle is entirely contained within the bounds of another rectangle.

Rectangle myRect = new Rectangle(0, 0, 50, 25);
// We can specify a point to check as a Coord, or two integers.
System.Console.WriteLine("(10, 15) is in myRect: " + myRect.Contains(10, 15));
System.Console.WriteLine("(100, 150) is NOT in myRect: " + myRect.Contains(Coord.Get(100, 150)));

Rectangle myRect2 = new Rectangle(10, 10, 5, 5); // Entirely contained within myRect

System.Console.WriteLine("myRect contains myRect2: " + myRect.Contains(myRect2));
System.Console.WriteLine("myRect2 does NOT contain myRect: " + myRect2.Contains(myRect));

// Although myRect3 largely overlaps with myRect, myRect does NOT
// completely contain myRect3, nor does myRect3 completely contain myRect.
Rectangle myRect3 = new Rectangle(-5, -5, 50, 50);
System.Console.WriteLine("myRect does NOT myRect3: " + myRect.Contains(myRect3));
System.Console.WriteLine("myRect3 does NOT contain myRect: " + myRect3.Contains(myRect));

Intersection

Functions are also provided to determine whether two Rectangles overlap (eg, intersect), and to get a rectangle representing the common area:

Rectangle myRect = new Rectangle(0, 0, 50, 25);

// Overlaps (but is not completely within) myRect
Rectangle myRect2 = new Rectangle(-5, -5, 50, 50);
System.Console.WriteLine("MyRect intersects MyRect2: " + myRect.Intersects(myRect2));
System.Console.WriteLine("MyRect2 intersects MyRect: " + myRect2.Intersects(myRect));

// Overlaps (and is within) myRect -- still intersects
Rectangle myRect3 = new Rectangle(10, 10, 5, 5);
System.Console.WriteLine("MyRect intersects MyRect3: " + myRect.Intersects(myRect3));
System.Console.WriteLine("MyRect3 intersects MyRect: " + myRect3.Intersects(myRect));

// Gets the exact area representing the intersection of the two rectangles
// (a rectangle containing only those positions contained within both rectangles)
Rectangle intersect = Rectangle.GetIntersection(myRect, myRect2);
System.Console.WriteLine("Intersection of myRect and myRect2 is " + intersect);

Union

Rectangle also provides GetUnion, which gets the smallest possible rectangle that encompasses two given rectangles:

Rectangle myRect = new Rectangle(1, 1, 49, 49);
Rectangle myRect2 = new Rectangle(0, 0, 5, 5);

// Smallest rectangle that contains both these rectangles is one with
// MinX/MinY of (0, 0), width and height of 50.
Rectangle union = Rectangle.GetUnion(myRect, myRect2);
System.Console.WriteLine("Bounding box of myRect and myRect2 is " + union);

Exact Union

Rectangle also provides GetExactUnion. This function is similar to GetUnion, but instead of returning the smallest possible Rectangle that encompasses the given Rectangles, it returns a MapArea that contains exactly those positions in one or both of the Rectangles given. This represents the exact shape of the union, rather than the "bounding box":

Rectangle myRect = new Rectangle(0, 0, 2, 3);
Rectangle myRect2 = new Rectangle(0, 0, 5, 2);

MapArea union = Rectangle.GetExactUnion(myRect, myRect2);
System.Console.WriteLine(union);

Difference

Finally, Rectangle provides Difference. This function returns a MapArea containing exactly those positions in the first rectangle, minus any positions in the second rectangle:

Rectangle myRect = new Rectangle(0, 0, 2, 3);
Rectangle myRect2 = new Rectangle(0, 0, 2, 2);

MapArea difference = Rectangle.GetDifference(myRect, myRect2);
System.Console.WriteLine(difference);