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