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