Skip to content

Axis Aligned Rectangle

Axis Aligned Rectangle class

AxisAlignedRectangle

Bases: Rectangle

Axis Aligned Rectangle class that inherits from Rectangle. It defines a rectangle that is axis-aligned, meaning:

  • its sides are parallel to the X and Y axes
  • the first point is the top-left point (considering the y-axis pointing downwards)
  • the points are ordered clockwise
Source code in otary/geometry/discrete/shape/axis_aligned_rectangle.py
class AxisAlignedRectangle(Rectangle):
    """
    Axis Aligned Rectangle class that inherits from Rectangle.
    It defines a rectangle that is axis-aligned, meaning:

     - its sides are parallel to the X and Y axes
     - the first point is the top-left point (considering the y-axis pointing downwards)
     - the points are ordered clockwise
    """

    def __init__(self, points: NDArray | list, is_cast_int: bool = False) -> None:
        super().__init__(points=points, is_cast_int=is_cast_int)

        if not self.is_axis_aligned:
            raise ValueError(
                "Trying to create an AxisAlignedRectangle from a non-axis-aligned "
                "rectangle. Please check the input points."
            )

    @classmethod
    def from_rectangle(cls, rectangle: Rectangle) -> AxisAlignedRectangle:
        """Create an AxisAlignedRectangle from an ordinary Rectangle.
        Only works if the input Rectangle forms an AxisAlignedRectangle with its points.

        Args:
            rectangle (Rectangle): Rectangle object

        Returns:
            AxisAlignedRectangle: AxisAlignedRectangle object
        """
        return cls(points=rectangle.points)

    @classmethod
    def from_center(
        cls,
        center: NDArray,
        width: float,
        height: float,
        is_cast_int: bool = False,
    ) -> AxisAlignedRectangle:
        """Create an AxisAlignedRectangle from a center point

        Args:
            center (NDArray): center point of the rectangle
            width (float): width of the rectangle
            height (float): height of the rectangle
            is_cast_int (bool, optional): cast the points coordinates to int

        Returns:
            AxisAlignedRectangle: new AxisAlignedRectangle object
        """
        return cls.from_rectangle(
            super().from_center(center, width, height, is_cast_int=is_cast_int)
        )

    @property
    def height(self) -> float:
        """Get the height of the AxisAlignedRectangle

        Returns:
            float: height of the rectangle
        """
        return self.ymax - self.ymin

    @property
    def width(self) -> float:
        """Get the width of the AxisAlignedRectangle

        Returns:
            float: width of the rectangle
        """
        return self.xmax - self.xmin

    @property
    def area(self) -> float:
        """Get the area of the AxisAlignedRectangle

        Returns:
            float: area of the rectangle
        """
        return self.width * self.height

    @property
    def perimeter(self) -> float:
        """Get the perimeter of the AxisAlignedRectangle

        Returns:
            float: perimeter of the rectangle
        """
        return 2 * (self.width + self.height)

    @property
    def as_pymupdf_rect(self) -> pymupdf.Rect:
        """Get the pymupdf representation of the given Rectangle.
        Beware a pymupdf can only be straight or axis-aligned.

        See: https://pymupdf.readthedocs.io/en/latest/rect.html

        Returns:
            pymupdf.Rect: pymupdf axis-aligned Rect object
        """
        return pymupdf.Rect(x0=self.xmin, y0=self.ymin, x1=self.xmax, y1=self.ymax)

    @property
    def rotated90(self) -> AxisAlignedRectangle:
        """Get the unique other related AxisAlignedRectangle that is the same one
        but rotated 90 degrees around its center.

        Returns:
            AxisAlignedRectangle: new AxisAlignedRectangle object
        """
        return AxisAlignedRectangle.from_center(
            center=self.centroid, width=self.height, height=self.width
        )

    def rotate(
        self,
        angle: float,
        is_degree: bool = False,
        is_clockwise: bool = True,
        pivot: Optional[NDArray] = None,
    ):
        """The in-place rotate method is not supported for AxisAlignedRectangle.
        Use the rotate_transform method instead.
        """
        raise TypeError("AxisAlignedRectangle does not support arbitrary rotation.")

    def rotate_transform(
        self,
        angle: float,
        is_degree: bool = False,
        is_clockwise: bool = True,
        pivot: Optional[NDArray] = None,
    ) -> Rectangle:
        """Rotate the AxisAlignedRectangle and transform it into a Rectangle.
        The result is a Rectangle object since the result is not
        guaranteed to be axis-aligned anymore.

        Args:
            angle (float): rotation angle
            is_degree (bool, optional): whether the angle is in degree or radian.
                Defaults to False which means radians.
            is_clockwise (bool, optional): whether the rotation is clockwise or
                counter-clockwise. Defaults to True.
            pivot (NDArray, optional): pivot point.
                Defaults to None which means that by default the centroid point of
                the shape is taken as the pivot point.

        Returns:
            Rectangle: object resulting from the rotation

        Example:
            The rotate method does not modify the original AxisAlignedRectangle object:
            ```python
            >>> rect = ot.AxisAlignedRectangle(points=[[0, 0], [4, 0], [4, 3], [0, 3]])
            >>> rot_rect = rect.rotate(angle=45, is_degree=True)
            >>> rot_rect.asarray
            array([[ 1.6464466 , -0.9748737 ],
                   [ 4.4748735 ,  1.8535534 ],
                   [ 2.3535533 ,  3.9748738 ],
                   [-0.47487372,  1.1464466 ]], dtype=float32)
            >>> rect
            array([[0, 0],
                   [4, 0],
                   [4, 3],
                   [0, 3]], dtype=int32)
            ```
        """
        # pylint: disable=R0801
        if pivot is None:
            pivot = self.centroid

        rot_points = rotate_2d_points(
            points=self.points,
            angle=angle,
            pivot=pivot,
            is_degree=is_degree,
            is_clockwise=is_clockwise,
        )
        return Rectangle(points=rot_points)

