1use glam::DVec3;
7
8use crate::trig;
9
10fn cos_sin(radians: f32) -> (f64, f64) {
12 let angle = f64::from(radians);
13 (f64::from(trig::cos(angle)), f64::from(trig::sin(angle)))
14}
15
16#[inline]
18#[must_use]
19pub fn x_rot(vector: DVec3, radians: f32) -> DVec3 {
20 let (cos, sin) = cos_sin(radians);
21 DVec3::new(
22 vector.x,
23 vector.y * cos + vector.z * sin,
24 vector.z * cos - vector.y * sin,
25 )
26}
27
28#[inline]
30#[must_use]
31pub fn y_rot(vector: DVec3, radians: f32) -> DVec3 {
32 let (cos, sin) = cos_sin(radians);
33 DVec3::new(
34 vector.x * cos + vector.z * sin,
35 vector.y,
36 vector.z * cos - vector.x * sin,
37 )
38}
39
40#[inline]
42#[must_use]
43pub fn z_rot(vector: DVec3, radians: f32) -> DVec3 {
44 let (cos, sin) = cos_sin(radians);
45 DVec3::new(
46 vector.x * cos + vector.y * sin,
47 vector.y * cos - vector.x * sin,
48 vector.z,
49 )
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use std::f32::consts::FRAC_PI_2;
56
57 const TABLE_EPSILON: f64 = 1e-4;
59
60 fn assert_close(actual: DVec3, expected: DVec3) {
61 assert!(
62 (actual - expected).length() < TABLE_EPSILON,
63 "expected {expected:?}, got {actual:?}"
64 );
65 }
66
67 #[test]
68 fn rotating_by_zero_returns_the_input() {
69 let vector = DVec3::new(1.0, 2.0, 3.0);
70
71 assert_eq!(x_rot(vector, 0.0).to_array(), vector.to_array());
72 assert_eq!(y_rot(vector, 0.0).to_array(), vector.to_array());
73 assert_eq!(z_rot(vector, 0.0).to_array(), vector.to_array());
74 }
75
76 #[test]
77 fn quarter_turns_match_vanilla_axis_mapping() {
78 assert_close(x_rot(DVec3::Y, FRAC_PI_2), DVec3::new(0.0, 0.0, -1.0));
79 assert_close(y_rot(DVec3::X, FRAC_PI_2), DVec3::new(0.0, 0.0, -1.0));
80 assert_close(z_rot(DVec3::X, FRAC_PI_2), DVec3::new(0.0, -1.0, 0.0));
81 }
82
83 #[test]
85 fn x_rot_opposes_glam_rotate_x_while_y_rot_agrees() {
86 let down = DVec3::new(0.0, -1.0, 0.0);
87 let radians = 30.0_f32.to_radians();
88
89 assert_close(x_rot(down, radians), DVec3::new(0.0, -0.866_025, 0.5));
90 assert_close(
91 down.rotate_x(f64::from(radians)),
92 DVec3::new(0.0, -0.866_025, -0.5),
93 );
94
95 let vector = DVec3::new(1.0, 0.0, 0.5);
96 assert_close(y_rot(vector, radians), vector.rotate_y(f64::from(radians)));
97 }
98}