rhusics_core/physics/
mass.rs1use std;
2use std::ops::Mul;
3
4use cgmath::{BaseFloat, Basis2, Matrix, Matrix3, Quaternion, SquareMatrix, Zero};
5
6use super::{Material, Volume};
7
8#[derive(Debug, Clone)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct Mass<S, I> {
20 mass: S,
21 inverse_mass: S,
22
23 inertia: I,
24 inverse_inertia: I,
25}
26
27pub trait Inertia: Mul<Self, Output = Self> + Copy {
29 type Orientation;
31 fn infinite() -> Self;
33 fn invert(&self) -> Self;
35 fn tensor(&self, orientation: &Self::Orientation) -> Self;
37}
38
39impl Inertia for f32 {
40 type Orientation = Basis2<f32>;
41
42 fn infinite() -> Self {
43 std::f32::INFINITY
44 }
45
46 fn invert(&self) -> Self {
47 if *self == 0. || self.is_infinite() {
48 0.
49 } else {
50 1. / *self
51 }
52 }
53
54 fn tensor(&self, _: &Basis2<f32>) -> Self {
55 *self
56 }
57}
58
59impl Inertia for f64 {
60 type Orientation = Basis2<f64>;
61
62 fn invert(&self) -> Self {
63 if *self == 0. || self.is_infinite() {
64 0.
65 } else {
66 1. / *self
67 }
68 }
69
70 fn tensor(&self, _: &Basis2<f64>) -> Self {
71 *self
72 }
73
74 fn infinite() -> Self {
75 std::f64::INFINITY
76 }
77}
78
79impl<S> Inertia for Matrix3<S>
80where
81 S: BaseFloat,
82{
83 type Orientation = Quaternion<S>;
84
85 fn invert(&self) -> Self {
86 if self.x.x.is_infinite() {
87 Matrix3::zero()
88 } else {
89 SquareMatrix::invert(self).unwrap_or_else(Matrix3::zero)
90 }
91 }
92
93 fn tensor(&self, orientation: &Quaternion<S>) -> Self {
94 let mat3 = Matrix3::from(*orientation);
95 mat3 * (*self * mat3.transpose())
96 }
97
98 fn infinite() -> Self {
99 Matrix3::from_value(S::infinity())
100 }
101}
102
103impl<S, I> Mass<S, I>
104where
105 S: BaseFloat,
106 I: Inertia,
107{
108 pub fn new(mass: S) -> Self {
110 Self::new_with_inertia(mass, I::infinite())
111 }
112
113 pub fn infinite() -> Self {
115 Self::new_with_inertia(S::infinity(), I::infinite())
116 }
117
118 pub fn new_with_inertia(mass: S, inertia: I) -> Self {
120 let inverse_mass = if mass.is_infinite() {
121 S::zero()
122 } else {
123 S::one() / mass
124 };
125 let inverse_inertia = inertia.invert();
126 Mass {
127 mass,
128 inverse_mass,
129 inertia,
130 inverse_inertia,
131 }
132 }
133
134 pub fn from_volume_and_material<V>(volume: &V, material: &Material) -> Self
136 where
137 V: Volume<S, I>,
138 {
139 volume.get_mass(material)
140 }
141
142 pub fn mass(&self) -> S {
144 self.mass
145 }
146
147 pub fn inverse_mass(&self) -> S {
149 self.inverse_mass
150 }
151
152 pub fn local_inertia(&self) -> I {
154 self.inertia
155 }
156
157 pub fn world_inertia(&self, orientation: &I::Orientation) -> I {
163 self.inertia.tensor(orientation)
164 }
165
166 pub fn local_inverse_inertia(&self) -> I {
168 self.inverse_inertia
169 }
170
171 pub fn world_inverse_inertia(&self, orientation: &I::Orientation) -> I {
177 self.inverse_inertia.tensor(orientation)
178 }
179}