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