Skip to main content

oxml_core/
length.rs

1//! Length unit type with convenient constructors.
2
3use crate::units::{Emu, HalfPoint, Twips};
4
5/// A length measurement that can be expressed in various units.
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Length {
8    emu: i64,
9}
10
11impl Length {
12    /// Create a length from inches.
13    pub fn inches(val: f64) -> Self {
14        Length {
15            emu: (val * 914400.0) as i64,
16        }
17    }
18
19    /// Create a length from centimeters.
20    pub fn cm(val: f64) -> Self {
21        Length {
22            emu: (val * 360000.0) as i64,
23        }
24    }
25
26    /// Create a length from millimetres.
27    pub fn mm(val: f64) -> Self {
28        Length {
29            emu: (val * 36000.0) as i64,
30        }
31    }
32
33    /// Create a length from points.
34    pub fn pt(val: f64) -> Self {
35        Length {
36            emu: (val * 12700.0) as i64,
37        }
38    }
39
40    /// Create a length from EMUs.
41    pub fn emu(val: i64) -> Self {
42        Length { emu: val }
43    }
44
45    /// Create a length from twips.
46    pub fn twips(val: i32) -> Self {
47        Length {
48            emu: val as i64 * 635,
49        }
50    }
51
52    /// Get the value in inches.
53    pub fn to_inches(self) -> f64 {
54        self.emu as f64 / 914400.0
55    }
56
57    /// Get the value in centimeters.
58    pub fn to_cm(self) -> f64 {
59        self.emu as f64 / 360000.0
60    }
61
62    /// Get the value in points.
63    pub fn to_pt(self) -> f64 {
64        self.emu as f64 / 12700.0
65    }
66
67    /// Get the value in EMUs.
68    pub fn to_emu(self) -> i64 {
69        self.emu
70    }
71
72    /// Get the value in twips.
73    pub fn to_twips(self) -> i32 {
74        (self.emu / 635) as i32
75    }
76
77    /// Convert to the OXML Twips type.
78    pub fn as_twips(self) -> Twips {
79        Twips(self.to_twips())
80    }
81
82    /// Convert to the OXML Emu type.
83    pub fn as_emu(self) -> Emu {
84        Emu(self.emu)
85    }
86
87    /// Convert to the OXML HalfPoint type (for font sizes).
88    pub fn as_half_points(self) -> HalfPoint {
89        HalfPoint((self.to_pt() * 2.0) as u32)
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn length_conversions() {
99        let one_inch = Length::inches(1.0);
100        assert!((one_inch.to_inches() - 1.0).abs() < 0.001);
101        assert!((one_inch.to_cm() - 2.54).abs() < 0.01);
102        assert!((one_inch.to_pt() - 72.0).abs() < 0.01);
103        assert_eq!(one_inch.to_twips(), 1440);
104    }
105
106    #[test]
107    fn length_from_pt() {
108        let twelve_pt = Length::pt(12.0);
109        assert_eq!(twelve_pt.as_half_points().0, 24);
110    }
111
112    #[test]
113    fn length_float_constructors_truncate_toward_zero() {
114        assert_eq!(Length::inches(1.75 / 914400.0).to_emu(), 1);
115        assert_eq!(Length::inches(-1.75 / 914400.0).to_emu(), -1);
116        assert_eq!(Length::cm(1.75 / 360000.0).to_emu(), 1);
117        assert_eq!(Length::cm(-1.75 / 360000.0).to_emu(), -1);
118        assert_eq!(Length::pt(1.75 / 12700.0).to_emu(), 1);
119        assert_eq!(Length::pt(-1.75 / 12700.0).to_emu(), -1);
120
121        assert_eq!(Length::emu(7).to_emu(), 7);
122        assert_eq!(Length::emu(-7).to_emu(), -7);
123        assert_eq!(Length::twips(7).to_emu(), 4445);
124        assert_eq!(Length::twips(-7).to_emu(), -4445);
125    }
126
127    #[test]
128    fn length_millimetres_round_trip() {
129        assert_eq!(Length::mm(25.4).to_emu(), 914_400);
130        assert_eq!(Length::mm(1.75 / 36_000.0).to_emu(), 1);
131        assert_eq!(Length::mm(-1.75 / 36_000.0).to_emu(), -1);
132    }
133}