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}