nalgebra/geometry/
unit_complex_construction.rs

1#[cfg(feature = "arbitrary")]
2use quickcheck::{Arbitrary, Gen};
3
4#[cfg(feature = "rand-no-std")]
5use rand::{
6    distributions::{Distribution, Standard},
7    Rng,
8};
9
10use num::One;
11use num_complex::Complex;
12
13use crate::base::dimension::{U1, U2};
14use crate::base::storage::Storage;
15use crate::base::{Matrix2, Scalar, Unit, Vector, Vector2};
16use crate::geometry::{Rotation2, UnitComplex};
17use simba::scalar::{RealField, SupersetOf};
18use simba::simd::SimdRealField;
19
20impl<T: SimdRealField> Default for UnitComplex<T>
21where
22    T::Element: SimdRealField,
23{
24    fn default() -> Self {
25        Self::identity()
26    }
27}
28
29/// # Identity
30impl<T: SimdRealField> UnitComplex<T>
31where
32    T::Element: SimdRealField,
33{
34    /// The unit complex number multiplicative identity.
35    ///
36    /// # Example
37    /// ```
38    /// # use nalgebra::UnitComplex;
39    /// let rot1 = UnitComplex::identity();
40    /// let rot2 = UnitComplex::new(1.7);
41    ///
42    /// assert_eq!(rot1 * rot2, rot2);
43    /// assert_eq!(rot2 * rot1, rot2);
44    /// ```
45    #[inline]
46    pub fn identity() -> Self {
47        Self::new_unchecked(Complex::new(T::one(), T::zero()))
48    }
49}
50
51/// # Construction from a 2D rotation angle
52impl<T: SimdRealField> UnitComplex<T>
53where
54    T::Element: SimdRealField,
55{
56    /// Builds the unit complex number corresponding to the rotation with the given angle.
57    ///
58    /// # Example
59    ///
60    /// ```
61    /// # #[macro_use] extern crate approx;
62    /// # use std::f32;
63    /// # use nalgebra::{UnitComplex, Point2};
64    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
65    ///
66    /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
67    /// ```
68    #[inline]
69    pub fn new(angle: T) -> Self {
70        let (sin, cos) = angle.simd_sin_cos();
71        Self::from_cos_sin_unchecked(cos, sin)
72    }
73
74    /// Builds the unit complex number corresponding to the rotation with the angle.
75    ///
76    /// Same as `Self::new(angle)`.
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// # #[macro_use] extern crate approx;
82    /// # use std::f32;
83    /// # use nalgebra::{UnitComplex, Point2};
84    /// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
85    ///
86    /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
87    /// ```
88    // TODO: deprecate this.
89    #[inline]
90    pub fn from_angle(angle: T) -> Self {
91        Self::new(angle)
92    }
93
94    /// Builds the unit complex number from the sinus and cosinus of the rotation angle.
95    ///
96    /// The input values are not checked to actually be cosines and sine of the same value.
97    /// Is is generally preferable to use the `::new(angle)` constructor instead.
98    ///
99    /// # Example
100    ///
101    /// ```
102    /// # #[macro_use] extern crate approx;
103    /// # use std::f32;
104    /// # use nalgebra::{UnitComplex, Vector2, Point2};
105    /// let angle = f32::consts::FRAC_PI_2;
106    /// let rot = UnitComplex::from_cos_sin_unchecked(angle.cos(), angle.sin());
107    ///
108    /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
109    /// ```
110    #[inline]
111    pub fn from_cos_sin_unchecked(cos: T, sin: T) -> Self {
112        Self::new_unchecked(Complex::new(cos, sin))
113    }
114
115    /// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector.
116    ///
117    /// This is generally used in the context of generic programming. Using
118    /// the `::new(angle)` method instead is more common.
119    #[inline]
120    pub fn from_scaled_axis<SB: Storage<T, U1>>(axisangle: Vector<T, U1, SB>) -> Self {
121        Self::from_angle(axisangle[0].clone())
122    }
123}
124
125/// # Construction from an existing 2D matrix or complex number
126impl<T: SimdRealField> UnitComplex<T>
127where
128    T::Element: SimdRealField,
129{
130    /// Cast the components of `self` to another type.
131    ///
132    /// # Example
133    /// ```
134    /// # use nalgebra::UnitComplex;
135    /// let c = UnitComplex::new(1.0f64);
136    /// let c2 = c.cast::<f32>();
137    /// assert_eq!(c2, UnitComplex::new(1.0f32));
138    /// ```
139    pub fn cast<To: Scalar>(self) -> UnitComplex<To>
140    where
141        UnitComplex<To>: SupersetOf<Self>,
142    {
143        crate::convert(self)
144    }
145
146    /// The underlying complex number.
147    ///
148    /// Same as `self.as_ref()`.
149    ///
150    /// # Example
151    /// ```
152    /// # extern crate num_complex;
153    /// # use num_complex::Complex;
154    /// # use nalgebra::UnitComplex;
155    /// let angle = 1.78f32;
156    /// let rot = UnitComplex::new(angle);
157    /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin()));
158    /// ```
159    #[inline]
160    #[must_use]
161    pub fn complex(&self) -> &Complex<T> {
162        self.as_ref()
163    }
164
165    /// Creates a new unit complex number from a complex number.
166    ///
167    /// The input complex number will be normalized.
168    #[inline]
169    pub fn from_complex(q: Complex<T>) -> Self {
170        Self::from_complex_and_get(q).0
171    }
172
173    /// Creates a new unit complex number from a complex number.
174    ///
175    /// The input complex number will be normalized. Returns the norm of the complex number as well.
176    #[inline]
177    pub fn from_complex_and_get(q: Complex<T>) -> (Self, T) {
178        let norm = (q.im.clone() * q.im.clone() + q.re.clone() * q.re.clone()).simd_sqrt();
179        (Self::new_unchecked(q / norm.clone()), norm)
180    }
181
182    /// Builds the unit complex number from the corresponding 2D rotation matrix.
183    ///
184    /// # Example
185    /// ```
186    /// # use nalgebra::{Rotation2, UnitComplex};
187    /// let rot = Rotation2::new(1.7);
188    /// let complex = UnitComplex::from_rotation_matrix(&rot);
189    /// assert_eq!(complex, UnitComplex::new(1.7));
190    /// ```
191    // TODO: add UnitComplex::from(...) instead?
192    #[inline]
193    pub fn from_rotation_matrix(rotmat: &Rotation2<T>) -> Self {
194        Self::new_unchecked(Complex::new(rotmat[(0, 0)].clone(), rotmat[(1, 0)].clone()))
195    }
196
197    /// Builds a rotation from a basis assumed to be orthonormal.
198    ///
199    /// In order to get a valid unit-quaternion, the input must be an
200    /// orthonormal basis, i.e., all vectors are normalized, and the are
201    /// all orthogonal to each other. These invariants are not checked
202    /// by this method.
203    pub fn from_basis_unchecked(basis: &[Vector2<T>; 2]) -> Self {
204        let mat = Matrix2::from_columns(&basis[..]);
205        let rot = Rotation2::from_matrix_unchecked(mat);
206        Self::from_rotation_matrix(&rot)
207    }
208
209    /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
210    ///
211    /// This is an iterative method. See `.from_matrix_eps` to provide mover
212    /// convergence parameters and starting solution.
213    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
214    pub fn from_matrix(m: &Matrix2<T>) -> Self
215    where
216        T: RealField,
217    {
218        Rotation2::from_matrix(m).into()
219    }
220
221    /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
222    ///
223    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
224    ///
225    /// # Parameters
226    ///
227    /// * `m`: the matrix from which the rotational part is to be extracted.
228    /// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
229    /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
230    /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
231    ///           to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other
232    ///           guesses come to mind.
233    pub fn from_matrix_eps(m: &Matrix2<T>, eps: T, max_iter: usize, guess: Self) -> Self
234    where
235        T: RealField,
236    {
237        let guess = Rotation2::from(guess);
238        Rotation2::from_matrix_eps(m, eps, max_iter, guess).into()
239    }
240
241    /// The unit complex number needed to make `self` and `other` coincide.
242    ///
243    /// The result is such that: `self.rotation_to(other) * self == other`.
244    ///
245    /// # Example
246    /// ```
247    /// # #[macro_use] extern crate approx;
248    /// # use nalgebra::UnitComplex;
249    /// let rot1 = UnitComplex::new(0.1);
250    /// let rot2 = UnitComplex::new(1.7);
251    /// let rot_to = rot1.rotation_to(&rot2);
252    ///
253    /// assert_relative_eq!(rot_to * rot1, rot2);
254    /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
255    /// ```
256    #[inline]
257    #[must_use]
258    pub fn rotation_to(&self, other: &Self) -> Self {
259        other / self
260    }
261
262    /// Raise this unit complex number to a given floating power.
263    ///
264    /// This returns the unit complex number that identifies a rotation angle equal to
265    /// `self.angle() × n`.
266    ///
267    /// # Example
268    /// ```
269    /// # #[macro_use] extern crate approx;
270    /// # use nalgebra::UnitComplex;
271    /// let rot = UnitComplex::new(0.78);
272    /// let pow = rot.powf(2.0);
273    /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
274    /// ```
275    #[inline]
276    #[must_use]
277    pub fn powf(&self, n: T) -> Self {
278        Self::from_angle(self.angle() * n)
279    }
280}
281
282/// # Construction from two vectors
283impl<T: SimdRealField> UnitComplex<T>
284where
285    T::Element: SimdRealField,
286{
287    /// The unit complex needed to make `a` and `b` be collinear and point toward the same
288    /// direction.
289    ///
290    /// # Example
291    /// ```
292    /// # #[macro_use] extern crate approx;
293    /// # use nalgebra::{Vector2, UnitComplex};
294    /// let a = Vector2::new(1.0, 2.0);
295    /// let b = Vector2::new(2.0, 1.0);
296    /// let rot = UnitComplex::rotation_between(&a, &b);
297    /// assert_relative_eq!(rot * a, b);
298    /// assert_relative_eq!(rot.inverse() * b, a);
299    /// ```
300    #[inline]
301    pub fn rotation_between<SB, SC>(a: &Vector<T, U2, SB>, b: &Vector<T, U2, SC>) -> Self
302    where
303        T: RealField,
304        SB: Storage<T, U2>,
305        SC: Storage<T, U2>,
306    {
307        Self::scaled_rotation_between(a, b, T::one())
308    }
309
310    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
311    /// direction, raised to the power `s`.
312    ///
313    /// # Example
314    /// ```
315    /// # #[macro_use] extern crate approx;
316    /// # use nalgebra::{Vector2, UnitComplex};
317    /// let a = Vector2::new(1.0, 2.0);
318    /// let b = Vector2::new(2.0, 1.0);
319    /// let rot2 = UnitComplex::scaled_rotation_between(&a, &b, 0.2);
320    /// let rot5 = UnitComplex::scaled_rotation_between(&a, &b, 0.5);
321    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
322    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
323    /// ```
324    #[inline]
325    pub fn scaled_rotation_between<SB, SC>(
326        a: &Vector<T, U2, SB>,
327        b: &Vector<T, U2, SC>,
328        s: T,
329    ) -> Self
330    where
331        T: RealField,
332        SB: Storage<T, U2>,
333        SC: Storage<T, U2>,
334    {
335        // TODO: code duplication with Rotation.
336        if let (Some(na), Some(nb)) = (
337            Unit::try_new(a.clone_owned(), T::zero()),
338            Unit::try_new(b.clone_owned(), T::zero()),
339        ) {
340            Self::scaled_rotation_between_axis(&na, &nb, s)
341        } else {
342            Self::identity()
343        }
344    }
345
346    /// The unit complex needed to make `a` and `b` be collinear and point toward the same
347    /// direction.
348    ///
349    /// # Example
350    /// ```
351    /// # #[macro_use] extern crate approx;
352    /// # use nalgebra::{Unit, Vector2, UnitComplex};
353    /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
354    /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
355    /// let rot = UnitComplex::rotation_between_axis(&a, &b);
356    /// assert_relative_eq!(rot * a, b);
357    /// assert_relative_eq!(rot.inverse() * b, a);
358    /// ```
359    #[inline]
360    pub fn rotation_between_axis<SB, SC>(
361        a: &Unit<Vector<T, U2, SB>>,
362        b: &Unit<Vector<T, U2, SC>>,
363    ) -> Self
364    where
365        SB: Storage<T, U2>,
366        SC: Storage<T, U2>,
367    {
368        Self::scaled_rotation_between_axis(a, b, T::one())
369    }
370
371    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
372    /// direction, raised to the power `s`.
373    ///
374    /// # Example
375    /// ```
376    /// # #[macro_use] extern crate approx;
377    /// # use nalgebra::{Unit, Vector2, UnitComplex};
378    /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
379    /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
380    /// let rot2 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.2);
381    /// let rot5 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.5);
382    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
383    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
384    /// ```
385    #[inline]
386    pub fn scaled_rotation_between_axis<SB, SC>(
387        na: &Unit<Vector<T, U2, SB>>,
388        nb: &Unit<Vector<T, U2, SC>>,
389        s: T,
390    ) -> Self
391    where
392        SB: Storage<T, U2>,
393        SC: Storage<T, U2>,
394    {
395        let sang = na.perp(nb);
396        let cang = na.dot(nb);
397
398        Self::from_angle(sang.simd_atan2(cang) * s)
399    }
400}
401
402impl<T: SimdRealField> One for UnitComplex<T>
403where
404    T::Element: SimdRealField,
405{
406    #[inline]
407    fn one() -> Self {
408        Self::identity()
409    }
410}
411
412#[cfg(feature = "rand")]
413impl<T: SimdRealField> Distribution<UnitComplex<T>> for Standard
414where
415    T::Element: SimdRealField,
416    rand_distr::UnitCircle: Distribution<[T; 2]>,
417{
418    /// Generate a uniformly distributed random `UnitComplex`.
419    #[inline]
420    fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex<T> {
421        let x = rng.sample(rand_distr::UnitCircle);
422        UnitComplex::new_unchecked(Complex::new(x[0].clone(), x[1].clone()))
423    }
424}
425
426#[cfg(feature = "arbitrary")]
427impl<T: SimdRealField + Arbitrary> Arbitrary for UnitComplex<T>
428where
429    T::Element: SimdRealField,
430{
431    #[inline]
432    fn arbitrary(g: &mut Gen) -> Self {
433        UnitComplex::from_angle(T::arbitrary(g))
434    }
435}