Skip to main content

sciforge_hub/domain/common/
units.rs

1//! Unit systems and conversion functions.
2//!
3//! Provides enums for length, mass, time, energy, temperature, angle,
4//! and pressure units together with bidirectional SI conversion helpers.
5
6/// Length measurement units.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum LengthUnit {
9    Meter,
10    Kilometer,
11    Centimeter,
12    Millimeter,
13    Micrometer,
14    Nanometer,
15    Angstrom,
16    Mile,
17    Yard,
18    Foot,
19    Inch,
20    AstronomicalUnit,
21    LightYear,
22    Parsec,
23}
24
25/// Mass measurement units.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum MassUnit {
28    Kilogram,
29    Gram,
30    Milligram,
31    Microgram,
32    Tonne,
33    Dalton,
34    Pound,
35    Ounce,
36    SolarMass,
37}
38
39/// Time measurement units.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum TimeUnit {
42    Second,
43    Millisecond,
44    Microsecond,
45    Nanosecond,
46    Minute,
47    Hour,
48    Day,
49    Year,
50}
51
52/// Temperature measurement units.
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum TemperatureUnit {
55    Kelvin,
56    Celsius,
57    Fahrenheit,
58    Rankine,
59}
60
61/// Energy measurement units.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum EnergyUnit {
64    Joule,
65    Kilojoule,
66    Calorie,
67    Kilocalorie,
68    ElectronVolt,
69    Erg,
70}
71
72/// Pressure measurement units.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum PressureUnit {
75    Pascal,
76    Kilopascal,
77    Megapascal,
78    Bar,
79    Atmosphere,
80    Torr,
81    Psi,
82}
83
84/// Angle measurement units.
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum AngleUnit {
87    Radian,
88    Degree,
89    Arcminute,
90    Arcsecond,
91}
92
93/// Converts a length value to SI (meters).
94pub fn length_to_si(value: f64, unit: LengthUnit) -> f64 {
95    value
96        * match unit {
97            LengthUnit::Meter => 1.0,
98            LengthUnit::Kilometer => 1e3,
99            LengthUnit::Centimeter => 1e-2,
100            LengthUnit::Millimeter => 1e-3,
101            LengthUnit::Micrometer => 1e-6,
102            LengthUnit::Nanometer => 1e-9,
103            LengthUnit::Angstrom => 1e-10,
104            LengthUnit::Mile => 1609.344,
105            LengthUnit::Yard => 0.9144,
106            LengthUnit::Foot => 0.3048,
107            LengthUnit::Inch => 0.0254,
108            LengthUnit::AstronomicalUnit => 1.495_978_707e11,
109            LengthUnit::LightYear => 9.460_730_472_58e15,
110            LengthUnit::Parsec => 3.085_677_581_28e16,
111        }
112}
113
114/// Converts a length value from SI (meters) to the target unit.
115pub fn length_from_si(value: f64, unit: LengthUnit) -> f64 {
116    value / length_to_si(1.0, unit)
117}
118
119/// Converts a mass value to SI (kilograms).
120pub fn mass_to_si(value: f64, unit: MassUnit) -> f64 {
121    value
122        * match unit {
123            MassUnit::Kilogram => 1.0,
124            MassUnit::Gram => 1e-3,
125            MassUnit::Milligram => 1e-6,
126            MassUnit::Microgram => 1e-9,
127            MassUnit::Tonne => 1e3,
128            MassUnit::Dalton => 1.660_539_066_6e-27,
129            MassUnit::Pound => 0.453_592_37,
130            MassUnit::Ounce => 0.028_349_523_125,
131            MassUnit::SolarMass => sciforge_lib::constants::SOLAR_MASS,
132        }
133}
134
135/// Converts a mass value from SI (kilograms) to the target unit.
136pub fn mass_from_si(value: f64, unit: MassUnit) -> f64 {
137    value / mass_to_si(1.0, unit)
138}
139
140/// Converts a time value to SI (seconds).
141pub fn time_to_si(value: f64, unit: TimeUnit) -> f64 {
142    value
143        * match unit {
144            TimeUnit::Second => 1.0,
145            TimeUnit::Millisecond => 1e-3,
146            TimeUnit::Microsecond => 1e-6,
147            TimeUnit::Nanosecond => 1e-9,
148            TimeUnit::Minute => 60.0,
149            TimeUnit::Hour => 3600.0,
150            TimeUnit::Day => 86400.0,
151            TimeUnit::Year => 365.25 * 86400.0,
152        }
153}
154
155/// Converts a time value from SI (seconds) to the target unit.
156pub fn time_from_si(value: f64, unit: TimeUnit) -> f64 {
157    value / time_to_si(1.0, unit)
158}
159
160/// Converts a temperature to Kelvin.
161pub fn temperature_to_kelvin(value: f64, unit: TemperatureUnit) -> f64 {
162    match unit {
163        TemperatureUnit::Kelvin => value,
164        TemperatureUnit::Celsius => value + 273.15,
165        TemperatureUnit::Fahrenheit => (value - 32.0) * 5.0 / 9.0 + 273.15,
166        TemperatureUnit::Rankine => value * 5.0 / 9.0,
167    }
168}
169
170/// Converts Kelvin to the target temperature unit.
171pub fn kelvin_to_temperature(value: f64, unit: TemperatureUnit) -> f64 {
172    match unit {
173        TemperatureUnit::Kelvin => value,
174        TemperatureUnit::Celsius => value - 273.15,
175        TemperatureUnit::Fahrenheit => (value - 273.15) * 9.0 / 5.0 + 32.0,
176        TemperatureUnit::Rankine => value * 9.0 / 5.0,
177    }
178}
179
180/// Converts an energy value to SI (joules).
181pub fn energy_to_si(value: f64, unit: EnergyUnit) -> f64 {
182    value
183        * match unit {
184            EnergyUnit::Joule => 1.0,
185            EnergyUnit::Kilojoule => 1e3,
186            EnergyUnit::Calorie => 4.184,
187            EnergyUnit::Kilocalorie => 4184.0,
188            EnergyUnit::ElectronVolt => 1.602_176_634e-19,
189            EnergyUnit::Erg => 1e-7,
190        }
191}
192
193/// Converts an energy value from SI (joules) to the target unit.
194pub fn energy_from_si(value: f64, unit: EnergyUnit) -> f64 {
195    value / energy_to_si(1.0, unit)
196}
197
198/// Converts a pressure value to SI (pascals).
199pub fn pressure_to_si(value: f64, unit: PressureUnit) -> f64 {
200    value
201        * match unit {
202            PressureUnit::Pascal => 1.0,
203            PressureUnit::Kilopascal => 1e3,
204            PressureUnit::Megapascal => 1e6,
205            PressureUnit::Bar => 1e5,
206            PressureUnit::Atmosphere => 101_325.0,
207            PressureUnit::Torr => 133.322_368_42,
208            PressureUnit::Psi => 6_894.757_293_168,
209        }
210}
211
212/// Converts a pressure value from SI (pascals) to the target unit.
213pub fn pressure_from_si(value: f64, unit: PressureUnit) -> f64 {
214    value / pressure_to_si(1.0, unit)
215}
216
217/// Converts an angle to radians.
218pub fn angle_to_radian(value: f64, unit: AngleUnit) -> f64 {
219    value
220        * match unit {
221            AngleUnit::Radian => 1.0,
222            AngleUnit::Degree => std::f64::consts::PI / 180.0,
223            AngleUnit::Arcminute => std::f64::consts::PI / 10800.0,
224            AngleUnit::Arcsecond => std::f64::consts::PI / 648_000.0,
225        }
226}
227
228/// Converts radians to the target angle unit.
229pub fn radian_to_angle(value: f64, unit: AngleUnit) -> f64 {
230    value / angle_to_radian(1.0, unit)
231}
232
233/// Converts a length between two arbitrary units.
234pub fn convert_length(value: f64, from: LengthUnit, to: LengthUnit) -> f64 {
235    length_from_si(length_to_si(value, from), to)
236}
237
238/// Converts a mass between two arbitrary units.
239pub fn convert_mass(value: f64, from: MassUnit, to: MassUnit) -> f64 {
240    mass_from_si(mass_to_si(value, from), to)
241}
242
243/// Converts a time between two arbitrary units.
244pub fn convert_time(value: f64, from: TimeUnit, to: TimeUnit) -> f64 {
245    time_from_si(time_to_si(value, from), to)
246}
247
248/// Converts a temperature between two arbitrary units.
249pub fn convert_temperature(value: f64, from: TemperatureUnit, to: TemperatureUnit) -> f64 {
250    kelvin_to_temperature(temperature_to_kelvin(value, from), to)
251}
252
253/// Converts an energy between two arbitrary units.
254pub fn convert_energy(value: f64, from: EnergyUnit, to: EnergyUnit) -> f64 {
255    energy_from_si(energy_to_si(value, from), to)
256}
257
258/// Converts a pressure between two arbitrary units.
259pub fn convert_pressure(value: f64, from: PressureUnit, to: PressureUnit) -> f64 {
260    pressure_from_si(pressure_to_si(value, from), to)
261}
262
263/// Converts an angle between two arbitrary units.
264pub fn convert_angle(value: f64, from: AngleUnit, to: AngleUnit) -> f64 {
265    radian_to_angle(angle_to_radian(value, from), to)
266}