Skip to content

Commit 4d34120

Browse files
committed
Added Torque and TorqueEnergy.
1 parent f08a923 commit 4d34120

File tree

7 files changed

+301
-3
lines changed

7 files changed

+301
-3
lines changed

examples/engine.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
extern crate measurements;
2+
use measurements::{Power, AngularVelocity};
3+
4+
fn main() {
5+
let power = Power::from_ps(225.0);
6+
let peak_revs = AngularVelocity::from_rpm(6000.0);
7+
let torque = power / peak_revs;
8+
println!(
9+
"At {:.0} rpm, a {:.1} ({:.1} PS) engine, produces {:.1} ({:.1} lbf·ft)",
10+
peak_revs.as_rpm(),
11+
power,
12+
power.as_ps(),
13+
torque,
14+
torque.as_pound_foot()
15+
);
16+
}

src/angular_velocity.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Types and constants for handling speed of rotation (angular velocity)
2+
3+
use super::measurement::*;
4+
use std::f64::consts::PI;
5+
6+
/// The 'AngularVelocity' struct can be used to deal with angular velocities in a common way.
7+
///
8+
/// # Example
9+
///
10+
/// ```
11+
/// use measurements::AngularVelocity;
12+
///
13+
/// const cylinders: f64 = 6.0;
14+
/// let engine_speed = AngularVelocity::from_rpm(9000.0);
15+
/// let sparks_per_second = (engine_speed.as_hertz() / 2.0) * cylinders;
16+
/// ```
17+
#[derive(Copy, Clone, Debug)]
18+
pub struct AngularVelocity {
19+
radians_per_second: f64,
20+
}
21+
22+
impl AngularVelocity {
23+
/// Create a new AngularVelocity from a floating point value in radians per second
24+
pub fn from_radians_per_second(radians_per_second: f64) -> Self {
25+
AngularVelocity { radians_per_second: radians_per_second }
26+
}
27+
28+
/// Create a new AngularVelocity from a floating point value in revolutions per minute (RPM)
29+
pub fn from_rpm(rpm: f64) -> Self {
30+
let revs_per_second = rpm / 60.0;
31+
AngularVelocity::from_radians_per_second(revs_per_second * PI * 2.0)
32+
}
33+
34+
/// Create a new AngularVelocity from a floating point value in revolutions per second (Hz)
35+
pub fn from_hertz(hz: f64) -> Self {
36+
AngularVelocity::from_radians_per_second(hz * PI * 2.0)
37+
}
38+
39+
/// Convert this AngularVelocity to a floating point value in radians per second
40+
pub fn as_radians_per_second(&self) -> f64 {
41+
self.radians_per_second
42+
}
43+
44+
/// Convert this AngularVelocity to a floating point value in degrees
45+
pub fn as_rpm(&self) -> f64 {
46+
(self.radians_per_second * 60.0) / (2.0 * PI)
47+
}
48+
49+
/// Convert this AngularVelocity to a floating point value in revolutions per second (Hz)
50+
pub fn as_hertz(&self) -> f64 {
51+
self.radians_per_second / (2.0 * PI)
52+
}
53+
}
54+
55+
impl Measurement for AngularVelocity {
56+
fn as_base_units(&self) -> f64 {
57+
self.radians_per_second
58+
}
59+
60+
fn from_base_units(units: f64) -> Self {
61+
Self::from_radians_per_second(units)
62+
}
63+
64+
fn as_base_units_name(&self) -> &'static str {
65+
"rad/s"
66+
}
67+
}
68+
69+
implement_measurement! { AngularVelocity }
70+
71+
#[cfg(test)]
72+
mod test {
73+
use super::*;
74+
use test_utils::assert_almost_eq;
75+
76+
#[test]
77+
fn rpm() {
78+
let i1 = AngularVelocity::from_rpm(6000.0);
79+
let r1 = i1.as_radians_per_second();
80+
let i2 = AngularVelocity::from_radians_per_second(100.0);
81+
let r2 = i2.as_rpm();
82+
assert_almost_eq(r1, 628.31853);
83+
assert_almost_eq(r2, 954.929659642538);
84+
}
85+
}

