ianmackenzie / elm-geometry-prerelease / Rectangle2d

A Rectangle2d represents a rectangle in 2D space. This module contains rectangle-related functionality such as:

Unlike bounding boxes, rectangles are not constrained to be axis-aligned - they can have arbitrary orientation and so can be rotated, mirrored etc.


type alias Rectangle2d =
Geometry.Types.Rectangle2d

Construction

from : Point2d -> Point2d -> Rectangle2d

Construct an axis-aligned rectangle stretching from one point to another. The order of the points does not matter, and they can represent either the lower left and upper right vertices or the upper left and lower right.

p1 =
    Point2d.fromCoordinates ( 5, 2 )

p2 =
    Point2d.fromCoordinates ( 1, 4 )

Rectangle2d.from p1 p2
--> Rectangle2d.fromExtrema
-->     { minX = 1
-->     , maxX = 5
-->     , minY = 2
-->     , maxY = 4
-->     }

centeredOn : Frame2d -> ( Basics.Float, Basics.Float ) -> Rectangle2d

Construct a rectangle centered on the given axes (frame), with the given overall X/Y dimensions (width/height).

frame =
    Frame2d.atCoordinates ( 3, 2 )

rectangle =
    Rectangle2d.centeredOn frame ( 4, 3 )

Rectangle2d.vertices rectangle
--> { bottomLeft = Point2d.fromCoordinates ( 1, 0.5 )
--> , bottomRight = Point2d.fromCoordinates ( 5, 0.5 )
--> , topLeft = Point2d.fromCoordinates ( 1, 3.5 )
--> , topRight = Point2d.fromCoordinates ( 5, 3.5 )
--> }

fromExtrema : { minX : Basics.Float, maxX : Basics.Float, minY : Basics.Float, maxY : Basics.Float } -> Rectangle2d

Construct an axis-aligned rectangle by specifying its minimum and maximum X and Y coordinates. If the min and max are given in the wrong order, they will be swapped.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.vertices rectangle
--> { bottomLeft = Point2d.fromCoordinates ( 2, 1 )
--> , bottomRight = Point2d.fromCoordinates ( 5, 1 )
--> , topLeft = Point2d.fromCoordinates ( 2, 3 )
--> , topRight = Point2d.fromCoordinates ( 5, 3 )
--> }

fromExtremaIn : Frame2d -> { minX : Basics.Float, maxX : Basics.Float, minY : Basics.Float, maxY : Basics.Float } -> Rectangle2d

Construct a rectangle by supplying its maximum and minimum X and Y values within a particular frame:

frame =
    Frame2d.atCoordinates ( 5, 4 )

Rectangle2d.fromExtremaIn frame
    { minX = -1
    , minY = -1
    , maxX = 3
    , maxY = 2
    }
--> Rectangle2d.fromExtrema
-->     { minX = 4
-->     , minY = 3
-->     , maxX = 8
-->     , maxY = 6
-->     }

Note that for simplicity we used a non-rotated frame in the above example - if we had used a rotated frame, the result could not have been expressed using Rectangle2d.fromExtrema since it would no longer have been axis-aligned.

Properties

dimensions : Rectangle2d -> ( Basics.Float, Basics.Float )

Get the overall dimensions (width and height) of a rectangle:

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.dimensions rectangle
--> ( 3, 2 )

axes : Rectangle2d -> Frame2d

Get the central axes of a rectangle as a Frame2d:

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.axes rectangle
--> Frame2d.atCoordinates ( 3.5, 2 )

The origin point of the frame will be the center point of the rectangle.

xAxis : Rectangle2d -> Axis2d

Get the X axis of a rectangle;

Rectangle2d.xAxis rectangle

is equivalent to

Frame2d.xAxis (Rectangle2d.axes rectangle)

yAxis : Rectangle2d -> Axis2d

Get the Y axis of a rectangle;

Rectangle2d.yAxis rectangle

is equivalent to

Frame2d.yAxis (Rectangle2d.axes rectangle)

centerPoint : Rectangle2d -> Point2d

Get the center point of a rectangle.

area : Rectangle2d -> Basics.Float

Get the area of a rectangle:

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.area rectangle
--> 6

vertices : Rectangle2d -> { bottomLeft : Point2d, bottomRight : Point2d, topRight : Point2d, topLeft : Point2d }

