avian3d/dynamics/rigid_body/
world_query.rs

1#![allow(missing_docs)]
2
3use crate::{prelude::*, utils::get_pos_translation};
4use bevy::{
5    ecs::query::QueryData,
6    prelude::{Entity, Has, Ref},
7};
8
9/// A `WorldQuery` to make querying and modifying rigid bodies more convenient.
10#[derive(QueryData)]
11#[query_data(mutable)]
12pub struct RigidBodyQuery {
13    pub entity: Entity,
14    pub rb: Ref<'static, RigidBody>,
15    pub position: &'static mut Position,
16    pub rotation: &'static mut Rotation,
17    pub previous_rotation: &'static mut PreviousRotation,
18    pub accumulated_translation: &'static mut AccumulatedTranslation,
19    pub linear_velocity: &'static mut LinearVelocity,
20    pub(crate) pre_solve_linear_velocity: &'static mut PreSolveLinearVelocity,
21    pub angular_velocity: &'static mut AngularVelocity,
22    pub(crate) pre_solve_angular_velocity: &'static mut PreSolveAngularVelocity,
23    pub mass: &'static mut ComputedMass,
24    pub angular_inertia: &'static mut ComputedAngularInertia,
25    #[cfg(feature = "3d")]
26    pub global_angular_inertia: &'static mut GlobalAngularInertia,
27    pub center_of_mass: &'static mut ComputedCenterOfMass,
28    pub friction: Option<&'static Friction>,
29    pub restitution: Option<&'static Restitution>,
30    pub locked_axes: Option<&'static LockedAxes>,
31    pub dominance: Option<&'static Dominance>,
32    pub time_sleeping: Option<&'static mut TimeSleeping>,
33    pub is_sleeping: Has<Sleeping>,
34    pub is_sensor: Has<Sensor>,
35}
36
37impl RigidBodyQueryItem<'_> {
38    /// Computes the velocity at the given `point` relative to the center of the body.
39    pub fn velocity_at_point(&self, point: Vector) -> Vector {
40        #[cfg(feature = "2d")]
41        {
42            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
43        }
44        #[cfg(feature = "3d")]
45        {
46            self.linear_velocity.0 + self.angular_velocity.cross(point)
47        }
48    }
49
50    /// Computes the effective inverse mass, taking into account any translation locking.
51    pub fn effective_inverse_mass(&self) -> Vector {
52        if !self.rb.is_dynamic() {
53            return Vector::ZERO;
54        }
55
56        let mut inv_mass = Vector::splat(self.mass.inverse());
57
58        if let Some(locked_axes) = self.locked_axes {
59            inv_mass = locked_axes.apply_to_vec(inv_mass);
60        }
61
62        inv_mass
63    }
64
65    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
66    pub fn angular_inertia(&self) -> ComputedAngularInertia {
67        if self.rb.is_dynamic() {
68            *self.angular_inertia
69        } else {
70            ComputedAngularInertia::INFINITY
71        }
72    }
73
74    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
75    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
76        if !self.rb.is_dynamic() {
77            return ComputedAngularInertia::INFINITY;
78        }
79
80        #[cfg(feature = "2d")]
81        let mut angular_inertia = *self.angular_inertia;
82        #[cfg(feature = "3d")]
83        let mut angular_inertia = **self.global_angular_inertia;
84
85        if let Some(locked_axes) = self.locked_axes {
86            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
87        }
88
89        angular_inertia
90    }
91
92    /// Returns the current position of the body. This is a sum of the [`Position`] and
93    /// [`AccumulatedTranslation`] components.
94    pub fn current_position(&self) -> Vector {
95        self.position.0
96            + get_pos_translation(
97                &self.accumulated_translation,
98                &self.previous_rotation,
99                &self.rotation,
100                &self.center_of_mass,
101            )
102    }
103
104    /// Returns the [dominance](Dominance) of the body.
105    ///
106    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
107    /// For static and kinematic bodies, `i8::MAX` (`127`) is always returned instead.
108    pub fn dominance(&self) -> i8 {
109        if !self.rb.is_dynamic() {
110            i8::MAX
111        } else {
112            self.dominance.map_or(0, |dominance| dominance.0)
113        }
114    }
115}
116
117impl RigidBodyQueryReadOnlyItem<'_> {
118    /// Computes the velocity at the given `point` relative to the center of mass.
119    pub fn velocity_at_point(&self, point: Vector) -> Vector {
120        #[cfg(feature = "2d")]
121        {
122            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
123        }
124        #[cfg(feature = "3d")]
125        {
126            self.linear_velocity.0 + self.angular_velocity.cross(point)
127        }
128    }
129
130    /// Returns the mass. If the rigid body is not dynamic, the returned mass is infinite.
131    pub fn mass(&self) -> ComputedMass {
132        if self.rb.is_dynamic() {
133            *self.mass
134        } else {
135            ComputedMass::INFINITY
136        }
137    }
138
139    /// Computes the effective inverse mass, taking into account any translation locking.
140    pub fn effective_inverse_mass(&self) -> Vector {
141        if !self.rb.is_dynamic() {
142            return Vector::ZERO;
143        }
144
145        let mut inv_mass = Vector::splat(self.mass.inverse());
146
147        if let Some(locked_axes) = self.locked_axes {
148            inv_mass = locked_axes.apply_to_vec(inv_mass);
149        }
150
151        inv_mass
152    }
153
154    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
155    pub fn angular_inertia(&self) -> ComputedAngularInertia {
156        if self.rb.is_dynamic() {
157            *self.angular_inertia
158        } else {
159            ComputedAngularInertia::INFINITY
160        }
161    }
162
163    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
164    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
165        if !self.rb.is_dynamic() {
166            return ComputedAngularInertia::INFINITY;
167        }
168
169        #[cfg(feature = "2d")]
170        let mut angular_inertia = *self.angular_inertia;
171        #[cfg(feature = "3d")]
172        let mut angular_inertia = **self.global_angular_inertia;
173
174        if let Some(locked_axes) = self.locked_axes {
175            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
176        }
177
178        angular_inertia
179    }
180
181    /// Returns the current position of the body. This is a sum of the [`Position`] and
182    /// [`AccumulatedTranslation`] components.
183    pub fn current_position(&self) -> Vector {
184        self.position.0
185            + get_pos_translation(
186                self.accumulated_translation,
187                self.previous_rotation,
188                self.rotation,
189                self.center_of_mass,
190            )
191    }
192
193    /// Returns the [dominance](Dominance) of the body.
194    ///
195    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
196    /// For static and kinematic bodies, `i8::MAX` (`127`) is always returned instead.
197    pub fn dominance(&self) -> i8 {
198        if !self.rb.is_dynamic() {
199            i8::MAX
200        } else {
201            self.dominance.map_or(0, |dominance| dominance.0)
202        }
203    }
204}