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 ReadRigidBodyForces for ForcesItem<'_, '_> {}
168impl ReadRigidBodyForces for NonWakingForcesItem<'_, '_> {}
169impl ReadRigidBodyForces for ForcesReadOnlyItem<'_, '_> {}
170impl WriteRigidBodyForces for ForcesItem<'_, '_> {}
171impl WriteRigidBodyForces for NonWakingForcesItem<'_, '_> {}
172
173/// A trait for reading and writing forces of a dynamic [rigid body](RigidBody).
174///
175/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
176/// returned by [`Forces`].
177///
178/// See the documentation of [`Forces`] for more information on how to work with forces in Avian.
179pub trait RigidBodyForces: ReadRigidBodyForces + WriteRigidBodyForces {}
180
181/// A trait for reading forces of a dynamic [rigid body](RigidBody).
182///
183/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
184/// returned by [`Forces`].
185///
186/// See the documentation of [`Forces`] for more information on how to work with forces in Avian.
187#[expect(
188    private_bounds,
189    reason = "The internal methods should not be publicly accessible."
190)]
191pub trait ReadRigidBodyForces: ReadRigidBodyForcesInternal {
192    /// Returns the [`Position`] of the body.
193    #[inline]
194    fn position(&self) -> &Position {
195        self.pos()
196    }
197
198    /// Returns the [`Rotation`] of the body.
199    #[inline]
200    fn rotation(&self) -> &Rotation {
201        self.rot()
202    }
203
204    /// Returns the [`LinearVelocity`] of the body in world space.
205    #[inline]
206    fn linear_velocity(&self) -> Vector {
207        self.lin_vel()
208    }
209
210    /// Returns the [`AngularVelocity`] of the body in world space.
211    #[inline]
212    fn angular_velocity(&self) -> AngularVector {
213        self.ang_vel()
214    }
215
216    /// Returns the linear acceleration that the body has accumulated
217    /// before the physics step in world space, including acceleration
218    /// caused by forces.
219    ///
220    /// This does not include gravity, contact forces, or joint forces.
221    /// Only forces and accelerations applied through [`Forces`] are included.
222    #[inline]
223    fn accumulated_linear_acceleration(&self) -> Vector {
224        // The linear increment is treated as linear acceleration until the integration step.
225        let world_linear_acceleration = self.integration_data().linear_increment;
226        let local_linear_acceleration = self.accumulated_local_acceleration().linear;
227
228        // Return the total world-space linear acceleration.
229        self.locked_axes()
230            .apply_to_vec(world_linear_acceleration + self.rot() * local_linear_acceleration)
231    }
232
233    /// Returns the angular acceleration that the body has accumulated
234    /// before the physics step in world space, including acceleration
235    /// caused by torques.
236    ///
237    /// This does not include gravity, contact forces, or joint forces.
238    /// Only torques and accelerations applied through [`Forces`] are included.
239    #[cfg(feature = "2d")]
240    #[inline]
241    fn accumulated_angular_acceleration(&self) -> AngularVector {
242        // The angular increment is treated as angular acceleration until the integration step.
243        self.locked_axes()
244            .apply_to_angular_velocity(self.integration_data().angular_increment)
245    }
246
247    /// Returns the angular acceleration that the body has accumulated
248    /// before the physics step in world space, including acceleration
249    /// caused by torques.
250    ///
251    /// This does not include gravity, contact forces, or joint forces.
252    /// Only torques and accelerations applied through [`Forces`] are included.
253    #[cfg(feature = "3d")]
254    #[inline]
255    fn accumulated_angular_acceleration(&self) -> AngularVector {
256        // The angular increment is treated as angular acceleration until the integration step.
257        let world_angular_acceleration = self.integration_data().angular_increment;
258        let local_angular_acceleration = self.accumulated_local_acceleration().angular;
259
260        // Return the total world-space angular acceleration.
261        self.locked_axes().apply_to_angular_velocity(
262            world_angular_acceleration + self.rot() * local_angular_acceleration,
263        )
264    }
265
266    /// Returns the velocity of a point in world space on the body.
267    #[inline]
268    #[doc(alias = "linear_velocity_at_point")]
269    fn velocity_at_point(&self, world_point: Vector) -> Vector {
270        let offset = world_point - self.global_center_of_mass();
271        #[cfg(feature = "2d")]
272        {
273            self.linear_velocity() + self.angular_velocity() * offset.perp()
274        }
275        #[cfg(feature = "3d")]
276        {
277            self.linear_velocity() + self.angular_velocity().cross(offset)
278        }
279    }
280}
281
282/// A trait for applying forces, impulses, and accelerations to a dynamic [rigid body](RigidBody).
283///
284/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
285/// returned by [`Forces`].
286///
287/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
288#[expect(
289    private_bounds,
290    reason = "The internal methods should not be publicly accessible."
291)]
292pub trait WriteRigidBodyForces: ReadRigidBodyForces + WriteRigidBodyForcesInternal {
293    /// Applies a force at the center of mass in world space. The unit is typically N or kg⋅m/s².
294    ///
295    /// The force is applied continuously over the physics step and cleared afterwards.
296    ///
297    /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
298    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
299    #[inline]
300    fn apply_force(&mut self, force: Vector) {
301        if force != Vector::ZERO && self.try_wake_up() {
302            let acceleration = self.inverse_mass() * force;
303            self.integration_data_mut()
304                .apply_linear_acceleration(acceleration);
305        }
306    }
307
308    /// Applies a force at the given point in world space. The unit is typically N or kg⋅m/s².
309    ///
310    /// If the point is not at the center of mass, the force will also generate a torque.
311    ///
312    /// The force is applied continuously over the physics step and cleared afterwards.
313    ///
314    /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
315    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
316    ///
317    /// # Note
318    ///
319    /// If the [`Transform`] of the body is modified before applying the force,
320    /// the torque will be computed using an outdated global center of mass.
321    /// This may cause problems when applying a force right after teleporting
322    /// an entity, as the torque could grow very large if the distance between the point
323    /// and old center of mass is large.
324    ///
325    /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
326    /// to update the global physics transform after modifying [`Transform`].
327    ///
328    /// [`Transform`]: bevy::transform::components::Transform
329    #[inline]
330    fn apply_force_at_point(&mut self, force: Vector, world_point: Vector) {
331        // Note: This does not consider the rotation of the body during substeps,
332        //       so the torque may not be accurate if the body is rotating quickly.
333        self.apply_force(force);
334        self.apply_torque(cross(world_point - self.global_center_of_mass(), force));
335    }
336
337    /// Applies a force at the center of mass in local space. The unit is typically N or kg⋅m/s².
338    ///
339    /// The force is applied continuously over the physics step and cleared afterwards.
340    ///
341    /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
342    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
343    #[inline]
344    fn apply_local_force(&mut self, force: Vector) {
345        if force != Vector::ZERO && self.try_wake_up() {
346            let acceleration = self.inverse_mass() * force;
347            self.accumulated_local_acceleration_mut().linear += acceleration;
348        }
349    }
350
351    /// Applies a torque in world space. The unit is typically N⋅m or kg⋅m²/s².
352    ///
353    /// The torque is applied continuously over the physics step and cleared afterwards.
354    ///
355    /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
356    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
357    #[inline]
358    fn apply_torque(&mut self, torque: AngularVector) {
359        if torque != AngularVector::ZERO && self.try_wake_up() {
360            let acceleration = self.effective_inverse_angular_inertia() * torque;
361            self.integration_data_mut()
362                .apply_angular_acceleration(acceleration);
363        }
364    }
365
366    /// Applies a torque in local space. The unit is typically N⋅m or kg⋅m²/s².
367    ///
368    /// The torque is applied continuously over the physics step and cleared afterwards.
369    ///
370    /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
371    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
372    #[cfg(feature = "3d")]
373    #[inline]
374    fn apply_local_torque(&mut self, torque: AngularVector) {
375        if torque != AngularVector::ZERO && self.try_wake_up() {
376            let acceleration = self.inverse_angular_inertia() * torque;
377            self.accumulated_local_acceleration_mut().angular += acceleration;
378        }
379    }
380
381    /// Applies a linear impulse at the center of mass in world space. The unit is typically N⋅s or kg⋅m/s.
382    ///
383    /// The impulse modifies the [`LinearVelocity`] of the body immediately.
384    ///
385    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
386    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
387    #[inline]
388    fn apply_linear_impulse(&mut self, impulse: Vector) {
389        if impulse != Vector::ZERO && self.try_wake_up() {
390            let effective_inverse_mass = self
391                .locked_axes()
392                .apply_to_vec(Vector::splat(self.inverse_mass()));
393            let delta_vel = effective_inverse_mass * impulse;
394            *self.linear_velocity_mut() += delta_vel;
395        }
396    }
397
398    /// Applies a linear impulse at the given point in world space. The unit is typically N⋅s or kg⋅m/s.
399    ///
400    /// If the point is not at the center of mass, the impulse will also generate an angular impulse.
401    ///
402    /// The impulse modifies the [`LinearVelocity`] and [`AngularVelocity`] of the body immediately.
403    ///
404    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
405    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
406    ///
407    /// # Note
408    ///
409    /// If the [`Transform`] of the body is modified before applying the impulse,
410    /// the torque will be computed using an outdated global center of mass.
411    /// This may cause problems when applying a impulse right after teleporting
412    /// an entity, as the torque could grow very large if the distance between the point
413    /// and old center of mass is large.
414    ///
415    /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
416    /// to update the global physics transform after modifying [`Transform`].
417    ///
418    /// [`Transform`]: bevy::transform::components::Transform
419    #[inline]
420    fn apply_linear_impulse_at_point(&mut self, impulse: Vector, world_point: Vector) {
421        self.apply_linear_impulse(impulse);
422        self.apply_angular_impulse(cross(world_point - self.global_center_of_mass(), impulse));
423    }
424
425    /// Applies a linear impulse in local space. The unit is typically N⋅s or kg⋅m/s.
426    ///
427    /// The impulse modifies the [`LinearVelocity`] of the body immediately.
428    ///
429    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
430    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
431    #[inline]
432    fn apply_local_linear_impulse(&mut self, impulse: Vector) {
433        if impulse != Vector::ZERO && self.try_wake_up() {
434            let world_impulse = self.rot() * impulse;
435            let effective_inverse_mass = self
436                .locked_axes()
437                .apply_to_vec(Vector::splat(self.inverse_mass()));
438            let delta_vel = effective_inverse_mass * world_impulse;
439            *self.linear_velocity_mut() += delta_vel;
440        }
441    }
442
443    /// Applies an angular impulse in world space. The unit is typically N⋅m⋅s or kg⋅m²/s.
444    ///
445    /// The impulse modifies the [`AngularVelocity`] of the body immediately.
446    ///
447    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
448    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
449    #[inline]
450    fn apply_angular_impulse(&mut self, impulse: AngularVector) {
451        if impulse != AngularVector::ZERO && self.try_wake_up() {
452            let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
453            let delta_vel = effective_inverse_angular_inertia * impulse;
454            *self.angular_velocity_mut() += delta_vel;
455        }
456    }
457
458    /// Applies an angular impulse in local space. The unit is typically N⋅m⋅s or kg⋅m²/s.
459    ///
460    /// The impulse modifies the [`AngularVelocity`] of the body immediately.
461    ///
462    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
463    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
464    #[cfg(feature = "3d")]
465    #[inline]
466    fn apply_local_angular_impulse(&mut self, impulse: AngularVector) {
467        if impulse != AngularVector::ZERO && self.try_wake_up() {
468            let world_impulse = self.rot() * impulse;
469            let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
470            let delta_vel = effective_inverse_angular_inertia * world_impulse;
471            *self.angular_velocity_mut() += delta_vel;
472        }
473    }
474
475    /// Applies a linear acceleration, ignoring mass. The unit is typically m/s².
476    ///
477    /// The acceleration is applied continuously over the physics step and cleared afterwards.
478    ///
479    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
480    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
481    #[inline]
482    fn apply_linear_acceleration(&mut self, acceleration: Vector) {
483        if acceleration != Vector::ZERO && self.try_wake_up() {
484            self.integration_data_mut()
485                .apply_linear_acceleration(acceleration);
486        }
487    }
488
489    /// Applies a linear acceleration at the given point in world space. The unit is typically m/s².
490    ///
491    /// If the point is not at the center of mass, the acceleration will also generate an angular acceleration.
492    ///
493    /// The acceleration is applied continuously over the physics step and cleared afterwards.
494    ///
495    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
496    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
497    ///
498    /// # Note
499    ///
500    /// If the [`Transform`] of the body is modified before applying the acceleration,
501    /// the angular acceleration will be computed using an outdated global center of mass.
502    /// This may cause problems when applying a acceleration right after teleporting
503    /// an entity, as the angular acceleration could grow very large if the distance between the point
504    /// and old center of mass is large.
505    ///
506    /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
507    /// to update the global physics transform after modifying [`Transform`].
508    ///
509    /// [`Transform`]: bevy::transform::components::Transform
510    #[inline]
511    fn apply_linear_acceleration_at_point(&mut self, acceleration: Vector, world_point: Vector) {
512        self.apply_linear_acceleration(acceleration);
513        self.apply_angular_acceleration(cross(
514            world_point - self.global_center_of_mass(),
515            acceleration,
516        ));
517    }
518
519    /// Applies a linear acceleration in local space, ignoring mass. The unit is typically m/s².
520    ///
521    /// The acceleration is applied continuously over the physics step and cleared afterwards.
522    ///
523    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
524    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
525    #[inline]
526    fn apply_local_linear_acceleration(&mut self, acceleration: Vector) {
527        if acceleration != Vector::ZERO && self.try_wake_up() {
528            self.accumulated_local_acceleration_mut().linear += acceleration;
529        }
530    }
531
532    /// Applies an angular acceleration, ignoring angular inertia. The unit is rad/s².
533    ///
534    /// The acceleration is applied continuously over the physics step and cleared afterwards.
535    ///
536    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
537    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
538    #[inline]
539    fn apply_angular_acceleration(&mut self, acceleration: AngularVector) {
540        if acceleration != AngularVector::ZERO && self.try_wake_up() {
541            self.integration_data_mut()
542                .apply_angular_acceleration(acceleration);
543        }
544    }
545
546    /// Applies an angular acceleration in local space, ignoring angular inertia. The unit is rad/s².
547    ///
548    /// The acceleration is applied continuously over the physics step and cleared afterwards.
549    ///
550    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
551    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
552    #[cfg(feature = "3d")]
553    #[inline]
554    fn apply_local_angular_acceleration(&mut self, acceleration: AngularVector) {
555        if acceleration != AngularVector::ZERO && self.try_wake_up() {
556            self.accumulated_local_acceleration_mut().angular += acceleration;
557        }
558    }
559
560    /// Returns a mutable reference to the [`LinearVelocity`] of the body in world space.
561    #[inline]
562    fn linear_velocity_mut(&mut self) -> &mut Vector {
563        self.lin_vel_mut()
564    }
565
566    /// Returns a mutable reference to the [`AngularVelocity`] of the body in world space.
567    #[inline]
568    fn angular_velocity_mut(&mut self) -> &mut AngularVector {
569        self.ang_vel_mut()
570    }
571
572    /// Resets the accumulated linear acceleration to zero.
573    #[inline]
574    fn reset_accumulated_linear_acceleration(&mut self) {
575        self.integration_data_mut().linear_increment = Vector::ZERO;
576        self.accumulated_local_acceleration_mut().linear = Vector::ZERO;
577    }
578
579    /// Resets the accumulated angular acceleration to zero.
580    #[inline]
581    fn reset_accumulated_angular_acceleration(&mut self) {
582        self.integration_data_mut().angular_increment = AngularVector::ZERO;
583        #[cfg(feature = "3d")]
584        {
585            self.accumulated_local_acceleration_mut().angular = AngularVector::ZERO;
586        }
587    }
588}
589
590/// A trait to provide internal read-only getters for [`ReadRigidBodyForces`].
591trait ReadRigidBodyForcesInternal {
592    fn pos(&self) -> &Position;
593    fn rot(&self) -> &Rotation;
594    fn lin_vel(&self) -> Vector;
595    fn ang_vel(&self) -> AngularVector;
596    fn global_center_of_mass(&self) -> Vector;
597    fn locked_axes(&self) -> LockedAxes;
598    fn integration_data(&self) -> &VelocityIntegrationData;
599    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration;
600}
601
602/// A trait to provide internal mutable getters and helpers for [`WriteRigidBodyForces`].
603trait WriteRigidBodyForcesInternal: ReadRigidBodyForcesInternal {
604    fn lin_vel_mut(&mut self) -> &mut Vector;
605    fn ang_vel_mut(&mut self) -> &mut AngularVector;
606    fn inverse_mass(&self) -> Scalar;
607    #[cfg(feature = "3d")]
608    fn inverse_angular_inertia(&self) -> SymmetricTensor;
609    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor;
610    fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData;
611    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration;
612    fn try_wake_up(&mut self) -> bool;
613}
614
615impl ReadRigidBodyForcesInternal for ForcesItem<'_, '_> {
616    #[inline]
617    fn pos(&self) -> &Position {
618        self.position
619    }
620    #[inline]
621    fn rot(&self) -> &Rotation {
622        self.rotation
623    }
624    #[inline]
625    fn lin_vel(&self) -> Vector {
626        self.linear_velocity.0
627    }
628    #[inline]
629    fn ang_vel(&self) -> AngularVector {
630        self.angular_velocity.0
631    }
632    #[inline]
633    fn global_center_of_mass(&self) -> Vector {
634        self.position.0 + self.rotation * self.center_of_mass.0
635    }
636    #[inline]
637    fn locked_axes(&self) -> LockedAxes {
638        self.locked_axes.copied().unwrap_or_default()
639    }
640    #[inline]
641    fn integration_data(&self) -> &VelocityIntegrationData {
642        &self.integration
643    }
644    #[inline]
645    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
646        &self.accumulated_local_acceleration
647    }
648}
649
650impl WriteRigidBodyForcesInternal for ForcesItem<'_, '_> {
651    #[inline]
652    fn lin_vel_mut(&mut self) -> &mut Vector {
653        &mut self.linear_velocity.0
654    }
655    #[inline]
656    fn ang_vel_mut(&mut self) -> &mut AngularVector {
657        &mut self.angular_velocity.0
658    }
659    #[inline]
660    fn inverse_mass(&self) -> Scalar {
661        self.mass.inverse()
662    }
663    #[inline]
664    #[cfg(feature = "3d")]
665    fn inverse_angular_inertia(&self) -> SymmetricTensor {
666        self.angular_inertia.inverse()
667    }
668    #[inline]
669    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
670        #[cfg(feature = "2d")]
671        let global_angular_inertia = *self.angular_inertia;
672        #[cfg(feature = "3d")]
673        let global_angular_inertia = self.angular_inertia.rotated(self.rotation.0);
674        self.locked_axes()
675            .apply_to_angular_inertia(global_angular_inertia)
676            .inverse()
677    }
678    #[inline]
679    fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
680        &mut self.integration
681    }
682    #[inline]
683    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
684        &mut self.accumulated_local_acceleration
685    }
686    #[inline]
687    fn try_wake_up(&mut self) -> bool {
688        // Wake up the body. Return `true` to indicate that the body is awake.
689        if let Some(sleep_timer) = &mut self.sleep_timer {
690            sleep_timer.0 = 0.0;
691        }
692        true
693    }
694}
695
696impl ReadRigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
697    #[inline]
698    fn pos(&self) -> &Position {
699        self.0.position()
700    }
701    #[inline]
702    fn rot(&self) -> &Rotation {
703        self.0.rot()
704    }
705    #[inline]
706    fn lin_vel(&self) -> Vector {
707        self.0.lin_vel()
708    }
709    #[inline]
710    fn ang_vel(&self) -> AngularVector {
711        self.0.ang_vel()
712    }
713    #[inline]
714    fn global_center_of_mass(&self) -> Vector {
715        self.0.global_center_of_mass()
716    }
717    #[inline]
718    fn locked_axes(&self) -> LockedAxes {
719        self.0.locked_axes()
720    }
721    #[inline]
722    fn integration_data(&self) -> &VelocityIntegrationData {
723        self.0.integration_data()
724    }
725    #[inline]
726    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
727        self.0.accumulated_local_acceleration()
728    }
729}
730
731impl ReadRigidBodyForcesInternal for ForcesReadOnlyItem<'_, '_> {
732    #[inline]
733    fn pos(&self) -> &Position {
734        self.position
735    }
736    #[inline]
737    fn rot(&self) -> &Rotation {
738        self.rotation
739    }
740    #[inline]
741    fn lin_vel(&self) -> Vector {
742        self.linear_velocity.0
743    }
744    #[inline]
745    fn ang_vel(&self) -> AngularVector {
746        self.angular_velocity.0
747    }
748    #[inline]
749    fn global_center_of_mass(&self) -> Vector {
750        self.position.0 + self.rotation * self.center_of_mass.0
751    }
752    #[inline]
753    fn locked_axes(&self) -> LockedAxes {
754        self.locked_axes.copied().unwrap_or_default()
755    }
756    #[inline]
757    fn integration_data(&self) -> &VelocityIntegrationData {
758        self.integration
759    }
760    #[inline]
761    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
762        self.accumulated_local_acceleration
763    }
764}
765
766impl WriteRigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
767    #[inline]
768    fn lin_vel_mut(&mut self) -> &mut Vector {
769        self.0.lin_vel_mut()
770    }
771    #[inline]
772    fn ang_vel_mut(&mut self) -> &mut AngularVector {
773        self.0.ang_vel_mut()
774    }
775    #[inline]
776    fn inverse_mass(&self) -> Scalar {
777        self.0.inverse_mass()
778    }
779    #[inline]
780    #[cfg(feature = "3d")]
781    fn inverse_angular_inertia(&self) -> SymmetricTensor {
782        self.0.inverse_angular_inertia()
783    }
784    #[inline]
785    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
786        self.0.effective_inverse_angular_inertia()
787    }
788    #[inline]
789    fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
790        self.0.integration_data_mut()
791    }
792    #[inline]
793    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
794        self.0.accumulated_local_acceleration_mut()
795    }
796    #[inline]
797    fn try_wake_up(&mut self) -> bool {
798        // Don't wake up the body.
799        // Return `true` if the body is already awake and forces should be applied.
800        !self.0.is_sleeping
801    }
802}