N-dimensional sphere. Defined through center position and radius.
| 39 | @sliceable(keepdims='vector') |
| 40 | @dataclass(frozen=True, eq=False) |
| 41 | class Sphere(Geometry, metaclass=SphereType): |
| 42 | """ |
| 43 | N-dimensional sphere. |
| 44 | Defined through center position and radius. |
| 45 | """ |
| 46 | |
| 47 | pos: Tensor |
| 48 | radius: Tensor |
| 49 | |
| 50 | variable_attrs: Tuple[str, ...] = ('pos', 'radius') |
| 51 | |
| 52 | def __post_init__(self): |
| 53 | assert 'vector' in self.pos.shape |
| 54 | assert 'vector' not in self.radius.shape, f"Sphere radius must not vary along vector but got {self.radius}" |
| 55 | |
| 56 | @cached_property |
| 57 | def shape(self): |
| 58 | return self.pos.shape & self.radius.shape |
| 59 | |
| 60 | @property |
| 61 | def center(self): |
| 62 | return self.pos |
| 63 | |
| 64 | @cached_property |
| 65 | def volume(self) -> math.Tensor: |
| 66 | return Sphere.volume_from_radius(self.radius, self.spatial_rank) |
| 67 | |
| 68 | @staticmethod |
| 69 | def volume_from_radius(radius: Union[float, Tensor], spatial_rank: int): |
| 70 | if spatial_rank == 1: |
| 71 | return 2 * radius |
| 72 | elif spatial_rank == 2: |
| 73 | return PI * radius ** 2 |
| 74 | elif spatial_rank == 3: |
| 75 | return 4/3 * PI * radius ** 3 |
| 76 | else: |
| 77 | raise NotImplementedError(f"spatial_rank>3 not supported, got {spatial_rank}") |
| 78 | # n = self.spatial_rank |
| 79 | # return math.pi ** (n // 2) / math.faculty(math.ceil(n / 2)) * self.radius ** n |
| 80 | |
| 81 | @staticmethod |
| 82 | def radius_from_volume(volume: Union[float, Tensor], spatial_rank: int): |
| 83 | if spatial_rank == 1: |
| 84 | return volume / 2 |
| 85 | elif spatial_rank == 2: |
| 86 | return math.sqrt(volume / PI) |
| 87 | elif spatial_rank == 3: |
| 88 | return (.75 / PI * volume) ** (1/3) |
| 89 | else: |
| 90 | raise NotImplementedError(f"spatial_rank>3 not supported, got {spatial_rank}") |
| 91 | |
| 92 | @staticmethod |
| 93 | def area_from_radius(radius: Union[float, Tensor], spatial_rank: int): |
| 94 | if spatial_rank == 1: |
| 95 | return 0 |
| 96 | elif spatial_rank == 2: |
| 97 | return 2*PI * radius |
| 98 | elif spatial_rank == 3: |
no outgoing calls