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}