diff --git a/src/matrix.rs b/src/matrix.rs index c960064..c5606d1 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -106,6 +106,11 @@ impl Matrix2 { Matrix2::new(c, s, -s, c) } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.x.is_finite() && self.y.is_finite() + } } impl Matrix3 { @@ -205,6 +210,11 @@ impl Matrix3 { _1subc * axis.z * axis.z + c, ) } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } } impl Matrix4 { @@ -357,6 +367,11 @@ impl Matrix4 { S::zero(), S::zero(), S::zero(), S::one(), ) } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.w.is_finite() && self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } } impl Zero for Matrix2 { diff --git a/src/point.rs b/src/point.rs index df5a299..980d496 100644 --- a/src/point.rs +++ b/src/point.rs @@ -118,6 +118,10 @@ macro_rules! impl_point { fn product(self) -> S where S: Mul { fold_array!(mul, { $(self.$field),+ }) } + + fn is_finite(&self) -> bool where S: BaseFloat { + $(self.$field.is_finite())&&+ + } } impl $PointN { diff --git a/src/quaternion.rs b/src/quaternion.rs index fb07ae4..8723785 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -173,6 +173,10 @@ impl Quaternion { (self * scale1 + other * scale2) * Rad::sin(theta).recip() } } + + pub fn is_finite(&self) -> bool { + self.s.is_finite() && self.v.is_finite() + } } impl Zero for Quaternion { diff --git a/src/structure.rs b/src/structure.rs index d165fa1..75eadeb 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -87,6 +87,11 @@ where fn product(self) -> Self::Element where Self::Element: Mul::Element>; + + /// Whether all elements of the array are finite + fn is_finite(&self) -> bool + where + Self::Element: BaseFloat; } /// Element-wise arithmetic operations. These are supplied for pragmatic diff --git a/src/vector.rs b/src/vector.rs index 108792a..055c7e0 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -163,6 +163,10 @@ macro_rules! impl_vector { fn product(self) -> S where S: Mul { fold_array!(mul, { $(self.$field),+ }) } + + fn is_finite(&self) -> bool where S: BaseFloat { + $(self.$field.is_finite())&&+ + } } impl Zero for $VectorN { @@ -353,6 +357,13 @@ macro_rules! impl_vector_default { $VectorN::new($($field),+) } + impl $VectorN { + /// True if all entries in the vector are finite + pub fn is_finite(&self) -> bool { + $(self.$field.is_finite())&&+ + } + } + impl $VectorN { /// Component-wise casting to another type. #[inline] @@ -398,6 +409,10 @@ macro_rules! impl_vector_default { fn product(self) -> S where S: Mul { fold_array!(mul, { $(self.$field),+ }) } + + fn is_finite(&self) -> bool where S: BaseFloat { + $(self.$field.is_finite())&&+ + } } impl Zero for $VectorN { @@ -1323,6 +1338,14 @@ mod tests { assert_eq!(v, &VECTOR2); } } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector2::from([Float::nan(), 1.0]).is_finite()); + assert!(!Vector2::from([1.0, Float::infinity()]).is_finite()); + assert!(Vector2::from([-1.0, 1.0]).is_finite()); + } } mod vector3 { @@ -1428,6 +1451,14 @@ mod tests { assert_eq!(v, &VECTOR3); } } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector3::from([Float::nan(), 1.0, 1.0]).is_finite()); + assert!(!Vector3::from([1.0, 1.0, Float::infinity()]).is_finite()); + assert!(Vector3::from([-1.0, 1.0, 1.0]).is_finite()); + } } mod vector4 { @@ -1539,5 +1570,13 @@ mod tests { assert_eq!(v, &VECTOR4); } } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector4::from([0.0, Float::nan(), 1.0, 1.0]).is_finite()); + assert!(!Vector4::from([1.0, 1.0, Float::neg_infinity(), 0.0]).is_finite()); + assert!(Vector4::from([-1.0, 0.0, 1.0, 1.0]).is_finite()); + } } }