Reference

std/geometry/rectangle

std/geometry/src/rectangle.trb

Rectangle, the axis-aligned box in the plane, and the one place where the half-open rule of this package is decided.

A rectangle is an origin and a size, not two corners, because that is the form a size can be read out of without a subtraction and the form a tile grid is written in. Which corner the origin is depends on nothing: it is the corner with the smaller coordinates, and whether a viewer sees that as the top or the bottom is the program's own business.

type Rectangle

type Rectangle<Scalar: Numeric = Float>

An axis-aligned rectangle: where it starts, and how big it is.

The minimum edge is inside and the maximum edge is outside. A point is in the rectangle when minimum.x <= point.x and point.x < maximum.x, on both axes and for every scalar. That is what makes a row of rectangles a tiling: Rectangle(Vector2(0, 0), Vector2(8, 8)) and Rectangle(Vector2(8, 0), Vector2(8, 8)) share the column x == 8 in neither of them, so a pixel belongs to exactly one tile and a hit test never answers twice.

Examples

const tile = Rectangle Vector2(0, 0), Vector2(8, 8)
print "{tile.contains(Vector2(0, 0))} {tile.contains(Vector2(8, 0))}"

Pitfalls

  • A size with a negative or zero component describes no points at all, and Rectangle.isEmpty says so. Nothing normalizes a rectangle for you: intersection answers an empty one rather than None, so that a chain of them stays a rectangle.
  • The half-open rule is about membership, not about bounds. bounds and covering answer the closed hull of what they are given, so a corner of a shape can lie exactly on the maximum edge of that shape's own bounding rectangle and contains answers false for it. A bound is a bound; a tiling is what the half-open rule is for.
  • area on a Rectangle<Int> counts cells, and on a Rectangle<Float> it measures an area. That is the same arithmetic and two different meanings, and the half-open rule is what makes the first one come out whole.

Open

  • Rectangle.center needs a Real scalar: the midpoint of a whole-number rectangle is not a whole number, and the library does not pick a rounding for a program.

Related

  • Box - the same in space.
  • Circle - the other shape a broad-phase test is written against.

field origin

origin: Vector2<Scalar>

The corner with the smaller coordinates.

field size

size: Vector2<Scalar>

How far the rectangle reaches from its origin, along each axis.

fn between

static fn between(first: Vector2<Scalar>, second: Vector2<Scalar>): Rectangle<Scalar>

The smallest rectangle with those two points as corners. Either point may be either corner.

print Rectangle.between Vector2(4, 4), Vector2(1, 2)

fn minimum

fn minimum(): Vector2<Scalar>

The corner with the smaller coordinates, which is inside the rectangle.

fn maximum

fn maximum(): Vector2<Scalar>

The corner with the larger coordinates, which is outside the rectangle.

fn isEmpty

fn isEmpty(): Bool

Whether the rectangle describes no points at all, which is the case as soon as a side is zero or negative.

fn area

fn area(): Scalar

How much the rectangle covers: cells for a whole-number scalar, area for one with fractions.

fn contains

fn contains(point: Vector2<Scalar>): Bool

Whether the point is inside, with the minimum edge in and the maximum edge out.

fn encloses

fn encloses(other: Rectangle<Scalar>): Bool

Whether the other rectangle is inside this one, edges included. An empty rectangle is inside everything.

fn intersects

fn intersects(other: Rectangle<Scalar>): Bool

Whether the two rectangles share at least one point. Touching along an edge is not sharing a point.

fn intersection

fn intersection(other: Rectangle<Scalar>): Rectangle<Scalar>

The rectangle both cover, which is empty where they do not overlap.

const first = Rectangle Vector2(0, 0), Vector2(4, 4)
print first.intersection(Rectangle(Vector2(2, 2), Vector2(4, 4)))

fn combined

fn combined(other: Rectangle<Scalar>): Rectangle<Scalar>

The smallest rectangle that covers both. An empty rectangle contributes nothing.

fn covering

fn covering(point: Vector2<Scalar>): Rectangle<Scalar>

The smallest rectangle whose corners hold this one and the point.

Like bounds, it answers the closed hull: the point can come to lie exactly on the maximum edge, and Rectangle.contains then answers false for it. A bounding rectangle is a bound and not a membership test.

fn translated

fn translated(by: Vector2<Scalar>): Rectangle<Scalar>

The same rectangle moved.

fn grown

fn grown(by: Vector2<Scalar>): Rectangle<Scalar>

The same rectangle with every side grown by that much on both ends. A negative amount shrinks it.

fn withSize

fn withSize(value: Vector2<Scalar>): Rectangle<Scalar>

The same rectangle with another size, from the same origin.

fn closestPoint

fn closestPoint(to: Vector2<Scalar>): Vector2<Scalar>

The point of the rectangle that is nearest to the one given, which is the point itself where it is inside.

fn bounds

fn bounds(): Rectangle<Scalar>

The rectangle itself: what every shape of this package answers, so that one broad phase can hold all of them.

extend Rectangle<Scalar>

extend<Scalar: Signed> Rectangle<Scalar>

What a sign buys: the distance to a point, measured along the axes.

fn manhattanDistanceTo

fn manhattanDistanceTo(point: Vector2<Scalar>): Scalar

The distance from the point to the nearest point of the rectangle, along the axes. Zero where it is inside.

extend Rectangle<Scalar>

extend<Scalar: Real> Rectangle<Scalar>

What a root and a halving buy: the midpoint, a rectangle written from one, and the euclidean distance.

fn centered

static fn centered(at: Vector2<Scalar>, size: Vector2<Scalar>): Rectangle<Scalar>

The rectangle of that size whose midpoint is the point given.

fn center

fn center(): Vector2<Scalar>

The midpoint.

fn distanceTo

fn distanceTo(point: Vector2<Scalar>): Scalar

The distance from the point to the nearest point of the rectangle. Zero where it is inside.

fn distanceSquaredTo

fn distanceSquaredTo(point: Vector2<Scalar>): Scalar

The square of Rectangle.distanceTo, for a comparison that needs no root.