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.
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
--> }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 )
--> }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 )
--> }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.
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 )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.
Get the X axis of a rectangle;
Rectangle2d.xAxis rectangleis equivalent to
Frame2d.xAxis (Rectangle2d.axes rectangle)Get the Y axis of a rectangle;
Rectangle2d.yAxis rectangleis equivalent to
Frame2d.yAxis (Rectangle2d.axes rectangle)Get the center point of a rectangle.
Get the area of a rectangle:
rectangle =
Rectangle2d.fromExtrema
{ minX = 2
, maxX = 5
, minY = 1
, maxY = 3
}
Rectangle2d.area rectangle
--> 6Get 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 )
--> }Get the bottom left vertex of a rectangle;
Rectangle2d.bottomLeftVertex rectangleis equivalent to
(Rectangle2d.vertices rectangle).bottomLeftbut is more efficient.
Get the bottom right vertex of a rectangle;
Rectangle2d.bottomRightVertex rectangleis equivalent to
(Rectangle2d.vertices rectangle).bottomRightbut is more efficient.
Get the top left vertex of a rectangle;
Rectangle2d.topLeftVertex rectangleis equivalent to
(Rectangle2d.vertices rectangle).topLeftbut is more efficient.
Get the top right vertex of a rectangle;
Rectangle2d.topRightVertex rectangleis equivalent to
(Rectangle2d.vertices rectangle).topRightbut is more efficient.
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):
bottom edge is from the bottom left to bottom right vertexright edge is from the bottom right to top right vertextop edge is from the top right to top left vertexleft edge is from the top left to bottom left vertex(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 )
--> )
--> }Get the left edge of a rectangle;
Rectangle2d.leftEdge rectangleis equivalent to
(Rectangle2d.edges rectangle).leftbut is more efficient.
Get the bottom edge of a rectangle;
Rectangle2d.bottomEdge rectangleis equivalent to
(Rectangle2d.edges rectangle).bottombut is more efficient.
Get the right edge of a rectangle;
Rectangle2d.rightEdge rectangleis equivalent to
(Rectangle2d.edges rectangle).rightbut is more efficient.
Get the top edge of a rectangle;
Rectangle2d.topEdge rectangleis equivalent to
(Rectangle2d.edges rectangle).topbut is more efficient.
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
--> }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
--> FalseScale 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.
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 )
--> }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
--> }Translate a rectangle in a given direction by a given distance;
Rectangle2d.translateIn direction distanceis equivalent to
Rectangle2d.translateBy
(Vector2d.withLength distance direction)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.
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
--> }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
--> }