1 #[cfg(feature = "arbitrary")]
2 use quickcheck::{Arbitrary, Gen};
3 
4 use num::One;
5 use num_complex::Complex;
6 use rand::distributions::{Distribution, OpenClosed01, Standard};
7 use rand::Rng;
8 
9 use alga::general::RealField;
10 use crate::base::dimension::{U1, U2};
11 use crate::base::storage::Storage;
12 use crate::base::{Unit, Vector, Matrix2};
13 use crate::geometry::{Rotation2, UnitComplex};
14 
15 impl<N: RealField> UnitComplex<N> {
16     /// The unit complex number multiplicative identity.
17     ///
18     /// # Example
19     /// ```
20     /// # use nalgebra::UnitComplex;
21     /// let rot1 = UnitComplex::identity();
22     /// let rot2 = UnitComplex::new(1.7);
23     ///
24     /// assert_eq!(rot1 * rot2, rot2);
25     /// assert_eq!(rot2 * rot1, rot2);
26     /// ```
27     #[inline]
identity() -> Self28     pub fn identity() -> Self {
29         Self::new_unchecked(Complex::new(N::one(), N::zero()))
30     }
31 
32     /// Builds the unit complex number corresponding to the rotation with the given angle.
33     ///
34     /// # Example
35     ///
36     /// ```
37     /// # #[macro_use] extern crate approx;
38     /// # use std::f32;
39     /// # use nalgebra::{UnitComplex, Point2};
40     /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
41     ///
42     /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
43     /// ```
44     #[inline]
new(angle: N) -> Self45     pub fn new(angle: N) -> Self {
46         let (sin, cos) = angle.sin_cos();
47         Self::from_cos_sin_unchecked(cos, sin)
48     }
49 
50     /// Builds the unit complex number corresponding to the rotation with the angle.
51     ///
52     /// Same as `Self::new(angle)`.
53     ///
54     /// # Example
55     ///
56     /// ```
57     /// # #[macro_use] extern crate approx;
58     /// # use std::f32;
59     /// # use nalgebra::{UnitComplex, Point2};
60     /// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
61     ///
62     /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
63     /// ```
64     // FIXME: deprecate this.
65     #[inline]
from_angle(angle: N) -> Self66     pub fn from_angle(angle: N) -> Self {
67         Self::new(angle)
68     }
69 
70     /// Builds the unit complex number from the sinus and cosinus of the rotation angle.
71     ///
72     /// The input values are not checked to actually be cosines and sine of the same value.
73     /// Is is generally preferable to use the `::new(angle)` constructor instead.
74     ///
75     /// # Example
76     ///
77     /// ```
78     /// # #[macro_use] extern crate approx;
79     /// # use std::f32;
80     /// # use nalgebra::{UnitComplex, Vector2, Point2};
81     /// let angle = f32::consts::FRAC_PI_2;
82     /// let rot = UnitComplex::from_cos_sin_unchecked(angle.cos(), angle.sin());
83     ///
84     /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
85     /// ```
86     #[inline]
from_cos_sin_unchecked(cos: N, sin: N) -> Self87     pub fn from_cos_sin_unchecked(cos: N, sin: N) -> Self {
88         Self::new_unchecked(Complex::new(cos, sin))
89     }
90 
91     /// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector.
92     ///
93     /// This is generally used in the context of generic programming. Using
94     /// the `::new(angle)` method instead is more common.
95     #[inline]
from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self96     pub fn from_scaled_axis<SB: Storage<N, U1>>(axisangle: Vector<N, U1, SB>) -> Self {
97         Self::from_angle(axisangle[0])
98     }
99 
100     /// Creates a new unit complex number from a complex number.
101     ///
102     /// The input complex number will be normalized.
103     #[inline]
from_complex(q: Complex<N>) -> Self104     pub fn from_complex(q: Complex<N>) -> Self {
105         Self::from_complex_and_get(q).0
106     }
107 
108     /// Creates a new unit complex number from a complex number.
109     ///
110     /// The input complex number will be normalized. Returns the norm of the complex number as well.
111     #[inline]
from_complex_and_get(q: Complex<N>) -> (Self, N)112     pub fn from_complex_and_get(q: Complex<N>) -> (Self, N) {
113         let norm = (q.im * q.im + q.re * q.re).sqrt();
114         (Self::new_unchecked(q / norm), norm)
115     }
116 
117     /// Builds the unit complex number from the corresponding 2D rotation matrix.
118     ///
119     /// # Example
120     /// ```
121     /// # use nalgebra::{Rotation2, UnitComplex};
122     /// let rot = Rotation2::new(1.7);
123     /// let complex = UnitComplex::from_rotation_matrix(&rot);
124     /// assert_eq!(complex, UnitComplex::new(1.7));
125     /// ```
126     // FIXME: add UnitComplex::from(...) instead?
127     #[inline]
from_rotation_matrix(rotmat: &Rotation2<N>) -> Self128     pub fn from_rotation_matrix(rotmat: &Rotation2<N>) -> Self {
129         Self::new_unchecked(Complex::new(rotmat[(0, 0)], rotmat[(1, 0)]))
130     }
131 
132     /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
133     ///
134     /// This is an iterative method. See `.from_matrix_eps` to provide mover
135     /// convergence parameters and starting solution.
136     /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
from_matrix(m: &Matrix2<N>) -> Self137     pub fn from_matrix(m: &Matrix2<N>) -> Self {
138         Rotation2::from_matrix(m).into()
139     }
140 
141     /// Builds an unit complex by extracting the rotation part of the given transformation `m`.
142     ///
143     /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
144     ///
145     /// # Parameters
146     ///
147     /// * `m`: the matrix from which the rotational part is to be extracted.
148     /// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
149     /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
150     /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
151     ///           to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other
152     ///           guesses come to mind.
from_matrix_eps(m: &Matrix2<N>, eps: N, max_iter: usize, guess: Self) -> Self153     pub fn from_matrix_eps(m: &Matrix2<N>, eps: N, max_iter: usize, guess: Self) -> Self {
154         let guess = Rotation2::from(guess);
155         Rotation2::from_matrix_eps(m, eps, max_iter, guess).into()
156     }
157 
158     /// The unit complex needed to make `a` and `b` be collinear and point toward the same
159     /// direction.
160     ///
161     /// # Example
162     /// ```
163     /// # #[macro_use] extern crate approx;
164     /// # use nalgebra::{Vector2, UnitComplex};
165     /// let a = Vector2::new(1.0, 2.0);
166     /// let b = Vector2::new(2.0, 1.0);
167     /// let rot = UnitComplex::rotation_between(&a, &b);
168     /// assert_relative_eq!(rot * a, b);
169     /// assert_relative_eq!(rot.inverse() * b, a);
170     /// ```
171     #[inline]
rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self where SB: Storage<N, U2>, SC: Storage<N, U2>,172     pub fn rotation_between<SB, SC>(a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>) -> Self
173     where
174         SB: Storage<N, U2>,
175         SC: Storage<N, U2>,
176     {
177         Self::scaled_rotation_between(a, b, N::one())
178     }
179 
180     /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
181     /// direction, raised to the power `s`.
182     ///
183     /// # Example
184     /// ```
185     /// # #[macro_use] extern crate approx;
186     /// # use nalgebra::{Vector2, UnitComplex};
187     /// let a = Vector2::new(1.0, 2.0);
188     /// let b = Vector2::new(2.0, 1.0);
189     /// let rot2 = UnitComplex::scaled_rotation_between(&a, &b, 0.2);
190     /// let rot5 = UnitComplex::scaled_rotation_between(&a, &b, 0.5);
191     /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
192     /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
193     /// ```
194     #[inline]
scaled_rotation_between<SB, SC>( a: &Vector<N, U2, SB>, b: &Vector<N, U2, SC>, s: N, ) -> Self where SB: Storage<N, U2>, SC: Storage<N, U2>,195     pub fn scaled_rotation_between<SB, SC>(
196         a: &Vector<N, U2, SB>,
197         b: &Vector<N, U2, SC>,
198         s: N,
199     ) -> Self
200     where
201         SB: Storage<N, U2>,
202         SC: Storage<N, U2>,
203     {
204         // FIXME: code duplication with Rotation.
205         if let (Some(na), Some(nb)) = (
206             Unit::try_new(a.clone_owned(), N::zero()),
207             Unit::try_new(b.clone_owned(), N::zero()),
208         ) {
209             Self::scaled_rotation_between_axis(&na, &nb, s)
210         } else {
211             Self::identity()
212         }
213     }
214 
215     /// The unit complex needed to make `a` and `b` be collinear and point toward the same
216     /// direction.
217     ///
218     /// # Example
219     /// ```
220     /// # #[macro_use] extern crate approx;
221     /// # use nalgebra::{Unit, Vector2, UnitComplex};
222     /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
223     /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
224     /// let rot = UnitComplex::rotation_between_axis(&a, &b);
225     /// assert_relative_eq!(rot * a, b);
226     /// assert_relative_eq!(rot.inverse() * b, a);
227     /// ```
228     #[inline]
rotation_between_axis<SB, SC>( a: &Unit<Vector<N, U2, SB>>, b: &Unit<Vector<N, U2, SC>>, ) -> Self where SB: Storage<N, U2>, SC: Storage<N, U2>,229     pub fn rotation_between_axis<SB, SC>(
230         a: &Unit<Vector<N, U2, SB>>,
231         b: &Unit<Vector<N, U2, SC>>,
232     ) -> Self
233     where
234         SB: Storage<N, U2>,
235         SC: Storage<N, U2>,
236     {
237         Self::scaled_rotation_between_axis(a, b, N::one())
238     }
239 
240     /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
241     /// direction, raised to the power `s`.
242     ///
243     /// # Example
244     /// ```
245     /// # #[macro_use] extern crate approx;
246     /// # use nalgebra::{Unit, Vector2, UnitComplex};
247     /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
248     /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
249     /// let rot2 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.2);
250     /// let rot5 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.5);
251     /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
252     /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
253     /// ```
254     #[inline]
scaled_rotation_between_axis<SB, SC>( na: &Unit<Vector<N, U2, SB>>, nb: &Unit<Vector<N, U2, SC>>, s: N, ) -> Self where SB: Storage<N, U2>, SC: Storage<N, U2>,255     pub fn scaled_rotation_between_axis<SB, SC>(
256         na: &Unit<Vector<N, U2, SB>>,
257         nb: &Unit<Vector<N, U2, SC>>,
258         s: N,
259     ) -> Self
260     where
261         SB: Storage<N, U2>,
262         SC: Storage<N, U2>,
263     {
264         let sang = na.perp(&nb);
265         let cang = na.dot(&nb);
266 
267         Self::from_angle(sang.atan2(cang) * s)
268     }
269 }
270 
271 impl<N: RealField> One for UnitComplex<N> {
272     #[inline]
one() -> Self273     fn one() -> Self {
274         Self::identity()
275     }
276 }
277 
278 impl<N: RealField> Distribution<UnitComplex<N>> for Standard
279 where OpenClosed01: Distribution<N>
280 {
281     /// Generate a uniformly distributed random `UnitComplex`.
282     #[inline]
sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex<N>283     fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex<N> {
284         UnitComplex::from_angle(rng.sample(OpenClosed01) * N::two_pi())
285     }
286 }
287 
288 #[cfg(feature = "arbitrary")]
289 impl<N: RealField + Arbitrary> Arbitrary for UnitComplex<N> {
290     #[inline]
arbitrary<G: Gen>(g: &mut G) -> Self291     fn arbitrary<G: Gen>(g: &mut G) -> Self {
292         UnitComplex::from_angle(N::arbitrary(g))
293     }
294 }
295