src/lib.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,19 @@ pub use angle::Angle;
5151
pub mod frequency;
5252
pub use frequency::Frequency;
5353

54+
pub mod angular_velocity;
55+
pub use angular_velocity::AngularVelocity;
56+
57+
pub mod torque;
58+
pub use torque::Torque;
59+
5460
pub mod prelude;
5561

62+
mod torque_energy;
63+
pub use torque_energy::TorqueEnergy;
64+
65+
pub mod test_utils;
66+
5667
/// For given types A, B and C, implement, using base units:
5768
/// - A = B * C
5869
/// - A = C * B
@@ -129,13 +140,51 @@ impl Measurement for std::time::Duration {
129140
}
130141

131142
impl_maths!(Area, Length);
132-
impl_maths!(Energy, Force, Length);
133143
impl_maths!(Energy, std::time::Duration, Power);
134144
impl_maths!(Force, Mass, Acceleration);
135145
impl_maths!(Force, Pressure, Area);
136146
impl_maths!(Length, std::time::Duration, Speed);
137147
impl_maths!(Power, Force, Speed);
138148
impl_maths!(Speed, std::time::Duration, Acceleration);
139149
impl_maths!(Volume, Length, Area);
150+
impl_maths!(Power, AngularVelocity, Torque);
140151

141-
pub mod test_utils;
152+
// Force * Distance is ambiguous. Create an ambiguous struct the user can then
153+
// cast into either Torque or Energy.
154+
155+
impl_maths!(TorqueEnergy, Force, Length);
156+
157+
// Implement the divisions manually (the above macro only implemented the
158+
// TorqueEnergy / X operations).
159+
160+
impl ::std::ops::Div<Length> for Torque {
161+
type Output = Force;
162+
163+
fn div(self, rhs: Length) -> Self::Output {
164+
Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
165+
}
166+
}
167+
168+
impl ::std::ops::Div<Force> for Torque {
169+
type Output = Length;
170+
171+
fn div(self, rhs: Force) -> Self::Output {
172+
Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
173+
}
174+
}
175+
176+
impl ::std::ops::Div<Length> for Energy {
177+
type Output = Force;
178+
179+
fn div(self, rhs: Length) -> Self::Output {
180+
Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
181+
}
182+
}
183+
184+
impl ::std::ops::Div<Force> for Energy {
185+
type Output = Length;
186+
187+
fn div(self, rhs: Force) -> Self::Output {
188+
Self::Output::from_base_units(self.as_base_units() / rhs.as_base_units())
189+
}
190+
}

src/speed.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ impl Measurement for Speed {
108108
];
109109
self.pick_appropriate_units(&list)
110110
}
111-
112111
}
113112

114113
implement_measurement! { Speed }

