Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use minor and major radii for Torus primitive shape #10643

Merged
merged 12 commits into from
Nov 21, 2023
97 changes: 91 additions & 6 deletions crates/bevy_math/src/primitives/dim3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,97 @@ pub struct ConicalFrustum {
}
impl Primitive3d for ConicalFrustum {}

/// A torus (AKA donut) primitive.
#[derive(Clone, Copy, Debug)]
/// The type of torus determined by the minor and major radii
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TorusKind {
/// A torus that has a ring.
/// The major radius is greater than the minor radius
Ring,
/// A torus that has no hole but also doesn't intersect itself.
/// The major radius is equal to the minor radius
Horn,
/// A self-intersecting torus.
/// The major radius is less than the minor radius
Spindle,
/// A torus with non-geometric properties like
/// a minor or major radius that is non-positive,
/// infinite or `NaN`
Invalid,
}

/// A torus primitive, often representing a ring or donut shape
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Torus {
/// The radius of the overall shape
pub radius: f32,
/// The radius of the internal ring
pub ring_radius: f32,
/// The radius of the tube of the torus
#[doc(
alias = "ring_radius",
alias = "tube_radius",
alias = "cross_section_radius"
)]
pub minor_radius: f32,
/// The distance from the center of the torus to the center of the tube
#[doc(alias = "radius_of_revolution")]
pub major_radius: f32,
}
impl Primitive3d for Torus {}

impl Torus {
/// Create a new `Torus` from an inner and outer radius.
///
/// The inner radius is the radius of the hole, and the outer radius
/// is the radius of the entire object
pub fn new(inner_radius: f32, outer_radius: f32) -> Self {
Jondolf marked this conversation as resolved.
Show resolved Hide resolved
let minor_radius = (outer_radius - inner_radius) / 2.0;
let major_radius = outer_radius - minor_radius;

Self {
minor_radius,
major_radius,
}
}

/// Get the inner radius of the torus.
/// For a ring torus, this corresponds to the radius of the hole,
/// or `major_radius - minor_radius`
#[inline]
#[must_use]
alice-i-cecile marked this conversation as resolved.
Show resolved Hide resolved
pub fn inner_radius(&self) -> f32 {
Jondolf marked this conversation as resolved.
Show resolved Hide resolved
self.major_radius - self.minor_radius
}

/// Get the outer radius of the torus.
/// This corresponds to the overall radius of the entire object,
/// or `major_radius + minor_radius`
#[inline]
#[must_use]
pub fn outer_radius(&self) -> f32 {
self.major_radius + self.minor_radius
}

/// Get the [`TorusKind`] determined by the minor and major radii.
///
/// The torus can either be a *ring torus* that has a hole,
/// a *horn torus* that doesn't have a hole but also isn't self-intersecting,
/// or a *spindle torus* that is self-intersecting.
///
/// If the minor or major radius is non-positive, infinite or `NaN`,
Jondolf marked this conversation as resolved.
Show resolved Hide resolved
/// [`TorusKind::Invalid`] is returned
#[inline]
#[must_use]
pub fn kind(&self) -> TorusKind {
// Invalid if minor or major radius is non-positive, infinite or NaN
if self.minor_radius <= 0.0
|| !self.minor_radius.is_finite()
|| self.major_radius <= 0.0
|| !self.major_radius.is_finite()
{
return TorusKind::Invalid;
}

match self.major_radius.partial_cmp(&self.minor_radius).unwrap() {
std::cmp::Ordering::Greater => TorusKind::Ring,
std::cmp::Ordering::Equal => TorusKind::Horn,
std::cmp::Ordering::Less => TorusKind::Spindle,
}
}
}