rapier3d/dynamics/
rigid_body.rs

1#[cfg(doc)]
2use super::IntegrationParameters;
3use crate::dynamics::{
4    LockedAxes, MassProperties, RigidBodyActivation, RigidBodyAdditionalMassProps, RigidBodyCcd,
5    RigidBodyChanges, RigidBodyColliders, RigidBodyDamping, RigidBodyDominance, RigidBodyForces,
6    RigidBodyIds, RigidBodyMassProps, RigidBodyPosition, RigidBodyType, RigidBodyVelocity,
7};
8use crate::geometry::{
9    ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition, ColliderSet, ColliderShape,
10};
11use crate::math::{AngVector, Isometry, Point, Real, Rotation, Vector};
12use crate::utils::SimdCross;
13use num::Zero;
14
15#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
16/// A rigid body.
17///
18/// To create a new rigid-body, use the [`RigidBodyBuilder`] structure.
19#[derive(Debug, Clone)]
20pub struct RigidBody {
21    pub(crate) pos: RigidBodyPosition,
22    pub(crate) mprops: RigidBodyMassProps,
23    // NOTE: we need this so that the CCD can use the actual velocities obtained
24    //       by the velocity solver with bias. If we switch to interpolation, we
25    //       should remove this field.
26    pub(crate) integrated_vels: RigidBodyVelocity,
27    pub(crate) vels: RigidBodyVelocity,
28    pub(crate) damping: RigidBodyDamping,
29    pub(crate) forces: RigidBodyForces,
30    pub(crate) ccd: RigidBodyCcd,
31    pub(crate) ids: RigidBodyIds,
32    pub(crate) colliders: RigidBodyColliders,
33    /// Whether or not this rigid-body is sleeping.
34    pub(crate) activation: RigidBodyActivation,
35    pub(crate) changes: RigidBodyChanges,
36    /// The status of the body, governing how it is affected by external forces.
37    pub(crate) body_type: RigidBodyType,
38    /// The dominance group this rigid-body is part of.
39    pub(crate) dominance: RigidBodyDominance,
40    pub(crate) enabled: bool,
41    pub(crate) additional_solver_iterations: usize,
42    /// User-defined data associated to this rigid-body.
43    pub user_data: u128,
44}
45
46impl Default for RigidBody {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl RigidBody {
53    fn new() -> Self {
54        Self {
55            pos: RigidBodyPosition::default(),
56            mprops: RigidBodyMassProps::default(),
57            integrated_vels: RigidBodyVelocity::default(),
58            vels: RigidBodyVelocity::default(),
59            damping: RigidBodyDamping::default(),
60            forces: RigidBodyForces::default(),
61            ccd: RigidBodyCcd::default(),
62            ids: RigidBodyIds::default(),
63            colliders: RigidBodyColliders::default(),
64            activation: RigidBodyActivation::active(),
65            changes: RigidBodyChanges::all(),
66            body_type: RigidBodyType::Dynamic,
67            dominance: RigidBodyDominance::default(),
68            enabled: true,
69            user_data: 0,
70            additional_solver_iterations: 0,
71        }
72    }
73
74    pub(crate) fn reset_internal_references(&mut self) {
75        self.colliders.0 = Vec::new();
76        self.ids = Default::default();
77    }
78
79    /// Copy all the characteristics from `other` to `self`.
80    ///
81    /// If you have a mutable reference to a rigid-body `rigid_body: &mut RigidBody`, attempting to
82    /// assign it a whole new rigid-body instance, e.g., `*rigid_body = RigidBodyBuilder::dynamic().build()`,
83    /// will crash due to some internal indices being overwritten. Instead, use
84    /// `rigid_body.copy_from(&RigidBodyBuilder::dynamic().build())`.
85    ///
86    /// This method will allow you to set most characteristics of this rigid-body from another
87    /// rigid-body instance without causing any breakage.
88    ///
89    /// This method **cannot** be used for editing the list of colliders attached to this rigid-body.
90    /// Therefore, the list of colliders attached to `self` won’t be replaced by the one attached
91    /// to `other`.
92    ///
93    /// The pose of `other` will only copied into `self` if `self` doesn’t have a parent (if it has
94    /// a parent, its position is directly controlled by the parent rigid-body).
95    pub fn copy_from(&mut self, other: &RigidBody) {
96        // NOTE: we deconstruct the rigid-body struct to be sure we don’t forget to
97        //       add some copies here if we add more field to RigidBody in the future.
98        let RigidBody {
99            pos,
100            mprops,
101            integrated_vels,
102            vels,
103            damping,
104            forces,
105            ccd,
106            ids: _ids,             // Internal ids must not be overwritten.
107            colliders: _colliders, // This function cannot be used to edit collider sets.
108            activation,
109            changes: _changes, // Will be set to ALL.
110            body_type,
111            dominance,
112            enabled,
113            additional_solver_iterations,
114            user_data,
115        } = other;
116
117        self.pos = *pos;
118        self.mprops = mprops.clone();
119        self.integrated_vels = *integrated_vels;
120        self.vels = *vels;
121        self.damping = *damping;
122        self.forces = *forces;
123        self.ccd = *ccd;
124        self.activation = *activation;
125        self.body_type = *body_type;
126        self.dominance = *dominance;
127        self.enabled = *enabled;
128        self.additional_solver_iterations = *additional_solver_iterations;
129        self.user_data = *user_data;
130
131        self.changes = RigidBodyChanges::all();
132    }
133
134    /// Set the additional number of solver iterations run for this rigid-body and
135    /// everything interacting with it.
136    ///
137    /// See [`Self::set_additional_solver_iterations`] for additional information.
138    pub fn additional_solver_iterations(&self) -> usize {
139        self.additional_solver_iterations
140    }
141
142    /// Set the additional number of solver iterations run for this rigid-body and
143    /// everything interacting with it.
144    ///
145    /// Increasing this number will help improve simulation accuracy on this rigid-body
146    /// and every rigid-body interacting directly or indirectly with it (through joints
147    /// or contacts). This implies a performance hit.
148    ///
149    /// The default value is 0, meaning exactly [`IntegrationParameters::num_solver_iterations`] will
150    /// be used as number of solver iterations for this body.
151    pub fn set_additional_solver_iterations(&mut self, additional_iterations: usize) {
152        self.additional_solver_iterations = additional_iterations;
153    }
154
155    /// The activation status of this rigid-body.
156    pub fn activation(&self) -> &RigidBodyActivation {
157        &self.activation
158    }
159
160    /// Mutable reference to the activation status of this rigid-body.
161    pub fn activation_mut(&mut self) -> &mut RigidBodyActivation {
162        self.changes |= RigidBodyChanges::SLEEP;
163        &mut self.activation
164    }
165
166    /// Is this rigid-body enabled?
167    pub fn is_enabled(&self) -> bool {
168        self.enabled
169    }
170
171    /// Sets whether this rigid-body is enabled or not.
172    pub fn set_enabled(&mut self, enabled: bool) {
173        if enabled != self.enabled {
174            if enabled {
175                // NOTE: this is probably overkill, but it makes sure we don’t
176                // forget anything that needs to be updated because the rigid-body
177                // was basically interpreted as if it was removed while it was
178                // disabled.
179                self.changes = RigidBodyChanges::all();
180            } else {
181                self.changes |= RigidBodyChanges::ENABLED_OR_DISABLED;
182            }
183
184            self.enabled = enabled;
185        }
186    }
187
188    /// The linear damping coefficient of this rigid-body.
189    #[inline]
190    pub fn linear_damping(&self) -> Real {
191        self.damping.linear_damping
192    }
193
194    /// Sets the linear damping coefficient of this rigid-body.
195    #[inline]
196    pub fn set_linear_damping(&mut self, damping: Real) {
197        self.damping.linear_damping = damping;
198    }
199
200    /// The angular damping coefficient of this rigid-body.
201    #[inline]
202    pub fn angular_damping(&self) -> Real {
203        self.damping.angular_damping
204    }
205
206    /// Sets the angular damping coefficient of this rigid-body.
207    #[inline]
208    pub fn set_angular_damping(&mut self, damping: Real) {
209        self.damping.angular_damping = damping
210    }
211
212    /// The type of this rigid-body.
213    pub fn body_type(&self) -> RigidBodyType {
214        self.body_type
215    }
216
217    /// Sets the type of this rigid-body.
218    pub fn set_body_type(&mut self, status: RigidBodyType, wake_up: bool) {
219        if status != self.body_type {
220            self.changes.insert(RigidBodyChanges::TYPE);
221            self.body_type = status;
222
223            if status == RigidBodyType::Fixed {
224                self.vels = RigidBodyVelocity::zero();
225            }
226
227            if self.is_dynamic() && wake_up {
228                self.wake_up(true);
229            }
230        }
231    }
232
233    /// The world-space center-of-mass of this rigid-body.
234    #[inline]
235    pub fn center_of_mass(&self) -> &Point<Real> {
236        &self.mprops.world_com
237    }
238
239    /// The local-space center-of-mass of this rigid-body.
240    #[inline]
241    pub fn local_center_of_mass(&self) -> &Point<Real> {
242        &self.mprops.local_mprops.local_com
243    }
244
245    /// The mass-properties of this rigid-body.
246    #[inline]
247    pub fn mass_properties(&self) -> &RigidBodyMassProps {
248        &self.mprops
249    }
250
251    /// The dominance group of this rigid-body.
252    ///
253    /// This method always returns `i8::MAX + 1` for non-dynamic
254    /// rigid-bodies.
255    #[inline]
256    pub fn effective_dominance_group(&self) -> i16 {
257        self.dominance.effective_group(&self.body_type)
258    }
259
260    /// Sets the axes along which this rigid-body cannot translate or rotate.
261    #[inline]
262    pub fn set_locked_axes(&mut self, locked_axes: LockedAxes, wake_up: bool) {
263        if locked_axes != self.mprops.flags {
264            if self.is_dynamic() && wake_up {
265                self.wake_up(true);
266            }
267
268            self.mprops.flags = locked_axes;
269            self.update_world_mass_properties();
270        }
271    }
272
273    /// The axes along which this rigid-body cannot translate or rotate.
274    #[inline]
275    pub fn locked_axes(&self) -> LockedAxes {
276        self.mprops.flags
277    }
278
279    #[inline]
280    /// Locks or unlocks all the rotations of this rigid-body.
281    pub fn lock_rotations(&mut self, locked: bool, wake_up: bool) {
282        if locked != self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED) {
283            if self.is_dynamic() && wake_up {
284                self.wake_up(true);
285            }
286
287            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_X, locked);
288            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_Y, locked);
289            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_Z, locked);
290            self.update_world_mass_properties();
291        }
292    }
293
294    #[inline]
295    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
296    pub fn set_enabled_rotations(
297        &mut self,
298        allow_rotations_x: bool,
299        allow_rotations_y: bool,
300        allow_rotations_z: bool,
301        wake_up: bool,
302    ) {
303        if self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_X) == allow_rotations_x
304            || self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Y) == allow_rotations_y
305            || self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z) == allow_rotations_z
306        {
307            if self.is_dynamic() && wake_up {
308                self.wake_up(true);
309            }
310
311            self.mprops
312                .flags
313                .set(LockedAxes::ROTATION_LOCKED_X, !allow_rotations_x);
314            self.mprops
315                .flags
316                .set(LockedAxes::ROTATION_LOCKED_Y, !allow_rotations_y);
317            self.mprops
318                .flags
319                .set(LockedAxes::ROTATION_LOCKED_Z, !allow_rotations_z);
320            self.update_world_mass_properties();
321        }
322    }
323
324    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
325    #[deprecated(note = "Use `set_enabled_rotations` instead")]
326    pub fn restrict_rotations(
327        &mut self,
328        allow_rotations_x: bool,
329        allow_rotations_y: bool,
330        allow_rotations_z: bool,
331        wake_up: bool,
332    ) {
333        self.set_enabled_rotations(
334            allow_rotations_x,
335            allow_rotations_y,
336            allow_rotations_z,
337            wake_up,
338        );
339    }
340
341    #[inline]
342    /// Locks or unlocks all the rotations of this rigid-body.
343    pub fn lock_translations(&mut self, locked: bool, wake_up: bool) {
344        if locked != self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED) {
345            if self.is_dynamic() && wake_up {
346                self.wake_up(true);
347            }
348
349            self.mprops
350                .flags
351                .set(LockedAxes::TRANSLATION_LOCKED, locked);
352            self.update_world_mass_properties();
353        }
354    }
355
356    #[inline]
357    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
358    pub fn set_enabled_translations(
359        &mut self,
360        allow_translation_x: bool,
361        allow_translation_y: bool,
362        #[cfg(feature = "dim3")] allow_translation_z: bool,
363        wake_up: bool,
364    ) {
365        #[cfg(feature = "dim2")]
366        if self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_X) != allow_translation_x
367            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Y) != allow_translation_y
368        {
369            // Nothing to change.
370            return;
371        }
372        #[cfg(feature = "dim3")]
373        if self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_X) != allow_translation_x
374            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Y) != allow_translation_y
375            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Z) != allow_translation_z
376        {
377            // Nothing to change.
378            return;
379        }
380
381        if self.is_dynamic() && wake_up {
382            self.wake_up(true);
383        }
384
385        self.mprops
386            .flags
387            .set(LockedAxes::TRANSLATION_LOCKED_X, !allow_translation_x);
388        self.mprops
389            .flags
390            .set(LockedAxes::TRANSLATION_LOCKED_Y, !allow_translation_y);
391        #[cfg(feature = "dim3")]
392        self.mprops
393            .flags
394            .set(LockedAxes::TRANSLATION_LOCKED_Z, !allow_translation_z);
395        self.update_world_mass_properties();
396    }
397
398    #[inline]
399    #[deprecated(note = "Use `set_enabled_translations` instead")]
400    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
401    pub fn restrict_translations(
402        &mut self,
403        allow_translation_x: bool,
404        allow_translation_y: bool,
405        #[cfg(feature = "dim3")] allow_translation_z: bool,
406        wake_up: bool,
407    ) {
408        self.set_enabled_translations(
409            allow_translation_x,
410            allow_translation_y,
411            #[cfg(feature = "dim3")]
412            allow_translation_z,
413            wake_up,
414        )
415    }
416
417    /// Are the translations of this rigid-body locked?
418    #[cfg(feature = "dim2")]
419    pub fn is_translation_locked(&self) -> bool {
420        self.mprops
421            .flags
422            .contains(LockedAxes::TRANSLATION_LOCKED_X | LockedAxes::TRANSLATION_LOCKED_Y)
423    }
424
425    /// Are the translations of this rigid-body locked?
426    #[cfg(feature = "dim3")]
427    pub fn is_translation_locked(&self) -> bool {
428        self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED)
429    }
430
431    /// Are the rotations of this rigid-body locked?
432    #[cfg(feature = "dim2")]
433    pub fn is_rotation_locked(&self) -> bool {
434        self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z)
435    }
436
437    /// Returns `true` for each rotational degrees of freedom locked on this rigid-body.
438    #[cfg(feature = "dim3")]
439    pub fn is_rotation_locked(&self) -> [bool; 3] {
440        [
441            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_X),
442            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Y),
443            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z),
444        ]
445    }
446
447    /// Enables of disable CCD (Continuous Collision-Detection) for this rigid-body.
448    ///
449    /// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
450    pub fn enable_ccd(&mut self, enabled: bool) {
451        self.ccd.ccd_enabled = enabled;
452    }
453
454    /// Is CCD (continuous collision-detection) enabled for this rigid-body?
455    pub fn is_ccd_enabled(&self) -> bool {
456        self.ccd.ccd_enabled
457    }
458
459    /// Sets the maximum prediction distance Soft Continuous Collision-Detection.
460    ///
461    /// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
462    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
463    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
464    /// performance badly by increasing the work needed from the broad-phase.
465    ///
466    /// It is a generally cheaper variant of regular CCD (that can be enabled with
467    /// [`RigidBody::enable_ccd`] since it relies on predictive constraints instead of
468    /// shape-cast and substeps.
469    pub fn set_soft_ccd_prediction(&mut self, prediction_distance: Real) {
470        self.ccd.soft_ccd_prediction = prediction_distance;
471    }
472
473    /// The soft-CCD prediction distance for this rigid-body.
474    ///
475    /// See the documentation of [`RigidBody::set_soft_ccd_prediction`] for additional details on
476    /// soft-CCD.
477    pub fn soft_ccd_prediction(&self) -> Real {
478        self.ccd.soft_ccd_prediction
479    }
480
481    // This is different from `is_ccd_enabled`. This checks that CCD
482    // is active for this rigid-body, i.e., if it was seen to move fast
483    // enough to justify a CCD run.
484    /// Is CCD active for this rigid-body?
485    ///
486    /// The CCD is considered active if the rigid-body is moving at
487    /// a velocity greater than an automatically-computed threshold.
488    ///
489    /// This is not the same as `self.is_ccd_enabled` which only
490    /// checks if CCD is enabled to run for this rigid-body or if
491    /// it is completely disabled (independently from its velocity).
492    pub fn is_ccd_active(&self) -> bool {
493        self.ccd.ccd_active
494    }
495
496    /// Recompute the mass-properties of this rigid-bodies based on its currently attached colliders.
497    pub fn recompute_mass_properties_from_colliders(&mut self, colliders: &ColliderSet) {
498        self.mprops.recompute_mass_properties_from_colliders(
499            colliders,
500            &self.colliders,
501            &self.pos.position,
502        );
503    }
504
505    /// Sets the rigid-body's additional mass.
506    ///
507    /// The total angular inertia of the rigid-body will be scaled automatically based on this
508    /// additional mass. If this scaling effect isn’t desired, use [`Self::set_additional_mass_properties`]
509    /// instead of this method.
510    ///
511    /// This is only the "additional" mass because the total mass of the  rigid-body is
512    /// equal to the sum of this additional mass and the mass computed from the colliders
513    /// (with non-zero densities) attached to this rigid-body.
514    ///
515    /// That total mass (which includes the attached colliders’ contributions)
516    /// will be updated at the name physics step, or can be updated manually with
517    /// [`Self::recompute_mass_properties_from_colliders`].
518    ///
519    /// This will override any previous mass-properties set by [`Self::set_additional_mass`],
520    /// [`Self::set_additional_mass_properties`], [`RigidBodyBuilder::additional_mass`], or
521    /// [`RigidBodyBuilder::additional_mass_properties`] for this rigid-body.
522    ///
523    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
524    /// put to sleep because it did not move for a while.
525    #[inline]
526    pub fn set_additional_mass(&mut self, additional_mass: Real, wake_up: bool) {
527        self.do_set_additional_mass_properties(
528            RigidBodyAdditionalMassProps::Mass(additional_mass),
529            wake_up,
530        )
531    }
532
533    /// Sets the rigid-body's additional mass-properties.
534    ///
535    /// This is only the "additional" mass-properties because the total mass-properties of the
536    /// rigid-body is equal to the sum of this additional mass-properties and the mass computed from
537    /// the colliders (with non-zero densities) attached to this rigid-body.
538    ///
539    /// That total mass-properties (which include the attached colliders’ contributions)
540    /// will be updated at the name physics step, or can be updated manually with
541    /// [`Self::recompute_mass_properties_from_colliders`].
542    ///
543    /// This will override any previous mass-properties set by [`Self::set_additional_mass`],
544    /// [`Self::set_additional_mass_properties`], [`RigidBodyBuilder::additional_mass`], or
545    /// [`RigidBodyBuilder::additional_mass_properties`] for this rigid-body.
546    ///
547    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
548    /// put to sleep because it did not move for a while.
549    #[inline]
550    pub fn set_additional_mass_properties(&mut self, props: MassProperties, wake_up: bool) {
551        self.do_set_additional_mass_properties(
552            RigidBodyAdditionalMassProps::MassProps(props),
553            wake_up,
554        )
555    }
556
557    fn do_set_additional_mass_properties(
558        &mut self,
559        props: RigidBodyAdditionalMassProps,
560        wake_up: bool,
561    ) {
562        let new_mprops = Some(Box::new(props));
563
564        if self.mprops.additional_local_mprops != new_mprops {
565            self.changes.insert(RigidBodyChanges::LOCAL_MASS_PROPERTIES);
566            self.mprops.additional_local_mprops = new_mprops;
567
568            if self.is_dynamic() && wake_up {
569                self.wake_up(true);
570            }
571        }
572    }
573
574    /// The handles of colliders attached to this rigid body.
575    pub fn colliders(&self) -> &[ColliderHandle] {
576        &self.colliders.0[..]
577    }
578
579    /// Is this rigid body dynamic?
580    ///
581    /// A dynamic body can move freely and is affected by forces.
582    pub fn is_dynamic(&self) -> bool {
583        self.body_type == RigidBodyType::Dynamic
584    }
585
586    /// Is this rigid body kinematic?
587    ///
588    /// A kinematic body can move freely but is not affected by forces.
589    pub fn is_kinematic(&self) -> bool {
590        self.body_type.is_kinematic()
591    }
592
593    /// Is this rigid body fixed?
594    ///
595    /// A fixed body cannot move and is not affected by forces.
596    pub fn is_fixed(&self) -> bool {
597        self.body_type == RigidBodyType::Fixed
598    }
599
600    /// The mass of this rigid body.
601    ///
602    /// Returns zero if this rigid body has an infinite mass.
603    pub fn mass(&self) -> Real {
604        self.mprops.local_mprops.mass()
605    }
606
607    /// The predicted position of this rigid-body.
608    ///
609    /// If this rigid-body is kinematic this value is set by the `set_next_kinematic_position`
610    /// method and is used for estimating the kinematic body velocity at the next timestep.
611    /// For non-kinematic bodies, this value is currently unspecified.
612    pub fn next_position(&self) -> &Isometry<Real> {
613        &self.pos.next_position
614    }
615
616    /// The scale factor applied to the gravity affecting this rigid-body.
617    pub fn gravity_scale(&self) -> Real {
618        self.forces.gravity_scale
619    }
620
621    /// Sets the gravity scale facter for this rigid-body.
622    pub fn set_gravity_scale(&mut self, scale: Real, wake_up: bool) {
623        if self.forces.gravity_scale != scale {
624            if wake_up && self.activation.sleeping {
625                self.changes.insert(RigidBodyChanges::SLEEP);
626                self.activation.sleeping = false;
627            }
628
629            self.forces.gravity_scale = scale;
630        }
631    }
632
633    /// The dominance group of this rigid-body.
634    pub fn dominance_group(&self) -> i8 {
635        self.dominance.0
636    }
637
638    /// The dominance group of this rigid-body.
639    pub fn set_dominance_group(&mut self, dominance: i8) {
640        if self.dominance.0 != dominance {
641            self.changes.insert(RigidBodyChanges::DOMINANCE);
642            self.dominance.0 = dominance
643        }
644    }
645
646    /// Adds a collider to this rigid-body.
647    pub(crate) fn add_collider_internal(
648        &mut self,
649        co_handle: ColliderHandle,
650        co_parent: &ColliderParent,
651        co_pos: &mut ColliderPosition,
652        co_shape: &ColliderShape,
653        co_mprops: &ColliderMassProps,
654    ) {
655        self.colliders.attach_collider(
656            &mut self.changes,
657            &mut self.ccd,
658            &mut self.mprops,
659            &self.pos,
660            co_handle,
661            co_pos,
662            co_parent,
663            co_shape,
664            co_mprops,
665        )
666    }
667
668    /// Removes a collider from this rigid-body.
669    pub(crate) fn remove_collider_internal(&mut self, handle: ColliderHandle) {
670        if let Some(i) = self.colliders.0.iter().position(|e| *e == handle) {
671            self.changes.set(RigidBodyChanges::COLLIDERS, true);
672            self.colliders.0.swap_remove(i);
673        }
674    }
675
676    /// Put this rigid body to sleep.
677    ///
678    /// A sleeping body no longer moves and is no longer simulated by the physics engine unless
679    /// it is waken up. It can be woken manually with `self.wake_up` or automatically due to
680    /// external forces like contacts.
681    pub fn sleep(&mut self) {
682        self.activation.sleep();
683        self.vels = RigidBodyVelocity::zero();
684    }
685
686    /// Wakes up this rigid body if it is sleeping.
687    ///
688    /// If `strong` is `true` then it is assured that the rigid-body will
689    /// remain awake during multiple subsequent timesteps.
690    pub fn wake_up(&mut self, strong: bool) {
691        if self.activation.sleeping {
692            self.changes.insert(RigidBodyChanges::SLEEP);
693        }
694
695        self.activation.wake_up(strong);
696    }
697
698    /// Is this rigid body sleeping?
699    pub fn is_sleeping(&self) -> bool {
700        // TODO: should we:
701        // - return false for fixed bodies.
702        // - return true for non-sleeping dynamic bodies.
703        // - return true only for kinematic bodies with non-zero velocity?
704        self.activation.sleeping
705    }
706
707    /// Is the velocity of this body not zero?
708    pub fn is_moving(&self) -> bool {
709        !self.vels.linvel.is_zero() || !self.vels.angvel.is_zero()
710    }
711
712    /// The linear and angular velocity of this rigid-body.
713    pub fn vels(&self) -> &RigidBodyVelocity {
714        &self.vels
715    }
716
717    /// The linear velocity of this rigid-body.
718    pub fn linvel(&self) -> &Vector<Real> {
719        &self.vels.linvel
720    }
721
722    /// The angular velocity of this rigid-body.
723    #[cfg(feature = "dim2")]
724    pub fn angvel(&self) -> Real {
725        self.vels.angvel
726    }
727
728    /// The angular velocity of this rigid-body.
729    #[cfg(feature = "dim3")]
730    pub fn angvel(&self) -> &Vector<Real> {
731        &self.vels.angvel
732    }
733
734    /// Set both the angular and linear velocity of this rigid-body.
735    ///
736    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
737    /// put to sleep because it did not move for a while.
738    pub fn set_vels(&mut self, vels: RigidBodyVelocity, wake_up: bool) {
739        self.set_linvel(vels.linvel, wake_up);
740        self.set_angvel(vels.angvel, wake_up);
741    }
742
743    /// The linear velocity of this rigid-body.
744    ///
745    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
746    /// put to sleep because it did not move for a while.
747    pub fn set_linvel(&mut self, linvel: Vector<Real>, wake_up: bool) {
748        if self.vels.linvel != linvel {
749            match self.body_type {
750                RigidBodyType::Dynamic => {
751                    self.vels.linvel = linvel;
752                    if wake_up {
753                        self.wake_up(true)
754                    }
755                }
756                RigidBodyType::KinematicVelocityBased => {
757                    self.vels.linvel = linvel;
758                }
759                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
760            }
761        }
762    }
763
764    /// The angular velocity of this rigid-body.
765    ///
766    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
767    /// put to sleep because it did not move for a while.
768    #[cfg(feature = "dim2")]
769    pub fn set_angvel(&mut self, angvel: Real, wake_up: bool) {
770        if self.vels.angvel != angvel {
771            match self.body_type {
772                RigidBodyType::Dynamic => {
773                    self.vels.angvel = angvel;
774                    if wake_up {
775                        self.wake_up(true)
776                    }
777                }
778                RigidBodyType::KinematicVelocityBased => {
779                    self.vels.angvel = angvel;
780                }
781                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
782            }
783        }
784    }
785
786    /// The angular velocity of this rigid-body.
787    ///
788    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
789    /// put to sleep because it did not move for a while.
790    #[cfg(feature = "dim3")]
791    pub fn set_angvel(&mut self, angvel: Vector<Real>, wake_up: bool) {
792        if self.vels.angvel != angvel {
793            match self.body_type {
794                RigidBodyType::Dynamic => {
795                    self.vels.angvel = angvel;
796                    if wake_up {
797                        self.wake_up(true)
798                    }
799                }
800                RigidBodyType::KinematicVelocityBased => {
801                    self.vels.angvel = angvel;
802                }
803                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
804            }
805        }
806    }
807
808    /// The world-space position of this rigid-body.
809    #[inline]
810    pub fn position(&self) -> &Isometry<Real> {
811        &self.pos.position
812    }
813
814    /// The translational part of this rigid-body's position.
815    #[inline]
816    pub fn translation(&self) -> &Vector<Real> {
817        &self.pos.position.translation.vector
818    }
819
820    /// Sets the translational part of this rigid-body's position.
821    #[inline]
822    pub fn set_translation(&mut self, translation: Vector<Real>, wake_up: bool) {
823        if self.pos.position.translation.vector != translation
824            || self.pos.next_position.translation.vector != translation
825        {
826            self.changes.insert(RigidBodyChanges::POSITION);
827            self.pos.position.translation.vector = translation;
828            self.pos.next_position.translation.vector = translation;
829
830            // Update the world mass-properties so torque application remains valid.
831            self.update_world_mass_properties();
832
833            // TODO: Do we really need to check that the body isn't dynamic?
834            if wake_up && self.is_dynamic() {
835                self.wake_up(true)
836            }
837        }
838    }
839
840    /// The rotational part of this rigid-body's position.
841    #[inline]
842    pub fn rotation(&self) -> &Rotation<Real> {
843        &self.pos.position.rotation
844    }
845
846    /// Sets the rotational part of this rigid-body's position.
847    #[inline]
848    pub fn set_rotation(&mut self, rotation: Rotation<Real>, wake_up: bool) {
849        if self.pos.position.rotation != rotation || self.pos.next_position.rotation != rotation {
850            self.changes.insert(RigidBodyChanges::POSITION);
851            self.pos.position.rotation = rotation;
852            self.pos.next_position.rotation = rotation;
853
854            // Update the world mass-properties so torque application remains valid.
855            self.update_world_mass_properties();
856
857            // TODO: Do we really need to check that the body isn't dynamic?
858            if wake_up && self.is_dynamic() {
859                self.wake_up(true)
860            }
861        }
862    }
863
864    /// Sets the position and `next_kinematic_position` of this rigid body.
865    ///
866    /// This will teleport the rigid-body to the specified position/orientation,
867    /// completely ignoring any physics rule. If this body is kinematic, this will
868    /// also set the next kinematic position to the same value, effectively
869    /// resetting to zero the next interpolated velocity of the kinematic body.
870    ///
871    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
872    /// put to sleep because it did not move for a while.
873    pub fn set_position(&mut self, pos: Isometry<Real>, wake_up: bool) {
874        if self.pos.position != pos || self.pos.next_position != pos {
875            self.changes.insert(RigidBodyChanges::POSITION);
876            self.pos.position = pos;
877            self.pos.next_position = pos;
878
879            // Update the world mass-properties so torque application remains valid.
880            self.update_world_mass_properties();
881
882            // TODO: Do we really need to check that the body isn't dynamic?
883            if wake_up && self.is_dynamic() {
884                self.wake_up(true)
885            }
886        }
887    }
888
889    /// If this rigid body is kinematic, sets its future orientation after the next timestep integration.
890    pub fn set_next_kinematic_rotation(&mut self, rotation: Rotation<Real>) {
891        if self.is_kinematic() {
892            self.pos.next_position.rotation = rotation;
893        }
894    }
895
896    /// If this rigid body is kinematic, sets its future translation after the next timestep integration.
897    pub fn set_next_kinematic_translation(&mut self, translation: Vector<Real>) {
898        if self.is_kinematic() {
899            self.pos.next_position.translation = translation.into();
900        }
901    }
902
903    /// If this rigid body is kinematic, sets its future position (translation and orientation) after
904    /// the next timestep integration.
905    pub fn set_next_kinematic_position(&mut self, pos: Isometry<Real>) {
906        if self.is_kinematic() {
907            self.pos.next_position = pos;
908        }
909    }
910
911    /// Predicts the next position of this rigid-body, by integrating its velocity and forces
912    /// by a time of `dt`.
913    pub(crate) fn predict_position_using_velocity_and_forces_with_max_dist(
914        &self,
915        dt: Real,
916        max_dist: Real,
917    ) -> Isometry<Real> {
918        let new_vels = self.forces.integrate(dt, &self.vels, &self.mprops);
919        // Compute the clamped dt such that the body doesn’t travel more than `max_dist`.
920        let linvel_norm = new_vels.linvel.norm();
921        let clamped_linvel = linvel_norm.min(max_dist * crate::utils::inv(dt));
922        let clamped_dt = dt * clamped_linvel * crate::utils::inv(linvel_norm);
923        new_vels.integrate(
924            clamped_dt,
925            &self.pos.position,
926            &self.mprops.local_mprops.local_com,
927        )
928    }
929
930    /// Predicts the next position of this rigid-body, by integrating its velocity and forces
931    /// by a time of `dt`.
932    pub fn predict_position_using_velocity_and_forces(&self, dt: Real) -> Isometry<Real> {
933        self.pos
934            .integrate_forces_and_velocities(dt, &self.forces, &self.vels, &self.mprops)
935    }
936
937    /// Predicts the next position of this rigid-body, by integrating only its velocity
938    /// by a time of `dt`.
939    ///
940    /// The forces that were applied to this rigid-body since the last physics step will
941    /// be ignored by this function. Use [`Self::predict_position_using_velocity_and_forces`]
942    /// instead to take forces into account.
943    pub fn predict_position_using_velocity(&self, dt: Real) -> Isometry<Real> {
944        self.vels
945            .integrate(dt, &self.pos.position, &self.mprops.local_mprops.local_com)
946    }
947
948    pub(crate) fn update_world_mass_properties(&mut self) {
949        self.mprops.update_world_mass_properties(&self.pos.position);
950    }
951}
952
953/// ## Applying forces and torques
954impl RigidBody {
955    /// Resets to zero all the constant (linear) forces manually applied to this rigid-body.
956    pub fn reset_forces(&mut self, wake_up: bool) {
957        if !self.forces.user_force.is_zero() {
958            self.forces.user_force = na::zero();
959
960            if wake_up {
961                self.wake_up(true);
962            }
963        }
964    }
965
966    /// Resets to zero all the constant torques manually applied to this rigid-body.
967    pub fn reset_torques(&mut self, wake_up: bool) {
968        if !self.forces.user_torque.is_zero() {
969            self.forces.user_torque = na::zero();
970
971            if wake_up {
972                self.wake_up(true);
973            }
974        }
975    }
976
977    /// Adds to this rigid-body a constant force applied at its center-of-mass.ç
978    ///
979    /// This does nothing on non-dynamic bodies.
980    pub fn add_force(&mut self, force: Vector<Real>, wake_up: bool) {
981        if !force.is_zero() && self.body_type == RigidBodyType::Dynamic {
982            self.forces.user_force += force;
983
984            if wake_up {
985                self.wake_up(true);
986            }
987        }
988    }
989
990    /// Adds to this rigid-body a constant torque at its center-of-mass.
991    ///
992    /// This does nothing on non-dynamic bodies.
993    #[cfg(feature = "dim2")]
994    pub fn add_torque(&mut self, torque: Real, wake_up: bool) {
995        if !torque.is_zero() && self.body_type == RigidBodyType::Dynamic {
996            self.forces.user_torque += torque;
997
998            if wake_up {
999                self.wake_up(true);
1000            }
1001        }
1002    }
1003
1004    /// Adds to this rigid-body a constant torque at its center-of-mass.
1005    ///
1006    /// This does nothing on non-dynamic bodies.
1007    #[cfg(feature = "dim3")]
1008    pub fn add_torque(&mut self, torque: Vector<Real>, wake_up: bool) {
1009        if !torque.is_zero() && self.body_type == RigidBodyType::Dynamic {
1010            self.forces.user_torque += torque;
1011
1012            if wake_up {
1013                self.wake_up(true);
1014            }
1015        }
1016    }
1017
1018    /// Adds to this rigid-body a constant force at the given world-space point of this rigid-body.
1019    ///
1020    /// This does nothing on non-dynamic bodies.
1021    pub fn add_force_at_point(&mut self, force: Vector<Real>, point: Point<Real>, wake_up: bool) {
1022        if !force.is_zero() && self.body_type == RigidBodyType::Dynamic {
1023            self.forces.user_force += force;
1024            self.forces.user_torque += (point - self.mprops.world_com).gcross(force);
1025
1026            if wake_up {
1027                self.wake_up(true);
1028            }
1029        }
1030    }
1031}
1032
1033/// ## Applying impulses and angular impulses
1034impl RigidBody {
1035    /// Applies an impulse at the center-of-mass of this rigid-body.
1036    /// The impulse is applied right away, changing the linear velocity.
1037    /// This does nothing on non-dynamic bodies.
1038    #[profiling::function]
1039    pub fn apply_impulse(&mut self, impulse: Vector<Real>, wake_up: bool) {
1040        if !impulse.is_zero() && self.body_type == RigidBodyType::Dynamic {
1041            self.vels.linvel += impulse.component_mul(&self.mprops.effective_inv_mass);
1042
1043            if wake_up {
1044                self.wake_up(true);
1045            }
1046        }
1047    }
1048
1049    /// Applies an angular impulse at the center-of-mass of this rigid-body.
1050    /// The impulse is applied right away, changing the angular velocity.
1051    /// This does nothing on non-dynamic bodies.
1052    #[cfg(feature = "dim2")]
1053    #[profiling::function]
1054    pub fn apply_torque_impulse(&mut self, torque_impulse: Real, wake_up: bool) {
1055        if !torque_impulse.is_zero() && self.body_type == RigidBodyType::Dynamic {
1056            self.vels.angvel += self.mprops.effective_world_inv_inertia_sqrt
1057                * (self.mprops.effective_world_inv_inertia_sqrt * torque_impulse);
1058
1059            if wake_up {
1060                self.wake_up(true);
1061            }
1062        }
1063    }
1064
1065    /// Applies an angular impulse at the center-of-mass of this rigid-body.
1066    /// The impulse is applied right away, changing the angular velocity.
1067    /// This does nothing on non-dynamic bodies.
1068    #[cfg(feature = "dim3")]
1069    #[profiling::function]
1070    pub fn apply_torque_impulse(&mut self, torque_impulse: Vector<Real>, wake_up: bool) {
1071        if !torque_impulse.is_zero() && self.body_type == RigidBodyType::Dynamic {
1072            self.vels.angvel += self.mprops.effective_world_inv_inertia_sqrt
1073                * (self.mprops.effective_world_inv_inertia_sqrt * torque_impulse);
1074
1075            if wake_up {
1076                self.wake_up(true);
1077            }
1078        }
1079    }
1080
1081    /// Applies an impulse at the given world-space point of this rigid-body.
1082    /// The impulse is applied right away, changing the linear and/or angular velocities.
1083    /// This does nothing on non-dynamic bodies.
1084    pub fn apply_impulse_at_point(
1085        &mut self,
1086        impulse: Vector<Real>,
1087        point: Point<Real>,
1088        wake_up: bool,
1089    ) {
1090        let torque_impulse = (point - self.mprops.world_com).gcross(impulse);
1091        self.apply_impulse(impulse, wake_up);
1092        self.apply_torque_impulse(torque_impulse, wake_up);
1093    }
1094
1095    /// Retrieves the constant force(s) that the user has added to the body.
1096    ///
1097    /// Returns zero if the rigid-body isn’t dynamic.
1098    pub fn user_force(&self) -> Vector<Real> {
1099        if self.body_type == RigidBodyType::Dynamic {
1100            self.forces.user_force
1101        } else {
1102            Vector::zeros()
1103        }
1104    }
1105
1106    /// Retrieves the constant torque(s) that the user has added to the body.
1107    ///
1108    /// Returns zero if the rigid-body isn’t dynamic.
1109    pub fn user_torque(&self) -> AngVector<Real> {
1110        if self.body_type == RigidBodyType::Dynamic {
1111            self.forces.user_torque
1112        } else {
1113            AngVector::zero()
1114        }
1115    }
1116}
1117
1118impl RigidBody {
1119    /// The velocity of the given world-space point on this rigid-body.
1120    pub fn velocity_at_point(&self, point: &Point<Real>) -> Vector<Real> {
1121        self.vels.velocity_at_point(point, &self.mprops.world_com)
1122    }
1123
1124    /// The kinetic energy of this body.
1125    pub fn kinetic_energy(&self) -> Real {
1126        self.vels.kinetic_energy(&self.mprops)
1127    }
1128
1129    /// The potential energy of this body in a gravity field.
1130    pub fn gravitational_potential_energy(&self, dt: Real, gravity: Vector<Real>) -> Real {
1131        let world_com = self
1132            .mprops
1133            .local_mprops
1134            .world_com(&self.pos.position)
1135            .coords;
1136
1137        // Project position back along velocity vector one half-step (leap-frog)
1138        // to sync up the potential energy with the kinetic energy:
1139        let world_com = world_com - self.vels.linvel * (dt / 2.0);
1140
1141        -self.mass() * self.forces.gravity_scale * gravity.dot(&world_com)
1142    }
1143}
1144
1145/// A builder for rigid-bodies.
1146#[derive(Clone, Debug, PartialEq)]
1147#[must_use = "Builder functions return the updated builder"]
1148pub struct RigidBodyBuilder {
1149    /// The initial position of the rigid-body to be built.
1150    pub position: Isometry<Real>,
1151    /// The linear velocity of the rigid-body to be built.
1152    pub linvel: Vector<Real>,
1153    /// The angular velocity of the rigid-body to be built.
1154    pub angvel: AngVector<Real>,
1155    /// The scale factor applied to the gravity affecting the rigid-body to be built, `1.0` by default.
1156    pub gravity_scale: Real,
1157    /// Damping factor for gradually slowing down the translational motion of the rigid-body, `0.0` by default.
1158    pub linear_damping: Real,
1159    /// Damping factor for gradually slowing down the angular motion of the rigid-body, `0.0` by default.
1160    pub angular_damping: Real,
1161    /// The type of rigid-body being constructed.
1162    pub body_type: RigidBodyType,
1163    mprops_flags: LockedAxes,
1164    /// The additional mass-properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information.
1165    additional_mass_properties: RigidBodyAdditionalMassProps,
1166    /// Whether the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
1167    pub can_sleep: bool,
1168    /// Whether the rigid-body is to be created asleep.
1169    pub sleeping: bool,
1170    /// Whether Continuous Collision-Detection is enabled for the rigid-body to be built.
1171    ///
1172    /// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
1173    pub ccd_enabled: bool,
1174    /// The maximum prediction distance Soft Continuous Collision-Detection.
1175    ///
1176    /// When set to 0, soft CCD is disabled. Soft-CCD helps prevent tunneling especially of
1177    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
1178    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
1179    /// performance badly by increasing the work needed from the broad-phase.
1180    ///
1181    /// It is a generally cheaper variant of regular CCD (that can be enabled with
1182    /// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
1183    /// shape-cast and substeps.
1184    pub soft_ccd_prediction: Real,
1185    /// The dominance group of the rigid-body to be built.
1186    pub dominance_group: i8,
1187    /// Will the rigid-body being built be enabled?
1188    pub enabled: bool,
1189    /// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
1190    pub user_data: u128,
1191    /// The additional number of solver iterations run for this rigid-body and
1192    /// everything interacting with it.
1193    ///
1194    /// See [`RigidBody::set_additional_solver_iterations`] for additional information.
1195    pub additional_solver_iterations: usize,
1196}
1197
1198impl Default for RigidBodyBuilder {
1199    fn default() -> Self {
1200        Self::dynamic()
1201    }
1202}
1203
1204impl RigidBodyBuilder {
1205    /// Initialize a new builder for a rigid body which is either fixed, dynamic, or kinematic.
1206    pub fn new(body_type: RigidBodyType) -> Self {
1207        Self {
1208            position: Isometry::identity(),
1209            linvel: Vector::zeros(),
1210            angvel: na::zero(),
1211            gravity_scale: 1.0,
1212            linear_damping: 0.0,
1213            angular_damping: 0.0,
1214            body_type,
1215            mprops_flags: LockedAxes::empty(),
1216            additional_mass_properties: RigidBodyAdditionalMassProps::default(),
1217            can_sleep: true,
1218            sleeping: false,
1219            ccd_enabled: false,
1220            soft_ccd_prediction: 0.0,
1221            dominance_group: 0,
1222            enabled: true,
1223            user_data: 0,
1224            additional_solver_iterations: 0,
1225        }
1226    }
1227
1228    /// Initializes the builder of a new fixed rigid body.
1229    #[deprecated(note = "use `RigidBodyBuilder::fixed()` instead")]
1230    pub fn new_static() -> Self {
1231        Self::fixed()
1232    }
1233    /// Initializes the builder of a new velocity-based kinematic rigid body.
1234    #[deprecated(note = "use `RigidBodyBuilder::kinematic_velocity_based()` instead")]
1235    pub fn new_kinematic_velocity_based() -> Self {
1236        Self::kinematic_velocity_based()
1237    }
1238    /// Initializes the builder of a new position-based kinematic rigid body.
1239    #[deprecated(note = "use `RigidBodyBuilder::kinematic_position_based()` instead")]
1240    pub fn new_kinematic_position_based() -> Self {
1241        Self::kinematic_position_based()
1242    }
1243
1244    /// Initializes the builder of a new fixed rigid body.
1245    pub fn fixed() -> Self {
1246        Self::new(RigidBodyType::Fixed)
1247    }
1248
1249    /// Initializes the builder of a new velocity-based kinematic rigid body.
1250    pub fn kinematic_velocity_based() -> Self {
1251        Self::new(RigidBodyType::KinematicVelocityBased)
1252    }
1253
1254    /// Initializes the builder of a new position-based kinematic rigid body.
1255    pub fn kinematic_position_based() -> Self {
1256        Self::new(RigidBodyType::KinematicPositionBased)
1257    }
1258
1259    /// Initializes the builder of a new dynamic rigid body.
1260    pub fn dynamic() -> Self {
1261        Self::new(RigidBodyType::Dynamic)
1262    }
1263
1264    /// Sets the additional number of solver iterations run for this rigid-body and
1265    /// everything interacting with it.
1266    ///
1267    /// See [`RigidBody::set_additional_solver_iterations`] for additional information.
1268    pub fn additional_solver_iterations(mut self, additional_iterations: usize) -> Self {
1269        self.additional_solver_iterations = additional_iterations;
1270        self
1271    }
1272
1273    /// Sets the scale applied to the gravity force affecting the rigid-body to be created.
1274    pub fn gravity_scale(mut self, scale_factor: Real) -> Self {
1275        self.gravity_scale = scale_factor;
1276        self
1277    }
1278
1279    /// Sets the dominance group of this rigid-body.
1280    pub fn dominance_group(mut self, group: i8) -> Self {
1281        self.dominance_group = group;
1282        self
1283    }
1284
1285    /// Sets the initial translation of the rigid-body to be created.
1286    pub fn translation(mut self, translation: Vector<Real>) -> Self {
1287        self.position.translation.vector = translation;
1288        self
1289    }
1290
1291    /// Sets the initial orientation of the rigid-body to be created.
1292    pub fn rotation(mut self, angle: AngVector<Real>) -> Self {
1293        self.position.rotation = Rotation::new(angle);
1294        self
1295    }
1296
1297    /// Sets the initial position (translation and orientation) of the rigid-body to be created.
1298    pub fn position(mut self, pos: Isometry<Real>) -> Self {
1299        self.position = pos;
1300        self
1301    }
1302
1303    /// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
1304    pub fn user_data(mut self, data: u128) -> Self {
1305        self.user_data = data;
1306        self
1307    }
1308
1309    /// Sets the additional mass-properties of the rigid-body being built.
1310    ///
1311    /// This will be overridden by a call to [`Self::additional_mass`] so it only makes sense to call
1312    /// either [`Self::additional_mass`] or [`Self::additional_mass_properties`].    
1313    ///
1314    /// Note that "additional" means that the final mass-properties of the rigid-bodies depends
1315    /// on the initial mass-properties of the rigid-body (set by this method)
1316    /// to which is added the contributions of all the colliders with non-zero density
1317    /// attached to this rigid-body.
1318    ///
1319    /// Therefore, if you want your provided mass-properties to be the final
1320    /// mass-properties of your rigid-body, don't attach colliders to it, or
1321    /// only attach colliders with densities equal to zero.
1322    pub fn additional_mass_properties(mut self, mprops: MassProperties) -> Self {
1323        self.additional_mass_properties = RigidBodyAdditionalMassProps::MassProps(mprops);
1324        self
1325    }
1326
1327    /// Sets the additional mass of the rigid-body being built.
1328    ///
1329    /// This will be overridden by a call to [`Self::additional_mass_properties`] so it only makes
1330    /// sense to call either [`Self::additional_mass`] or [`Self::additional_mass_properties`].    
1331    ///
1332    /// This is only the "additional" mass because the total mass of the  rigid-body is
1333    /// equal to the sum of this additional mass and the mass computed from the colliders
1334    /// (with non-zero densities) attached to this rigid-body.
1335    ///
1336    /// The total angular inertia of the rigid-body will be scaled automatically based on this
1337    /// additional mass. If this scaling effect isn’t desired, use [`Self::additional_mass_properties`]
1338    /// instead of this method.
1339    ///
1340    /// # Parameters
1341    /// * `mass`- The mass that will be added to the created rigid-body.
1342    pub fn additional_mass(mut self, mass: Real) -> Self {
1343        self.additional_mass_properties = RigidBodyAdditionalMassProps::Mass(mass);
1344        self
1345    }
1346
1347    /// Sets the axes along which this rigid-body cannot translate or rotate.
1348    pub fn locked_axes(mut self, locked_axes: LockedAxes) -> Self {
1349        self.mprops_flags = locked_axes;
1350        self
1351    }
1352
1353    /// Prevents this rigid-body from translating because of forces.
1354    pub fn lock_translations(mut self) -> Self {
1355        self.mprops_flags.set(LockedAxes::TRANSLATION_LOCKED, true);
1356        self
1357    }
1358
1359    /// Only allow translations of this rigid-body around specific coordinate axes.
1360    pub fn enabled_translations(
1361        mut self,
1362        allow_translations_x: bool,
1363        allow_translations_y: bool,
1364        #[cfg(feature = "dim3")] allow_translations_z: bool,
1365    ) -> Self {
1366        self.mprops_flags
1367            .set(LockedAxes::TRANSLATION_LOCKED_X, !allow_translations_x);
1368        self.mprops_flags
1369            .set(LockedAxes::TRANSLATION_LOCKED_Y, !allow_translations_y);
1370        #[cfg(feature = "dim3")]
1371        self.mprops_flags
1372            .set(LockedAxes::TRANSLATION_LOCKED_Z, !allow_translations_z);
1373        self
1374    }
1375
1376    #[deprecated(note = "Use `enabled_translations` instead")]
1377    /// Only allow translations of this rigid-body around specific coordinate axes.
1378    pub fn restrict_translations(
1379        self,
1380        allow_translations_x: bool,
1381        allow_translations_y: bool,
1382        #[cfg(feature = "dim3")] allow_translations_z: bool,
1383    ) -> Self {
1384        self.enabled_translations(
1385            allow_translations_x,
1386            allow_translations_y,
1387            #[cfg(feature = "dim3")]
1388            allow_translations_z,
1389        )
1390    }
1391
1392    /// Prevents this rigid-body from rotating because of forces.
1393    pub fn lock_rotations(mut self) -> Self {
1394        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_X, true);
1395        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_Y, true);
1396        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_Z, true);
1397        self
1398    }
1399
1400    /// Only allow rotations of this rigid-body around specific coordinate axes.
1401    #[cfg(feature = "dim3")]
1402    pub fn enabled_rotations(
1403        mut self,
1404        allow_rotations_x: bool,
1405        allow_rotations_y: bool,
1406        allow_rotations_z: bool,
1407    ) -> Self {
1408        self.mprops_flags
1409            .set(LockedAxes::ROTATION_LOCKED_X, !allow_rotations_x);
1410        self.mprops_flags
1411            .set(LockedAxes::ROTATION_LOCKED_Y, !allow_rotations_y);
1412        self.mprops_flags
1413            .set(LockedAxes::ROTATION_LOCKED_Z, !allow_rotations_z);
1414        self
1415    }
1416
1417    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
1418    #[deprecated(note = "Use `enabled_rotations` instead")]
1419    #[cfg(feature = "dim3")]
1420    pub fn restrict_rotations(
1421        self,
1422        allow_rotations_x: bool,
1423        allow_rotations_y: bool,
1424        allow_rotations_z: bool,
1425    ) -> Self {
1426        self.enabled_rotations(allow_rotations_x, allow_rotations_y, allow_rotations_z)
1427    }
1428
1429    /// Sets the damping factor for the linear part of the rigid-body motion.
1430    ///
1431    /// The higher the linear damping factor is, the more quickly the rigid-body
1432    /// will slow-down its translational movement.
1433    pub fn linear_damping(mut self, factor: Real) -> Self {
1434        self.linear_damping = factor;
1435        self
1436    }
1437
1438    /// Sets the damping factor for the angular part of the rigid-body motion.
1439    ///
1440    /// The higher the angular damping factor is, the more quickly the rigid-body
1441    /// will slow-down its rotational movement.
1442    pub fn angular_damping(mut self, factor: Real) -> Self {
1443        self.angular_damping = factor;
1444        self
1445    }
1446
1447    /// Sets the initial linear velocity of the rigid-body to be created.
1448    pub fn linvel(mut self, linvel: Vector<Real>) -> Self {
1449        self.linvel = linvel;
1450        self
1451    }
1452
1453    /// Sets the initial angular velocity of the rigid-body to be created.
1454    pub fn angvel(mut self, angvel: AngVector<Real>) -> Self {
1455        self.angvel = angvel;
1456        self
1457    }
1458
1459    /// Sets whether the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
1460    pub fn can_sleep(mut self, can_sleep: bool) -> Self {
1461        self.can_sleep = can_sleep;
1462        self
1463    }
1464
1465    /// Sets whether Continuous Collision-Detection is enabled for this rigid-body.
1466    ///
1467    /// CCD prevents tunneling, but may still allow limited interpenetration of colliders.
1468    pub fn ccd_enabled(mut self, enabled: bool) -> Self {
1469        self.ccd_enabled = enabled;
1470        self
1471    }
1472
1473    /// Sets the maximum prediction distance Soft Continuous Collision-Detection.
1474    ///
1475    /// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
1476    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
1477    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
1478    /// performance badly by increasing the work needed from the broad-phase.
1479    ///
1480    /// It is a generally cheaper variant of regular CCD (that can be enabled with
1481    /// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
1482    /// shape-cast and substeps.
1483    pub fn soft_ccd_prediction(mut self, prediction_distance: Real) -> Self {
1484        self.soft_ccd_prediction = prediction_distance;
1485        self
1486    }
1487
1488    /// Sets whether the rigid-body is to be created asleep.
1489    pub fn sleeping(mut self, sleeping: bool) -> Self {
1490        self.sleeping = sleeping;
1491        self
1492    }
1493
1494    /// Enable or disable the rigid-body after its creation.
1495    pub fn enabled(mut self, enabled: bool) -> Self {
1496        self.enabled = enabled;
1497        self
1498    }
1499
1500    /// Build a new rigid-body with the parameters configured with this builder.
1501    pub fn build(&self) -> RigidBody {
1502        let mut rb = RigidBody::new();
1503        rb.pos.next_position = self.position;
1504        rb.pos.position = self.position;
1505        rb.vels.linvel = self.linvel;
1506        rb.vels.angvel = self.angvel;
1507        rb.body_type = self.body_type;
1508        rb.user_data = self.user_data;
1509        rb.additional_solver_iterations = self.additional_solver_iterations;
1510
1511        if self.additional_mass_properties
1512            != RigidBodyAdditionalMassProps::MassProps(MassProperties::zero())
1513            && self.additional_mass_properties != RigidBodyAdditionalMassProps::Mass(0.0)
1514        {
1515            rb.mprops.additional_local_mprops = Some(Box::new(self.additional_mass_properties));
1516        }
1517
1518        rb.mprops.flags = self.mprops_flags;
1519        rb.damping.linear_damping = self.linear_damping;
1520        rb.damping.angular_damping = self.angular_damping;
1521        rb.forces.gravity_scale = self.gravity_scale;
1522        rb.dominance = RigidBodyDominance(self.dominance_group);
1523        rb.enabled = self.enabled;
1524        rb.enable_ccd(self.ccd_enabled);
1525        rb.set_soft_ccd_prediction(self.soft_ccd_prediction);
1526
1527        if self.can_sleep && self.sleeping {
1528            rb.sleep();
1529        }
1530
1531        if !self.can_sleep {
1532            rb.activation.normalized_linear_threshold = -1.0;
1533            rb.activation.angular_threshold = -1.0;
1534        }
1535
1536        rb
1537    }
1538}
1539
1540impl From<RigidBodyBuilder> for RigidBody {
1541    fn from(val: RigidBodyBuilder) -> RigidBody {
1542        val.build()
1543    }
1544}