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