nalgebra/geometry/
unit_complex.rs

1use approx::{AbsDiffEq, RelativeEq, UlpsEq};
2use num_complex::Complex;
3use std::fmt;
4
5use crate::base::{Matrix2, Matrix3, Normed, Unit, Vector1, Vector2};
6use crate::geometry::{Point2, Rotation2};
7use crate::Scalar;
8use simba::scalar::RealField;
9use simba::simd::SimdRealField;
10use std::cmp::{Eq, PartialEq};
11
12/// A 2D rotation represented as a complex number with magnitude 1.
13///
14/// All the methods specific [`UnitComplex`](crate::UnitComplex) are listed here. You may also
15/// read the documentation of the [`Complex`](crate::Complex) type which
16/// is used internally and accessible with `unit_complex.complex()`.
17///
18/// # Construction
19/// * [Identity <span style="float:right;">`identity`</span>](#identity)
20/// * [From a 2D rotation angle <span style="float:right;">`new`, `from_cos_sin_unchecked`…</span>](#construction-from-a-2d-rotation-angle)
21/// * [From an existing 2D matrix or complex number <span style="float:right;">`from_matrix`, `rotation_to`, `powf`…</span>](#construction-from-an-existing-2d-matrix-or-complex-number)
22/// * [From two vectors <span style="float:right;">`rotation_between`, `scaled_rotation_between_axis`…</span>](#construction-from-two-vectors)
23///
24/// # Transformation and composition
25/// * [Angle extraction <span style="float:right;">`angle`, `angle_to`…</span>](#angle-extraction)
26/// * [Transformation of a vector or a point <span style="float:right;">`transform_vector`, `inverse_transform_point`…</span>](#transformation-of-a-vector-or-a-point)
27/// * [Conjugation and inversion <span style="float:right;">`conjugate`, `inverse_mut`…</span>](#conjugation-and-inversion)
28/// * [Interpolation <span style="float:right;">`slerp`…</span>](#interpolation)
29///
30/// # Conversion
31/// * [Conversion to a matrix <span style="float:right;">`to_rotation_matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
32pub type UnitComplex<T> = Unit<Complex<T>>;
33
34impl<T: Scalar + PartialEq> PartialEq for UnitComplex<T> {
35    #[inline]
36    fn eq(&self, rhs: &Self) -> bool {
37        (**self).eq(&**rhs)
38    }
39}
40
41impl<T: Scalar + Eq> Eq for UnitComplex<T> {}
42
43impl<T: SimdRealField> Normed for Complex<T> {
44    type Norm = T::SimdRealField;
45
46    #[inline]
47    fn norm(&self) -> T::SimdRealField {
48        // We don't use `.norm_sqr()` because it requires
49        // some very strong Num trait requirements.
50        (self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone()).simd_sqrt()
51    }
52
53    #[inline]
54    fn norm_squared(&self) -> T::SimdRealField {
55        // We don't use `.norm_sqr()` because it requires
56        // some very strong Num trait requirements.
57        self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone()
58    }
59
60    #[inline]
61    fn scale_mut(&mut self, n: Self::Norm) {
62        self.re *= n.clone();
63        self.im *= n;
64    }
65
66    #[inline]
67    fn unscale_mut(&mut self, n: Self::Norm) {
68        self.re /= n.clone();
69        self.im /= n;
70    }
71}
72
73/// # Angle extraction
74impl<T: SimdRealField> UnitComplex<T>
75where
76    T::Element: SimdRealField,
77{
78    /// The rotation angle in `]-pi; pi]` of this unit complex number.
79    ///
80    /// # Example
81    /// ```
82    /// # use nalgebra::UnitComplex;
83    /// let rot = UnitComplex::new(1.78);
84    /// assert_eq!(rot.angle(), 1.78);
85    /// ```
86    #[inline]
87    #[must_use]
88    pub fn angle(&self) -> T {
89        self.im.clone().simd_atan2(self.re.clone())
90    }
91
92    /// The sine of the rotation angle.
93    ///
94    /// # Example
95    /// ```
96    /// # use nalgebra::UnitComplex;
97    /// let angle = 1.78f32;
98    /// let rot = UnitComplex::new(angle);
99    /// assert_eq!(rot.sin_angle(), angle.sin());
100    /// ```
101    #[inline]
102    #[must_use]
103    pub fn sin_angle(&self) -> T {
104        self.im.clone()
105    }
106
107    /// The cosine of the rotation angle.
108    ///
109    /// # Example
110    /// ```
111    /// # use nalgebra::UnitComplex;
112    /// let angle = 1.78f32;
113    /// let rot = UnitComplex::new(angle);
114    /// assert_eq!(rot.cos_angle(),angle.cos());
115    /// ```
116    #[inline]
117    #[must_use]
118    pub fn cos_angle(&self) -> T {
119        self.re.clone()
120    }
121
122    /// The rotation angle returned as a 1-dimensional vector.
123    ///
124    /// This is generally used in the context of generic programming. Using
125    /// the `.angle()` method instead is more common.
126    #[inline]
127    #[must_use]
128    pub fn scaled_axis(&self) -> Vector1<T> {
129        Vector1::new(self.angle())
130    }
131
132    /// The rotation axis and angle in (0, pi] of this complex number.
133    ///
134    /// This is generally used in the context of generic programming. Using
135    /// the `.angle()` method instead is more common.
136    /// Returns `None` if the angle is zero.
137    #[inline]
138    #[must_use]
139    pub fn axis_angle(&self) -> Option<(Unit<Vector1<T>>, T)>
140    where
141        T: RealField,
142    {
143        let ang = self.angle();
144
145        if ang.is_zero() {
146            None
147        } else if ang.is_sign_positive() {
148            Some((Unit::new_unchecked(Vector1::x()), ang))
149        } else {
150            Some((Unit::new_unchecked(-Vector1::<T>::x()), -ang))
151        }
152    }
153
154    /// The rotation angle needed to make `self` and `other` coincide.
155    ///
156    /// # Example
157    /// ```
158    /// # #[macro_use] extern crate approx;
159    /// # use nalgebra::UnitComplex;
160    /// let rot1 = UnitComplex::new(0.1);
161    /// let rot2 = UnitComplex::new(1.7);
162    /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
163    /// ```
164    #[inline]
165    #[must_use]
166    pub fn angle_to(&self, other: &Self) -> T {
167        let delta = self.rotation_to(other);
168        delta.angle()
169    }
170}
171
172/// # Conjugation and inversion
173impl<T: SimdRealField> UnitComplex<T>
174where
175    T::Element: SimdRealField,
176{
177    /// Compute the conjugate of this unit complex number.
178    ///
179    /// # Example
180    /// ```
181    /// # use nalgebra::UnitComplex;
182    /// let rot = UnitComplex::new(1.78);
183    /// let conj = rot.conjugate();
184    /// assert_eq!(rot.complex().im, -conj.complex().im);
185    /// assert_eq!(rot.complex().re, conj.complex().re);
186    /// ```
187    #[inline]
188    #[must_use = "Did you mean to use conjugate_mut()?"]
189    pub fn conjugate(&self) -> Self {
190        Self::new_unchecked(self.conj())
191    }
192
193    /// Inverts this complex number if it is not zero.
194    ///
195    /// # Example
196    /// ```
197    /// # #[macro_use] extern crate approx;
198    /// # use nalgebra::UnitComplex;
199    /// let rot = UnitComplex::new(1.2);
200    /// let inv = rot.inverse();
201    /// assert_relative_eq!(rot * inv, UnitComplex::identity(), epsilon = 1.0e-6);
202    /// assert_relative_eq!(inv * rot, UnitComplex::identity(), epsilon = 1.0e-6);
203    /// ```
204    #[inline]
205    #[must_use = "Did you mean to use inverse_mut()?"]
206    pub fn inverse(&self) -> Self {
207        self.conjugate()
208    }
209
210    /// Compute in-place the conjugate of this unit complex number.
211    ///
212    /// # Example
213    /// ```
214    /// # #[macro_use] extern crate approx;
215    /// # use nalgebra::UnitComplex;
216    /// let angle = 1.7;
217    /// let rot = UnitComplex::new(angle);
218    /// let mut conj = UnitComplex::new(angle);
219    /// conj.conjugate_mut();
220    /// assert_eq!(rot.complex().im, -conj.complex().im);
221    /// assert_eq!(rot.complex().re, conj.complex().re);
222    /// ```
223    #[inline]
224    pub fn conjugate_mut(&mut self) {
225        let me = self.as_mut_unchecked();
226        me.im = -me.im.clone();
227    }
228
229    /// Inverts in-place this unit complex number.
230    ///
231    /// # Example
232    /// ```
233    /// # #[macro_use] extern crate approx;
234    /// # use nalgebra::UnitComplex;
235    /// let angle = 1.7;
236    /// let mut rot = UnitComplex::new(angle);
237    /// rot.inverse_mut();
238    /// assert_relative_eq!(rot * UnitComplex::new(angle), UnitComplex::identity());
239    /// assert_relative_eq!(UnitComplex::new(angle) * rot, UnitComplex::identity());
240    /// ```
241    #[inline]
242    pub fn inverse_mut(&mut self) {
243        self.conjugate_mut()
244    }
245}
246
247/// # Conversion to a matrix
248impl<T: SimdRealField> UnitComplex<T>
249where
250    T::Element: SimdRealField,
251{
252    /// Builds the rotation matrix corresponding to this unit complex number.
253    ///
254    /// # Example
255    /// ```
256    /// # use nalgebra::{UnitComplex, Rotation2};
257    /// # use std::f32;
258    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_6);
259    /// let expected = Rotation2::new(f32::consts::FRAC_PI_6);
260    /// assert_eq!(rot.to_rotation_matrix(), expected);
261    /// ```
262    #[inline]
263    #[must_use]
264    pub fn to_rotation_matrix(self) -> Rotation2<T> {
265        let r = self.re.clone();
266        let i = self.im.clone();
267
268        Rotation2::from_matrix_unchecked(Matrix2::new(r.clone(), -i.clone(), i, r))
269    }
270
271    /// Converts this unit complex number into its equivalent homogeneous transformation matrix.
272    ///
273    /// # Example
274    /// ```
275    /// # use nalgebra::{UnitComplex, Matrix3};
276    /// # use std::f32;
277    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_6);
278    /// let expected = Matrix3::new(0.8660254, -0.5,      0.0,
279    ///                             0.5,       0.8660254, 0.0,
280    ///                             0.0,       0.0,       1.0);
281    /// assert_eq!(rot.to_homogeneous(), expected);
282    /// ```
283    #[inline]
284    #[must_use]
285    pub fn to_homogeneous(self) -> Matrix3<T> {
286        self.to_rotation_matrix().to_homogeneous()
287    }
288}
289
290/// # Transformation of a vector or a point
291impl<T: SimdRealField> UnitComplex<T>
292where
293    T::Element: SimdRealField,
294{
295    /// Rotate the given point by this unit complex number.
296    ///
297    /// This is the same as the multiplication `self * pt`.
298    ///
299    /// # Example
300    /// ```
301    /// # #[macro_use] extern crate approx;
302    /// # use nalgebra::{UnitComplex, Point2};
303    /// # use std::f32;
304    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
305    /// let transformed_point = rot.transform_point(&Point2::new(1.0, 2.0));
306    /// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6);
307    /// ```
308    #[inline]
309    #[must_use]
310    pub fn transform_point(&self, pt: &Point2<T>) -> Point2<T> {
311        self * pt
312    }
313
314    /// Rotate the given vector by this unit complex number.
315    ///
316    /// This is the same as the multiplication `self * v`.
317    ///
318    /// # Example
319    /// ```
320    /// # #[macro_use] extern crate approx;
321    /// # use nalgebra::{UnitComplex, Vector2};
322    /// # use std::f32;
323    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
324    /// let transformed_vector = rot.transform_vector(&Vector2::new(1.0, 2.0));
325    /// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6);
326    /// ```
327    #[inline]
328    #[must_use]
329    pub fn transform_vector(&self, v: &Vector2<T>) -> Vector2<T> {
330        self * v
331    }
332
333    /// Rotate the given point by the inverse of this unit complex number.
334    ///
335    /// # Example
336    /// ```
337    /// # #[macro_use] extern crate approx;
338    /// # use nalgebra::{UnitComplex, Point2};
339    /// # use std::f32;
340    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
341    /// let transformed_point = rot.inverse_transform_point(&Point2::new(1.0, 2.0));
342    /// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6);
343    /// ```
344    #[inline]
345    #[must_use]
346    pub fn inverse_transform_point(&self, pt: &Point2<T>) -> Point2<T> {
347        // TODO: would it be useful performance-wise not to call inverse explicitly (i-e. implement
348        // the inverse transformation explicitly here) ?
349        self.inverse() * pt
350    }
351
352    /// Rotate the given vector by the inverse of this unit complex number.
353    ///
354    /// # Example
355    /// ```
356    /// # #[macro_use] extern crate approx;
357    /// # use nalgebra::{UnitComplex, Vector2};
358    /// # use std::f32;
359    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
360    /// let transformed_vector = rot.inverse_transform_vector(&Vector2::new(1.0, 2.0));
361    /// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6);
362    /// ```
363    #[inline]
364    #[must_use]
365    pub fn inverse_transform_vector(&self, v: &Vector2<T>) -> Vector2<T> {
366        self.inverse() * v
367    }
368
369    /// Rotate the given vector by the inverse of this unit complex number.
370    ///
371    /// # Example
372    /// ```
373    /// # #[macro_use] extern crate approx;
374    /// # use nalgebra::{UnitComplex, Vector2};
375    /// # use std::f32;
376    /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
377    /// let transformed_vector = rot.inverse_transform_unit_vector(&Vector2::x_axis());
378    /// assert_relative_eq!(transformed_vector, -Vector2::y_axis(), epsilon = 1.0e-6);
379    /// ```
380    #[inline]
381    #[must_use]
382    pub fn inverse_transform_unit_vector(&self, v: &Unit<Vector2<T>>) -> Unit<Vector2<T>> {
383        self.inverse() * v
384    }
385}
386
387/// # Interpolation
388impl<T: SimdRealField> UnitComplex<T>
389where
390    T::Element: SimdRealField,
391{
392    /// Spherical linear interpolation between two rotations represented as unit complex numbers.
393    ///
394    /// # Examples:
395    ///
396    /// ```
397    /// # #[macro_use] extern crate approx;
398    /// # use nalgebra::geometry::UnitComplex;
399    ///
400    /// let rot1 = UnitComplex::new(std::f32::consts::FRAC_PI_4);
401    /// let rot2 = UnitComplex::new(-std::f32::consts::PI);
402    ///
403    /// let rot = rot1.slerp(&rot2, 1.0 / 3.0);
404    ///
405    /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2);
406    /// ```
407    #[inline]
408    #[must_use]
409    pub fn slerp(&self, other: &Self, t: T) -> Self {
410        let delta = other / self;
411        self * Self::new(delta.angle() * t)
412    }
413}
414
415impl<T: RealField + fmt::Display> fmt::Display for UnitComplex<T> {
416    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417        write!(f, "UnitComplex angle: {}", self.angle())
418    }
419}
420
421impl<T: RealField> AbsDiffEq for UnitComplex<T> {
422    type Epsilon = T;
423
424    #[inline]
425    fn default_epsilon() -> Self::Epsilon {
426        T::default_epsilon()
427    }
428
429    #[inline]
430    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
431        self.re.abs_diff_eq(&other.re, epsilon.clone()) && self.im.abs_diff_eq(&other.im, epsilon)
432    }
433}
434
435impl<T: RealField> RelativeEq for UnitComplex<T> {
436    #[inline]
437    fn default_max_relative() -> Self::Epsilon {
438        T::default_max_relative()
439    }
440
441    #[inline]
442    fn relative_eq(
443        &self,
444        other: &Self,
445        epsilon: Self::Epsilon,
446        max_relative: Self::Epsilon,
447    ) -> bool {
448        self.re
449            .relative_eq(&other.re, epsilon.clone(), max_relative.clone())
450            && self.im.relative_eq(&other.im, epsilon, max_relative)
451    }
452}
453
454impl<T: RealField> UlpsEq for UnitComplex<T> {
455    #[inline]
456    fn default_max_ulps() -> u32 {
457        T::default_max_ulps()
458    }
459
460    #[inline]
461    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
462        self.re.ulps_eq(&other.re, epsilon.clone(), max_ulps)
463            && self.im.ulps_eq(&other.im, epsilon, max_ulps)
464    }
465}