Skip to main content

steel_math/
angle.rs

1//! Common angle constants.
2
3use std::f32::consts::PI as PI_F32;
4use std::f64::consts::PI as PI_F64;
5
6/// Degrees in a quarter turn.
7pub const DEGREE_90: f32 = 90.0;
8/// Degrees in a half turn.
9pub const DEGREE_180: f32 = 180.0;
10/// Degrees in three quarters of a turn.
11pub const DEGREE_270: f32 = 270.0;
12/// Degrees in a full turn.
13pub const DEGREE_360: f32 = 360.0;
14
15/// Multiplier for converting `f32` degrees to radians.
16///
17/// This matches vanilla's `Mth.DEG_TO_RAD`.
18pub const DEG_TO_RAD: f32 = PI_F32 / DEGREE_180;
19/// Multiplier for converting `f32` radians to degrees.
20///
21/// This matches vanilla's `Mth.RAD_TO_DEG`.
22pub const RAD_TO_DEG: f32 = DEGREE_180 / PI_F32;
23
24/// Multiplier for converting `f64` degrees to radians.
25pub const DEG_TO_RAD_F64: f64 = PI_F64 / DEGREE_180 as f64;
26/// Multiplier for converting `f64` radians to degrees.
27pub const RAD_TO_DEG_F64: f64 = DEGREE_180 as f64 / PI_F64;
28
29/// Wraps an angle in degrees to vanilla's `[-180, 180)` range.
30#[must_use]
31pub fn wrap_degrees(mut degrees: f32) -> f32 {
32    degrees %= DEGREE_360;
33    if degrees >= DEGREE_180 {
34        degrees -= DEGREE_360;
35    }
36    if degrees < -DEGREE_180 {
37        degrees += DEGREE_360;
38    }
39    degrees
40}
41
42/// Converts an angle in degrees to vanilla's 16-segment rotation value.
43#[must_use]
44pub fn convert_to_rotation_segment(degrees: f32) -> u8 {
45    (((degrees.rem_euclid(DEGREE_360) / (DEGREE_360 / 16.0)) + 0.5) as u8) & 15
46}
47
48#[cfg(test)]
49mod tests {
50    use super::{convert_to_rotation_segment, wrap_degrees};
51
52    #[test]
53    fn wrap_degrees_matches_vanilla_range() {
54        assert_eq!(wrap_degrees(181.0).to_bits(), (-179.0_f32).to_bits());
55        assert_eq!(wrap_degrees(-181.0).to_bits(), 179.0_f32.to_bits());
56        assert_eq!(wrap_degrees(90.0).to_bits(), 90.0_f32.to_bits());
57        assert_eq!(wrap_degrees(540.0).to_bits(), (-180.0_f32).to_bits());
58    }
59
60    #[test]
61    fn rotation_segment_wraps_and_rounds_to_nearest_segment() {
62        assert_eq!(convert_to_rotation_segment(11.24), 0);
63        assert_eq!(convert_to_rotation_segment(11.25), 1);
64        assert_eq!(convert_to_rotation_segment(-90.0), 12);
65        assert_eq!(convert_to_rotation_segment(360.0), 0);
66    }
67}