avian3d/dynamics/rigid_body/
world_query.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#![allow(missing_docs)]

use crate::{prelude::*, utils::get_pos_translation};
use bevy::{
    ecs::query::QueryData,
    prelude::{Entity, Has, Ref},
};

/// A `WorldQuery` to make querying and modifying rigid bodies more convenient.
#[derive(QueryData)]
#[query_data(mutable)]
pub struct RigidBodyQuery {
    pub entity: Entity,
    pub rb: Ref<'static, RigidBody>,
    pub position: &'static mut Position,
    pub rotation: &'static mut Rotation,
    pub previous_rotation: &'static mut PreviousRotation,
    pub accumulated_translation: &'static mut AccumulatedTranslation,
    pub linear_velocity: &'static mut LinearVelocity,
    pub(crate) pre_solve_linear_velocity: &'static mut PreSolveLinearVelocity,
    pub angular_velocity: &'static mut AngularVelocity,
    pub(crate) pre_solve_angular_velocity: &'static mut PreSolveAngularVelocity,
    pub mass: &'static mut ComputedMass,
    pub angular_inertia: &'static mut ComputedAngularInertia,
    #[cfg(feature = "3d")]
    pub global_angular_inertia: &'static mut GlobalAngularInertia,
    pub center_of_mass: &'static mut ComputedCenterOfMass,
    pub friction: Option<&'static Friction>,
    pub restitution: Option<&'static Restitution>,
    pub locked_axes: Option<&'static LockedAxes>,
    pub dominance: Option<&'static Dominance>,
    pub time_sleeping: &'static mut TimeSleeping,
    pub is_sleeping: Has<Sleeping>,
    pub is_sensor: Has<Sensor>,
}

impl RigidBodyQueryItem<'_> {
    /// Computes the velocity at the given `point` relative to the center of the body.
    pub fn velocity_at_point(&self, point: Vector) -> Vector {
        #[cfg(feature = "2d")]
        {
            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
        }
        #[cfg(feature = "3d")]
        {
            self.linear_velocity.0 + self.angular_velocity.cross(point)
        }
    }

    /// Computes the effective inverse mass, taking into account any translation locking.
    pub fn effective_inverse_mass(&self) -> Vector {
        if !self.rb.is_dynamic() {
            return Vector::ZERO;
        }

        let mut inv_mass = Vector::splat(self.mass.inverse());

        if let Some(locked_axes) = self.locked_axes {
            inv_mass = locked_axes.apply_to_vec(inv_mass);
        }

        inv_mass
    }

    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
    pub fn angular_inertia(&self) -> ComputedAngularInertia {
        if self.rb.is_dynamic() {
            *self.angular_inertia
        } else {
            ComputedAngularInertia::INFINITY
        }
    }

    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
        if !self.rb.is_dynamic() {
            return ComputedAngularInertia::INFINITY;
        }

        #[cfg(feature = "2d")]
        let mut angular_inertia = *self.angular_inertia;
        #[cfg(feature = "3d")]
        let mut angular_inertia = **self.global_angular_inertia;

        if let Some(locked_axes) = self.locked_axes {
            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
        }

        angular_inertia
    }

    /// Returns the current position of the body. This is a sum of the [`Position`] and
    /// [`AccumulatedTranslation`] components.
    pub fn current_position(&self) -> Vector {
        self.position.0
            + get_pos_translation(
                &self.accumulated_translation,
                &self.previous_rotation,
                &self.rotation,
                &self.center_of_mass,
            )
    }

    /// Returns the [dominance](Dominance) of the body.
    ///
    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
    /// For static and kinematic bodies, `i8::MAX` (`127`) is always returned instead.
    pub fn dominance(&self) -> i8 {
        if !self.rb.is_dynamic() {
            i8::MAX
        } else {
            self.dominance.map_or(0, |dominance| dominance.0)
        }
    }
}

impl RigidBodyQueryReadOnlyItem<'_> {
    /// Computes the velocity at the given `point` relative to the center of mass.
    pub fn velocity_at_point(&self, point: Vector) -> Vector {
        #[cfg(feature = "2d")]
        {
            self.linear_velocity.0 + self.angular_velocity.0 * point.perp()
        }
        #[cfg(feature = "3d")]
        {
            self.linear_velocity.0 + self.angular_velocity.cross(point)
        }
    }

    /// Returns the mass. If the rigid body is not dynamic, the returned mass is infinite.
    pub fn mass(&self) -> ComputedMass {
        if self.rb.is_dynamic() {
            *self.mass
        } else {
            ComputedMass::INFINITY
        }
    }

    /// Computes the effective inverse mass, taking into account any translation locking.
    pub fn effective_inverse_mass(&self) -> Vector {
        if !self.rb.is_dynamic() {
            return Vector::ZERO;
        }

        let mut inv_mass = Vector::splat(self.mass.inverse());

        if let Some(locked_axes) = self.locked_axes {
            inv_mass = locked_axes.apply_to_vec(inv_mass);
        }

        inv_mass
    }

    /// Returns the local angular inertia. If the rigid body is not dynamic, the returned angular inertia is infinite.
    pub fn angular_inertia(&self) -> ComputedAngularInertia {
        if self.rb.is_dynamic() {
            *self.angular_inertia
        } else {
            ComputedAngularInertia::INFINITY
        }
    }

    /// Computes the effective world-space angular inertia, taking into account any rotation locking.
    pub fn effective_global_angular_inertia(&self) -> ComputedAngularInertia {
        if !self.rb.is_dynamic() {
            return ComputedAngularInertia::INFINITY;
        }

        #[cfg(feature = "2d")]
        let mut angular_inertia = *self.angular_inertia;
        #[cfg(feature = "3d")]
        let mut angular_inertia = **self.global_angular_inertia;

        if let Some(locked_axes) = self.locked_axes {
            angular_inertia = locked_axes.apply_to_angular_inertia(angular_inertia);
        }

        angular_inertia
    }

    /// Returns the current position of the body. This is a sum of the [`Position`] and
    /// [`AccumulatedTranslation`] components.
    pub fn current_position(&self) -> Vector {
        self.position.0
            + get_pos_translation(
                self.accumulated_translation,
                self.previous_rotation,
                self.rotation,
                self.center_of_mass,
            )
    }

    /// Returns the [dominance](Dominance) of the body.
    ///
    /// If it isn't specified, the default of `0` is returned for dynamic bodies.
    /// For static and kinematic bodies, `i8::MAX` (`127`) is always returned instead.
    pub fn dominance(&self) -> i8 {
        if !self.rb.is_dynamic() {
            i8::MAX
        } else {
            self.dominance.map_or(0, |dominance| dominance.0)
        }
    }
}