avian3d/dynamics/rigid_body/forces/query_data.rs
1use crate::{dynamics::integrator::VelocityIntegrationData, prelude::*};
2use bevy::ecs::{
3 query::{Has, QueryData},
4 system::lifetimeless::{Read, Write},
5};
6
7use super::AccumulatedLocalAcceleration;
8
9/// A helper [`QueryData`] for applying forces, impulses, and accelerations to dynamic [rigid bodies](RigidBody).
10///
11/// For constant forces that persist across time steps, consider using components like [`ConstantForce`] instead.
12///
13/// See the [module-level documentation](crate::dynamics::rigid_body::forces) for more general information about forces in Avian.
14///
15/// # Usage
16///
17/// To use [`Forces`], add it to a [`Query`](bevy::prelude::Query) (without `&` or `&mut`),
18/// and use the associated methods to apply forces, impulses, and accelerations to the rigid bodies.
19///
20/// ```
21#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
22#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
23/// # use bevy::prelude::*;
24/// #
25/// # #[cfg(feature = "f32")]
26/// fn apply_forces(mut query: Query<Forces>) {
27/// for mut forces in &mut query {
28/// // Apply a force of 10 N in the positive Y direction to the entity.
29#[cfg_attr(
30 feature = "2d",
31 doc = " forces.apply_force(Vec2::new(0.0, 10.0));"
32)]
33#[cfg_attr(
34 feature = "3d",
35 doc = " forces.apply_force(Vec3::new(0.0, 10.0, 0.0));"
36)]
37/// }
38/// }
39/// ```
40///
41/// The force is applied continuously during the physics step, and cleared automatically after the step is complete.
42///
43/// By default, applying forces to [sleeping](Sleeping) bodies will wake them up. If this is not desired,
44/// the [`non_waking`](ForcesItem::non_waking) method can be used to fetch a [`NonWakingForcesItem`]
45/// that allows applying forces to a body without waking it up.
46///
47/// ```
48#[cfg_attr(feature = "2d", doc = "# use avian2d::{math::Vector, prelude::*};")]
49#[cfg_attr(feature = "3d", doc = "# use avian3d::{math::Vector, prelude::*};")]
50/// # use bevy::prelude::*;
51/// #
52/// # fn apply_impulses(mut query: Query<Forces>) {
53/// # for mut forces in &mut query {
54/// # let force = Vector::default();
55/// // Apply a force without waking up the body if it is sleeping.
56/// forces.non_waking().apply_force(force);
57/// # }
58/// # }
59/// ```
60///
61/// [`Forces`] can also apply forces and impulses at a specific point in the world. If the point is not aligned
62/// with the [center of mass](CenterOfMass), it will apply a torque to the body.
63///
64/// ```
65#[cfg_attr(feature = "2d", doc = "# use avian2d::{math::Vector, prelude::*};")]
66#[cfg_attr(feature = "3d", doc = "# use avian3d::{math::Vector, prelude::*};")]
67/// # use bevy::prelude::*;
68/// #
69/// # fn apply_impulses(mut query: Query<Forces>) {
70/// # for mut forces in &mut query {
71/// # let force = Vector::default();
72/// # let point = Vector::default();
73/// // Apply an impulse at a specific point in the world.
74/// // Unlike forces, impulses are applied immediately to the velocity.
75/// forces.apply_linear_impulse_at_point(force, point);
76/// # }
77/// # }
78/// ```
79///
80/// As an example, you could implement radial gravity that pulls rigid bodies towards the world origin
81/// with a system like the following:
82///
83/// ```
84#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
85#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
86/// # use bevy::prelude::*;
87/// #
88/// # #[cfg(feature = "f32")]
89/// fn radial_gravity(mut query: Query<(Forces, &GlobalTransform)>) {
90/// for (mut forces, global_transform) in &mut query {
91/// // Compute the direction towards the center of the world.
92/// let direction = -global_transform.translation().normalize_or_zero();
93/// // Apply a linear acceleration of 9.81 m/s² towards the center of the world.
94#[cfg_attr(
95 feature = "2d",
96 doc = " forces.apply_linear_acceleration(direction.truncate() * 9.81);"
97)]
98#[cfg_attr(
99 feature = "3d",
100 doc = " forces.apply_linear_acceleration(direction * 9.81);"
101)]
102/// }
103/// }
104/// ```
105#[derive(QueryData)]
106#[query_data(mutable)]
107pub struct Forces {
108 position: Read<Position>,
109 rotation: Read<Rotation>,
110 linear_velocity: Write<LinearVelocity>,
111 angular_velocity: Write<AngularVelocity>,
112 mass: Read<ComputedMass>,
113 angular_inertia: Read<ComputedAngularInertia>,
114 center_of_mass: Read<ComputedCenterOfMass>,
115 locked_axes: Option<Read<LockedAxes>>,
116 integration: Write<VelocityIntegrationData>,
117 accumulated_local_acceleration: Write<AccumulatedLocalAcceleration>,
118 sleep_timer: Option<Write<SleepTimer>>,
119 is_sleeping: Has<Sleeping>,
120}
121
122/// A [`ForcesItem`] that does not wake up the body when applying forces, torques, impulses, or accelerations.
123/// Returned by [`ForcesItem::non_waking`].
124///
125/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
126pub struct NonWakingForcesItem<'w, 's>(pub ForcesItem<'w, 's>);
127
128impl ForcesItem<'_, '_> {
129 /// Reborrows `self` as a new instance of [`ForcesItem`].
130 #[inline]
131 #[must_use]
132 pub fn reborrow(&mut self) -> ForcesItem<'_, '_> {
133 ForcesItem {
134 position: self.position,
135 rotation: self.rotation,
136 linear_velocity: self.linear_velocity.reborrow(),
137 angular_velocity: self.angular_velocity.reborrow(),
138 mass: self.mass,
139 angular_inertia: self.angular_inertia,
140 center_of_mass: self.center_of_mass,
141 locked_axes: self.locked_axes,
142 integration: self.integration.reborrow(),
143 accumulated_local_acceleration: self.accumulated_local_acceleration.reborrow(),
144 sleep_timer: self.sleep_timer.as_mut().map(|s| s.reborrow()),
145 is_sleeping: self.is_sleeping,
146 }
147 }
148
149 /// Returns a [`NonWakingForcesItem`] that allows applying forces, impulses, and accelerations
150 /// without waking up the body if it is sleeping.
151 #[inline]
152 #[must_use]
153 pub fn non_waking(&mut self) -> NonWakingForcesItem<'_, '_> {
154 NonWakingForcesItem(self.reborrow())
155 }
156}
157
158impl<'w, 's> NonWakingForcesItem<'w, 's> {
159 /// Returns a [`ForcesItem`] that will wake up the body when applying forces, impulses, or accelerations.
160 #[inline]
161 #[must_use]
162 pub fn waking(self) -> ForcesItem<'w, 's> {
163 self.0
164 }
165}
166
167impl RigidBodyForces for ForcesItem<'_, '_> {}
168impl RigidBodyForces for NonWakingForcesItem<'_, '_> {}
169
170/// A trait for applying forces, impulses, and accelerations to a dynamic [rigid body](RigidBody).
171///
172/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
173/// returned by [`Forces`].
174///
175/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
176#[expect(
177 private_bounds,
178 reason = "The `data` method should not be publicly accessible."
179)]
180pub trait RigidBodyForces: RigidBodyForcesInternal {
181 /// Applies a force at the center of mass in world space. The unit is typically N or kg⋅m/s².
182 ///
183 /// The force is applied continuously over the physics step and cleared afterwards.
184 ///
185 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
186 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
187 #[inline]
188 fn apply_force(&mut self, force: Vector) {
189 if force != Vector::ZERO && self.try_wake_up() {
190 let acceleration = self.inverse_mass() * force;
191 self.integration_data_mut()
192 .apply_linear_acceleration(acceleration);
193 }
194 }
195
196 /// Applies a force at the given point in world space. The unit is typically N or kg⋅m/s².
197 ///
198 /// If the point is not at the center of mass, the force will also generate a torque.
199 ///
200 /// The force is applied continuously over the physics step and cleared afterwards.
201 ///
202 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
203 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
204 ///
205 /// # Note
206 ///
207 /// If the [`Transform`] of the body is modified before applying the force,
208 /// the torque will be computed using an outdated global center of mass.
209 /// This may cause problems when applying a force right after teleporting
210 /// an entity, as the torque could grow very large if the distance between the point
211 /// and old center of mass is large.
212 ///
213 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
214 /// to update the global physics transform after modifying [`Transform`].
215 ///
216 /// [`Transform`]: bevy::transform::components::Transform
217 #[inline]
218 fn apply_force_at_point(&mut self, force: Vector, world_point: Vector) {
219 // Note: This does not consider the rotation of the body during substeps,
220 // so the torque may not be accurate if the body is rotating quickly.
221 self.apply_force(force);
222 self.apply_torque(cross(world_point - self.global_center_of_mass(), force));
223 }
224
225 /// Applies a force at the center of mass in local space. The unit is typically N or kg⋅m/s².
226 ///
227 /// The force is applied continuously over the physics step and cleared afterwards.
228 ///
229 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
230 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
231 #[inline]
232 fn apply_local_force(&mut self, force: Vector) {
233 if force != Vector::ZERO && self.try_wake_up() {
234 let acceleration = self.inverse_mass() * force;
235 self.accumulated_local_acceleration_mut().linear += acceleration;
236 }
237 }
238
239 /// Applies a torque in world space. The unit is typically N⋅m or kg⋅m²/s².
240 ///
241 /// The torque is applied continuously over the physics step and cleared afterwards.
242 ///
243 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
244 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
245 #[inline]
246 fn apply_torque(&mut self, torque: AngularVector) {
247 if torque != AngularVector::ZERO && self.try_wake_up() {
248 let acceleration = self.global_inverse_angular_inertia() * torque;
249 self.integration_data_mut()
250 .apply_angular_acceleration(acceleration);
251 }
252 }
253
254 /// Applies a torque in local space. The unit is typically N⋅m or kg⋅m²/s².
255 ///
256 /// The torque is applied continuously over the physics step and cleared afterwards.
257 ///
258 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
259 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
260 #[cfg(feature = "3d")]
261 #[inline]
262 fn apply_local_torque(&mut self, torque: AngularVector) {
263 if torque != AngularVector::ZERO && self.try_wake_up() {
264 let acceleration = self.inverse_angular_inertia() * torque;
265 self.accumulated_local_acceleration_mut().angular += acceleration;
266 }
267 }
268
269 /// Applies a linear impulse at the center of mass in world space. The unit is typically N⋅s or kg⋅m/s.
270 ///
271 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
272 ///
273 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
274 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
275 #[inline]
276 fn apply_linear_impulse(&mut self, impulse: Vector) {
277 if impulse != Vector::ZERO && self.try_wake_up() {
278 let effective_inverse_mass = self
279 .locked_axes()
280 .apply_to_vec(Vector::splat(self.inverse_mass()));
281 let delta_vel = effective_inverse_mass * impulse;
282 *self.linear_velocity_mut() += delta_vel;
283 }
284 }
285
286 /// Applies a linear impulse at the given point in world space. The unit is typically N⋅s or kg⋅m/s.
287 ///
288 /// If the point is not at the center of mass, the impulse will also generate an angular impulse.
289 ///
290 /// The impulse modifies the [`LinearVelocity`] and [`AngularVelocity`] of the body immediately.
291 ///
292 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
293 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
294 ///
295 /// # Note
296 ///
297 /// If the [`Transform`] of the body is modified before applying the impulse,
298 /// the torque will be computed using an outdated global center of mass.
299 /// This may cause problems when applying a impulse right after teleporting
300 /// an entity, as the torque could grow very large if the distance between the point
301 /// and old center of mass is large.
302 ///
303 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
304 /// to update the global physics transform after modifying [`Transform`].
305 ///
306 /// [`Transform`]: bevy::transform::components::Transform
307 #[inline]
308 fn apply_linear_impulse_at_point(&mut self, impulse: Vector, world_point: Vector) {
309 self.apply_linear_impulse(impulse);
310 self.apply_angular_impulse(cross(world_point - self.global_center_of_mass(), impulse));
311 }
312
313 /// Applies a linear impulse in local space. The unit is typically N⋅s or kg⋅m/s.
314 ///
315 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
316 ///
317 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
318 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
319 #[inline]
320 fn apply_local_linear_impulse(&mut self, impulse: Vector) {
321 if impulse != Vector::ZERO && self.try_wake_up() {
322 let world_impulse = self.rot() * impulse;
323 let effective_inverse_mass = self
324 .locked_axes()
325 .apply_to_vec(Vector::splat(self.inverse_mass()));
326 let delta_vel = effective_inverse_mass * world_impulse;
327 *self.linear_velocity_mut() += delta_vel;
328 }
329 }
330
331 /// Applies an angular impulse in world space. The unit is typically N⋅m⋅s or kg⋅m²/s.
332 ///
333 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
334 ///
335 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
336 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
337 #[inline]
338 fn apply_angular_impulse(&mut self, impulse: AngularVector) {
339 if impulse != AngularVector::ZERO && self.try_wake_up() {
340 let effective_inverse_angular_inertia = self
341 .locked_axes()
342 .apply_to_angular_inertia(self.global_inverse_angular_inertia());
343 let delta_vel = effective_inverse_angular_inertia * impulse;
344 *self.angular_velocity_mut() += delta_vel;
345 }
346 }
347
348 /// Applies an angular impulse in local space. The unit is typically N⋅m⋅s or kg⋅m²/s.
349 ///
350 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
351 ///
352 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
353 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
354 #[cfg(feature = "3d")]
355 #[inline]
356 fn apply_local_angular_impulse(&mut self, impulse: AngularVector) {
357 if impulse != AngularVector::ZERO && self.try_wake_up() {
358 let world_impulse = self.rot() * impulse;
359 let effective_inverse_angular_inertia = self
360 .locked_axes()
361 .apply_to_angular_inertia(self.global_inverse_angular_inertia());
362 let delta_vel = effective_inverse_angular_inertia * world_impulse;
363 *self.angular_velocity_mut() += delta_vel;
364 }
365 }
366
367 /// Applies a linear acceleration, ignoring mass. The unit is typically m/s².
368 ///
369 /// The acceleration is applied continuously over the physics step and cleared afterwards.
370 ///
371 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
372 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
373 #[inline]
374 fn apply_linear_acceleration(&mut self, acceleration: Vector) {
375 if acceleration != Vector::ZERO && self.try_wake_up() {
376 self.integration_data_mut()
377 .apply_linear_acceleration(acceleration);
378 }
379 }
380
381 /// Applies a linear acceleration at the given point in world space. The unit is typically m/s².
382 ///
383 /// If the point is not at the center of mass, the acceleration will also generate an angular acceleration.
384 ///
385 /// The acceleration is applied continuously over the physics step and cleared afterwards.
386 ///
387 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
388 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
389 ///
390 /// # Note
391 ///
392 /// If the [`Transform`] of the body is modified before applying the acceleration,
393 /// the angular acceleration will be computed using an outdated global center of mass.
394 /// This may cause problems when applying a acceleration right after teleporting
395 /// an entity, as the angular acceleration could grow very large if the distance between the point
396 /// and old center of mass is large.
397 ///
398 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
399 /// to update the global physics transform after modifying [`Transform`].
400 ///
401 /// [`Transform`]: bevy::transform::components::Transform
402 #[inline]
403 fn apply_linear_acceleration_at_point(&mut self, acceleration: Vector, world_point: Vector) {
404 self.apply_linear_acceleration(acceleration);
405 self.apply_angular_acceleration(cross(
406 world_point - self.global_center_of_mass(),
407 acceleration,
408 ));
409 }
410
411 /// Applies a linear acceleration in local space, ignoring mass. The unit is typically m/s².
412 ///
413 /// The acceleration is applied continuously over the physics step and cleared afterwards.
414 ///
415 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
416 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
417 #[inline]
418 fn apply_local_linear_acceleration(&mut self, acceleration: Vector) {
419 if acceleration != Vector::ZERO && self.try_wake_up() {
420 self.accumulated_local_acceleration_mut().linear += acceleration;
421 }
422 }
423
424 /// Applies an angular acceleration, ignoring angular inertia. The unit is rad/s².
425 ///
426 /// The acceleration is applied continuously over the physics step and cleared afterwards.
427 ///
428 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
429 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
430 #[inline]
431 fn apply_angular_acceleration(&mut self, acceleration: AngularVector) {
432 if acceleration != AngularVector::ZERO && self.try_wake_up() {
433 self.integration_data_mut()
434 .apply_angular_acceleration(acceleration);
435 }
436 }
437
438 /// Applies an angular acceleration in local space, ignoring angular inertia. The unit is rad/s².
439 ///
440 /// The acceleration is applied continuously over the physics step and cleared afterwards.
441 ///
442 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
443 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
444 #[cfg(feature = "3d")]
445 #[inline]
446 fn apply_local_angular_acceleration(&mut self, acceleration: AngularVector) {
447 if acceleration != AngularVector::ZERO && self.try_wake_up() {
448 self.accumulated_local_acceleration_mut().angular += acceleration;
449 }
450 }
451
452 /// Returns the linear acceleration that the body has accumulated
453 /// before the physics step in world space, including acceleration
454 /// caused by forces.
455 ///
456 /// This does not include gravity, contact forces, or joint forces.
457 /// Only forces and accelerations applied through [`Forces`] are included.
458 #[inline]
459 fn accumulated_linear_acceleration(&self) -> Vector {
460 // The linear increment is treated as linear acceleration until the integration step.
461 let world_linear_acceleration = self.integration_data().linear_increment;
462 let local_linear_acceleration = self.accumulated_local_acceleration().linear;
463
464 // Return the total world-space linear acceleration.
465 self.locked_axes()
466 .apply_to_vec(world_linear_acceleration + self.rot() * local_linear_acceleration)
467 }
468
469 /// Returns the angular acceleration that the body has accumulated
470 /// before the physics step in world space, including acceleration
471 /// caused by torques.
472 ///
473 /// This does not include gravity, contact forces, or joint forces.
474 /// Only torques and accelerations applied through [`Forces`] are included.
475 #[cfg(feature = "2d")]
476 #[inline]
477 fn accumulated_angular_acceleration(&self) -> AngularVector {
478 // The angular increment is treated as angular acceleration until the integration step.
479 self.locked_axes()
480 .apply_to_angular_velocity(self.integration_data().angular_increment)
481 }
482
483 /// Returns the angular acceleration that the body has accumulated
484 /// before the physics step in world space, including acceleration
485 /// caused by torques.
486 ///
487 /// This does not include gravity, contact forces, or joint forces.
488 /// Only torques and accelerations applied through [`Forces`] are included.
489 #[cfg(feature = "3d")]
490 #[inline]
491 fn accumulated_angular_acceleration(&self) -> AngularVector {
492 // The angular increment is treated as angular acceleration until the integration step.
493 let world_angular_acceleration = self.integration_data().angular_increment;
494 let local_angular_acceleration = self.accumulated_local_acceleration().angular;
495
496 // Return the total world-space angular acceleration.
497 self.locked_axes().apply_to_angular_velocity(
498 world_angular_acceleration + self.rot() * local_angular_acceleration,
499 )
500 }
501
502 /// Resets the accumulated linear acceleration to zero.
503 #[inline]
504 fn reset_accumulated_linear_acceleration(&mut self) {
505 self.integration_data_mut().linear_increment = Vector::ZERO;
506 self.accumulated_local_acceleration_mut().linear = Vector::ZERO;
507 }
508
509 /// Resets the accumulated angular acceleration to zero.
510 #[inline]
511 fn reset_accumulated_angular_acceleration(&mut self) {
512 self.integration_data_mut().angular_increment = AngularVector::ZERO;
513 #[cfg(feature = "3d")]
514 {
515 self.accumulated_local_acceleration_mut().angular = AngularVector::ZERO;
516 }
517 }
518
519 /// Returns the [`Position`] of the body.
520 #[inline]
521 fn position(&self) -> &Position {
522 self.pos()
523 }
524
525 /// Returns the [`Rotation`] of the body.
526 #[inline]
527 fn rotation(&self) -> &Rotation {
528 self.rot()
529 }
530
531 /// Returns the [`LinearVelocity`] of the body in world space.
532 #[inline]
533 fn linear_velocity(&self) -> Vector {
534 self.lin_vel()
535 }
536
537 /// Returns a mutable reference to the [`LinearVelocity`] of the body in world space.
538 #[inline]
539 fn linear_velocity_mut(&mut self) -> &mut Vector {
540 self.lin_vel_mut()
541 }
542
543 /// Returns the [`AngularVelocity`] of the body in world space.
544 #[inline]
545 fn angular_velocity(&self) -> AngularVector {
546 self.ang_vel()
547 }
548
549 /// Returns a mutable reference to the [`AngularVelocity`] of the body in world space.
550 #[inline]
551 fn angular_velocity_mut(&mut self) -> &mut AngularVector {
552 self.ang_vel_mut()
553 }
554
555 /// Returns the velocity of a point in world space on the body.
556 #[inline]
557 #[doc(alias = "linear_velocity_at_point")]
558 fn velocity_at_point(&self, world_point: Vector) -> Vector {
559 let offset = world_point - self.global_center_of_mass();
560 #[cfg(feature = "2d")]
561 {
562 self.linear_velocity() + self.angular_velocity() * offset.perp()
563 }
564 #[cfg(feature = "3d")]
565 {
566 self.linear_velocity() + self.angular_velocity().cross(offset)
567 }
568 }
569}
570
571/// A trait to provide internal getters and helpers for [`RigidBodyForces`].
572trait RigidBodyForcesInternal {
573 fn pos(&self) -> &Position;
574 fn rot(&self) -> &Rotation;
575 fn lin_vel(&self) -> Vector;
576 fn lin_vel_mut(&mut self) -> &mut Vector;
577 fn ang_vel(&self) -> AngularVector;
578 fn ang_vel_mut(&mut self) -> &mut AngularVector;
579 fn inverse_mass(&self) -> Scalar;
580 #[cfg(feature = "3d")]
581 fn inverse_angular_inertia(&self) -> SymmetricTensor;
582 fn global_inverse_angular_inertia(&self) -> SymmetricTensor;
583 fn global_center_of_mass(&self) -> Vector;
584 fn locked_axes(&self) -> LockedAxes;
585 fn integration_data(&self) -> &VelocityIntegrationData;
586 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData;
587 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration;
588 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration;
589 fn try_wake_up(&mut self) -> bool;
590}
591
592impl RigidBodyForcesInternal for ForcesItem<'_, '_> {
593 #[inline]
594 fn pos(&self) -> &Position {
595 self.position
596 }
597 #[inline]
598 fn rot(&self) -> &Rotation {
599 self.rotation
600 }
601 #[inline]
602 fn lin_vel(&self) -> Vector {
603 self.linear_velocity.0
604 }
605 #[inline]
606 fn lin_vel_mut(&mut self) -> &mut Vector {
607 &mut self.linear_velocity.0
608 }
609 #[inline]
610 fn ang_vel(&self) -> AngularVector {
611 self.angular_velocity.0
612 }
613 #[inline]
614 fn ang_vel_mut(&mut self) -> &mut AngularVector {
615 &mut self.angular_velocity.0
616 }
617 #[inline]
618 fn inverse_mass(&self) -> Scalar {
619 self.mass.inverse()
620 }
621 #[inline]
622 #[cfg(feature = "3d")]
623 fn inverse_angular_inertia(&self) -> SymmetricTensor {
624 self.angular_inertia.inverse()
625 }
626 #[inline]
627 fn global_inverse_angular_inertia(&self) -> SymmetricTensor {
628 #[cfg(feature = "2d")]
629 let global_angular_inertia = *self.angular_inertia;
630 #[cfg(feature = "3d")]
631 let global_angular_inertia = self.angular_inertia.rotated(self.rotation.0);
632 self.locked_axes()
633 .apply_to_angular_inertia(global_angular_inertia)
634 .inverse()
635 }
636 #[inline]
637 fn global_center_of_mass(&self) -> Vector {
638 self.position.0 + self.rotation * self.center_of_mass.0
639 }
640 #[inline]
641 fn locked_axes(&self) -> LockedAxes {
642 self.locked_axes.copied().unwrap_or_default()
643 }
644 #[inline]
645 fn integration_data(&self) -> &VelocityIntegrationData {
646 &self.integration
647 }
648 #[inline]
649 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
650 &mut self.integration
651 }
652 #[inline]
653 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
654 &self.accumulated_local_acceleration
655 }
656 #[inline]
657 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
658 &mut self.accumulated_local_acceleration
659 }
660 #[inline]
661 fn try_wake_up(&mut self) -> bool {
662 // Wake up the body. Return `true` to indicate that the body is awake.
663 if let Some(sleep_timer) = &mut self.sleep_timer {
664 sleep_timer.0 = 0.0;
665 }
666 true
667 }
668}
669
670impl RigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
671 #[inline]
672 fn pos(&self) -> &Position {
673 self.0.position()
674 }
675 #[inline]
676 fn rot(&self) -> &Rotation {
677 self.0.rot()
678 }
679 #[inline]
680 fn lin_vel(&self) -> Vector {
681 self.0.lin_vel()
682 }
683 #[inline]
684 fn lin_vel_mut(&mut self) -> &mut Vector {
685 self.0.lin_vel_mut()
686 }
687 #[inline]
688 fn ang_vel(&self) -> AngularVector {
689 self.0.ang_vel()
690 }
691 #[inline]
692 fn ang_vel_mut(&mut self) -> &mut AngularVector {
693 self.0.ang_vel_mut()
694 }
695 #[inline]
696 fn inverse_mass(&self) -> Scalar {
697 self.0.inverse_mass()
698 }
699 #[inline]
700 #[cfg(feature = "3d")]
701 fn inverse_angular_inertia(&self) -> SymmetricTensor {
702 self.0.inverse_angular_inertia()
703 }
704 #[inline]
705 fn global_inverse_angular_inertia(&self) -> SymmetricTensor {
706 self.0.global_inverse_angular_inertia()
707 }
708 #[inline]
709 fn global_center_of_mass(&self) -> Vector {
710 self.0.global_center_of_mass()
711 }
712 #[inline]
713 fn locked_axes(&self) -> LockedAxes {
714 self.0.locked_axes()
715 }
716 #[inline]
717 fn integration_data(&self) -> &VelocityIntegrationData {
718 self.0.integration_data()
719 }
720 #[inline]
721 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
722 self.0.integration_data_mut()
723 }
724 #[inline]
725 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
726 self.0.accumulated_local_acceleration()
727 }
728 #[inline]
729 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
730 self.0.accumulated_local_acceleration_mut()
731 }
732 #[inline]
733 fn try_wake_up(&mut self) -> bool {
734 // Don't wake up the body.
735 // Return `true` if the body is already awake and forces should be applied.
736 !self.0.is_sleeping
737 }
738}