Repository: bitshifter/glam-rs
Pull request #238 (2021-09-27 08:03:04)

Add `NAN` constants to all types
`Vec2::NAN`, `Mat4::NAN` etc added which fills all values with `f32/f64::NAN`.

This is useful for marking a value as invalid (poisoning).

This is accomplished by having `f32`, `f64` and all private types implement this new trait:

``` rust
pub trait NanConstEx: Sized {
    const NAN: Self;
}
```


Patch:
diff --git a/src/affine2.rs b/src/affine2.rs
index 645226f..ce385bb 100644
--- a/src/affine2.rs
+++ b/src/affine2.rs
@@ -36,6 +36,12 @@ macro_rules! impl_affine2_methods {
                 translation: $column::ZERO,
             };
 
+            /// All NAN:s.
+            pub const NAN: Self = Self {
+                matrix2: $matrix::NAN,
+                translation: $column::NAN,
+            };
+
             /// Creates an affine transform from three column vectors.
             #[inline(always)]
             pub fn from_cols(x_axis: $column, y_axis: $column, z_axis: $column) -> Self {
diff --git a/src/affine3.rs b/src/affine3.rs
index e71c048..75a8452 100644
--- a/src/affine3.rs
+++ b/src/affine3.rs
@@ -39,6 +39,12 @@ macro_rules! impl_affine3_methods {
                 translation: $column::ZERO,
             };
 
+            /// All NAN.
+            pub const NAN: Self = Self {
+                matrix3: $matrix::NAN,
+                translation: $column::NAN,
+            };
+
             /// Creates an affine transform from four column vectors.
             #[inline(always)]
             pub fn from_cols(
diff --git a/src/core/scalar/matrix.rs b/src/core/scalar/matrix.rs
index 7782809..34b0211 100644
--- a/src/core/scalar/matrix.rs
+++ b/src/core/scalar/matrix.rs
@@ -6,7 +6,7 @@ use crate::core::{
             Matrix4x4, MatrixConst,
         },
         projection::ProjectionMatrix,
-        scalar::{FloatEx, NumEx},
+        scalar::{FloatEx, NanConstEx, NumEx},
         vector::*,
     },
 };
@@ -22,6 +22,13 @@ impl<T: NumEx> MatrixConst for Columns2<XY<T>> {
     };
 }
 
+impl<T: NanConstEx> NanConstEx for Columns2<XY<T>> {
+    const NAN: Self = Self {
+        x_axis: XY::NAN,
+        y_axis: XY::NAN,
+    };
+}
+
 impl<T: NumEx> Matrix<T> for Columns2<XY<T>> {}
 
 impl<T: NumEx> Matrix2x2<T, XY<T>> for Columns2<XY<T>> {
@@ -56,6 +63,14 @@ impl<T: NumEx> MatrixConst for Columns3<XYZ<T>> {
     };
 }
 
+impl<T: NanConstEx> NanConstEx for Columns3<XYZ<T>> {
+    const NAN: Self = Self {
+        x_axis: XYZ::NAN,
+        y_axis: XYZ::NAN,
+        z_axis: XYZ::NAN,
+    };
+}
+
 impl<T: NumEx> Matrix<T> for Columns3<XYZ<T>> {}
 
 impl<T: NumEx> Matrix3x3<T, XYZ<T>> for Columns3<XYZ<T>> {
@@ -122,6 +137,14 @@ impl MatrixConst for Columns3<XYZF32A16> {
     };
 }
 
+impl NanConstEx for Columns3<XYZF32A16> {
+    const NAN: Self = Self {
+        x_axis: XYZF32A16::NAN,
+        y_axis: XYZF32A16::NAN,
+        z_axis: XYZF32A16::NAN,
+    };
+}
+
 impl Matrix<f32> for Columns3<XYZF32A16> {}
 
 impl Matrix3x3<f32, XYZF32A16> for Columns3<XYZF32A16> {
@@ -181,6 +204,15 @@ impl<T: NumEx> MatrixConst for Columns4<XYZW<T>> {
     };
 }
 
