commit
e05bfe48b3
|
@ -48,6 +48,14 @@ mod translation_coordinates;
|
||||||
mod translation_ops;
|
mod translation_ops;
|
||||||
mod translation_simba;
|
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;
|
||||||
mod isometry_alias;
|
mod isometry_alias;
|
||||||
mod isometry_construction;
|
mod isometry_construction;
|
||||||
|
@ -95,6 +103,9 @@ pub use self::unit_complex::*;
|
||||||
pub use self::translation::*;
|
pub use self::translation::*;
|
||||||
pub use self::translation_alias::*;
|
pub use self::translation_alias::*;
|
||||||
|
|
||||||
|
pub use self::scale::*;
|
||||||
|
pub use self::scale_alias::*;
|
||||||
|
|
||||||
pub use self::isometry::*;
|
pub use self::isometry::*;
|
||||||
pub use self::isometry_alias::*;
|
pub use self::isometry_alias::*;
|
||||||
|
|
||||||
|
|
|
@ -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, "}}")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>;
|
|
@ -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;
|
||||||
|
);
|
|
@ -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(),
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
@ -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; );
|
|
@ -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