devela/num/geom/metric/angle/
mod.rs

1// devela::num::geom::metric::angle
2//
3//! Defines [`Angle`], [`AngleDirection`], [`AngleKind`].
4//
5// [`Angle`]s and [`Cycle`]s are closely related:
6// - An angle represents a fraction of a full rotation.
7// - A cycle represents a repeating pattern over a period.
8// - A full-turn normalized angle (0.0 to 1.0 or 0..256) is directly analogous to phase in a cycle.
9
10mod r#impl;
11
12mod kind;
13pub use kind::AngleKind;
14
15/// An angle represents a fraction of a full rotation.
16///
17/// It's unit-agnostic over radians or degrees, and respects directionality.
18///
19/// When `T` is an integer primitive the angle is considered to be always
20/// normalized. By virtue of the range from `[0..T::MAX]` representing a full
21/// positive (counterclockwise) turn. And in the case of signed primitives,
22/// the range from `[0..T::MIN]` represents a full negative (clockwise) turn.
23///
24/// For floating-point primitives the range from -1 to 1 (non-inclusive) represents
25/// the normalized full turn, and anything beyond that are non-normalied angles.
26///
27/// # Features
28/// It will be implemented for primitive floating point types when either the
29/// `std` or `_float_f[32|64]` features are enabled.
30/// And it will implemented for primitive integer types when its corresponding
31/// feature capability is enabled (e.g. `_int_i32`).
32///
33/// # Methods
34/// Methods are implemented the same for each main angle representation, using:
35///
36/// - Floating-point: E.g.: [methods for `f32`](#methods-for-angles-represented-using-f32).
37/// - Signed integers. E.g: [methods for `i32`](#methods-for-angles-represented-using-i32).
38/// - Unsigned integers. E.g.: [methods for `u32`](#methods-for-angles-represented-using-u32).
39///
40/// ## Methods for `f32`
41/// - Construction:
42///   - `new_`
43///     [`full`](Self::new_full),
44///     [`right`][Self::new_right],
45///     [`straight`][Self::new_straight].
46///   - `from_`
47///     [`rad`](Self::from_rad),
48///     [`deg`][Self::from_deg],
49///     [`custom`][Self::from_custom].
50/// - Conversion:
51///   - `to_`
52///     [`rad`](Self::to_rad),
53///     [`deg`][Self::to_deg],
54///     [`custom`][Self::to_custom].
55/// - Normalization:
56///   - [`normalize`](Self::normalize), *(
57///     [`is_`][Self::is_normalized],
58///     [`set_`][Self::set_normalized]. )*
59/// - Direction:
60///   - [`direction`](Self::direction), *(
61///     [`with_`](Self::with_direction),
62///     [`has_`](Self::has_direction),
63///     [`set_`](Self::set_direction),
64///     [`invert_`](Self::invert_direction). )*
65///   - [`negative`](Self::negative), *(
66///     [`set_`](Self::set_negative). )*
67///   - [`positive`](Self::positive), *(
68///     [`set_`](Self::set_positive). )*
69/// - Kind:
70///   - [`kind`](Self::kind), *(
71///     [`is_`](Self::is_kind). )*
72///
73/// This type does **not enforce normalization**, but it is expected
74/// to be normalized in most use cases.
75#[must_use]
76#[repr(transparent)]
77pub struct Angle<T> {
78    /// A unit-agnostic rotation.
79    pub turn: T,
80}
81
82impl<T> Angle<T> {
83    /// Creates a new angle.
84    pub const fn new(turn: T) -> Self {
85        Self { turn }
86    }
87}
88
89/// The direction of rotation of an angle.
90///
91/// In mathematics and most graphics programming contexts, the default direction
92/// for angle measurements is counterclockwise from a defined zero point (usually
93/// the positive x-axis). This convention applies to both 2D and 3D coordinate
94/// systems where:
95/// - A positive angle represents a counterclockwise rotation.
96/// - A negative angle represents a clockwise rotation.
97///
98/// It aligns with the right-hand rule used in mathematics, physics, and engineering.
99#[must_use]
100#[repr(i8)]
101#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub enum AngleDirection {
103    /// By convention, **positive** angles represent a **counterclockwise** rotation.
104    ///
105    /// Also known as the Right-Handed Rule.
106    ///
107    /// This is the default direction of rotation.
108    #[default]
109    Positive = 1,
110
111    /// By convention, **negative** angles represent a **clockwise** rotation.
112    ///
113    /// Also known as the Left-Hand Rule.
114    Negative = -1,
115
116    /// An undefined direction can occur when a full-turn angle is normalized
117    /// to an unsigned `0`, such as when working with primitive signed integers.
118    Undefined = 0,
119}
120
121#[allow(missing_docs, non_upper_case_globals)]
122impl AngleDirection {
123    /// Alias of **positive** angle direction.
124    pub const CounterClockwise: AngleDirection = AngleDirection::Positive;
125    pub const CCW: AngleDirection = AngleDirection::Positive;
126    pub const RightHandRule: AngleDirection = AngleDirection::Positive;
127    pub const RHR: AngleDirection = AngleDirection::Positive;
128
129    /// Alias of **negative** angle direction.
130    pub const Clockwise: AngleDirection = AngleDirection::Negative;
131    pub const CW: AngleDirection = AngleDirection::Negative;
132    pub const LeftHandRule: AngleDirection = AngleDirection::Positive;
133    pub const LHR: AngleDirection = AngleDirection::Positive;
134}