nalgebra/geometry/
similarity_construction.rs

1#[cfg(feature = "arbitrary")]
2use crate::base::storage::Owned;
3#[cfg(feature = "arbitrary")]
4use quickcheck::{Arbitrary, Gen};
5
6use num::One;
7#[cfg(feature = "rand-no-std")]
8use rand::{
9    distributions::{Distribution, Standard},
10    Rng,
11};
12
13use simba::scalar::SupersetOf;
14use simba::simd::SimdRealField;
15
16use crate::base::{Vector2, Vector3};
17
18use crate::{
19    AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Scalar, Similarity,
20    Translation, UnitComplex, UnitQuaternion,
21};
22
23impl<T: SimdRealField, R, const D: usize> Default for Similarity<T, R, D>
24where
25    T::Element: SimdRealField,
26    R: AbstractRotation<T, D>,
27{
28    fn default() -> Self {
29        Self::identity()
30    }
31}
32
33impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D>
34where
35    T::Element: SimdRealField,
36    R: AbstractRotation<T, D>,
37{
38    /// Creates a new identity similarity.
39    ///
40    /// # Example
41    ///
42    /// ```
43    /// # use nalgebra::{Similarity2, Point2, Similarity3, Point3};
44    ///
45    /// let sim = Similarity2::identity();
46    /// let pt = Point2::new(1.0, 2.0);
47    /// assert_eq!(sim * pt, pt);
48    ///
49    /// let sim = Similarity3::identity();
50    /// let pt = Point3::new(1.0, 2.0, 3.0);
51    /// assert_eq!(sim * pt, pt);
52    /// ```
53    #[inline]
54    pub fn identity() -> Self {
55        Self::from_isometry(Isometry::identity(), T::one())
56    }
57}
58
59impl<T: SimdRealField, R, const D: usize> One for Similarity<T, R, D>
60where
61    T::Element: SimdRealField,
62    R: AbstractRotation<T, D>,
63{
64    /// Creates a new identity similarity.
65    #[inline]
66    fn one() -> Self {
67        Self::identity()
68    }
69}
70
71#[cfg(feature = "rand-no-std")]
72impl<T: crate::RealField, R, const D: usize> Distribution<Similarity<T, R, D>> for Standard
73where
74    R: AbstractRotation<T, D>,
75    Standard: Distribution<T> + Distribution<R>,
76{
77    /// Generate an arbitrary random variate for testing purposes.
78    #[inline]
79    fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Similarity<T, R, D> {
80        let mut s = rng.gen();
81        while relative_eq!(s, T::zero()) {
82            s = rng.gen()
83        }
84
85        Similarity::from_isometry(rng.gen(), s)
86    }
87}
88
89impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D>
90where
91    T::Element: SimdRealField,
92    R: AbstractRotation<T, D>,
93{
94    /// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with
95    /// its axis passing through the point `p`.
96    ///
97    /// # Example
98    ///
99    /// ```
100    /// # #[macro_use] extern crate approx;
101    /// # use std::f32;
102    /// # use nalgebra::{Similarity2, Point2, UnitComplex};
103    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
104    /// let pt = Point2::new(3.0, 2.0);
105    /// let sim = Similarity2::rotation_wrt_point(rot, pt, 4.0);
106    ///
107    /// assert_relative_eq!(sim * Point2::new(1.0, 2.0), Point2::new(-3.0, 3.0), epsilon = 1.0e-6);
108    /// ```
109    #[inline]
110    pub fn rotation_wrt_point(r: R, p: Point<T, D>, scaling: T) -> Self {
111        let shift = r.transform_vector(&-&p.coords);
112        Self::from_parts(Translation::from(shift + p.coords), r, scaling)
113    }
114}
115
116#[cfg(feature = "arbitrary")]
117impl<T, R, const D: usize> Arbitrary for Similarity<T, R, D>
118where
119    T: crate::RealField + Arbitrary + Send,
120    T::Element: crate::RealField,
121    R: AbstractRotation<T, D> + Arbitrary + Send,
122    Owned<T, crate::Const<D>>: Send,
123{
124    #[inline]
125    fn arbitrary(rng: &mut Gen) -> Self {
126        let mut s: T = Arbitrary::arbitrary(rng);
127        while s.is_zero() {
128            s = Arbitrary::arbitrary(rng)
129        }
130
131        Self::from_isometry(Arbitrary::arbitrary(rng), s)
132    }
133}
134
135/*
136 *
137 * Constructors for various static dimensions.
138 *
139 */
140
141// 2D similarity.
142impl<T: SimdRealField> Similarity<T, Rotation2<T>, 2>
143where
144    T::Element: SimdRealField,
145{
146    /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor.
147    ///
148    /// # Example
149    ///
150    /// ```
151    /// # #[macro_use] extern crate approx;
152    /// # use std::f32;
153    /// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
154    /// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
155    ///
156    /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
157    /// ```
158    #[inline]
159    pub fn new(translation: Vector2<T>, angle: T, scaling: T) -> Self {
160        Self::from_parts(
161            Translation::from(translation),
162            Rotation2::new(angle),
163            scaling,
164        )
165    }
166
167    /// Cast the components of `self` to another type.
168    ///
169    /// # Example
170    /// ```
171    /// # use nalgebra::SimilarityMatrix2;
172    /// let sim = SimilarityMatrix2::<f64>::identity();
173    /// let sim2 = sim.cast::<f32>();
174    /// assert_eq!(sim2, SimilarityMatrix2::<f32>::identity());
175    /// ```
176    pub fn cast<To: Scalar>(self) -> Similarity<To, Rotation2<To>, 2>
177    where
178        Similarity<To, Rotation2<To>, 2>: SupersetOf<Self>,
179    {
180        crate::convert(self)
181    }
182}
183
184impl<T: SimdRealField> Similarity<T, UnitComplex<T>, 2>
185where
186    T::Element: SimdRealField,
187{
188    /// Creates a new similarity from a translation and a rotation angle.
189    ///
190    /// # Example
191    ///
192    /// ```
193    /// # #[macro_use] extern crate approx;
194    /// # use std::f32;
195    /// # use nalgebra::{Similarity2, Vector2, Point2};
196    /// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
197    ///
198    /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
199    /// ```
200    #[inline]
201    pub fn new(translation: Vector2<T>, angle: T, scaling: T) -> Self {
202        Self::from_parts(
203            Translation::from(translation),
204            UnitComplex::new(angle),
205            scaling,
206        )
207    }
208
209    /// Cast the components of `self` to another type.
210    ///
211    /// # Example
212    /// ```
213    /// # use nalgebra::Similarity2;
214    /// let sim = Similarity2::<f64>::identity();
215    /// let sim2 = sim.cast::<f32>();
216    /// assert_eq!(sim2, Similarity2::<f32>::identity());
217    /// ```
218    pub fn cast<To: Scalar>(self) -> Similarity<To, UnitComplex<To>, 2>
219    where
220        Similarity<To, UnitComplex<To>, 2>: SupersetOf<Self>,
221    {
222        crate::convert(self)
223    }
224}
225
226// 3D rotation.
227macro_rules! similarity_construction_impl(
228    ($Rot: ident) => {
229        impl<T: SimdRealField> Similarity<T, $Rot<T>, 3>
230        where T::Element: SimdRealField {
231            /// Creates a new similarity from a translation, rotation axis-angle, and scaling
232            /// factor.
233            ///
234            /// # Example
235            ///
236            /// ```
237            /// # #[macro_use] extern crate approx;
238            /// # use std::f32;
239            /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
240            /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
241            /// let translation = Vector3::new(1.0, 2.0, 3.0);
242            /// // Point and vector being transformed in the tests.
243            /// let pt = Point3::new(4.0, 5.0, 6.0);
244            /// let vec = Vector3::new(4.0, 5.0, 6.0);
245            ///
246            /// // Similarity with its rotation part represented as a UnitQuaternion
247            /// let sim = Similarity3::new(translation, axisangle, 3.0);
248            /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
249            /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
250            ///
251            /// // Similarity with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
252            /// let sim = SimilarityMatrix3::new(translation, axisangle, 3.0);
253            /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
254            /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
255            /// ```
256            #[inline]
257            pub fn new(translation: Vector3<T>, axisangle: Vector3<T>, scaling: T) -> Self
258            {
259                Self::from_isometry(Isometry::<_, $Rot<T>, 3>::new(translation, axisangle), scaling)
260            }
261
262            /// Cast the components of `self` to another type.
263            ///
264            /// # Example
265            /// ```
266            /// # use nalgebra::Similarity3;
267            /// let sim = Similarity3::<f64>::identity();
268            /// let sim2 = sim.cast::<f32>();
269            /// assert_eq!(sim2, Similarity3::<f32>::identity());
270            /// ```
271            pub fn cast<To: Scalar>(self) -> Similarity<To, $Rot<To>, 3>
272            where
273                Similarity<To, $Rot<To>, 3>: SupersetOf<Self>,
274            {
275                crate::convert(self)
276            }
277
278            /// Creates an similarity that corresponds to a scaling factor and a local frame of
279            /// an observer standing at the point `eye` and looking toward `target`.
280            ///
281            /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
282            /// `eye`.
283            ///
284            /// # Arguments
285            ///   * eye - The observer position.
286            ///   * target - The target position.
287            ///   * up - Vertical direction. The only requirement of this parameter is to not be collinear
288            ///   to `eye - at`. Non-collinearity is not checked.
289            ///
290            /// # Example
291            ///
292            /// ```
293            /// # #[macro_use] extern crate approx;
294            /// # use std::f32;
295            /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
296            /// let eye = Point3::new(1.0, 2.0, 3.0);
297            /// let target = Point3::new(2.0, 2.0, 3.0);
298            /// let up = Vector3::y();
299            ///
300            /// // Similarity with its rotation part represented as a UnitQuaternion
301            /// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
302            /// assert_eq!(sim * Point3::origin(), eye);
303            /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
304            ///
305            /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
306            /// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
307            /// assert_eq!(sim * Point3::origin(), eye);
308            /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
309            /// ```
310            #[inline]
311            pub fn face_towards(eye:    &Point3<T>,
312                                target: &Point3<T>,
313                                up:     &Vector3<T>,
314                                scaling: T)
315                                -> Self {
316                Self::from_isometry(Isometry::<_, $Rot<T>, 3>::face_towards(eye, target, up), scaling)
317            }
318
319            /// Deprecated: Use [`SimilarityMatrix3::face_towards`] instead.
320            #[deprecated(note="renamed to `face_towards`")]
321            pub fn new_observer_frames(eye:    &Point3<T>,
322                                       target: &Point3<T>,
323                                       up:     &Vector3<T>,
324                                       scaling: T)
325                                       -> Self {
326                Self::face_towards(eye, target, up, scaling)
327            }
328
329            /// Builds a right-handed look-at view matrix including scaling factor.
330            ///
331            /// This conforms to the common notion of right handed look-at matrix from the computer
332            /// graphics community.
333            ///
334            /// # Arguments
335            ///   * eye - The eye position.
336            ///   * target - The target position.
337            ///   * up - A vector approximately aligned with required the vertical axis. The only
338            ///   requirement of this parameter is to not be collinear to `target - eye`.
339            ///
340            /// # Example
341            ///
342            /// ```
343            /// # #[macro_use] extern crate approx;
344            /// # use std::f32;
345            /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
346            /// let eye = Point3::new(1.0, 2.0, 3.0);
347            /// let target = Point3::new(2.0, 2.0, 3.0);
348            /// let up = Vector3::y();
349            ///
350            /// // Similarity with its rotation part represented as a UnitQuaternion
351            /// let iso = Similarity3::look_at_rh(&eye, &target, &up, 3.0);
352            /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
353            ///
354            /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
355            /// let iso = SimilarityMatrix3::look_at_rh(&eye, &target, &up, 3.0);
356            /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
357            /// ```
358            #[inline]
359            pub fn look_at_rh(eye:     &Point3<T>,
360                              target:  &Point3<T>,
361                              up:      &Vector3<T>,
362                              scaling: T)
363                              -> Self {
364                Self::from_isometry(Isometry::<_, $Rot<T>, 3>::look_at_rh(eye, target, up), scaling)
365            }
366
367            /// Builds a left-handed look-at view matrix including a scaling factor.
368            ///
369            /// This conforms to the common notion of left handed look-at matrix from the computer
370            /// graphics community.
371            ///
372            /// # Arguments
373            ///   * eye - The eye position.
374            ///   * target - The target position.
375            ///   * up - A vector approximately aligned with required the vertical axis. The only
376            ///   requirement of this parameter is to not be collinear to `target - eye`.
377            ///
378            /// # Example
379            ///
380            /// ```
381            /// # #[macro_use] extern crate approx;
382            /// # use std::f32;
383            /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
384            /// let eye = Point3::new(1.0, 2.0, 3.0);
385            /// let target = Point3::new(2.0, 2.0, 3.0);
386            /// let up = Vector3::y();
387            ///
388            /// // Similarity with its rotation part represented as a UnitQuaternion
389            /// let sim = Similarity3::look_at_lh(&eye, &target, &up, 3.0);
390            /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
391            ///
392            /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
393            /// let sim = SimilarityMatrix3::look_at_lh(&eye, &target, &up, 3.0);
394            /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
395            /// ```
396            #[inline]
397            pub fn look_at_lh(eye:     &Point3<T>,
398                              target:  &Point3<T>,
399                              up:      &Vector3<T>,
400                              scaling: T)
401                              -> Self {
402                Self::from_isometry(Isometry::<_, $Rot<T>, 3>::look_at_lh(eye, target, up), scaling)
403            }
404        }
405    }
406);
407
408similarity_construction_impl!(Rotation3);
409similarity_construction_impl!(UnitQuaternion);