Get the vertices of a rectangle as a record. Note that 'bottom', 'top', 'left' and 'right' are with respect to the rectangle's axes, so the may not correspond to global up/down or left/right if the rectangle has been rotated or mirrored.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.vertices rectangle
--> { bottomLeft = Point2d.fromCoordinates ( 2, 1 )
--> , bottomRight = Point2d.fromCoordinates ( 5, 1 )
--> , topLeft = Point2d.fromCoordinates ( 2, 3 )
--> , topRight = Point2d.fromCoordinates ( 5, 3 )
--> }

bottomLeftVertex : Rectangle2d -> Point2d

Get the bottom left vertex of a rectangle;

Rectangle2d.bottomLeftVertex rectangle

is equivalent to

(Rectangle2d.vertices rectangle).bottomLeft

but is more efficient.

bottomRightVertex : Rectangle2d -> Point2d

Get the bottom right vertex of a rectangle;

Rectangle2d.bottomRightVertex rectangle

is equivalent to

(Rectangle2d.vertices rectangle).bottomRight

but is more efficient.

topLeftVertex : Rectangle2d -> Point2d

Get the top left vertex of a rectangle;

Rectangle2d.topLeftVertex rectangle

is equivalent to

(Rectangle2d.vertices rectangle).topLeft

but is more efficient.

topRightVertex : Rectangle2d -> Point2d

Get the top right vertex of a rectangle;

Rectangle2d.topRightVertex rectangle

is equivalent to

(Rectangle2d.vertices rectangle).topRight

but is more efficient.

edges : Rectangle2d -> { bottom : LineSegment2d, right : LineSegment2d, top : LineSegment2d, left : LineSegment2d }

Get the edges of a rectangle as a record. Note that 'bottom', 'top', 'left' and 'right' are with respect to the rectangle's axes, so the may not correspond to global up/down or left/right if the rectangle has been rotated or mirrored. The orientation of each edge is chosen so that it will be in a counterclockwise direction (unless the rectangle has been mirrored):

(Note that this ordering will lead to each edge being in a clockwise direction if the rectangle has been mirrored.)

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.edges rectangle
--> { bottom =
-->     LineSegment2d.fromEndpoints
-->         ( Point2d.fromCoordinates ( 2, 1 )
-->         , Point2d.fromCoordinates ( 5, 1 )
-->         )
--> , right =
-->     LineSegment2d.fromEndpoints
-->         ( Point2d.fromCoordinates ( 5, 1 )
-->         , Point2d.fromCoordinates ( 5, 3 )
-->         )
--> , top =
-->     LineSegment2d.fromEndpoints
-->         ( Point2d.fromCoordinates ( 5, 3 )
-->         , Point2d.fromCoordinates ( 2, 3 )
-->         )
--> , left =
-->     LineSegment2d.fromEndpoints
-->         ( Point2d.fromCoordinates ( 2, 3 )
-->         , Point2d.fromCoordinates ( 2, 1 )
-->         )
--> }

leftEdge : Rectangle2d -> LineSegment2d

Get the left edge of a rectangle;

Rectangle2d.leftEdge rectangle

is equivalent to

(Rectangle2d.edges rectangle).left

but is more efficient.

bottomEdge : Rectangle2d -> LineSegment2d

Get the bottom edge of a rectangle;

Rectangle2d.bottomEdge rectangle

is equivalent to

(Rectangle2d.edges rectangle).bottom

but is more efficient.

rightEdge : Rectangle2d -> LineSegment2d

Get the right edge of a rectangle;

Rectangle2d.rightEdge rectangle

is equivalent to

(Rectangle2d.edges rectangle).right

but is more efficient.

topEdge : Rectangle2d -> LineSegment2d

Get the top edge of a rectangle;

Rectangle2d.topEdge rectangle

is equivalent to

(Rectangle2d.edges rectangle).top

but is more efficient.

boundingBox : Rectangle2d -> BoundingBox2d

Get the minimal bounding box containing a given rectangle. This have exactly the same shape and size as the rectangle itself if the rectangle is axis-aligned, but will be larger than the rectangle if the rectangle is at an angle.

square =
    Rectangle2d.fromExtrema
        { minX = 0
        , maxX = 1
        , minY = 0
        , maxY = 1
        }

diamond =
    square
        |> Rectangle2d.rotateAround Point2d.origin
            (degrees 45)

Rectangle2d.boundingBox diamond
--> BoundingBox2d.fromExtrema
-->     { minX = -0.7071
-->     , maxX = 0.7071
-->     , minY = 0
-->     , maxY = 1.4142
-->     }

