nalgebra/geometry/similarity_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, Point, Point3, Rotation2, Rotation3, Scalar, Similarity,
20 Translation, UnitComplex, UnitQuaternion,
21};
22
23impl<T: SimdRealField, R, const D: usize> Default for Similarity<T, R, D>
24where
25 T::Element: SimdRealField,
26 R: AbstractRotation<T, D>,
27{
28 fn default() -> Self {
29 Self::identity()
30 }
31}
32
33impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D>
34where
35 T::Element: SimdRealField,
36 R: AbstractRotation<T, D>,
37{
38 /// Creates a new identity similarity.
39 ///
40 /// # Example
41 /// ```
42 /// # use nalgebra::{Similarity2, Point2, Similarity3, Point3};
43 ///
44 /// let sim = Similarity2::identity();
45 /// let pt = Point2::new(1.0, 2.0);
46 /// assert_eq!(sim * pt, pt);
47 ///
48 /// let sim = Similarity3::identity();
49 /// let pt = Point3::new(1.0, 2.0, 3.0);
50 /// assert_eq!(sim * pt, pt);
51 /// ```
52 #[inline]
53 pub fn identity() -> Self {
54 Self::from_isometry(Isometry::identity(), T::one())
55 }
56}
57
58impl<T: SimdRealField, R, const D: usize> One for Similarity<T, R, D>
59where
60 T::Element: SimdRealField,
61 R: AbstractRotation<T, D>,
62{
63 /// Creates a new identity similarity.
64 #[inline]
65 fn one() -> Self {
66 Self::identity()
67 }
68}
69
70#[cfg(feature = "rand-no-std")]
71impl<T: crate::RealField, R, const D: usize> Distribution<Similarity<T, R, D>> for Standard
72where
73 R: AbstractRotation<T, D>,
74 Standard: Distribution<T> + Distribution<R>,
75{
76 /// Generate an arbitrary random variate for testing purposes.
77 #[inline]
78 fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Similarity<T, R, D> {
79 let mut s = rng.gen();
80 while relative_eq!(s, T::zero()) {
81 s = rng.gen()
82 }
83
84 Similarity::from_isometry(rng.gen(), s)
85 }
86}
87
88impl<T: SimdRealField, R, const D: usize> Similarity<T, R, D>
89where
90 T::Element: SimdRealField,
91 R: AbstractRotation<T, D>,
92{
93 /// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with
94 /// its axis passing through the point `p`.
95 ///
96 /// # Example
97 /// ```
98 /// # #[macro_use] extern crate approx;
99 /// # use std::f32;
100 /// # use nalgebra::{Similarity2, Point2, UnitComplex};
101 /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
102 /// let pt = Point2::new(3.0, 2.0);
103 /// let sim = Similarity2::rotation_wrt_point(rot, pt, 4.0);
104 ///
105 /// assert_relative_eq!(sim * Point2::new(1.0, 2.0), Point2::new(-3.0, 3.0), epsilon = 1.0e-6);
106 /// ```
107 #[inline]
108 pub fn rotation_wrt_point(r: R, p: Point<T, D>, scaling: T) -> Self {
109 let shift = r.transform_vector(&-&p.coords);
110 Self::from_parts(Translation::from(shift + p.coords), r, scaling)
111 }
112}
113
114#[cfg(feature = "arbitrary")]
115impl<T, R, const D: usize> Arbitrary for Similarity<T, R, D>
116where
117 T: crate::RealField + Arbitrary + Send,
118 T::Element: crate::RealField,
119 R: AbstractRotation<T, D> + Arbitrary + Send,
120 Owned<T, crate::Const<D>>: Send,
121{
122 #[inline]
123 fn arbitrary(rng: &mut Gen) -> Self {
124 let mut s: T = Arbitrary::arbitrary(rng);
125 while s.is_zero() {
126 s = Arbitrary::arbitrary(rng)
127 }
128
129 Self::from_isometry(Arbitrary::arbitrary(rng), s)
130 }
131}
132
133/*
134 *
135 * Constructors for various static dimensions.
136 *
137 */
138
139// 2D similarity.
140impl<T: SimdRealField> Similarity<T, Rotation2<T>, 2>
141where
142 T::Element: SimdRealField,
143{
144 /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor.
145 ///
146 /// # Example
147 /// ```
148 /// # #[macro_use] extern crate approx;
149 /// # use std::f32;
150 /// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
151 /// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
152 ///
153 /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
154 /// ```
155 #[inline]
156 pub fn new(translation: Vector2<T>, angle: T, scaling: T) -> Self {
157 Self::from_parts(
158 Translation::from(translation),
159 Rotation2::new(angle),
160 scaling,
161 )
162 }
163
164 /// Cast the components of `self` to another type.
165 ///
166 /// # Example
167 /// ```
168 /// # use nalgebra::SimilarityMatrix2;
169 /// let sim = SimilarityMatrix2::<f64>::identity();
170 /// let sim2 = sim.cast::<f32>();
171 /// assert_eq!(sim2, SimilarityMatrix2::<f32>::identity());
172 /// ```
173 pub fn cast<To: Scalar>(self) -> Similarity<To, Rotation2<To>, 2>
174 where
175 Similarity<To, Rotation2<To>, 2>: SupersetOf<Self>,
176 {
177 crate::convert(self)
178 }
179}
180
181impl<T: SimdRealField> Similarity<T, UnitComplex<T>, 2>
182where
183 T::Element: SimdRealField,
184{
185 /// Creates a new similarity from a translation and a rotation angle.
186 ///
187 /// # Example
188 /// ```
189 /// # #[macro_use] extern crate approx;
190 /// # use std::f32;
191 /// # use nalgebra::{Similarity2, Vector2, Point2};
192 /// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
193 ///
194 /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6);
195 /// ```
196 #[inline]
197 pub fn new(translation: Vector2<T>, angle: T, scaling: T) -> Self {
198 Self::from_parts(
199 Translation::from(translation),
200 UnitComplex::new(angle),
201 scaling,
202 )
203 }
204
205 /// Cast the components of `self` to another type.
206 ///
207 /// # Example
208 /// ```
209 /// # use nalgebra::Similarity2;
210 /// let sim = Similarity2::<f64>::identity();
211 /// let sim2 = sim.cast::<f32>();
212 /// assert_eq!(sim2, Similarity2::<f32>::identity());
213 /// ```
214 pub fn cast<To: Scalar>(self) -> Similarity<To, UnitComplex<To>, 2>
215 where
216 Similarity<To, UnitComplex<To>, 2>: SupersetOf<Self>,
217 {
218 crate::convert(self)
219 }
220}
221
222// 3D rotation.
223macro_rules! similarity_construction_impl(
224 ($Rot: ident) => {
225 impl<T: SimdRealField> Similarity<T, $Rot<T>, 3>
226 where T::Element: SimdRealField {
227 /// Creates a new similarity from a translation, rotation axis-angle, and scaling
228 /// factor.
229 ///
230 /// # Example
231 /// ```
232 /// # #[macro_use] extern crate approx;
233 /// # use std::f32;
234 /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
235 /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
236 /// let translation = Vector3::new(1.0, 2.0, 3.0);
237 /// // Point and vector being transformed in the tests.
238 /// let pt = Point3::new(4.0, 5.0, 6.0);
239 /// let vec = Vector3::new(4.0, 5.0, 6.0);
240 ///
241 /// // Similarity with its rotation part represented as a UnitQuaternion
242 /// let sim = Similarity3::new(translation, axisangle, 3.0);
243 /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
244 /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
245 ///
246 /// // Similarity with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
247 /// let sim = SimilarityMatrix3::new(translation, axisangle, 3.0);
248 /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5);
249 /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5);
250 /// ```
251 #[inline]
252 pub fn new(translation: Vector3<T>, axisangle: Vector3<T>, scaling: T) -> Self
253 {
254 Self::from_isometry(Isometry::<_, $Rot<T>, 3>::new(translation, axisangle), scaling)
255 }
256
257 /// Cast the components of `self` to another type.
258 ///
259 /// # Example
260 /// ```
261 /// # use nalgebra::Similarity3;
262 /// let sim = Similarity3::<f64>::identity();
263 /// let sim2 = sim.cast::<f32>();
264 /// assert_eq!(sim2, Similarity3::<f32>::identity());
265 /// ```
266 pub fn cast<To: Scalar>(self) -> Similarity<To, $Rot<To>, 3>
267 where
268 Similarity<To, $Rot<To>, 3>: SupersetOf<Self>,
269 {
270 crate::convert(self)
271 }
272
273 /// Creates an similarity that corresponds to a scaling factor and a local frame of
274 /// an observer standing at the point `eye` and looking toward `target`.
275 ///
276 /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
277 /// `eye`.
278 ///
279 /// # Arguments
280 /// * eye - The observer position.
281 /// * target - The target position.
282 /// * up - Vertical direction. The only requirement of this parameter is to not be collinear
283 /// to `eye - at`. Non-collinearity is not checked.
284 ///
285 /// # Example
286 /// ```
287 /// # #[macro_use] extern crate approx;
288 /// # use std::f32;
289 /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
290 /// let eye = Point3::new(1.0, 2.0, 3.0);
291 /// let target = Point3::new(2.0, 2.0, 3.0);
292 /// let up = Vector3::y();
293 ///
294 /// // Similarity with its rotation part represented as a UnitQuaternion
295 /// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
296 /// assert_eq!(sim * Point3::origin(), eye);
297 /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
298 ///
299 /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
300 /// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
301 /// assert_eq!(sim * Point3::origin(), eye);
302 /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
303 /// ```
304 #[inline]
305 pub fn face_towards(eye: &Point3<T>,
306 target: &Point3<T>,
307 up: &Vector3<T>,
308 scaling: T)
309 -> Self {
310 Self::from_isometry(Isometry::<_, $Rot<T>, 3>::face_towards(eye, target, up), scaling)
311 }
312
313 /// Deprecated: Use [`SimilarityMatrix3::face_towards`](Self::face_towards) instead.
314 #[deprecated(note="renamed to `face_towards`")]
315 pub fn new_observer_frames(eye: &Point3<T>,
316 target: &Point3<T>,
317 up: &Vector3<T>,
318 scaling: T)
319 -> Self {
320 Self::face_towards(eye, target, up, scaling)
321 }
322
323 /// Builds a right-handed look-at view matrix including scaling factor.
324 ///
325 /// This conforms to the common notion of right handed look-at matrix from the computer
326 /// graphics community.
327 ///
328 /// # Arguments
329 /// * eye - The eye position.
330 /// * target - The target position.
331 /// * up - A vector approximately aligned with required the vertical axis. The only
332 /// requirement of this parameter is to not be collinear to `target - eye`.
333 ///
334 /// # Example
335 /// ```
336 /// # #[macro_use] extern crate approx;
337 /// # use std::f32;
338 /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
339 /// let eye = Point3::new(1.0, 2.0, 3.0);
340 /// let target = Point3::new(2.0, 2.0, 3.0);
341 /// let up = Vector3::y();
342 ///
343 /// // Similarity with its rotation part represented as a UnitQuaternion
344 /// let iso = Similarity3::look_at_rh(&eye, &target, &up, 3.0);
345 /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
346 ///
347 /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
348 /// let iso = SimilarityMatrix3::look_at_rh(&eye, &target, &up, 3.0);
349 /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6);
350 /// ```
351 #[inline]
352 pub fn look_at_rh(eye: &Point3<T>,
353 target: &Point3<T>,
354 up: &Vector3<T>,
355 scaling: T)
356 -> Self {
357 Self::from_isometry(Isometry::<_, $Rot<T>, 3>::look_at_rh(eye, target, up), scaling)
358 }
359
360 /// Builds a left-handed look-at view matrix including a scaling factor.
361 ///
362 /// This conforms to the common notion of left handed look-at matrix from the computer
363 /// graphics community.
364 ///
365 /// # Arguments
366 /// * eye - The eye position.
367 /// * target - The target position.
368 /// * up - A vector approximately aligned with required the vertical axis. The only
369 /// requirement of this parameter is to not be collinear to `target - eye`.
370 ///
371 /// # Example
372 /// ```
373 /// # #[macro_use] extern crate approx;
374 /// # use std::f32;
375 /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
376 /// let eye = Point3::new(1.0, 2.0, 3.0);
377 /// let target = Point3::new(2.0, 2.0, 3.0);
378 /// let up = Vector3::y();
379 ///
380 /// // Similarity with its rotation part represented as a UnitQuaternion
381 /// let sim = Similarity3::look_at_lh(&eye, &target, &up, 3.0);
382 /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
383 ///
384 /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
385 /// let sim = SimilarityMatrix3::look_at_lh(&eye, &target, &up, 3.0);
386 /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6);
387 /// ```
388 #[inline]
389 pub fn look_at_lh(eye: &Point3<T>,
390 target: &Point3<T>,
391 up: &Vector3<T>,
392 scaling: T)
393 -> Self {
394 Self::from_isometry(Isometry::<_, $Rot<T>, 3>::look_at_lh(eye, target, up), scaling)
395 }
396 }
397 }
398);
399
400similarity_construction_impl!(Rotation3);
401similarity_construction_impl!(UnitQuaternion);