+impl<T: NanConstEx> NanConstEx for Columns4<XYZW<T>> {
+    const NAN: Self = Self {
+        x_axis: XYZW::NAN,
+        y_axis: XYZW::NAN,
+        z_axis: XYZW::NAN,
+        w_axis: XYZW::NAN,
+    };
+}
+
 impl<T: NumEx> Matrix<T> for Columns4<XYZW<T>> {}
 
 impl<T: NumEx> Matrix4x4<T, XYZW<T>> for Columns4<XYZW<T>> {
diff --git a/src/core/scalar/vector.rs b/src/core/scalar/vector.rs
index f0f2370..94e0131 100644
--- a/src/core/scalar/vector.rs
+++ b/src/core/scalar/vector.rs
@@ -14,6 +14,13 @@ impl<T: NumEx> VectorConst for XY<T> {
     };
 }
 
+impl<T: NanConstEx> NanConstEx for XY<T> {
+    const NAN: Self = Self {
+        x: <T as NanConstEx>::NAN,
+        y: <T as NanConstEx>::NAN,
+    };
+}
+
 impl<T: NumEx> Vector2Const for XY<T> {
     const X: Self = Self {
         x: <T as NumConstEx>::ONE,
@@ -38,6 +45,14 @@ impl<T: NumEx> VectorConst for XYZ<T> {
     };
 }
 
+impl<T: NanConstEx> NanConstEx for XYZ<T> {
+    const NAN: Self = Self {
+        x: <T as NanConstEx>::NAN,
+        y: <T as NanConstEx>::NAN,
+        z: <T as NanConstEx>::NAN,
+    };
+}
+
 impl<T: NumEx> Vector3Const for XYZ<T> {
     const X: Self = Self {
         x: <T as NumConstEx>::ONE,
@@ -70,6 +85,16 @@ impl<T: NumEx> VectorConst for XYZW<T> {
         w: <T as NumConstEx>::ONE,
     };
 }
+
+impl<T: NanConstEx> NanConstEx for XYZW<T> {
+    const NAN: Self = Self {
+        x: <T as NanConstEx>::NAN,
+        y: <T as NanConstEx>::NAN,
+        z: <T as NanConstEx>::NAN,
+        w: <T as NanConstEx>::NAN,
+    };
+}
+
 impl<T: NumEx> Vector4Const for XYZW<T> {
     const X: Self = Self {
         x: <T as NumConstEx>::ONE,
@@ -913,6 +938,14 @@ impl VectorConst for XYZF32A16 {
     };
 }
 
+impl NanConstEx for XYZF32A16 {
+    const NAN: Self = Self {
+        x: f32::NAN,
+        y: f32::NAN,
+        z: f32::NAN,
+    };
+}
+
 impl Vector3Const for XYZF32A16 {
     const X: Self = Self {
         x: 1.0,
diff --git a/src/core/sse2/matrix.rs b/src/core/sse2/matrix.rs
index 780089f..87e8a4c 100644
--- a/src/core/sse2/matrix.rs
+++ b/src/core/sse2/matrix.rs
@@ -13,6 +13,7 @@ use crate::core::{
             Matrix4x4, MatrixConst,
         },
         projection::ProjectionMatrix,
+        scalar::NanConstEx,
         vector::{FloatVector4, Vector, Vector4, Vector4Const},
     },
 };
@@ -23,6 +24,10 @@ impl MatrixConst for __m128 {
     const IDENTITY: __m128 = const_f32x4!([1.0, 0.0, 0.0, 1.0]);
 }
 
+impl NanConstEx for __m128 {
+    const NAN: __m128 = const_f32x4!([f32::NAN; 4]);
+}
+
 impl Matrix<f32> for __m128 {}
 
 impl Matrix2x2<f32, XY<f32>> for __m128 {
@@ -146,6 +151,14 @@ impl MatrixConst for Columns3<__m128> {
     };
 }
 
+impl NanConstEx for Columns3<__m128> {
+    const NAN: Columns3<__m128> = Columns3 {
+        x_axis: __m128::NAN,
+        y_axis: __m128::NAN,
+        z_axis: __m128::NAN,
+    };
+}
+
 impl Matrix<f32> for Columns3<__m128> {}
 
 impl Matrix3x3<f32, __m128> for Columns3<__m128> {
@@ -220,6 +233,15 @@ impl MatrixConst for Columns4<__m128> {
     };
 }
 
+impl NanConstEx for Columns4<__m128> {
+    const NAN: Columns4<__m128> = Columns4 {
+        x_axis: __m128::NAN,
+        y_axis: __m128::NAN,
+        z_axis: __m128::NAN,
+        w_axis: __m128::NAN,
+    };
+}
+
 impl Matrix<f32> for Columns4<__m128> {}
 
 impl Matrix4x4<f32, __m128> for Columns4<__m128> {
diff --git a/src/core/traits/scalar.rs b/src/core/traits/scalar.rs
index f3817d5..1f1f954 100644
--- a/src/core/traits/scalar.rs
+++ b/src/core/traits/scalar.rs
@@ -153,6 +153,10 @@ pub trait FloatConstEx: Sized {
     const HALF: Self;
 }
 
+pub trait NanConstEx: Sized {
+    const NAN: Self;
+}
+
 pub trait NumEx:
     Num
     + NumConstEx
@@ -172,7 +176,7 @@ pub trait NumEx:
 
 pub trait SignedEx: Signed + NumEx {}
 
-pub trait FloatEx: Float + FloatConstEx + SignedEx {
+pub trait FloatEx: Float + FloatConstEx + SignedEx + NanConstEx {
     /// Returns a very close approximation of `self.clamp(-1.0, 1.0).acos()`.
     fn acos_approx(self) -> Self;
     fn from_f32(f: f32) -> Self;
@@ -184,6 +188,10 @@ impl NumConstEx for f32 {
     const ONE: Self = 1.0;
 }
 
+impl NanConstEx for f32 {
+    const NAN: Self = f32::NAN;
+}
+
 impl FloatConstEx for f32 {
     const NEG_ONE: Self = -1.0;
     const TWO: Self = 2.0;
@@ -252,6 +260,10 @@ impl NumConstEx for f64 {
     const ONE: Self = 1.0;
 }
 
+impl NanConstEx for f64 {
+    const NAN: Self = f64::NAN;
+}
+
 impl FloatConstEx for f64 {
     const NEG_ONE: Self = -1.0;
     const TWO: Self = 2.0;
diff --git a/src/core/wasm32/matrix.rs b/src/core/wasm32/matrix.rs
index 29f4612..c5546ba 100644
--- a/src/core/wasm32/matrix.rs
+++ b/src/core/wasm32/matrix.rs
@@ -15,6 +15,7 @@ use crate::core::{
 // v128 as a Matrix2x2
 impl MatrixConst for v128 {
     const ZERO: v128 = const_f32x4!([0.0, 0.0, 0.0, 0.0]);
+    const NAN: v128 = const_f32x4!([f32::NAN; 4]);
     const IDENTITY: v128 = const_f32x4!([1.0, 0.0, 0.0, 1.0]);
 }
 
@@ -128,6 +129,11 @@ impl MatrixConst for Columns3<v128> {
         y_axis: VectorConst::ZERO,
         z_axis: VectorConst::ZERO,
     };
+    const NAN: Columns3<v128> = Columns3 {
+        x_axis: VectorConst::NAN,
+        y_axis: VectorConst::NAN,
+        z_axis: VectorConst::NAN,
+    };
     const IDENTITY: Columns3<v128> = Columns3 {
         x_axis: v128::X,
         y_axis: v128::Y,
@@ -199,6 +205,12 @@ impl MatrixConst for Columns4<v128> {
         z_axis: VectorConst::ZERO,
         w_axis: VectorConst::ZERO,
     };
+    const NAN: Columns4<v128> = Columns4 {
+        x_axis: VectorConst::NAN,
+        y_axis: VectorConst::NAN,
+        z_axis: VectorConst::NAN,
+        w_axis: VectorConst::NAN,
+    };
     const IDENTITY: Columns4<v128> = Columns4 {
         x_axis: v128::X,
         y_axis: v128::Y,
diff --git a/src/core/wasm32/vector.rs b/src/core/wasm32/vector.rs
index 38f3ea1..b13ace2 100644
--- a/src/core/wasm32/vector.rs
+++ b/src/core/wasm32/vector.rs
@@ -148,6 +148,10 @@ impl VectorConst for v128 {
     const ONE: v128 = const_f32x4!([1.0; 4]);
 }
 
+impl NanConstEx for v128 {
+    const NAN: v128 = const_f32x4!([f32::NAN; 4]);
+}
+
 impl Vector3Const for v128 {
     const X: v128 = const_f32x4!([1.0, 0.0, 0.0, 0.0]);
     const Y: v128 = const_f32x4!([0.0, 1.0, 0.0, 0.0]);
diff --git a/src/mat2.rs b/src/mat2.rs
index 422085d..6660153 100644
--- a/src/mat2.rs
+++ b/src/mat2.rs
@@ -32,6 +32,9 @@ macro_rules! impl_mat2_methods {
         /// A 2x2 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
         pub const IDENTITY: Self = Self($inner::IDENTITY);
 
+        /// All NAN:s.
+        pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
+
         /// Creates a 2x2 matrix from two column vectors.
         #[inline(always)]
         pub fn from_cols(x_axis: $vec2, y_axis: $vec2) -> Self {
diff --git a/src/mat3.rs b/src/mat3.rs
index ad11a27..d5db658 100644
--- a/src/mat3.rs
+++ b/src/mat3.rs
@@ -65,6 +65,9 @@ macro_rules! impl_mat3_methods {
         /// elements are `0`.
         pub const IDENTITY: Self = Self($inner::IDENTITY);
 
+        /// All NAN:s.
+        pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
+
         /// Creates a 3x3 matrix from three column vectors.
         #[inline(always)]
         pub fn from_cols(x_axis: $vec3a, y_axis: $vec3a, z_axis: $vec3a) -> Self {
diff --git a/src/mat4.rs b/src/mat4.rs
index f8e3557..5350e9d 100644
--- a/src/mat4.rs
+++ b/src/mat4.rs
@@ -71,6 +71,9 @@ macro_rules! impl_mat4_methods {
         /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
         pub const IDENTITY: Self = Self($inner::IDENTITY);
 
+        /// All NAN:s.
+        pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
+
         /// Creates a 4x4 matrix from four column vectors.
         #[inline(always)]
         pub fn from_cols(x_axis: $vec4, y_axis: $vec4, z_axis: $vec4, w_axis: $vec4) -> Self {
diff --git a/src/quat.rs b/src/quat.rs
index 342afcb..5b5378f 100644
--- a/src/quat.rs
+++ b/src/quat.rs
@@ -35,6 +35,9 @@ macro_rules! impl_quat_methods {
         /// The identity quaternion. Corresponds to no rotation.
         pub const IDENTITY: Self = Self($inner::W);
 
+        /// All NAN:s.
+        pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
+
         /// Creates a new rotation quaternion.
         ///
         /// This should generally not be called manually unless you know what you are doing.
diff --git a/src/transform.rs b/src/transform.rs
index 2a02869..d7b1b66 100644
--- a/src/transform.rs
+++ b/src/transform.rs
@@ -64,6 +64,13 @@ impl TransformSRT {
         translation: Vec3::ZERO,
     };
 
+    /// All NaN:s.
+    pub const NAN: Self = Self {
+        scale: Vec3::NAN,
+        rotation: Quat::NAN,
+        translation: Vec3::NAN,
+    };
+
     #[inline]
     pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
         Self {
@@ -73,6 +80,19 @@ impl TransformSRT {
         }
     }
 
+    /// Returns `true` if, and only if, all elements are finite.
+    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
+    #[inline]
+    pub fn is_finite(&self) -> bool {
+        self.rotation.is_finite() && self.translation.is_finite()
+    }
+
+    /// Returns `true` if, and only if, any element is `NaN`.
+    #[inline]
+    pub fn is_nan(&self) -> bool {
+        self.rotation.is_nan() || self.translation.is_nan()
+    }
+
     #[inline]
     pub fn inverse(&self) -> Self {
         let scale = self.scale.recip();
@@ -205,6 +225,12 @@ impl TransformRT {
         translation: Vec3::ZERO,
     };
 
+    /// All NaN:s.
+    pub const NAN: Self = Self {
+        rotation: Quat::NAN,
+        translation: Vec3::NAN,
+    };
+
     #[inline]
     pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
         Self {
@@ -220,6 +246,7 @@ impl TransformRT {
         self.rotation.is_finite() && self.translation.is_finite()
     }
 
+    /// Returns `true` if, and only if, any element is `NaN`.
     #[inline]
     pub fn is_nan(&self) -> bool {
         self.rotation.is_nan() || self.translation.is_nan()
diff --git a/src/vec.rs b/src/vec.rs
index dfe1a59..f739496 100644
--- a/src/vec.rs
+++ b/src/vec.rs
@@ -1,4 +1,5 @@
 // Adds common vector methods to an impl.
+
 // The methods here should be supported for all types of $t and all sizes of vector.
 macro_rules! impl_vecn_common_methods {
     ($t:ty, $vecn:ident, $mask:ident, $inner:ident, $vectrait:ident) => {
@@ -187,6 +188,9 @@ macro_rules! impl_vecn_float_methods {
     ($t:ty, $vecn:ident, $mask:ident, $inner:ident, $flttrait:ident) => {
         // impl_vecn_signed_methods!($t, $vecn, $mask, $inner, $sgntrait, $vectrait);
 
+        /// All NAN.
+        pub const NAN: Self = Self(<$inner as crate::core::traits::scalar::NanConstEx>::NAN);
+
         /// Returns `true` if, and only if, all elements are finite.  If any element is either
         /// `NaN`, positive or negative infinity, this will return `false`.
         #[inline(always)]


Test patch:
diff --git a/tests/affine2.rs b/tests/affine2.rs
index fd969a3..772d8c0 100644
--- a/tests/affine2.rs
+++ b/tests/affine2.rs
@@ -20,6 +20,11 @@ macro_rules! impl_affine2_tests {
             );
         });
 
+        glam_test!(test_affine2_nan, {
+            assert!($affine2::NAN.is_nan());
+            assert!(!$affine2::NAN.is_finite());
+        });
+
         glam_test!(test_affine2_translation, {
             let translate = $affine2::from_translation($vec2::new(1.0, 2.0));
             assert_eq!(translate.translation, $vec2::new(1.0, 2.0).into());
diff --git a/tests/affine3.rs b/tests/affine3.rs
index a0c51d3..62b4fed 100644
--- a/tests/affine3.rs
+++ b/tests/affine3.rs
@@ -25,6 +25,11 @@ macro_rules! impl_affine3_tests {
             );
         });
 
+        glam_test!(test_affine3_nan, {
+            assert!($affine3::NAN.is_nan());
+            assert!(!$affine3::NAN.is_finite());
+        });
+
         glam_test!(test_affine3_translation, {
             let translate = $affine3::from_translation($vec3::new(1.0, 2.0, 3.0));
             assert_eq!(translate.translation, $vec3::new(1.0, 2.0, 3.0).into());
diff --git a/tests/mat2.rs b/tests/mat2.rs
index 2283a63..42e0a81 100644
--- a/tests/mat2.rs
+++ b/tests/mat2.rs
@@ -29,6 +29,11 @@ macro_rules! impl_mat2_tests {
             assert_eq!($mat2::ZERO, $mat2::from_cols_array(&[0., 0., 0., 0.]));
         });
 
+        glam_test!(test_mat2_nan, {
+            assert!($mat2::NAN.is_nan());
+            assert!(!$mat2::NAN.is_finite());
+        });
+
         glam_test!(test_mat2_accessors, {
             let mut m = $mat2::ZERO;
             m.x_axis = $vec2::new(1.0, 2.0);
diff --git a/tests/mat3.rs b/tests/mat3.rs
index 278cae3..4ef575e 100644
--- a/tests/mat3.rs
+++ b/tests/mat3.rs
@@ -49,6 +49,11 @@ macro_rules! impl_mat3_tests {
             );
         });
 
+        glam_test!(test_mat3_nan, {
+            assert!($mat3::NAN.is_nan());
+            assert!(!$mat3::NAN.is_finite());
+        });
+
         glam_test!(test_mat3_accessors, {
             let mut m = $mat3::ZERO;
             m.x_axis = $newvec3(1.0, 2.0, 3.0);
diff --git a/tests/mat4.rs b/tests/mat4.rs
index c6f3011..2737b2e 100644
--- a/tests/mat4.rs
+++ b/tests/mat4.rs
@@ -82,6 +82,11 @@ macro_rules! impl_mat4_tests {
             );
         });
 
+        glam_test!(test_mat4_nan, {
+            assert!($mat4::NAN.is_nan());
+            assert!(!$mat4::NAN.is_finite());
+        });
+
         glam_test!(test_mat4_accessors, {
             let mut m = $mat4::ZERO;
             m.x_axis = $vec4::new(1.0, 2.0, 3.0, 4.0);
diff --git a/tests/quat.rs b/tests/quat.rs
index 01f082e..cdd393a 100644
--- a/tests/quat.rs
+++ b/tests/quat.rs
@@ -12,6 +12,11 @@ macro_rules! impl_quat_tests {
             assert_eq!($quat::from_xyzw(1.0, 2.0, 3.0, 4.0), Q);
         });
 
+        glam_test!(test_nan, {
+            assert!($quat::NAN.is_nan());
+            assert!(!$quat::NAN.is_finite());
+        });
+
         glam_test!(test_new, {
             let ytheta = deg(45.0);
             let q0 = $quat::from_rotation_y(ytheta);
diff --git a/tests/transform.rs b/tests/transform.rs
index 5ca0c77..e7f7715 100644
--- a/tests/transform.rs
+++ b/tests/transform.rs
@@ -57,6 +57,15 @@ mod transform {
         assert_eq!(TransformSRT::IDENTITY, TransformSRT::default());
     }
 
+    #[test]
+    fn test_nan() {
+        assert!(TransformRT::NAN.is_nan());
+        assert!(!TransformRT::NAN.is_finite());
+
+        assert!(TransformSRT::NAN.is_nan());
+        assert!(!TransformSRT::NAN.is_finite());
+    }
+
     #[test]
     fn test_new() {
         let t = Vec3::new(1.0, 2.0, 3.0);
diff --git a/tests/vec2.rs b/tests/vec2.rs
index 7a6e1c3..c385ed2 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -441,6 +441,11 @@ macro_rules! impl_vec2_float_tests {
             assert_eq!($vec2::Y, $new(0 as $t, 1 as $t));
         });
 
+        glam_test!(test_vec2_nan, {
+            assert!($vec2::NAN.is_nan());
+            assert!(!$vec2::NAN.is_finite());
+        });
+
         glam_test!(test_length, {
             let x = $new(1.0, 0.0);
             let y = $new(0.0, 1.0);
diff --git a/tests/vec3.rs b/tests/vec3.rs
index d29a8c2..c23a7f4 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -478,6 +478,11 @@ macro_rules! impl_vec3_float_tests {
         use core::$t::NAN;
         use core::$t::NEG_INFINITY;
 
+        glam_test!(test_nan, {
+            assert!($vec3::NAN.is_nan());
+            assert!(!$vec3::NAN.is_finite());
+        });
+
         glam_test!(test_vec3_consts, {
             assert_eq!($vec3::ZERO, $new(0 as $t, 0 as $t, 0 as $t));
             assert_eq!($vec3::ONE, $new(1 as $t, 1 as $t, 1 as $t));
diff --git a/tests/vec4.rs b/tests/vec4.rs
index 31ec4db..6a8c960 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -554,6 +554,11 @@ macro_rules! impl_vec4_float_tests {
         use core::$t::NAN;
         use core::$t::NEG_INFINITY;
 
+        glam_test!(test_vec4_nan, {
+            assert!($vec4::NAN.is_nan());
+            assert!(!$vec4::NAN.is_finite());
+        });
+
         glam_test!(test_funcs, {
             let x = $new(1.0, 0.0, 0.0, 0.0);
             let y = $new(0.0, 1.0, 0.0, 0.0);