cgmath/
rotation.rs

1// Copyright 2014 The CGMath Developers. For a full listing of the authors,
2// refer to the Cargo.toml file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use std::fmt;
17use std::iter;
18use std::ops::*;
19
20use structure::*;
21
22use angle::Rad;
23use approx;
24use euler::Euler;
25use matrix::{Matrix2, Matrix3};
26use num::BaseFloat;
27use point::{Point2, Point3};
28use quaternion::Quaternion;
29use vector::{Vector2, Vector3};
30
31/// A trait for a generic rotation. A rotation is a transformation that
32/// creates a circular motion, and preserves at least one point in the space.
33pub trait Rotation: Sized + Copy + One
34where
35    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
36    Self: approx::AbsDiffEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
37    Self: approx::RelativeEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
38    Self: approx::UlpsEq<Epsilon = <<Self as Rotation>::Space as EuclideanSpace>::Scalar>,
39    <Self::Space as EuclideanSpace>::Scalar: BaseFloat,
40    Self: iter::Product<Self>,
41{
42    type Space: EuclideanSpace;
43
44    /// Create a rotation to a given direction with an 'up' vector.
45    fn look_at(
46        dir: <Self::Space as EuclideanSpace>::Diff,
47        up: <Self::Space as EuclideanSpace>::Diff,
48    ) -> Self;
49
50    /// Create a shortest rotation to transform vector 'a' into 'b'.
51    /// Both given vectors are assumed to have unit length.
52    fn between_vectors(
53        a: <Self::Space as EuclideanSpace>::Diff,
54        b: <Self::Space as EuclideanSpace>::Diff,
55    ) -> Self;
56
57    /// Rotate a vector using this rotation.
58    fn rotate_vector(
59        &self,
60        vec: <Self::Space as EuclideanSpace>::Diff,
61    ) -> <Self::Space as EuclideanSpace>::Diff;
62
63    /// Rotate a point using this rotation, by converting it to its
64    /// representation as a vector.
65    #[inline]
66    fn rotate_point(&self, point: Self::Space) -> Self::Space {
67        Self::Space::from_vec(self.rotate_vector(point.to_vec()))
68    }
69
70    /// Create a new rotation which "un-does" this rotation. That is,
71    /// `r * r.invert()` is the identity.
72    fn invert(&self) -> Self;
73}
74
75/// A two-dimensional rotation.
76pub trait Rotation2:
77    Rotation<Space = Point2<<Self as Rotation2>::Scalar>>
78    + Into<Matrix2<<Self as Rotation2>::Scalar>>
79    + Into<Basis2<<Self as Rotation2>::Scalar>>
80{
81    type Scalar: BaseFloat;
82
83    /// Create a rotation by a given angle. Thus is a redundant case of both
84    /// from_axis_angle() and from_euler() for 2D space.
85    fn from_angle<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self;
86}
87
88/// A three-dimensional rotation.
89pub trait Rotation3:
90    Rotation<Space = Point3<<Self as Rotation3>::Scalar>>
91    + Into<Matrix3<<Self as Rotation3>::Scalar>>
92    + Into<Basis3<<Self as Rotation3>::Scalar>>
93    + Into<Quaternion<<Self as Rotation3>::Scalar>>
94    + From<Euler<Rad<<Self as Rotation3>::Scalar>>>
95{
96    type Scalar: BaseFloat;
97
98    /// Create a rotation using an angle around a given axis.
99    ///
100    /// The specified axis **must be normalized**, or it represents an invalid rotation.
101    fn from_axis_angle<A: Into<Rad<Self::Scalar>>>(axis: Vector3<Self::Scalar>, angle: A) -> Self;
102
103    /// Create a rotation from an angle around the `x` axis (pitch).
104    #[inline]
105    fn from_angle_x<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
106        Rotation3::from_axis_angle(Vector3::unit_x(), theta)
107    }
108
109    /// Create a rotation from an angle around the `y` axis (yaw).
110    #[inline]
111    fn from_angle_y<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
112        Rotation3::from_axis_angle(Vector3::unit_y(), theta)
113    }
114
115    /// Create a rotation from an angle around the `z` axis (roll).
116    #[inline]
117    fn from_angle_z<A: Into<Rad<Self::Scalar>>>(theta: A) -> Self {
118        Rotation3::from_axis_angle(Vector3::unit_z(), theta)
119    }
120}
121
122/// A two-dimensional rotation matrix.
123///
124/// The matrix is guaranteed to be orthogonal, so some operations can be
125/// implemented more efficiently than the implementations for `math::Matrix2`. To
126/// enforce orthogonality at the type level the operations have been restricted
127/// to a subset of those implemented on `Matrix2`.
128///
129/// ## Example
130///
131/// Suppose we want to rotate a vector that lies in the x-y plane by some
132/// angle. We can accomplish this quite easily with a two-dimensional rotation
133/// matrix:
134///
135/// ```no_run
136/// use cgmath::Rad;
137/// use cgmath::Vector2;
138/// use cgmath::{Matrix, Matrix2};
139/// use cgmath::{Rotation, Rotation2, Basis2};
140/// use cgmath::UlpsEq;
141/// use std::f64;
142///
143/// // For simplicity, we will rotate the unit x vector to the unit y vector --
144/// // so the angle is 90 degrees, or π/2.
145/// let unit_x: Vector2<f64> = Vector2::unit_x();
146/// let rot: Basis2<f64> = Rotation2::from_angle(Rad(0.5f64 * f64::consts::PI));
147///
148/// // Rotate the vector using the two-dimensional rotation matrix:
149/// let unit_y = rot.rotate_vector(unit_x);
150///
151/// // Since sin(π/2) may not be exactly zero due to rounding errors, we can
152/// // use approx's assert_ulps_eq!() feature to show that it is close enough.
153/// // assert_ulps_eq!(&unit_y, &Vector2::unit_y()); // TODO: Figure out how to use this
154///
155/// // This is exactly equivalent to using the raw matrix itself:
156/// let unit_y2: Matrix2<_> = rot.into();
157/// let unit_y2 = unit_y2 * unit_x;
158/// assert_eq!(unit_y2, unit_y);
159///
160/// // Note that we can also concatenate rotations:
161/// let rot_half: Basis2<f64> = Rotation2::from_angle(Rad(0.25f64 * f64::consts::PI));
162/// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x);
163/// // assert_ulps_eq!(&unit_y3, &unit_y2); // TODO: Figure out how to use this
164/// ```
165#[derive(PartialEq, Copy, Clone)]
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
167pub struct Basis2<S> {
168    mat: Matrix2<S>,
169}
170
171impl<S: BaseFloat> Basis2<S> {
172    pub fn look_at_stable(dir: Vector2<S>, flip: bool) -> Basis2<S> {
173        Basis2 {
174            mat: Matrix2::look_at_stable(dir, flip),
175        }
176    }
177}
178
179impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
180    #[inline]
181    fn as_ref(&self) -> &Matrix2<S> {
182        &self.mat
183    }
184}
185
186impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
187    #[inline]
188    fn from(b: Basis2<S>) -> Matrix2<S> {
189        b.mat
190    }
191}
192
193impl<S: BaseFloat> iter::Product<Basis2<S>> for Basis2<S> {
194    #[inline]
195    fn product<I: Iterator<Item = Basis2<S>>>(iter: I) -> Basis2<S> {
196        iter.fold(Basis2::one(), Mul::mul)
197    }
198}
199
200impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
201    #[inline]
202    fn product<I: Iterator<Item = &'a Basis2<S>>>(iter: I) -> Basis2<S> {
203        iter.fold(Basis2::one(), Mul::mul)
204    }
205}
206
207impl<S: BaseFloat> Rotation for Basis2<S> {
208    type Space = Point2<S>;
209
210    #[inline]
211    fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
212        Basis2 {
213            mat: Matrix2::look_at(dir, up),
214        }
215    }
216
217    #[inline]
218    fn between_vectors(a: Vector2<S>, b: Vector2<S>) -> Basis2<S> {
219        Rotation2::from_angle(Rad::acos(a.dot(b)))
220    }
221
222    #[inline]
223    fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> {
224        self.mat * vec
225    }
226
227    // TODO: we know the matrix is orthogonal, so this could be re-written
228    // to be faster
229    #[inline]
230    fn invert(&self) -> Basis2<S> {
231        Basis2 {
232            mat: self.mat.invert().unwrap(),
233        }
234    }
235}
236
237impl<S: BaseFloat> One for Basis2<S> {
238    #[inline]
239    fn one() -> Basis2<S> {
240        Basis2 {
241            mat: Matrix2::one(),
242        }
243    }
244}
245
246impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> {
247    fn mul(lhs, rhs) -> Basis2<S> { Basis2 { mat: lhs.mat * rhs.mat  } }
248});
249
250impl<S: BaseFloat> approx::AbsDiffEq for Basis2<S> {
251    type Epsilon = S::Epsilon;
252
253    #[inline]
254    fn default_epsilon() -> S::Epsilon {
255        S::default_epsilon()
256    }
257
258    #[inline]
259    fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool {
260        Matrix2::abs_diff_eq(&self.mat, &other.mat, epsilon)
261    }
262}
263
264impl<S: BaseFloat> approx::RelativeEq for Basis2<S> {
265    #[inline]
266    fn default_max_relative() -> S::Epsilon {
267        S::default_max_relative()
268    }
269
270    #[inline]
271    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
272        Matrix2::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
273    }
274}
275
276impl<S: BaseFloat> approx::UlpsEq for Basis2<S> {
277    #[inline]
278    fn default_max_ulps() -> u32 {
279        S::default_max_ulps()
280    }
281
282    #[inline]
283    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
284        Matrix2::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
285    }
286}
287
288impl<S: BaseFloat> Rotation2 for Basis2<S> {
289    type Scalar = S;
290
291    fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> {
292        Basis2 {
293            mat: Matrix2::from_angle(theta),
294        }
295    }
296}
297
298impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
299    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300        write!(f, "Basis2 ")?;
301        <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f)
302    }
303}
304
305/// A three-dimensional rotation matrix.
306///
307/// The matrix is guaranteed to be orthogonal, so some operations, specifically
308/// inversion, can be implemented more efficiently than the implementations for
309/// `math::Matrix3`. To ensure orthogonality is maintained, the operations have
310/// been restricted to a subset of those implemented on `Matrix3`.
311#[derive(PartialEq, Copy, Clone)]
312#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
313pub struct Basis3<S> {
314    mat: Matrix3<S>,
315}
316
317impl<S: BaseFloat> Basis3<S> {
318    /// Create a new rotation matrix from a quaternion.
319    #[inline]
320    pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
321        Basis3 {
322            mat: quaternion.clone().into(),
323        }
324    }
325}
326
327impl<S> AsRef<Matrix3<S>> for Basis3<S> {
328    #[inline]
329    fn as_ref(&self) -> &Matrix3<S> {
330        &self.mat
331    }
332}
333
334impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
335    #[inline]
336    fn from(b: Basis3<S>) -> Matrix3<S> {
337        b.mat
338    }
339}
340
341impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
342    #[inline]
343    fn from(b: Basis3<S>) -> Quaternion<S> {
344        b.mat.into()
345    }
346}
347
348impl<S: BaseFloat> iter::Product<Basis3<S>> for Basis3<S> {
349    #[inline]
350    fn product<I: Iterator<Item = Basis3<S>>>(iter: I) -> Basis3<S> {
351        iter.fold(Basis3::one(), Mul::mul)
352    }
353}
354
355impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> {
356    #[inline]
357    fn product<I: Iterator<Item = &'a Basis3<S>>>(iter: I) -> Basis3<S> {
358        iter.fold(Basis3::one(), Mul::mul)
359    }
360}
361
362impl<S: BaseFloat> Rotation for Basis3<S> {
363    type Space = Point3<S>;
364
365    #[inline]
366    fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
367        Basis3 {
368            mat: Matrix3::look_to_lh(dir, up),
369        }
370    }
371
372    #[inline]
373    fn between_vectors(a: Vector3<S>, b: Vector3<S>) -> Basis3<S> {
374        let q: Quaternion<S> = Rotation::between_vectors(a, b);
375        q.into()
376    }
377
378    #[inline]
379    fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> {
380        self.mat * vec
381    }
382
383    // TODO: we know the matrix is orthogonal, so this could be re-written
384    // to be faster
385    #[inline]
386    fn invert(&self) -> Basis3<S> {
387        Basis3 {
388            mat: self.mat.invert().unwrap(),
389        }
390    }
391}
392
393impl<S: BaseFloat> One for Basis3<S> {
394    #[inline]
395    fn one() -> Basis3<S> {
396        Basis3 {
397            mat: Matrix3::one(),
398        }
399    }
400}
401
402impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> {
403    fn mul(lhs, rhs) -> Basis3<S> { Basis3 { mat: lhs.mat * rhs.mat  } }
404});
405
406impl<S: BaseFloat> approx::AbsDiffEq for Basis3<S> {
407    type Epsilon = S::Epsilon;
408
409    #[inline]
410    fn default_epsilon() -> S::Epsilon {
411        S::default_epsilon()
412    }
413
414    #[inline]
415    fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool {
416        Matrix3::abs_diff_eq(&self.mat, &other.mat, epsilon)
417    }
418}
419
420impl<S: BaseFloat> approx::RelativeEq for Basis3<S> {
421    #[inline]
422    fn default_max_relative() -> S::Epsilon {
423        S::default_max_relative()
424    }
425
426    #[inline]
427    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
428        Matrix3::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
429    }
430}
431
432impl<S: BaseFloat> approx::UlpsEq for Basis3<S> {
433    #[inline]
434    fn default_max_ulps() -> u32 {
435        S::default_max_ulps()
436    }
437
438    #[inline]
439    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
440        Matrix3::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
441    }
442}
443
444impl<S: BaseFloat> Rotation3 for Basis3<S> {
445    type Scalar = S;
446
447    fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
448        Basis3 {
449            mat: Matrix3::from_axis_angle(axis, angle),
450        }
451    }
452
453    fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
454        Basis3 {
455            mat: Matrix3::from_angle_x(theta),
456        }
457    }
458
459    fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
460        Basis3 {
461            mat: Matrix3::from_angle_y(theta),
462        }
463    }
464
465    fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
466        Basis3 {
467            mat: Matrix3::from_angle_z(theta),
468        }
469    }
470}
471
472impl<A: Angle> From<Euler<A>> for Basis3<A::Unitless>
473where
474    A: Into<Rad<<A as Angle>::Unitless>>,
475{
476    /// Create a three-dimensional rotation matrix from a set of euler angles.
477    fn from(src: Euler<A>) -> Basis3<A::Unitless> {
478        Basis3 {
479            mat: Matrix3::from(src),
480        }
481    }
482}
483
484impl<S: fmt::Debug> fmt::Debug for Basis3<S> {
485    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
486        write!(f, "Basis3 ")?;
487        <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f)
488    }
489}