src/torque.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Types and constants for handling torque
2+
3+
use super::measurement::*;
4+
5+
/// Number of pound-foot in a newton-metre
6+
const NEWTON_METRE_POUND_FOOT_FACTOR: f64 = 0.73756326522588;
7+
8+
/// The 'Torque' struct can be used to deal with torque in a common way.
9+
///
10+
/// # Example
11+
///
12+
/// ```
13+
/// use measurements::Torque;
14+
///
15+
/// let engine_torque = Torque::from_pound_foot(250.0);
16+
/// println!("In metric, that's {} Nm", engine_torque.as_newton_metres());
17+
/// ```
18+
#[derive(Copy, Clone, Debug)]
19+
pub struct Torque {
20+
newton_metres: f64,
21+
}
22+
23+
impl Torque {
24+
/// Create a new Torque from a floating point value in newton metres
25+
pub fn from_newton_metres(newton_metres: f64) -> Self {
26+
Torque { newton_metres: newton_metres }
27+
}
28+
29+
/// Create a new Torque from a floating point value in newton meters
30+
pub fn from_newton_meters(newton_meters: f64) -> Self {
31+
Torque::from_newton_metres(newton_meters)
32+
}
33+
34+
/// Create a new Torque from a floating point value in pound-foot (lbf.ft)
35+
pub fn from_pound_foot(pound_foot: f64) -> Self {
36+
Torque::from_newton_metres(pound_foot / NEWTON_METRE_POUND_FOOT_FACTOR)
37+
}
38+
39+
/// Convert this Torque to a floating point value in newton metres
40+
pub fn as_newton_metres(&self) -> f64 {
41+
self.newton_metres
42+
}
43+
44+
/// Convert this Torque to a floating point value in newton meters
45+
pub fn as_newton_meters(&self) -> f64 {
46+
self.newton_metres
47+
}
48+
49+
/// Convert this Torque to a floating point value in pound-foot (lbf-ft)
50+
pub fn as_pound_foot(&self) -> f64 {
51+
self.newton_metres * NEWTON_METRE_POUND_FOOT_FACTOR
52+
}
53+
}
54+
55+
impl Measurement for Torque {
56+
fn as_base_units(&self) -> f64 {
57+
self.newton_metres
58+
}
59+
60+
fn from_base_units(units: f64) -> Self {
61+
Self::from_newton_metres(units)
62+
}
63+
64+
fn as_base_units_name(&self) -> &'static str {
65+
"Nm"
66+
}
67+
}
68+
69+
implement_measurement! { Torque }
70+
71+
#[cfg(test)]
72+
mod test {
73+
use super::*;
74+
use test_utils::assert_almost_eq;
75+
76+
#[test]
77+
fn lbf_ft() {
78+
let i1 = Torque::from_pound_foot(250.0);
79+
let r1 = i1.as_newton_metres();
80+
let i2 = Torque::from_newton_metres(300.0);
81+
let r2 = i2.as_pound_foot();
82+
assert_almost_eq(r1, 338.954);
83+
assert_almost_eq(r2, 221.269);
84+
}
85+
}

src/torque_energy.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! Implements a bridging structure to distinguish between Torque and Energy
2+
3+
use super::*;
4+
5+
/// If you multiply a Force by a Length, we can't tell if you're
6+
/// pushing something along (which requires Energy) or rotating
7+
/// something (which creates a Torque). This struct is what results
8+
/// from the multiplication, and you have to then convert
9+
/// it to whichever you want.
10+
pub struct TorqueEnergy {
11+
newton_metres: f64,
12+
}
13+
14+
impl std::convert::From<TorqueEnergy> for Torque {
15+
fn from(t: TorqueEnergy) -> Torque {
16+
Torque::from_newton_metres(t.newton_metres)
17+
}
18+
}
19+
20+
impl std::convert::From<TorqueEnergy> for Energy {
21+
fn from(t: TorqueEnergy) -> Energy {
22+
Energy::from_joules(t.newton_metres)
23+
}
24+
}
25+
26+
impl Measurement for TorqueEnergy {
27+
fn as_base_units(&self) -> f64 {
28+
self.newton_metres
29+
}
30+
31+
fn from_base_units(units: f64) -> Self {
32+
TorqueEnergy { newton_metres: units }
33+
}
34+
35+
fn as_base_units_name(&self) -> &'static str {
36+
"Nm||J"
37+
}
38+
}

tests/torque_and_energy.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
extern crate measurements;
2+
3+
use measurements::*;
4+
5+
#[test]
6+
fn create() -> () {
7+
let f = Force::from_newtons(10.0);
8+
let d = Length::from_metres(1.0);
9+
let w: Energy = Energy::from(f * d);
10+
let t: Torque = Torque::from(f * d);
11+
println!("That's {} as energy", w);
12+
println!("That's {} as torque", t);
13+
}
14+
15+
#[test]
16+
fn divide() -> () {
17+
let w = Energy::from_joules(100.0);
18+
let d = Length::from_metres(10.0);
19+
let f: Force = w / d;
20+
test_utils::assert_almost_eq(f.as_newtons(), 10.0);
21+
22+
let t = Torque::from_newton_metres(100.0);
23+
let d = Length::from_metres(10.0);
24+
let f: Force = t / d;
25+
test_utils::assert_almost_eq(f.as_newtons(), 10.0);
26+
}

0 commit comments

Comments
 (0)