Source code for fibomat.shapes.circle
"""Provides the :class:`Circle` class."""
# pylint: disable=invalid-name
from __future__ import annotations
from typing import Optional
import numpy as np
from fibomat.shapes.shape import Shape
from fibomat.linalg import Vector, VectorLike, BoundingBox
from fibomat.shapes.arc_spline import ArcSpline, ArcSplineCompatible
[docs]class Circle(Shape, ArcSplineCompatible):
"""2-dim circle."""
[docs] def __init__(self, r: float, center: Optional[VectorLike] = None, description: Optional[str] = None):
"""
Args:
r (float): radius
center (:class:`~fibomat.linalg.vectortypes.VectorLike`, optional): center of circle, default to (0, 0)
description (str, optional): description
Raises:
ValueError: Raised if r <= 0.
"""
super().__init__(description)
self._center = Vector(center) if center is not None else Vector()
self._r = float(r)
if self._r <= 0:
raise ValueError('radius <= 0.')
[docs] @classmethod
def from_points(cls, p1: VectorLike, p2: VectorLike, p3: VectorLike, description: Optional[str] = None):
"""Create circumscribed circle (from three points).
Args:
p1 (VectorLike): first points
p2 (VectorLike): second points
p3 (VectorLike): third points
description (str, optional): description
Returns:
Circle
"""
# https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2
a = Vector(p1) # A
b = Vector(p2) - a # B
c = Vector(p3) - a # C
inv_d = 1 / (2 * (b.x * c.y - b.y * c.x))
b2 = b.x*b.x + b.y*b.y
c2 = c.x*c.x + c.y*c.y
u = Vector(inv_d * (c.y * b2 - b.y * c2), inv_d * (b.x * c2 - c.x * b2))
r = np.sqrt(u.x*u.x + u.y*u.y)
return cls(r, u + a, description)
def __repr__(self) -> str:
return '{}(r={!r}, center={!r})'.format(
self.__class__.__name__, self.r, self.center)
[docs] def to_arc_spline(self) -> ArcSpline:
return ArcSpline(
[(*(self._center + Vector(self._r, 0.)), 1.), (*(self._center - Vector(self._r, 0.)), 1.)],
True,
self.description
)
@property
def r(self) -> float:
"""Radius.
Access:
get
Returns:
float
"""
return self._r
@property
def center(self) -> Vector:
return self._center
@property
def bounding_box(self) -> BoundingBox:
return BoundingBox(self._center-(self._r, self._r), self._center + (self._r, self._r))
@property
def is_closed(self) -> bool:
return True
def _impl_translate(self, trans_vec: VectorLike) -> None:
self._center += Vector(trans_vec)
def _impl_rotate(self, theta: float) -> None:
self._center = self._center.rotated(theta)
def _impl_scale(self, fac: float) -> None:
self._center *= float(fac)
self._r *= float(fac)
def _impl_mirror(self, mirror_axis: VectorLike) -> None:
self._center = self._center.mirrored(mirror_axis)