77 lines
1.9 KiB
Plaintext
77 lines
1.9 KiB
Plaintext
use std::{
|
|
marker::PhantomData,
|
|
f64::consts::PI,
|
|
};
|
|
|
|
pub trait AngleUnit: Copy {
|
|
const TURN: f64;
|
|
const NAME: &'static str;
|
|
}
|
|
|
|
macro_rules! unit {
|
|
($name:ident, $value:expr, $string:expr) => (
|
|
#[derive(Debug, Copy, Clone)]
|
|
struct $name;
|
|
impl AngleUnit for $name {
|
|
const TURN: f64 = $value;
|
|
const NAME: &'static str = $string;
|
|
}
|
|
);
|
|
}
|
|
|
|
unit!(Degrees, 360.0, "Degrees");
|
|
unit!(Radians, PI * 2.0, "Radians");
|
|
unit!(Gradians, 400.0, "Gradians");
|
|
unit!(Mils, 6400.0, "Mils");
|
|
|
|
#[derive(Copy, Clone, PartialEq, PartialOrd)]
|
|
struct Angle<T: AngleUnit>(f64, PhantomData<T>);
|
|
|
|
impl<T: AngleUnit> Angle<T> {
|
|
pub fn new(val: f64) -> Self {
|
|
Self(val, PhantomData)
|
|
}
|
|
|
|
pub fn normalize(self) -> Self {
|
|
Self(self.0 % T::TURN, PhantomData)
|
|
}
|
|
|
|
pub fn val(self) -> f64 {
|
|
self.0
|
|
}
|
|
|
|
pub fn convert<U: AngleUnit>(self) -> Angle<U> {
|
|
Angle::new(self.0 * U::TURN / T::TURN)
|
|
}
|
|
|
|
pub fn name(self) -> &'static str {
|
|
T::NAME
|
|
}
|
|
}
|
|
|
|
fn print_angles<T: AngleUnit>() {
|
|
let angles = [-2.0, -1.0, 0.0, 1.0, 2.0, 6.2831853, 16.0, 57.2957795, 359.0, 399.0, 6399.0, 1000000.0];
|
|
println!("{:<12} {:<12} {:<12} {:<12} {:<12} {:<12}", "Angle", "Unit", "Degrees", "Gradians", "Mils", "Radians");
|
|
|
|
for &angle in &angles {
|
|
let deg = Angle::<T>::new(angle).normalize();
|
|
println!("{:<12} {:<12} {:<12.4} {:<12.4} {:<12.4} {:<12.4}",
|
|
angle,
|
|
deg.name(),
|
|
deg.convert::<Degrees>().val(),
|
|
deg.convert::<Gradians>().val(),
|
|
deg.convert::<Mils>().val(),
|
|
deg.convert::<Radians>().val(),
|
|
);
|
|
}
|
|
|
|
println!();
|
|
}
|
|
|
|
fn main() {
|
|
print_angles::<Degrees>();
|
|
print_angles::<Gradians>();
|
|
print_angles::<Mils>();
|
|
print_angles::<Radians>();
|
|
}
|