From 9ec6d62228e6766dca28b079aa6754e07d51d27c Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Thu, 1 Feb 2024 21:22:28 +0200 Subject: [PATCH] Implement `approx` traits for direction types (#11650) # Objective `approx` has traits like [`AbsDiffEq`](https://docs.rs/approx/latest/approx/trait.AbsDiffEq.html), [`RelativeEq`](https://docs.rs/approx/latest/approx/trait.RelativeEq.html), and [`UlpsEq`](https://docs.rs/approx/latest/approx/trait.UlpsEq.html). Glam implements them for its math types when the `approx` feature is enabled. Bevy's `Direction2d` and `Direction3d` should implement these too. ## Solution Implement the traits. See [how Glam implements them for its own math types](https://github.com/bitshifter/glam-rs/blob/main/src/features/impl_approx.rs). For the epsilon values, I use the same as `Vec2`/`Vec3` (just `f32::EPSILON`). --- crates/bevy_math/Cargo.toml | 3 ++- crates/bevy_math/src/primitives/dim2.rs | 32 +++++++++++++++++++++++++ crates/bevy_math/src/primitives/dim3.rs | 32 +++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 9c696b9a09474b..d9686abf4f2b78 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -11,6 +11,7 @@ keywords = ["bevy"] [dependencies] glam = { version = "0.25", features = ["bytemuck"] } serde = { version = "1", features = ["derive"], optional = true } +approx = { version = "0.5", optional = true } [dev-dependencies] approx = "0.5" @@ -18,7 +19,7 @@ approx = "0.5" [features] serialize = ["dep:serde", "glam/serde"] # Enable approx for glam types to approximate floating point equality comparisons and assertions -approx = ["glam/approx"] +approx = ["dep:approx", "glam/approx"] # Enable interoperation of glam types with mint-compatible libraries mint = ["glam/mint"] # Enable libm mathematical functions for glam types to ensure consistent outputs diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index a413b180930d67..c0ad0b2d1c6952 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -81,6 +81,38 @@ impl std::ops::Neg for Direction2d { } } +#[cfg(feature = "approx")] +impl approx::AbsDiffEq for Direction2d { + type Epsilon = f32; + fn default_epsilon() -> f32 { + f32::EPSILON + } + fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool { + self.as_ref().abs_diff_eq(other.as_ref(), epsilon) + } +} + +#[cfg(feature = "approx")] +impl approx::RelativeEq for Direction2d { + fn default_max_relative() -> f32 { + f32::EPSILON + } + fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool { + self.as_ref() + .relative_eq(other.as_ref(), epsilon, max_relative) + } +} + +#[cfg(feature = "approx")] +impl approx::UlpsEq for Direction2d { + fn default_max_ulps() -> u32 { + 4 + } + fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool { + self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) + } +} + /// A circle primitive #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 7d0b34ad2def8f..150db82ecc57e5 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -85,6 +85,38 @@ impl std::ops::Neg for Direction3d { } } +#[cfg(feature = "approx")] +impl approx::AbsDiffEq for Direction3d { + type Epsilon = f32; + fn default_epsilon() -> f32 { + f32::EPSILON + } + fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool { + self.as_ref().abs_diff_eq(other.as_ref(), epsilon) + } +} + +#[cfg(feature = "approx")] +impl approx::RelativeEq for Direction3d { + fn default_max_relative() -> f32 { + f32::EPSILON + } + fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool { + self.as_ref() + .relative_eq(other.as_ref(), epsilon, max_relative) + } +} + +#[cfg(feature = "approx")] +impl approx::UlpsEq for Direction3d { + fn default_max_ulps() -> u32 { + 4 + } + fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool { + self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) + } +} + /// A sphere primitive #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]