diff --git a/CHANGELOG.md b/CHANGELOG.md index e65ed971..24450f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.25.2] +### Added +- A `convert-glam` cargo feature to enable implementations of `From` traits to convert + between `glam` types and `nalgebra` types. +- A `convert-glam-unchecked` cargo feature to enable some extra `glam`/`nalgebra` conversions that may + lead to unexpected results if used improperly. For example, this enables the conversion from a + `glam::Mat4` to a `na::Isometry3`. This conversion will be cheap (without any check) but willlead to + unexpected results if the glam matrix contains non-isometric components (like scaling for example). +- A `cast` method has been added to most types. This can be used to change the + type of the components of a given entity. Example: `vector.cast::()`. + ## [0.25.1] This release replaces the version 0.25.0 which has been yanked. The 0.25.0 version added significant complication to build `nalgebra` targeting a `#[no-std]` platform diff --git a/Cargo.toml b/Cargo.toml index ea9a2894..666dbeb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.25.1" +version = "0.25.2" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." @@ -24,11 +24,6 @@ path = "src/lib.rs" [features] default = [ "std" ] std = [ "matrixmultiply", "simba/std" ] -rand-no-std = [ "rand-package" ] -rand = [ "rand-no-std", "rand-package/std", "rand-package/std_rng", "rand_distr" ] -arbitrary = [ "quickcheck" ] -serde-serialize = [ "serde", "num-complex/serde" ] -abomonation-serialize = [ "abomonation" ] sparse = [ ] debug = [ "approx/num-complex", "rand" ] alloc = [ ] @@ -36,11 +31,26 @@ io = [ "pest", "pest_derive" ] compare = [ "matrixcompare-core" ] libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] -proptest-support = [ "proptest" ] no_unsound_assume_init = [ ] -# This feature is only used for tests, and enables tests that require more time to run -slow-tests = [] +# Conversion +convert-mint = [ "mint" ] +convert-glam = [ "glam" ] +convert-glam-unchecked = [ "convert-glam" ] # Unable edgy conversions like Mat4 -> Isometry3 +convert-bytemuck = [ "bytemuck" ] + +# Serialization +serde-serialize = [ "serde", "num-complex/serde" ] +abomonation-serialize = [ "abomonation" ] + +# Randomness +rand-no-std = [ "rand-package" ] +rand = [ "rand-no-std", "rand-package/std", "rand-package/std_rng", "rand_distr" ] + +# Tests +arbitrary = [ "quickcheck" ] +proptest-support = [ "proptest" ] +slow-tests = [] [dependencies] typenum = "1.12" @@ -57,6 +67,7 @@ matrixmultiply = { version = "0.3", optional = true } serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true } abomonation = { version = "0.7", optional = true } mint = { version = "0.5", optional = true } +glam = { version = "0.13", optional = true } quickcheck = { version = "1", optional = true } pest = { version = "2", optional = true } pest_derive = { version = "2", optional = true } diff --git a/src/base/conversion.rs b/src/base/conversion.rs index 8ef1a967..92d3be15 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -1,7 +1,5 @@ #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; -#[cfg(feature = "mint")] -use mint; use simba::scalar::{SubsetOf, SupersetOf}; use std::convert::{AsMut, AsRef, From, Into}; use std::mem; @@ -235,119 +233,6 @@ impl_from_into_asref_2D!( (U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6); ); -#[cfg(feature = "mint")] -macro_rules! impl_from_into_mint_1D( - ($($NRows: ident => $VT:ident [$SZ: expr]);* $(;)*) => {$( - impl From> for MatrixMN - where N: Scalar, - DefaultAllocator: Allocator { - #[inline] - fn from(v: mint::$VT) -> Self { - unsafe { - let mut res = Self::new_uninitialized(); - ptr::copy_nonoverlapping(&v.x, (*res.as_mut_ptr()).data.ptr_mut(), $SZ); - - res.assume_init() - } - } - } - - impl Into> for Matrix - where N: Scalar, - S: ContiguousStorage { - #[inline] - fn into(self) -> mint::$VT { - unsafe { - let mut res: mint::$VT = mem::MaybeUninit::uninit().assume_init(); - ptr::copy_nonoverlapping(self.data.ptr(), &mut res.x, $SZ); - res - } - } - } - - impl AsRef> for Matrix - where N: Scalar, - S: ContiguousStorage { - #[inline] - fn as_ref(&self) -> &mint::$VT { - unsafe { - mem::transmute(self.data.ptr()) - } - } - } - - impl AsMut> for Matrix - where N: Scalar, - S: ContiguousStorageMut { - #[inline] - fn as_mut(&mut self) -> &mut mint::$VT { - unsafe { - mem::transmute(self.data.ptr_mut()) - } - } - } - )*} -); - -// Implement for vectors of dimension 2 .. 4. -#[cfg(feature = "mint")] -impl_from_into_mint_1D!( - U2 => Vector2[2]; - U3 => Vector3[3]; - U4 => Vector4[4]; -); - -#[cfg(feature = "mint")] -macro_rules! impl_from_into_mint_2D( - ($(($NRows: ty, $NCols: ty) => $MV:ident{ $($component:ident),* }[$SZRows: expr]);* $(;)*) => {$( - impl From> for MatrixMN - where N: Scalar, - DefaultAllocator: Allocator { - #[inline] - fn from(m: mint::$MV) -> Self { - unsafe { - let mut res = Self::new_uninitialized(); - let mut ptr = (*res.as_mut_ptr()).data.ptr_mut(); - $( - ptr::copy_nonoverlapping(&m.$component.x, ptr, $SZRows); - ptr = ptr.offset($SZRows); - )* - let _ = ptr; - res.assume_init() - } - } - } - - impl Into> for MatrixMN - where N: Scalar, - DefaultAllocator: Allocator { - #[inline] - fn into(self) -> mint::$MV { - unsafe { - let mut res: mint::$MV = mem::MaybeUninit::uninit().assume_init(); - let mut ptr = self.data.ptr(); - $( - ptr::copy_nonoverlapping(ptr, &mut res.$component.x, $SZRows); - ptr = ptr.offset($SZRows); - )* - let _ = ptr; - res - } - } - } - )*} -); - -// Implement for matrices with shape 2x2 .. 4x4. -#[cfg(feature = "mint")] -impl_from_into_mint_2D!( - (U2, U2) => ColumnMatrix2{x, y}[2]; - (U2, U3) => ColumnMatrix2x3{x, y, z}[2]; - (U3, U3) => ColumnMatrix3{x, y, z}[3]; - (U3, U4) => ColumnMatrix3x4{x, y, z, w}[3]; - (U4, U4) => ColumnMatrix4{x, y, z, w}[4]; -); - impl<'a, N, R, C, RStride, CStride> From> for Matrix> where diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 89d24dcc..ee426227 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -16,7 +16,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field}; +use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf}; use simba::simd::SimdPartialOrd; use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; @@ -610,6 +610,23 @@ impl> Matrix { res } + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let q = Vector3::new(1.0f64, 2.0, 3.0); + /// let q2 = q.cast::(); + /// assert_eq!(q2, Vector3::new(1.0f32, 2.0, 3.0)); + /// ``` + pub fn cast(self) -> MatrixMN + where + MatrixMN: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } + /// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure. /// /// The initialization closure is given the first component of this matrix: diff --git a/src/base/mod.rs b/src/base/mod.rs index 9f08572f..fdfbb5c7 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -22,8 +22,6 @@ mod conversion; mod edition; pub mod indexing; mod matrix; -#[cfg(feature = "alga")] -mod matrix_alga; mod matrix_simba; mod matrix_slice; mod norm; diff --git a/src/geometry/dual_quaternion_construction.rs b/src/geometry/dual_quaternion_construction.rs index 739972a9..047a9a2b 100644 --- a/src/geometry/dual_quaternion_construction.rs +++ b/src/geometry/dual_quaternion_construction.rs @@ -5,6 +5,7 @@ use crate::{ use num::{One, Zero}; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; +use simba::scalar::SupersetOf; impl DualQuaternion { /// Creates a dual quaternion from its rotation and translation components. @@ -49,6 +50,22 @@ impl DualQuaternion { Quaternion::from_real(N::zero()), ) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, DualQuaternion}; + /// let q = DualQuaternion::from_real(Quaternion::new(1.0f64, 2.0, 3.0, 4.0)); + /// let q2 = q.cast::(); + /// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0))); + /// ``` + pub fn cast(self) -> DualQuaternion + where + DualQuaternion: SupersetOf, + { + crate::convert(self) + } } impl DualQuaternion @@ -129,6 +146,22 @@ impl UnitDualQuaternion { pub fn identity() -> Self { Self::new_unchecked(DualQuaternion::identity()) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitDualQuaternion; + /// let q = UnitDualQuaternion::::identity(); + /// let q2 = q.cast::(); + /// assert_eq!(q2, UnitDualQuaternion::::identity()); + /// ``` + pub fn cast(self) -> UnitDualQuaternion + where + UnitDualQuaternion: SupersetOf, + { + crate::convert(self) + } } impl UnitDualQuaternion diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index 00138573..1edf269b 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -10,15 +10,16 @@ use rand::{ Rng, }; +use simba::scalar::SupersetOf; use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U2}; use crate::base::{DefaultAllocator, Vector2, Vector3}; -use crate::geometry::{ +use crate::{ AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point, - Point3, Rotation, Rotation3, Translation, Translation2, Translation3, UnitComplex, + Point3, Rotation, Rotation3, Scalar, Translation, Translation2, Translation3, UnitComplex, UnitQuaternion, }; @@ -153,6 +154,22 @@ where pub fn rotation(angle: N) -> Self { Self::new(Vector2::zeros(), angle) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::IsometryMatrix2; + /// let iso = IsometryMatrix2::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, IsometryMatrix2::::identity()); + /// ``` + pub fn cast(self) -> IsometryMatrix2 + where + IsometryMatrix2: SupersetOf, + { + crate::convert(self) + } } impl Isometry2 @@ -191,6 +208,22 @@ where pub fn rotation(angle: N) -> Self { Self::new(Vector2::zeros(), angle) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Isometry2; + /// let iso = Isometry2::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, Isometry2::::identity()); + /// ``` + pub fn cast(self) -> Isometry2 + where + Isometry2: SupersetOf, + { + crate::convert(self) + } } // 3D rotation. @@ -387,6 +420,22 @@ where N::Element: SimdRealField, { basic_isometry_construction_impl!(UnitQuaternion); + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Isometry3; + /// let iso = Isometry3::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, Isometry3::::identity()); + /// ``` + pub fn cast(self) -> Isometry3 + where + Isometry3: SupersetOf, + { + crate::convert(self) + } } impl IsometryMatrix3 @@ -394,6 +443,22 @@ where N::Element: SimdRealField, { basic_isometry_construction_impl!(Rotation3); + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::IsometryMatrix3; + /// let iso = IsometryMatrix3::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, IsometryMatrix3::::identity()); + /// ``` + pub fn cast(self) -> IsometryMatrix3 + where + IsometryMatrix3: SupersetOf, + { + crate::convert(self) + } } /// # Construction from a 3D eye position and target point diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 5fa8c094..2675817e 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -6,8 +6,6 @@ mod op_macros; mod abstract_rotation; mod point; -#[cfg(feature = "alga")] -mod point_alga; mod point_alias; mod point_construction; mod point_conversion; @@ -16,8 +14,6 @@ mod point_ops; mod point_simba; mod rotation; -#[cfg(feature = "alga")] -mod rotation_alga; mod rotation_alias; mod rotation_construction; mod rotation_conversion; @@ -27,8 +23,6 @@ mod rotation_simba; // TODO: implement Rotation methods. mod rotation_specialization; mod quaternion; -#[cfg(feature = "alga")] -mod quaternion_alga; mod quaternion_construction; mod quaternion_conversion; mod quaternion_coordinates; @@ -36,23 +30,17 @@ mod quaternion_ops; mod quaternion_simba; mod dual_quaternion; -#[cfg(feature = "alga")] -mod dual_quaternion_alga; mod dual_quaternion_construction; mod dual_quaternion_conversion; mod dual_quaternion_ops; mod unit_complex; -#[cfg(feature = "alga")] -mod unit_complex_alga; mod unit_complex_construction; mod unit_complex_conversion; mod unit_complex_ops; mod unit_complex_simba; mod translation; -#[cfg(feature = "alga")] -mod translation_alga; mod translation_alias; mod translation_construction; mod translation_conversion; @@ -61,8 +49,6 @@ mod translation_ops; mod translation_simba; mod isometry; -#[cfg(feature = "alga")] -mod isometry_alga; mod isometry_alias; mod isometry_construction; mod isometry_conversion; @@ -71,8 +57,6 @@ mod isometry_ops; mod isometry_simba; mod similarity; -#[cfg(feature = "alga")] -mod similarity_alga; mod similarity_alias; mod similarity_construction; mod similarity_conversion; @@ -82,8 +66,6 @@ mod similarity_simba; mod swizzle; mod transform; -#[cfg(feature = "alga")] -mod transform_alga; mod transform_alias; mod transform_construction; mod transform_conversion; diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 26ee8a8c..bf88ece0 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -15,7 +15,7 @@ use crate::{ Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, }; -use simba::scalar::ClosedDiv; +use simba::scalar::{ClosedDiv, SupersetOf}; use crate::geometry::Point; @@ -119,6 +119,23 @@ where None } } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Point2; + /// let pt = Point2::new(1.0f64, 2.0); + /// let pt2 = pt.cast::(); + /// assert_eq!(pt2, Point2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> Point + where + Point: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } } /* diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 2723e626..6f3d865b 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -6,23 +6,14 @@ use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::{DefaultAllocator, Matrix, Scalar, VectorN}; -#[cfg(feature = "mint")] -use crate::base::dimension::{U2, U3}; -#[cfg(feature = "mint")] -use crate::base::storage::{Storage, StorageMut}; use crate::geometry::Point; -#[cfg(feature = "mint")] -use mint; -#[cfg(feature = "mint")] -use std::convert::{AsMut, AsRef, From, Into}; + /* * This file provides the following conversions: * ============================================= * * Point -> Point * Point -> Vector (homogeneous) - * - * mint::Point <-> Point */ impl SubsetOf> for Point @@ -80,57 +71,6 @@ where } } -#[cfg(feature = "mint")] -macro_rules! impl_from_into_mint_1D( - ($($NRows: ident => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$( - impl From> for Point - where N: Scalar { - #[inline] - fn from(p: mint::$PT) -> Self { - Self { - coords: VectorN::from(mint::$VT::from(p)), - } - } - } - - impl Into> for Point - where N: Scalar { - #[inline] - fn into(self) -> mint::$PT { - let mint_vec: mint::$VT = self.coords.into(); - mint::$PT::from(mint_vec) - } - } - - impl AsRef> for Point - where N: Scalar { - #[inline] - fn as_ref(&self) -> &mint::$PT { - unsafe { - &*(self.coords.data.ptr() as *const mint::$PT) - } - } - } - - impl AsMut> for Point - where N: Scalar { - #[inline] - fn as_mut(&mut self) -> &mut mint::$PT { - unsafe { - &mut *(self.coords.data.ptr_mut() as *mut mint::$PT) - } - } - } - )*} -); - -// Implement for points of dimension 2, 3. -#[cfg(feature = "mint")] -impl_from_into_mint_1D!( - U2 => Point2, Vector2[2]; - U3 => Point3, Vector3[3]; -); - impl From> for VectorN> where D: DimNameAdd, diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 6b40fe49..89911b91 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -13,7 +13,7 @@ use rand::{ use num::{One, Zero}; -use simba::scalar::RealField; +use simba::scalar::{RealField, SupersetOf}; use simba::simd::SimdBool; use crate::base::dimension::U3; @@ -49,6 +49,22 @@ impl Quaternion { pub fn new(w: N, i: N, j: N, k: N) -> Self { Self::from(Vector4::new(i, j, k, w)) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0f64, 2.0, 3.0, 4.0); + /// let q2 = q.cast::(); + /// assert_eq!(q2, Quaternion::new(1.0f32, 2.0, 3.0, 4.0)); + /// ``` + pub fn cast(self) -> Quaternion + where + To: SupersetOf, + { + crate::convert(self) + } } impl Quaternion { @@ -199,6 +215,23 @@ where Self::new_unchecked(Quaternion::identity()) } + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitQuaternion; + /// # use approx::assert_relative_eq; + /// let q = UnitQuaternion::from_euler_angles(1.0f64, 2.0, 3.0); + /// let q2 = q.cast::(); + /// assert_relative_eq!(q2, UnitQuaternion::from_euler_angles(1.0f32, 2.0, 3.0), epsilon = 1.0e-6); + /// ``` + pub fn cast(self) -> UnitQuaternion + where + To: SupersetOf, + { + crate::convert(self) + } + /// Creates a new quaternion from a unit vector (the rotation axis) and an angle /// (the rotation angle). /// diff --git a/src/geometry/quaternion_conversion.rs b/src/geometry/quaternion_conversion.rs index 2707419e..c8b5c6ed 100644 --- a/src/geometry/quaternion_conversion.rs +++ b/src/geometry/quaternion_conversion.rs @@ -3,9 +3,6 @@ use num::Zero; use simba::scalar::{RealField, SubsetOf, SupersetOf}; use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; -#[cfg(feature = "mint")] -use mint; - use crate::base::dimension::U3; use crate::base::{Matrix3, Matrix4, Scalar, Vector4}; use crate::geometry::{ @@ -26,17 +23,14 @@ use crate::geometry::{ * UnitQuaternion -> Transform * UnitQuaternion -> Matrix (homogeneous) * - * mint::Quaternion <-> Quaternion - * UnitQuaternion -> mint::Quaternion - * * NOTE: * UnitQuaternion -> Quaternion is already provided by: Unit -> T */ impl SubsetOf> for Quaternion where - N1: SimdRealField, - N2: SimdRealField + SupersetOf, + N1: Scalar, + N2: Scalar + SupersetOf, { #[inline] fn to_superset(&self) -> Quaternion { @@ -58,8 +52,8 @@ where impl SubsetOf> for UnitQuaternion where - N1: SimdRealField, - N2: SimdRealField + SupersetOf, + N1: Scalar, + N2: Scalar + SupersetOf, { #[inline] fn to_superset(&self) -> UnitQuaternion { @@ -206,41 +200,6 @@ impl> SubsetOf> for Un } } -#[cfg(feature = "mint")] -impl From> for Quaternion { - fn from(q: mint::Quaternion) -> Self { - Self::new(q.s, q.v.x, q.v.y, q.v.z) - } -} - -#[cfg(feature = "mint")] -impl Into> for Quaternion { - fn into(self) -> mint::Quaternion { - mint::Quaternion { - v: mint::Vector3 { - x: self[0].inlined_clone(), - y: self[1].inlined_clone(), - z: self[2].inlined_clone(), - }, - s: self[3].inlined_clone(), - } - } -} - -#[cfg(feature = "mint")] -impl Into> for UnitQuaternion { - fn into(self) -> mint::Quaternion { - mint::Quaternion { - v: mint::Vector3 { - x: self[0].inlined_clone(), - y: self[1].inlined_clone(), - z: self[2].inlined_clone(), - }, - s: self[3].inlined_clone(), - } - } -} - impl From> for Matrix4 where N::Element: SimdRealField, diff --git a/src/geometry/rotation_construction.rs b/src/geometry/rotation_construction.rs index c351f373..f198fc92 100644 --- a/src/geometry/rotation_construction.rs +++ b/src/geometry/rotation_construction.rs @@ -1,6 +1,6 @@ use num::{One, Zero}; -use simba::scalar::{ClosedAdd, ClosedMul}; +use simba::scalar::{ClosedAdd, ClosedMul, SupersetOf}; use crate::base::allocator::Allocator; use crate::base::dimension::DimName; @@ -31,6 +31,28 @@ where } } +impl Rotation +where + DefaultAllocator: Allocator, +{ + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::::identity(); + /// let rot2 = rot.cast::(); + /// assert_eq!(rot2, Rotation2::::identity()); + /// ``` + pub fn cast(self) -> Rotation + where + Rotation: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } +} + impl One for Rotation where N: Scalar + Zero + One + ClosedAdd + ClosedMul, diff --git a/src/geometry/rotation_conversion.rs b/src/geometry/rotation_conversion.rs index accf9a41..21f5a936 100644 --- a/src/geometry/rotation_conversion.rs +++ b/src/geometry/rotation_conversion.rs @@ -3,9 +3,6 @@ use num::Zero; use simba::scalar::{RealField, SubsetOf, SupersetOf}; use simba::simd::{PrimitiveSimdValue, SimdValue}; -#[cfg(feature = "mint")] -use mint; - use crate::base::allocator::Allocator; use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; use crate::base::{DefaultAllocator, Matrix2, Matrix3, Matrix4, MatrixN, Scalar}; @@ -27,7 +24,6 @@ use crate::geometry::{ * Rotation -> Similarity * Rotation -> Transform * Rotation -> Matrix (homogeneous) - * mint::EulerAngles -> Rotation */ @@ -236,13 +232,6 @@ where } } -#[cfg(feature = "mint")] -impl From> for Rotation3 { - fn from(euler: mint::EulerAngles) -> Self { - Self::from_euler_angles(euler.a, euler.b, euler.c) - } -} - impl From> for Matrix3 { #[inline] fn from(q: Rotation2) -> Self { diff --git a/src/geometry/similarity_construction.rs b/src/geometry/similarity_construction.rs index c24e09b2..4501bdb7 100644 --- a/src/geometry/similarity_construction.rs +++ b/src/geometry/similarity_construction.rs @@ -10,15 +10,16 @@ use rand::{ Rng, }; +use simba::scalar::SupersetOf; use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U2, U3}; use crate::base::{DefaultAllocator, Vector2, Vector3}; -use crate::geometry::{ - AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Similarity, Translation, - UnitComplex, UnitQuaternion, +use crate::{ + AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Scalar, Similarity, + Translation, UnitComplex, UnitQuaternion, }; impl Similarity @@ -158,6 +159,22 @@ where scaling, ) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::SimilarityMatrix2; + /// let sim = SimilarityMatrix2::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, SimilarityMatrix2::::identity()); + /// ``` + pub fn cast(self) -> Similarity> + where + Similarity>: SupersetOf, + { + crate::convert(self) + } } impl Similarity> @@ -184,12 +201,28 @@ where scaling, ) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Similarity2; + /// let sim = Similarity2::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, Similarity2::::identity()); + /// ``` + pub fn cast(self) -> Similarity> + where + Similarity>: SupersetOf, + { + crate::convert(self) + } } // 3D rotation. macro_rules! similarity_construction_impl( - ($Rot: ty) => { - impl Similarity + ($Rot: ident) => { + impl Similarity> where N::Element: SimdRealField { /// Creates a new similarity from a translation, rotation axis-angle, and scaling /// factor. @@ -219,7 +252,23 @@ macro_rules! similarity_construction_impl( #[inline] pub fn new(translation: Vector3, axisangle: Vector3, scaling: N) -> Self { - Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) + Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Similarity3; + /// let sim = Similarity3::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, Similarity3::::identity()); + /// ``` + pub fn cast(self) -> Similarity> + where + Similarity>: SupersetOf, + { + crate::convert(self) } /// Creates an similarity that corresponds to a scaling factor and a local frame of @@ -260,7 +309,7 @@ macro_rules! similarity_construction_impl( up: &Vector3, scaling: N) -> Self { - Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling) } /// Deprecated: Use [SimilarityMatrix3::face_towards] instead. @@ -308,7 +357,7 @@ macro_rules! similarity_construction_impl( up: &Vector3, scaling: N) -> Self { - Self::from_isometry(Isometry::<_, U3, $Rot>::look_at_rh(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, U3, $Rot>::look_at_rh(eye, target, up), scaling) } /// Builds a left-handed look-at view matrix including a scaling factor. @@ -346,11 +395,11 @@ macro_rules! similarity_construction_impl( up: &Vector3, scaling: N) -> Self { - Self::from_isometry(Isometry::<_, _, $Rot>::look_at_lh(eye, target, up), scaling) + Self::from_isometry(Isometry::<_, _, $Rot>::look_at_lh(eye, target, up), scaling) } } } ); -similarity_construction_impl!(Rotation3); -similarity_construction_impl!(UnitQuaternion); +similarity_construction_impl!(Rotation3); +similarity_construction_impl!(UnitQuaternion); diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index 3dd14a34..964cd105 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -10,7 +10,7 @@ use rand::{ Rng, }; -use simba::scalar::ClosedAdd; +use simba::scalar::{ClosedAdd, SupersetOf}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U1, U2, U3, U4, U5, U6}; @@ -18,7 +18,7 @@ use crate::base::{DefaultAllocator, Scalar, VectorN}; use crate::geometry::Translation; -impl Translation +impl Translation where DefaultAllocator: Allocator, { @@ -37,9 +37,29 @@ where /// assert_eq!(t * p, p); /// ``` #[inline] - pub fn identity() -> Translation { + pub fn identity() -> Translation + where + N: Zero, + { Self::from(VectorN::::from_element(N::zero())) } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Translation2; + /// let tra = Translation2::new(1.0f64, 2.0); + /// let tra2 = tra.cast::(); + /// assert_eq!(tra2, Translation2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> Translation + where + Translation: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } } impl One for Translation diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index 21f56562..9a24a57d 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -12,9 +12,9 @@ use num_complex::Complex; use crate::base::dimension::{U1, U2}; use crate::base::storage::Storage; -use crate::base::{Matrix2, Unit, Vector, Vector2}; +use crate::base::{Matrix2, Scalar, Unit, Vector, Vector2}; use crate::geometry::{Rotation2, UnitComplex}; -use simba::scalar::RealField; +use simba::scalar::{RealField, SupersetOf}; use simba::simd::SimdRealField; /// # Identity @@ -118,6 +118,22 @@ impl UnitComplex where N::Element: SimdRealField, { + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let c = UnitComplex::new(1.0f64); + /// let c2 = c.cast::(); + /// assert_eq!(c2, UnitComplex::new(1.0f32)); + /// ``` + pub fn cast(self) -> UnitComplex + where + UnitComplex: SupersetOf, + { + crate::convert(self) + } + /// The underlying complex number. /// /// Same as `self.as_ref()`. diff --git a/src/lib.rs b/src/lib.rs index 14314116..d8f48189 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,7 @@ pub mod linalg; pub mod proptest; #[cfg(feature = "sparse")] pub mod sparse; +mod third_party; pub use crate::base::*; pub use crate::geometry::*; diff --git a/src/geometry/dual_quaternion_alga.rs b/src/third_party/alga/alga_dual_quaternion.rs similarity index 100% rename from src/geometry/dual_quaternion_alga.rs rename to src/third_party/alga/alga_dual_quaternion.rs diff --git a/src/geometry/isometry_alga.rs b/src/third_party/alga/alga_isometry.rs similarity index 100% rename from src/geometry/isometry_alga.rs rename to src/third_party/alga/alga_isometry.rs diff --git a/src/base/matrix_alga.rs b/src/third_party/alga/alga_matrix.rs similarity index 100% rename from src/base/matrix_alga.rs rename to src/third_party/alga/alga_matrix.rs diff --git a/src/geometry/point_alga.rs b/src/third_party/alga/alga_point.rs similarity index 100% rename from src/geometry/point_alga.rs rename to src/third_party/alga/alga_point.rs diff --git a/src/geometry/quaternion_alga.rs b/src/third_party/alga/alga_quaternion.rs similarity index 100% rename from src/geometry/quaternion_alga.rs rename to src/third_party/alga/alga_quaternion.rs diff --git a/src/geometry/rotation_alga.rs b/src/third_party/alga/alga_rotation.rs similarity index 100% rename from src/geometry/rotation_alga.rs rename to src/third_party/alga/alga_rotation.rs diff --git a/src/geometry/similarity_alga.rs b/src/third_party/alga/alga_similarity.rs similarity index 100% rename from src/geometry/similarity_alga.rs rename to src/third_party/alga/alga_similarity.rs diff --git a/src/geometry/transform_alga.rs b/src/third_party/alga/alga_transform.rs similarity index 100% rename from src/geometry/transform_alga.rs rename to src/third_party/alga/alga_transform.rs diff --git a/src/geometry/translation_alga.rs b/src/third_party/alga/alga_translation.rs similarity index 100% rename from src/geometry/translation_alga.rs rename to src/third_party/alga/alga_translation.rs diff --git a/src/geometry/unit_complex_alga.rs b/src/third_party/alga/alga_unit_complex.rs similarity index 100% rename from src/geometry/unit_complex_alga.rs rename to src/third_party/alga/alga_unit_complex.rs diff --git a/src/third_party/alga/mod.rs b/src/third_party/alga/mod.rs new file mode 100644 index 00000000..f8cc3b00 --- /dev/null +++ b/src/third_party/alga/mod.rs @@ -0,0 +1,10 @@ +mod alga_dual_quaternion; +mod alga_isometry; +mod alga_matrix; +mod alga_point; +mod alga_quaternion; +mod alga_rotation; +mod alga_similarity; +mod alga_transform; +mod alga_translation; +mod alga_unit_complex; diff --git a/src/third_party/glam/glam_isometry.rs b/src/third_party/glam/glam_isometry.rs new file mode 100644 index 00000000..52c36e37 --- /dev/null +++ b/src/third_party/glam/glam_isometry.rs @@ -0,0 +1,54 @@ +use crate::{Isometry2, Isometry3}; +use glam::{DMat3, DMat4, Mat3, Mat4}; + +impl From> for Mat3 { + fn from(iso: Isometry2) -> Mat3 { + iso.to_homogeneous().into() + } +} +impl From> for Mat4 { + fn from(iso: Isometry3) -> Mat4 { + iso.to_homogeneous().into() + } +} + +impl From> for DMat3 { + fn from(iso: Isometry2) -> DMat3 { + iso.to_homogeneous().into() + } +} +impl From> for DMat4 { + fn from(iso: Isometry3) -> DMat4 { + iso.to_homogeneous().into() + } +} + +#[cfg(feature = "convert-glam-unchecked")] +mod unchecked { + use crate::{Isometry2, Isometry3, Matrix3, Matrix4}; + use glam::{DMat3, DMat4, Mat3, Mat4}; + + impl From for Isometry2 { + fn from(mat3: Mat3) -> Isometry2 { + crate::convert_unchecked(Matrix3::from(mat3)) + } + } + + impl From for Isometry3 { + fn from(mat4: Mat4) -> Isometry3 { + crate::convert_unchecked(Matrix4::from(mat4)) + } + } + + impl From for Isometry2 { + fn from(mat3: DMat3) -> Isometry2 { + crate::convert_unchecked(Matrix3::from(mat3)) + } + } + + impl From for Isometry3 { + fn from(mat4: DMat4) -> Isometry3 { + crate::convert_unchecked(Matrix4::from(mat4)) + } + } +} diff --git a/src/third_party/glam/glam_matrix.rs b/src/third_party/glam/glam_matrix.rs new file mode 100644 index 00000000..bbb2bd17 --- /dev/null +++ b/src/third_party/glam/glam_matrix.rs @@ -0,0 +1,210 @@ +use crate::storage::Storage; +use crate::{Matrix, Matrix2, Matrix3, Matrix4, Vector, Vector2, Vector3, Vector4, U2, U3, U4}; +use glam::{ + BVec2, BVec3, BVec4, DMat2, DMat3, DMat4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, Mat2, Mat3, + Mat4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4, +}; + +macro_rules! impl_vec_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Vector2<$N> { + #[inline] + fn from(e: $Vec2) -> Vector2<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec2 + where + S: Storage<$N, U2>, + { + #[inline] + fn from(e: Vector<$N, U2, S>) -> $Vec2 { + <$Vec2>::new(e[0], e[1]) + } + } + + impl From<$Vec3> for Vector3<$N> { + #[inline] + fn from(e: $Vec3) -> Vector3<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec3 + where + S: Storage<$N, U3>, + { + #[inline] + fn from(e: Vector<$N, U3, S>) -> $Vec3 { + <$Vec3>::new(e[0], e[1], e[2]) + } + } + + impl From<$Vec4> for Vector4<$N> { + #[inline] + fn from(e: $Vec4) -> Vector4<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec4 + where + S: Storage<$N, U4>, + { + #[inline] + fn from(e: Vector<$N, U4, S>) -> $Vec4 { + <$Vec4>::new(e[0], e[1], e[2], e[3]) + } + } + } +); + +impl_vec_conversion!(f32, Vec2, Vec3, Vec4); +impl_vec_conversion!(f64, DVec2, DVec3, DVec4); +impl_vec_conversion!(i32, IVec2, IVec3, IVec4); +impl_vec_conversion!(u32, UVec2, UVec3, UVec4); +impl_vec_conversion!(bool, BVec2, BVec3, BVec4); + +impl From for Vector3 { + #[inline] + fn from(e: Vec3A) -> Vector3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A +where + S: Storage, +{ + #[inline] + fn from(e: Vector) -> Vec3A { + Vec3A::new(e[0], e[1], e[2]) + } +} + +impl From for Matrix2 { + #[inline] + fn from(e: Mat2) -> Matrix2 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat2 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> Mat2 { + Mat2::from_cols( + Vec2::new(e[(0, 0)], e[(1, 0)]), + Vec2::new(e[(0, 1)], e[(1, 1)]), + ) + } +} + +impl From for Matrix3 { + #[inline] + fn from(e: Mat3) -> Matrix3 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat3 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> Mat3 { + Mat3::from_cols( + Vec3::new(e[(0, 0)], e[(1, 0)], e[(2, 0)]), + Vec3::new(e[(0, 1)], e[(1, 1)], e[(2, 1)]), + Vec3::new(e[(0, 2)], e[(1, 2)], e[(2, 2)]), + ) + } +} + +impl From for Matrix4 { + #[inline] + fn from(e: Mat4) -> Matrix4 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat4 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> Mat4 { + Mat4::from_cols( + Vec4::new(e[(0, 0)], e[(1, 0)], e[(2, 0)], e[(3, 0)]), + Vec4::new(e[(0, 1)], e[(1, 1)], e[(2, 1)], e[(3, 1)]), + Vec4::new(e[(0, 2)], e[(1, 2)], e[(2, 2)], e[(3, 2)]), + Vec4::new(e[(0, 3)], e[(1, 3)], e[(2, 3)], e[(3, 3)]), + ) + } +} + +impl From for Matrix2 { + #[inline] + fn from(e: DMat2) -> Matrix2 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat2 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> DMat2 { + DMat2::from_cols( + DVec2::new(e[(0, 0)], e[(1, 0)]), + DVec2::new(e[(0, 1)], e[(1, 1)]), + ) + } +} + +impl From for Matrix3 { + #[inline] + fn from(e: DMat3) -> Matrix3 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat3 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> DMat3 { + DMat3::from_cols( + DVec3::new(e[(0, 0)], e[(1, 0)], e[(2, 0)]), + DVec3::new(e[(0, 1)], e[(1, 1)], e[(2, 1)]), + DVec3::new(e[(0, 2)], e[(1, 2)], e[(2, 2)]), + ) + } +} + +impl From for Matrix4 { + #[inline] + fn from(e: DMat4) -> Matrix4 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat4 +where + S: Storage, +{ + #[inline] + fn from(e: Matrix) -> DMat4 { + DMat4::from_cols( + DVec4::new(e[(0, 0)], e[(1, 0)], e[(2, 0)], e[(3, 0)]), + DVec4::new(e[(0, 1)], e[(1, 1)], e[(2, 1)], e[(3, 1)]), + DVec4::new(e[(0, 2)], e[(1, 2)], e[(2, 2)], e[(3, 2)]), + DVec4::new(e[(0, 3)], e[(1, 3)], e[(2, 3)], e[(3, 3)]), + ) + } +} diff --git a/src/third_party/glam/glam_point.rs b/src/third_party/glam/glam_point.rs new file mode 100644 index 00000000..823dc806 --- /dev/null +++ b/src/third_party/glam/glam_point.rs @@ -0,0 +1,71 @@ +use crate::{Point2, Point3, Point4}; +use glam::{ + BVec2, BVec3, BVec4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, Vec2, Vec3, + Vec3A, Vec4, +}; + +macro_rules! impl_point_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Point2<$N> { + #[inline] + fn from(e: $Vec2) -> Point2<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec2 { + #[inline] + fn from(e: Point2<$N>) -> $Vec2 { + <$Vec2>::new(e[0], e[1]) + } + } + + impl From<$Vec3> for Point3<$N> { + #[inline] + fn from(e: $Vec3) -> Point3<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec3 { + #[inline] + fn from(e: Point3<$N>) -> $Vec3 { + <$Vec3>::new(e[0], e[1], e[2]) + } + } + + impl From<$Vec4> for Point4<$N> { + #[inline] + fn from(e: $Vec4) -> Point4<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec4 { + #[inline] + fn from(e: Point4<$N>) -> $Vec4 { + <$Vec4>::new(e[0], e[1], e[2], e[3]) + } + } + } +); + +impl_point_conversion!(f32, Vec2, Vec3, Vec4); +impl_point_conversion!(f64, DVec2, DVec3, DVec4); +impl_point_conversion!(i32, IVec2, IVec3, IVec4); +impl_point_conversion!(u32, UVec2, UVec3, UVec4); +impl_point_conversion!(bool, BVec2, BVec3, BVec4); + +impl From for Point3 { + #[inline] + fn from(e: Vec3A) -> Point3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: Point3) -> Vec3A { + Vec3A::new(e[0], e[1], e[2]) + } +} diff --git a/src/third_party/glam/glam_quaternion.rs b/src/third_party/glam/glam_quaternion.rs new file mode 100644 index 00000000..e57b7714 --- /dev/null +++ b/src/third_party/glam/glam_quaternion.rs @@ -0,0 +1,64 @@ +use crate::{Quaternion, UnitQuaternion}; +use glam::{DQuat, Quat}; + +impl From for Quaternion { + #[inline] + fn from(e: Quat) -> Quaternion { + Quaternion::new(e.w, e.x, e.y, e.z) + } +} + +impl From> for Quat { + #[inline] + fn from(e: Quaternion) -> Quat { + Quat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From> for Quat { + #[inline] + fn from(e: UnitQuaternion) -> Quat { + Quat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From for Quaternion { + #[inline] + fn from(e: DQuat) -> Quaternion { + Quaternion::new(e.w, e.x, e.y, e.z) + } +} + +impl From> for DQuat { + #[inline] + fn from(e: Quaternion) -> DQuat { + DQuat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From> for DQuat { + #[inline] + fn from(e: UnitQuaternion) -> DQuat { + DQuat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +#[cfg(feature = "convert-glam-unchecked")] +mod unchecked { + use crate::{Quaternion, UnitQuaternion}; + use glam::{DQuat, Quat}; + + impl From for UnitQuaternion { + #[inline] + fn from(e: Quat) -> UnitQuaternion { + UnitQuaternion::new_unchecked(Quaternion::from(e)) + } + } + + impl From for UnitQuaternion { + #[inline] + fn from(e: DQuat) -> UnitQuaternion { + UnitQuaternion::new_unchecked(Quaternion::from(e)) + } + } +} diff --git a/src/third_party/glam/glam_rotation.rs b/src/third_party/glam/glam_rotation.rs new file mode 100644 index 00000000..2db9f50e --- /dev/null +++ b/src/third_party/glam/glam_rotation.rs @@ -0,0 +1,64 @@ +use crate::{Rotation2, Rotation3, UnitQuaternion}; +use glam::{DMat2, DQuat, Mat2, Quat}; + +impl From> for Mat2 { + #[inline] + fn from(e: Rotation2) -> Mat2 { + e.into_inner().into() + } +} + +impl From> for DMat2 { + #[inline] + fn from(e: Rotation2) -> DMat2 { + e.into_inner().into() + } +} + +impl From> for Quat { + #[inline] + fn from(e: Rotation3) -> Quat { + UnitQuaternion::from(e).into() + } +} + +impl From> for DQuat { + #[inline] + fn from(e: Rotation3) -> DQuat { + UnitQuaternion::from(e).into() + } +} + +#[cfg(feature = "convert-glam-unchecked")] +mod unchecked { + use crate::{Rotation2, Rotation3, UnitQuaternion}; + use glam::{DMat2, DQuat, Mat2, Quat}; + + impl From for Rotation2 { + #[inline] + fn from(e: Mat2) -> Rotation2 { + Rotation2::from_matrix_unchecked(e.into()) + } + } + + impl From for Rotation2 { + #[inline] + fn from(e: DMat2) -> Rotation2 { + Rotation2::from_matrix_unchecked(e.into()) + } + } + + impl From for Rotation3 { + #[inline] + fn from(e: Quat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) + } + } + + impl From for Rotation3 { + #[inline] + fn from(e: DQuat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) + } + } +} diff --git a/src/third_party/glam/glam_similarity.rs b/src/third_party/glam/glam_similarity.rs new file mode 100644 index 00000000..92107074 --- /dev/null +++ b/src/third_party/glam/glam_similarity.rs @@ -0,0 +1,54 @@ +use crate::{Similarity2, Similarity3}; +use glam::{DMat3, DMat4, Mat3, Mat4}; + +impl From> for Mat3 { + fn from(iso: Similarity2) -> Mat3 { + iso.to_homogeneous().into() + } +} +impl From> for Mat4 { + fn from(iso: Similarity3) -> Mat4 { + iso.to_homogeneous().into() + } +} + +impl From> for DMat3 { + fn from(iso: Similarity2) -> DMat3 { + iso.to_homogeneous().into() + } +} +impl From> for DMat4 { + fn from(iso: Similarity3) -> DMat4 { + iso.to_homogeneous().into() + } +} + +#[cfg(feature = "convert-glam-unchecked")] +mod unchecked { + use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; + use glam::{DMat3, DMat4, Mat3, Mat4}; + + impl From for Similarity2 { + fn from(mat3: Mat3) -> Similarity2 { + crate::convert_unchecked(Matrix3::from(mat3)) + } + } + + impl From for Similarity3 { + fn from(mat4: Mat4) -> Similarity3 { + crate::convert_unchecked(Matrix4::from(mat4)) + } + } + + impl From for Similarity2 { + fn from(mat3: DMat3) -> Similarity2 { + crate::convert_unchecked(Matrix3::from(mat3)) + } + } + + impl From for Similarity3 { + fn from(mat4: DMat4) -> Similarity3 { + crate::convert_unchecked(Matrix4::from(mat4)) + } + } +} diff --git a/src/third_party/glam/glam_unit_complex.rs b/src/third_party/glam/glam_unit_complex.rs new file mode 100644 index 00000000..c5d9cc6a --- /dev/null +++ b/src/third_party/glam/glam_unit_complex.rs @@ -0,0 +1,36 @@ +use crate::UnitComplex; +use glam::{DMat2, Mat2}; + +impl From> for Mat2 { + #[inline] + fn from(e: UnitComplex) -> Mat2 { + e.to_rotation_matrix().into_inner().into() + } +} + +impl From> for DMat2 { + #[inline] + fn from(e: UnitComplex) -> DMat2 { + e.to_rotation_matrix().into_inner().into() + } +} + +#[cfg(feature = "convert-glam-unchecked")] +mod unchecked { + use crate::{Rotation2, UnitComplex}; + use glam::{DMat2, Mat2}; + + impl From for UnitComplex { + #[inline] + fn from(e: Mat2) -> UnitComplex { + Rotation2::from_matrix_unchecked(e.into()).into() + } + } + + impl From for UnitComplex { + #[inline] + fn from(e: DMat2) -> UnitComplex { + Rotation2::from_matrix_unchecked(e.into()).into() + } + } +} diff --git a/src/third_party/glam/mod.rs b/src/third_party/glam/mod.rs new file mode 100644 index 00000000..d4f8b643 --- /dev/null +++ b/src/third_party/glam/mod.rs @@ -0,0 +1,7 @@ +mod glam_isometry; +mod glam_matrix; +mod glam_point; +mod glam_quaternion; +mod glam_rotation; +mod glam_similarity; +mod glam_unit_complex; diff --git a/src/third_party/mint/mint_matrix.rs b/src/third_party/mint/mint_matrix.rs new file mode 100644 index 00000000..30800f65 --- /dev/null +++ b/src/third_party/mint/mint_matrix.rs @@ -0,0 +1,117 @@ +use std::convert::{AsMut, AsRef, From, Into}; +use std::mem; +use std::ptr; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{U1, U2, U3, U4}; +use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, Scalar}; + +macro_rules! impl_from_into_mint_1D( + ($($NRows: ident => $VT:ident [$SZ: expr]);* $(;)*) => {$( + impl From> for MatrixMN + where N: Scalar, + DefaultAllocator: Allocator { + #[inline] + fn from(v: mint::$VT) -> Self { + unsafe { + let mut res = Self::new_uninitialized(); + ptr::copy_nonoverlapping(&v.x, (*res.as_mut_ptr()).data.ptr_mut(), $SZ); + + res.assume_init() + } + } + } + + impl Into> for Matrix + where N: Scalar, + S: ContiguousStorage { + #[inline] + fn into(self) -> mint::$VT { + unsafe { + let mut res: mint::$VT = mem::MaybeUninit::uninit().assume_init(); + ptr::copy_nonoverlapping(self.data.ptr(), &mut res.x, $SZ); + res + } + } + } + + impl AsRef> for Matrix + where N: Scalar, + S: ContiguousStorage { + #[inline] + fn as_ref(&self) -> &mint::$VT { + unsafe { + mem::transmute(self.data.ptr()) + } + } + } + + impl AsMut> for Matrix + where N: Scalar, + S: ContiguousStorageMut { + #[inline] + fn as_mut(&mut self) -> &mut mint::$VT { + unsafe { + mem::transmute(self.data.ptr_mut()) + } + } + } + )*} +); + +// Implement for vectors of dimension 2 .. 4. +impl_from_into_mint_1D!( + U2 => Vector2[2]; + U3 => Vector3[3]; + U4 => Vector4[4]; +); + +macro_rules! impl_from_into_mint_2D( + ($(($NRows: ty, $NCols: ty) => $MV:ident{ $($component:ident),* }[$SZRows: expr]);* $(;)*) => {$( + impl From> for MatrixMN + where N: Scalar, + DefaultAllocator: Allocator { + #[inline] + fn from(m: mint::$MV) -> Self { + unsafe { + let mut res = Self::new_uninitialized(); + let mut ptr = (*res.as_mut_ptr()).data.ptr_mut(); + $( + ptr::copy_nonoverlapping(&m.$component.x, ptr, $SZRows); + ptr = ptr.offset($SZRows); + )* + let _ = ptr; + res.assume_init() + } + } + } + + impl Into> for MatrixMN + where N: Scalar, + DefaultAllocator: Allocator { + #[inline] + fn into(self) -> mint::$MV { + unsafe { + let mut res: mint::$MV = mem::MaybeUninit::uninit().assume_init(); + let mut ptr = self.data.ptr(); + $( + ptr::copy_nonoverlapping(ptr, &mut res.$component.x, $SZRows); + ptr = ptr.offset($SZRows); + )* + let _ = ptr; + res + } + } + } + )*} +); + +// Implement for matrices with shape 2x2 .. 4x4. +impl_from_into_mint_2D!( + (U2, U2) => ColumnMatrix2{x, y}[2]; + (U2, U3) => ColumnMatrix2x3{x, y, z}[2]; + (U3, U3) => ColumnMatrix3{x, y, z}[3]; + (U3, U4) => ColumnMatrix3x4{x, y, z, w}[3]; + (U4, U4) => ColumnMatrix4{x, y, z, w}[4]; +); diff --git a/src/third_party/mint/mint_point.rs b/src/third_party/mint/mint_point.rs new file mode 100644 index 00000000..62a2bf77 --- /dev/null +++ b/src/third_party/mint/mint_point.rs @@ -0,0 +1,52 @@ +use crate::base::storage::{Storage, StorageMut}; +use crate::{Point, Scalar, VectorN, U2, U3}; +use std::convert::{AsMut, AsRef}; + +macro_rules! impl_from_into_mint_1D( + ($($NRows: ident => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$( + impl From> for Point + where N: Scalar { + #[inline] + fn from(p: mint::$PT) -> Self { + Self { + coords: VectorN::from(mint::$VT::from(p)), + } + } + } + + impl Into> for Point + where N: Scalar { + #[inline] + fn into(self) -> mint::$PT { + let mint_vec: mint::$VT = self.coords.into(); + mint::$PT::from(mint_vec) + } + } + + impl AsRef> for Point + where N: Scalar { + #[inline] + fn as_ref(&self) -> &mint::$PT { + unsafe { + &*(self.coords.data.ptr() as *const mint::$PT) + } + } + } + + impl AsMut> for Point + where N: Scalar { + #[inline] + fn as_mut(&mut self) -> &mut mint::$PT { + unsafe { + &mut *(self.coords.data.ptr_mut() as *mut mint::$PT) + } + } + } + )*} +); + +// Implement for points of dimension 2, 3. +impl_from_into_mint_1D!( + U2 => Point2, Vector2[2]; + U3 => Point3, Vector3[3]; +); diff --git a/src/third_party/mint/mint_quaternion.rs b/src/third_party/mint/mint_quaternion.rs new file mode 100644 index 00000000..01a1a94c --- /dev/null +++ b/src/third_party/mint/mint_quaternion.rs @@ -0,0 +1,33 @@ +use crate::{Quaternion, Scalar, SimdValue, UnitQuaternion}; + +impl From> for Quaternion { + fn from(q: mint::Quaternion) -> Self { + Self::new(q.s, q.v.x, q.v.y, q.v.z) + } +} + +impl Into> for Quaternion { + fn into(self) -> mint::Quaternion { + mint::Quaternion { + v: mint::Vector3 { + x: self[0].inlined_clone(), + y: self[1].inlined_clone(), + z: self[2].inlined_clone(), + }, + s: self[3].inlined_clone(), + } + } +} + +impl Into> for UnitQuaternion { + fn into(self) -> mint::Quaternion { + mint::Quaternion { + v: mint::Vector3 { + x: self[0].inlined_clone(), + y: self[1].inlined_clone(), + z: self[2].inlined_clone(), + }, + s: self[3].inlined_clone(), + } + } +} diff --git a/src/third_party/mint/mint_rotation.rs b/src/third_party/mint/mint_rotation.rs new file mode 100644 index 00000000..9903da5d --- /dev/null +++ b/src/third_party/mint/mint_rotation.rs @@ -0,0 +1,7 @@ +use crate::{RealField, Rotation3}; + +impl From> for Rotation3 { + fn from(euler: mint::EulerAngles) -> Self { + Self::from_euler_angles(euler.a, euler.b, euler.c) + } +} diff --git a/src/third_party/mint/mod.rs b/src/third_party/mint/mod.rs new file mode 100644 index 00000000..3f326dfe --- /dev/null +++ b/src/third_party/mint/mod.rs @@ -0,0 +1,4 @@ +mod mint_matrix; +mod mint_point; +mod mint_quaternion; +mod mint_rotation; diff --git a/src/third_party/mod.rs b/src/third_party/mod.rs new file mode 100644 index 00000000..ce0fcaad --- /dev/null +++ b/src/third_party/mod.rs @@ -0,0 +1,6 @@ +#[cfg(feature = "alga")] +mod alga; +#[cfg(feature = "glam")] +mod glam; +#[cfg(feature = "mint")] +mod mint;