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}