Skip to main content

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