area property

Get the area of the AxisAlignedRectangle

Returns:

Name Type Description
float float

area of the rectangle

as_pymupdf_rect property

Get the pymupdf representation of the given Rectangle. Beware a pymupdf can only be straight or axis-aligned.

See: https://pymupdf.readthedocs.io/en/latest/rect.html

Returns:

Type Description
Rect

pymupdf.Rect: pymupdf axis-aligned Rect object

height property

Get the height of the AxisAlignedRectangle

Returns:

Name Type Description
float float

height of the rectangle

perimeter property

Get the perimeter of the AxisAlignedRectangle

Returns:

Name Type Description
float float

perimeter of the rectangle

rotated90 property

Get the unique other related AxisAlignedRectangle that is the same one but rotated 90 degrees around its center.

Returns:

Name Type Description
AxisAlignedRectangle AxisAlignedRectangle

new AxisAlignedRectangle object

width property

Get the width of the AxisAlignedRectangle

Returns:

Name Type Description
float float

width of the rectangle

from_center(center, width, height, is_cast_int=False) classmethod

Create an AxisAlignedRectangle from a center point

Parameters:

Name Type Description Default
center NDArray

center point of the rectangle

required
width float

width of the rectangle

required
height float

height of the rectangle

required
is_cast_int bool

cast the points coordinates to int

False

Returns:

Name Type Description
AxisAlignedRectangle AxisAlignedRectangle

new AxisAlignedRectangle object

Source code in otary/geometry/discrete/shape/axis_aligned_rectangle.py
@classmethod
def from_center(
    cls,
    center: NDArray,
    width: float,
    height: float,
    is_cast_int: bool = False,
) -> AxisAlignedRectangle:
    """Create an AxisAlignedRectangle from a center point

    Args:
        center (NDArray): center point of the rectangle
        width (float): width of the rectangle
        height (float): height of the rectangle
        is_cast_int (bool, optional): cast the points coordinates to int

    Returns:
        AxisAlignedRectangle: new AxisAlignedRectangle object
    """
    return cls.from_rectangle(
        super().from_center(center, width, height, is_cast_int=is_cast_int)
    )

from_rectangle(rectangle) classmethod

Create an AxisAlignedRectangle from an ordinary Rectangle. Only works if the input Rectangle forms an AxisAlignedRectangle with its points.

Parameters:

Name Type Description Default
rectangle Rectangle

Rectangle object

required

Returns:

Name Type Description
AxisAlignedRectangle AxisAlignedRectangle

AxisAlignedRectangle object

