Skip to main content

cad_cs/libs/angle/
math.rs

1// 📃 src/libs/angle/math.rs
2
3use std::f64::consts;
4
5use super::{
6	abstracts::{AbstractAngle, AngleExt},
7	model::{Angle, AngleFmt},
8};
9use crate::libs::frac;
10
11impl AbstractAngle for Angle {
12	/// 📚 【 POL】: Tworzy instancję Angle bezpośrednio z wartości w radianach (Konstruktor bazowy).
13	/// 📚 【 ENG】: Creates an Angle instance directly from a value in radians (Base constructor).
14	#[inline]
15	fn from_rad(r: f64) -> Self { Self(r) }
16
17	/// 📚 【 POL】: Tworzy instancję Angle z wartości w stopniach, dokonując konwersji na radiany.
18	/// 📚 【 ENG】: Creates an Angle instance from a value in degrees, converting it to radians.
19	#[inline]
20	fn from_deg(d: f64) -> Self { Self(d.to_radians()) }
21
22	/// 📚 【 POL】: Tworzy instancję Angle jako wielokrotność liczby PI.
23	/// 📚 【 ENG】: Creates an Angle instance as a multiple of PI.
24	#[inline]
25	fn from_pi_frac(fraction: f64) -> Self { Self(fraction * consts::PI) }
26
27	/// 📚 【 POL】: Dekoduje format DMS (Stopnie, Minuty, Sekundy) do reprezentacji radianowej.
28	/// 📚 【 ENG】: Decodes DMS (Degrees, Minutes, Seconds) format to radian representation.
29	///
30	/// ⚠️ 【 POL】: Wykorzystanie i16 dla stopni uniemożliwia reprezentację "-0°" w formacie DMS.
31	/// ⚠️ 【 ENG】: Using i16 for degrees prevents representation of "-0°" in DMS format.
32	fn from_dms(d: i16, m: u8, s: f32) -> Self {
33		// Uwaga: prosty 'sign' z d < 0 nie obsłuży "-0 stopni".
34		// W GIS często używa się f64 z signum() dla stopnia, ale trzymając się i16:
35		let sign = if d < 0 { -1.0_f64 } else { 1.0_f64 };
36		let ddd = (d as f64) + sign * ((m as f64) / 60.0) + sign * ((s as f64) / 3600.0);
37		Self::from_deg(ddd)
38	}
39
40	/// 📚 【 POL】: Dekomponuje kąt z radianów do formatu DMS (Stopnie, Minuty, Sekundy).
41	/// 📚 【 ENG】: Decomposes angle from radians to DMS (Degrees, Minutes, Seconds) format.
42	fn to_dms(self) -> (i16, u8, f32) {
43		let ddd = self.deg();
44		let sign = ddd.signum();
45		let abs_ddd = ddd.abs();
46
47		let d = (abs_ddd.floor() * sign) as i16;
48		let m_float = (abs_ddd - abs_ddd.floor()) * 60.0;
49		let m = m_float.floor() as u8;
50		let s = ((m_float - m_float.floor()) * 60.0) as f32;
51
52		(d, m, s)
53	}
54
55	/// 📚 【 POL】: Zwraca wartość kąta w radianach (f64). Operacja bezkosztowa.
56	/// 📚 【 ENG】: Returns angle value in radians (f64). Zero-cost operation.
57	#[inline]
58	fn rad(self) -> f64 { self.0 }
59
60	/// 📚 【 POL】: Zwraca wartość kąta w stopniach (f64).
61	/// 📚 【 ENG】: Returns angle value in degrees (f64).
62	#[inline]
63	fn deg(self) -> f64 { self.0.to_degrees() }
64
65	/// 📚 【 POL】: Zwraca kąt jako ułamek liczby PI w postaci (licznik, mianownik).
66	/// 📚 【 ENG】: Returns angle as a fraction of PI in (numerator, denominator) form.
67	#[inline]
68	fn pi_frac(self) -> (f64, f64) { frac::as_frac_pi(self.0) }
69
70	/// 📚 【 POL】: Formatuje kąt jako ciąg znaków w radianach. Alokuje String.
71	/// 📚 【 ENG】: Formats angle as a string in radians. Allocates String.
72	fn print_rad(self) -> String { format!("{:.4} rad", self.rad()) }
73
74	/// 📚 【 POL】: Formatuje kąt jako ciąg znaków w stopniach. Alokuje String.
75	/// 📚 【 ENG】: Formats angle as a string in degrees. Allocates String.
76	fn print_deg(self) -> String { format!("{:.2}°", self.deg()) }
77
78	/// 📚 【 POL】: Formatuje kąt jako ułamek liczby PI. Alokuje String.
79	/// 📚 【 ENG】: Formats angle as a fraction of PI. Allocates String.
80	fn print_pi_frac(self) -> String {
81		let (num, den) = self.pi_frac();
82		if num == 0.0 {
83			return "0".to_string();
84		}
85		if den == 1.0 {
86			return format!("{} π", num);
87		}
88		format!("{} / {} π", num, den)
89	}
90}
91
92impl AngleExt for f64 {
93	#[rustfmt::skip] #[inline]	fn deg(self) -> Angle { Angle::from_deg(self) }
94	#[rustfmt::skip] #[inline]	fn rad(self) -> Angle { Angle::from_rad(self) }
95	#[rustfmt::skip] #[inline]	fn pi_frac(self) -> Angle { Angle::from_pi_frac(self) }
96}
97
98impl AngleFmt {
99	/// 📚 【 POL】: Formatuje wartość f64 (interpretowaną jako radiany) zgodnie z wybranym formatem.
100	/// 📚 【 ENG】: Formats a f64 value (interpreted as radians) according to the selected format.
101    #[rustfmt::skip] #[inline]
102	pub fn format(&self, val: f64) -> String {
103        match self {
104            Self::Rad    => Angle::from_rad(val).print_rad(),
105			Self::Deg    => Angle::from_rad(val).print_deg(),
106			Self::PiFrac => Angle::from_rad(val).print_pi_frac(),
107        }
108    }
109}
110
111/// 📚 【 POL】: Funkcja pomocnicza (Top-level API) tworząca instancję Angle z wartości w radianach.
112/// 📚 【 ENG】: Helper function (Top-level API) creating an Angle instance from a value in radians.
113#[rustfmt::skip] #[inline] pub const fn rad(r: f64) -> Angle { Angle(r) }
114
115/// 📚 【 POL】: Funkcja pomocnicza (Top-level API) tworząca instancję Angle z wartości w stopniach.
116/// 📚 【 ENG】: Helper function (Top-level API) creating an Angle instance from a value in degrees.
117#[rustfmt::skip] #[inline] pub fn deg(d: f64) -> Angle { Angle::from_deg(d) }
118
119/// 📚 【 POL】: Funkcja pomocnicza (Top-level API) tworząca instancję Angle jako wielokrotność liczby PI.
120/// 📚 【 ENG】: Helper function (Top-level API) creating an Angle instance as a multiple of PI.
121#[rustfmt::skip] #[inline] pub fn pi_frac(fraction: f64) -> Angle { Angle::from_pi_frac(fraction) }