1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
from numbers import Number
from math import sqrt, asin
def clamp(low: Number, high: Number, num: Number) -> Number:
"""Limit range of ``num`` between ``low`` and ``high``"""
return max(low, min(high, num))
def circrect(a: tuple[Number, Number], b: tuple[Number, Number], c: Number = 1) -> Number:
"""
Calculate the area of the overlap between a rectangle defined by opposing
corner points ``a`` and ``b`` and a circle with radius ``c``.
Args:
a: first corner coordinate of rectangle
b: second corner coordinate of rectangle (opposite of b)
c: circle radius (optional, with default of 1)
Returns:
Overlap area (square units)
"""
# input variable normalization
a, b = (
(min(a[0], b[0]), min(a[1], b[1])),
(max(a[0], b[0]), max(a[1], b[1])),
)
c = abs(c)
a = (clamp(-1, 1, a[0] / c), clamp(-1, 1, a[1] / c))
b = (clamp(-1, 1, b[0] / c), clamp(-1, 1, b[1] / c))
# can not have shared area if ab already has no area
if a == b: return 0.0
f = lambda x: sqrt(1 - x**2)
F = lambda x, n: 0.5 * (2*n*x + sqrt(1 - x**2)*x + asin(x))
g = lambda a, b: F(clamp(a[0], b[0], f(a[1])), -a[1]) \
- F(clamp(a[0], b[0], -f(a[1])), -a[1]) \
- F(clamp(a[0], b[0], f(b[1])), -b[1]) \
+ F(clamp(a[0], b[0], -f(b[1])), -b[1])
h = lambda a, b: g((a[0], max(0, a[1])), (b[0], max(0, b[1]))) \
+ g((a[0], max(0, -b[1])), (b[0], max(0, -a[1])))
o = h(a, b) * (c ** 2)
return o
|