Skip to main content

space_units/quantities/
geometry.rs

1use super::DisplayWithUnit;
2
3// -------------------------
4// Area
5// -------------------------
6
7/// An area quantity, stored canonically in square meters (m²).
8///
9/// # Construction
10/// ```
11/// use space_units::Area;
12/// let a = Area::from_km2(0.5);
13/// ```
14///
15/// # Typed arithmetic
16/// - [`Length`](crate::Length) × [`Length`](crate::Length) → [`Area`]
17/// - [`Area`] × [`Length`](crate::Length) → [`Volume`]
18#[must_use]
19#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
20pub struct Area(pub(crate) f64);
21
22/// Display/conversion units for [`Area`].
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum AreaUnit {
25    /// Square meters (m²) -- SI base unit for area.
26    SquareMeter,
27    /// Square millimeters (mm²).
28    SquareMillimeter,
29    /// Square centimeters (cm²).
30    SquareCentimeter,
31    /// Square kilometers (km²).
32    SquareKilometer,
33    /// Square feet (ft²).
34    SquareFoot,
35    /// Square inches (in²).
36    SquareInch,
37}
38
39impl AreaUnit {
40    const fn symbol(self) -> &'static str {
41        match self {
42            Self::SquareMeter => "m^2",
43            Self::SquareMillimeter => "mm^2",
44            Self::SquareCentimeter => "cm^2",
45            Self::SquareKilometer => "km^2",
46            Self::SquareFoot => "ft^2",
47            Self::SquareInch => "in^2",
48        }
49    }
50
51    const fn m2_per_unit(self) -> f64 {
52        match self {
53            Self::SquareMeter => 1.0,
54            Self::SquareMillimeter => 1e-6,
55            Self::SquareCentimeter => 1e-4,
56            Self::SquareKilometer => 1_000_000.0,
57            Self::SquareFoot => 0.092_903_04,
58            Self::SquareInch => 0.000_645_16,
59        }
60    }
61}
62
63impl Area {
64    /// Create from square meters (m²).
65    pub const fn from_m2(val: f64) -> Self {
66        Self(val)
67    }
68
69    /// Create from square kilometers (km²).
70    pub const fn from_km2(val: f64) -> Self {
71        Self(val * 1_000_000.0)
72    }
73
74    /// Create from square millimeters (mm²).
75    pub const fn from_mm2(val: f64) -> Self {
76        Self(val * 1e-6)
77    }
78
79    /// Create from square centimeters (cm²).
80    pub const fn from_cm2(val: f64) -> Self {
81        Self(val * 1e-4)
82    }
83
84    /// Create from square feet (ft²).
85    pub const fn from_ft2(val: f64) -> Self {
86        Self(val * 0.092_903_04)
87    }
88
89    /// Create from square inches (in²).
90    pub const fn from_in2(val: f64) -> Self {
91        Self(val * 0.000_645_16)
92    }
93
94    /// Get value in square meters (m²).
95    pub const fn in_m2(self) -> f64 {
96        self.0
97    }
98
99    /// Get value in square kilometers (km²).
100    pub const fn in_km2(self) -> f64 {
101        self.0 / 1_000_000.0
102    }
103
104    /// Get value in square millimeters (mm²).
105    pub const fn in_mm2(self) -> f64 {
106        self.0 / 1e-6
107    }
108
109    /// Get value in square centimeters (cm²).
110    pub const fn in_cm2(self) -> f64 {
111        self.0 / 1e-4
112    }
113
114    /// Get value in square feet (ft²).
115    pub const fn in_ft2(self) -> f64 {
116        self.0 / 0.092_903_04
117    }
118
119    /// Get value in square inches (in²).
120    pub const fn in_in2(self) -> f64 {
121        self.0 / 0.000_645_16
122    }
123
124    /// Get value in the specified [`AreaUnit`].
125    pub fn in_unit(self, unit: AreaUnit) -> f64 {
126        self.0 / unit.m2_per_unit()
127    }
128
129    /// Return a display wrapper that formats this area in the given unit.
130    pub fn display_as(self, unit: AreaUnit) -> DisplayWithUnit {
131        DisplayWithUnit {
132            value: self.in_unit(unit),
133            symbol: unit.symbol(),
134        }
135    }
136
137    /// Return the absolute value of this area.
138    pub fn abs(self) -> Self {
139        Self(self.0.abs())
140    }
141}
142
143impl_quantity_display!(Area, "m²");
144
145impl_common_ops!(Area);
146
147// -------------------------
148// Volume
149// -------------------------
150
151/// A volume quantity, stored canonically in cubic meters (m³).
152///
153/// # Construction
154/// ```
155/// use space_units::Volume;
156/// let v = Volume::from_l(500.0);
157/// ```
158///
159/// # Typed arithmetic
160/// - [`Area`] × [`Length`](crate::Length) → [`Volume`]
161/// - [`Mass`](crate::Mass) / [`Volume`] → [`Density`]
162#[must_use]
163#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
164pub struct Volume(pub(crate) f64);
165
166/// Display/conversion units for [`Volume`].
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum VolumeUnit {
169    /// Cubic meters (m³) -- SI base unit for volume.
170    CubicMeter,
171    /// Liters (L).
172    Liter,
173    /// Cubic centimeters (cm³).
174    CubicCentimeter,
175    /// Cubic feet (ft³).
176    CubicFoot,
177    /// US gallons (gal).
178    GallonUs,
179}
180
181impl VolumeUnit {
182    const fn symbol(self) -> &'static str {
183        match self {
184            Self::CubicMeter => "m^3",
185            Self::Liter => "L",
186            Self::CubicCentimeter => "cm^3",
187            Self::CubicFoot => "ft^3",
188            Self::GallonUs => "gal",
189        }
190    }
191
192    const fn m3_per_unit(self) -> f64 {
193        match self {
194            Self::CubicMeter => 1.0,
195            Self::Liter => 1e-3,
196            Self::CubicCentimeter => 1e-6,
197            Self::CubicFoot => 0.028_316_846_592,
198            Self::GallonUs => 0.003_785_411_784,
199        }
200    }
201}
202
203impl Volume {
204    /// Create from cubic meters (m³).
205    pub const fn from_m3(val: f64) -> Self {
206        Self(val)
207    }
208
209    /// Create from liters (L).
210    pub const fn from_l(val: f64) -> Self {
211        Self(val * 1e-3)
212    }
213
214    /// Create from cubic centimeters (cm³).
215    pub const fn from_cm3(val: f64) -> Self {
216        Self(val * 1e-6)
217    }
218
219    /// Create from cubic feet (ft³).
220    pub const fn from_ft3(val: f64) -> Self {
221        Self(val * 0.028_316_846_592)
222    }
223
224    /// Create from US gallons (gal).
225    pub const fn from_gal(val: f64) -> Self {
226        Self(val * 0.003_785_411_784)
227    }
228
229    /// Get value in cubic meters (m³).
230    pub const fn in_m3(self) -> f64 {
231        self.0
232    }
233
234    /// Get value in liters (L).
235    pub const fn in_l(self) -> f64 {
236        self.0 / 1e-3
237    }
238
239    /// Get value in cubic centimeters (cm³).
240    pub const fn in_cm3(self) -> f64 {
241        self.0 / 1e-6
242    }
243
244    /// Get value in cubic feet (ft³).
245    pub const fn in_ft3(self) -> f64 {
246        self.0 / 0.028_316_846_592
247    }
248
249    /// Get value in US gallons (gal).
250    pub const fn in_gal(self) -> f64 {
251        self.0 / 0.003_785_411_784
252    }
253
254    /// Get value in the specified [`VolumeUnit`].
255    pub fn in_unit(self, unit: VolumeUnit) -> f64 {
256        self.0 / unit.m3_per_unit()
257    }
258
259    /// Return a display wrapper that formats this volume in the given unit.
260    pub fn display_as(self, unit: VolumeUnit) -> DisplayWithUnit {
261        DisplayWithUnit {
262            value: self.in_unit(unit),
263            symbol: unit.symbol(),
264        }
265    }
266
267    /// Return the absolute value of this volume.
268    pub fn abs(self) -> Self {
269        Self(self.0.abs())
270    }
271}
272
273impl_quantity_display!(Volume, "m³");
274
275impl_common_ops!(Volume);
276
277// -------------------------
278// Density
279// -------------------------
280
281/// A density quantity, stored canonically in kilograms per cubic meter (kg/m³).
282///
283/// # Construction
284/// ```
285/// use space_units::Density;
286/// let d = Density::from_gpcm3(1.0); // water
287/// ```
288///
289/// # Typed arithmetic
290/// - [`Density`] × [`Volume`] → [`Mass`](crate::Mass)
291#[must_use]
292#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
293pub struct Density(pub(crate) f64);
294
295/// Display/conversion units for [`Density`].
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
297pub enum DensityUnit {
298    /// Kilograms per cubic meter (kg/m³) -- SI derived unit for density.
299    KgPerM3,
300    /// Grams per cubic centimeter (g/cm³).
301    GramPerCm3,
302    /// Pounds per cubic foot (lb/ft³).
303    PoundPerFt3,
304}
305
306impl DensityUnit {
307    const fn symbol(self) -> &'static str {
308        match self {
309            Self::KgPerM3 => "kg/m^3",
310            Self::GramPerCm3 => "g/cm^3",
311            Self::PoundPerFt3 => "lb/ft^3",
312        }
313    }
314}
315
316impl Density {
317    /// Create from kilograms per cubic meter (kg/m³).
318    pub const fn from_kgpm3(val: f64) -> Self {
319        Self(val)
320    }
321
322    /// Create from grams per cubic centimeter (g/cm³).
323    pub const fn from_gpcm3(val: f64) -> Self {
324        Self(val * 1e3)
325    }
326
327    /// Create from pounds per cubic foot (lb/ft³).
328    pub const fn from_lbpft3(val: f64) -> Self {
329        Self(val * 16.018_463)
330    }
331
332    /// Get value in kilograms per cubic meter (kg/m³).
333    pub const fn in_kgpm3(self) -> f64 {
334        self.0
335    }
336
337    /// Get value in grams per cubic centimeter (g/cm³).
338    pub const fn in_gpcm3(self) -> f64 {
339        self.0 / 1e3
340    }
341
342    /// Get value in pounds per cubic foot (lb/ft³).
343    pub const fn in_lbpft3(self) -> f64 {
344        self.0 / 16.018_463
345    }
346
347    /// Return a display wrapper that formats this density in the given unit.
348    pub const fn display_as(self, unit: DensityUnit) -> DisplayWithUnit {
349        match unit {
350            DensityUnit::KgPerM3 => DisplayWithUnit {
351                value: self.0,
352                symbol: unit.symbol(),
353            },
354            DensityUnit::GramPerCm3 => DisplayWithUnit {
355                value: self.in_gpcm3(),
356                symbol: unit.symbol(),
357            },
358            DensityUnit::PoundPerFt3 => DisplayWithUnit {
359                value: self.in_lbpft3(),
360                symbol: unit.symbol(),
361            },
362        }
363    }
364
365    /// Return the absolute value of this density.
366    pub fn abs(self) -> Self {
367        Self(self.0.abs())
368    }
369}
370
371impl_quantity_display!(Density, "kg/m³");
372
373impl_common_ops!(Density);