Querying

contains : Point2d -> Rectangle2d -> Basics.Bool

Check if a rectangle contains a given point:

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

p1 =
    Point2d.fromCoordinates ( 3, 2 )

p2 =
    Point2d.fromCoordinates ( 3, 4 )

rectangle |> Rectangle2d.contains p1
--> True

rectangle |> Rectangle2d.contains p2
--> False

Conversion

toPolygon : Rectangle2d -> Polygon2d

Convert a rectangle to a Polygon2d.

Transformation

scaleAbout : Point2d -> Basics.Float -> Rectangle2d -> Rectangle2d

Scale a rectangle about a given point by a given scale.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

rectangle
    |> Rectangle2d.scaleAbout Point2d.origin 2
--> Rectangle2d.fromExtrema
-->     { minX = 4
-->     , maxX = 10
-->     , minY = 2
-->     , maxY = 6
-->     }

Note that scaling by a negative value will flip the handedness of the rectangle's axes, and therefore the order/direction of results from Rectangle2d.vertices and Rectangle2d.edges will change.

rotateAround : Point2d -> Basics.Float -> Rectangle2d -> Rectangle2d

Rotate a rectangle around a given point by a given angle (in radians).

rectangle =
    Rectangle2d.fromExtrema
        { minX = 0
        , maxX = 1
        , minY = 0
        , maxY = 1
        }

rotated =
    rectangle
        |> Rectangle2d.rotateAround Point2d.origin
            (degrees 45)

Rectangle2d.centerPoint rotated
--> Point2d.fromCoordinates ( 0, 0.7071 )

Rectangle2d.xDirection rotated
--> Direction2d.fromAngle (degrees 45)

Rectangle2d.vertices rotated
--> { bottomLeft =
-->     Point2d.origin
--> , bottomRight =
-->     Point2d.fromCoordinates ( 0.7071, 0.7071 )
--> , topRight =
-->     Point2d.fromCoordinates ( 0, 1.4142 )
--> , topLeft =
-->     Point2d.fromCoordinates ( -0.7071, 0.7071 )
--> }

translateBy : Vector2d -> Rectangle2d -> Rectangle2d

Translate a rectangle by a given displacement.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

displacement =
    Vector2d.fromComponents ( 2, -3 )

Rectangle2d.translateBy displacement rectangle
--> Rectangle2d.fromExtrema
-->     { minX = 4
-->     , maxX = 7
-->     , minY = -2
-->     , maxY = 0
-->     }

translateIn : Direction2d -> Basics.Float -> Rectangle2d -> Rectangle2d

Translate a rectangle in a given direction by a given distance;

Rectangle2d.translateIn direction distance

is equivalent to

Rectangle2d.translateBy
    (Vector2d.withLength distance direction)

mirrorAcross : Axis2d -> Rectangle2d -> Rectangle2d

Mirror a rectangle across a given axis.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

Rectangle2d.mirrorAcross Axis2d.x rectangle
--> Rectangle2d.fromExtrema
-->     { minX = 2
-->     , maxX = 5
-->     , minY = -3
-->     , maxY = -1
-->     }

Note that this will flip the handedness of the rectangle's axes, and therefore the order/direction of results from Rectangle2d.vertices and Rectangle2d.edges will change.

Coordinate conversions

relativeTo : Frame2d -> Rectangle2d -> Rectangle2d

Take a rectangle defined in global coordinates, and return it expressed in local coordinates relative to a given reference frame.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

localFrame =
    Frame2d.atCoordinates ( 1, 2 )

Rectangle2d.relativeTo localFrame rectangle
--> Rectangle2d.fromExtrema
-->     { minX = 1
-->     , maxX = 4
-->     , minY = -1
-->     , maxY = 1
-->     }

placeIn : Frame2d -> Rectangle2d -> Rectangle2d

Take a rectangle considered to be defined in local coordinates relative to a given reference frame, and return that rectangle expressed in global coordinates.

rectangle =
    Rectangle2d.fromExtrema
        { minX = 2
        , maxX = 5
        , minY = 1
        , maxY = 3
        }

localFrame =
    Frame2d.atCoordinates ( 1, 2 )

Rectangle2d.placeIn localFrame rectangle
--> Rectangle2d.fromExtrema
-->     { minX = 3
-->     , maxX = 6
-->     , minY = 3
-->     , maxY = 5
-->     }