1
- # from https://www.nayuki.io/page/smallest-enclosing-circle
2
-
3
1
import math
4
2
import random
5
3
from typing import Union , Tuple , List
@@ -18,6 +16,7 @@ def __init__(self, center: Tuple[float, float], radius: float):
18
16
def from_points (cls , points : List [Tuple [float , float ]]) -> 'Circle' :
19
17
"""
20
18
Returns the smallest circle that encloses all the given points.
19
+ from https://www.nayuki.io/page/smallest-enclosing-circle
21
20
22
21
If 0 points are given, `None` is returned.
23
22
If 1 point is given, a circle of radius 0 is returned.
@@ -92,6 +91,7 @@ def _expand_circle_from_one_point(
92
91
) -> Circle :
93
92
"""
94
93
One boundary point known
94
+ from https://www.nayuki.io/page/smallest-enclosing-circle
95
95
"""
96
96
97
97
circle = Circle (a , 0.0 )
@@ -111,6 +111,7 @@ def _expand_circle_from_two_points(
111
111
) -> Circle :
112
112
"""
113
113
Two boundary points known
114
+ from https://www.nayuki.io/page/smallest-enclosing-circle
114
115
"""
115
116
116
117
circ = Circle .from_points ([a , b ])
@@ -125,27 +126,15 @@ def _expand_circle_from_two_points(
125
126
continue
126
127
127
128
# Form a circumcircle and classify it on left or right side
128
- cross = _cross_product (((px , py ), (qx , qy ), (r [0 ], r [1 ])))
129
+ cross = _triangle_cross_product (((px , py ), (qx , qy ), (r [0 ], r [1 ])))
129
130
c = circumcircle (a , b , r )
130
- cross_2 = _cross_product (((px , py ), (qx , qy ), (c .center [0 ], c .center [1 ])))
131
+ cross_2 = _triangle_cross_product (((px , py ), (qx , qy ), (c .center [0 ], c .center [1 ])))
131
132
if c is None :
132
133
continue
133
- elif cross > 0.0 and (left is None or cross_2 > _cross_product (((px , py ), (qx , qy ), left .center ))):
134
+ elif cross > 0.0 and (left is None or cross_2 > _triangle_cross_product (((px , py ), (qx , qy ), left .center ))):
134
135
left = c
135
- elif cross < 0.0 and (right is None or cross_2 < _cross_product (((px , py ), (qx , qy ), right .center ))):
136
+ elif cross < 0.0 and (right is None or cross_2 < _triangle_cross_product (((px , py ), (qx , qy ), right .center ))):
136
137
right = c
137
- # cross = _cross_product(((px, py), (qx, qy), (r[0], r[1])))
138
- # c = Circle.from_points([p, q, r])
139
- # if c is None:
140
- # continue
141
- # elif cross > 0.0 and (
142
- # left is None or _cross_product(px, py, qx, qy, c[0], c[1]) > _cross_product(px, py, qx, qy, left[0],
143
- # left[1])):
144
- # left = c
145
- # elif cross < 0.0 and (
146
- # right is None or _cross_product(px, py, qx, qy, c[0], c[1]) < _cross_product(px, py, qx, qy, right[0],
147
- # right[1])):
148
- # right = c
149
138
150
139
# Select which circle to return
151
140
if left is None and right is None :
@@ -163,6 +152,10 @@ def circumcircle(
163
152
b : Tuple [float , float ],
164
153
c : Tuple [float , float ],
165
154
) -> Circle :
155
+ """
156
+ from https://www.nayuki.io/page/smallest-enclosing-circle
157
+ """
158
+
166
159
# Mathematical algorithm from Wikipedia: Circumscribed circle
167
160
ox = (min (a [0 ], b [0 ], c [0 ]) + max (a [0 ], b [0 ], c [0 ])) / 2
168
161
oy = (min (a [1 ], b [1 ], c [1 ]) + max (a [1 ], b [1 ], c [1 ])) / 2
@@ -185,8 +178,10 @@ def circumcircle(
185
178
return Circle ((x , y ), max (ra , rb , rc ))
186
179
187
180
188
- def _cross_product (triangle : Tuple [Tuple [float , float ], Tuple [float , float ], Tuple [float , float ]]) -> float :
181
+ def _triangle_cross_product (triangle : Tuple [Tuple [float , float ], Tuple [float , float ], Tuple [float , float ]]) -> float :
189
182
"""
183
+ from https://www.nayuki.io/page/smallest-enclosing-circle
184
+
190
185
:param triangle: three points defining a triangle
191
186
:return: twice the signed area of triangle
192
187
"""
0 commit comments