Skip to main content

hoomd_geometry/shape/
sphero.rs

1// Copyright (c) 2024-2026 The Regents of the University of Michigan.
2// Part of hoomd-rs, released under the BSD 3-Clause License.
3
4//! Implement [`Sphero`]
5
6use serde::{Deserialize, Serialize};
7
8use crate::{BoundingSphereRadius, SupportMapping};
9use hoomd_utility::valid::PositiveReal;
10use hoomd_vector::InnerProduct;
11
12/// Round a shape with a given radius.
13///
14/// [`Sphero`] modifies a given shape by sweeping it with a hypersphere of the
15/// given radius. The resulting [`Sphero<S>`] type is a shape itself. If `S`
16/// implements [`crate::SupportMapping`], then [`Sphero<S>`] can be used in
17/// [`IntersectsAt`](crate::IntersectsAt) tests with other convex shapes. See
18/// the full list of implementations below to see what other traits [`Sphero<S>`]
19/// implements for a given `S`.
20///
21/// # Example
22///
23/// Test if a circle overlaps with a rounded rectangle:
24/// ```
25/// use hoomd_geometry::{
26///     Convex, IntersectsAt,
27///     shape::{Circle, Rectangle, Sphero},
28/// };
29/// use hoomd_vector::{Angle, Cartesian};
30/// use std::f64::consts::PI;
31///
32/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
33/// let circle = Convex(Circle {
34///     radius: 0.5.try_into()?,
35/// });
36/// let rectangle = Rectangle {
37///     edge_lengths: [3.0.try_into()?, 2.0.try_into()?],
38/// };
39/// let rounded_rectangle = Convex(Sphero {
40///     shape: rectangle,
41///     rounding_radius: 0.5.try_into()?,
42/// });
43///
44/// assert!(rounded_rectangle.intersects_at(
45///     &circle,
46///     &[2.4, 0.0].into(),
47///     &Angle::default()
48/// ));
49/// assert!(!rounded_rectangle.intersects_at(
50///     &circle,
51///     &[0.0, 2.4].into(),
52///     &Angle::default()
53/// ));
54/// assert!(circle.intersects_at(
55///     &rounded_rectangle,
56///     &[0.0, 2.4].into(),
57///     &Angle::from(PI / 2.0)
58/// ));
59/// # Ok(())
60/// # }
61/// ```
62#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
63pub struct Sphero<S> {
64    /// The shape to round.
65    pub shape: S,
66    /// The radius of the rounding hypersphere.
67    pub rounding_radius: PositiveReal,
68}
69
70impl<S, V> SupportMapping<V> for Sphero<S>
71where
72    S: SupportMapping<V>,
73    V: InnerProduct,
74{
75    #[inline]
76    fn support_mapping(&self, n: &V) -> V {
77        self.shape.support_mapping(n) + *n / n.norm() * self.rounding_radius.get()
78    }
79}
80
81impl<S> BoundingSphereRadius for Sphero<S>
82where
83    S: BoundingSphereRadius,
84{
85    #[inline]
86    fn bounding_sphere_radius(&self) -> PositiveReal {
87        (self.shape.bounding_sphere_radius().get() + self.rounding_radius.get())
88            .try_into()
89            .expect("expression should evaluate to a positive real")
90    }
91}