Source code for fibomat.shapes.rect

"""Provides the :class:`Rect` class."""
from __future__ import annotations
from typing import Optional, List

import numpy as np

from fibomat.shapes import Shape
from fibomat.shapes.arc_spline import ArcSplineCompatible, ArcSpline
from fibomat.linalg import VectorLike, Vector, BoundingBox, signed_angle_between
from fibomat.shapes.line import Line


[docs]class Rect(Shape, ArcSplineCompatible): """2-dim rect."""
[docs] def __init__( # pylint: disable=too-many-arguments self, width: float, height: float, theta: float = 0, center: Optional[VectorLike] = None, description: Optional[str] = None ): """ Args: width (float): width of rect height (float): height of rect theta (float): rotation angle of rect, default to 0 center (VectorLike, optional): center of rect, default to (0, 0) description (str, optional): description """ super().__init__(description) width_half = float(width) / 2 height_half = float(height) / 2 center = Vector(center) self._rect = ArcSpline([ (*(center + (width_half, height_half)), 0.), (*(center + (-width_half, height_half)), 0.), (*(center + (-width_half, -height_half)), 0.), (*(center + (width_half, -height_half)), 0.) ], True).rotated(theta, 'center') self._rot_angle = float(theta)
# self._axes = VectorArray([float(width) / 2, 0.], [0., float(height) / 2]) # self._axes = self._axes.rotated(theta) # # self._center = Vector(center) if center is not None else Vector()
[docs] @classmethod def from_bounding_box(cls, bbox: BoundingBox) -> Rect: """Create a rect from a BoundingBox. Args: bbox: bounding box from which a rect is constructed Returns: Rect """ return cls(bbox.width, bbox.height, 0., bbox.center)
[docs] @classmethod def from_line(cls, line: Line, height: float): """Create a rect defined by a line a certain height Args: line (Line): height (float): Returns: Rect """ direction = (line.end - line.start) width = direction.mag # is theta correct? return cls(width=width, height=height, center=line.center, theta=direction.angle_about_x_axis)
[docs] def to_arc_spline(self) -> ArcSpline: vertices = np.append(self.corners, np.zeros(4)[:, np.newaxis], axis=1) return ArcSpline(vertices, True, self.description)
@property def width(self) -> float: """Width of rect. Access: get Returns: float """ start, end = self._rect.vertices[(0, 1), :2] return np.linalg.norm(start - end) @property def height(self) -> float: """Height of rect. Access: get Returns: float """ start, end = self._rect.vertices[(1, 2), :2] return np.linalg.norm(start - end) @property def theta(self) -> float: """ Rotation angle of rect. Access: get Returns: float """ return self._rot_angle @property def corners(self) -> List[Vector]: """Corner points of rect Access: get Returns: List[Vector] """ return [Vector(vec) for vec in self._rect.vertices[:, :2]] def __repr__(self) -> str: return '{}(width={!r}, height={!r}, theta={!r}, center={!r})'.format( self.__class__.__name__, self.width, self.height, self.theta, self.center) @property def center(self) -> Vector: return self._rect.center @property def bounding_box(self) -> BoundingBox: return BoundingBox.from_points(self.corners) @property def is_closed(self) -> bool: return True def _impl_translate(self, trans_vec: VectorLike) -> None: self._rect._impl_translate(trans_vec) def _impl_rotate(self, theta: float) -> None: self._rect._impl_rotate(theta) self._rot_angle += float(theta) def _impl_scale(self, fac: float) -> None: self._rect._impl_scale(fac) def _impl_mirror(self, mirror_axis: VectorLike) -> None: # how das mirroring affect rot angle? # TODO: test this carefully ref_vec = self._rect.vertices[0, :2] self._rect._impl_mirror(mirror_axis) rot_angle = signed_angle_between(ref_vec, self._rect.vertices[0, :2]) self._rot_angle += rot_angle