Merge pull request #844 from dimforge/cast

@sebcrozet Add "cast" methods to cast the type component types
This commit is contained in:
Sébastien Crozet 2021-03-06 12:19:41 +01:00 committed by GitHub
commit a798d1c4ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 303 additions and 26 deletions

View File

@ -4,6 +4,11 @@ documented here.
This project adheres to [Semantic Versioning](https://semver.org/). This project adheres to [Semantic Versioning](https://semver.org/).
## [0.25.2] - WIP
### Added
- 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::<f32>()`.
## [0.25.1] ## [0.25.1]
This release replaces the version 0.25.0 which has been yanked. The 0.25.0 version 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 added significant complication to build `nalgebra` targeting a `#[no-std]` platform

View File

@ -16,7 +16,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation; use abomonation::Abomonation;
use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field}; use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf};
use simba::simd::SimdPartialOrd; use simba::simd::SimdPartialOrd;
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
@ -610,6 +610,23 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res 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::<f32>();
/// assert_eq!(q2, Vector3::new(1.0f32, 2.0, 3.0));
/// ```
pub fn cast<N2: Scalar>(self) -> MatrixMN<N2, R, C>
where
MatrixMN<N2, R, C>: SupersetOf<Self>,
DefaultAllocator: Allocator<N2, R, C>,
{
crate::convert(self)
}
/// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure. /// 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: /// The initialization closure is given the first component of this matrix:

View File

