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}