matrices: implement Matrix4x4:rotation_[xyz]

This commit is contained in:
Bill Thiede 2021-07-05 18:36:43 -07:00
parent f792d1a626
commit 245b02b443
2 changed files with 147 additions and 0 deletions

View File

@ -283,6 +283,117 @@ impl Matrix4x4 {
)
}
/// Creates a 4x4 matrix representing a rotation around the x-axis.
///
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use float_cmp::approx_eq;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.);
/// let half_quarter = Matrix4x4::rotation_x(PI / 4.);
/// let full_quarter = Matrix4x4::rotation_x(PI / 2.);
///
/// assert_eq!(
/// half_quarter * p,
/// Tuple::point(0., 2_f32.sqrt() / 2., 2_f32.sqrt() / 2.)
/// );
/// assert!(approx_eq!(
/// Tuple,
/// full_quarter * p,
/// Tuple::point(0., 0., 1.),
/// epsilon = 0.0001
/// ));
/// ```
pub fn rotation_x(radians: f32) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[1., 0., 0., 0.],
[0., r.cos(), -r.sin(), 0.],
[0., r.sin(), r.cos(), 0.],
[0., 0., 0., 1.],
)
}
/// Creates a 4x4 matrix representing a rotation around the y-axis.
///
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use float_cmp::approx_eq;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 0., 1.);
/// let half_quarter = Matrix4x4::rotation_y(PI / 4.);
/// let full_quarter = Matrix4x4::rotation_y(PI / 2.);
///
/// assert_eq!(
/// half_quarter * p,
/// Tuple::point(2_f32.sqrt() / 2., 0., 2_f32.sqrt() / 2.)
/// );
/// assert!(approx_eq!(
/// Tuple,
/// full_quarter * p,
/// Tuple::point(1., 0., 0.,),
/// epsilon = 0.0001
/// ));
/// ```
pub fn rotation_y(radians: f32) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[r.cos(), 0., r.sin(), 0.],
[0., 1., 0., 0.],
[-r.sin(), 0., r.cos(), 0.],
[0., 0., 0., 1.],
)
}
/// Creates a 4x4 matrix representing a rotation around the z-axis.
///
/// # Examples
///
/// ```
/// use std::f32::consts::PI;
///
/// use float_cmp::approx_eq;
///
/// use rtchallenge::{matrices::Matrix4x4, tuples::Tuple};
///
/// // A scaling matrix applied to a point.
/// let p = Tuple::point(0., 1., 0.);
/// let half_quarter = Matrix4x4::rotation_z(PI / 4.);
/// let full_quarter = Matrix4x4::rotation_z(PI / 2.);
///
/// assert_eq!(
/// half_quarter * p,
/// Tuple::point(-2_f32.sqrt() / 2., 2_f32.sqrt() / 2., 0.)
/// );
/// assert!(approx_eq!(
/// Tuple,
/// full_quarter * p,
/// Tuple::point(-1., 0., 0.,),
/// epsilon = 0.0001
/// ));
/// ```
pub fn rotation_z(radians: f32) -> Matrix4x4 {
let r = radians;
Matrix4x4::new(
[r.cos(), -r.sin(), 0., 0.],
[r.sin(), r.cos(), 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
)
}
/// Transpose self, returning a new matrix that has been reflected across the diagonal.
/// # Examples
///

View File

@ -1,5 +1,7 @@
use std::ops::{Add, Div, Mul, Neg, Sub};
use float_cmp::{ApproxEq, F32Margin};
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct Tuple {
pub x: f32,
@ -43,6 +45,40 @@ impl Tuple {
}
}
impl ApproxEq for Tuple {
type Margin = F32Margin;
/// Implement float_cmp::ApproxEq for Tuple
///
/// # Examples
/// ```
/// use float_cmp::approx_eq;
/// use rtchallenge::tuples::Tuple;
///
/// assert!(approx_eq!(
/// Tuple,
/// Tuple::point(1., 1., 0.),
/// Tuple::point(1., 1., 0.),
/// ulps = 1
/// ));
///
/// assert!(approx_eq!(
/// Tuple,
/// Tuple::vector(1., 1., 0.),
/// Tuple::vector(1., 1., 0.),
/// ulps = 1
/// ));
/// ```
fn approx_eq<T: Into<Self::Margin>>(self, t2: Self, margin: T) -> bool {
let t = self;
let margin = margin.into();
t.x.approx_eq(t2.x, margin)
&& t.y.approx_eq(t2.y, margin)
&& t.z.approx_eq(t2.z, margin)
&& t.w.approx_eq(t2.w, margin)
}
}
impl Add for Tuple {
type Output = Self;
fn add(self, other: Self) -> Self {