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}