lib3mf_core/model/units.rs
1use serde::{Deserialize, Serialize};
2
3/// Units of measurement for the 3MF model.
4///
5/// Defines how vertex coordinates and dimensions are interpreted in real-world
6/// measurements. The unit applies to all geometric coordinates in the model
7/// (vertices, transformations, radii, etc.).
8///
9/// Per the 3MF specification, the default unit is Millimeter if not specified.
10///
11/// # Examples
12///
13/// ```
14/// use lib3mf_core::model::Unit;
15///
16/// // Default is millimeter
17/// let unit = Unit::default();
18/// assert_eq!(unit, Unit::Millimeter);
19///
20/// // Convert between units
21/// let inches = Unit::Inch.convert(1.0, Unit::Millimeter);
22/// assert!((inches - 25.4).abs() < 1e-5);
23///
24/// // Get scale factor to meters
25/// assert_eq!(Unit::Millimeter.scale_factor(), 0.001);
26/// ```
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
28#[serde(rename_all = "lowercase")]
29pub enum Unit {
30 /// Micrometers - 0.000001 meters (1 μm)
31 Micron,
32 /// Millimeters - 0.001 meters (1 mm) - Default per 3MF spec
33 #[default]
34 Millimeter,
35 /// Centimeters - 0.01 meters (1 cm)
36 Centimeter,
37 /// Inches - 0.0254 meters (1 in)
38 Inch,
39 /// Feet - 0.3048 meters (1 ft)
40 Foot,
41 /// Meters - 1.0 meters (1 m)
42 Meter,
43}
44
45impl Unit {
46 /// Returns the scale factor to convert this unit to meters.
47 ///
48 /// # Examples
49 ///
50 /// ```
51 /// use lib3mf_core::model::Unit;
52 ///
53 /// assert_eq!(Unit::Millimeter.scale_factor(), 0.001);
54 /// assert_eq!(Unit::Meter.scale_factor(), 1.0);
55 /// ```
56 pub fn scale_factor(&self) -> f64 {
57 match self {
58 Unit::Micron => 1e-6,
59 Unit::Millimeter => 0.001,
60 Unit::Centimeter => 0.01,
61 Unit::Inch => 0.0254,
62 Unit::Foot => 0.3048,
63 Unit::Meter => 1.0,
64 }
65 }
66
67 /// Converts a value from this unit to another target unit.
68 ///
69 /// # Arguments
70 ///
71 /// * `value` - The value in this unit
72 /// * `target` - The unit to convert to
73 ///
74 /// # Returns
75 ///
76 /// The value converted to the target unit.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use lib3mf_core::model::Unit;
82 ///
83 /// // 1 inch = 25.4 mm
84 /// let mm = Unit::Inch.convert(1.0, Unit::Millimeter);
85 /// assert!((mm - 25.4).abs() < 1e-5);
86 ///
87 /// // 1000 mm = 1 meter
88 /// let m = Unit::Millimeter.convert(1000.0, Unit::Meter);
89 /// assert!((m - 1.0).abs() < 1e-5);
90 /// ```
91 pub fn convert(&self, value: f64, target: Unit) -> f64 {
92 if *self == target {
93 return value;
94 }
95 let meters = value * self.scale_factor();
96 meters / target.scale_factor()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_scale_factors() {
106 assert!((Unit::Millimeter.scale_factor() - 0.001).abs() < 1e-10);
107 assert!((Unit::Inch.scale_factor() - 0.0254).abs() < 1e-10);
108 }
109
110 #[test]
111 fn test_conversion() {
112 // 1 inch is 25.4 mm
113 let val = Unit::Inch.convert(1.0, Unit::Millimeter);
114 assert!((val - 25.4).abs() < 1e-5);
115
116 // 1000 mm is 1 meter
117 let val = Unit::Millimeter.convert(1000.0, Unit::Meter);
118 assert!((val - 1.0).abs() < 1e-5);
119 }
120}