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.isEmptysays so. Nothing normalizes a rectangle for you:intersectionanswers an empty one rather thanNone, so that a chain of them stays a rectangle. - The half-open rule is about membership, not about bounds.
boundsandcoveringanswer 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 andcontainsanswersfalsefor it. A bound is a bound; a tiling is what the half-open rule is for. areaon aRectangle<Int>counts cells, and on aRectangle<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.centerneeds aRealscalar: 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.