@ -5,6 +5,7 @@ use crate::{
use num::{One, Zero}; use num::{One, Zero};
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use simba::scalar::SupersetOf;
impl<N: Scalar> DualQuaternion<N> { impl<N: Scalar> DualQuaternion<N> {
/// Creates a dual quaternion from its rotation and translation components. /// Creates a dual quaternion from its rotation and translation components.
@ -49,6 +50,22 @@ impl<N: Scalar> DualQuaternion<N> {
Quaternion::from_real(N::zero()), 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::<f32>();
/// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0)));
/// ```
pub fn cast<To: Scalar>(self) -> DualQuaternion<To>
where
DualQuaternion<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> DualQuaternion<N> impl<N: SimdRealField> DualQuaternion<N>
@ -129,6 +146,22 @@ impl<N: SimdRealField> UnitDualQuaternion<N> {
pub fn identity() -> Self { pub fn identity() -> Self {
Self::new_unchecked(DualQuaternion::identity()) Self::new_unchecked(DualQuaternion::identity())
} }
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::UnitDualQuaternion;
/// let q = UnitDualQuaternion::<f64>::identity();
/// let q2 = q.cast::<f32>();
/// assert_eq!(q2, UnitDualQuaternion::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> UnitDualQuaternion<To>
where
UnitDualQuaternion<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> UnitDualQuaternion<N> impl<N: SimdRealField> UnitDualQuaternion<N>

View File

@ -10,15 +10,16 @@ use rand::{
Rng, Rng,
}; };
use simba::scalar::SupersetOf;
use simba::simd::SimdRealField; use simba::simd::SimdRealField;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, U2}; use crate::base::dimension::{DimName, U2};
use crate::base::{DefaultAllocator, Vector2, Vector3}; use crate::base::{DefaultAllocator, Vector2, Vector3};
use crate::geometry::{ use crate::{
AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point, AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point,
Point3, Rotation, Rotation3, Translation, Translation2, Translation3, UnitComplex, Point3, Rotation, Rotation3, Scalar, Translation, Translation2, Translation3, UnitComplex,
UnitQuaternion, UnitQuaternion,
}; };
@ -153,6 +154,22 @@ where
pub fn rotation(angle: N) -> Self { pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle) Self::new(Vector2::zeros(), angle)
} }
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::IsometryMatrix2;
/// let iso = IsometryMatrix2::<f64>::identity();
/// let iso2 = iso.cast::<f32>();
/// assert_eq!(iso2, IsometryMatrix2::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> IsometryMatrix2<To>
where
IsometryMatrix2<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> Isometry2<N> impl<N: SimdRealField> Isometry2<N>
@ -191,6 +208,22 @@ where
pub fn rotation(angle: N) -> Self { pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle) Self::new(Vector2::zeros(), angle)
} }
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::Isometry2;
/// let iso = Isometry2::<f64>::identity();
/// let iso2 = iso.cast::<f32>();
/// assert_eq!(iso2, Isometry2::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Isometry2<To>
where
Isometry2<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
// 3D rotation. // 3D rotation.
@ -387,6 +420,22 @@ where
N::Element: SimdRealField, N::Element: SimdRealField,
{ {
basic_isometry_construction_impl!(UnitQuaternion<N>); basic_isometry_construction_impl!(UnitQuaternion<N>);
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::Isometry3;
/// let iso = Isometry3::<f64>::identity();
/// let iso2 = iso.cast::<f32>();
/// assert_eq!(iso2, Isometry3::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Isometry3<To>
where
Isometry3<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> IsometryMatrix3<N> impl<N: SimdRealField> IsometryMatrix3<N>
@ -394,6 +443,22 @@ where
N::Element: SimdRealField, N::Element: SimdRealField,
{ {
basic_isometry_construction_impl!(Rotation3<N>); basic_isometry_construction_impl!(Rotation3<N>);
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::IsometryMatrix3;
/// let iso = IsometryMatrix3::<f64>::identity();
/// let iso2 = iso.cast::<f32>();
/// assert_eq!(iso2, IsometryMatrix3::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> IsometryMatrix3<To>
where
IsometryMatrix3<To>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
/// # Construction from a 3D eye position and target point /// # Construction from a 3D eye position and target point

View File

@ -15,7 +15,7 @@ use crate::{
Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, Vector4, Vector5, Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, Vector4, Vector5,
Vector6, Vector6,
}; };
use simba::scalar::ClosedDiv; use simba::scalar::{ClosedDiv, SupersetOf};
use crate::geometry::Point; use crate::geometry::Point;
@ -119,6 +119,23 @@ where
None 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::<f32>();
/// assert_eq!(pt2, Point2::new(1.0f32, 2.0));
/// ```
pub fn cast<To: Scalar>(self) -> Point<To, D>
where
Point<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D>,
{
crate::convert(self)
}
} }
/* /*

View File

@ -13,7 +13,7 @@ use rand::{
use num::{One, Zero}; use num::{One, Zero};
use simba::scalar::RealField; use simba::scalar::{RealField, SupersetOf};
use simba::simd::SimdBool; use simba::simd::SimdBool;
use crate::base::dimension::U3; use crate::base::dimension::U3;
@ -49,6 +49,22 @@ impl<N: Scalar> Quaternion<N> {
pub fn new(w: N, i: N, j: N, k: N) -> Self { pub fn new(w: N, i: N, j: N, k: N) -> Self {
Self::from(Vector4::new(i, j, k, w)) 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::<f32>();
/// assert_eq!(q2, Quaternion::new(1.0f32, 2.0, 3.0, 4.0));
/// ```
pub fn cast<To: Scalar>(self) -> Quaternion<To>
where
To: SupersetOf<N>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> Quaternion<N> { impl<N: SimdRealField> Quaternion<N> {
@ -199,6 +215,23 @@ where
Self::new_unchecked(Quaternion::identity()) 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::<f32>();
/// assert_relative_eq!(q2, UnitQuaternion::from_euler_angles(1.0f32, 2.0, 3.0), epsilon = 1.0e-6);
/// ```
pub fn cast<To: Scalar>(self) -> UnitQuaternion<To>
where
To: SupersetOf<N>,
{
crate::convert(self)
}
/// Creates a new quaternion from a unit vector (the rotation axis) and an angle /// Creates a new quaternion from a unit vector (the rotation axis) and an angle
/// (the rotation angle). /// (the rotation angle).
/// ///

View File

@ -35,8 +35,8 @@ use crate::geometry::{
impl<N1, N2> SubsetOf<Quaternion<N2>> for Quaternion<N1> impl<N1, N2> SubsetOf<Quaternion<N2>> for Quaternion<N1>
where where
N1: SimdRealField, N1: Scalar,
N2: SimdRealField + SupersetOf<N1>, N2: Scalar + SupersetOf<N1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Quaternion<N2> { fn to_superset(&self) -> Quaternion<N2> {
@ -58,8 +58,8 @@ where
impl<N1, N2> SubsetOf<UnitQuaternion<N2>> for UnitQuaternion<N1> impl<N1, N2> SubsetOf<UnitQuaternion<N2>> for UnitQuaternion<N1>
where where
N1: SimdRealField, N1: Scalar,
N2: SimdRealField + SupersetOf<N1>, N2: Scalar + SupersetOf<N1>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> UnitQuaternion<N2> { fn to_superset(&self) -> UnitQuaternion<N2> {

View File

@ -1,6 +1,6 @@
use num::{One, Zero}; use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul}; use simba::scalar::{ClosedAdd, ClosedMul, SupersetOf};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::DimName; use crate::base::dimension::DimName;
@ -31,6 +31,28 @@ where
} }
} }
impl<N: Scalar, D: DimName> Rotation<N, D>
where
DefaultAllocator: Allocator<N, D, D>,
{
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::Rotation2;
/// let rot = Rotation2::<f64>::identity();
/// let rot2 = rot.cast::<f32>();
/// assert_eq!(rot2, Rotation2::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Rotation<To, D>
where
Rotation<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D, D>,
{
crate::convert(self)
}
}
impl<N, D: DimName> One for Rotation<N, D> impl<N, D: DimName> One for Rotation<N, D>
where where
N: Scalar + Zero + One + ClosedAdd + ClosedMul, N: Scalar + Zero + One + ClosedAdd + ClosedMul,

View File

@ -10,15 +10,16 @@ use rand::{
Rng, Rng,
}; };
use simba::scalar::SupersetOf;
use simba::simd::SimdRealField; use simba::simd::SimdRealField;
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, U2, U3}; use crate::base::dimension::{DimName, U2, U3};
use crate::base::{DefaultAllocator, Vector2, Vector3}; use crate::base::{DefaultAllocator, Vector2, Vector3};
use crate::geometry::{ use crate::{
AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Similarity, Translation, AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Scalar, Similarity,
UnitComplex, UnitQuaternion, Translation, UnitComplex, UnitQuaternion,
}; };
impl<N: SimdRealField, D: DimName, R> Similarity<N, D, R> impl<N: SimdRealField, D: DimName, R> Similarity<N, D, R>
@ -158,6 +159,22 @@ where
scaling, scaling,
) )
} }
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::SimilarityMatrix2;
/// let sim = SimilarityMatrix2::<f64>::identity();
/// let sim2 = sim.cast::<f32>();
/// assert_eq!(sim2, SimilarityMatrix2::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Similarity<To, U2, Rotation2<To>>
where
Similarity<To, U2, Rotation2<To>>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
impl<N: SimdRealField> Similarity<N, U2, UnitComplex<N>> impl<N: SimdRealField> Similarity<N, U2, UnitComplex<N>>
@ -184,12 +201,28 @@ where
scaling, scaling,
) )
} }
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::Similarity2;
/// let sim = Similarity2::<f64>::identity();
/// let sim2 = sim.cast::<f32>();
/// assert_eq!(sim2, Similarity2::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Similarity<To, U2, UnitComplex<To>>
where
Similarity<To, U2, UnitComplex<To>>: SupersetOf<Self>,
{
crate::convert(self)
}
} }
// 3D rotation. // 3D rotation.
macro_rules! similarity_construction_impl( macro_rules! similarity_construction_impl(
($Rot: ty) => { ($Rot: ident) => {
impl<N: SimdRealField> Similarity<N, U3, $Rot> impl<N: SimdRealField> Similarity<N, U3, $Rot<N>>
where N::Element: SimdRealField { where N::Element: SimdRealField {
/// Creates a new similarity from a translation, rotation axis-angle, and scaling /// Creates a new similarity from a translation, rotation axis-angle, and scaling
/// factor. /// factor.
@ -219,7 +252,23 @@ macro_rules! similarity_construction_impl(
#[inline] #[inline]
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self pub fn new(translation: Vector3<N>, axisangle: Vector3<N>, scaling: N) -> Self
{ {
Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) Self::from_isometry(Isometry::<_, U3, $Rot<N>>::new(translation, axisangle), scaling)
}
/// Cast the components of `self` to another type.
///
/// # Example
/// ```
/// # use nalgebra::Similarity3;
/// let sim = Similarity3::<f64>::identity();
/// let sim2 = sim.cast::<f32>();
/// assert_eq!(sim2, Similarity3::<f32>::identity());
/// ```
pub fn cast<To: Scalar>(self) -> Similarity<To, U3, $Rot<To>>
where
Similarity<To, U3, $Rot<To>>: SupersetOf<Self>,
{
crate::convert(self)
} }
/// Creates an similarity that corresponds to a scaling factor and a local frame of /// 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<N>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling) Self::from_isometry(Isometry::<_, U3, $Rot<N>>::face_towards(eye, target, up), scaling)
} }
/// Deprecated: Use [SimilarityMatrix3::face_towards] instead. /// Deprecated: Use [SimilarityMatrix3::face_towards] instead.
@ -308,7 +357,7 @@ macro_rules! similarity_construction_impl(
up: &Vector3<N>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::look_at_rh(eye, target, up), scaling) Self::from_isometry(Isometry::<_, U3, $Rot<N>>::look_at_rh(eye, target, up), scaling)
} }
/// Builds a left-handed look-at view matrix including a scaling factor. /// Builds a left-handed look-at view matrix including a scaling factor.
@ -346,11 +395,11 @@ macro_rules! similarity_construction_impl(
up: &Vector3<N>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> Self {
Self::from_isometry(Isometry::<_, _, $Rot>::look_at_lh(eye, target, up), scaling) Self::from_isometry(Isometry::<_, _, $Rot<N>>::look_at_lh(eye, target, up), scaling)
} }
} }
} }
); );
similarity_construction_impl!(Rotation3<N>); similarity_construction_impl!(Rotation3);
similarity_construction_impl!(UnitQuaternion<N>); similarity_construction_impl!(UnitQuaternion);

View File

@ -10,7 +10,7 @@ use rand::{
Rng, Rng,
}; };
use simba::scalar::ClosedAdd; use simba::scalar::{ClosedAdd, SupersetOf};
use crate::base::allocator::Allocator; use crate::base::allocator::Allocator;
use crate::base::dimension::{DimName, U1, U2, U3, U4, U5, U6}; 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; use crate::geometry::Translation;
impl<N: Scalar + Zero, D: DimName> Translation<N, D> impl<N: Scalar, D: DimName> Translation<N, D>
where where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
@ -37,9 +37,29 @@ where
/// assert_eq!(t * p, p); /// assert_eq!(t * p, p);
/// ``` /// ```
#[inline] #[inline]
pub fn identity() -> Translation<N, D> { pub fn identity() -> Translation<N, D>
where
N: Zero,
{
Self::from(VectorN::<N, D>::from_element(N::zero())) Self::from(VectorN::<N, D>::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::<f32>();
/// assert_eq!(tra2, Translation2::new(1.0f32, 2.0));
/// ```
pub fn cast<To: Scalar>(self) -> Translation<To, D>
where
Translation<To, D>: SupersetOf<Self>,
DefaultAllocator: Allocator<To, D>,
{
crate::convert(self)
}
} }
impl<N: Scalar + Zero + ClosedAdd, D: DimName> One for Translation<N, D> impl<N: Scalar + Zero + ClosedAdd, D: DimName> One for Translation<N, D>

View File

@ -12,9 +12,9 @@ use num_complex::Complex;
use crate::base::dimension::{U1, U2}; use crate::base::dimension::{U1, U2};
use crate::base::storage::Storage; 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 crate::geometry::{Rotation2, UnitComplex};
use simba::scalar::RealField; use simba::scalar::{RealField, SupersetOf};
use simba::simd::SimdRealField; use simba::simd::SimdRealField;
/// # Identity /// # Identity
@ -118,6 +118,22 @@ impl<N: SimdRealField> UnitComplex<N>
where where
N::Element: SimdRealField, 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::<f32>();
/// assert_eq!(c2, UnitComplex::new(1.0f32));
/// ```
pub fn cast<To: Scalar>(self) -> UnitComplex<To>
where
UnitComplex<To>: SupersetOf<Self>,
{
crate::convert(self)
}
/// The underlying complex number. /// The underlying complex number.
/// ///
/// Same as `self.as_ref()`. /// Same as `self.as_ref()`.