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 a) 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