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    /// #[macro_use] extern crate approx;
135    /// # use nalgebra::UnitComplex;
136    /// let c = UnitComplex::new(1.0f64);
137    /// let c2 = c.cast::<f32>();
138    /// assert_relative_eq!(c2, UnitComplex::new(1.0f32));
139    /// ```
140    pub fn cast<To: Scalar>(self) -> UnitComplex<To>
141    where
142        UnitComplex<To>: SupersetOf<Self>,
143    {
144        crate::convert(self)
145    }
146
147    /// The underlying complex number.
148    ///
149    /// Same as `self.as_ref()`.
150    ///
151    /// # Example
152    /// ```
153    /// # extern crate num_complex;
154    /// # use num_complex::Complex;
155    /// # use nalgebra::UnitComplex;
156    /// let angle = 1.78f32;
157    /// let rot = UnitComplex::new(angle);
158    /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin()));
159    /// ```
160    #[inline]
161    #[must_use]
162    pub fn complex(&self) -> &Complex<T> {
163        self.as_ref()
164    }
165
166    /// Creates a new unit complex number from a complex number.
167    ///
168    /// The input complex number will be normalized.
169    #[inline]
170    pub fn from_complex(q: Complex<T>) -> Self {
171        Self::from_complex_and_get(q).0
172    }
173
174    /// Creates a new unit complex number from a complex number.
175    ///
176    /// The input complex number will be normalized. Returns the norm of the complex number as well.
177    #[inline]
178    pub fn from_complex_and_get(q: Complex<T>) -> (Self, T) {
179        let norm = (q.im.clone() * q.im.clone() + q.re.clone() * q.re.clone()).simd_sqrt();
180        (Self::new_unchecked(q / norm.clone()), norm)
181    }
182
183    /// Builds the unit complex number from the corresponding 2D rotation matrix.
184    ///
185    /// # Example
186    /// ```
187    /// # use nalgebra::{Rotation2, UnitComplex};
188    /// let rot = Rotation2::new(1.7);
189    /// let complex = UnitComplex::from_rotation_matrix(&rot);
190    /// assert_eq!(complex, UnitComplex::new(1.7));
191    /// ```
192    // TODO: add UnitComplex::from(...) instead?
193    #[inline]
194    pub fn from_rotation_matrix(rotmat: &Rotation2<T>) -> Self {
195        Self::new_unchecked(Complex::new(rotmat[(0, 0)].clone(), rotmat[(1, 0)].clone()))
196    }
197
198    /// Builds a rotation from a basis assumed to be orthonormal.
199    ///
200    /// In order to get a valid unit-quaternion, the input must be an
201    /// orthonormal basis, i.e., all vectors are normalized, and the are
202    /// all orthogonal to each other. These invariants are not checked
203    /// by this method.
204    pub fn from_basis_unchecked(basis: &[Vector2<T>; 2]) -> Self {
205        let mat = Matrix2::from_columns(&basis[..]);
206        let rot = Rotation2::from_matrix_unchecked(mat);
207        Self::from_rotation_matrix(&rot)
208    }
209
210    /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
211    ///
212    /// This is an iterative method. See `.from_matrix_eps` to provide mover
213    /// convergence parameters and starting solution.
214    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
215    pub fn from_matrix(m: &Matrix2<T>) -> Self
216    where
217        T: RealField,
218    {
219        Rotation2::from_matrix(m).into()
220    }
221
222    /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
223    ///
224    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
225    ///
226    /// # Parameters
227    ///
228    /// * `m`: the matrix from which the rotational part is to be extracted.
229    /// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
230    /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
231    /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
232    ///           to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other
233    ///           guesses come to mind.
234    pub fn from_matrix_eps(m: &Matrix2<T>, eps: T, max_iter: usize, guess: Self) -> Self
235    where
236        T: RealField,
237    {
238        let guess = Rotation2::from(guess);
239        Rotation2::from_matrix_eps(m, eps, max_iter, guess).into()
240    }
241
242    /// The unit complex number needed to make `self` and `other` coincide.
243    ///
244    /// The result is such that: `self.rotation_to(other) * self == other`.
245    ///
246    /// # Example
247    /// ```
248    /// # #[macro_use] extern crate approx;
249    /// # use nalgebra::UnitComplex;
250    /// let rot1 = UnitComplex::new(0.1);
251    /// let rot2 = UnitComplex::new(1.7);
252    /// let rot_to = rot1.rotation_to(&rot2);
253    ///
254    /// assert_relative_eq!(rot_to * rot1, rot2);
255    /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
256    /// ```
257    #[inline]
258    #[must_use]
259    pub fn rotation_to(&self, other: &Self) -> Self {
260        other / self
261    }
262
263    /// Raise this unit complex number to a given floating power.
264    ///
265    /// This returns the unit complex number that identifies a rotation angle equal to
266    /// `self.angle() × n`.
267    ///
268    /// # Example
269    /// ```
270    /// # #[macro_use] extern crate approx;
271    /// # use nalgebra::UnitComplex;
272    /// let rot = UnitComplex::new(0.78);
273    /// let pow = rot.powf(2.0);
274    /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
275    /// ```
276    #[inline]
277    #[must_use]
278    pub fn powf(&self, n: T) -> Self {
279        Self::from_angle(self.angle() * n)
280    }
281}
282
283/// # Construction from two vectors
284impl<T: SimdRealField> UnitComplex<T>
285where
286    T::Element: SimdRealField,
287{
288    /// The unit complex needed to make `a` and `b` be collinear and point toward the same
289    /// direction.
290    ///
291    /// # Example
292    /// ```
293    /// # #[macro_use] extern crate approx;
294    /// # use nalgebra::{Vector2, UnitComplex};
295    /// let a = Vector2::new(1.0, 2.0);
296    /// let b = Vector2::new(2.0, 1.0);
297    /// let rot = UnitComplex::rotation_between(&a, &b);
298    /// assert_relative_eq!(rot * a, b);
299    /// assert_relative_eq!(rot.inverse() * b, a);
300    /// ```
301    #[inline]
302    pub fn rotation_between<SB, SC>(a: &Vector<T, U2, SB>, b: &Vector<T, U2, SC>) -> Self
303    where
304        T: RealField,
305        SB: Storage<T, U2>,
306        SC: Storage<T, U2>,
307    {
308        Self::scaled_rotation_between(a, b, T::one())
309    }
310
311    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
312    /// direction, raised to the power `s`.
313    ///
314    /// # Example
315    /// ```
316    /// # #[macro_use] extern crate approx;
317    /// # use nalgebra::{Vector2, UnitComplex};
318    /// let a = Vector2::new(1.0, 2.0);
319    /// let b = Vector2::new(2.0, 1.0);
320    /// let rot2 = UnitComplex::scaled_rotation_between(&a, &b, 0.2);
321    /// let rot5 = UnitComplex::scaled_rotation_between(&a, &b, 0.5);
322    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
323    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
324    /// ```
325    #[inline]
326    pub fn scaled_rotation_between<SB, SC>(
327        a: &Vector<T, U2, SB>,
328        b: &Vector<T, U2, SC>,
329        s: T,
330    ) -> Self
331    where
332        T: RealField,
333        SB: Storage<T, U2>,
334        SC: Storage<T, U2>,
335    {
336        // TODO: code duplication with Rotation.
337        if let (Some(na), Some(nb)) = (
338            Unit::try_new(a.clone_owned(), T::zero()),
339            Unit::try_new(b.clone_owned(), T::zero()),
340        ) {
341            Self::scaled_rotation_between_axis(&na, &nb, s)
342        } else {
343            Self::identity()
344        }
345    }
346
347    /// The unit complex needed to make `a` and `b` be collinear and point toward the same
348    /// direction.
349    ///
350    /// # Example
351    /// ```
352    /// # #[macro_use] extern crate approx;
353    /// # use nalgebra::{Unit, Vector2, UnitComplex};
354    /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
355    /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
356    /// let rot = UnitComplex::rotation_between_axis(&a, &b);
357    /// assert_relative_eq!(rot * a, b);
358    /// assert_relative_eq!(rot.inverse() * b, a);
359    /// ```
360    #[inline]
361    pub fn rotation_between_axis<SB, SC>(
362        a: &Unit<Vector<T, U2, SB>>,
363        b: &Unit<Vector<T, U2, SC>>,
364    ) -> Self
365    where
366        SB: Storage<T, U2>,
367        SC: Storage<T, U2>,
368    {
369        Self::scaled_rotation_between_axis(a, b, T::one())
370    }
371
372    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
373    /// direction, raised to the power `s`.
374    ///
375    /// # Example
376    /// ```
377    /// # #[macro_use] extern crate approx;
378    /// # use nalgebra::{Unit, Vector2, UnitComplex};
379    /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
380    /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
381    /// let rot2 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.2);
382    /// let rot5 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.5);
383    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
384    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
385    /// ```
386    #[inline]
387    pub fn scaled_rotation_between_axis<SB, SC>(
388        na: &Unit<Vector<T, U2, SB>>,
389        nb: &Unit<Vector<T, U2, SC>>,
390        s: T,
391    ) -> Self
392    where
393        SB: Storage<T, U2>,
394        SC: Storage<T, U2>,
395    {
396        let sang = na.perp(nb);
397        let cang = na.dot(nb);
398
399        Self::from_angle(sang.simd_atan2(cang) * s)
400    }
401}
402
403impl<T: SimdRealField> One for UnitComplex<T>
404where
405    T::Element: SimdRealField,
406{
407    #[inline]
408    fn one() -> Self {
409        Self::identity()
410    }
411}
412
413#[cfg(feature = "rand")]
414impl<T: SimdRealField> Distribution<UnitComplex<T>> for Standard
415where
416    T::Element: SimdRealField,
417    rand_distr::UnitCircle: Distribution<[T; 2]>,
418{
419    /// Generate a uniformly distributed random `UnitComplex`.
420    #[inline]
421    fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex<T> {
422        let x = rng.sample(rand_distr::UnitCircle);
423        UnitComplex::new_unchecked(Complex::new(x[0].clone(), x[1].clone()))
424    }
425}
426
427#[cfg(feature = "arbitrary")]
428impl<T: SimdRealField + Arbitrary> Arbitrary for UnitComplex<T>
429where
430    T::Element: SimdRealField,
431{
432    #[inline]
433    fn arbitrary(g: &mut Gen) -> Self {
434        UnitComplex::from_angle(T::arbitrary(g))
435    }
436}