diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index af9b0cb..6355b30 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: features: --features unstable - version: nightly features: --features unstable,serde - + steps: - uses: actions/checkout@v4 @@ -46,6 +46,13 @@ jobs: env: RUST_BACKTRACE: 1 + minimal-no-std: + name: Check that no-std builds (with a reduced featureset) without libm + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: cargo check --no-default-features + fmt: name: Check code formatting runs-on: ubuntu-latest diff --git a/src/angle.rs b/src/angle.rs index 81c43d1..8cda48f 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -7,20 +7,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::approxeq::ApproxEq; -use crate::trig::Trig; - use core::cmp::{Eq, PartialEq}; use core::hash::Hash; -use core::iter::Sum; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; #[cfg(feature = "bytemuck")] use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use num_traits::real::Real; -use num_traits::{Float, FloatConst, NumCast, One, Zero}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -73,320 +66,337 @@ impl Angle { } } -impl Angle -where - T: Trig, -{ - #[inline] - pub fn degrees(deg: T) -> Self { - Angle { - radians: T::degrees_to_radians(deg), +#[cfg(any(feature = "std", feature = "libm"))] +mod float { + use super::Angle; + use crate::approxeq::ApproxEq; + use crate::trig::Trig; + use core::iter::Sum; + use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; + use num_traits::real::Real; + use num_traits::{Float, FloatConst, NumCast, One, Zero}; + + impl Angle + where + T: Trig, + { + #[inline] + pub fn degrees(deg: T) -> Self { + Angle { + radians: T::degrees_to_radians(deg), + } } - } - #[inline] - pub fn to_degrees(self) -> T { - T::radians_to_degrees(self.radians) + #[inline] + pub fn to_degrees(self) -> T { + T::radians_to_degrees(self.radians) + } } -} -impl Angle -where - T: Rem + Sub + Add + Zero + FloatConst + PartialOrd + Copy, -{ - /// Returns this angle in the [0..2*PI[ range. - pub fn positive(&self) -> Self { - let two_pi = T::PI() + T::PI(); - let mut a = self.radians % two_pi; - if a < T::zero() { - a = a + two_pi; - } - Angle::radians(a) - } + impl Angle + where + T: Rem + + Sub + + Add + + Zero + + FloatConst + + PartialOrd + + Copy, + { + /// Returns this angle in the [0..2*PI[ range. + pub fn positive(&self) -> Self { + let two_pi = T::PI() + T::PI(); + let mut a = self.radians % two_pi; + if a < T::zero() { + a = a + two_pi; + } + Angle::radians(a) + } - /// Returns this angle in the ]-PI..PI] range. - pub fn signed(&self) -> Self { - Angle::pi() - (Angle::pi() - *self).positive() + /// Returns this angle in the ]-PI..PI] range. + pub fn signed(&self) -> Self { + Angle::pi() - (Angle::pi() - *self).positive() + } } -} -impl Angle -where - T: Rem - + Mul - + Sub - + Add - + One - + FloatConst - + Copy, -{ - /// Returns the shortest signed angle between two angles. - /// - /// Takes wrapping and signs into account. - pub fn angle_to(&self, to: Self) -> Self { - let two = T::one() + T::one(); - let max = T::PI() * two; - let d = (to.radians - self.radians) % max; - - Angle::radians(two * d % max - d) - } + impl Angle + where + T: Rem + + Mul + + Sub + + Add + + One + + FloatConst + + Copy, + { + /// Returns the shortest signed angle between two angles. + /// + /// Takes wrapping and signs into account. + pub fn angle_to(&self, to: Self) -> Self { + let two = T::one() + T::one(); + let max = T::PI() * two; + let d = (to.radians - self.radians) % max; + + Angle::radians(two * d % max - d) + } - /// Linear interpolation between two angles, using the shortest path. - pub fn lerp(&self, other: Self, t: T) -> Self { - *self + self.angle_to(other) * t + /// Linear interpolation between two angles, using the shortest path. + pub fn lerp(&self, other: Self, t: T) -> Self { + *self + self.angle_to(other) * t + } } -} -impl Angle -where - T: Float, -{ - /// Returns `true` if the angle is a finite number. - #[inline] - pub fn is_finite(self) -> bool { - self.radians.is_finite() + impl Angle + where + T: Float, + { + /// Returns `true` if the angle is a finite number. + #[inline] + pub fn is_finite(self) -> bool { + self.radians.is_finite() + } } -} -impl Angle -where - T: Real, -{ - /// Returns `(sin(self), cos(self))`. - pub fn sin_cos(self) -> (T, T) { - self.radians.sin_cos() + impl Angle + where + T: Real, + { + /// Returns `(sin(self), cos(self))`. + pub fn sin_cos(self) -> (T, T) { + self.radians.sin_cos() + } } -} -impl Angle -where - T: Zero, -{ - pub fn zero() -> Self { - Angle::radians(T::zero()) + impl Angle + where + T: Zero, + { + pub fn zero() -> Self { + Angle::radians(T::zero()) + } } -} -impl Angle -where - T: FloatConst + Add, -{ - pub fn pi() -> Self { - Angle::radians(T::PI()) - } + impl Angle + where + T: FloatConst + Add, + { + pub fn pi() -> Self { + Angle::radians(T::PI()) + } - pub fn two_pi() -> Self { - Angle::radians(T::PI() + T::PI()) - } + pub fn two_pi() -> Self { + Angle::radians(T::PI() + T::PI()) + } - pub fn frac_pi_2() -> Self { - Angle::radians(T::FRAC_PI_2()) - } + pub fn frac_pi_2() -> Self { + Angle::radians(T::FRAC_PI_2()) + } - pub fn frac_pi_3() -> Self { - Angle::radians(T::FRAC_PI_3()) - } + pub fn frac_pi_3() -> Self { + Angle::radians(T::FRAC_PI_3()) + } - pub fn frac_pi_4() -> Self { - Angle::radians(T::FRAC_PI_4()) + pub fn frac_pi_4() -> Self { + Angle::radians(T::FRAC_PI_4()) + } } -} -impl Angle -where - T: NumCast + Copy, -{ - /// Cast from one numeric representation to another. - #[inline] - pub fn cast(&self) -> Angle { - self.try_cast().unwrap() - } + impl Angle + where + T: NumCast + Copy, + { + /// Cast from one numeric representation to another. + #[inline] + pub fn cast(&self) -> Angle { + self.try_cast().unwrap() + } - /// Fallible cast from one numeric representation to another. - pub fn try_cast(&self) -> Option> { - NumCast::from(self.radians).map(|radians| Angle { radians }) - } + /// Fallible cast from one numeric representation to another. + pub fn try_cast(&self) -> Option> { + NumCast::from(self.radians).map(|radians| Angle { radians }) + } - // Convenience functions for common casts. + // Convenience functions for common casts. - /// Cast angle to `f32`. - #[inline] - pub fn to_f32(&self) -> Angle { - self.cast() - } + /// Cast angle to `f32`. + #[inline] + pub fn to_f32(&self) -> Angle { + self.cast() + } - /// Cast angle `f64`. - #[inline] - pub fn to_f64(&self) -> Angle { - self.cast() + /// Cast angle `f64`. + #[inline] + pub fn to_f64(&self) -> Angle { + self.cast() + } } -} -impl> Add for Angle { - type Output = Self; - fn add(self, other: Self) -> Self { - Self::radians(self.radians + other.radians) + impl> Add for Angle { + type Output = Self; + fn add(self, other: Self) -> Self { + Self::radians(self.radians + other.radians) + } } -} -impl> Add<&Self> for Angle { - type Output = Self; - fn add(self, other: &Self) -> Self { - Self::radians(self.radians + other.radians) + impl> Add<&Self> for Angle { + type Output = Self; + fn add(self, other: &Self) -> Self { + Self::radians(self.radians + other.radians) + } } -} -impl Sum for Angle { - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) + impl Sum for Angle { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), Add::add) + } } -} -impl<'a, T: 'a + Add + Copy + Zero> Sum<&'a Self> for Angle { - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) + impl<'a, T: 'a + Add + Copy + Zero> Sum<&'a Self> for Angle { + fn sum>(iter: I) -> Self { + iter.fold(Self::zero(), Add::add) + } } -} -impl> AddAssign for Angle { - fn add_assign(&mut self, other: Angle) { - self.radians += other.radians; + impl> AddAssign for Angle { + fn add_assign(&mut self, other: Angle) { + self.radians += other.radians; + } } -} -impl> Sub> for Angle { - type Output = Angle; - fn sub(self, other: Angle) -> ::Output { - Angle::radians(self.radians - other.radians) + impl> Sub> for Angle { + type Output = Angle; + fn sub(self, other: Angle) -> ::Output { + Angle::radians(self.radians - other.radians) + } } -} -impl> SubAssign for Angle { - fn sub_assign(&mut self, other: Angle) { - self.radians -= other.radians; + impl> SubAssign for Angle { + fn sub_assign(&mut self, other: Angle) { + self.radians -= other.radians; + } } -} -impl> Div> for Angle { - type Output = T; - #[inline] - fn div(self, other: Angle) -> T { - self.radians / other.radians + impl> Div> for Angle { + type Output = T; + #[inline] + fn div(self, other: Angle) -> T { + self.radians / other.radians + } } -} -impl> Div for Angle { - type Output = Angle; - #[inline] - fn div(self, factor: T) -> Angle { - Angle::radians(self.radians / factor) + impl> Div for Angle { + type Output = Angle; + #[inline] + fn div(self, factor: T) -> Angle { + Angle::radians(self.radians / factor) + } } -} -impl> DivAssign for Angle { - fn div_assign(&mut self, factor: T) { - self.radians /= factor; + impl> DivAssign for Angle { + fn div_assign(&mut self, factor: T) { + self.radians /= factor; + } } -} -impl> Mul for Angle { - type Output = Angle; - #[inline] - fn mul(self, factor: T) -> Angle { - Angle::radians(self.radians * factor) + impl> Mul for Angle { + type Output = Angle; + #[inline] + fn mul(self, factor: T) -> Angle { + Angle::radians(self.radians * factor) + } } -} -impl> MulAssign for Angle { - fn mul_assign(&mut self, factor: T) { - self.radians *= factor; + impl> MulAssign for Angle { + fn mul_assign(&mut self, factor: T) { + self.radians *= factor; + } } -} -impl> Neg for Angle { - type Output = Self; - fn neg(self) -> Self { - Angle::radians(-self.radians) + impl> Neg for Angle { + type Output = Self; + fn neg(self) -> Self { + Angle::radians(-self.radians) + } } -} -impl> ApproxEq for Angle { - #[inline] - fn approx_epsilon() -> T { - T::approx_epsilon() - } + impl> ApproxEq for Angle { + #[inline] + fn approx_epsilon() -> T { + T::approx_epsilon() + } - #[inline] - fn approx_eq_eps(&self, other: &Angle, approx_epsilon: &T) -> bool { - self.radians.approx_eq_eps(&other.radians, approx_epsilon) + #[inline] + fn approx_eq_eps(&self, other: &Angle, approx_epsilon: &T) -> bool { + self.radians.approx_eq_eps(&other.radians, approx_epsilon) + } } -} - -#[test] -fn wrap_angles() { - use core::f32::consts::{FRAC_PI_2, PI}; - - assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero())); - assert!(Angle::radians(FRAC_PI_2) - .positive() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(-FRAC_PI_2) - .positive() - .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); - assert!(Angle::radians(3.0 * FRAC_PI_2) - .positive() - .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); - assert!(Angle::radians(5.0 * FRAC_PI_2) - .positive() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(2.0 * PI) - .positive() - .approx_eq(&Angle::zero())); - assert!(Angle::radians(-2.0 * PI) - .positive() - .approx_eq(&Angle::zero())); - assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi())); - assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi())); - - assert!(Angle::radians(FRAC_PI_2) - .signed() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(3.0 * FRAC_PI_2) - .signed() - .approx_eq(&-Angle::frac_pi_2())); - assert!(Angle::radians(5.0 * FRAC_PI_2) - .signed() - .approx_eq(&Angle::frac_pi_2())); - assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero())); - assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero())); - assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi())); - assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi())); -} -#[test] -fn lerp() { - type A = Angle; - - let a = A::radians(1.0); - let b = A::radians(2.0); - assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25))); - assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5))); - assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b + A::two_pi(), 0.75) - .approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b - A::two_pi(), 0.75) - .approx_eq(&Angle::radians(1.75))); - assert!(a - .lerp(b + A::two_pi() * 5.0, 0.75) - .approx_eq(&Angle::radians(1.75))); -} - -#[test] -fn sum() { - type A = Angle; - let angles = [A::radians(1.0), A::radians(2.0), A::radians(3.0)]; - let sum = A::radians(6.0); - assert_eq!(angles.iter().sum::(), sum); + #[test] + fn wrap_angles() { + use core::f32::consts::{FRAC_PI_2, PI}; + + assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero())); + assert!(Angle::radians(FRAC_PI_2) + .positive() + .approx_eq(&Angle::frac_pi_2())); + assert!(Angle::radians(-FRAC_PI_2) + .positive() + .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); + assert!(Angle::radians(3.0 * FRAC_PI_2) + .positive() + .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); + assert!(Angle::radians(5.0 * FRAC_PI_2) + .positive() + .approx_eq(&Angle::frac_pi_2())); + assert!(Angle::radians(2.0 * PI) + .positive() + .approx_eq(&Angle::zero())); + assert!(Angle::radians(-2.0 * PI) + .positive() + .approx_eq(&Angle::zero())); + assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi())); + assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi())); + + assert!(Angle::radians(FRAC_PI_2) + .signed() + .approx_eq(&Angle::frac_pi_2())); + assert!(Angle::radians(3.0 * FRAC_PI_2) + .signed() + .approx_eq(&-Angle::frac_pi_2())); + assert!(Angle::radians(5.0 * FRAC_PI_2) + .signed() + .approx_eq(&Angle::frac_pi_2())); + assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero())); + assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero())); + assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi())); + assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi())); + } + + #[test] + fn lerp() { + type A = Angle; + + let a = A::radians(1.0); + let b = A::radians(2.0); + assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25))); + assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5))); + assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75))); + assert!(a + .lerp(b + A::two_pi(), 0.75) + .approx_eq(&Angle::radians(1.75))); + assert!(a + .lerp(b - A::two_pi(), 0.75) + .approx_eq(&Angle::radians(1.75))); + assert!(a + .lerp(b + A::two_pi() * 5.0, 0.75) + .approx_eq(&Angle::radians(1.75))); + } + + #[test] + fn sum() { + type A = Angle; + let angles = [A::radians(1.0), A::radians(2.0), A::radians(3.0)]; + let sum = A::radians(6.0); + assert_eq!(angles.iter().sum::(), sum); + } } diff --git a/src/box2d.rs b/src/box2d.rs index 685f6aa..e7b17c6 100644 --- a/src/box2d.rs +++ b/src/box2d.rs @@ -21,7 +21,7 @@ use crate::vector::{vec2, Vector2D}; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use num_traits::{Float, NumCast}; +use num_traits::NumCast; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -728,14 +728,6 @@ impl Box2D { } } -impl Box2D { - /// Returns `true` if all members are finite. - #[inline] - pub fn is_finite(self) -> bool { - self.min.is_finite() && self.max.is_finite() - } -} - impl Box2D where T: Round, @@ -797,6 +789,7 @@ impl Default for Box2D { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use crate::default::Box2D; use crate::side_offsets::SideOffsets2D; @@ -1030,3 +1023,17 @@ mod tests { assert_eq!(b.size(), size2(5.0, 6.0)); } } + +#[cfg(any(feature = "std", feature = "libm"))] +mod float { + use super::Box2D; + use num_traits::Float; + + impl Box2D { + /// Returns `true` if all members are finite. + #[inline] + pub fn is_finite(self) -> bool { + self.min.is_finite() && self.max.is_finite() + } + } +} diff --git a/src/box3d.rs b/src/box3d.rs index fbdcb1b..364d885 100644 --- a/src/box3d.rs +++ b/src/box3d.rs @@ -19,7 +19,7 @@ use crate::vector::Vector3D; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use num_traits::{Float, NumCast}; +use num_traits::NumCast; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -738,14 +738,6 @@ impl Box3D { } } -impl Box3D { - /// Returns `true` if all members are finite. - #[inline] - pub fn is_finite(self) -> bool { - self.min.is_finite() && self.max.is_finite() - } -} - impl Box3D where T: Round, @@ -824,6 +816,7 @@ pub fn box3d( } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use crate::default::{Box3D, Point3D}; use crate::{point3, size3, vec3}; @@ -1083,3 +1076,17 @@ mod tests { assert!(Box3D { min: point3(1.0, -2.0, 1.0), max: point3(0.0, 1.0, NAN) }.is_empty()); } } + +#[cfg(any(feature = "std", feature = "libm"))] +mod float { + use super::Box3D; + use num_traits::Float; + + impl Box3D { + /// Returns `true` if all members are finite. + #[inline] + pub fn is_finite(self) -> bool { + self.min.is_finite() && self.max.is_finite() + } + } +} diff --git a/src/homogen.rs b/src/homogen.rs index 0033bfb..67036b7 100644 --- a/src/homogen.rs +++ b/src/homogen.rs @@ -219,6 +219,7 @@ impl fmt::Debug for HomogeneousVector { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod homogeneous { use super::HomogeneousVector; use crate::default::{Point2D, Point3D}; diff --git a/src/length.rs b/src/length.rs index 49e1a7f..1123e98 100644 --- a/src/length.rs +++ b/src/length.rs @@ -8,6 +8,7 @@ // except according to those terms. //! A one-dimensional length, tagged with its units. +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::num::Zero; @@ -361,6 +362,7 @@ impl Zero for Length { } } +#[cfg(any(feature = "std", feature = "libm"))] impl> ApproxEq for Length { #[inline] fn approx_epsilon() -> T { @@ -374,6 +376,7 @@ impl> ApproxEq for Length { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use super::Length; use crate::num::Zero; diff --git a/src/lib.rs b/src/lib.rs index 36e471e..3b97d30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,12 +59,14 @@ pub use crate::rotation::{Rotation2D, Rotation3D}; pub use crate::side_offsets::SideOffsets2D; pub use crate::size::{size2, size3, Size2D, Size3D}; pub use crate::translation::{Translation2D, Translation3D}; +#[cfg(any(feature = "std", feature = "libm"))] pub use crate::trig::Trig; #[macro_use] mod macros; mod angle; +#[cfg(any(feature = "std", feature = "libm"))] pub mod approxeq; pub mod approxord; mod box2d; @@ -82,6 +84,7 @@ mod size; mod transform2d; mod transform3d; mod translation; +#[cfg(any(feature = "std", feature = "libm"))] mod trig; mod vector; diff --git a/src/num.rs b/src/num.rs index e5135d0..dd7448a 100644 --- a/src/num.rs +++ b/src/num.rs @@ -93,29 +93,6 @@ macro_rules! num_int { }; } -macro_rules! num_float { - ($ty:ty) => { - impl Round for $ty { - #[inline] - fn round(self) -> $ty { - (self + 0.5).floor() - } - } - impl Floor for $ty { - #[inline] - fn floor(self) -> $ty { - num_traits::Float::floor(self) - } - } - impl Ceil for $ty { - #[inline] - fn ceil(self) -> $ty { - num_traits::Float::ceil(self) - } - } - }; -} - num_int!(i16); num_int!(u16); num_int!(i32); @@ -124,5 +101,36 @@ num_int!(i64); num_int!(u64); num_int!(isize); num_int!(usize); -num_float!(f32); -num_float!(f64); + +#[cfg(any(feature = "std", feature = "libm"))] +pub mod float { + use super::Ceil; + use super::Floor; + use super::Round; + + macro_rules! num_float { + ($ty:ty) => { + impl Round for $ty { + #[inline] + fn round(self) -> $ty { + (self + 0.5).floor() + } + } + impl Floor for $ty { + #[inline] + fn floor(self) -> $ty { + num_traits::Float::floor(self) + } + } + impl Ceil for $ty { + #[inline] + fn ceil(self) -> $ty { + num_traits::Float::ceil(self) + } + } + }; + } + + num_float!(f32); + num_float!(f64); +} diff --git a/src/point.rs b/src/point.rs index deb39c9..1cdc4b2 100644 --- a/src/point.rs +++ b/src/point.rs @@ -8,6 +8,7 @@ // except according to those terms. use super::UnknownUnit; +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; @@ -24,8 +25,12 @@ use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAss use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "mint")] use mint; +#[cfg(any(feature = "std", feature = "libm"))] use num_traits::real::Real; -use num_traits::{Euclid, Float, NumCast}; +#[cfg(any(feature = "std", feature = "libm"))] +use num_traits::Float; +use num_traits::{Euclid, NumCast}; + #[cfg(feature = "serde")] use serde; @@ -539,6 +544,7 @@ impl Point2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Point2D { /// Returns `true` if all members are finite. #[inline] @@ -554,6 +560,7 @@ impl, U> Point2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> Point2D { #[inline] pub fn distance_to(self, other: Self) -> T { @@ -742,6 +749,7 @@ impl Floor for Point2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> ApproxEq> for Point2D { #[inline] fn approx_epsilon() -> Self { @@ -1371,6 +1379,7 @@ impl Point3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Point3D { /// Returns `true` if all members are finite. #[inline] @@ -1390,6 +1399,7 @@ impl, U> Point3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> Point3D { #[inline] pub fn distance_to(self, other: Self) -> T { @@ -1590,6 +1600,7 @@ impl Floor for Point3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> ApproxEq> for Point3D { #[inline] fn approx_epsilon() -> Self { @@ -1704,6 +1715,7 @@ pub const fn point3(x: T, y: T, z: T) -> Point3D { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod point2d { use crate::default::Point2D; use crate::point2; @@ -1990,6 +2002,7 @@ mod point2d { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod point3d { use crate::default; use crate::default::Point3D; diff --git a/src/rect.rs b/src/rect.rs index 1b870ba..6f53762 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -20,7 +20,9 @@ use crate::vector::Vector2D; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; -use num_traits::{Float, NumCast}; +#[cfg(any(feature = "std", feature = "libm"))] +use num_traits::Float; +use num_traits::NumCast; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -609,6 +611,7 @@ impl Rect { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Rect { /// Returns `true` if all members are finite. #[inline] @@ -677,6 +680,7 @@ pub const fn rect(x: T, y: T, w: T, h: T) -> Rect { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use crate::default::{Point2D, Rect, Size2D}; use crate::side_offsets::SideOffsets2D; diff --git a/src/rigid.rs b/src/rigid.rs index 61b82d4..c6568eb 100644 --- a/src/rigid.rs +++ b/src/rigid.rs @@ -2,7 +2,9 @@ //! i.e. a vector `v` is transformed with `v * T`, and if you want to apply `T1` //! before `T2` you use `T1 * T2` +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; +#[cfg(any(feature = "std", feature = "libm"))] use crate::trig::Trig; use crate::{Rotation3D, Transform3D, UnknownUnit, Vector3D}; @@ -12,6 +14,7 @@ use core::{fmt, hash}; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +#[cfg(any(feature = "std", feature = "libm"))] use num_traits::real::Real; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -51,6 +54,7 @@ impl RigidTransform3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> RigidTransform3D { /// Construct an identity transform #[inline] @@ -251,6 +255,7 @@ impl MallocSizeOf for RigidTransform3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> From> for RigidTransform3D { @@ -259,6 +264,7 @@ impl, Src, Dst> From> } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> From> for RigidTransform3D { fn from(t: Vector3D) -> Self { Self::from_translation(t) @@ -266,6 +272,7 @@ impl, Src, Dst> From> for RigidTransform3 } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod test { use super::RigidTransform3D; use crate::default::{Rotation3D, Transform3D, Vector3D}; diff --git a/src/rotation.rs b/src/rotation.rs index 7103fd9..2468320 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -7,7 +7,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; +#[cfg(any(feature = "std", feature = "libm"))] use crate::trig::Trig; use crate::{point2, point3, vec3, Angle, Point2D, Point3D, Vector2D, Vector3D}; use crate::{Transform2D, Transform3D, UnknownUnit}; @@ -22,6 +24,7 @@ use core::ops::{Add, Mul, Neg, Sub}; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "malloc_size_of")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +#[cfg(any(feature = "std", feature = "libm"))] use num_traits::real::Real; use num_traits::{NumCast, One, Zero}; #[cfg(feature = "serde")] @@ -196,6 +199,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] impl Rotation2D { /// Creates a 3d rotation (around the z axis) from this 2d rotation. #[inline] @@ -233,6 +237,7 @@ impl Rotation2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Rotation2D where T: Copy + Add + Sub + Mul + Zero + Trig, @@ -250,6 +255,7 @@ impl fmt::Debug for Rotation2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl ApproxEq for Rotation2D where T: Copy + Neg + ApproxEq, @@ -476,6 +482,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] impl Rotation3D where T: Real, @@ -787,6 +794,7 @@ impl fmt::Debug for Rotation3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl ApproxEq for Rotation3D where T: Copy + Neg + ApproxEq, @@ -807,261 +815,268 @@ where } } -#[test] -fn simple_rotation_2d() { - use crate::default::Rotation2D; - use core::f32::consts::{FRAC_PI_2, PI}; - - let ri = Rotation2D::identity(); - let r90 = Rotation2D::radians(FRAC_PI_2); - let rm90 = Rotation2D::radians(-FRAC_PI_2); - let r180 = Rotation2D::radians(PI); - - assert!(ri - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(1.0, 2.0))); - assert!(r90 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(-2.0, 1.0))); - assert!(rm90 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(2.0, -1.0))); - assert!(r180 - .transform_point(point2(1.0, 2.0)) - .approx_eq(&point2(-1.0, -2.0))); - - assert!(r90 - .inverse() - .inverse() - .transform_point(point2(1.0, 2.0)) - .approx_eq(&r90.transform_point(point2(1.0, 2.0)))); -} +#[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] +mod tests { + use crate::approxeq::ApproxEq; + use crate::{point2, point3, Angle}; + + #[test] + fn simple_rotation_2d() { + use crate::default::Rotation2D; + use core::f32::consts::{FRAC_PI_2, PI}; + + let ri = Rotation2D::identity(); + let r90 = Rotation2D::radians(FRAC_PI_2); + let rm90 = Rotation2D::radians(-FRAC_PI_2); + let r180 = Rotation2D::radians(PI); + + assert!(ri + .transform_point(point2(1.0, 2.0)) + .approx_eq(&point2(1.0, 2.0))); + assert!(r90 + .transform_point(point2(1.0, 2.0)) + .approx_eq(&point2(-2.0, 1.0))); + assert!(rm90 + .transform_point(point2(1.0, 2.0)) + .approx_eq(&point2(2.0, -1.0))); + assert!(r180 + .transform_point(point2(1.0, 2.0)) + .approx_eq(&point2(-1.0, -2.0))); + + assert!(r90 + .inverse() + .inverse() + .transform_point(point2(1.0, 2.0)) + .approx_eq(&r90.transform_point(point2(1.0, 2.0)))); + } -#[test] -fn simple_rotation_3d_in_2d() { - use crate::default::Rotation3D; - use core::f32::consts::{FRAC_PI_2, PI}; - - let ri = Rotation3D::identity(); - let r90 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); - let rm90 = Rotation3D::around_z(Angle::radians(-FRAC_PI_2)); - let r180 = Rotation3D::around_z(Angle::radians(PI)); - - assert!(ri - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(1.0, 2.0))); - assert!(r90 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(-2.0, 1.0))); - assert!(rm90 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(2.0, -1.0))); - assert!(r180 - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&point2(-1.0, -2.0))); - - assert!(r90 - .inverse() - .inverse() - .transform_point2d(point2(1.0, 2.0)) - .approx_eq(&r90.transform_point2d(point2(1.0, 2.0)))); -} + #[test] + fn simple_rotation_3d_in_2d() { + use crate::default::Rotation3D; + use core::f32::consts::{FRAC_PI_2, PI}; + + let ri = Rotation3D::identity(); + let r90 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); + let rm90 = Rotation3D::around_z(Angle::radians(-FRAC_PI_2)); + let r180 = Rotation3D::around_z(Angle::radians(PI)); + + assert!(ri + .transform_point2d(point2(1.0, 2.0)) + .approx_eq(&point2(1.0, 2.0))); + assert!(r90 + .transform_point2d(point2(1.0, 2.0)) + .approx_eq(&point2(-2.0, 1.0))); + assert!(rm90 + .transform_point2d(point2(1.0, 2.0)) + .approx_eq(&point2(2.0, -1.0))); + assert!(r180 + .transform_point2d(point2(1.0, 2.0)) + .approx_eq(&point2(-1.0, -2.0))); + + assert!(r90 + .inverse() + .inverse() + .transform_point2d(point2(1.0, 2.0)) + .approx_eq(&r90.transform_point2d(point2(1.0, 2.0)))); + } -#[test] -fn pre_post() { - use crate::default::Rotation3D; - use core::f32::consts::FRAC_PI_2; + #[test] + fn pre_post() { + use crate::default::Rotation3D; + use core::f32::consts::FRAC_PI_2; - let r1 = Rotation3D::around_x(Angle::radians(FRAC_PI_2)); - let r2 = Rotation3D::around_y(Angle::radians(FRAC_PI_2)); - let r3 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); + let r1 = Rotation3D::around_x(Angle::radians(FRAC_PI_2)); + let r2 = Rotation3D::around_y(Angle::radians(FRAC_PI_2)); + let r3 = Rotation3D::around_z(Angle::radians(FRAC_PI_2)); - let t1 = r1.to_transform(); - let t2 = r2.to_transform(); - let t3 = r3.to_transform(); + let t1 = r1.to_transform(); + let t2 = r2.to_transform(); + let t3 = r3.to_transform(); - let p = point3(1.0, 2.0, 3.0); + let p = point3(1.0, 2.0, 3.0); - // Check that the order of transformations is correct (corresponds to what - // we do in Transform3D). - let p1 = r1.then(&r2).then(&r3).transform_point3d(p); - let p2 = t1.then(&t2).then(&t3).transform_point3d(p); + // Check that the order of transformations is correct (corresponds to what + // we do in Transform3D). + let p1 = r1.then(&r2).then(&r3).transform_point3d(p); + let p2 = t1.then(&t2).then(&t3).transform_point3d(p); - assert!(p1.approx_eq(&p2.unwrap())); + assert!(p1.approx_eq(&p2.unwrap())); - // Check that changing the order indeed matters. - let p3 = t3.then(&t1).then(&t2).transform_point3d(p); - assert!(!p1.approx_eq(&p3.unwrap())); -} + // Check that changing the order indeed matters. + let p3 = t3.then(&t1).then(&t2).transform_point3d(p); + assert!(!p1.approx_eq(&p3.unwrap())); + } -#[test] -fn to_transform3d() { - use crate::default::Rotation3D; - - use core::f32::consts::{FRAC_PI_2, PI}; - let rotations = [ - Rotation3D::identity(), - Rotation3D::around_x(Angle::radians(FRAC_PI_2)), - Rotation3D::around_x(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_x(Angle::radians(PI)), - Rotation3D::around_y(Angle::radians(FRAC_PI_2)), - Rotation3D::around_y(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_y(Angle::radians(PI)), - Rotation3D::around_z(Angle::radians(FRAC_PI_2)), - Rotation3D::around_z(Angle::radians(-FRAC_PI_2)), - Rotation3D::around_z(Angle::radians(PI)), - ]; - - let points = [ - point3(0.0, 0.0, 0.0), - point3(1.0, 2.0, 3.0), - point3(-5.0, 3.0, -1.0), - point3(-0.5, -1.0, 1.5), - ]; - - for rotation in &rotations { - for &point in &points { - let p1 = rotation.transform_point3d(point); - let p2 = rotation.to_transform().transform_point3d(point); - assert!(p1.approx_eq(&p2.unwrap())); + #[test] + fn to_transform3d() { + use crate::default::Rotation3D; + + use core::f32::consts::{FRAC_PI_2, PI}; + let rotations = [ + Rotation3D::identity(), + Rotation3D::around_x(Angle::radians(FRAC_PI_2)), + Rotation3D::around_x(Angle::radians(-FRAC_PI_2)), + Rotation3D::around_x(Angle::radians(PI)), + Rotation3D::around_y(Angle::radians(FRAC_PI_2)), + Rotation3D::around_y(Angle::radians(-FRAC_PI_2)), + Rotation3D::around_y(Angle::radians(PI)), + Rotation3D::around_z(Angle::radians(FRAC_PI_2)), + Rotation3D::around_z(Angle::radians(-FRAC_PI_2)), + Rotation3D::around_z(Angle::radians(PI)), + ]; + + let points = [ + point3(0.0, 0.0, 0.0), + point3(1.0, 2.0, 3.0), + point3(-5.0, 3.0, -1.0), + point3(-0.5, -1.0, 1.5), + ]; + + for rotation in &rotations { + for &point in &points { + let p1 = rotation.transform_point3d(point); + let p2 = rotation.to_transform().transform_point3d(point); + assert!(p1.approx_eq(&p2.unwrap())); + } } } -} -#[test] -fn slerp() { - use crate::default::Rotation3D; - - let q1 = Rotation3D::quaternion(1.0, 0.0, 0.0, 0.0); - let q2 = Rotation3D::quaternion(0.0, 1.0, 0.0, 0.0); - let q3 = Rotation3D::quaternion(0.0, 0.0, -1.0, 0.0); - - // The values below can be obtained with a python program: - // import numpy - // import quaternion - // q1 = numpy.quaternion(1, 0, 0, 0) - // q2 = numpy.quaternion(0, 1, 0, 0) - // quaternion.slerp_evaluate(q1, q2, 0.2) - - assert!(q1.slerp(&q2, 0.0).approx_eq(&q1)); - assert!(q1.slerp(&q2, 0.2).approx_eq(&Rotation3D::quaternion( - 0.951056516295154, - 0.309016994374947, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.4).approx_eq(&Rotation3D::quaternion( - 0.809016994374947, - 0.587785252292473, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.6).approx_eq(&Rotation3D::quaternion( - 0.587785252292473, - 0.809016994374947, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 0.8).approx_eq(&Rotation3D::quaternion( - 0.309016994374947, - 0.951056516295154, - 0.0, - 0.0 - ))); - assert!(q1.slerp(&q2, 1.0).approx_eq(&q2)); - - assert!(q1.slerp(&q3, 0.0).approx_eq(&q1)); - assert!(q1.slerp(&q3, 0.2).approx_eq(&Rotation3D::quaternion( - 0.951056516295154, - 0.0, - -0.309016994374947, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.4).approx_eq(&Rotation3D::quaternion( - 0.809016994374947, - 0.0, - -0.587785252292473, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.6).approx_eq(&Rotation3D::quaternion( - 0.587785252292473, - 0.0, - -0.809016994374947, - 0.0 - ))); - assert!(q1.slerp(&q3, 0.8).approx_eq(&Rotation3D::quaternion( - 0.309016994374947, - 0.0, - -0.951056516295154, - 0.0 - ))); - assert!(q1.slerp(&q3, 1.0).approx_eq(&q3)); -} + #[test] + fn slerp() { + use crate::default::Rotation3D; + + let q1 = Rotation3D::quaternion(1.0, 0.0, 0.0, 0.0); + let q2 = Rotation3D::quaternion(0.0, 1.0, 0.0, 0.0); + let q3 = Rotation3D::quaternion(0.0, 0.0, -1.0, 0.0); + + // The values below can be obtained with a python program: + // import numpy + // import quaternion + // q1 = numpy.quaternion(1, 0, 0, 0) + // q2 = numpy.quaternion(0, 1, 0, 0) + // quaternion.slerp_evaluate(q1, q2, 0.2) + + assert!(q1.slerp(&q2, 0.0).approx_eq(&q1)); + assert!(q1.slerp(&q2, 0.2).approx_eq(&Rotation3D::quaternion( + 0.951056516295154, + 0.309016994374947, + 0.0, + 0.0 + ))); + assert!(q1.slerp(&q2, 0.4).approx_eq(&Rotation3D::quaternion( + 0.809016994374947, + 0.587785252292473, + 0.0, + 0.0 + ))); + assert!(q1.slerp(&q2, 0.6).approx_eq(&Rotation3D::quaternion( + 0.587785252292473, + 0.809016994374947, + 0.0, + 0.0 + ))); + assert!(q1.slerp(&q2, 0.8).approx_eq(&Rotation3D::quaternion( + 0.309016994374947, + 0.951056516295154, + 0.0, + 0.0 + ))); + assert!(q1.slerp(&q2, 1.0).approx_eq(&q2)); + + assert!(q1.slerp(&q3, 0.0).approx_eq(&q1)); + assert!(q1.slerp(&q3, 0.2).approx_eq(&Rotation3D::quaternion( + 0.951056516295154, + 0.0, + -0.309016994374947, + 0.0 + ))); + assert!(q1.slerp(&q3, 0.4).approx_eq(&Rotation3D::quaternion( + 0.809016994374947, + 0.0, + -0.587785252292473, + 0.0 + ))); + assert!(q1.slerp(&q3, 0.6).approx_eq(&Rotation3D::quaternion( + 0.587785252292473, + 0.0, + -0.809016994374947, + 0.0 + ))); + assert!(q1.slerp(&q3, 0.8).approx_eq(&Rotation3D::quaternion( + 0.309016994374947, + 0.0, + -0.951056516295154, + 0.0 + ))); + assert!(q1.slerp(&q3, 1.0).approx_eq(&q3)); + } -#[test] -fn around_axis() { - use crate::default::Rotation3D; - use core::f32::consts::{FRAC_PI_2, PI}; - - // Two sort of trivial cases: - let r1 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(PI)); - let r2 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(FRAC_PI_2)); - assert!(r1 - .transform_point3d(point3(1.0, 2.0, 0.0)) - .approx_eq(&point3(2.0, 1.0, 0.0))); - assert!(r2 - .transform_point3d(point3(1.0, 0.0, 0.0)) - .approx_eq(&point3(0.5, 0.5, -0.5.sqrt()))); - - // A more arbitrary test (made up with numpy): - let r3 = Rotation3D::around_axis(vec3(0.5, 1.0, 2.0), Angle::radians(2.291288)); - assert!(r3 - .transform_point3d(point3(1.0, 0.0, 0.0)) - .approx_eq(&point3(-0.58071821, 0.81401868, -0.01182979))); -} + #[test] + fn around_axis() { + use crate::default::Rotation3D; + use core::f32::consts::{FRAC_PI_2, PI}; + + // Two sort of trivial cases: + let r1 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(PI)); + let r2 = Rotation3D::around_axis(vec3(1.0, 1.0, 0.0), Angle::radians(FRAC_PI_2)); + assert!(r1 + .transform_point3d(point3(1.0, 2.0, 0.0)) + .approx_eq(&point3(2.0, 1.0, 0.0))); + assert!(r2 + .transform_point3d(point3(1.0, 0.0, 0.0)) + .approx_eq(&point3(0.5, 0.5, -0.5.sqrt()))); + + // A more arbitrary test (made up with numpy): + let r3 = Rotation3D::around_axis(vec3(0.5, 1.0, 2.0), Angle::radians(2.291288)); + assert!(r3 + .transform_point3d(point3(1.0, 0.0, 0.0)) + .approx_eq(&point3(-0.58071821, 0.81401868, -0.01182979))); + } -#[test] -fn from_euler() { - use crate::default::Rotation3D; - use core::f32::consts::FRAC_PI_2; - - // First test simple separate yaw pitch and roll rotations, because it is easy to come - // up with the corresponding quaternion. - // Since several quaternions can represent the same transformation we compare the result - // of transforming a point rather than the values of each quaternions. - let p = point3(1.0, 2.0, 3.0); - - let angle = Angle::radians(FRAC_PI_2); - let zero = Angle::radians(0.0); - - // roll - let roll_re = Rotation3D::euler(angle, zero, zero); - let roll_rq = Rotation3D::around_x(angle); - let roll_pe = roll_re.transform_point3d(p); - let roll_pq = roll_rq.transform_point3d(p); - - // pitch - let pitch_re = Rotation3D::euler(zero, angle, zero); - let pitch_rq = Rotation3D::around_y(angle); - let pitch_pe = pitch_re.transform_point3d(p); - let pitch_pq = pitch_rq.transform_point3d(p); - - // yaw - let yaw_re = Rotation3D::euler(zero, zero, angle); - let yaw_rq = Rotation3D::around_z(angle); - let yaw_pe = yaw_re.transform_point3d(p); - let yaw_pq = yaw_rq.transform_point3d(p); - - assert!(roll_pe.approx_eq(&roll_pq)); - assert!(pitch_pe.approx_eq(&pitch_pq)); - assert!(yaw_pe.approx_eq(&yaw_pq)); - - // Now check that the yaw pitch and roll transformations when combined are applied in - // the proper order: roll -> pitch -> yaw. - let ypr_e = Rotation3D::euler(angle, angle, angle); - let ypr_q = roll_rq.then(&pitch_rq).then(&yaw_rq); - let ypr_pe = ypr_e.transform_point3d(p); - let ypr_pq = ypr_q.transform_point3d(p); - - assert!(ypr_pe.approx_eq(&ypr_pq)); + #[test] + fn from_euler() { + use crate::default::Rotation3D; + use core::f32::consts::FRAC_PI_2; + + // First test simple separate yaw pitch and roll rotations, because it is easy to come + // up with the corresponding quaternion. + // Since several quaternions can represent the same transformation we compare the result + // of transforming a point rather than the values of each quaternions. + let p = point3(1.0, 2.0, 3.0); + + let angle = Angle::radians(FRAC_PI_2); + let zero = Angle::radians(0.0); + + // roll + let roll_re = Rotation3D::euler(angle, zero, zero); + let roll_rq = Rotation3D::around_x(angle); + let roll_pe = roll_re.transform_point3d(p); + let roll_pq = roll_rq.transform_point3d(p); + + // pitch + let pitch_re = Rotation3D::euler(zero, angle, zero); + let pitch_rq = Rotation3D::around_y(angle); + let pitch_pe = pitch_re.transform_point3d(p); + let pitch_pq = pitch_rq.transform_point3d(p); + + // yaw + let yaw_re = Rotation3D::euler(zero, zero, angle); + let yaw_rq = Rotation3D::around_z(angle); + let yaw_pe = yaw_re.transform_point3d(p); + let yaw_pq = yaw_rq.transform_point3d(p); + + assert!(roll_pe.approx_eq(&roll_pq)); + assert!(pitch_pe.approx_eq(&pitch_pq)); + assert!(yaw_pe.approx_eq(&yaw_pq)); + + // Now check that the yaw pitch and roll transformations when combined are applied in + // the proper order: roll -> pitch -> yaw. + let ypr_e = Rotation3D::euler(angle, angle, angle); + let ypr_q = roll_rq.then(&pitch_rq).then(&yaw_rq); + let ypr_pe = ypr_e.transform_point3d(p); + let ypr_pq = ypr_q.transform_point3d(p); + + assert!(ypr_pe.approx_eq(&ypr_pq)); + } } diff --git a/src/scale.rs b/src/scale.rs index 983b366..15eb7d4 100644 --- a/src/scale.rs +++ b/src/scale.rs @@ -437,6 +437,7 @@ impl One for Scale { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use super::Scale; diff --git a/src/side_offsets.rs b/src/side_offsets.rs index 7f5e6fe..25982c2 100644 --- a/src/side_offsets.rs +++ b/src/side_offsets.rs @@ -411,128 +411,134 @@ impl DivAssign> for SideOffsets2D { } } -#[test] -fn from_vectors() { - use crate::{point2, vec2}; - type Box2D = crate::default::Box2D; - - let b = Box2D { - min: point2(10, 10), - max: point2(20, 20), - }; - - let outer = b.outer_box(SideOffsets2D::from_vectors_outer(vec2(-1, -2), vec2(3, 4))); - let inner = b.inner_box(SideOffsets2D::from_vectors_inner(vec2(1, 2), vec2(-3, -4))); - - assert_eq!( - outer, - Box2D { - min: point2(9, 8), - max: point2(23, 24) - } - ); - assert_eq!( - inner, - Box2D { - min: point2(11, 12), - max: point2(17, 16) - } - ); -} +#[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] +mod tests { + use crate::SideOffsets2D; -#[test] -fn test_is_zero() { - let s1: SideOffsets2D = SideOffsets2D::new_all_same(0.0); - assert!(s1.is_zero()); + #[test] + fn from_vectors() { + use crate::{point2, vec2}; + type Box2D = crate::default::Box2D; + + let b = Box2D { + min: point2(10, 10), + max: point2(20, 20), + }; + + let outer = b.outer_box(SideOffsets2D::from_vectors_outer(vec2(-1, -2), vec2(3, 4))); + let inner = b.inner_box(SideOffsets2D::from_vectors_inner(vec2(1, 2), vec2(-3, -4))); + + assert_eq!( + outer, + Box2D { + min: point2(9, 8), + max: point2(23, 24) + } + ); + assert_eq!( + inner, + Box2D { + min: point2(11, 12), + max: point2(17, 16) + } + ); + } - let s2: SideOffsets2D = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - assert!(!s2.is_zero()); -} + #[test] + fn test_is_zero() { + let s1: SideOffsets2D = SideOffsets2D::new_all_same(0.0); + assert!(s1.is_zero()); -#[cfg(test)] -mod ops { - use crate::Scale; + let s2: SideOffsets2D = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); + assert!(!s2.is_zero()); + } - pub enum Mm {} - pub enum Cm {} + #[cfg(test)] + mod ops { + use crate::Scale; - type SideOffsets2D = crate::default::SideOffsets2D; - type SideOffsets2DMm = crate::SideOffsets2D; - type SideOffsets2DCm = crate::SideOffsets2D; + pub enum Mm {} + pub enum Cm {} - #[test] - fn test_mul_scalar() { - let s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); + type SideOffsets2D = crate::default::SideOffsets2D; + type SideOffsets2DMm = crate::SideOffsets2D; + type SideOffsets2DCm = crate::SideOffsets2D; - let result = s * 3.0; + #[test] + fn test_mul_scalar() { + let s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - assert_eq!(result, SideOffsets2D::new(3.0, 6.0, 9.0, 12.0)); - } + let result = s * 3.0; - #[test] - fn test_mul_assign_scalar() { - let mut s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); + assert_eq!(result, SideOffsets2D::new(3.0, 6.0, 9.0, 12.0)); + } - s *= 2.0; + #[test] + fn test_mul_assign_scalar() { + let mut s = SideOffsets2D::new(1.0, 2.0, 3.0, 4.0); - assert_eq!(s, SideOffsets2D::new(2.0, 4.0, 6.0, 8.0)); - } + s *= 2.0; - #[test] - fn test_mul_scale() { - let s = SideOffsets2DMm::new(0.0, 1.0, 3.0, 2.0); - let cm_per_mm: Scale = Scale::new(0.1); + assert_eq!(s, SideOffsets2D::new(2.0, 4.0, 6.0, 8.0)); + } - let result = s * cm_per_mm; + #[test] + fn test_mul_scale() { + let s = SideOffsets2DMm::new(0.0, 1.0, 3.0, 2.0); + let cm_per_mm: Scale = Scale::new(0.1); - assert_eq!(result, SideOffsets2DCm::new(0.0, 0.1, 0.3, 0.2)); - } + let result = s * cm_per_mm; - #[test] - fn test_mul_assign_scale() { - let mut s = SideOffsets2DMm::new(2.0, 4.0, 6.0, 8.0); - let scale: Scale = Scale::new(0.1); + assert_eq!(result, SideOffsets2DCm::new(0.0, 0.1, 0.3, 0.2)); + } - s *= scale; + #[test] + fn test_mul_assign_scale() { + let mut s = SideOffsets2DMm::new(2.0, 4.0, 6.0, 8.0); + let scale: Scale = Scale::new(0.1); - assert_eq!(s, SideOffsets2DMm::new(0.2, 0.4, 0.6, 0.8)); - } + s *= scale; - #[test] - fn test_div_scalar() { - let s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); + assert_eq!(s, SideOffsets2DMm::new(0.2, 0.4, 0.6, 0.8)); + } - let result = s / 10.0; + #[test] + fn test_div_scalar() { + let s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); - assert_eq!(result, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); - } + let result = s / 10.0; - #[test] - fn test_div_assign_scalar() { - let mut s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); + assert_eq!(result, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); + } - s /= 10.0; + #[test] + fn test_div_assign_scalar() { + let mut s = SideOffsets2D::new(10.0, 20.0, 30.0, 40.0); - assert_eq!(s, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); - } + s /= 10.0; - #[test] - fn test_div_scale() { - let s = SideOffsets2DCm::new(0.1, 0.2, 0.3, 0.4); - let cm_per_mm: Scale = Scale::new(0.1); + assert_eq!(s, SideOffsets2D::new(1.0, 2.0, 3.0, 4.0)); + } - let result = s / cm_per_mm; + #[test] + fn test_div_scale() { + let s = SideOffsets2DCm::new(0.1, 0.2, 0.3, 0.4); + let cm_per_mm: Scale = Scale::new(0.1); - assert_eq!(result, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); - } + let result = s / cm_per_mm; - #[test] - fn test_div_assign_scale() { - let mut s = SideOffsets2DMm::new(0.1, 0.2, 0.3, 0.4); - let scale: Scale = Scale::new(0.1); + assert_eq!(result, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); + } - s /= scale; + #[test] + fn test_div_assign_scale() { + let mut s = SideOffsets2DMm::new(0.1, 0.2, 0.3, 0.4); + let scale: Scale = Scale::new(0.1); - assert_eq!(s, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); + s /= scale; + + assert_eq!(s, SideOffsets2DMm::new(1.0, 2.0, 3.0, 4.0)); + } } } diff --git a/src/size.rs b/src/size.rs index 6eb5618..1a23112 100644 --- a/src/size.rs +++ b/src/size.rs @@ -28,7 +28,10 @@ use bytemuck::{Pod, Zeroable}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "mint")] use mint; -use num_traits::{Float, NumCast, Signed}; +#[cfg(any(feature = "std", feature = "libm"))] +use num_traits::Float; +use num_traits::{NumCast, Signed}; + #[cfg(feature = "serde")] use serde; @@ -409,6 +412,7 @@ impl Size2D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Size2D { /// Returns `true` if all members are finite. #[inline] @@ -1326,6 +1330,7 @@ impl Size3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl Size3D { /// Returns `true` if all members are finite. #[inline] @@ -1691,6 +1696,7 @@ pub const fn size3(w: T, h: T, d: T) -> Size3D { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod size3d { mod ops { use crate::default::{Size2D, Size3D}; diff --git a/src/transform2d.rs b/src/transform2d.rs index 38d3ba1..8d3f9e1 100644 --- a/src/transform2d.rs +++ b/src/transform2d.rs @@ -10,12 +10,14 @@ #![allow(clippy::just_underscores_and_digits)] use super::{Angle, UnknownUnit}; +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; use crate::box2d::Box2D; use crate::num::{One, Zero}; use crate::point::{point2, Point2D}; use crate::rect::Rect; use crate::transform3d::Transform3D; +#[cfg(any(feature = "std", feature = "libm"))] use crate::trig::Trig; use crate::vector::{vec2, Vector2D}; use core::cmp::{Eq, PartialEq}; @@ -183,7 +185,10 @@ impl Transform2D { _unit: PhantomData, } } +} +#[cfg(any(feature = "std", feature = "libm"))] +impl Transform2D { /// Returns `true` if this transform is approximately equal to the other one, using /// `T`'s default epsilon value. /// @@ -464,6 +469,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] /// Methods for creating and combining rotation transformations impl Transform2D where @@ -657,6 +663,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> ApproxEq for Transform2D { #[inline] fn approx_epsilon() -> T { @@ -712,6 +719,7 @@ impl From> for mint::RowMatrix3x2 { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod test { use super::*; use crate::approxeq::ApproxEq; diff --git a/src/transform3d.rs b/src/transform3d.rs index a897c58..490d1b4 100644 --- a/src/transform3d.rs +++ b/src/transform3d.rs @@ -10,6 +10,7 @@ #![allow(clippy::just_underscores_and_digits)] use super::{Angle, UnknownUnit}; +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; use crate::box2d::Box2D; use crate::box3d::Box3D; @@ -19,6 +20,7 @@ use crate::point::{point2, point3, Point2D, Point3D}; use crate::rect::Rect; use crate::scale::Scale; use crate::transform2d::Transform2D; +#[cfg(any(feature = "std", feature = "libm"))] use crate::trig::Trig; use crate::vector::{vec2, vec3, Vector2D, Vector3D}; @@ -487,6 +489,7 @@ where *self == Self::identity() } + #[cfg(any(feature = "std", feature = "libm"))] /// Create a 2d skew transform. /// /// See @@ -627,6 +630,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] /// Methods for creating and combining rotation transformations impl Transform3D where @@ -1133,6 +1137,7 @@ impl Transform3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> Transform3D { /// Returns `true` if this transform is approximately equal to the other one, using /// `T`'s default epsilon value. @@ -1153,6 +1158,7 @@ impl, Src, Dst> Transform3D { } } +#[cfg(any(feature = "std", feature = "libm"))] impl, Src, Dst> ApproxEq for Transform3D { #[inline] fn approx_epsilon() -> T { @@ -1222,6 +1228,7 @@ impl From> for mint::RowMatrix4 { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod tests { use super::*; use crate::approxeq::ApproxEq; diff --git a/src/translation.rs b/src/translation.rs index 662d9a4..1a6b21d 100644 --- a/src/translation.rs +++ b/src/translation.rs @@ -849,6 +849,7 @@ impl fmt::Debug for Translation3D { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod _2d { #[test] fn simple() { @@ -955,6 +956,7 @@ mod _2d { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod _3d { #[test] fn simple() { diff --git a/src/vector.rs b/src/vector.rs index 7a009e7..d2408ed 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -8,6 +8,7 @@ // except according to those terms. use super::UnknownUnit; +#[cfg(any(feature = "std", feature = "libm"))] use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; @@ -17,6 +18,7 @@ use crate::scale::Scale; use crate::size::{size2, size3, Size2D, Size3D}; use crate::transform2d::Transform2D; use crate::transform3d::Transform3D; +#[cfg(any(feature = "std", feature = "libm"))] use crate::trig::Trig; use crate::Angle; use core::cmp::{Eq, PartialEq}; @@ -25,12 +27,13 @@ use core::hash::Hash; use core::iter::Sum; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -#[cfg(feature = "malloc_size_of")] -use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; #[cfg(feature = "mint")] use mint; +#[cfg(any(feature = "std", feature = "libm"))] use num_traits::real::Real; -use num_traits::{Float, NumCast, Signed}; +#[cfg(any(feature = "std", feature = "libm"))] +use num_traits::Float; +use num_traits::{NumCast, Signed}; #[cfg(feature = "serde")] use serde; @@ -62,13 +65,6 @@ impl Clone for Vector2D { } } -#[cfg(feature = "malloc_size_of")] -impl MallocSizeOf for Vector2D { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.x.size_of(ops) + self.y.size_of(ops) - } -} - #[cfg(feature = "serde")] impl<'de, T, U> serde::Deserialize<'de> for Vector2D where @@ -198,14 +194,6 @@ impl Vector2D { } } - /// Constructor taking angle and length - pub fn from_angle_and_length(angle: Angle, length: T) -> Self - where - T: Trig + Mul + Copy, - { - vec2(length * angle.radians.cos(), length * angle.radians.sin()) - } - /// Constructor taking properly Lengths instead of scalar values. #[inline] pub fn from_lengths(x: Length, y: Length) -> Self { @@ -438,18 +426,6 @@ impl Vector2D { vec2(self.x.floor(), self.y.floor()) } - /// Returns the signed angle between this vector and the x axis. - /// Positive values counted counterclockwise, where 0 is `+x` axis, `PI/2` - /// is `+y` axis. - /// - /// The returned angle is between -PI and PI. - pub fn angle_from_x_axis(self) -> Angle - where - T: Trig, - { - Angle::radians(Trig::fast_atan2(self.y, self.x)) - } - /// Creates translation by this vector in vector units. #[inline] pub fn to_transform(self) -> Transform2D @@ -480,18 +456,9 @@ where { onto * (self.dot(onto) / onto.square_length()) } - - /// Returns the signed angle between this vector and another vector. - /// - /// The returned angle is between -PI and PI. - pub fn angle_to(self, other: Self) -> Angle - where - T: Sub + Trig, - { - Angle::radians(Trig::fast_atan2(self.cross(other), self.dot(other))) - } } +#[cfg(any(feature = "std", feature = "libm"))] impl Vector2D { /// Return the normalized vector even if the length is larger than the max value of Float. #[inline] @@ -506,13 +473,14 @@ impl Vector2D { } } - /// Returns `true` if all members are finite. + /// Returns true if all members are finite. #[inline] pub fn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() } } +#[cfg(any(feature = "std", feature = "libm"))] impl Vector2D { /// Returns the vector length. #[inline] @@ -529,7 +497,7 @@ impl Vector2D { /// Returns the vector with length of one unit. /// - /// Unlike [`Vector2D::normalize`], this returns `None` in the case that the + /// Unlike [`Vector2D::normalize`](#method.normalize), this returns None in the case that the /// length of the vector is zero. #[inline] #[must_use] @@ -724,16 +692,6 @@ impl Vector2D { self.cast() } - /// Cast into an `isize` vector, truncating decimals if any. - /// - /// When casting from floating vector vectors, it is worth considering whether - /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain - /// the desired conversion behavior. - #[inline] - pub fn to_isize(self) -> Vector2D { - self.cast() - } - /// Cast into an `u32` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether @@ -807,7 +765,7 @@ impl<'a, T: 'a + Add + Copy + Zero, U: 'a> Sum<&'a Self> for Vector2 impl, U> AddAssign for Vector2D { #[inline] fn add_assign(&mut self, other: Self) { - *self = *self + other; + *self = *self + other } } @@ -823,7 +781,7 @@ impl Sub for Vector2D { impl, U> SubAssign> for Vector2D { #[inline] fn sub_assign(&mut self, other: Self) { - *self = *self - other; + *self = *self - other } } @@ -839,7 +797,7 @@ impl Mul for Vector2D { impl, U> MulAssign for Vector2D { #[inline] fn mul_assign(&mut self, scale: T) { - *self = *self * scale; + *self = *self * scale } } @@ -872,7 +830,7 @@ impl Div for Vector2D { impl, U> DivAssign for Vector2D { #[inline] fn div_assign(&mut self, scale: T) { - *self = *self / scale; + *self = *self / scale } } @@ -894,7 +852,7 @@ impl DivAssign> for Vector2D { } impl Round for Vector2D { - /// See [`Vector2D::round`]. + /// See [`Vector2D::round()`](#method.round) #[inline] fn round(self) -> Self { self.round() @@ -902,7 +860,7 @@ impl Round for Vector2D { } impl Ceil for Vector2D { - /// See [`Vector2D::ceil`]. + /// See [`Vector2D::ceil()`](#method.ceil) #[inline] fn ceil(self) -> Self { self.ceil() @@ -910,13 +868,14 @@ impl Ceil for Vector2D { } impl Floor for Vector2D { - /// See [`Vector2D::floor`]. + /// See [`Vector2D::floor()`](#method.floor) #[inline] fn floor(self) -> Self { self.floor() } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> ApproxEq> for Vector2D { #[inline] fn approx_epsilon() -> Self { @@ -1019,35 +978,12 @@ where } } -#[cfg(feature = "arbitrary")] -impl<'a, T, U> arbitrary::Arbitrary<'a> for Vector3D -where - T: arbitrary::Arbitrary<'a>, -{ - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let (x, y, z) = arbitrary::Arbitrary::arbitrary(u)?; - Ok(Vector3D { - x, - y, - z, - _unit: PhantomData, - }) - } -} - #[cfg(feature = "bytemuck")] unsafe impl Zeroable for Vector3D {} #[cfg(feature = "bytemuck")] unsafe impl Pod for Vector3D {} -#[cfg(feature = "malloc_size_of")] -impl MallocSizeOf for Vector3D { - fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { - self.x.size_of(ops) + self.y.size_of(ops) + self.z.size_of(ops) - } -} - impl Eq for Vector3D {} impl PartialEq for Vector3D { @@ -1411,6 +1347,7 @@ where } } +#[cfg(any(feature = "std", feature = "libm"))] impl Vector3D { /// Return the normalized vector even if the length is larger than the max value of Float. #[inline] @@ -1425,13 +1362,14 @@ impl Vector3D { } } - /// Returns `true` if all members are finite. + /// Returns true if all members are finite. #[inline] pub fn is_finite(self) -> bool { self.x.is_finite() && self.y.is_finite() && self.z.is_finite() } } +#[cfg(any(feature = "std", feature = "libm"))] impl Vector3D { /// Returns the positive angle between this vector and another vector. /// @@ -1461,7 +1399,7 @@ impl Vector3D { /// Returns the vector with length of one unit. /// - /// Unlike [`Vector2D::normalize`], this returns `None` in the case that the + /// Unlike [`Vector2D::normalize`](#method.normalize), this returns None in the case that the /// length of the vector is zero. #[inline] #[must_use] @@ -1504,6 +1442,39 @@ impl Vector3D { } } +#[cfg(any(feature = "std", feature = "libm"))] +impl Vector2D { + /// Constructor taking angle and length + pub fn from_angle_and_length(angle: Angle, length: T) -> Self + where + T: Trig + Mul + Copy, + { + vec2(length * angle.radians.cos(), length * angle.radians.sin()) + } + + /// Returns the signed angle between this vector and the x axis. + /// Positive values counted counterclockwise, where 0 is `+x` axis, `PI/2` + /// is `+y` axis. + /// + /// The returned angle is between -PI and PI. + pub fn angle_from_x_axis(self) -> Angle + where + T: Trig, + { + Angle::radians(Trig::fast_atan2(self.y, self.x)) + } + + /// Returns the signed angle between this vector and another vector. + /// + /// The returned angle is between -PI and PI. + pub fn angle_to(self, other: Self) -> Angle + where + T: Copy + Add + Sub + Mul + Trig, + { + Angle::radians(Trig::fast_atan2(self.cross(other), self.dot(other))) + } +} + impl Vector3D where T: Copy + One + Add + Sub + Mul, @@ -1666,16 +1637,6 @@ impl Vector3D { self.cast() } - /// Cast into an `isize` vector, truncating decimals if any. - /// - /// When casting from floating vector vectors, it is worth considering whether - /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain - /// the desired conversion behavior. - #[inline] - pub fn to_isize(self) -> Vector3D { - self.cast() - } - /// Cast into an `u32` vector, truncating decimals if any. /// /// When casting from floating vector vectors, it is worth considering whether @@ -1749,7 +1710,7 @@ impl<'a, T: 'a + Add + Copy + Zero, U: 'a> Sum<&'a Self> for Vector3 impl, U> AddAssign for Vector3D { #[inline] fn add_assign(&mut self, other: Self) { - *self = *self + other; + *self = *self + other } } @@ -1765,7 +1726,7 @@ impl Sub for Vector3D { impl, U> SubAssign> for Vector3D { #[inline] fn sub_assign(&mut self, other: Self) { - *self = *self - other; + *self = *self - other } } @@ -1781,7 +1742,7 @@ impl Mul for Vector3D { impl, U> MulAssign for Vector3D { #[inline] fn mul_assign(&mut self, scale: T) { - *self = *self * scale; + *self = *self * scale } } @@ -1815,7 +1776,7 @@ impl Div for Vector3D { impl, U> DivAssign for Vector3D { #[inline] fn div_assign(&mut self, scale: T) { - *self = *self / scale; + *self = *self / scale } } @@ -1838,7 +1799,7 @@ impl DivAssign> for Vector3D { } impl Round for Vector3D { - /// See [`Vector3D::round`]. + /// See [`Vector3D::round()`](#method.round) #[inline] fn round(self) -> Self { self.round() @@ -1846,7 +1807,7 @@ impl Round for Vector3D { } impl Ceil for Vector3D { - /// See [`Vector3D::ceil`]. + /// See [`Vector3D::ceil()`](#method.ceil) #[inline] fn ceil(self) -> Self { self.ceil() @@ -1854,13 +1815,14 @@ impl Ceil for Vector3D { } impl Floor for Vector3D { - /// See [`Vector3D::floor`]. + /// See [`Vector3D::floor()`](#method.floor) #[inline] fn floor(self) -> Self { self.floor() } } +#[cfg(any(feature = "std", feature = "libm"))] impl, U> ApproxEq> for Vector3D { #[inline] fn approx_epsilon() -> Self { @@ -2106,27 +2068,6 @@ impl BoolVector3D { } } -#[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for BoolVector2D { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - Ok(BoolVector2D { - x: arbitrary::Arbitrary::arbitrary(u)?, - y: arbitrary::Arbitrary::arbitrary(u)?, - }) - } -} - -#[cfg(feature = "arbitrary")] -impl<'a> arbitrary::Arbitrary<'a> for BoolVector3D { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - Ok(BoolVector3D { - x: arbitrary::Arbitrary::arbitrary(u)?, - y: arbitrary::Arbitrary::arbitrary(u)?, - z: arbitrary::Arbitrary::arbitrary(u)?, - }) - } -} - /// Convenience constructor. #[inline] pub const fn vec2(x: T, y: T) -> Vector2D { @@ -2161,6 +2102,7 @@ pub const fn bvec3(x: bool, y: bool, z: bool) -> BoolVector3D { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod vector2d { use crate::scale::Scale; use crate::{default, vec2}; @@ -2398,6 +2340,7 @@ mod vector2d { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod vector3d { use crate::scale::Scale; use crate::{default, vec2, vec3}; @@ -2620,6 +2563,7 @@ mod vector3d { } #[cfg(test)] +#[cfg(any(feature = "std", feature = "libm"))] mod bool_vector { use super::*; use crate::default;