diff --git a/src/structure.rs b/src/structure.rs index 89dcbfd9..2acaf584 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -273,6 +273,9 @@ where } /// Returns a vector with the same direction, but with a magnitude of `1`. + /// + /// If a vector with magnitude zero is passed in this will return a `NaN` vector. If you do not + /// want this then use `InnerSpace::checked_normalize` instead. #[inline] fn normalize(self) -> Self where @@ -282,6 +285,9 @@ where } /// Returns a vector with the same direction and a given magnitude. + /// + /// If a vector with magnitude zero is passed in this will return a `NaN` vector. If you do not + /// want this then use `InnerSpace::checked_normalize_to` instead. #[inline] fn normalize_to(self, magnitude: Self::Scalar) -> Self where @@ -289,6 +295,38 @@ where { self * (magnitude / self.magnitude()) } + + /// Returns a vector with the same direction, but with a magnitude of `1` unless the vector is + /// zero in which case it will return zero. + /// + /// Same as `InnerSpace::normalize` except when `Zero::is_zero` is true. + #[inline] + fn checked_normalize(self) -> Self + where + Self::Scalar: Float, + { + if self.is_zero() { + self + } else { + self.normalize() + } + } + + /// Returns a vector with the same direction and a given magnitude unless the vector is + /// zero in which case it will return zero. + /// + /// Same as `InnerSpace::normalize_to` except when `Zero::is_zero` is true. + #[inline] + fn checked_normalize_to(self, magnitude: Self::Scalar) -> Self + where + Self::Scalar: Float, + { + if self.is_zero() { + self + } else { + self.normalize_to(magnitude) + } + } } /// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) diff --git a/tests/vector.rs b/tests/vector.rs index e6029320..bc9a0c29 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -319,6 +319,34 @@ fn test_normalize() { ); } +#[test] +fn test_checked_normalize() { + assert_ulps_eq!( + Vector2::new(0.0f64, 0.0f64).checked_normalize(), + Vector2::new(0.0f64, 0.0f64) + ); + assert_ulps_eq!( + Vector3::new(0.0f64, 0.0f64, 0.0f64).checked_normalize(), + Vector3::new(0.0f64, 0.0f64, 0.0f64) + ); + assert_ulps_eq!( + Vector4::new(0.0f64, 0.0f64, 0.0f64, 0.0f64).checked_normalize(), + Vector4::new(0.0f64, 0.0f64, 0.0f64, 0.0f64) + ); + assert_ulps_eq!( + Vector2::new(5.0f64, 12.0f64).checked_normalize(), + Vector2::new(5.0 / 13.0, 12.0 / 13.0) + ); + assert_ulps_eq!( + Vector3::new(4.0f64, 4.0f64, 7.0f64).checked_normalize(), + Vector3::new(4.0 / 9.0, 4.0 / 9.0, 7.0 / 9.0) + ); + assert_ulps_eq!( + Vector4::new(1.0f64, 3.0f64, 5.0f64, 17.0f64).checked_normalize(), + Vector4::new(1.0 / 18.0, 3.0 / 18.0, 5.0 / 18.0, 17.0 / 18.0) + ); +} + #[test] fn test_project_on() { assert_ulps_eq!(