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