forked from M-Labs/nalgebra
commit
e05bfe48b3
@ -48,6 +48,14 @@ mod translation_coordinates;
|
||||
mod translation_ops;
|
||||
mod translation_simba;
|
||||
|
||||
mod scale;
|
||||
mod scale_alias;
|
||||
mod scale_construction;
|
||||
mod scale_conversion;
|
||||
mod scale_coordinates;
|
||||
mod scale_ops;
|
||||
mod scale_simba;
|
||||
|
||||
mod isometry;
|
||||
mod isometry_alias;
|
||||
mod isometry_construction;
|
||||
@ -95,6 +103,9 @@ pub use self::unit_complex::*;
|
||||
pub use self::translation::*;
|
||||
pub use self::translation_alias::*;
|
||||
|
||||
pub use self::scale::*;
|
||||
pub use self::scale_alias::*;
|
||||
|
||||
pub use self::isometry::*;
|
||||
pub use self::isometry_alias::*;
|
||||
|
||||
|
450
src/geometry/scale.rs
Executable file
450
src/geometry/scale.rs
Executable file
@ -0,0 +1,450 @@
|
||||
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||
use num::{One, Zero};
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
#[cfg(feature = "abomonation-serialize")]
|
||||
use std::io::{Result as IOResult, Write};
|
||||
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[cfg(feature = "abomonation-serialize")]
|
||||
use abomonation::Abomonation;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::storage::Owned;
|
||||
use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar};
|
||||
use crate::ClosedDiv;
|
||||
use crate::ClosedMul;
|
||||
|
||||
use crate::geometry::Point;
|
||||
|
||||
/// A scale which supports non-uniform scaling.
|
||||
#[repr(C)]
|
||||
pub struct Scale<T, const D: usize> {
|
||||
/// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is
|
||||
/// scaled.
|
||||
pub vector: SVector<T, D>,
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, const D: usize> fmt::Debug for Scale<T, D> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
self.vector.as_slice().fmt(formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Scale<T, D>
|
||||
where
|
||||
Owned<T, Const<D>>: hash::Hash,
|
||||
{
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.vector.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + Copy, const D: usize> Copy for Scale<T, D> {}
|
||||
|
||||
impl<T: Scalar, const D: usize> Clone for Scale<T, D>
|
||||
where
|
||||
Owned<T, Const<D>>: Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Scale::from(self.vector.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bytemuck")]
|
||||
unsafe impl<T, const D: usize> bytemuck::Zeroable for Scale<T, D>
|
||||
where
|
||||
T: Scalar + bytemuck::Zeroable,
|
||||
SVector<T, D>: bytemuck::Zeroable,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "bytemuck")]
|
||||
unsafe impl<T, const D: usize> bytemuck::Pod for Scale<T, D>
|
||||
where
|
||||
T: Scalar + bytemuck::Pod,
|
||||
SVector<T, D>: bytemuck::Pod,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "abomonation-serialize")]
|
||||
impl<T, const D: usize> Abomonation for Scale<T, D>
|
||||
where
|
||||
T: Scalar,
|
||||
SVector<T, D>: Abomonation,
|
||||
{
|
||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||
self.vector.entomb(writer)
|
||||
}
|
||||
|
||||
fn extent(&self) -> usize {
|
||||
self.vector.extent()
|
||||
}
|
||||
|
||||
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
|
||||
self.vector.exhume(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
impl<T: Scalar, const D: usize> Serialize for Scale<T, D>
|
||||
where
|
||||
Owned<T, Const<D>>: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.vector.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-serialize-no-std")]
|
||||
impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Scale<T, D>
|
||||
where
|
||||
Owned<T, Const<D>>: Deserialize<'a>,
|
||||
{
|
||||
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
|
||||
where
|
||||
Des: Deserializer<'a>,
|
||||
{
|
||||
let matrix = SVector::<T, D>::deserialize(deserializer)?;
|
||||
|
||||
Ok(Scale::from(matrix))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv-serialize-no-std")]
|
||||
mod rkyv_impl {
|
||||
use super::Scale;
|
||||
use crate::base::SVector;
|
||||
use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
|
||||
|
||||
impl<T: Archive, const D: usize> Archive for Scale<T, D> {
|
||||
type Archived = Scale<T::Archived, D>;
|
||||
type Resolver = <SVector<T, D> as Archive>::Resolver;
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
pos: usize,
|
||||
resolver: Self::Resolver,
|
||||
out: &mut core::mem::MaybeUninit<Self::Archived>,
|
||||
) {
|
||||
self.vector.resolve(
|
||||
pos + offset_of!(Self::Archived, vector),
|
||||
resolver,
|
||||
project_struct!(out: Self::Archived => vector),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S> for Scale<T, D> {
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
self.vector.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Archive, _D: Fallible + ?Sized, const D: usize> Deserialize<Scale<T, D>, _D>
|
||||
for Scale<T::Archived, D>
|
||||
where
|
||||
T::Archived: Deserialize<T, _D>,
|
||||
{
|
||||
fn deserialize(&self, deserializer: &mut _D) -> Result<Scale<T, D>, _D::Error> {
|
||||
Ok(Scale {
|
||||
vector: self.vector.deserialize(deserializer)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar, const D: usize> Scale<T, D> {
|
||||
/// Inverts `self`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale2, Scale3};
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// assert_eq!(t * t.try_inverse().unwrap(), Scale3::identity());
|
||||
/// assert_eq!(t.try_inverse().unwrap() * t, Scale3::identity());
|
||||
///
|
||||
/// // Work in all dimensions.
|
||||
/// let t = Scale2::new(1.0, 2.0);
|
||||
/// assert_eq!(t * t.try_inverse().unwrap(), Scale2::identity());
|
||||
/// assert_eq!(t.try_inverse().unwrap() * t, Scale2::identity());
|
||||
///
|
||||
/// // Returns None if any coordinate is 0.
|
||||
/// let t = Scale2::new(0.0, 2.0);
|
||||
/// assert_eq!(t.try_inverse(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "Did you mean to use try_inverse_mut()?"]
|
||||
pub fn try_inverse(&self) -> Option<Scale<T, D>>
|
||||
where
|
||||
T: ClosedDiv + One + Zero,
|
||||
{
|
||||
for i in 0..D {
|
||||
if self.vector[i] == T::zero() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
return Some(self.vector.map(|e| T::one() / e).into());
|
||||
}
|
||||
|
||||
/// Inverts `self`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale2, Scale3};
|
||||
///
|
||||
/// unsafe {
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// assert_eq!(t * t.inverse_unchecked(), Scale3::identity());
|
||||
/// assert_eq!(t.inverse_unchecked() * t, Scale3::identity());
|
||||
///
|
||||
/// // Work in all dimensions.
|
||||
/// let t = Scale2::new(1.0, 2.0);
|
||||
/// assert_eq!(t * t.inverse_unchecked(), Scale2::identity());
|
||||
/// assert_eq!(t.inverse_unchecked() * t, Scale2::identity());
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub unsafe fn inverse_unchecked(&self) -> Scale<T, D>
|
||||
where
|
||||
T: ClosedDiv + One,
|
||||
{
|
||||
return self.vector.map(|e| T::one() / e).into();
|
||||
}
|
||||
|
||||
/// Inverts `self`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale2, Scale3};
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// assert_eq!(t * t.pseudo_inverse(), Scale3::identity());
|
||||
/// assert_eq!(t.pseudo_inverse() * t, Scale3::identity());
|
||||
///
|
||||
/// // Work in all dimensions.
|
||||
/// let t = Scale2::new(1.0, 2.0);
|
||||
/// assert_eq!(t * t.pseudo_inverse(), Scale2::identity());
|
||||
/// assert_eq!(t.pseudo_inverse() * t, Scale2::identity());
|
||||
///
|
||||
/// // Inverts only non-zero coordinates.
|
||||
/// let t = Scale2::new(0.0, 2.0);
|
||||
/// assert_eq!(t * t.pseudo_inverse(), Scale2::new(0.0, 1.0));
|
||||
/// assert_eq!(t.pseudo_inverse() * t, Scale2::new(0.0, 1.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn pseudo_inverse(&self) -> Scale<T, D>
|
||||
where
|
||||
T: ClosedDiv + One + Zero,
|
||||
{
|
||||
return self
|
||||
.vector
|
||||
.map(|e| {
|
||||
if e != T::zero() {
|
||||
T::one() / e
|
||||
} else {
|
||||
T::zero()
|
||||
}
|
||||
})
|
||||
.into();
|
||||
}
|
||||
|
||||
/// Converts this Scale into its equivalent homogeneous transformation matrix.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale2, Scale3, Matrix3, Matrix4};
|
||||
/// let t = Scale3::new(10.0, 20.0, 30.0);
|
||||
/// let expected = Matrix4::new(10.0, 0.0, 0.0, 0.0,
|
||||
/// 0.0, 20.0, 0.0, 0.0,
|
||||
/// 0.0, 0.0, 30.0, 0.0,
|
||||
/// 0.0, 0.0, 0.0, 1.0);
|
||||
/// assert_eq!(t.to_homogeneous(), expected);
|
||||
///
|
||||
/// let t = Scale2::new(10.0, 20.0);
|
||||
/// let expected = Matrix3::new(10.0, 0.0, 0.0,
|
||||
/// 0.0, 20.0, 0.0,
|
||||
/// 0.0, 0.0, 1.0);
|
||||
/// assert_eq!(t.to_homogeneous(), expected);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
where
|
||||
T: Zero + One + Clone,
|
||||
Const<D>: DimNameAdd<U1>,
|
||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
+ Allocator<T, DimNameSum<Const<D>, U1>, U1>,
|
||||
{
|
||||
// TODO: use self.vector.push() instead. We can’t right now because
|
||||
// that would require the DimAdd bound (but here we use DimNameAdd).
|
||||
// This should be fixable once Rust gets a more complete support of
|
||||
// const-generics.
|
||||
let mut v = OVector::from_element(T::one());
|
||||
for i in 0..D {
|
||||
v[i] = self.vector[i].clone();
|
||||
}
|
||||
return OMatrix::from_diagonal(&v);
|
||||
}
|
||||
|
||||
/// Inverts `self` in-place.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale2, Scale3};
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// let mut inv_t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// assert!(inv_t.try_inverse_mut());
|
||||
/// assert_eq!(t * inv_t, Scale3::identity());
|
||||
/// assert_eq!(inv_t * t, Scale3::identity());
|
||||
///
|
||||
/// // Work in all dimensions.
|
||||
/// let t = Scale2::new(1.0, 2.0);
|
||||
/// let mut inv_t = Scale2::new(1.0, 2.0);
|
||||
/// assert!(inv_t.try_inverse_mut());
|
||||
/// assert_eq!(t * inv_t, Scale2::identity());
|
||||
/// assert_eq!(inv_t * t, Scale2::identity());
|
||||
///
|
||||
/// // Does not perform any operation if a coordinate is 0.
|
||||
/// let mut t = Scale2::new(0.0, 2.0);
|
||||
/// assert!(!t.try_inverse_mut());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_inverse_mut(&mut self) -> bool
|
||||
where
|
||||
T: ClosedDiv + One + Zero,
|
||||
{
|
||||
if let Some(v) = self.try_inverse() {
|
||||
self.vector = v.vector;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + ClosedMul, const D: usize> Scale<T, D> {
|
||||
/// Translate the given point.
|
||||
///
|
||||
/// This is the same as the multiplication `self * pt`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale3, Point3};
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0));
|
||||
/// assert_eq!(transformed_point, Point3::new(4.0, 10.0, 18.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
|
||||
self * pt
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + ClosedDiv + ClosedMul + One + Zero, const D: usize> Scale<T, D> {
|
||||
/// Translate the given point by the inverse of this Scale.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Scale3, Point3};
|
||||
/// let t = Scale3::new(1.0, 2.0, 3.0);
|
||||
/// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)).unwrap();
|
||||
/// assert_eq!(transformed_point, Point3::new(4.0, 3.0, 2.0));
|
||||
///
|
||||
/// // Returns None if the inverse doesn't exist.
|
||||
/// let t = Scale3::new(1.0, 0.0, 3.0);
|
||||
/// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0));
|
||||
/// assert_eq!(transformed_point, None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn try_inverse_transform_point(&self, pt: &Point<T, D>) -> Option<Point<T, D>> {
|
||||
self.try_inverse().map(|s| s * pt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + Eq, const D: usize> Eq for Scale<T, D> {}
|
||||
|
||||
impl<T: Scalar + PartialEq, const D: usize> PartialEq for Scale<T, D> {
|
||||
#[inline]
|
||||
fn eq(&self, right: &Scale<T, D>) -> bool {
|
||||
self.vector == right.vector
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Scale<T, D>
|
||||
where
|
||||
T::Epsilon: Clone,
|
||||
{
|
||||
type Epsilon = T::Epsilon;
|
||||
|
||||
#[inline]
|
||||
fn default_epsilon() -> Self::Epsilon {
|
||||
T::default_epsilon()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
|
||||
self.vector.abs_diff_eq(&other.vector, epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Scale<T, D>
|
||||
where
|
||||
T::Epsilon: Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn default_max_relative() -> Self::Epsilon {
|
||||
T::default_max_relative()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn relative_eq(
|
||||
&self,
|
||||
other: &Self,
|
||||
epsilon: Self::Epsilon,
|
||||
max_relative: Self::Epsilon,
|
||||
) -> bool {
|
||||
self.vector
|
||||
.relative_eq(&other.vector, epsilon, max_relative)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Scale<T, D>
|
||||
where
|
||||
T::Epsilon: Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn default_max_ulps() -> u32 {
|
||||
T::default_max_ulps()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
|
||||
self.vector.ulps_eq(&other.vector, epsilon, max_ulps)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Display
|
||||
*
|
||||
*/
|
||||
impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Scale<T, D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let precision = f.precision().unwrap_or(3);
|
||||
|
||||
writeln!(f, "Scale {{")?;
|
||||
write!(f, "{:.*}", precision, self.vector)?;
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
19
src/geometry/scale_alias.rs
Normal file
19
src/geometry/scale_alias.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::geometry::Scale;
|
||||
|
||||
/// A 1-dimensional scale.
|
||||
pub type Scale1<T> = Scale<T, 1>;
|
||||
|
||||
/// A 2-dimensional scale.
|
||||
pub type Scale2<T> = Scale<T, 2>;
|
||||
|
||||
/// A 3-dimensional scale.
|
||||
pub type Scale3<T> = Scale<T, 3>;
|
||||
|
||||
/// A 4-dimensional scale.
|
||||
pub type Scale4<T> = Scale<T, 4>;
|
||||
|
||||
/// A 5-dimensional scale.
|
||||
pub type Scale5<T> = Scale<T, 5>;
|
||||
|
||||
/// A 6-dimensional scale.
|
||||
pub type Scale6<T> = Scale<T, 6>;
|
123
src/geometry/scale_construction.rs
Normal file
123
src/geometry/scale_construction.rs
Normal file
@ -0,0 +1,123 @@
|
||||
#[cfg(feature = "arbitrary")]
|
||||
use crate::base::storage::Owned;
|
||||
#[cfg(feature = "arbitrary")]
|
||||
use quickcheck::{Arbitrary, Gen};
|
||||
|
||||
use num::One;
|
||||
#[cfg(feature = "rand-no-std")]
|
||||
use rand::{
|
||||
distributions::{Distribution, Standard},
|
||||
Rng,
|
||||
};
|
||||
|
||||
use simba::scalar::{ClosedMul, SupersetOf};
|
||||
|
||||
use crate::base::{SVector, Scalar};
|
||||
use crate::geometry::Scale;
|
||||
|
||||
impl<T: Scalar, const D: usize> Scale<T, D> {
|
||||
/// Creates a new identity scale.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::{Point2, Point3, Scale2, Scale3};
|
||||
/// let t = Scale2::identity();
|
||||
/// let p = Point2::new(1.0, 2.0);
|
||||
/// assert_eq!(t * p, p);
|
||||
///
|
||||
/// // Works in all dimensions.
|
||||
/// let t = Scale3::identity();
|
||||
/// let p = Point3::new(1.0, 2.0, 3.0);
|
||||
/// assert_eq!(t * p, p);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn identity() -> Scale<T, D>
|
||||
where
|
||||
T: One,
|
||||
{
|
||||
Scale::from(SVector::from_element(T::one()))
|
||||
}
|
||||
|
||||
/// Cast the components of `self` to another type.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use nalgebra::Scale2;
|
||||
/// let tra = Scale2::new(1.0f64, 2.0);
|
||||
/// let tra2 = tra.cast::<f32>();
|
||||
/// assert_eq!(tra2, Scale2::new(1.0f32, 2.0));
|
||||
/// ```
|
||||
pub fn cast<To: Scalar>(self) -> Scale<To, D>
|
||||
where
|
||||
Scale<To, D>: SupersetOf<Self>,
|
||||
{
|
||||
crate::convert(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + One + ClosedMul, const D: usize> One for Scale<T, D> {
|
||||
#[inline]
|
||||
fn one() -> Self {
|
||||
Self::identity()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand-no-std")]
|
||||
impl<T: Scalar, const D: usize> Distribution<Scale<T, D>> for Standard
|
||||
where
|
||||
Standard: Distribution<T>,
|
||||
{
|
||||
/// Generate an arbitrary random variate for testing purposes.
|
||||
#[inline]
|
||||
fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> Scale<T, D> {
|
||||
Scale::from(rng.gen::<SVector<T, D>>())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "arbitrary")]
|
||||
impl<T: Scalar + Arbitrary + Send, const D: usize> Arbitrary for Scale<T, D>
|
||||
where
|
||||
Owned<T, crate::Const<D>>: Send,
|
||||
{
|
||||
#[inline]
|
||||
fn arbitrary(rng: &mut Gen) -> Self {
|
||||
let v: SVector<T, D> = Arbitrary::arbitrary(rng);
|
||||
Self::from(v)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Small Scale construction from components.
|
||||
*
|
||||
*/
|
||||
macro_rules! componentwise_constructors_impl(
|
||||
($($doc: expr; $D: expr, $($args: ident:$irow: expr),*);* $(;)*) => {$(
|
||||
impl<T> Scale<T, $D>
|
||||
{
|
||||
#[doc = "Initializes this Scale from its components."]
|
||||
#[doc = "# Example\n```"]
|
||||
#[doc = $doc]
|
||||
#[doc = "```"]
|
||||
#[inline]
|
||||
pub const fn new($($args: T),*) -> Self {
|
||||
Self { vector: SVector::<T, $D>::new($($args),*) }
|
||||
}
|
||||
}
|
||||
)*}
|
||||
);
|
||||
|
||||
componentwise_constructors_impl!(
|
||||
"# use nalgebra::Scale1;\nlet t = Scale1::new(1.0);\nassert!(t.vector.x == 1.0);";
|
||||
1, x:0;
|
||||
"# use nalgebra::Scale2;\nlet t = Scale2::new(1.0, 2.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0);";
|
||||
2, x:0, y:1;
|
||||
"# use nalgebra::Scale3;\nlet t = Scale3::new(1.0, 2.0, 3.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0);";
|
||||
3, x:0, y:1, z:2;
|
||||
"# use nalgebra::Scale4;\nlet t = Scale4::new(1.0, 2.0, 3.0, 4.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0);";
|
||||
4, x:0, y:1, z:2, w:3;
|
||||
"# use nalgebra::Scale5;\nlet t = Scale5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0);";
|
||||
5, x:0, y:1, z:2, w:3, a:4;
|
||||
"# use nalgebra::Scale6;\nlet t = Scale6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0 && t.vector.b == 6.0);";
|
||||
6, x:0, y:1, z:2, w:3, a:4, b:5;
|
||||
);
|
233
src/geometry/scale_conversion.rs
Normal file
233
src/geometry/scale_conversion.rs
Normal file
@ -0,0 +1,233 @@
|
||||
use num::{One, Zero};
|
||||
|
||||
use simba::scalar::{RealField, SubsetOf, SupersetOf};
|
||||
use simba::simd::PrimitiveSimdValue;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar};
|
||||
|
||||
use crate::geometry::{Scale, SuperTCategoryOf, TAffine, Transform};
|
||||
use crate::Point;
|
||||
|
||||
/*
|
||||
* This file provides the following conversions:
|
||||
* =============================================
|
||||
*
|
||||
* Scale -> Scale
|
||||
* Scale -> Transform
|
||||
* Scale -> Matrix (homogeneous)
|
||||
*/
|
||||
|
||||
impl<T1, T2, const D: usize> SubsetOf<Scale<T2, D>> for Scale<T1, D>
|
||||
where
|
||||
T1: Scalar,
|
||||
T2: Scalar + SupersetOf<T1>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_superset(&self) -> Scale<T2, D> {
|
||||
Scale::from(self.vector.to_superset())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(rot: &Scale<T2, D>) -> bool {
|
||||
crate::is_convertible::<_, SVector<T1, D>>(&rot.vector)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(rot: &Scale<T2, D>) -> Self {
|
||||
Scale {
|
||||
vector: rot.vector.to_subset_unchecked(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, C, const D: usize> SubsetOf<Transform<T2, C, D>> for Scale<T1, D>
|
||||
where
|
||||
T1: RealField,
|
||||
T2: RealField + SupersetOf<T1>,
|
||||
C: SuperTCategoryOf<TAffine>,
|
||||
Const<D>: DimNameAdd<U1>,
|
||||
DefaultAllocator: Allocator<T1, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
+ Allocator<T1, DimNameSum<Const<D>, U1>, U1>
|
||||
+ Allocator<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_superset(&self) -> Transform<T2, C, D> {
|
||||
Transform::from_matrix_unchecked(self.to_homogeneous().to_superset())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(t: &Transform<T2, C, D>) -> bool {
|
||||
<Self as SubsetOf<_>>::is_in_subset(t.matrix())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(t: &Transform<T2, C, D>) -> Self {
|
||||
Self::from_superset_unchecked(t.matrix())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, const D: usize>
|
||||
SubsetOf<OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>> for Scale<T1, D>
|
||||
where
|
||||
T1: RealField,
|
||||
T2: RealField + SupersetOf<T1>,
|
||||
Const<D>: DimNameAdd<U1>,
|
||||
DefaultAllocator: Allocator<T1, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
+ Allocator<T1, DimNameSum<Const<D>, U1>, U1>
|
||||
+ Allocator<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_superset(&self) -> OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
|
||||
self.to_homogeneous().to_superset()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_in_subset(m: &OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>) -> bool {
|
||||
if m[(D, D)] != T2::one() {
|
||||
return false;
|
||||
}
|
||||
for i in 0..D + 1 {
|
||||
for j in 0..D + 1 {
|
||||
if i != j && m[(i, j)] != T2::zero() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_superset_unchecked(
|
||||
m: &OMatrix<T2, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
|
||||
) -> Self {
|
||||
let v = m.fixed_slice::<D, D>(0, 0).diagonal();
|
||||
Self {
|
||||
vector: crate::convert_unchecked(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + Zero + One, const D: usize> From<Scale<T, D>>
|
||||
for OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
where
|
||||
Const<D>: DimNameAdd<U1>,
|
||||
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
|
||||
+ Allocator<T, DimNameSum<Const<D>, U1>, U1>
|
||||
+ Allocator<T, Const<D>>,
|
||||
{
|
||||
#[inline]
|
||||
fn from(t: Scale<T, D>) -> Self {
|
||||
t.to_homogeneous()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar, const D: usize> From<OVector<T, Const<D>>> for Scale<T, D> {
|
||||
#[inline]
|
||||
fn from(vector: OVector<T, Const<D>>) -> Self {
|
||||
Scale { vector }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar, const D: usize> From<[T; D]> for Scale<T, D> {
|
||||
#[inline]
|
||||
fn from(coords: [T; D]) -> Self {
|
||||
Scale {
|
||||
vector: coords.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar, const D: usize> From<Point<T, D>> for Scale<T, D> {
|
||||
#[inline]
|
||||
fn from(pt: Point<T, D>) -> Self {
|
||||
Scale { vector: pt.coords }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar, const D: usize> From<Scale<T, D>> for [T; D] {
|
||||
#[inline]
|
||||
fn from(t: Scale<T, D>) -> Self {
|
||||
t.vector.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Scale<T::Element, D>; 2]> for Scale<T, D>
|
||||
where
|
||||
T: From<[<T as simba::simd::SimdValue>::Element; 2]>,
|
||||
T::Element: Scalar,
|
||||
{
|
||||
#[inline]
|
||||
fn from(arr: [Scale<T::Element, D>; 2]) -> Self {
|
||||
Self::from(OVector::from([
|
||||
arr[0].vector.clone(),
|
||||
arr[1].vector.clone(),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Scale<T::Element, D>; 4]> for Scale<T, D>
|
||||
where
|
||||
T: From<[<T as simba::simd::SimdValue>::Element; 4]>,
|
||||
T::Element: Scalar,
|
||||
{
|
||||
#[inline]
|
||||
fn from(arr: [Scale<T::Element, D>; 4]) -> Self {
|
||||
Self::from(OVector::from([
|
||||
arr[0].vector.clone(),
|
||||
arr[1].vector.clone(),
|
||||
arr[2].vector.clone(),
|
||||
arr[3].vector.clone(),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Scale<T::Element, D>; 8]> for Scale<T, D>
|
||||
where
|
||||
T: From<[<T as simba::simd::SimdValue>::Element; 8]>,
|
||||
T::Element: Scalar,
|
||||
{
|
||||
#[inline]
|
||||
fn from(arr: [Scale<T::Element, D>; 8]) -> Self {
|
||||
Self::from(OVector::from([
|
||||
arr[0].vector.clone(),
|
||||
arr[1].vector.clone(),
|
||||
arr[2].vector.clone(),
|
||||
arr[3].vector.clone(),
|
||||
arr[4].vector.clone(),
|
||||
arr[5].vector.clone(),
|
||||
arr[6].vector.clone(),
|
||||
arr[7].vector.clone(),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar + PrimitiveSimdValue, const D: usize> From<[Scale<T::Element, D>; 16]>
|
||||
for Scale<T, D>
|
||||
where
|
||||
T: From<[<T as simba::simd::SimdValue>::Element; 16]>,
|
||||
T::Element: Scalar,
|
||||
{
|
||||
#[inline]
|
||||
fn from(arr: [Scale<T::Element, D>; 16]) -> Self {
|
||||
Self::from(OVector::from([
|
||||
arr[0].vector.clone(),
|
||||
arr[1].vector.clone(),
|
||||
arr[2].vector.clone(),
|
||||
arr[3].vector.clone(),
|
||||
arr[4].vector.clone(),
|
||||
arr[5].vector.clone(),
|
||||
arr[6].vector.clone(),
|
||||
arr[7].vector.clone(),
|
||||
arr[8].vector.clone(),
|
||||
arr[9].vector.clone(),
|
||||
arr[10].vector.clone(),
|
||||
arr[11].vector.clone(),
|
||||
arr[12].vector.clone(),
|
||||
arr[13].vector.clone(),
|
||||
arr[14].vector.clone(),
|
||||
arr[15].vector.clone(),
|
||||
]))
|
||||
}
|
||||
}
|
39
src/geometry/scale_coordinates.rs
Normal file
39
src/geometry/scale_coordinates.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
|
||||
use crate::base::Scalar;
|
||||
|
||||
use crate::geometry::Scale;
|
||||
|
||||
/*
|
||||
*
|
||||
* Give coordinates to Scale{1 .. 6}
|
||||
*
|
||||
*/
|
||||
|
||||
macro_rules! deref_impl(
|
||||
($D: expr, $Target: ident $(, $comps: ident)*) => {
|
||||
impl<T: Scalar> Deref for Scale<T, $D> {
|
||||
type Target = $Target<T>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.vector.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Scalar> DerefMut for Scale<T, $D> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.vector.deref_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
deref_impl!(1, X, x);
|
||||
deref_impl!(2, XY, x, y);
|
||||
deref_impl!(3, XYZ, x, y, z);
|
||||
deref_impl!(4, XYZW, x, y, z, w);
|
||||
deref_impl!(5, XYZWA, x, y, z, w, a);
|
||||
deref_impl!(6, XYZWAB, x, y, z, w, a, b);
|
125
src/geometry/scale_ops.rs
Normal file
125
src/geometry/scale_ops.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use std::ops::{Mul, MulAssign};
|
||||
|
||||
use simba::scalar::ClosedMul;
|
||||
|
||||
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
|
||||
use crate::base::dimension::U1;
|
||||
use crate::base::{Const, SVector, Scalar};
|
||||
|
||||
use crate::geometry::{Point, Scale};
|
||||
|
||||
// Scale × Scale
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: &'b Scale<T, D>, Output = Scale<T, D>;
|
||||
Scale::from(self.vector.component_mul(&right.vector));
|
||||
'a, 'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: Scale<T, D>, Output = Scale<T, D>;
|
||||
Scale::from(self.vector.component_mul(&right.vector));
|
||||
'a);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: &'b Scale<T, D>, Output = Scale<T, D>;
|
||||
Scale::from(self.vector.component_mul(&right.vector));
|
||||
'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: Scale<T, D>, Output = Scale<T, D>;
|
||||
Scale::from(self.vector.component_mul(&right.vector)); );
|
||||
|
||||
// Scale × scalar
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: T, Output = Scale<T, D>;
|
||||
Scale::from(&self.vector * right);
|
||||
'a);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: T, Output = Scale<T, D>;
|
||||
Scale::from(self.vector * right); );
|
||||
|
||||
// Scale × Point
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: &'b Point<T, D>, Output = Point<T, D>;
|
||||
Point::from(self.vector.component_mul(&right.coords));
|
||||
'a, 'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: Point<T, D>, Output = Point<T, D>;
|
||||
Point::from(self.vector.component_mul(&right.coords));
|
||||
'a);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: &'b Point<T, D>, Output = Point<T, D>;
|
||||
Point::from(self.vector.component_mul(&right.coords));
|
||||
'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: Point<T, D>, Output = Point<T, D>;
|
||||
Point::from(self.vector.component_mul(&right.coords)); );
|
||||
|
||||
// Scale * Vector
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: &'b SVector<T, D>, Output = SVector<T, D>;
|
||||
SVector::from(self.vector.component_mul(&right));
|
||||
'a, 'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: &'a Scale<T, D>, right: SVector<T, D>, Output = SVector<T, D>;
|
||||
SVector::from(self.vector.component_mul(&right));
|
||||
'a);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: &'b SVector<T, D>, Output = SVector<T, D>;
|
||||
SVector::from(self.vector.component_mul(&right));
|
||||
'b);
|
||||
|
||||
add_sub_impl!(Mul, mul, ClosedMul;
|
||||
(Const<D>, U1), (Const<D>, U1) -> (Const<D>, U1)
|
||||
const D; for; where;
|
||||
self: Scale<T, D>, right: SVector<T, D>, Output = SVector<T, D>;
|
||||
SVector::from(self.vector.component_mul(&right)); );
|
||||
|
||||
// Scale *= Scale
|
||||
add_sub_assign_impl!(MulAssign, mul_assign, ClosedMul;
|
||||
const D;
|
||||
self: Scale<T, D>, right: &'b Scale<T, D>;
|
||||
self.vector.component_mul_assign(&right.vector);
|
||||
'b);
|
||||
|
||||
add_sub_assign_impl!(MulAssign, mul_assign, ClosedMul;
|
||||
const D;
|
||||
self: Scale<T, D>, right: Scale<T, D>;
|
||||
self.vector.component_mul_assign(&right.vector); );
|
||||
|
||||
// Scale ×= scalar
|
||||
add_sub_assign_impl!(MulAssign, mul_assign, ClosedMul;
|
||||
const D;
|
||||
self: Scale<T, D>, right: T;
|
||||
self.vector *= right; );
|
49
src/geometry/scale_simba.rs
Executable file
49
src/geometry/scale_simba.rs
Executable file
@ -0,0 +1,49 @@
|
||||
use simba::simd::SimdValue;
|
||||
|
||||
use crate::base::OVector;
|
||||
use crate::Scalar;
|
||||
|
||||
use crate::geometry::Scale;
|
||||
|
||||
impl<T: Scalar + SimdValue, const D: usize> SimdValue for Scale<T, D>
|
||||
where
|
||||
T::Element: Scalar,
|
||||
{
|
||||
type Element = Scale<T::Element, D>;
|
||||
type SimdBool = T::SimdBool;
|
||||
|
||||
#[inline]
|
||||
fn lanes() -> usize {
|
||||
T::lanes()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn splat(val: Self::Element) -> Self {
|
||||
OVector::splat(val.vector).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extract(&self, i: usize) -> Self::Element {
|
||||
self.vector.extract(i).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
|
||||
self.vector.extract_unchecked(i).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace(&mut self, i: usize, val: Self::Element) {
|
||||
self.vector.replace(i, val.vector)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
|
||||
self.vector.replace_unchecked(i, val.vector)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn select(self, cond: Self::SimdBool, other: Self) -> Self {
|
||||
self.vector.select(cond, other.vector).into()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user