1 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT 2 // file at the top-level directory of this distribution. 3 // 4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7 // option. This file may not be copied, modified, or distributed 8 // except according to those terms. 9 10 #![cfg_attr(feature = "cargo-clippy", allow(just_underscores_and_digits))] 11 12 use super::{UnknownUnit, Angle}; 13 use crate::approxeq::ApproxEq; 14 use crate::homogen::HomogeneousVector; 15 #[cfg(feature = "mint")] 16 use mint; 17 use crate::trig::Trig; 18 use crate::point::{Point2D, point2, Point3D, point3}; 19 use crate::vector::{Vector2D, Vector3D, vec2, vec3}; 20 use crate::rect::Rect; 21 use crate::box2d::Box2D; 22 use crate::box3d::Box3D; 23 use crate::transform2d::Transform2D; 24 use crate::scale::Scale; 25 use crate::num::{One, Zero}; 26 use core::ops::{Add, Mul, Sub, Div, Neg}; 27 use core::marker::PhantomData; 28 use core::fmt; 29 use core::cmp::{Eq, PartialEq}; 30 use core::hash::{Hash}; 31 use num_traits::NumCast; 32 #[cfg(feature = "serde")] 33 use serde::{Deserialize, Serialize}; 34 35 /// A 3d transform stored as a column-major 4 by 4 matrix. 36 /// 37 /// Transforms can be parametrized over the source and destination units, to describe a 38 /// transformation from a space to another. 39 /// For example, `Transform3D<f32, WorldSpace, ScreenSpace>::transform_point3d` 40 /// takes a `Point3D<f32, WorldSpace>` and returns a `Point3D<f32, ScreenSpace>`. 41 /// 42 /// Transforms expose a set of convenience methods for pre- and post-transformations. 43 /// Pre-transformations (`pre_*` methods) correspond to adding an operation that is 44 /// applied before the rest of the transformation, while post-transformations (`then_*` 45 /// methods) add an operation that is applied after. 46 /// 47 /// When translating Transform3D into general matrix representations, consider that the 48 /// representation follows the column major notation with column vectors. 49 /// 50 /// ```text 51 /// |x'| | m11 m12 m13 m14 | |x| 52 /// |y'| | m21 m22 m23 m24 | |y| 53 /// |z'| = | m31 m32 m33 m34 | x |y| 54 /// |w | | m41 m42 m43 m44 | |1| 55 /// ``` 56 /// 57 /// The translation terms are m41, m42 and m43. 58 #[repr(C)] 59 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 60 #[cfg_attr( 61 feature = "serde", 62 serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")) 63 )] 64 pub struct Transform3D<T, Src, Dst> { 65 pub m11: T, pub m12: T, pub m13: T, pub m14: T, 66 pub m21: T, pub m22: T, pub m23: T, pub m24: T, 67 pub m31: T, pub m32: T, pub m33: T, pub m34: T, 68 pub m41: T, pub m42: T, pub m43: T, pub m44: T, 69 #[doc(hidden)] 70 pub _unit: PhantomData<(Src, Dst)>, 71 } 72 73 74 #[cfg(feature = "arbitrary")] 75 impl<'a, T, Src, Dst> arbitrary::Arbitrary<'a> for Transform3D<T, Src, Dst> 76 where 77 T: arbitrary::Arbitrary<'a>, 78 { arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self>79 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> 80 { 81 let (m11, m12, m13, m14) = arbitrary::Arbitrary::arbitrary(u)?; 82 let (m21, m22, m23, m24) = arbitrary::Arbitrary::arbitrary(u)?; 83 let (m31, m32, m33, m34) = arbitrary::Arbitrary::arbitrary(u)?; 84 let (m41, m42, m43, m44) = arbitrary::Arbitrary::arbitrary(u)?; 85 86 Ok(Transform3D { 87 m11, 88 m12, 89 m13, 90 m14, 91 m21, 92 m22, 93 m23, 94 m24, 95 m31, 96 m32, 97 m33, 98 m34, 99 m41, 100 m42, 101 m43, 102 m44, 103 _unit: PhantomData, 104 }) 105 } 106 } 107 108 impl<T: Copy, Src, Dst> Copy for Transform3D<T, Src, Dst> {} 109 110 impl<T: Clone, Src, Dst> Clone for Transform3D<T, Src, Dst> { clone(&self) -> Self111 fn clone(&self) -> Self { 112 Transform3D { 113 m11: self.m11.clone(), 114 m12: self.m12.clone(), 115 m13: self.m13.clone(), 116 m14: self.m14.clone(), 117 m21: self.m21.clone(), 118 m22: self.m22.clone(), 119 m23: self.m23.clone(), 120 m24: self.m24.clone(), 121 m31: self.m31.clone(), 122 m32: self.m32.clone(), 123 m33: self.m33.clone(), 124 m34: self.m34.clone(), 125 m41: self.m41.clone(), 126 m42: self.m42.clone(), 127 m43: self.m43.clone(), 128 m44: self.m44.clone(), 129 _unit: PhantomData, 130 } 131 } 132 } 133 134 impl<T, Src, Dst> Eq for Transform3D<T, Src, Dst> where T: Eq {} 135 136 impl<T, Src, Dst> PartialEq for Transform3D<T, Src, Dst> 137 where T: PartialEq 138 { eq(&self, other: &Self) -> bool139 fn eq(&self, other: &Self) -> bool { 140 self.m11 == other.m11 && 141 self.m12 == other.m12 && 142 self.m13 == other.m13 && 143 self.m14 == other.m14 && 144 self.m21 == other.m21 && 145 self.m22 == other.m22 && 146 self.m23 == other.m23 && 147 self.m24 == other.m24 && 148 self.m31 == other.m31 && 149 self.m32 == other.m32 && 150 self.m33 == other.m33 && 151 self.m34 == other.m34 && 152 self.m41 == other.m41 && 153 self.m42 == other.m42 && 154 self.m43 == other.m43 && 155 self.m44 == other.m44 156 } 157 } 158 159 impl<T, Src, Dst> Hash for Transform3D<T, Src, Dst> 160 where T: Hash 161 { hash<H: core::hash::Hasher>(&self, h: &mut H)162 fn hash<H: core::hash::Hasher>(&self, h: &mut H) { 163 self.m11.hash(h); 164 self.m12.hash(h); 165 self.m13.hash(h); 166 self.m14.hash(h); 167 self.m21.hash(h); 168 self.m22.hash(h); 169 self.m23.hash(h); 170 self.m24.hash(h); 171 self.m31.hash(h); 172 self.m32.hash(h); 173 self.m33.hash(h); 174 self.m34.hash(h); 175 self.m41.hash(h); 176 self.m42.hash(h); 177 self.m43.hash(h); 178 self.m44.hash(h); 179 } 180 } 181 182 183 impl<T, Src, Dst> Transform3D<T, Src, Dst> { 184 /// Create a transform specifying all of it's component as a 4 by 4 matrix. 185 /// 186 /// Components are specified following column-major-column-vector matrix notation. 187 /// For example, the translation terms m41, m42, m43 are the 13rd, 14th and 15th parameters. 188 /// 189 /// ``` 190 /// use euclid::default::Transform3D; 191 /// let tx = 1.0; 192 /// let ty = 2.0; 193 /// let tz = 3.0; 194 /// let translation = Transform3D::new( 195 /// 1.0, 0.0, 0.0, 0.0, 196 /// 0.0, 1.0, 0.0, 0.0, 197 /// 0.0, 0.0, 1.0, 0.0, 198 /// tx, ty, tz, 1.0, 199 /// ); 200 /// ``` 201 #[inline] 202 #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] new( m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T, m41: T, m42: T, m43: T, m44: T, ) -> Self203 pub const fn new( 204 m11: T, m12: T, m13: T, m14: T, 205 m21: T, m22: T, m23: T, m24: T, 206 m31: T, m32: T, m33: T, m34: T, 207 m41: T, m42: T, m43: T, m44: T, 208 ) -> Self { 209 Transform3D { 210 m11, m12, m13, m14, 211 m21, m22, m23, m24, 212 m31, m32, m33, m34, 213 m41, m42, m43, m44, 214 _unit: PhantomData, 215 } 216 } 217 218 /// Create a transform representing a 2d transformation from the components 219 /// of a 2 by 3 matrix transformation. 220 /// 221 /// Components follow the column-major-column-vector notation (m41 and m42 222 /// representating the translation terms). 223 /// 224 /// ```text 225 /// m11 m12 0 0 226 /// m21 m22 0 0 227 /// 0 0 1 0 228 /// m41 m42 0 1 229 /// ``` 230 #[inline] new_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self where T: Zero + One,231 pub fn new_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self 232 where 233 T: Zero + One, 234 { 235 let _0 = || T::zero(); 236 let _1 = || T::one(); 237 238 Self::new( 239 m11, m12, _0(), _0(), 240 m21, m22, _0(), _0(), 241 _0(), _0(), _1(), _0(), 242 m41, m42, _0(), _1() 243 ) 244 } 245 246 247 /// Returns `true` if this transform can be represented with a `Transform2D`. 248 /// 249 /// See <https://drafts.csswg.org/css-transforms/#2d-transform> 250 #[inline] is_2d(&self) -> bool where T: Zero + One + PartialEq,251 pub fn is_2d(&self) -> bool 252 where 253 T: Zero + One + PartialEq, 254 { 255 let (_0, _1): (T, T) = (Zero::zero(), One::one()); 256 self.m31 == _0 && self.m32 == _0 && 257 self.m13 == _0 && self.m23 == _0 && 258 self.m43 == _0 && self.m14 == _0 && 259 self.m24 == _0 && self.m34 == _0 && 260 self.m33 == _1 && self.m44 == _1 261 } 262 } 263 264 impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> { 265 /// Returns an array containing this transform's terms. 266 /// 267 /// The terms are laid out in the same order as they are 268 /// specified in `Transform3D::new`, that is following the 269 /// column-major-column-vector matrix notation. 270 /// 271 /// For example the translation terms are found on the 272 /// 13th, 14th and 15th slots of the array. 273 #[inline] to_array(&self) -> [T; 16]274 pub fn to_array(&self) -> [T; 16] { 275 [ 276 self.m11, self.m12, self.m13, self.m14, 277 self.m21, self.m22, self.m23, self.m24, 278 self.m31, self.m32, self.m33, self.m34, 279 self.m41, self.m42, self.m43, self.m44 280 ] 281 } 282 283 /// Returns an array containing this transform's terms transposed. 284 /// 285 /// The terms are laid out in transposed order from the same order of 286 /// `Transform3D::new` and `Transform3D::to_array`, that is following 287 /// the row-major-column-vector matrix notation. 288 /// 289 /// For example the translation terms are found at indices 3, 7 and 11 290 /// of the array. 291 #[inline] to_array_transposed(&self) -> [T; 16]292 pub fn to_array_transposed(&self) -> [T; 16] { 293 [ 294 self.m11, self.m21, self.m31, self.m41, 295 self.m12, self.m22, self.m32, self.m42, 296 self.m13, self.m23, self.m33, self.m43, 297 self.m14, self.m24, self.m34, self.m44 298 ] 299 } 300 301 /// Equivalent to `to_array` with elements packed four at a time 302 /// in an array of arrays. 303 #[inline] to_arrays(&self) -> [[T; 4]; 4]304 pub fn to_arrays(&self) -> [[T; 4]; 4] { 305 [ 306 [self.m11, self.m12, self.m13, self.m14], 307 [self.m21, self.m22, self.m23, self.m24], 308 [self.m31, self.m32, self.m33, self.m34], 309 [self.m41, self.m42, self.m43, self.m44] 310 ] 311 } 312 313 /// Equivalent to `to_array_transposed` with elements packed 314 /// four at a time in an array of arrays. 315 #[inline] to_arrays_transposed(&self) -> [[T; 4]; 4]316 pub fn to_arrays_transposed(&self) -> [[T; 4]; 4] { 317 [ 318 [self.m11, self.m21, self.m31, self.m41], 319 [self.m12, self.m22, self.m32, self.m42], 320 [self.m13, self.m23, self.m33, self.m43], 321 [self.m14, self.m24, self.m34, self.m44] 322 ] 323 } 324 325 /// Create a transform providing its components via an array 326 /// of 16 elements instead of as individual parameters. 327 /// 328 /// The order of the components corresponds to the 329 /// column-major-column-vector matrix notation (the same order 330 /// as `Transform3D::new`). 331 #[inline] from_array(array: [T; 16]) -> Self332 pub fn from_array(array: [T; 16]) -> Self { 333 Self::new( 334 array[0], array[1], array[2], array[3], 335 array[4], array[5], array[6], array[7], 336 array[8], array[9], array[10], array[11], 337 array[12], array[13], array[14], array[15], 338 ) 339 } 340 341 /// Equivalent to `from_array` with elements packed four at a time 342 /// in an array of arrays. 343 /// 344 /// The order of the components corresponds to the 345 /// column-major-column-vector matrix notation (the same order 346 /// as `Transform3D::new`). 347 #[inline] from_arrays(array: [[T; 4]; 4]) -> Self348 pub fn from_arrays(array: [[T; 4]; 4]) -> Self { 349 Self::new( 350 array[0][0], array[0][1], array[0][2], array[0][3], 351 array[1][0], array[1][1], array[1][2], array[1][3], 352 array[2][0], array[2][1], array[2][2], array[2][3], 353 array[3][0], array[3][1], array[3][2], array[3][3], 354 ) 355 } 356 357 /// Tag a unitless value with units. 358 #[inline] from_untyped(m: &Transform3D<T, UnknownUnit, UnknownUnit>) -> Self359 pub fn from_untyped(m: &Transform3D<T, UnknownUnit, UnknownUnit>) -> Self { 360 Transform3D::new( 361 m.m11, m.m12, m.m13, m.m14, 362 m.m21, m.m22, m.m23, m.m24, 363 m.m31, m.m32, m.m33, m.m34, 364 m.m41, m.m42, m.m43, m.m44, 365 ) 366 } 367 368 /// Drop the units, preserving only the numeric value. 369 #[inline] to_untyped(&self) -> Transform3D<T, UnknownUnit, UnknownUnit>370 pub fn to_untyped(&self) -> Transform3D<T, UnknownUnit, UnknownUnit> { 371 Transform3D::new( 372 self.m11, self.m12, self.m13, self.m14, 373 self.m21, self.m22, self.m23, self.m24, 374 self.m31, self.m32, self.m33, self.m34, 375 self.m41, self.m42, self.m43, self.m44, 376 ) 377 } 378 379 /// Returns the same transform with a different source unit. 380 #[inline] with_source<NewSrc>(&self) -> Transform3D<T, NewSrc, Dst>381 pub fn with_source<NewSrc>(&self) -> Transform3D<T, NewSrc, Dst> { 382 Transform3D::new( 383 self.m11, self.m12, self.m13, self.m14, 384 self.m21, self.m22, self.m23, self.m24, 385 self.m31, self.m32, self.m33, self.m34, 386 self.m41, self.m42, self.m43, self.m44, 387 ) 388 } 389 390 /// Returns the same transform with a different destination unit. 391 #[inline] with_destination<NewDst>(&self) -> Transform3D<T, Src, NewDst>392 pub fn with_destination<NewDst>(&self) -> Transform3D<T, Src, NewDst> { 393 Transform3D::new( 394 self.m11, self.m12, self.m13, self.m14, 395 self.m21, self.m22, self.m23, self.m24, 396 self.m31, self.m32, self.m33, self.m34, 397 self.m41, self.m42, self.m43, self.m44, 398 ) 399 } 400 401 /// Create a 2D transform picking the relevant terms from this transform. 402 /// 403 /// This method assumes that self represents a 2d transformation, callers 404 /// should check that [`self.is_2d()`] returns `true` beforehand. 405 /// 406 /// [`self.is_2d()`]: #method.is_2d to_2d(&self) -> Transform2D<T, Src, Dst>407 pub fn to_2d(&self) -> Transform2D<T, Src, Dst> { 408 Transform2D::new( 409 self.m11, self.m12, 410 self.m21, self.m22, 411 self.m41, self.m42 412 ) 413 } 414 } 415 416 impl <T, Src, Dst> Transform3D<T, Src, Dst> 417 where 418 T: Zero + One, 419 { 420 /// Creates an identity matrix: 421 /// 422 /// ```text 423 /// 1 0 0 0 424 /// 0 1 0 0 425 /// 0 0 1 0 426 /// 0 0 0 1 427 /// ``` 428 #[inline] identity() -> Self429 pub fn identity() -> Self { 430 Self::translation(T::zero(), T::zero(), T::zero()) 431 } 432 433 /// Intentional not public, because it checks for exact equivalence 434 /// while most consumers will probably want some sort of approximate 435 /// equivalence to deal with floating-point errors. 436 #[inline] is_identity(&self) -> bool where T: PartialEq,437 fn is_identity(&self) -> bool 438 where 439 T: PartialEq, 440 { 441 *self == Self::identity() 442 } 443 444 /// Create a 2d skew transform. 445 /// 446 /// See <https://drafts.csswg.org/css-transforms/#funcdef-skew> skew(alpha: Angle<T>, beta: Angle<T>) -> Self where T: Trig,447 pub fn skew(alpha: Angle<T>, beta: Angle<T>) -> Self 448 where 449 T: Trig, 450 { 451 let _0 = || T::zero(); 452 let _1 = || T::one(); 453 let (sx, sy) = (beta.radians.tan(), alpha.radians.tan()); 454 455 Self::new( 456 _1(), sx, _0(), _0(), 457 sy, _1(), _0(), _0(), 458 _0(), _0(), _1(), _0(), 459 _0(), _0(), _0(), _1(), 460 ) 461 } 462 463 /// Create a simple perspective transform, projecting to the plane `z = -d`. 464 /// 465 /// ```text 466 /// 1 0 0 0 467 /// 0 1 0 0 468 /// 0 0 1 -1/d 469 /// 0 0 0 1 470 /// ``` 471 /// 472 /// See <https://drafts.csswg.org/css-transforms-2/#PerspectiveDefined>. perspective(d: T) -> Self where T: Neg<Output = T> + Div<Output = T>,473 pub fn perspective(d: T) -> Self 474 where 475 T: Neg<Output = T> + Div<Output = T>, 476 { 477 let _0 = || T::zero(); 478 let _1 = || T::one(); 479 480 Self::new( 481 _1(), _0(), _0(), _0(), 482 _0(), _1(), _0(), _0(), 483 _0(), _0(), _1(), -_1() / d, 484 _0(), _0(), _0(), _1(), 485 ) 486 } 487 } 488 489 490 /// Methods for combining generic transformations 491 impl <T, Src, Dst> Transform3D<T, Src, Dst> 492 where 493 T: Copy + Add<Output = T> + Mul<Output = T>, 494 { 495 /// Returns the multiplication of the two matrices such that mat's transformation 496 /// applies after self's transformation. 497 /// 498 /// Assuming row vectors, this is equivalent to self * mat 499 #[must_use] then<NewDst>(&self, other: &Transform3D<T, Dst, NewDst>) -> Transform3D<T, Src, NewDst>500 pub fn then<NewDst>(&self, other: &Transform3D<T, Dst, NewDst>) -> Transform3D<T, Src, NewDst> { 501 Transform3D::new( 502 self.m11 * other.m11 + self.m12 * other.m21 + self.m13 * other.m31 + self.m14 * other.m41, 503 self.m11 * other.m12 + self.m12 * other.m22 + self.m13 * other.m32 + self.m14 * other.m42, 504 self.m11 * other.m13 + self.m12 * other.m23 + self.m13 * other.m33 + self.m14 * other.m43, 505 self.m11 * other.m14 + self.m12 * other.m24 + self.m13 * other.m34 + self.m14 * other.m44, 506 507 self.m21 * other.m11 + self.m22 * other.m21 + self.m23 * other.m31 + self.m24 * other.m41, 508 self.m21 * other.m12 + self.m22 * other.m22 + self.m23 * other.m32 + self.m24 * other.m42, 509 self.m21 * other.m13 + self.m22 * other.m23 + self.m23 * other.m33 + self.m24 * other.m43, 510 self.m21 * other.m14 + self.m22 * other.m24 + self.m23 * other.m34 + self.m24 * other.m44, 511 512 self.m31 * other.m11 + self.m32 * other.m21 + self.m33 * other.m31 + self.m34 * other.m41, 513 self.m31 * other.m12 + self.m32 * other.m22 + self.m33 * other.m32 + self.m34 * other.m42, 514 self.m31 * other.m13 + self.m32 * other.m23 + self.m33 * other.m33 + self.m34 * other.m43, 515 self.m31 * other.m14 + self.m32 * other.m24 + self.m33 * other.m34 + self.m34 * other.m44, 516 517 self.m41 * other.m11 + self.m42 * other.m21 + self.m43 * other.m31 + self.m44 * other.m41, 518 self.m41 * other.m12 + self.m42 * other.m22 + self.m43 * other.m32 + self.m44 * other.m42, 519 self.m41 * other.m13 + self.m42 * other.m23 + self.m43 * other.m33 + self.m44 * other.m43, 520 self.m41 * other.m14 + self.m42 * other.m24 + self.m43 * other.m34 + self.m44 * other.m44, 521 ) 522 } 523 } 524 525 /// Methods for creating and combining translation transformations 526 impl <T, Src, Dst> Transform3D<T, Src, Dst> 527 where 528 T: Zero + One, 529 { 530 /// Create a 3d translation transform: 531 /// 532 /// ```text 533 /// 1 0 0 0 534 /// 0 1 0 0 535 /// 0 0 1 0 536 /// x y z 1 537 /// ``` 538 #[inline] translation(x: T, y: T, z: T) -> Self539 pub fn translation(x: T, y: T, z: T) -> Self { 540 let _0 = || T::zero(); 541 let _1 = || T::one(); 542 543 Self::new( 544 _1(), _0(), _0(), _0(), 545 _0(), _1(), _0(), _0(), 546 _0(), _0(), _1(), _0(), 547 x, y, z, _1(), 548 ) 549 } 550 551 /// Returns a transform with a translation applied before self's transformation. 552 #[must_use] pre_translate(&self, v: Vector3D<T, Src>) -> Self where T: Copy + Add<Output = T> + Mul<Output = T>,553 pub fn pre_translate(&self, v: Vector3D<T, Src>) -> Self 554 where 555 T: Copy + Add<Output = T> + Mul<Output = T>, 556 { 557 Transform3D::translation(v.x, v.y, v.z).then(self) 558 } 559 560 /// Returns a transform with a translation applied after self's transformation. 561 #[must_use] then_translate(&self, v: Vector3D<T, Dst>) -> Self where T: Copy + Add<Output = T> + Mul<Output = T>,562 pub fn then_translate(&self, v: Vector3D<T, Dst>) -> Self 563 where 564 T: Copy + Add<Output = T> + Mul<Output = T>, 565 { 566 self.then(&Transform3D::translation(v.x, v.y, v.z)) 567 } 568 } 569 570 /// Methods for creating and combining rotation transformations 571 impl<T, Src, Dst> Transform3D<T, Src, Dst> 572 where 573 T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Zero + One + Trig, 574 { 575 /// Create a 3d rotation transform from an angle / axis. 576 /// The supplied axis must be normalized. rotation(x: T, y: T, z: T, theta: Angle<T>) -> Self577 pub fn rotation(x: T, y: T, z: T, theta: Angle<T>) -> Self { 578 let (_0, _1): (T, T) = (Zero::zero(), One::one()); 579 let _2 = _1 + _1; 580 581 let xx = x * x; 582 let yy = y * y; 583 let zz = z * z; 584 585 let half_theta = theta.get() / _2; 586 let sc = half_theta.sin() * half_theta.cos(); 587 let sq = half_theta.sin() * half_theta.sin(); 588 589 Transform3D::new( 590 _1 - _2 * (yy + zz) * sq, 591 _2 * (x * y * sq + z * sc), 592 _2 * (x * z * sq - y * sc), 593 _0, 594 595 596 _2 * (x * y * sq - z * sc), 597 _1 - _2 * (xx + zz) * sq, 598 _2 * (y * z * sq + x * sc), 599 _0, 600 601 _2 * (x * z * sq + y * sc), 602 _2 * (y * z * sq - x * sc), 603 _1 - _2 * (xx + yy) * sq, 604 _0, 605 606 _0, 607 _0, 608 _0, 609 _1 610 ) 611 } 612 613 /// Returns a transform with a rotation applied after self's transformation. 614 #[must_use] then_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self615 pub fn then_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self { 616 self.then(&Transform3D::rotation(x, y, z, theta)) 617 } 618 619 /// Returns a transform with a rotation applied before self's transformation. 620 #[must_use] pre_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self621 pub fn pre_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self { 622 Transform3D::rotation(x, y, z, theta).then(self) 623 } 624 } 625 626 /// Methods for creating and combining scale transformations 627 impl<T, Src, Dst> Transform3D<T, Src, Dst> 628 where 629 T: Zero + One, 630 { 631 /// Create a 3d scale transform: 632 /// 633 /// ```text 634 /// x 0 0 0 635 /// 0 y 0 0 636 /// 0 0 z 0 637 /// 0 0 0 1 638 /// ``` 639 #[inline] scale(x: T, y: T, z: T) -> Self640 pub fn scale(x: T, y: T, z: T) -> Self { 641 let _0 = || T::zero(); 642 let _1 = || T::one(); 643 644 Self::new( 645 x, _0(), _0(), _0(), 646 _0(), y, _0(), _0(), 647 _0(), _0(), z, _0(), 648 _0(), _0(), _0(), _1(), 649 ) 650 } 651 652 /// Returns a transform with a scale applied before self's transformation. 653 #[must_use] pre_scale(&self, x: T, y: T, z: T) -> Self where T: Copy + Add<Output = T> + Mul<Output = T>,654 pub fn pre_scale(&self, x: T, y: T, z: T) -> Self 655 where 656 T: Copy + Add<Output = T> + Mul<Output = T>, 657 { 658 Transform3D::new( 659 self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x, 660 self.m21 * y, self.m22 * y, self.m23 * y, self.m24 * y, 661 self.m31 * z, self.m32 * z, self.m33 * z, self.m34 * z, 662 self.m41 , self.m42, self.m43, self.m44 663 ) 664 } 665 666 /// Returns a transform with a scale applied after self's transformation. 667 #[must_use] then_scale(&self, x: T, y: T, z: T) -> Self where T: Copy + Add<Output = T> + Mul<Output = T>,668 pub fn then_scale(&self, x: T, y: T, z: T) -> Self 669 where 670 T: Copy + Add<Output = T> + Mul<Output = T>, 671 { 672 self.then(&Transform3D::scale(x, y, z)) 673 } 674 } 675 676 /// Methods for apply transformations to objects 677 impl<T, Src, Dst> Transform3D<T, Src, Dst> 678 where 679 T: Copy + Add<Output = T> + Mul<Output = T>, 680 { 681 /// Returns the homogeneous vector corresponding to the transformed 2d point. 682 /// 683 /// The input point must be use the unit Src, and the returned point has the unit Dst. 684 #[inline] transform_point2d_homogeneous( &self, p: Point2D<T, Src> ) -> HomogeneousVector<T, Dst>685 pub fn transform_point2d_homogeneous( 686 &self, p: Point2D<T, Src> 687 ) -> HomogeneousVector<T, Dst> { 688 let x = p.x * self.m11 + p.y * self.m21 + self.m41; 689 let y = p.x * self.m12 + p.y * self.m22 + self.m42; 690 let z = p.x * self.m13 + p.y * self.m23 + self.m43; 691 let w = p.x * self.m14 + p.y * self.m24 + self.m44; 692 693 HomogeneousVector::new(x, y, z, w) 694 } 695 696 /// Returns the given 2d point transformed by this transform, if the transform makes sense, 697 /// or `None` otherwise. 698 /// 699 /// The input point must be use the unit Src, and the returned point has the unit Dst. 700 #[inline] transform_point2d(&self, p: Point2D<T, Src>) -> Option<Point2D<T, Dst>> where T: Div<Output = T> + Zero + PartialOrd,701 pub fn transform_point2d(&self, p: Point2D<T, Src>) -> Option<Point2D<T, Dst>> 702 where 703 T: Div<Output = T> + Zero + PartialOrd, 704 { 705 //Note: could use `transform_point2d_homogeneous()` but it would waste the calculus of `z` 706 let w = p.x * self.m14 + p.y * self.m24 + self.m44; 707 if w > T::zero() { 708 let x = p.x * self.m11 + p.y * self.m21 + self.m41; 709 let y = p.x * self.m12 + p.y * self.m22 + self.m42; 710 711 Some(Point2D::new(x / w, y / w)) 712 } else { 713 None 714 } 715 } 716 717 /// Returns the given 2d vector transformed by this matrix. 718 /// 719 /// The input point must be use the unit Src, and the returned point has the unit Dst. 720 #[inline] transform_vector2d(&self, v: Vector2D<T, Src>) -> Vector2D<T, Dst>721 pub fn transform_vector2d(&self, v: Vector2D<T, Src>) -> Vector2D<T, Dst> { 722 vec2( 723 v.x * self.m11 + v.y * self.m21, 724 v.x * self.m12 + v.y * self.m22, 725 ) 726 } 727 728 /// Returns the homogeneous vector corresponding to the transformed 3d point. 729 /// 730 /// The input point must be use the unit Src, and the returned point has the unit Dst. 731 #[inline] transform_point3d_homogeneous( &self, p: Point3D<T, Src> ) -> HomogeneousVector<T, Dst>732 pub fn transform_point3d_homogeneous( 733 &self, p: Point3D<T, Src> 734 ) -> HomogeneousVector<T, Dst> { 735 let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41; 736 let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42; 737 let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43; 738 let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44; 739 740 HomogeneousVector::new(x, y, z, w) 741 } 742 743 /// Returns the given 3d point transformed by this transform, if the transform makes sense, 744 /// or `None` otherwise. 745 /// 746 /// The input point must be use the unit Src, and the returned point has the unit Dst. 747 #[inline] transform_point3d(&self, p: Point3D<T, Src>) -> Option<Point3D<T, Dst>> where T: Div<Output = T> + Zero + PartialOrd,748 pub fn transform_point3d(&self, p: Point3D<T, Src>) -> Option<Point3D<T, Dst>> 749 where 750 T: Div<Output = T> + Zero + PartialOrd, 751 { 752 self.transform_point3d_homogeneous(p).to_point3d() 753 } 754 755 /// Returns the given 3d vector transformed by this matrix. 756 /// 757 /// The input point must be use the unit Src, and the returned point has the unit Dst. 758 #[inline] transform_vector3d(&self, v: Vector3D<T, Src>) -> Vector3D<T, Dst>759 pub fn transform_vector3d(&self, v: Vector3D<T, Src>) -> Vector3D<T, Dst> { 760 vec3( 761 v.x * self.m11 + v.y * self.m21 + v.z * self.m31, 762 v.x * self.m12 + v.y * self.m22 + v.z * self.m32, 763 v.x * self.m13 + v.y * self.m23 + v.z * self.m33, 764 ) 765 } 766 767 /// Returns a rectangle that encompasses the result of transforming the given rectangle by this 768 /// transform, if the transform makes sense for it, or `None` otherwise. outer_transformed_rect(&self, rect: &Rect<T, Src>) -> Option<Rect<T, Dst>> where T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,769 pub fn outer_transformed_rect(&self, rect: &Rect<T, Src>) -> Option<Rect<T, Dst>> 770 where 771 T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd, 772 { 773 let min = rect.min(); 774 let max = rect.max(); 775 Some(Rect::from_points(&[ 776 self.transform_point2d(min)?, 777 self.transform_point2d(max)?, 778 self.transform_point2d(point2(max.x, min.y))?, 779 self.transform_point2d(point2(min.x, max.y))?, 780 ])) 781 } 782 783 /// Returns a 2d box that encompasses the result of transforming the given box by this 784 /// transform, if the transform makes sense for it, or `None` otherwise. outer_transformed_box2d(&self, b: &Box2D<T, Src>) -> Option<Box2D<T, Dst>> where T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,785 pub fn outer_transformed_box2d(&self, b: &Box2D<T, Src>) -> Option<Box2D<T, Dst>> 786 where 787 T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd, 788 { 789 Some(Box2D::from_points(&[ 790 self.transform_point2d(b.min)?, 791 self.transform_point2d(b.max)?, 792 self.transform_point2d(point2(b.max.x, b.min.y))?, 793 self.transform_point2d(point2(b.min.x, b.max.y))?, 794 ])) 795 } 796 797 /// Returns a 3d box that encompasses the result of transforming the given box by this 798 /// transform, if the transform makes sense for it, or `None` otherwise. outer_transformed_box3d(&self, b: &Box3D<T, Src>) -> Option<Box3D<T, Dst>> where T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,799 pub fn outer_transformed_box3d(&self, b: &Box3D<T, Src>) -> Option<Box3D<T, Dst>> 800 where 801 T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd, 802 { 803 Some(Box3D::from_points(&[ 804 self.transform_point3d(point3(b.min.x, b.min.y, b.min.z))?, 805 self.transform_point3d(point3(b.min.x, b.min.y, b.max.z))?, 806 self.transform_point3d(point3(b.min.x, b.max.y, b.min.z))?, 807 self.transform_point3d(point3(b.min.x, b.max.y, b.max.z))?, 808 self.transform_point3d(point3(b.max.x, b.min.y, b.min.z))?, 809 self.transform_point3d(point3(b.max.x, b.min.y, b.max.z))?, 810 self.transform_point3d(point3(b.max.x, b.max.y, b.min.z))?, 811 self.transform_point3d(point3(b.max.x, b.max.y, b.max.z))?, 812 ])) 813 } 814 } 815 816 817 impl <T, Src, Dst> Transform3D<T, Src, Dst> 818 where T: Copy + 819 Add<T, Output=T> + 820 Sub<T, Output=T> + 821 Mul<T, Output=T> + 822 Div<T, Output=T> + 823 Neg<Output=T> + 824 PartialOrd + 825 One + Zero { 826 827 /// Create an orthogonal projection transform. ortho(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Self828 pub fn ortho(left: T, right: T, 829 bottom: T, top: T, 830 near: T, far: T) -> Self { 831 let tx = -((right + left) / (right - left)); 832 let ty = -((top + bottom) / (top - bottom)); 833 let tz = -((far + near) / (far - near)); 834 835 let (_0, _1): (T, T) = (Zero::zero(), One::one()); 836 let _2 = _1 + _1; 837 Transform3D::new( 838 _2 / (right - left), _0 , _0 , _0, 839 _0 , _2 / (top - bottom), _0 , _0, 840 _0 , _0 , -_2 / (far - near), _0, 841 tx , ty , tz , _1 842 ) 843 } 844 845 /// Check whether shapes on the XY plane with Z pointing towards the 846 /// screen transformed by this matrix would be facing back. is_backface_visible(&self) -> bool847 pub fn is_backface_visible(&self) -> bool { 848 // inverse().m33 < 0; 849 let det = self.determinant(); 850 let m33 = self.m12 * self.m24 * self.m41 - self.m14 * self.m22 * self.m41 + 851 self.m14 * self.m21 * self.m42 - self.m11 * self.m24 * self.m42 - 852 self.m12 * self.m21 * self.m44 + self.m11 * self.m22 * self.m44; 853 let _0: T = Zero::zero(); 854 (m33 * det) < _0 855 } 856 857 /// Returns whether it is possible to compute the inverse transform. 858 #[inline] is_invertible(&self) -> bool859 pub fn is_invertible(&self) -> bool { 860 self.determinant() != Zero::zero() 861 } 862 863 /// Returns the inverse transform if possible. inverse(&self) -> Option<Transform3D<T, Dst, Src>>864 pub fn inverse(&self) -> Option<Transform3D<T, Dst, Src>> { 865 let det = self.determinant(); 866 867 if det == Zero::zero() { 868 return None; 869 } 870 871 // todo(gw): this could be made faster by special casing 872 // for simpler transform types. 873 let m = Transform3D::new( 874 self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 + 875 self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 - 876 self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44, 877 878 self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 - 879 self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 + 880 self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44, 881 882 self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 + 883 self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 - 884 self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44, 885 886 self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 - 887 self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 + 888 self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34, 889 890 self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 - 891 self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 + 892 self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44, 893 894 self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 + 895 self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 - 896 self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44, 897 898 self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 - 899 self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 + 900 self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44, 901 902 self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 + 903 self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 - 904 self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34, 905 906 self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 + 907 self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 - 908 self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44, 909 910 self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 - 911 self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 + 912 self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44, 913 914 self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 + 915 self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 - 916 self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44, 917 918 self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 - 919 self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 + 920 self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34, 921 922 self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 - 923 self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 + 924 self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43, 925 926 self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 + 927 self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 - 928 self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43, 929 930 self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 - 931 self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 + 932 self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43, 933 934 self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 + 935 self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 - 936 self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33 937 ); 938 939 let _1: T = One::one(); 940 Some(m.mul_s(_1 / det)) 941 } 942 943 /// Compute the determinant of the transform. determinant(&self) -> T944 pub fn determinant(&self) -> T { 945 self.m14 * self.m23 * self.m32 * self.m41 - 946 self.m13 * self.m24 * self.m32 * self.m41 - 947 self.m14 * self.m22 * self.m33 * self.m41 + 948 self.m12 * self.m24 * self.m33 * self.m41 + 949 self.m13 * self.m22 * self.m34 * self.m41 - 950 self.m12 * self.m23 * self.m34 * self.m41 - 951 self.m14 * self.m23 * self.m31 * self.m42 + 952 self.m13 * self.m24 * self.m31 * self.m42 + 953 self.m14 * self.m21 * self.m33 * self.m42 - 954 self.m11 * self.m24 * self.m33 * self.m42 - 955 self.m13 * self.m21 * self.m34 * self.m42 + 956 self.m11 * self.m23 * self.m34 * self.m42 + 957 self.m14 * self.m22 * self.m31 * self.m43 - 958 self.m12 * self.m24 * self.m31 * self.m43 - 959 self.m14 * self.m21 * self.m32 * self.m43 + 960 self.m11 * self.m24 * self.m32 * self.m43 + 961 self.m12 * self.m21 * self.m34 * self.m43 - 962 self.m11 * self.m22 * self.m34 * self.m43 - 963 self.m13 * self.m22 * self.m31 * self.m44 + 964 self.m12 * self.m23 * self.m31 * self.m44 + 965 self.m13 * self.m21 * self.m32 * self.m44 - 966 self.m11 * self.m23 * self.m32 * self.m44 - 967 self.m12 * self.m21 * self.m33 * self.m44 + 968 self.m11 * self.m22 * self.m33 * self.m44 969 } 970 971 /// Multiplies all of the transform's component by a scalar and returns the result. 972 #[must_use] mul_s(&self, x: T) -> Self973 pub fn mul_s(&self, x: T) -> Self { 974 Transform3D::new( 975 self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x, 976 self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x, 977 self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x, 978 self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x 979 ) 980 } 981 982 /// Convenience function to create a scale transform from a `Scale`. from_scale(scale: Scale<T, Src, Dst>) -> Self983 pub fn from_scale(scale: Scale<T, Src, Dst>) -> Self { 984 Transform3D::scale(scale.get(), scale.get(), scale.get()) 985 } 986 } 987 988 impl <T, Src, Dst> Transform3D<T, Src, Dst> 989 where 990 T: Copy + Mul<Output = T> + Div<Output = T> + Zero + One + PartialEq, 991 { 992 /// Returns a projection of this transform in 2d space. project_to_2d(&self) -> Self993 pub fn project_to_2d(&self) -> Self { 994 let (_0, _1): (T, T) = (Zero::zero(), One::one()); 995 996 let mut result = self.clone(); 997 998 result.m31 = _0; 999 result.m32 = _0; 1000 result.m13 = _0; 1001 result.m23 = _0; 1002 result.m33 = _1; 1003 result.m43 = _0; 1004 result.m34 = _0; 1005 1006 // Try to normalize perspective when possible to convert to a 2d matrix. 1007 // Some matrices, such as those derived from perspective transforms, can 1008 // modify m44 from 1, while leaving the rest of the fourth column 1009 // (m14, m24) at 0. In this case, after resetting the third row and 1010 // third column above, the value of m44 functions only to scale the 1011 // coordinate transform divide by W. The matrix can be converted to 1012 // a true 2D matrix by normalizing out the scaling effect of m44 on 1013 // the remaining components ahead of time. 1014 if self.m14 == _0 && self.m24 == _0 && self.m44 != _0 && self.m44 != _1 { 1015 let scale = _1 / self.m44; 1016 result.m11 = result.m11 * scale; 1017 result.m12 = result.m12 * scale; 1018 result.m21 = result.m21 * scale; 1019 result.m22 = result.m22 * scale; 1020 result.m41 = result.m41 * scale; 1021 result.m42 = result.m42 * scale; 1022 result.m44 = _1; 1023 } 1024 1025 result 1026 } 1027 } 1028 1029 impl<T: NumCast + Copy, Src, Dst> Transform3D<T, Src, Dst> { 1030 /// Cast from one numeric representation to another, preserving the units. 1031 #[inline] cast<NewT: NumCast>(&self) -> Transform3D<NewT, Src, Dst>1032 pub fn cast<NewT: NumCast>(&self) -> Transform3D<NewT, Src, Dst> { 1033 self.try_cast().unwrap() 1034 } 1035 1036 /// Fallible cast from one numeric representation to another, preserving the units. try_cast<NewT: NumCast>(&self) -> Option<Transform3D<NewT, Src, Dst>>1037 pub fn try_cast<NewT: NumCast>(&self) -> Option<Transform3D<NewT, Src, Dst>> { 1038 match (NumCast::from(self.m11), NumCast::from(self.m12), 1039 NumCast::from(self.m13), NumCast::from(self.m14), 1040 NumCast::from(self.m21), NumCast::from(self.m22), 1041 NumCast::from(self.m23), NumCast::from(self.m24), 1042 NumCast::from(self.m31), NumCast::from(self.m32), 1043 NumCast::from(self.m33), NumCast::from(self.m34), 1044 NumCast::from(self.m41), NumCast::from(self.m42), 1045 NumCast::from(self.m43), NumCast::from(self.m44)) { 1046 (Some(m11), Some(m12), Some(m13), Some(m14), 1047 Some(m21), Some(m22), Some(m23), Some(m24), 1048 Some(m31), Some(m32), Some(m33), Some(m34), 1049 Some(m41), Some(m42), Some(m43), Some(m44)) => { 1050 Some(Transform3D::new(m11, m12, m13, m14, 1051 m21, m22, m23, m24, 1052 m31, m32, m33, m34, 1053 m41, m42, m43, m44)) 1054 }, 1055 _ => None 1056 } 1057 } 1058 } 1059 1060 impl<T: ApproxEq<T>, Src, Dst> Transform3D<T, Src, Dst> { 1061 /// Returns true is this transform is approximately equal to the other one, using 1062 /// T's default epsilon value. 1063 /// 1064 /// The same as [`ApproxEq::approx_eq()`] but available without importing trait. 1065 /// 1066 /// [`ApproxEq::approx_eq()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq 1067 #[inline] approx_eq(&self, other: &Self) -> bool1068 pub fn approx_eq(&self, other: &Self) -> bool { 1069 <Self as ApproxEq<T>>::approx_eq(&self, &other) 1070 } 1071 1072 /// Returns true is this transform is approximately equal to the other one, using 1073 /// a provided epsilon value. 1074 /// 1075 /// The same as [`ApproxEq::approx_eq_eps()`] but available without importing trait. 1076 /// 1077 /// [`ApproxEq::approx_eq_eps()`]: ./approxeq/trait.ApproxEq.html#method.approx_eq_eps 1078 #[inline] approx_eq_eps(&self, other: &Self, eps: &T) -> bool1079 pub fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { 1080 <Self as ApproxEq<T>>::approx_eq_eps(&self, &other, &eps) 1081 } 1082 } 1083 1084 1085 impl<T: ApproxEq<T>, Src, Dst> ApproxEq<T> for Transform3D<T, Src, Dst> { 1086 #[inline] approx_epsilon() -> T1087 fn approx_epsilon() -> T { T::approx_epsilon() } 1088 approx_eq_eps(&self, other: &Self, eps: &T) -> bool1089 fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool { 1090 self.m11.approx_eq_eps(&other.m11, eps) && self.m12.approx_eq_eps(&other.m12, eps) && 1091 self.m13.approx_eq_eps(&other.m13, eps) && self.m14.approx_eq_eps(&other.m14, eps) && 1092 self.m21.approx_eq_eps(&other.m21, eps) && self.m22.approx_eq_eps(&other.m22, eps) && 1093 self.m23.approx_eq_eps(&other.m23, eps) && self.m24.approx_eq_eps(&other.m24, eps) && 1094 self.m31.approx_eq_eps(&other.m31, eps) && self.m32.approx_eq_eps(&other.m32, eps) && 1095 self.m33.approx_eq_eps(&other.m33, eps) && self.m34.approx_eq_eps(&other.m34, eps) && 1096 self.m41.approx_eq_eps(&other.m41, eps) && self.m42.approx_eq_eps(&other.m42, eps) && 1097 self.m43.approx_eq_eps(&other.m43, eps) && self.m44.approx_eq_eps(&other.m44, eps) 1098 } 1099 } 1100 1101 impl <T, Src, Dst> Default for Transform3D<T, Src, Dst> 1102 where T: Zero + One 1103 { 1104 /// Returns the [identity transform](#method.identity). default() -> Self1105 fn default() -> Self { 1106 Self::identity() 1107 } 1108 } 1109 1110 impl<T, Src, Dst> fmt::Debug for Transform3D<T, Src, Dst> 1111 where T: Copy + fmt::Debug + 1112 PartialEq + 1113 One + Zero { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1115 if self.is_identity() { 1116 write!(f, "[I]") 1117 } else { 1118 self.to_array().fmt(f) 1119 } 1120 } 1121 } 1122 1123 #[cfg(feature = "mint")] 1124 impl<T, Src, Dst> From<mint::RowMatrix4<T>> for Transform3D<T, Src, Dst> { from(m: mint::RowMatrix4<T>) -> Self1125 fn from(m: mint::RowMatrix4<T>) -> Self { 1126 Transform3D { 1127 m11: m.x.x, m12: m.x.y, m13: m.x.z, m14: m.x.w, 1128 m21: m.y.x, m22: m.y.y, m23: m.y.z, m24: m.y.w, 1129 m31: m.z.x, m32: m.z.y, m33: m.z.z, m34: m.z.w, 1130 m41: m.w.x, m42: m.w.y, m43: m.w.z, m44: m.w.w, 1131 _unit: PhantomData, 1132 } 1133 } 1134 } 1135 #[cfg(feature = "mint")] 1136 impl<T, Src, Dst> Into<mint::RowMatrix4<T>> for Transform3D<T, Src, Dst> { into(self) -> mint::RowMatrix4<T>1137 fn into(self) -> mint::RowMatrix4<T> { 1138 mint::RowMatrix4 { 1139 x: mint::Vector4 { x: self.m11, y: self.m12, z: self.m13, w: self.m14 }, 1140 y: mint::Vector4 { x: self.m21, y: self.m22, z: self.m23, w: self.m24 }, 1141 z: mint::Vector4 { x: self.m31, y: self.m32, z: self.m33, w: self.m34 }, 1142 w: mint::Vector4 { x: self.m41, y: self.m42, z: self.m43, w: self.m44 }, 1143 } 1144 } 1145 } 1146 1147 1148 #[cfg(test)] 1149 mod tests { 1150 use crate::approxeq::ApproxEq; 1151 use super::*; 1152 use crate::{point2, point3}; 1153 use crate::default; 1154 1155 use core::f32::consts::{FRAC_PI_2, PI}; 1156 1157 type Mf32 = default::Transform3D<f32>; 1158 1159 // For convenience. rad(v: f32) -> Angle<f32>1160 fn rad(v: f32) -> Angle<f32> { Angle::radians(v) } 1161 1162 #[test] test_translation()1163 pub fn test_translation() { 1164 let t1 = Mf32::translation(1.0, 2.0, 3.0); 1165 let t2 = Mf32::identity().pre_translate(vec3(1.0, 2.0, 3.0)); 1166 let t3 = Mf32::identity().then_translate(vec3(1.0, 2.0, 3.0)); 1167 assert_eq!(t1, t2); 1168 assert_eq!(t1, t3); 1169 1170 assert_eq!(t1.transform_point3d(point3(1.0, 1.0, 1.0)), Some(point3(2.0, 3.0, 4.0))); 1171 assert_eq!(t1.transform_point2d(point2(1.0, 1.0)), Some(point2(2.0, 3.0))); 1172 1173 assert_eq!(t1.then(&t1), Mf32::translation(2.0, 4.0, 6.0)); 1174 1175 assert!(!t1.is_2d()); 1176 assert_eq!(Mf32::translation(1.0, 2.0, 3.0).to_2d(), Transform2D::translation(1.0, 2.0)); 1177 } 1178 1179 #[test] test_rotation()1180 pub fn test_rotation() { 1181 let r1 = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)); 1182 let r2 = Mf32::identity().pre_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2)); 1183 let r3 = Mf32::identity().then_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2)); 1184 assert_eq!(r1, r2); 1185 assert_eq!(r1, r3); 1186 1187 assert!(r1.transform_point3d(point3(1.0, 2.0, 3.0)).unwrap().approx_eq(&point3(-2.0, 1.0, 3.0))); 1188 assert!(r1.transform_point2d(point2(1.0, 2.0)).unwrap().approx_eq(&point2(-2.0, 1.0))); 1189 1190 assert!(r1.then(&r1).approx_eq(&Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2*2.0)))); 1191 1192 assert!(r1.is_2d()); 1193 assert!(r1.to_2d().approx_eq(&Transform2D::rotation(rad(FRAC_PI_2)))); 1194 } 1195 1196 #[test] test_scale()1197 pub fn test_scale() { 1198 let s1 = Mf32::scale(2.0, 3.0, 4.0); 1199 let s2 = Mf32::identity().pre_scale(2.0, 3.0, 4.0); 1200 let s3 = Mf32::identity().then_scale(2.0, 3.0, 4.0); 1201 assert_eq!(s1, s2); 1202 assert_eq!(s1, s3); 1203 1204 assert!(s1.transform_point3d(point3(2.0, 2.0, 2.0)).unwrap().approx_eq(&point3(4.0, 6.0, 8.0))); 1205 assert!(s1.transform_point2d(point2(2.0, 2.0)).unwrap().approx_eq(&point2(4.0, 6.0))); 1206 1207 assert_eq!(s1.then(&s1), Mf32::scale(4.0, 9.0, 16.0)); 1208 1209 assert!(!s1.is_2d()); 1210 assert_eq!(Mf32::scale(2.0, 3.0, 0.0).to_2d(), Transform2D::scale(2.0, 3.0)); 1211 } 1212 1213 1214 #[test] test_pre_then_scale()1215 pub fn test_pre_then_scale() { 1216 let m = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)).then_translate(vec3(6.0, 7.0, 8.0)); 1217 let s = Mf32::scale(2.0, 3.0, 4.0); 1218 assert_eq!(m.then(&s), m.then_scale(2.0, 3.0, 4.0)); 1219 } 1220 1221 1222 #[test] test_ortho()1223 pub fn test_ortho() { 1224 let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32); 1225 let (near, far) = (-1.0f32, 1.0f32); 1226 let result = Mf32::ortho(left, right, bottom, top, near, far); 1227 let expected = Mf32::new( 1228 2.0, 0.0, 0.0, 0.0, 1229 0.0, 2.22222222, 0.0, 0.0, 1230 0.0, 0.0, -1.0, 0.0, 1231 -1.0, -1.22222222, -0.0, 1.0 1232 ); 1233 assert!(result.approx_eq(&expected)); 1234 } 1235 1236 #[test] test_is_2d()1237 pub fn test_is_2d() { 1238 assert!(Mf32::identity().is_2d()); 1239 assert!(Mf32::rotation(0.0, 0.0, 1.0, rad(0.7854)).is_2d()); 1240 assert!(!Mf32::rotation(0.0, 1.0, 0.0, rad(0.7854)).is_2d()); 1241 } 1242 1243 #[test] test_new_2d()1244 pub fn test_new_2d() { 1245 let m1 = Mf32::new_2d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); 1246 let m2 = Mf32::new( 1247 1.0, 2.0, 0.0, 0.0, 1248 3.0, 4.0, 0.0, 0.0, 1249 0.0, 0.0, 1.0, 0.0, 1250 5.0, 6.0, 0.0, 1.0 1251 ); 1252 assert_eq!(m1, m2); 1253 } 1254 1255 #[test] test_inverse_simple()1256 pub fn test_inverse_simple() { 1257 let m1 = Mf32::identity(); 1258 let m2 = m1.inverse().unwrap(); 1259 assert!(m1.approx_eq(&m2)); 1260 } 1261 1262 #[test] test_inverse_scale()1263 pub fn test_inverse_scale() { 1264 let m1 = Mf32::scale(1.5, 0.3, 2.1); 1265 let m2 = m1.inverse().unwrap(); 1266 assert!(m1.then(&m2).approx_eq(&Mf32::identity())); 1267 assert!(m2.then(&m1).approx_eq(&Mf32::identity())); 1268 } 1269 1270 #[test] test_inverse_translate()1271 pub fn test_inverse_translate() { 1272 let m1 = Mf32::translation(-132.0, 0.3, 493.0); 1273 let m2 = m1.inverse().unwrap(); 1274 assert!(m1.then(&m2).approx_eq(&Mf32::identity())); 1275 assert!(m2.then(&m1).approx_eq(&Mf32::identity())); 1276 } 1277 1278 #[test] test_inverse_rotate()1279 pub fn test_inverse_rotate() { 1280 let m1 = Mf32::rotation(0.0, 1.0, 0.0, rad(1.57)); 1281 let m2 = m1.inverse().unwrap(); 1282 assert!(m1.then(&m2).approx_eq(&Mf32::identity())); 1283 assert!(m2.then(&m1).approx_eq(&Mf32::identity())); 1284 } 1285 1286 #[test] test_inverse_transform_point_2d()1287 pub fn test_inverse_transform_point_2d() { 1288 let m1 = Mf32::translation(100.0, 200.0, 0.0); 1289 let m2 = m1.inverse().unwrap(); 1290 assert!(m1.then(&m2).approx_eq(&Mf32::identity())); 1291 assert!(m2.then(&m1).approx_eq(&Mf32::identity())); 1292 1293 let p1 = point2(1000.0, 2000.0); 1294 let p2 = m1.transform_point2d(p1); 1295 assert_eq!(p2, Some(point2(1100.0, 2200.0))); 1296 1297 let p3 = m2.transform_point2d(p2.unwrap()); 1298 assert_eq!(p3, Some(p1)); 1299 } 1300 1301 #[test] test_inverse_none()1302 fn test_inverse_none() { 1303 assert!(Mf32::scale(2.0, 0.0, 2.0).inverse().is_none()); 1304 assert!(Mf32::scale(2.0, 2.0, 2.0).inverse().is_some()); 1305 } 1306 1307 #[test] test_pre_post()1308 pub fn test_pre_post() { 1309 let m1 = default::Transform3D::identity().then_scale(1.0, 2.0, 3.0).then_translate(vec3(1.0, 2.0, 3.0)); 1310 let m2 = default::Transform3D::identity().pre_translate(vec3(1.0, 2.0, 3.0)).pre_scale(1.0, 2.0, 3.0); 1311 assert!(m1.approx_eq(&m2)); 1312 1313 let r = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)); 1314 let t = Mf32::translation(2.0, 3.0, 0.0); 1315 1316 let a = point3(1.0, 1.0, 1.0); 1317 1318 assert!(r.then(&t).transform_point3d(a).unwrap().approx_eq(&point3(1.0, 4.0, 1.0))); 1319 assert!(t.then(&r).transform_point3d(a).unwrap().approx_eq(&point3(-4.0, 3.0, 1.0))); 1320 assert!(t.then(&r).transform_point3d(a).unwrap().approx_eq(&r.transform_point3d(t.transform_point3d(a).unwrap()).unwrap())); 1321 } 1322 1323 #[test] test_size_of()1324 fn test_size_of() { 1325 use core::mem::size_of; 1326 assert_eq!(size_of::<default::Transform3D<f32>>(), 16*size_of::<f32>()); 1327 assert_eq!(size_of::<default::Transform3D<f64>>(), 16*size_of::<f64>()); 1328 } 1329 1330 #[test] test_transform_associativity()1331 pub fn test_transform_associativity() { 1332 let m1 = Mf32::new(3.0, 2.0, 1.5, 1.0, 1333 0.0, 4.5, -1.0, -4.0, 1334 0.0, 3.5, 2.5, 40.0, 1335 0.0, 3.0, 0.0, 1.0); 1336 let m2 = Mf32::new(1.0, -1.0, 3.0, 0.0, 1337 -1.0, 0.5, 0.0, 2.0, 1338 1.5, -2.0, 6.0, 0.0, 1339 -2.5, 6.0, 1.0, 1.0); 1340 1341 let p = point3(1.0, 3.0, 5.0); 1342 let p1 = m1.then(&m2).transform_point3d(p).unwrap(); 1343 let p2 = m2.transform_point3d(m1.transform_point3d(p).unwrap()).unwrap(); 1344 assert!(p1.approx_eq(&p2)); 1345 } 1346 1347 #[test] test_is_identity()1348 pub fn test_is_identity() { 1349 let m1 = default::Transform3D::identity(); 1350 assert!(m1.is_identity()); 1351 let m2 = m1.then_translate(vec3(0.1, 0.0, 0.0)); 1352 assert!(!m2.is_identity()); 1353 } 1354 1355 #[test] test_transform_vector()1356 pub fn test_transform_vector() { 1357 // Translation does not apply to vectors. 1358 let m = Mf32::translation(1.0, 2.0, 3.0); 1359 let v1 = vec3(10.0, -10.0, 3.0); 1360 assert_eq!(v1, m.transform_vector3d(v1)); 1361 // While it does apply to points. 1362 assert_ne!(Some(v1.to_point()), m.transform_point3d(v1.to_point())); 1363 1364 // same thing with 2d vectors/points 1365 let v2 = vec2(10.0, -5.0); 1366 assert_eq!(v2, m.transform_vector2d(v2)); 1367 assert_ne!(Some(v2.to_point()), m.transform_point2d(v2.to_point())); 1368 } 1369 1370 #[test] test_is_backface_visible()1371 pub fn test_is_backface_visible() { 1372 // backface is not visible for rotate-x 0 degree. 1373 let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(0.0)); 1374 assert!(!r1.is_backface_visible()); 1375 // backface is not visible for rotate-x 45 degree. 1376 let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI * 0.25)); 1377 assert!(!r1.is_backface_visible()); 1378 // backface is visible for rotate-x 180 degree. 1379 let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI)); 1380 assert!(r1.is_backface_visible()); 1381 // backface is visible for rotate-x 225 degree. 1382 let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI * 1.25)); 1383 assert!(r1.is_backface_visible()); 1384 // backface is not visible for non-inverseable matrix 1385 let r1 = Mf32::scale(2.0, 0.0, 2.0); 1386 assert!(!r1.is_backface_visible()); 1387 } 1388 1389 #[test] test_homogeneous()1390 pub fn test_homogeneous() { 1391 let m = Mf32::new( 1392 1.0, 2.0, 0.5, 5.0, 1393 3.0, 4.0, 0.25, 6.0, 1394 0.5, -1.0, 1.0, -1.0, 1395 -1.0, 1.0, -1.0, 2.0, 1396 ); 1397 assert_eq!( 1398 m.transform_point2d_homogeneous(point2(1.0, 2.0)), 1399 HomogeneousVector::new(6.0, 11.0, 0.0, 19.0), 1400 ); 1401 assert_eq!( 1402 m.transform_point3d_homogeneous(point3(1.0, 2.0, 4.0)), 1403 HomogeneousVector::new(8.0, 7.0, 4.0, 15.0), 1404 ); 1405 } 1406 1407 #[test] test_perspective_division()1408 pub fn test_perspective_division() { 1409 let p = point2(1.0, 2.0); 1410 let mut m = Mf32::identity(); 1411 assert!(m.transform_point2d(p).is_some()); 1412 m.m44 = 0.0; 1413 assert_eq!(None, m.transform_point2d(p)); 1414 m.m44 = 1.0; 1415 m.m24 = -1.0; 1416 assert_eq!(None, m.transform_point2d(p)); 1417 } 1418 1419 #[cfg(feature = "mint")] 1420 #[test] test_mint()1421 pub fn test_mint() { 1422 let m1 = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)); 1423 let mm: mint::RowMatrix4<_> = m1.into(); 1424 let m2 = Mf32::from(mm); 1425 1426 assert_eq!(m1, m2); 1427 } 1428 } 1429