1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// fisica::units::force
//
//!
//
use crate::units::{Acceleration, Distance, GravitationalFieldStrength, Length, Mass, Moment};
use crate::{Direction, Magnitude};
/// Any interaction that, when unopposed, will change the motion of an object,
/// measured in `N` (newtons).
///
/// See also:
/// - [Weight]
///
/// # External links
/// - <https://en.wikipedia.org/wiki/Force>
/// - <https://en.wikipedia.org/wiki/Newton_(unit)>
#[derive(Clone, Copy, Debug)]
pub struct Force {
pub d: Direction,
}
impl Force {
/// new Force.
#[inline]
pub const fn new(d: Direction) -> Self {
Self { d }
}
/// Returns the magnitude.
#[inline]
pub fn m(&self) -> Magnitude {
self.d.magnitude()
}
}
/// (== [`Force`]) The pull of gravity on an object.
pub type Weight = Force;
/// # Formulas: [`Force`]
impl Force {
/// Derives the `Force` from the given [`Mass`] and [`Acceleration`] (`F = m × a`).
pub fn from_mass_acceleration(m: Mass, a: Acceleration) -> Self {
Self::new(a.d * m.m())
}
/// (Alias of [from_mass_acceleration][Force::from_mass_acceleration]).
#[inline]
pub fn from_acceleration_mass(a: Acceleration, m: Mass) -> Self {
Self::from_mass_acceleration(m, a)
}
/// Calculates the [`Mass`] given the [`Acceleration`] (`m = F / a`).
#[inline]
pub fn calc_mass(&self, a: Acceleration) -> Mass {
Mass::new(self.m() / a.m())
}
/// Calculates the [`Acceleration`] given the [`Mass`] (`a = F / m`).
#[inline]
pub fn calc_acceleration(&self, m: Mass) -> Acceleration {
Acceleration::new(self.d / m.m())
}
/// Derives the `Force` from the given [`Moment`] and [`Distance`] (`F = M / d`).
pub fn from_moment_distance(m: Moment, d: Distance) -> Self {
Self::new(m.d / d.m())
}
/// (Alias of [from_moment_distance][Force::from_moment_distance]).
#[inline]
pub fn from_distance_moment(d: Distance, m: Moment) -> Self {
Self::from_moment_distance(m, d)
}
/// Calculates the [`Moment`] given the [`Distance`] (`M = F × d`).
#[inline]
pub fn calc_moment(&self, d: Distance) -> Moment {
Moment::new(self.d * d.m())
}
/// Calculates the [`Distance`] given the [`Moment`] (`d = M / F`).
#[inline]
pub fn calc_distance(&self, m: Moment) -> Distance {
Length::new(m.m() / self.m())
}
}
/// # Formulas: [`Weight`]
impl Weight {
/// Returns the `Weight` given the [`Mass`] and [`GravitationalFieldStrength`]
/// (`w = m × g`).
///
/// # Example
///
/// A mass of 60 kg would weight 588 N in Earth and 96 N in the Moon (6.125
/// times less), as heavy as a 9.79 kg mass would feel in Earth.
///
/// ```
/// # use fisica::units::{Mass, Weight, Gfs};
/// let mass = Mass::in_kilograms(60.);
/// let w_earth = Weight::from_mass_gfs(mass, Gfs::in_earth());
/// let w_moon = Weight::from_mass_gfs(mass, Gfs::in_moon());
/// let ratio = w_earth.m() / w_moon.m();
/// print!("A mass of {} would weight {} in Earth and {} in the Moon ({} times less)",
/// mass, w_earth, w_moon, ratio);
/// println!(", as heavy as a {} mass would feel in Earth",
/// Mass::in_kg(mass.m() / ratio));
/// ```
///
/// # Trivia
///
/// A common home scale in reality measures the Weight (Force), calibrated
/// to show the Mass in kg, assuming it's being used on Earth's surface.
pub fn from_mass_gfs(m: Mass, g: GravitationalFieldStrength) -> Self {
Self::new(g.d * m.m())
}
/// Calculates the [`Mass`] given the [`GravitationalFieldStrength`] (`m = w / g`).
#[inline]
pub fn calc_mass_from_gfs(&self, g: GravitationalFieldStrength) -> Mass {
Mass::new(self.m() / g.m())
}
/// Calculates the [`GravitationalFieldStrength`] given the [`Mass`] (`g = w / m`).
#[inline]
pub fn calc_gfs(&self, m: Mass) -> GravitationalFieldStrength {
GravitationalFieldStrength::new(self.d / m.m())
}
}
impl_vector_methods![Force, N, newtons];
#[cfg(test)]
mod tests {
use {super::*, float_eq::assert_float_eq};
/// Checks the formulas behave as expected.
#[test]
fn force_formulas() {
// Force, Acceleration & Mass
let force = Force::from_mass_acceleration(
Mass::new(5.),
Acceleration::new(Direction::new(2., 0., 0.)),
);
assert_float_eq!(10., force.m(), r2nd <= Magnitude::EPSILON);
assert_float_eq!(
5.,
force
.calc_mass(Acceleration::new(Direction::new(2., 0., 0.)))
.m(),
r2nd <= Magnitude::EPSILON
);
assert_float_eq!(
2.,
force.calc_acceleration(Mass::new(5.)).m(),
r2nd <= Magnitude::EPSILON
);
// Distance, Moment & Force
let force =
Force::from_moment_distance(Moment::new(Direction::new(6., 0., 0.)), Length::new(0.2));
assert_float_eq!(30., force.m(), r2nd <= Magnitude::EPSILON);
assert_float_eq!(
0.2,
force
.calc_distance(Moment::new(Direction::new(6., 0., 0.)))
.m(),
r2nd <= Magnitude::EPSILON
);
assert_float_eq!(
6.,
force.calc_moment(Length::new(0.2)).m(),
r2nd <= Magnitude::EPSILON
);
}
}