otary 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- otary-0.1.0/PKG-INFO +19 -0
- otary-0.1.0/README.md +0 -0
- otary-0.1.0/otary/__init__.py +0 -0
- otary-0.1.0/otary/geometry/__init__.py +32 -0
- otary-0.1.0/otary/geometry/continuous/entity.py +172 -0
- otary-0.1.0/otary/geometry/continuous/shape/circle.py +237 -0
- otary-0.1.0/otary/geometry/continuous/shape/ellipse.py +333 -0
- otary-0.1.0/otary/geometry/discrete/entity.py +511 -0
- otary-0.1.0/otary/geometry/discrete/linear/__init__.py +0 -0
- otary-0.1.0/otary/geometry/discrete/linear/directed/__init__.py +0 -0
- otary-0.1.0/otary/geometry/discrete/linear/directed/entity.py +91 -0
- otary-0.1.0/otary/geometry/discrete/linear/directed/vector.py +83 -0
- otary-0.1.0/otary/geometry/discrete/linear/directed/vectorized_linear_spline.py +44 -0
- otary-0.1.0/otary/geometry/discrete/linear/entity.py +107 -0
- otary-0.1.0/otary/geometry/discrete/linear/segment.py +261 -0
- otary-0.1.0/otary/geometry/discrete/linear/spline.py +111 -0
- otary-0.1.0/otary/geometry/discrete/point.py +124 -0
- otary-0.1.0/otary/geometry/discrete/shape/__init__.py +0 -0
- otary-0.1.0/otary/geometry/discrete/shape/polygon.py +894 -0
- otary-0.1.0/otary/geometry/discrete/shape/rectangle.py +418 -0
- otary-0.1.0/otary/geometry/discrete/shape/triangle.py +16 -0
- otary-0.1.0/otary/geometry/entity.py +227 -0
- otary-0.1.0/otary/geometry/utils/constants.py +7 -0
- otary-0.1.0/otary/geometry/utils/tools.py +110 -0
- otary-0.1.0/otary/image/__init__.py +25 -0
- otary-0.1.0/otary/image/base.py +340 -0
- otary-0.1.0/otary/image/components/__init__.py +10 -0
- otary-0.1.0/otary/image/components/drawer/__init__.py +22 -0
- otary-0.1.0/otary/image/components/drawer/drawer.py +242 -0
- otary-0.1.0/otary/image/components/drawer/utils/render.py +94 -0
- otary-0.1.0/otary/image/components/drawer/utils/tools.py +103 -0
- otary-0.1.0/otary/image/components/io/reader.py +154 -0
- otary-0.1.0/otary/image/components/io/utils/readfile.py +101 -0
- otary-0.1.0/otary/image/components/io/writer.py +63 -0
- otary-0.1.0/otary/image/components/transformer/__init__.py +0 -0
- otary-0.1.0/otary/image/components/transformer/components/__init__.py +23 -0
- otary-0.1.0/otary/image/components/transformer/components/binarizer/binarizer.py +152 -0
- otary-0.1.0/otary/image/components/transformer/components/binarizer/utils/thresholding.py +89 -0
- otary-0.1.0/otary/image/components/transformer/components/cropper/cropper.py +351 -0
- otary-0.1.0/otary/image/components/transformer/components/geometrizer/geometrizer.py +217 -0
- otary-0.1.0/otary/image/components/transformer/components/morphologyzer/morphologyzer.py +234 -0
- otary-0.1.0/otary/image/components/transformer/transformer.py +30 -0
- otary-0.1.0/otary/image/image.py +1738 -0
- otary-0.1.0/otary/image/utils/__init__.py +0 -0
- otary-0.1.0/otary/image/utils/colors.py +50 -0
- otary-0.1.0/otary/utils/__init__.py +0 -0
- otary-0.1.0/otary/utils/cv/ocrsingleoutput.py +15 -0
- otary-0.1.0/otary/utils/perf_eval.py +27 -0
- otary-0.1.0/otary/utils/tools.py +25 -0
- otary-0.1.0/pyproject.toml +77 -0
otary-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: otary
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Image and 2D Geometry library for easy and fast image manipulation
|
|
5
|
+
Author: Alexandre Poupeau
|
|
6
|
+
Author-email: alexandre.poupeau.contact@gmail.com
|
|
7
|
+
Requires-Python: >=3.11.2,<4.0.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Requires-Dist: metpy (>=1.6.2,<2.0.0)
|
|
12
|
+
Requires-Dist: opencv-python (>=4.10.0.84,<5.0.0.0)
|
|
13
|
+
Requires-Dist: pymupdf (>=1.24.12,<2.0.0)
|
|
14
|
+
Requires-Dist: setuptools (>=70.0.0,<71.0.0)
|
|
15
|
+
Requires-Dist: shapely (>=2.0.4,<3.0.0)
|
|
16
|
+
Requires-Dist: sympy (>=1.12,<2.0)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
|
otary-0.1.0/README.md
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to facilitate imports in geometry
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"DEFAULT_MARGIN_ANGLE_ERROR",
|
|
7
|
+
"Point",
|
|
8
|
+
"Segment",
|
|
9
|
+
"Vector",
|
|
10
|
+
"LinearSpline",
|
|
11
|
+
"VectorizedLinearSpline",
|
|
12
|
+
"Polygon",
|
|
13
|
+
"Triangle",
|
|
14
|
+
"Rectangle",
|
|
15
|
+
"Ellipse",
|
|
16
|
+
"Circle",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# pylint: disable=cyclic-import
|
|
20
|
+
from otary.geometry.utils.constants import DEFAULT_MARGIN_ANGLE_ERROR
|
|
21
|
+
from otary.geometry.discrete.point import Point
|
|
22
|
+
from otary.geometry.discrete.linear.segment import Segment
|
|
23
|
+
from otary.geometry.discrete.linear.directed.vector import Vector
|
|
24
|
+
from otary.geometry.discrete.linear.spline import LinearSpline
|
|
25
|
+
from otary.geometry.discrete.linear.directed.vectorized_linear_spline import (
|
|
26
|
+
VectorizedLinearSpline,
|
|
27
|
+
)
|
|
28
|
+
from otary.geometry.discrete.shape.polygon import Polygon
|
|
29
|
+
from otary.geometry.discrete.shape.triangle import Triangle
|
|
30
|
+
from otary.geometry.discrete.shape.rectangle import Rectangle
|
|
31
|
+
from otary.geometry.continuous.shape.ellipse import Ellipse
|
|
32
|
+
from otary.geometry.continuous.shape.circle import Circle
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ContinuousGeometryEntity module class
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
|
|
9
|
+
import cv2
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from otary.geometry.entity import GeometryEntity
|
|
13
|
+
from otary.geometry import Polygon, Rectangle
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ContinuousGeometryEntity(GeometryEntity, ABC):
|
|
17
|
+
"""
|
|
18
|
+
ContinuousGeometryEntity class which is the abstract base class for
|
|
19
|
+
continuous or smooth geometry objects like circles, ellipse, etc...
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
DEFAULT_N_POINTS_POLYGONAL_APPROX = 1000
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self, n_points_polygonal_approx: int = DEFAULT_N_POINTS_POLYGONAL_APPROX
|
|
26
|
+
):
|
|
27
|
+
"""Initialize a ContinuousGeometryEntity object
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
n_points_polygonal_approx (int, optional): n points to be used in
|
|
31
|
+
the polygonal approximation.
|
|
32
|
+
Defaults to DEFAULT_N_POINTS_POLYGONAL_APPROX.
|
|
33
|
+
"""
|
|
34
|
+
self._n_points_polygonal_approx = n_points_polygonal_approx
|
|
35
|
+
|
|
36
|
+
# --------------------------------- PROPERTIES ------------------------------------
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def n_points_polygonal_approx(self) -> int:
|
|
40
|
+
"""Get the number of points for the polygonal approximation.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
int: The number of points used in the polygonal approximation.
|
|
44
|
+
"""
|
|
45
|
+
return self._n_points_polygonal_approx
|
|
46
|
+
|
|
47
|
+
@n_points_polygonal_approx.setter
|
|
48
|
+
def n_points_polygonal_approx(self, value):
|
|
49
|
+
"""
|
|
50
|
+
Set the number of points for the polygonal approximation.
|
|
51
|
+
This would also update the polygonal approximation of the geometry entity.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
value (int): The number of points to be used in the polygonal approximation.
|
|
55
|
+
"""
|
|
56
|
+
self._n_points_polygonal_approx = value
|
|
57
|
+
self.update_polyapprox()
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def polyaprox(self) -> Polygon:
|
|
61
|
+
"""Generate a polygonal approximation of the continuous geometry entity
|
|
62
|
+
No setter is defined for this property as it is a read-only property.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Polygon: polygonal approximation of the continuous geometry entity
|
|
66
|
+
"""
|
|
67
|
+
return self._polyapprox
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def polygonal_approx(self, n_points: int, is_cast_int: bool) -> Polygon:
|
|
71
|
+
"""Generate a polygonal approximation of the continuous geometry entity
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
n_points (int): number of points that make up the polygonal
|
|
75
|
+
approximation. The bigger the better to obtain more precise
|
|
76
|
+
results in intersection or other similar computations.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Polygon: polygonal approximation of the continuous geometry entity
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def xmax(self) -> float:
|
|
84
|
+
"""Get the maximum X coordinate of the geometry entity
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
np.ndarray: 2D point
|
|
88
|
+
"""
|
|
89
|
+
return self.polyaprox.xmax
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def xmin(self) -> float:
|
|
93
|
+
"""Get the minimum X coordinate of the geometry entity
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
np.ndarray: 2D point
|
|
97
|
+
"""
|
|
98
|
+
return self.polyaprox.xmin
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def ymax(self) -> float:
|
|
102
|
+
"""Get the maximum Y coordinate of the geometry entity
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
np.ndarray: 2D point
|
|
106
|
+
"""
|
|
107
|
+
return self.polyaprox.ymax
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def ymin(self) -> float:
|
|
111
|
+
"""Get the minimum Y coordinate of the geometry entity
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
np.ndarray: 2D point
|
|
115
|
+
"""
|
|
116
|
+
return self.polyaprox.ymin
|
|
117
|
+
|
|
118
|
+
# ---------------------------- MODIFICATION METHODS -------------------------------
|
|
119
|
+
|
|
120
|
+
# done in the derived classes
|
|
121
|
+
|
|
122
|
+
# ------------------------------- CLASSIC METHODS ---------------------------------
|
|
123
|
+
|
|
124
|
+
def update_polyapprox(self) -> None:
|
|
125
|
+
"""Update the polygonal approximation of the continuous geometry entity"""
|
|
126
|
+
self._polyapprox = self.polygonal_approx(
|
|
127
|
+
n_points=self.n_points_polygonal_approx, is_cast_int=False
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def enclosing_axis_aligned_bbox(self) -> Rectangle:
|
|
131
|
+
"""Compute the smallest area enclosing Axis-Aligned Bounding Box (AABB)
|
|
132
|
+
See: https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Rectangle: Rectangle object
|
|
136
|
+
"""
|
|
137
|
+
topleft_x, topleft_y, width, height = cv2.boundingRect(
|
|
138
|
+
array=self.polyaprox.asarray
|
|
139
|
+
)
|
|
140
|
+
bbox = np.array(
|
|
141
|
+
[
|
|
142
|
+
[topleft_x, topleft_y],
|
|
143
|
+
[topleft_x + width, topleft_y],
|
|
144
|
+
[topleft_x + width, topleft_y + height],
|
|
145
|
+
[topleft_x, topleft_y + height],
|
|
146
|
+
]
|
|
147
|
+
)
|
|
148
|
+
return Rectangle(bbox)
|
|
149
|
+
|
|
150
|
+
def enclosing_oriented_bbox(self) -> Rectangle:
|
|
151
|
+
"""Compute the smallest area enclosing Oriented Bounding Box (OBB)
|
|
152
|
+
See: https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Rectangle: Rectangle object
|
|
156
|
+
"""
|
|
157
|
+
rect = cv2.minAreaRect(self.polyaprox.asarray)
|
|
158
|
+
bbox = cv2.boxPoints(rect)
|
|
159
|
+
return Rectangle(bbox)
|
|
160
|
+
|
|
161
|
+
def enclosing_convex_hull(self) -> "Polygon":
|
|
162
|
+
"""Compute the smallest area enclosing Convex Hull
|
|
163
|
+
See: https://docs.opencv.org/3.4/dd/d49/tutorial_py_contour_features.html
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Polygon: Polygon object
|
|
167
|
+
"""
|
|
168
|
+
# pylint: disable=import-outside-toplevel
|
|
169
|
+
from otary.geometry import Polygon
|
|
170
|
+
|
|
171
|
+
convexhull = np.squeeze(cv2.convexHull(self.polyaprox.asarray))
|
|
172
|
+
return Polygon(convexhull)
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Circle Geometric Object
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Self, Optional
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
from shapely import Polygon as SPolygon, LinearRing
|
|
12
|
+
|
|
13
|
+
from otary.geometry.utils.tools import rotate_2d_points
|
|
14
|
+
from otary.geometry.continuous.entity import ContinuousGeometryEntity
|
|
15
|
+
from otary.geometry import Ellipse, Polygon
|
|
16
|
+
from otary.utils.tools import assert_transform_shift_vector
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Circle(Ellipse):
|
|
20
|
+
"""Circle geometrical object"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
center: NDArray,
|
|
25
|
+
radius: float,
|
|
26
|
+
n_points_polygonal_approx: int = ContinuousGeometryEntity.DEFAULT_N_POINTS_POLYGONAL_APPROX,
|
|
27
|
+
):
|
|
28
|
+
"""Initialize a Circle geometrical object
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
center (NDArray): center 2D point
|
|
32
|
+
radius (float): radius value
|
|
33
|
+
n_points_polygonal_approx (int, optional): number of points to be used in
|
|
34
|
+
the polygonal approximation of the circle. Defaults to
|
|
35
|
+
ContinuousGeometryEntity.DEFAULT_N_POINTS_POLYGONAL_APPROX.
|
|
36
|
+
"""
|
|
37
|
+
super().__init__(
|
|
38
|
+
foci1=center,
|
|
39
|
+
foci2=center,
|
|
40
|
+
semi_major_axis=radius,
|
|
41
|
+
n_points_polygonal_approx=n_points_polygonal_approx,
|
|
42
|
+
)
|
|
43
|
+
self.center = center
|
|
44
|
+
self.radius = radius
|
|
45
|
+
self.update_polyapprox()
|
|
46
|
+
|
|
47
|
+
# --------------------------------- PROPERTIES ------------------------------------
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def perimeter(self) -> float:
|
|
51
|
+
"""Perimeter of the circle
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
float: perimeter value
|
|
55
|
+
"""
|
|
56
|
+
return 2 * math.pi * self.radius
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def centroid(self) -> NDArray:
|
|
60
|
+
"""Center of the circle
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
float: center 2D point
|
|
64
|
+
"""
|
|
65
|
+
return self.center
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def shapely_surface(self) -> SPolygon:
|
|
69
|
+
"""Returns the Shapely.Polygon as an surface representation of the Circle.
|
|
70
|
+
See https://shapely.readthedocs.io/en/stable/reference/shapely.Polygon.html
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Polygon: shapely.Polygon object
|
|
74
|
+
"""
|
|
75
|
+
return SPolygon(self.polyaprox.asarray, holes=None)
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def shapely_edges(self) -> LinearRing:
|
|
79
|
+
"""Returns the Shapely.LinearRing as a curve representation of the Circle.
|
|
80
|
+
See https://shapely.readthedocs.io/en/stable/reference/shapely.LinearRing.html
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
LinearRing: shapely.LinearRing object
|
|
84
|
+
"""
|
|
85
|
+
return LinearRing(coordinates=self.polyaprox.asarray)
|
|
86
|
+
|
|
87
|
+
def polygonal_approx(self, n_points: int, is_cast_int: bool = False) -> Polygon:
|
|
88
|
+
"""Generate a Polygon object that is an approximation of the circle
|
|
89
|
+
as a discrete geometrical object made up of only points and segments.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
n_points (int): number of points that make up the circle
|
|
93
|
+
polygonal approximation
|
|
94
|
+
is_cast_int (bool): whether to cast to int the points coordinates or
|
|
95
|
+
not. Defaults to False
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Polygon: Polygon representing the circle as a succession of n points
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
points = []
|
|
102
|
+
for theta in np.linspace(0, 2 * math.pi, n_points):
|
|
103
|
+
x = self.center[0] + self.radius * math.cos(theta)
|
|
104
|
+
y = self.center[1] + self.radius * math.sin(theta)
|
|
105
|
+
points.append([x, y])
|
|
106
|
+
|
|
107
|
+
poly = Polygon(points=np.asarray(points), is_cast_int=is_cast_int)
|
|
108
|
+
return poly
|
|
109
|
+
|
|
110
|
+
def curvature(self, point: Optional[NDArray] = None) -> float:
|
|
111
|
+
"""Curvature of circle is a constant and does not depend on a position of
|
|
112
|
+
a point
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
float: curvature value
|
|
116
|
+
"""
|
|
117
|
+
return 1 / self.radius
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def xmax(self) -> float:
|
|
121
|
+
"""Get the maximum X coordinate of the geometry entity
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
NDArray: 2D point
|
|
125
|
+
"""
|
|
126
|
+
return self.center[0] + self.radius
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def xmin(self) -> float:
|
|
130
|
+
"""Get the minimum X coordinate of the geometry entity
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
NDArray: 2D point
|
|
134
|
+
"""
|
|
135
|
+
return self.center[0] - self.radius
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def ymax(self) -> float:
|
|
139
|
+
"""Get the maximum Y coordinate of the geometry entity
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
NDArray: 2D point
|
|
143
|
+
"""
|
|
144
|
+
return self.center[1] + self.radius
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def ymin(self) -> float:
|
|
148
|
+
"""Get the minimum Y coordinate of the geometry entity
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
NDArray: 2D point
|
|
152
|
+
"""
|
|
153
|
+
return self.center[1] - self.radius
|
|
154
|
+
|
|
155
|
+
# ---------------------------- MODIFICATION METHODS -------------------------------
|
|
156
|
+
|
|
157
|
+
def rotate(
|
|
158
|
+
self,
|
|
159
|
+
angle: float,
|
|
160
|
+
is_degree: bool = False,
|
|
161
|
+
is_clockwise: bool = True,
|
|
162
|
+
pivot: Optional[NDArray] = None,
|
|
163
|
+
) -> Self:
|
|
164
|
+
"""Rotate the circle around a pivot point.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
angle (float): angle by which to rotate the circle
|
|
168
|
+
is_degree (bool, optional): whether the angle is in degrees. Defaults to False.
|
|
169
|
+
is_clockwise (bool, optional): whether the rotation is clockwise. Defaults to True.
|
|
170
|
+
pivot (Optional[NDArray], optional): pivot point around which to rotate. Defaults to None.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Self: rotated circle object
|
|
174
|
+
"""
|
|
175
|
+
if pivot is None:
|
|
176
|
+
# If no pivot is given, the circle is rotated around its center
|
|
177
|
+
# and thus is not modified
|
|
178
|
+
return self
|
|
179
|
+
|
|
180
|
+
self.center = rotate_2d_points(
|
|
181
|
+
points=self.center,
|
|
182
|
+
angle=angle,
|
|
183
|
+
is_degree=is_degree,
|
|
184
|
+
is_clockwise=is_clockwise,
|
|
185
|
+
pivot=pivot,
|
|
186
|
+
)
|
|
187
|
+
self.update_polyapprox()
|
|
188
|
+
return self
|
|
189
|
+
|
|
190
|
+
def shift(self, vector: NDArray) -> Self:
|
|
191
|
+
"""Shift the circle by a given vector.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
vector (NDArray): 2D vector by which to shift the circle
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Self: shifted circle object
|
|
198
|
+
"""
|
|
199
|
+
vector = assert_transform_shift_vector(vector=vector)
|
|
200
|
+
self.center += vector
|
|
201
|
+
self.update_polyapprox()
|
|
202
|
+
return self
|
|
203
|
+
|
|
204
|
+
def normalize(self, x: float, y: float) -> Self:
|
|
205
|
+
"""Normalize the circle by dividing the points by a norm on the x and y
|
|
206
|
+
coordinates. This does not change the circle radius.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
x (float): x coordinate norm
|
|
210
|
+
y (float): y coordinate norm
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Self: normalized circle object
|
|
214
|
+
"""
|
|
215
|
+
self.center = self.center / np.array([x, y])
|
|
216
|
+
self.update_polyapprox()
|
|
217
|
+
return self
|
|
218
|
+
|
|
219
|
+
# ------------------------------- CLASSIC METHODS ---------------------------------
|
|
220
|
+
|
|
221
|
+
def copy(self) -> Self:
|
|
222
|
+
"""Copy the circle object
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Self: copied circle object
|
|
226
|
+
"""
|
|
227
|
+
return type(self)(
|
|
228
|
+
center=self.center,
|
|
229
|
+
radius=self.radius,
|
|
230
|
+
n_points_polygonal_approx=self.n_points_polygonal_approx,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def __str__(self) -> str:
|
|
234
|
+
return f"Circle(center={self.center}, radius={self.radius})"
|
|
235
|
+
|
|
236
|
+
def __repr__(self):
|
|
237
|
+
return f"Circle(center={self.center}, radius={self.radius})"
|