measurements/
force.rs

1//! Types and constants for handling force.
2
3use super::measurement::*;
4
5/// Number of POUNDS force in a Newton
6pub const POUNDS_PER_NEWTON: f64 = 0.224809;
7/// Number of POUNDALS in a Newton.  A poundal is the force necessary to
8/// accelerate 1 pound-mass at 1 foot per second per second.
9pub const POUNDALS_PER_NEWTON: f64 = 7.2330;
10/// Number of KILOPONDS in a Newton
11pub const KILOPONDS_PER_NEWTON: f64 = 1.0 / 9.80665;
12/// Number of DYNES in a Newton
13pub const DYNES_PER_NEWTON: f64 = 1e5;
14
15/// The `Force` struct can be used to deal with force in a common way.
16///
17/// #Example
18///
19/// ```
20/// use measurements::Force;
21/// use measurements::Mass;
22/// use measurements::Acceleration;
23///
24/// let metric_ton = Mass::from_metric_tons(1.0);
25/// let gravity = Acceleration::from_meters_per_second_per_second(9.81);
26/// let force: Force = metric_ton * gravity; // F=ma
27/// println!(
28///     "One metric ton exerts a force of {} due to gravity",
29///     force);
30/// ```
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32#[derive(Copy, Clone, Debug, Default)]
33pub struct Force {
34    newtons: f64,
35}
36
37impl Force {
38    /// Create a Force from a floating point value in Newtons
39    pub fn from_newtons(newtons: f64) -> Self {
40        Force { newtons }
41    }
42
43    /// Create a Force from a floating point value in Micronewtons
44    pub fn from_micronewtons(micronewtons: f64) -> Self {
45        Self::from_newtons(micronewtons / 1e6)
46    }
47
48    /// Create a Force from a floating point value in Millinewtons
49    pub fn from_millinewtons(millinewtons: f64) -> Self {
50        Self::from_newtons(millinewtons / 1e3)
51    }
52
53    /// Create a Force from a floating point value in pounds
54    pub fn from_pounds(pounds: f64) -> Self {
55        Self::from_newtons(pounds / POUNDS_PER_NEWTON)
56    }
57
58    /// Create a Force from a floating point value in poundals
59    pub fn from_poundals(poundals: f64) -> Self {
60        Self::from_newtons(poundals / POUNDALS_PER_NEWTON)
61    }
62
63    /// Create a Force from a floating point value in kiloponds
64    pub fn from_kiloponds(kiloponds: f64) -> Self {
65        Self::from_newtons(kiloponds / KILOPONDS_PER_NEWTON)
66    }
67
68    /// Create a Force from a floating point value in Dynes
69    pub fn from_dynes(dynes: f64) -> Self {
70        Self::from_newtons(dynes / DYNES_PER_NEWTON)
71    }
72
73    /// Convert this Force into a floating point value in Micronewtons
74    pub fn as_micronewtons(&self) -> f64 {
75        self.newtons * 1e6
76    }
77
78    /// Convert this Force into a floating point value in Millinewtons
79    pub fn as_millinewtons(&self) -> f64 {
80        self.newtons * 1e3
81    }
82
83    /// Convert this Force into a floating point value in Newtons
84    pub fn as_newtons(&self) -> f64 {
85        self.newtons
86    }
87
88    /// Convert this Force into a floating point value in pound-force (lb.f)
89    pub fn as_pounds(&self) -> f64 {
90        self.newtons * POUNDS_PER_NEWTON
91    }
92
93    /// Convert this Force into a floating point value in poundals
94    pub fn as_poundals(&self) -> f64 {
95        self.newtons * POUNDALS_PER_NEWTON
96    }
97
98    /// Convert this Force into a floating point value in kiloponds
99    pub fn as_kiloponds(&self) -> f64 {
100        self.newtons * KILOPONDS_PER_NEWTON
101    }
102
103    /// Convert this Force into a floating point value in dynes
104    pub fn as_dynes(&self) -> f64 {
105        self.newtons * DYNES_PER_NEWTON
106    }
107}
108
109impl Measurement for Force {
110    fn get_appropriate_units(&self) -> (&'static str, f64) {
111        // Smallest to largest
112        let list = [
113            ("nN", 1e-9),
114            ("\u{00B5}N", 1e-6),
115            ("mN", 1e-3),
116            ("N", 1e0),
117            ("kN", 1e3),
118            ("MN", 1e6),
119            ("GN", 1e9),
120            ("TN", 1e12),
121        ];
122        self.pick_appropriate_units(&list)
123    }
124
125    fn get_base_units_name(&self) -> &'static str {
126        "N"
127    }
128
129    fn as_base_units(&self) -> f64 {
130        self.newtons
131    }
132
133    fn from_base_units(units: f64) -> Self {
134        Self::from_newtons(units)
135    }
136}
137
138implement_measurement! { Force }
139
140#[cfg(test)]
141mod test {
142    use crate::{force::*, test_utils::assert_almost_eq};
143
144    #[test]
145    pub fn newtons() {
146        let i1 = Force::from_newtons(100.0);
147        let r1 = i1.as_newtons();
148
149        assert_almost_eq(r1, 100.0);
150    }
151
152    #[test]
153    pub fn micronewtons() {
154        let i1 = Force::from_newtons(100.0);
155        let r1 = i1.as_micronewtons();
156
157        let i2 = Force::from_micronewtons(100.0);
158        let r2 = i2.as_newtons();
159
160        assert_almost_eq(r1, 1e8);
161        assert_almost_eq(r2, 1e-4);
162    }
163
164    #[test]
165    pub fn millinewtons() {
166        let i1 = Force::from_newtons(100.0);
167        let r1 = i1.as_millinewtons();
168
169        let i2 = Force::from_millinewtons(100.0);
170        let r2 = i2.as_newtons();
171
172        assert_almost_eq(r1, 1e5);
173        assert_almost_eq(r2, 1e-1);
174    }
175
176    #[test]
177    pub fn pounds() {
178        let i1 = Force::from_newtons(100.0);
179        let r1 = i1.as_pounds();
180
181        let i2 = Force::from_pounds(100.0);
182        let r2 = i2.as_newtons();
183
184        assert_almost_eq(r1, 22.480886300718);
185        assert_almost_eq(r2, 444.822);
186    }
187
188    #[test]
189    pub fn poundals() {
190        let i1 = Force::from_newtons(100.0);
191        let r1 = i1.as_poundals();
192
193        let i2 = Force::from_poundals(100.0);
194        let r2 = i2.as_newtons();
195
196        assert_almost_eq(r1, 723.3016238104);
197        assert_almost_eq(r2, 13.8255);
198    }
199
200    #[test]
201    pub fn kiloponds() {
202        let i1 = Force::from_newtons(100.0);
203        let r1 = i1.as_kiloponds();
204
205        let i2 = Force::from_kiloponds(100.0);
206        let r2 = i2.as_newtons();
207
208        assert_almost_eq(r1, 10.1972);
209        assert_almost_eq(r2, 980.665);
210    }
211
212    #[test]
213    pub fn dynes() {
214        let i1 = Force::from_newtons(100.0);
215        let r1 = i1.as_dynes();
216
217        let i2 = Force::from_dynes(100.0);
218        let r2 = i2.as_newtons();
219
220        assert_almost_eq(r1, 1e7);
221        assert_almost_eq(r2, 0.001);
222    }
223
224    #[test]
225    fn add() {
226        let a = Force::from_newtons(2.0);
227        let b = Force::from_newtons(4.0);
228        let c = a + b;
229        let d = b + a;
230        assert_almost_eq(c.as_newtons(), 6.0);
231        assert_eq!(c, d);
232    }
233
234    #[test]
235    fn sub() {
236        let a = Force::from_newtons(2.0);
237        let b = Force::from_newtons(4.0);
238        let c = a - b;
239        assert_almost_eq(c.as_newtons(), -2.0);
240    }
241
242    #[test]
243    fn mul() {
244        let a = Force::from_newtons(3.0);
245        let b = a * 2.0;
246        let c = 2.0 * a;
247        assert_almost_eq(b.as_newtons(), 6.0);
248        assert_eq!(b, c);
249    }
250
251    #[test]
252    fn div() {
253        let a = Force::from_newtons(2.0);
254        let b = Force::from_newtons(4.0);
255        let c = a / b;
256        let d = a / 2.0;
257        assert_almost_eq(c, 0.5);
258        assert_almost_eq(d.as_newtons(), 1.0);
259    }
260
261    #[test]
262    fn eq() {
263        let a = Force::from_newtons(2.0);
264        let b = Force::from_newtons(2.0);
265        assert_eq!(a == b, true);
266    }
267
268    #[test]
269    fn neq() {
270        let a = Force::from_newtons(2.0);
271        let b = Force::from_newtons(4.0);
272        assert_eq!(a == b, false);
273    }
274
275    #[test]
276    fn cmp() {
277        let a = Force::from_newtons(2.0);
278        let b = Force::from_newtons(4.0);
279        assert_eq!(a < b, true);
280        assert_eq!(a <= b, true);
281        assert_eq!(a > b, false);
282        assert_eq!(a >= b, false);
283    }
284}