avian3d/dynamics/rigid_body/mass_properties/
system_param.rs1use crate::prelude::*;
2use bevy::{
3 ecs::system::{
4 lifetimeless::{Read, Write},
5 SystemParam,
6 },
7 prelude::*,
8};
9
10#[derive(SystemParam)]
14pub struct MassPropertyHelper<'w, 's> {
15 query: Query<
16 'w,
17 's,
18 (
19 Option<Read<Mass>>,
20 Option<Read<AngularInertia>>,
21 Option<Read<CenterOfMass>>,
22 Option<Read<ColliderMassProperties>>,
23 Option<Read<ColliderTransform>>,
24 Has<Sensor>,
25 ),
26 Or<(
27 With<Mass>,
28 With<AngularInertia>,
29 With<CenterOfMass>,
30 (
31 With<ColliderMassProperties>,
32 With<ColliderTransform>,
33 Without<Sensor>,
34 ),
35 )>,
36 >,
37 computed_mass_properties_query: Query<
38 'w,
39 's,
40 (
41 Write<ComputedMass>,
42 Write<ComputedAngularInertia>,
43 Write<ComputedCenterOfMass>,
44 Option<Read<Mass>>,
45 Option<Read<AngularInertia>>,
46 Option<Read<CenterOfMass>>,
47 Has<NoAutoMass>,
48 Has<NoAutoAngularInertia>,
49 Has<NoAutoCenterOfMass>,
50 ),
51 >,
52 children: Query<'w, 's, Read<Children>>,
53}
54
55impl MassPropertyHelper<'_, '_> {
56 pub fn update_mass_properties(&mut self, entity: Entity) {
61 let mut mass_props = self.total_mass_properties(entity);
63
64 let Ok((
65 mut computed_mass,
66 mut computed_inertia,
67 mut computed_com,
68 mass,
69 angular_inertia,
70 center_of_mass,
71 no_auto_mass,
72 no_auto_inertia,
73 no_auto_com,
74 )) = self.computed_mass_properties_query.get_mut(entity)
75 else {
76 return;
77 };
78
79 if no_auto_mass {
83 if let Some(mass) = mass {
84 mass_props.set_mass(mass.0, !no_auto_inertia);
85 computed_mass.set(mass_props.mass as Scalar);
86 } else if !no_auto_inertia {
87 #[allow(clippy::unnecessary_cast)]
89 mass_props.set_mass(computed_mass.value() as f32, true);
90 }
91 } else {
92 computed_mass.set(mass_props.mass as Scalar);
93 }
94
95 if no_auto_inertia {
96 if let Some(angular_inertia) = angular_inertia {
97 #[cfg(feature = "2d")]
98 {
99 mass_props.angular_inertia = angular_inertia.0;
100 computed_inertia.set(mass_props.angular_inertia as Scalar);
101 }
102 #[cfg(feature = "3d")]
103 {
104 mass_props.principal_angular_inertia = angular_inertia.principal;
105 mass_props.local_inertial_frame = angular_inertia.local_frame;
106 computed_inertia.set(
107 mass_props
108 .angular_inertia_tensor()
109 .as_mat3()
110 .adjust_precision(),
111 );
112 }
113 }
114 } else {
115 #[cfg(feature = "2d")]
116 {
117 computed_inertia.set(mass_props.angular_inertia as Scalar);
118 }
119 #[cfg(feature = "3d")]
120 {
121 computed_inertia.set(
122 mass_props
123 .angular_inertia_tensor()
124 .as_mat3()
125 .adjust_precision(),
126 );
127 }
128 }
129
130 if no_auto_com {
131 if let Some(center_of_mass) = center_of_mass {
132 mass_props.center_of_mass = center_of_mass.0;
133 computed_com.0 = mass_props.center_of_mass.adjust_precision();
134 }
135 } else {
136 computed_com.0 = mass_props.center_of_mass.adjust_precision();
137 }
138 }
139
140 pub fn total_mass_properties(&self, entity: Entity) -> MassProperties {
145 core::iter::once(self.local_mass_properties(entity))
146 .chain(
147 self.children
148 .iter_descendants(entity)
149 .map(|child| self.local_mass_properties(child)),
150 )
151 .flatten()
152 .sum()
153 }
154
155 pub fn descendants_mass_properties(&self, entity: Entity) -> MassProperties {
159 self.children
160 .iter_descendants(entity)
161 .filter_map(|child| self.local_mass_properties(child))
162 .sum()
163 }
164
165 pub fn local_mass_properties(&self, entity: Entity) -> Option<MassProperties> {
172 let (mass, angular_inertia, center_of_mass, collider_mass, collider_transform, is_sensor) =
173 self.query.get(entity).ok()?;
174
175 let mut mass_props = collider_mass
177 .filter(|_| !is_sensor)
178 .map_or(MassProperties::ZERO, |m| **m);
179
180 if let Some(mass) = mass {
182 let update_angular_inertia = angular_inertia.is_none();
185 mass_props.set_mass(mass.0, update_angular_inertia);
186 }
187
188 if let Some(angular_inertia) = angular_inertia {
190 #[cfg(feature = "2d")]
191 {
192 mass_props.angular_inertia = angular_inertia.0;
193 }
194 #[cfg(feature = "3d")]
195 {
196 mass_props.principal_angular_inertia = angular_inertia.principal;
197 mass_props.local_inertial_frame = angular_inertia.local_frame;
198 }
199 }
200
201 if let Some(center_of_mass) = center_of_mass {
203 mass_props.center_of_mass = center_of_mass.0;
204 }
205
206 if let Some(collider_transform) = collider_mass.and(collider_transform) {
207 #[cfg(feature = "2d")]
208 {
209 mass_props.transform_by(Isometry2d::new(
210 collider_transform.translation.f32(),
211 Rot2::from(collider_transform.rotation),
212 ));
213 }
214 #[cfg(feature = "3d")]
215 {
216 mass_props.transform_by(Isometry3d::new(
217 collider_transform.translation.f32(),
218 collider_transform.rotation.f32(),
219 ));
220 }
221 }
222
223 Some(mass_props)
224 }
225}