avian2d/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.effective_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.effective_inverse_angular_inertia();
341            let delta_vel = effective_inverse_angular_inertia * impulse;
342            *self.angular_velocity_mut() += delta_vel;
343        }
344    }
345
346    /// Applies an angular impulse in local space. The unit is typically N⋅m⋅s or kg⋅m²/s.
347    ///
348    /// The impulse modifies the [`AngularVelocity`] of the body immediately.
349    ///
350    /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
351    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
352    #[cfg(feature = "3d")]
353    #[inline]
354    fn apply_local_angular_impulse(&mut self, impulse: AngularVector) {
355        if impulse != AngularVector::ZERO && self.try_wake_up() {
356            let world_impulse = self.rot() * impulse;
357            let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
358            let delta_vel = effective_inverse_angular_inertia * world_impulse;
359            *self.angular_velocity_mut() += delta_vel;
360        }
361    }
362
363    /// Applies a linear acceleration, ignoring mass. The unit is typically m/s².
364    ///
365    /// The acceleration is applied continuously over the physics step and cleared afterwards.
366    ///
367    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
368    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
369    #[inline]
370    fn apply_linear_acceleration(&mut self, acceleration: Vector) {
371        if acceleration != Vector::ZERO && self.try_wake_up() {
372            self.integration_data_mut()
373                .apply_linear_acceleration(acceleration);
374        }
375    }
376
377    /// Applies a linear acceleration at the given point in world space. The unit is typically m/s².
378    ///
379    /// If the point is not at the center of mass, the acceleration will also generate an angular acceleration.
380    ///
381    /// The acceleration is applied continuously over the physics step and cleared afterwards.
382    ///
383    /// By default, a non-zero acceleration 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    ///
386    /// # Note
387    ///
388    /// If the [`Transform`] of the body is modified before applying the acceleration,
389    /// the angular acceleration will be computed using an outdated global center of mass.
390    /// This may cause problems when applying a acceleration right after teleporting
391    /// an entity, as the angular acceleration could grow very large if the distance between the point
392    /// and old center of mass is large.
393    ///
394    /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
395    /// to update the global physics transform after modifying [`Transform`].
396    ///
397    /// [`Transform`]: bevy::transform::components::Transform
398    #[inline]
399    fn apply_linear_acceleration_at_point(&mut self, acceleration: Vector, world_point: Vector) {
400        self.apply_linear_acceleration(acceleration);
401        self.apply_angular_acceleration(cross(
402            world_point - self.global_center_of_mass(),
403            acceleration,
404        ));
405    }
406
407    /// Applies a linear acceleration in local space, ignoring mass. The unit is typically m/s².
408    ///
409    /// The acceleration is applied continuously over the physics step and cleared afterwards.
410    ///
411    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
412    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
413    #[inline]
414    fn apply_local_linear_acceleration(&mut self, acceleration: Vector) {
415        if acceleration != Vector::ZERO && self.try_wake_up() {
416            self.accumulated_local_acceleration_mut().linear += acceleration;
417        }
418    }
419
420    /// Applies an angular acceleration, ignoring angular inertia. The unit is rad/s².
421    ///
422    /// The acceleration is applied continuously over the physics step and cleared afterwards.
423    ///
424    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
425    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
426    #[inline]
427    fn apply_angular_acceleration(&mut self, acceleration: AngularVector) {
428        if acceleration != AngularVector::ZERO && self.try_wake_up() {
429            self.integration_data_mut()
430                .apply_angular_acceleration(acceleration);
431        }
432    }
433
434    /// Applies an angular acceleration in local space, ignoring angular inertia. The unit is rad/s².
435    ///
436    /// The acceleration is applied continuously over the physics step and cleared afterwards.
437    ///
438    /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
439    /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
440    #[cfg(feature = "3d")]
441    #[inline]
442    fn apply_local_angular_acceleration(&mut self, acceleration: AngularVector) {
443        if acceleration != AngularVector::ZERO && self.try_wake_up() {
444            self.accumulated_local_acceleration_mut().angular += acceleration;
445        }
446    }
447
448    /// Returns the linear acceleration that the body has accumulated
449    /// before the physics step in world space, including acceleration
450    /// caused by forces.
451    ///
452    /// This does not include gravity, contact forces, or joint forces.
453    /// Only forces and accelerations applied through [`Forces`] are included.
454    #[inline]
455    fn accumulated_linear_acceleration(&self) -> Vector {
456        // The linear increment is treated as linear acceleration until the integration step.
457        let world_linear_acceleration = self.integration_data().linear_increment;
458        let local_linear_acceleration = self.accumulated_local_acceleration().linear;
459
460        // Return the total world-space linear acceleration.
461        self.locked_axes()
462            .apply_to_vec(world_linear_acceleration + self.rot() * local_linear_acceleration)
463    }
464
465    /// Returns the angular acceleration that the body has accumulated
466    /// before the physics step in world space, including acceleration
467    /// caused by torques.
468    ///
469    /// This does not include gravity, contact forces, or joint forces.
470    /// Only torques and accelerations applied through [`Forces`] are included.
471    #[cfg(feature = "2d")]
472    #[inline]
473    fn accumulated_angular_acceleration(&self) -> AngularVector {
474        // The angular increment is treated as angular acceleration until the integration step.
475        self.locked_axes()
476            .apply_to_angular_velocity(self.integration_data().angular_increment)
477    }
478
479    /// Returns the angular acceleration that the body has accumulated
480    /// before the physics step in world space, including acceleration
481    /// caused by torques.
482    ///
483    /// This does not include gravity, contact forces, or joint forces.
484    /// Only torques and accelerations applied through [`Forces`] are included.
485    #[cfg(feature = "3d")]
486    #[inline]
487    fn accumulated_angular_acceleration(&self) -> AngularVector {
488        // The angular increment is treated as angular acceleration until the integration step.
489        let world_angular_acceleration = self.integration_data().angular_increment;
490        let local_angular_acceleration = self.accumulated_local_acceleration().angular;
491
492        // Return the total world-space angular acceleration.
493        self.locked_axes().apply_to_angular_velocity(
494            world_angular_acceleration + self.rot() * local_angular_acceleration,
495        )
496    }
497
498    /// Resets the accumulated linear acceleration to zero.
499    #[inline]
500    fn reset_accumulated_linear_acceleration(&mut self) {
501        self.integration_data_mut().linear_increment = Vector::ZERO;
502        self.accumulated_local_acceleration_mut().linear = Vector::ZERO;
503    }
504
505    /// Resets the accumulated angular acceleration to zero.
506    #[inline]
507    fn reset_accumulated_angular_acceleration(&mut self) {
508        self.integration_data_mut().angular_increment = AngularVector::ZERO;
509        #[cfg(feature = "3d")]
510        {
511            self.accumulated_local_acceleration_mut().angular = AngularVector::ZERO;
512        }
513    }
514
515    /// Returns the [`Position`] of the body.
516    #[inline]
517    fn position(&self) -> &Position {
518        self.pos()
519    }
520
521    /// Returns the [`Rotation`] of the body.
522    #[inline]
523    fn rotation(&self) -> &Rotation {
524        self.rot()
525    }
526
527    /// Returns the [`LinearVelocity`] of the body in world space.
528    #[inline]
529    fn linear_velocity(&self) -> Vector {
530        self.lin_vel()
531    }
532
533    /// Returns a mutable reference to the [`LinearVelocity`] of the body in world space.
534    #[inline]
535    fn linear_velocity_mut(&mut self) -> &mut Vector {
536        self.lin_vel_mut()
537    }
538
539    /// Returns the [`AngularVelocity`] of the body in world space.
540    #[inline]
541    fn angular_velocity(&self) -> AngularVector {
542        self.ang_vel()
543    }
544
545    /// Returns a mutable reference to the [`AngularVelocity`] of the body in world space.
546    #[inline]
547    fn angular_velocity_mut(&mut self) -> &mut AngularVector {
548        self.ang_vel_mut()
549    }
550
551    /// Returns the velocity of a point in world space on the body.
552    #[inline]
553    #[doc(alias = "linear_velocity_at_point")]
554    fn velocity_at_point(&self, world_point: Vector) -> Vector {
555        let offset = world_point - self.global_center_of_mass();
556        #[cfg(feature = "2d")]
557        {
558            self.linear_velocity() + self.angular_velocity() * offset.perp()
559        }
560        #[cfg(feature = "3d")]
561        {
562            self.linear_velocity() + self.angular_velocity().cross(offset)
563        }
564    }
565}
566
567/// A trait to provide internal getters and helpers for [`RigidBodyForces`].
568trait RigidBodyForcesInternal {
569    fn pos(&self) -> &Position;
570    fn rot(&self) -> &Rotation;
571    fn lin_vel(&self) -> Vector;
572    fn lin_vel_mut(&mut self) -> &mut Vector;
573    fn ang_vel(&self) -> AngularVector;
574    fn ang_vel_mut(&mut self) -> &mut AngularVector;
575    fn inverse_mass(&self) -> Scalar;
576    #[cfg(feature = "3d")]
577    fn inverse_angular_inertia(&self) -> SymmetricTensor;
578    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor;
579    fn global_center_of_mass(&self) -> Vector;
580    fn locked_axes(&self) -> LockedAxes;
581    fn integration_data(&self) -> &VelocityIntegrationData;
582    fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData;
583    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration;
584    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration;
585    fn try_wake_up(&mut self) -> bool;
586}
587
588impl RigidBodyForcesInternal for ForcesItem<'_, '_> {
589    #[inline]
590    fn pos(&self) -> &Position {
591        self.position
592    }
593    #[inline]
594    fn rot(&self) -> &Rotation {
595        self.rotation
596    }
597    #[inline]
598    fn lin_vel(&self) -> Vector {
599        self.linear_velocity.0
600    }
601    #[inline]
602    fn lin_vel_mut(&mut self) -> &mut Vector {
603        &mut self.linear_velocity.0
604    }
605    #[inline]
606    fn ang_vel(&self) -> AngularVector {
607        self.angular_velocity.0
608    }
609    #[inline]
610    fn ang_vel_mut(&mut self) -> &mut AngularVector {
611        &mut self.angular_velocity.0
612    }
613    #[inline]
614    fn inverse_mass(&self) -> Scalar {
615        self.mass.inverse()
616    }
617    #[inline]
618    #[cfg(feature = "3d")]
619    fn inverse_angular_inertia(&self) -> SymmetricTensor {
620        self.angular_inertia.inverse()
621    }
622    #[inline]
623    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
624        #[cfg(feature = "2d")]
625        let global_angular_inertia = *self.angular_inertia;
626        #[cfg(feature = "3d")]
627        let global_angular_inertia = self.angular_inertia.rotated(self.rotation.0);
628        self.locked_axes()
629            .apply_to_angular_inertia(global_angular_inertia)
630            .inverse()
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 integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
646        &mut self.integration
647    }
648    #[inline]
649    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
650        &self.accumulated_local_acceleration
651    }
652    #[inline]
653    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
654        &mut self.accumulated_local_acceleration
655    }
656    #[inline]
657    fn try_wake_up(&mut self) -> bool {
658        // Wake up the body. Return `true` to indicate that the body is awake.
659        if let Some(sleep_timer) = &mut self.sleep_timer {
660            sleep_timer.0 = 0.0;
661        }
662        true
663    }
664}
665
666impl RigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
667    #[inline]
668    fn pos(&self) -> &Position {
669        self.0.position()
670    }
671    #[inline]
672    fn rot(&self) -> &Rotation {
673        self.0.rot()
674    }
675    #[inline]
676    fn lin_vel(&self) -> Vector {
677        self.0.lin_vel()
678    }
679    #[inline]
680    fn lin_vel_mut(&mut self) -> &mut Vector {
681        self.0.lin_vel_mut()
682    }
683    #[inline]
684    fn ang_vel(&self) -> AngularVector {
685        self.0.ang_vel()
686    }
687    #[inline]
688    fn ang_vel_mut(&mut self) -> &mut AngularVector {
689        self.0.ang_vel_mut()
690    }
691    #[inline]
692    fn inverse_mass(&self) -> Scalar {
693        self.0.inverse_mass()
694    }
695    #[inline]
696    #[cfg(feature = "3d")]
697    fn inverse_angular_inertia(&self) -> SymmetricTensor {
698        self.0.inverse_angular_inertia()
699    }
700    #[inline]
701    fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
702        self.0.effective_inverse_angular_inertia()
703    }
704    #[inline]
705    fn global_center_of_mass(&self) -> Vector {
706        self.0.global_center_of_mass()
707    }
708    #[inline]
709    fn locked_axes(&self) -> LockedAxes {
710        self.0.locked_axes()
711    }
712    #[inline]
713    fn integration_data(&self) -> &VelocityIntegrationData {
714        self.0.integration_data()
715    }
716    #[inline]
717    fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
718        self.0.integration_data_mut()
719    }
720    #[inline]
721    fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
722        self.0.accumulated_local_acceleration()
723    }
724    #[inline]
725    fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
726        self.0.accumulated_local_acceleration_mut()
727    }
728    #[inline]
729    fn try_wake_up(&mut self) -> bool {
730        // Don't wake up the body.
731        // Return `true` if the body is already awake and forces should be applied.
732        !self.0.is_sleeping
733    }
734}