From a528d008a1fe3fc1b11f96a1c74d9758a91359de Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 14:11:05 +0200 Subject: [PATCH 01/12] Use minor and major radii for `Torus` shape representation --- crates/bevy_math/src/primitives/dim3.rs | 62 ++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 60105622f57ce..052a6bb9bc52f 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -240,12 +240,62 @@ pub struct ConicalFrustum { } impl Primitive3d for ConicalFrustum {} -/// A torus (AKA donut) primitive. -#[derive(Clone, Copy, Debug)] +/// 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 { + let minor_radius = (outer_radius - inner_radius) / 2.0; + Self { + minor_radius, + major_radius: outer_radius - minor_radius, + } + } + + /// Get the inner radius of the torus. + /// For a ring torus, this corresponds to the radius of the hole + pub fn inner_radius(&self) -> f32 { + self.major_radius - self.minor_radius + } + + /// Get the outer radius of the torus. + /// This corresponds to the overall radius of the entire object + pub fn outer_radius(&self) -> f32 { + self.major_radius + self.minor_radius + } + + /// Return `true` if the torus has a ring. The major radius + /// is greater than the minor radius + pub fn is_ring_torus(&self) -> bool { + self.major_radius > self.minor_radius + } + + /// Return `true` if the torus has no hole but also isn't + /// self-intersecting. The major radius is equal to the minor radius + pub fn is_horn_torus(&self) -> bool { + self.major_radius == self.minor_radius + } + + /// Return `true` if the torus is self-intersecting. + /// The major radius is less than the minor radius + pub fn is_spindle_torus(&self) -> bool { + self.major_radius < self.minor_radius + } +} From d1634382aa352cd3f56a401c436de7d6edcec874 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 16:43:24 +0200 Subject: [PATCH 02/12] Add `TorusKind` enum --- crates/bevy_math/src/primitives/dim3.rs | 40 +++++++++++++++---------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 052a6bb9bc52f..bb0bdb6459059 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -240,6 +240,19 @@ pub struct ConicalFrustum { } impl Primitive3d for ConicalFrustum {} +/// The type of torus determined by the minor and major radii +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 primitive, often representing a ring or donut shape #[derive(Clone, Copy, Debug, PartialEq)] pub struct Torus { @@ -281,21 +294,16 @@ impl Torus { self.major_radius + self.minor_radius } - /// Return `true` if the torus has a ring. The major radius - /// is greater than the minor radius - pub fn is_ring_torus(&self) -> bool { - self.major_radius > self.minor_radius - } - - /// Return `true` if the torus has no hole but also isn't - /// self-intersecting. The major radius is equal to the minor radius - pub fn is_horn_torus(&self) -> bool { - self.major_radius == self.minor_radius - } - - /// Return `true` if the torus is self-intersecting. - /// The major radius is less than the minor radius - pub fn is_spindle_torus(&self) -> bool { - 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 + pub fn kind(&self) -> TorusKind { + match self.major_radius.total_cmp(&self.minor_radius) { + std::cmp::Ordering::Greater => TorusKind::Ring, + std::cmp::Ordering::Equal => TorusKind::Horn, + std::cmp::Ordering::Less => TorusKind::Spindle, + } } } From c1811ca38f394bc2e4ae3eded240e36b9f476850 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 16:45:26 +0200 Subject: [PATCH 03/12] Add derives for `TorusKind` --- crates/bevy_math/src/primitives/dim3.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index bb0bdb6459059..7aee97de019a0 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -241,6 +241,7 @@ pub struct ConicalFrustum { impl Primitive3d for ConicalFrustum {} /// 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 From 8b4edf0a91eca82401546ad69ca622a87567e0fc Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 17:49:57 +0200 Subject: [PATCH 04/12] Inline `Torus` methods and add inner/outer radius formulae --- crates/bevy_math/src/primitives/dim3.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 7aee97de019a0..9e191bdd8cc2f 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -284,13 +284,17 @@ impl Torus { } /// Get the inner radius of the torus. - /// For a ring torus, this corresponds to the radius of the hole + /// For a ring torus, this corresponds to the radius of the hole, + /// or `major_radius - minor_radius` + #[inline] pub fn inner_radius(&self) -> f32 { self.major_radius - self.minor_radius } /// Get the outer radius of the torus. - /// This corresponds to the overall radius of the entire object + /// This corresponds to the overall radius of the entire object, + /// or `major_radius + minor_radius` + #[inline] pub fn outer_radius(&self) -> f32 { self.major_radius + self.minor_radius } @@ -300,6 +304,7 @@ impl Torus { /// 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 + #[inline] pub fn kind(&self) -> TorusKind { match self.major_radius.total_cmp(&self.minor_radius) { std::cmp::Ordering::Greater => TorusKind::Ring, From b9437bb2b16596dc6e61a933d5abfc3d7d513c2e Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 17:54:19 +0200 Subject: [PATCH 05/12] Use `partial_cmp` and add a Panics section for `Torus::kind` --- crates/bevy_math/src/primitives/dim3.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 9e191bdd8cc2f..bd4e27921a014 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -304,9 +304,17 @@ impl Torus { /// 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 + /// + /// # Panics + /// + /// Panics if the minor or major radius of the torus is `NaN` #[inline] pub fn kind(&self) -> TorusKind { - match self.major_radius.total_cmp(&self.minor_radius) { + match self + .major_radius + .partial_cmp(&self.minor_radius) + .expect("radius of torus is NaN") + { std::cmp::Ordering::Greater => TorusKind::Ring, std::cmp::Ordering::Equal => TorusKind::Horn, std::cmp::Ordering::Less => TorusKind::Spindle, From ffa5ad0969e237ef0018e1d4571ee0c32084d119 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 17:57:26 +0200 Subject: [PATCH 06/12] `must_use` torus methods --- crates/bevy_math/src/primitives/dim3.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index bd4e27921a014..3c24915dbc5d4 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -287,6 +287,7 @@ impl Torus { /// For a ring torus, this corresponds to the radius of the hole, /// or `major_radius - minor_radius` #[inline] + #[must_use] pub fn inner_radius(&self) -> f32 { self.major_radius - self.minor_radius } @@ -295,6 +296,7 @@ impl 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 } @@ -309,6 +311,7 @@ impl Torus { /// /// Panics if the minor or major radius of the torus is `NaN` #[inline] + #[must_use] pub fn kind(&self) -> TorusKind { match self .major_radius From 9f54788b4c3bfb2961b4f26bce00d10efa3f2901 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 18:09:33 +0200 Subject: [PATCH 07/12] Assert positive minor/major radii for torus --- crates/bevy_math/src/primitives/dim3.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 3c24915dbc5d4..226fe78abceaf 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -277,9 +277,14 @@ impl Torus { /// is the radius of the entire object pub fn new(inner_radius: f32, outer_radius: f32) -> Self { let minor_radius = (outer_radius - inner_radius) / 2.0; + let major_radius = outer_radius - minor_radius; + + assert!(minor_radius > 0.0, "minor radius of torus in non-positive"); + assert!(major_radius > 0.0, "major radius of torus in non-positive"); + Self { minor_radius, - major_radius: outer_radius - minor_radius, + major_radius, } } From c8d7be1ba2eb51cac09c15b4863acf2b8a2d8495 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 18:19:58 +0200 Subject: [PATCH 08/12] Remove assert --- crates/bevy_math/src/primitives/dim3.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 226fe78abceaf..a2064d03dbd61 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -279,9 +279,6 @@ impl Torus { let minor_radius = (outer_radius - inner_radius) / 2.0; let major_radius = outer_radius - minor_radius; - assert!(minor_radius > 0.0, "minor radius of torus in non-positive"); - assert!(major_radius > 0.0, "major radius of torus in non-positive"); - Self { minor_radius, major_radius, From 4653ffa3f5116fcef428d83397c4965f89fef00c Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 18:20:38 +0200 Subject: [PATCH 09/12] Add `TorusKind::Invalid` --- crates/bevy_math/src/primitives/dim3.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index a2064d03dbd61..5a56799e9f21c 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -252,6 +252,9 @@ pub enum TorusKind { /// A self-intersecting torus. /// The major radius is less than the minor radius Spindle, + /// A torus with non-geometric properties like + /// a non-positive minor or major radius + Invalid, } /// A torus primitive, often representing a ring or donut shape @@ -307,7 +310,8 @@ impl Torus { /// /// 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 + /// or a *spindle torus* that is self-intersecting. If the minor or major radius + /// is non-positive or infinite, [`TorusKind::Invalid`] is returned /// /// # Panics /// @@ -315,11 +319,20 @@ impl Torus { #[inline] #[must_use] pub fn kind(&self) -> TorusKind { - match self - .major_radius - .partial_cmp(&self.minor_radius) - .expect("radius of torus is NaN") + // Panic if NaN radius + assert!(!self.minor_radius.is_nan(), "minor radius of torus is NaN"); + assert!(!self.major_radius.is_nan(), "major radius of torus is NaN"); + + // A torus typically can't have a non-positive or infinite minor or major radius + if self.minor_radius <= 0.0 + || self.minor_radius.is_infinite() + || self.major_radius <= 0.0 + || self.major_radius.is_infinite() { + 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, From f66d486b46a8c2a6faed73c1f3eca8f199381f05 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 21:14:47 +0200 Subject: [PATCH 10/12] Return `TorusKind::Invalid` for `NaN` --- crates/bevy_math/src/primitives/dim3.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 5a56799e9f21c..ce5e65a3d5b60 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -253,7 +253,8 @@ pub enum TorusKind { /// The major radius is less than the minor radius Spindle, /// A torus with non-geometric properties like - /// a non-positive minor or major radius + /// a minor or major radius that is non-positive, + /// infinite or `NaN` Invalid, } @@ -310,24 +311,18 @@ impl Torus { /// /// 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 or infinite, [`TorusKind::Invalid`] is returned + /// or a *spindle torus* that is self-intersecting. /// - /// # Panics - /// - /// Panics if the minor or major radius of the torus is `NaN` + /// If the minor or major radius is non-positive, infinite or `NaN`, + /// [`TorusKind::Invalid`] is returned #[inline] #[must_use] pub fn kind(&self) -> TorusKind { - // Panic if NaN radius - assert!(!self.minor_radius.is_nan(), "minor radius of torus is NaN"); - assert!(!self.major_radius.is_nan(), "major radius of torus is NaN"); - - // A torus typically can't have a non-positive or infinite minor or major radius + // Invalid if minor or major radius is non-positive, infinite or NaN if self.minor_radius <= 0.0 - || self.minor_radius.is_infinite() + || !self.minor_radius.is_finite() || self.major_radius <= 0.0 - || self.major_radius.is_infinite() + || !self.major_radius.is_finite() { return TorusKind::Invalid; } From 2d3586b57c46ccb40501e7927a8ff2562137e315 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 19 Nov 2023 23:13:32 +0200 Subject: [PATCH 11/12] Oxford comma --- crates/bevy_math/src/primitives/dim3.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index ce5e65a3d5b60..0f89a3f5b17d4 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -161,7 +161,7 @@ pub struct Cuboid { impl Primitive3d for Cuboid {} impl Cuboid { - /// Create a cuboid from a full x, y and z length + /// Create a cuboid from a full x, y, and z length pub fn new(x_length: f32, y_length: f32, z_length: f32) -> Self { Self::from_size(Vec3::new(x_length, y_length, z_length)) } @@ -254,7 +254,7 @@ pub enum TorusKind { Spindle, /// A torus with non-geometric properties like /// a minor or major radius that is non-positive, - /// infinite or `NaN` + /// infinite, or `NaN` Invalid, } @@ -313,12 +313,12 @@ impl Torus { /// 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`, + /// If the minor or major radius is non-positive, infinite, or `NaN`, /// [`TorusKind::Invalid`] is returned #[inline] #[must_use] pub fn kind(&self) -> TorusKind { - // Invalid if minor or major radius is non-positive, infinite or NaN + // 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 From 4f4f1e0a1deb59ddd7a0e662c48ab93561e34d46 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 20 Nov 2023 15:53:28 +0200 Subject: [PATCH 12/12] Remove `must_use` --- crates/bevy_math/src/primitives/dim3.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 0f89a3f5b17d4..891f51558fd3b 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -293,7 +293,6 @@ impl Torus { /// For a ring torus, this corresponds to the radius of the hole, /// or `major_radius - minor_radius` #[inline] - #[must_use] pub fn inner_radius(&self) -> f32 { self.major_radius - self.minor_radius } @@ -302,7 +301,6 @@ impl 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 } @@ -316,7 +314,6 @@ impl Torus { /// If the minor or major radius is non-positive, infinite, or `NaN`, /// [`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