nalgebra/geometry/
isometry_construction.rs

1#[cfg(feature = "arbitrary")]
2use crate::base::storage::Owned;
3#[cfg(feature = "arbitrary")]
4use quickcheck::{Arbitrary, Gen};
5
6use num::One;
7#[cfg(feature = "rand-no-std")]
8use rand::{
9    distributions::{Distribution, Standard},
10    Rng,
11};
12
13use simba::scalar::SupersetOf;
14use simba::simd::SimdRealField;
15
16use crate::base::{Vector2, Vector3};
17
18use crate::{
19    AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point,
20    Point3, Rotation, Rotation3, Scalar, Translation, Translation2, Translation3, UnitComplex,
21    UnitQuaternion,
22};
23
24impl<T: SimdRealField, R: AbstractRotation<T, D>, const D: usize> Default for Isometry<T, R, D>
25where
26    T::Element: SimdRealField,
27{
28    fn default() -> Self {
29        Self::identity()
30    }
31}
32
33impl<T: SimdRealField, R: AbstractRotation<T, D>, const D: usize> Isometry<T, R, D>
34where
35    T::Element: SimdRealField,
36{
37    /// Creates a new identity isometry.
38    ///
39    /// # Example
40    ///
41    /// ```
42    /// # use nalgebra::{Isometry2, Point2, Isometry3, Point3};
43    ///
44    /// let iso = Isometry2::identity();
45    /// let pt = Point2::new(1.0, 2.0);
46    /// assert_eq!(iso * pt, pt);
47    ///
48    /// let iso = Isometry3::identity();
49    /// let pt = Point3::new(1.0, 2.0, 3.0);
50    /// assert_eq!(iso * pt, pt);
51    /// ```
52    #[inline]
53    pub fn identity() -> Self {
54        Self::from_parts(Translation::identity(), R::identity())
55    }
56
57    /// The isometry that applies the rotation `r` with its axis passing through the point `p`.
58    /// This effectively lets `p` invariant.
59    ///
60    /// # Example
61    ///
62    /// ```
63    /// # #[macro_use] extern crate approx;
64    /// # use std::f32;
65    /// # use nalgebra::{Isometry2, Point2, UnitComplex};
66    /// let rot = UnitComplex::new(f32::consts::PI);
67    /// let pt = Point2::new(1.0, 0.0);
68    /// let iso = Isometry2::rotation_wrt_point(rot, pt);
69    ///
70    /// assert_eq!(iso * pt, pt); // The rotation center is not affected.
71    /// assert_relative_eq!(iso * Point2::new(1.0, 2.0), Point2::new(1.0, -2.0), epsilon = 1.0e-6);
72    /// ```
73    #[inline]
74    pub fn rotation_wrt_point(r: R, p: Point<T, D>) -> Self {
75        let shift = r.transform_vector(&-&p.coords);
76        Self::from_parts(Translation::from(shift + p.coords), r)
77    }
78}
79
80impl<T: SimdRealField, R: AbstractRotation<T, D>, const D: usize> One for Isometry<T, R, D>
81where
82    T::Element: SimdRealField,
83{
84    /// Creates a new identity isometry.
85    #[inline]
86    fn one() -> Self {
87        Self::identity()
88    }
89}
90
91#[cfg(feature = "rand-no-std")]
92impl<T: crate::RealField, R, const D: usize> Distribution<Isometry<T, R, D>> for Standard
93where
94    R: AbstractRotation<T, D>,
95    Standard: Distribution<T> + Distribution<R>,
96{
97    #[inline]
98    fn sample<G: Rng + ?Sized>(&self, rng: &mut G) -> Isometry<T, R, D> {
99        Isometry::from_parts(rng.gen(), rng.gen())
100    }
101}
102
103#[cfg(feature = "arbitrary")]
104impl<T, R, const D: usize> Arbitrary for Isometry<T, R, D>
105where
106    T: SimdRealField + Arbitrary + Send,
107    T::Element: SimdRealField,
108    R: AbstractRotation<T, D> + Arbitrary + Send,
109    Owned<T, crate::Const<D>>: Send,
110{
111    #[inline]
112    fn arbitrary(rng: &mut Gen) -> Self {
113        Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
114    }
115}
116
117/*
118 *
119 * Constructors for various static dimensions.
120 *
121 */
122
123/// # Construction from a 2D vector and/or a rotation angle
124impl<T: SimdRealField> IsometryMatrix2<T>
125where
126    T::Element: SimdRealField,
127{
128    /// Creates a new 2D isometry from a translation and a rotation angle.
129    ///
130    /// Its rotational part is represented as a 2x2 rotation matrix.
131    ///
132    /// # Example
133    ///
134    /// ```
135    /// # use std::f32;
136    /// # use nalgebra::{Isometry2, Vector2, Point2};
137    /// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
138    ///
139    /// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0));
140    /// ```
141    #[inline]
142    pub fn new(translation: Vector2<T>, angle: T) -> Self {
143        Self::from_parts(Translation::from(translation), Rotation::<T, 2>::new(angle))
144    }
145
146    /// Creates a new isometry from the given translation coordinates.
147    #[inline]
148    pub fn translation(x: T, y: T) -> Self {
149        Self::new(Vector2::new(x, y), T::zero())
150    }
151
152    /// Creates a new isometry from the given rotation angle.
153    #[inline]
154    pub fn rotation(angle: T) -> Self {
155        Self::new(Vector2::zeros(), angle)
156    }
157
158    /// Cast the components of `self` to another type.
159    ///
160    /// # Example
161    /// ```
162    /// # use nalgebra::IsometryMatrix2;
163    /// let iso = IsometryMatrix2::<f64>::identity();
164    /// let iso2 = iso.cast::<f32>();
165    /// assert_eq!(iso2, IsometryMatrix2::<f32>::identity());
166    /// ```
167    pub fn cast<To: Scalar>(self) -> IsometryMatrix2<To>
168    where
169        IsometryMatrix2<To>: SupersetOf<Self>,
170    {
171        crate::convert(self)
172    }
173}
174
175impl<T: SimdRealField> Isometry2<T>
176where
177    T::Element: SimdRealField,
178{
179    /// Creates a new 2D isometry from a translation and a rotation angle.
180    ///
181    /// Its rotational part is represented as an unit complex number.
182    ///
183    /// # Example
184    ///
185    /// ```
186    /// # use std::f32;
187    /// # use nalgebra::{IsometryMatrix2, Point2, Vector2};
188    /// let iso = IsometryMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
189    ///
190    /// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0));
191    /// ```
192    #[inline]
193    pub fn new(translation: Vector2<T>, angle: T) -> Self {
194        Self::from_parts(
195            Translation::from(translation),
196            UnitComplex::from_angle(angle),
197        )
198    }
199
200    /// Creates a new isometry from the given translation coordinates.
201    #[inline]
202    pub fn translation(x: T, y: T) -> Self {
203        Self::from_parts(Translation2::new(x, y), UnitComplex::identity())
204    }
205
206    /// Creates a new isometry from the given rotation angle.
207    #[inline]
208    pub fn rotation(angle: T) -> Self {
209        Self::new(Vector2::zeros(), angle)
210    }
211
212    /// Cast the components of `self` to another type.
213    ///
214    /// # Example
215    /// ```
216    /// # use nalgebra::Isometry2;
217    /// let iso = Isometry2::<f64>::identity();
218    /// let iso2 = iso.cast::<f32>();
219    /// assert_eq!(iso2, Isometry2::<f32>::identity());
220    /// ```
221    pub fn cast<To: Scalar>(self) -> Isometry2<To>
222    where
223        Isometry2<To>: SupersetOf<Self>,
224    {
225        crate::convert(self)
226    }
227}
228
229// 3D rotation.
230macro_rules! basic_isometry_construction_impl(
231    ($RotId: ident < $($RotParams: ident),*>) => {
232        /// Creates a new isometry from a translation and a rotation axis-angle.
233        ///
234        /// # Example
235        ///
236        /// ```
237        /// # #[macro_use] extern crate approx;
238        /// # use std::f32;
239        /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
240        /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
241        /// let translation = Vector3::new(1.0, 2.0, 3.0);
242        /// // Point and vector being transformed in the tests.
243        /// let pt = Point3::new(4.0, 5.0, 6.0);
244        /// let vec = Vector3::new(4.0, 5.0, 6.0);
245        ///
246        /// // Isometry with its rotation part represented as a UnitQuaternion
247        /// let iso = Isometry3::new(translation, axisangle);
248        /// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
249        /// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
250        ///
251        /// // Isometry with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
252        /// let iso = IsometryMatrix3::new(translation, axisangle);
253        /// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
254        /// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
255        /// ```
256        #[inline]
257        pub fn new(translation: Vector3<T>, axisangle: Vector3<T>) -> Self {
258            Self::from_parts(
259                Translation::from(translation),
260                $RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
261        }
262
263        /// Creates a new isometry from the given translation coordinates.
264        #[inline]
265        pub fn translation(x: T, y: T, z: T) -> Self {
266            Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
267        }
268
269        /// Creates a new isometry from the given rotation angle.
270        #[inline]
271        pub fn rotation(axisangle: Vector3<T>) -> Self {
272            Self::new(Vector3::zeros(), axisangle)
273        }
274    }
275);
276
277macro_rules! look_at_isometry_construction_impl(
278    ($RotId: ident < $($RotParams: ident),*>) => {
279        /// Creates an isometry that corresponds to the local frame of an observer standing at the
280        /// point `eye` and looking toward `target`.
281        ///
282        /// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`.
283        ///
284        /// # Arguments
285        ///   * eye - The observer position.
286        ///   * target - The target position.
287        ///   * up - Vertical direction. The only requirement of this parameter is to not be collinear
288        ///     to `eye - at`. Non-collinearity is not checked.
289        ///
290        /// # Example
291        ///
292        /// ```
293        /// # #[macro_use] extern crate approx;
294        /// # use std::f32;
295        /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
296        /// let eye = Point3::new(1.0, 2.0, 3.0);
297        /// let target = Point3::new(2.0, 2.0, 3.0);
298        /// let up = Vector3::y();
299        ///
300        /// // Isometry with its rotation part represented as a UnitQuaternion
301        /// let iso = Isometry3::face_towards(&eye, &target, &up);
302        /// assert_eq!(iso * Point3::origin(), eye);
303        /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
304        ///
305        /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
306        /// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
307        /// assert_eq!(iso * Point3::origin(), eye);
308        /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
309        /// ```
310        #[inline]
311        pub fn face_towards(eye:    &Point3<T>,
312                            target: &Point3<T>,
313                            up:     &Vector3<T>)
314                            -> Self {
315            Self::from_parts(
316                Translation::from(eye.coords.clone()),
317                $RotId::face_towards(&(target - eye), up))
318        }
319
320        /// Deprecated: Use [`Isometry::face_towards`] instead.
321        #[deprecated(note="renamed to `face_towards`")]
322        pub fn new_observer_frame(eye:    &Point3<T>,
323                                  target: &Point3<T>,
324                                  up:     &Vector3<T>)
325                                  -> Self {
326            Self::face_towards(eye, target, up)
327        }
328
329        /// Builds a right-handed look-at view matrix.
330        ///
331        /// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin.
332        /// This conforms to the common notion of right handed camera look-at **view matrix** from
333        /// the computer graphics community, i.e. the camera is assumed to look toward its local `-z` axis.
334        ///
335        /// # Arguments
336        ///   * eye - The eye position.
337        ///   * target - The target position.
338        ///   * up - A vector approximately aligned with required the vertical axis. The only
339        ///     requirement of this parameter is to not be collinear to `target - eye`.
340        ///
341        /// # Example
342        ///
343        /// ```
344        /// # #[macro_use] extern crate approx;
345        /// # use std::f32;
346        /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
347        /// let eye = Point3::new(1.0, 2.0, 3.0);
348        /// let target = Point3::new(2.0, 2.0, 3.0);
349        /// let up = Vector3::y();
350        ///
351        /// // Isometry with its rotation part represented as a UnitQuaternion
352        /// let iso = Isometry3::look_at_rh(&eye, &target, &up);
353        /// assert_eq!(iso * eye, Point3::origin());
354        /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
355        ///
356        /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
357        /// let iso = IsometryMatrix3::look_at_rh(&eye, &target, &up);
358        /// assert_eq!(iso * eye, Point3::origin());
359        /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
360        /// ```
361        #[inline]
362        pub fn look_at_rh(eye:    &Point3<T>,
363                          target: &Point3<T>,
364                          up:     &Vector3<T>)
365                          -> Self {
366            let rotation = $RotId::look_at_rh(&(target - eye), up);
367            let trans    = &rotation * (-eye);
368
369            Self::from_parts(Translation::from(trans.coords), rotation)
370        }
371
372        /// Builds a left-handed look-at view matrix.
373        ///
374        /// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin.
375        /// This conforms to the common notion of left handed camera look-at **view matrix** from
376        /// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis.
377        ///
378        /// # Arguments
379        ///   * eye - The eye position.
380        ///   * target - The target position.
381        ///   * up - A vector approximately aligned with required the vertical axis. The only
382        ///     requirement of this parameter is to not be collinear to `target - eye`.
383        ///
384        /// # Example
385        ///
386        /// ```
387        /// # #[macro_use] extern crate approx;
388        /// # use std::f32;
389        /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
390        /// let eye = Point3::new(1.0, 2.0, 3.0);
391        /// let target = Point3::new(2.0, 2.0, 3.0);
392        /// let up = Vector3::y();
393        ///
394        /// // Isometry with its rotation part represented as a UnitQuaternion
395        /// let iso = Isometry3::look_at_lh(&eye, &target, &up);
396        /// assert_eq!(iso * eye, Point3::origin());
397        /// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
398        ///
399        /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
400        /// let iso = IsometryMatrix3::look_at_lh(&eye, &target, &up);
401        /// assert_eq!(iso * eye, Point3::origin());
402        /// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
403        /// ```
404        #[inline]
405        pub fn look_at_lh(eye:    &Point3<T>,
406                          target: &Point3<T>,
407                          up:     &Vector3<T>)
408                          -> Self {
409            let rotation = $RotId::look_at_lh(&(target - eye), up);
410            let trans    = &rotation * (-eye);
411
412            Self::from_parts(Translation::from(trans.coords), rotation)
413        }
414    }
415);
416
417/// # Construction from a 3D vector and/or an axis-angle
418impl<T: SimdRealField> Isometry3<T>
419where
420    T::Element: SimdRealField,
421{
422    basic_isometry_construction_impl!(UnitQuaternion<T>);
423
424    /// Cast the components of `self` to another type.
425    ///
426    /// # Example
427    /// ```
428    /// # use nalgebra::Isometry3;
429    /// let iso = Isometry3::<f64>::identity();
430    /// let iso2 = iso.cast::<f32>();
431    /// assert_eq!(iso2, Isometry3::<f32>::identity());
432    /// ```
433    pub fn cast<To: Scalar>(self) -> Isometry3<To>
434    where
435        Isometry3<To>: SupersetOf<Self>,
436    {
437        crate::convert(self)
438    }
439}
440
441impl<T: SimdRealField> IsometryMatrix3<T>
442where
443    T::Element: SimdRealField,
444{
445    basic_isometry_construction_impl!(Rotation3<T>);
446
447    /// Cast the components of `self` to another type.
448    ///
449    /// # Example
450    /// ```
451    /// # use nalgebra::IsometryMatrix3;
452    /// let iso = IsometryMatrix3::<f64>::identity();
453    /// let iso2 = iso.cast::<f32>();
454    /// assert_eq!(iso2, IsometryMatrix3::<f32>::identity());
455    /// ```
456    pub fn cast<To: Scalar>(self) -> IsometryMatrix3<To>
457    where
458        IsometryMatrix3<To>: SupersetOf<Self>,
459    {
460        crate::convert(self)
461    }
462}
463
464/// # Construction from a 3D eye position and target point
465impl<T: SimdRealField> Isometry3<T>
466where
467    T::Element: SimdRealField,
468{
469    look_at_isometry_construction_impl!(UnitQuaternion<T>);
470}
471
472impl<T: SimdRealField> IsometryMatrix3<T>
473where
474    T::Element: SimdRealField,
475{
476    look_at_isometry_construction_impl!(Rotation3<T>);
477}