Source code in otary/geometry/discrete/shape/axis_aligned_rectangle.py
@classmethod
def from_rectangle(cls, rectangle: Rectangle) -> AxisAlignedRectangle:
    """Create an AxisAlignedRectangle from an ordinary Rectangle.
    Only works if the input Rectangle forms an AxisAlignedRectangle with its points.

    Args:
        rectangle (Rectangle): Rectangle object

    Returns:
        AxisAlignedRectangle: AxisAlignedRectangle object
    """
    return cls(points=rectangle.points)

rotate(angle, is_degree=False, is_clockwise=True, pivot=None)

The in-place rotate method is not supported for AxisAlignedRectangle. Use the rotate_transform method instead.

Source code in otary/geometry/discrete/shape/axis_aligned_rectangle.py
def rotate(
    self,
    angle: float,
    is_degree: bool = False,
    is_clockwise: bool = True,
    pivot: Optional[NDArray] = None,
):
    """The in-place rotate method is not supported for AxisAlignedRectangle.
    Use the rotate_transform method instead.
    """
    raise TypeError("AxisAlignedRectangle does not support arbitrary rotation.")

rotate_transform(angle, is_degree=False, is_clockwise=True, pivot=None)

Rotate the AxisAlignedRectangle and transform it into a Rectangle. The result is a Rectangle object since the result is not guaranteed to be axis-aligned anymore.

Parameters:

Name Type Description Default
angle float

rotation angle

required
is_degree bool

whether the angle is in degree or radian. Defaults to False which means radians.

False
is_clockwise bool

whether the rotation is clockwise or counter-clockwise. Defaults to True.

True
pivot NDArray

pivot point. Defaults to None which means that by default the centroid point of the shape is taken as the pivot point.

None

Returns:

Name Type Description
Rectangle Rectangle

object resulting from the rotation

Example

The rotate method does not modify the original AxisAlignedRectangle object:

>>> rect = ot.AxisAlignedRectangle(points=[[0, 0], [4, 0], [4, 3], [0, 3]])
>>> rot_rect = rect.rotate(angle=45, is_degree=True)
>>> rot_rect.asarray
array([[ 1.6464466 , -0.9748737 ],
       [ 4.4748735 ,  1.8535534 ],
       [ 2.3535533 ,  3.9748738 ],
       [-0.47487372,  1.1464466 ]], dtype=float32)
>>> rect
array([[0, 0],
       [4, 0],
       [4, 3],
       [0, 3]], dtype=int32)

Source code in otary/geometry/discrete/shape/axis_aligned_rectangle.py
def rotate_transform(
    self,
    angle: float,
    is_degree: bool = False,
    is_clockwise: bool = True,
    pivot: Optional[NDArray] = None,
) -> Rectangle:
    """Rotate the AxisAlignedRectangle and transform it into a Rectangle.
    The result is a Rectangle object since the result is not
    guaranteed to be axis-aligned anymore.

    Args:
        angle (float): rotation angle
        is_degree (bool, optional): whether the angle is in degree or radian.
            Defaults to False which means radians.
        is_clockwise (bool, optional): whether the rotation is clockwise or
            counter-clockwise. Defaults to True.
        pivot (NDArray, optional): pivot point.
            Defaults to None which means that by default the centroid point of
            the shape is taken as the pivot point.

    Returns:
        Rectangle: object resulting from the rotation

    Example:
        The rotate method does not modify the original AxisAlignedRectangle object:
        ```python
        >>> rect = ot.AxisAlignedRectangle(points=[[0, 0], [4, 0], [4, 3], [0, 3]])
        >>> rot_rect = rect.rotate(angle=45, is_degree=True)
        >>> rot_rect.asarray
        array([[ 1.6464466 , -0.9748737 ],
               [ 4.4748735 ,  1.8535534 ],
               [ 2.3535533 ,  3.9748738 ],
               [-0.47487372,  1.1464466 ]], dtype=float32)
        >>> rect
        array([[0, 0],
               [4, 0],
               [4, 3],
               [0, 3]], dtype=int32)
        ```
    """
    # pylint: disable=R0801
    if pivot is None:
        pivot = self.centroid

    rot_points = rotate_2d_points(
        points=self.points,
        angle=angle,
        pivot=pivot,
        is_degree=is_degree,
        is_clockwise=is_clockwise,
    )
    return Rectangle(points=rot_points)