microcad_lang/syntax/literal/
units.rs

1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad unit syntax element.
5
6use crate::{syntax::*, ty::*};
7
8/// Definition of type & scale of numbers.
9#[derive(Default, Clone, 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 Unit {
162    /// Return type to use with this unit.
163    pub fn ty(self) -> Type {
164        match self {
165            Self::None | Self::Percent => Type::Quantity(QuantityType::Scalar),
166            Self::Meter
167            | Self::Centimeter
168            | Self::Millimeter
169            | Self::Micrometer
170            | Self::Inch
171            | Self::Foot
172            | Self::Yard => Type::Quantity(QuantityType::Length),
173            Self::Deg | Self::DegS | Self::Grad | Self::Turns | Self::Rad => {
174                Type::Quantity(QuantityType::Angle)
175            }
176            Self::Gram | Self::Kilogram | Self::Pound | Self::Ounce => {
177                Type::Quantity(QuantityType::Weight)
178            }
179            Self::Meter2
180            | Self::Centimeter2
181            | Self::Millimeter2
182            | Self::Micrometer2
183            | Self::Inch2
184            | Self::Foot2
185            | Self::Yard2 => Type::Quantity(QuantityType::Area),
186            Self::Meter3
187            | Self::Centimeter3
188            | Self::Millimeter3
189            | Self::Micrometer3
190            | Self::Inch3
191            | Self::Foot3
192            | Self::Yard3
193            | Self::Liter
194            | Self::Centiliter
195            | Self::Milliliter
196            | Self::Microliter => Type::Quantity(QuantityType::Volume),
197            Self::GramPerMeter3 | Self::GramPerMillimeter3 => Type::Quantity(QuantityType::Density),
198        }
199    }
200
201    /// Normalize value to base unit.
202    pub fn normalize(self, x: f64) -> f64 {
203        match self {
204            // Scalar
205            Self::None => x,
206            Self::Percent => x * 0.01_f64,
207
208            // Lengths
209            Self::Meter => x * 1_000_f64,
210            Self::Centimeter => x * 10_f64,
211            Self::Millimeter => x,
212            Self::Micrometer => x / 1_000_f64,
213            Self::Inch => x * 25.4_f64,
214            Self::Foot => x * 304.8_f64,
215            Self::Yard => x * 914.4_f64,
216
217            // Angles
218            Self::Deg | Self::DegS => x / 180. * std::f64::consts::PI,
219            Self::Grad => x / 200. * std::f64::consts::PI,
220            Self::Turns => x * 2.0 * std::f64::consts::PI,
221            Self::Rad => x,
222
223            // Weights
224            Self::Gram => x,
225            Self::Kilogram => x * 1_000_f64,
226            Self::Pound => x * 453.59237_f64,
227            Self::Ounce => x * 28.349_523_125_f64,
228
229            // Areas
230            Self::Meter2 => x * 1_000_000_f64,
231            Self::Centimeter2 => x * 100_f64,
232            Self::Millimeter2 => x,
233            Self::Micrometer2 => x * 0.000_000_1,
234            Self::Inch2 => x * 645.16_f64,
235            Self::Foot2 => x * 92_903_043.04_f64,
236            Self::Yard2 => x * 836_127.36_f64,
237
238            // Volumes
239            Self::Meter3 => x * 1_000_000_000_f64,
240            Self::Centimeter3 => x * 1_000_f64,
241            Self::Millimeter3 => x,
242            Self::Micrometer3 => x * 0.000_000_000_1,
243            Self::Inch3 => x * 16_387.06_f64,
244            Self::Foot3 => x * 28_316_846.592_f64,
245            Self::Yard3 => x * 764_554_857.984_f64,
246            Self::Liter => x * 1_000_000_f64,
247            Self::Centiliter => x * 10_000_f64,
248            Self::Milliliter => x * 1_000_f64,
249            Self::Microliter => x * 1_000_000.0_f64,
250
251            // Densities
252            Self::GramPerMeter3 => 1_000_000_000_f64,
253            Self::GramPerMillimeter3 => 1_f64,
254        }
255    }
256}
257
258impl TreeDisplay for Unit {
259    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
260        if !matches!(self, Unit::None) {
261            writeln!(f, "{:depth$}Unit: {}", "", self)
262        } else {
263            Ok(())
264        }
265    }
266}