Skip to main content

microcad_lang/ty/
unit.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad unit syntax element.
5
6use crate::ty::*;
7
8/// Definition of type & scale of numbers.
9#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
10pub enum Unit {
11    // Scalar
12    /// No unit was given.
13    #[default]
14    None,
15    /// Percents
16    Percent,
17
18    // Length
19    /// Meters
20    Meter,
21    /// Centimeters
22    Centimeter,
23    /// Millimeters
24    Millimeter,
25    /// Micrometers
26    Micrometer,
27    /// Inches
28    Inch,
29    /// Feet
30    Foot,
31    /// Yards
32    Yard,
33
34    // Angle
35    /// Degree
36    Deg,
37    /// Degree
38    DegS,
39    /// Gradient
40    Grad,
41    /// Turns
42    Turns,
43    /// Radians
44    Rad,
45
46    // Weight
47    /// Grams
48    Gram,
49    /// Kilograms
50    Kilogram,
51    /// Pounds
52    Pound,
53    /// Ounces
54    Ounce,
55
56    // Areas
57    /// Square Meters
58    Meter2,
59    /// Square Centimeters
60    Centimeter2,
61    /// Square Millimeters
62    Millimeter2,
63    /// Square Micrometers
64    Micrometer2,
65    /// Square Inches
66    Inch2,
67    /// Square Foot
68    Foot2,
69    /// Square Yard
70    Yard2,
71
72    // Volumes
73    /// Cubic Meters
74    Meter3,
75    /// Cubic Centimeters
76    Centimeter3,
77    /// Cubic Millimeters
78    Millimeter3,
79    /// Cubic Micrometers
80    Micrometer3,
81    /// Cubic Inches
82    Inch3,
83    /// Cubic Foot
84    Foot3,
85    /// Cubic Yard
86    Yard3,
87    /// Liters
88    Liter,
89    /// Centiliter
90    Centiliter,
91    ///Milliliter
92    Milliliter,
93    /// Microliter
94    Microliter,
95
96    /// Density
97    GramPerMeter3,
98    /// Density
99    GramPerMillimeter3,
100}
101
102impl std::fmt::Display for Unit {
103    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
104        match self {
105            // Scalars
106            Self::None => write!(f, ""),
107            Self::Percent => write!(f, "%"),
108
109            // Lengths
110            Self::Meter => write!(f, "m"),
111            Self::Centimeter => write!(f, "cm"),
112            Self::Millimeter => write!(f, "mm"),
113            Self::Micrometer => write!(f, "µm"),
114            Self::Inch => write!(f, "in"),
115            Self::Foot => write!(f, "ft"),
116            Self::Yard => write!(f, "yd"),
117
118            // Angles
119            Self::Deg => write!(f, "deg"),
120            Self::DegS => write!(f, "°"),
121            Self::Grad => write!(f, "grad"),
122            Self::Turns => write!(f, "turns"),
123            Self::Rad => write!(f, "rad"),
124
125            // Weights
126            Self::Gram => write!(f, "g"),
127            Self::Kilogram => write!(f, "kg"),
128            Self::Pound => write!(f, "lb"),
129            Self::Ounce => write!(f, "oz"),
130
131            // Areas
132            Self::Meter2 => write!(f, "m³"),
133            Self::Centimeter2 => write!(f, "cm²"),
134            Self::Millimeter2 => write!(f, "mm²"),
135            Self::Micrometer2 => write!(f, "µm²"),
136            Self::Inch2 => write!(f, "in²"),
137            Self::Foot2 => write!(f, "ft²"),
138            Self::Yard2 => write!(f, "yd²"),
139
140            // Volumes
141            Self::Meter3 => write!(f, "m³"),
142            Self::Centimeter3 => write!(f, "cm³"),
143            Self::Millimeter3 => write!(f, "mm³"),
144            Self::Micrometer3 => write!(f, "µm³"),
145            Self::Inch3 => write!(f, "in³"),
146            Self::Foot3 => write!(f, "ft³"),
147            Self::Yard3 => write!(f, "yd³"),
148
149            Self::Milliliter => write!(f, "ml"),
150            Self::Centiliter => write!(f, "cl"),
151            Self::Liter => write!(f, "l"),
152            Self::Microliter => write!(f, "µl"),
153
154            // Density
155            Self::GramPerMeter3 => write!(f, "g/m³"),
156            Self::GramPerMillimeter3 => write!(f, "g/mm³"),
157        }
158    }
159}
160
161impl Ty for Unit {
162    /// Return type to use with this unit.
163    fn ty(&self) -> Type {
164        Type::Quantity(self.quantity_type())
165    }
166}
167
168impl Unit {
169    pub fn quantity_type(&self) -> QuantityType {
170        match self {
171            Self::None | Self::Percent => QuantityType::Scalar,
172            Self::Meter
173            | Self::Centimeter
174            | Self::Millimeter
175            | Self::Micrometer
176            | Self::Inch
177            | Self::Foot
178            | Self::Yard => QuantityType::Length,
179            Self::Deg | Self::DegS | Self::Grad | Self::Turns | Self::Rad => QuantityType::Angle,
180            Self::Gram | Self::Kilogram | Self::Pound | Self::Ounce => QuantityType::Weight,
181            Self::Meter2
182            | Self::Centimeter2
183            | Self::Millimeter2
184            | Self::Micrometer2
185            | Self::Inch2
186            | Self::Foot2
187            | Self::Yard2 => QuantityType::Area,
188            Self::Meter3
189            | Self::Centimeter3
190            | Self::Millimeter3
191            | Self::Micrometer3
192            | Self::Inch3
193            | Self::Foot3
194            | Self::Yard3
195            | Self::Liter
196            | Self::Centiliter
197            | Self::Milliliter
198            | Self::Microliter => QuantityType::Volume,
199            Self::GramPerMeter3 | Self::GramPerMillimeter3 => QuantityType::Density,
200        }
201    }
202
203    pub fn factor(&self) -> f64 {
204        match &self {
205            // Scalar
206            Self::None => 1.0,
207            Self::Percent => 0.01_f64,
208
209            // Lengths
210            Self::Meter => 1_000_f64,
211            Self::Centimeter => 10_f64,
212            Self::Millimeter => 1.0,
213            Self::Micrometer => 1.0 / 1_000_f64,
214            Self::Inch => 25.4_f64,
215            Self::Foot => 304.8_f64,
216            Self::Yard => 914.4_f64,
217
218            // Angles
219            Self::Deg | Self::DegS => 1.0 / 180. * std::f64::consts::PI,
220            Self::Grad => 1.0 / 200. * std::f64::consts::PI,
221            Self::Turns => 2.0 * std::f64::consts::PI,
222            Self::Rad => 1.0,
223
224            // Weights
225            Self::Gram => 1.0,
226            Self::Kilogram => 1_000_f64,
227            Self::Pound => 453.59237_f64,
228            Self::Ounce => 28.349_523_125_f64,
229
230            // Areas
231            Self::Meter2 => 1_000_000_f64,
232            Self::Centimeter2 => 100_f64,
233            Self::Millimeter2 => 1.0,
234            Self::Micrometer2 => 0.000_000_1,
235            Self::Inch2 => 645.16_f64,
236            Self::Foot2 => 92_903_043.04_f64,
237            Self::Yard2 => 836_127.36_f64,
238
239            // Volumes
240            Self::Meter3 => 1_000_000_000_f64,
241            Self::Centimeter3 => 1_000_f64,
242            Self::Millimeter3 => 1.0,
243            Self::Micrometer3 => 0.000_000_000_1,
244            Self::Inch3 => 16_387.06_f64,
245            Self::Foot3 => 28_316_846.592_f64,
246            Self::Yard3 => 764_554_857.984_f64,
247            Self::Liter => 1_000_000_f64,
248            Self::Centiliter => 10_000_f64,
249            Self::Milliliter => 1_000_f64,
250            Self::Microliter => 1_000_000.0_f64,
251
252            // Densities
253            Self::GramPerMeter3 => 1_000_000_000_f64,
254            Self::GramPerMillimeter3 => 1_f64,
255        }
256    }
257
258    /// Normalize value to base unit.
259    pub fn normalize(self, x: f64) -> f64 {
260        x * self.factor()
261    }
262
263    /// Denormalize value to unit
264    pub fn denormalize(self, x: f64) -> f64 {
265        x / self.factor()
266    }
267}