1use crate::dynamics::MassProperties;
2use crate::geometry::{
3 ColliderChanges, ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition,
4 ColliderSet, ColliderShape,
5};
6use crate::math::{
7 AngVector, AngularInertia, Isometry, Point, Real, Rotation, Translation, Vector,
8};
9use crate::parry::partitioning::IndexedData;
10use crate::utils::{SimdAngularInertia, SimdCross, SimdDot};
11use num::Zero;
12
13#[cfg(doc)]
14use super::IntegrationParameters;
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
18#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
19#[repr(transparent)]
20pub struct RigidBodyHandle(pub crate::data::arena::Index);
21
22impl RigidBodyHandle {
23 pub fn into_raw_parts(self) -> (u32, u32) {
25 self.0.into_raw_parts()
26 }
27
28 pub fn from_raw_parts(id: u32, generation: u32) -> Self {
30 Self(crate::data::arena::Index::from_raw_parts(id, generation))
31 }
32
33 pub fn invalid() -> Self {
35 Self(crate::data::arena::Index::from_raw_parts(
36 crate::INVALID_U32,
37 crate::INVALID_U32,
38 ))
39 }
40}
41
42impl IndexedData for RigidBodyHandle {
43 fn default() -> Self {
44 Self(IndexedData::default())
45 }
46
47 fn index(&self) -> usize {
48 self.0.index()
49 }
50}
51
52#[deprecated(note = "renamed as RigidBodyType")]
54pub type BodyStatus = RigidBodyType;
55
56#[derive(Copy, Clone, Debug, PartialEq, Eq)]
57#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
58pub enum RigidBodyType {
60 Dynamic = 0,
62 Fixed = 1,
64 KinematicPositionBased = 2,
71 KinematicVelocityBased = 3,
78 }
81
82impl RigidBodyType {
83 pub fn is_fixed(self) -> bool {
85 self == RigidBodyType::Fixed
86 }
87
88 pub fn is_dynamic(self) -> bool {
90 self == RigidBodyType::Dynamic
91 }
92
93 pub fn is_kinematic(self) -> bool {
95 self == RigidBodyType::KinematicPositionBased
96 || self == RigidBodyType::KinematicVelocityBased
97 }
98}
99
100bitflags::bitflags! {
101 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
102 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
103 pub struct RigidBodyChanges: u32 {
105 const MODIFIED = 1 << 0;
107 const POSITION = 1 << 1;
109 const SLEEP = 1 << 2;
111 const COLLIDERS = 1 << 3;
113 const TYPE = 1 << 4;
115 const DOMINANCE = 1 << 5;
117 const LOCAL_MASS_PROPERTIES = 1 << 6;
119 const ENABLED_OR_DISABLED = 1 << 7;
121 }
122}
123
124impl Default for RigidBodyChanges {
125 fn default() -> Self {
126 RigidBodyChanges::empty()
127 }
128}
129
130#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
131#[derive(Clone, Debug, Copy, PartialEq)]
132pub struct RigidBodyPosition {
134 pub position: Isometry<Real>,
136 pub next_position: Isometry<Real>,
146}
147
148impl Default for RigidBodyPosition {
149 fn default() -> Self {
150 Self {
151 position: Isometry::identity(),
152 next_position: Isometry::identity(),
153 }
154 }
155}
156
157impl RigidBodyPosition {
158 #[must_use]
161 pub fn interpolate_velocity(&self, inv_dt: Real, local_com: &Point<Real>) -> RigidBodyVelocity {
162 let com = self.position * local_com;
163 let shift = Translation::from(com.coords);
164 let dpos = shift.inverse() * self.next_position * self.position.inverse() * shift;
165
166 let angvel;
167 #[cfg(feature = "dim2")]
168 {
169 angvel = dpos.rotation.angle() * inv_dt;
170 }
171 #[cfg(feature = "dim3")]
172 {
173 angvel = dpos.rotation.scaled_axis() * inv_dt;
174 }
175 let linvel = dpos.translation.vector * inv_dt;
176
177 RigidBodyVelocity { linvel, angvel }
178 }
179
180 #[must_use]
184 pub fn integrate_forces_and_velocities(
185 &self,
186 dt: Real,
187 forces: &RigidBodyForces,
188 vels: &RigidBodyVelocity,
189 mprops: &RigidBodyMassProps,
190 ) -> Isometry<Real> {
191 let new_vels = forces.integrate(dt, vels, mprops);
192 new_vels.integrate(dt, &self.position, &mprops.local_mprops.local_com)
193 }
194}
195
196impl<T> From<T> for RigidBodyPosition
197where
198 Isometry<Real>: From<T>,
199{
200 fn from(position: T) -> Self {
201 let position = position.into();
202 Self {
203 position,
204 next_position: position,
205 }
206 }
207}
208
209bitflags::bitflags! {
210 #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
211 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
212 pub struct LockedAxes: u8 {
215 const TRANSLATION_LOCKED_X = 1 << 0;
217 const TRANSLATION_LOCKED_Y = 1 << 1;
219 const TRANSLATION_LOCKED_Z = 1 << 2;
221 const TRANSLATION_LOCKED = Self::TRANSLATION_LOCKED_X.bits() | Self::TRANSLATION_LOCKED_Y.bits() | Self::TRANSLATION_LOCKED_Z.bits();
223 const ROTATION_LOCKED_X = 1 << 3;
225 const ROTATION_LOCKED_Y = 1 << 4;
227 const ROTATION_LOCKED_Z = 1 << 5;
229 const ROTATION_LOCKED = Self::ROTATION_LOCKED_X.bits() | Self::ROTATION_LOCKED_Y.bits() | Self::ROTATION_LOCKED_Z.bits();
231 }
232}
233
234#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
236#[derive(Copy, Clone, Debug, PartialEq)]
237pub enum RigidBodyAdditionalMassProps {
238 MassProps(MassProperties),
240 Mass(Real),
243}
244
245impl Default for RigidBodyAdditionalMassProps {
246 fn default() -> Self {
247 RigidBodyAdditionalMassProps::MassProps(MassProperties::default())
248 }
249}
250
251#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
252#[derive(Clone, Debug, PartialEq)]
253pub struct RigidBodyMassProps {
255 pub flags: LockedAxes,
257 pub local_mprops: MassProperties,
259 pub additional_local_mprops: Option<Box<RigidBodyAdditionalMassProps>>,
261 pub world_com: Point<Real>,
263 pub effective_inv_mass: Vector<Real>,
265 pub effective_world_inv_inertia_sqrt: AngularInertia<Real>,
268}
269
270impl Default for RigidBodyMassProps {
271 fn default() -> Self {
272 Self {
273 flags: LockedAxes::empty(),
274 local_mprops: MassProperties::zero(),
275 additional_local_mprops: None,
276 world_com: Point::origin(),
277 effective_inv_mass: Vector::zero(),
278 effective_world_inv_inertia_sqrt: AngularInertia::zero(),
279 }
280 }
281}
282
283impl From<LockedAxes> for RigidBodyMassProps {
284 fn from(flags: LockedAxes) -> Self {
285 Self {
286 flags,
287 ..Self::default()
288 }
289 }
290}
291
292impl From<MassProperties> for RigidBodyMassProps {
293 fn from(local_mprops: MassProperties) -> Self {
294 Self {
295 local_mprops,
296 ..Default::default()
297 }
298 }
299}
300
301impl RigidBodyMassProps {
302 #[must_use]
304 pub fn mass(&self) -> Real {
305 crate::utils::inv(self.local_mprops.inv_mass)
306 }
307
308 #[must_use]
311 pub fn effective_mass(&self) -> Vector<Real> {
312 self.effective_inv_mass.map(crate::utils::inv)
313 }
314
315 #[must_use]
318 pub fn effective_angular_inertia_sqrt(&self) -> AngularInertia<Real> {
319 #[allow(unused_mut)] let mut ang_inertia = self.effective_world_inv_inertia_sqrt;
321
322 #[cfg(feature = "dim3")]
324 {
325 if self.flags.contains(LockedAxes::ROTATION_LOCKED_X) {
326 ang_inertia.m11 = 1.0;
327 }
328 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Y) {
329 ang_inertia.m22 = 1.0;
330 }
331 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Z) {
332 ang_inertia.m33 = 1.0;
333 }
334 }
335
336 #[allow(unused_mut)] let mut result = ang_inertia.inverse();
338
339 #[cfg(feature = "dim3")]
341 {
342 if self.flags.contains(LockedAxes::ROTATION_LOCKED_X) {
343 result.m11 = 0.0;
344 }
345 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Y) {
346 result.m22 = 0.0;
347 }
348 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Z) {
349 result.m33 = 0.0;
350 }
351 }
352
353 result
354 }
355
356 #[must_use]
359 pub fn effective_angular_inertia(&self) -> AngularInertia<Real> {
360 self.effective_angular_inertia_sqrt().squared()
361 }
362
363 pub fn recompute_mass_properties_from_colliders(
365 &mut self,
366 colliders: &ColliderSet,
367 attached_colliders: &RigidBodyColliders,
368 position: &Isometry<Real>,
369 ) {
370 let added_mprops = self
371 .additional_local_mprops
372 .as_ref()
373 .map(|mprops| **mprops)
374 .unwrap_or_else(|| RigidBodyAdditionalMassProps::MassProps(MassProperties::default()));
375
376 self.local_mprops = MassProperties::default();
377
378 for handle in &attached_colliders.0 {
379 if let Some(co) = colliders.get(*handle) {
380 if co.is_enabled() {
381 if let Some(co_parent) = co.parent {
382 let to_add = co
383 .mprops
384 .mass_properties(&*co.shape)
385 .transform_by(&co_parent.pos_wrt_parent);
386 self.local_mprops += to_add;
387 }
388 }
389 }
390 }
391
392 match added_mprops {
393 RigidBodyAdditionalMassProps::MassProps(mprops) => {
394 self.local_mprops += mprops;
395 }
396 RigidBodyAdditionalMassProps::Mass(mass) => {
397 let new_mass = self.local_mprops.mass() + mass;
398 self.local_mprops.set_mass(new_mass, true);
399 }
400 }
401
402 self.update_world_mass_properties(position);
403 }
404
405 pub fn update_world_mass_properties(&mut self, position: &Isometry<Real>) {
407 self.world_com = self.local_mprops.world_com(position);
408 self.effective_inv_mass = Vector::repeat(self.local_mprops.inv_mass);
409 self.effective_world_inv_inertia_sqrt =
410 self.local_mprops.world_inv_inertia_sqrt(&position.rotation);
411
412 if self.flags.contains(LockedAxes::TRANSLATION_LOCKED_X) {
414 self.effective_inv_mass.x = 0.0;
415 }
416
417 if self.flags.contains(LockedAxes::TRANSLATION_LOCKED_Y) {
418 self.effective_inv_mass.y = 0.0;
419 }
420
421 #[cfg(feature = "dim3")]
422 if self.flags.contains(LockedAxes::TRANSLATION_LOCKED_Z) {
423 self.effective_inv_mass.z = 0.0;
424 }
425
426 #[cfg(feature = "dim2")]
427 {
428 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Z) {
429 self.effective_world_inv_inertia_sqrt = 0.0;
430 }
431 }
432 #[cfg(feature = "dim3")]
433 {
434 if self.flags.contains(LockedAxes::ROTATION_LOCKED_X) {
435 self.effective_world_inv_inertia_sqrt.m11 = 0.0;
436 self.effective_world_inv_inertia_sqrt.m12 = 0.0;
437 self.effective_world_inv_inertia_sqrt.m13 = 0.0;
438 }
439
440 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Y) {
441 self.effective_world_inv_inertia_sqrt.m22 = 0.0;
442 self.effective_world_inv_inertia_sqrt.m12 = 0.0;
443 self.effective_world_inv_inertia_sqrt.m23 = 0.0;
444 }
445 if self.flags.contains(LockedAxes::ROTATION_LOCKED_Z) {
446 self.effective_world_inv_inertia_sqrt.m33 = 0.0;
447 self.effective_world_inv_inertia_sqrt.m13 = 0.0;
448 self.effective_world_inv_inertia_sqrt.m23 = 0.0;
449 }
450 }
451 }
452}
453
454#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
455#[derive(Clone, Debug, Copy, PartialEq)]
456pub struct RigidBodyVelocity {
458 pub linvel: Vector<Real>,
460 pub angvel: AngVector<Real>,
462}
463
464impl Default for RigidBodyVelocity {
465 fn default() -> Self {
466 Self::zero()
467 }
468}
469
470impl RigidBodyVelocity {
471 #[must_use]
473 pub fn new(linvel: Vector<Real>, angvel: AngVector<Real>) -> Self {
474 Self { linvel, angvel }
475 }
476
477 #[must_use]
482 #[cfg(feature = "dim2")]
483 pub fn from_slice(slice: &[Real]) -> Self {
484 Self {
485 linvel: Vector::new(slice[0], slice[1]),
486 angvel: slice[2],
487 }
488 }
489
490 #[must_use]
495 #[cfg(feature = "dim3")]
496 pub fn from_slice(slice: &[Real]) -> Self {
497 Self {
498 linvel: Vector::new(slice[0], slice[1], slice[2]),
499 angvel: AngVector::new(slice[3], slice[4], slice[5]),
500 }
501 }
502
503 #[must_use]
505 pub fn zero() -> Self {
506 Self {
507 linvel: na::zero(),
508 angvel: na::zero(),
509 }
510 }
511
512 #[inline]
516 pub fn as_slice(&self) -> &[Real] {
517 self.as_vector().as_slice()
518 }
519
520 #[inline]
524 pub fn as_mut_slice(&mut self) -> &mut [Real] {
525 self.as_vector_mut().as_mut_slice()
526 }
527
528 #[inline]
532 #[cfg(feature = "dim2")]
533 pub fn as_vector(&self) -> &na::Vector3<Real> {
534 unsafe { std::mem::transmute(self) }
535 }
536
537 #[inline]
541 #[cfg(feature = "dim2")]
542 pub fn as_vector_mut(&mut self) -> &mut na::Vector3<Real> {
543 unsafe { std::mem::transmute(self) }
544 }
545
546 #[inline]
550 #[cfg(feature = "dim3")]
551 pub fn as_vector(&self) -> &na::Vector6<Real> {
552 unsafe { std::mem::transmute(self) }
553 }
554
555 #[inline]
559 #[cfg(feature = "dim3")]
560 pub fn as_vector_mut(&mut self) -> &mut na::Vector6<Real> {
561 unsafe { std::mem::transmute(self) }
562 }
563
564 #[must_use]
566 pub fn transformed(self, rotation: &Rotation<Real>) -> Self {
567 Self {
568 linvel: rotation * self.linvel,
569 #[cfg(feature = "dim2")]
570 angvel: self.angvel,
571 #[cfg(feature = "dim3")]
572 angvel: rotation * self.angvel,
573 }
574 }
575
576 #[must_use]
582 pub fn pseudo_kinetic_energy(&self) -> Real {
583 0.5 * (self.linvel.norm_squared() + self.angvel.gdot(self.angvel))
584 }
585
586 #[must_use]
588 pub fn apply_damping(&self, dt: Real, damping: &RigidBodyDamping) -> Self {
589 RigidBodyVelocity {
590 linvel: self.linvel * (1.0 / (1.0 + dt * damping.linear_damping)),
591 angvel: self.angvel * (1.0 / (1.0 + dt * damping.angular_damping)),
592 }
593 }
594
595 #[must_use]
597 pub fn velocity_at_point(&self, point: &Point<Real>, world_com: &Point<Real>) -> Vector<Real> {
598 let dpt = point - world_com;
599 self.linvel + self.angvel.gcross(dpt)
600 }
601
602 #[must_use]
605 pub fn integrate(
606 &self,
607 dt: Real,
608 init_pos: &Isometry<Real>,
609 local_com: &Point<Real>,
610 ) -> Isometry<Real> {
611 let com = init_pos * local_com;
612 let shift = Translation::from(com.coords);
613 let mut result =
614 shift * Isometry::new(self.linvel * dt, self.angvel * dt) * shift.inverse() * init_pos;
615 result.rotation.renormalize_fast();
616 result
617 }
618
619 #[must_use]
621 pub fn is_zero(&self) -> bool {
622 self.linvel.is_zero() && self.angvel.is_zero()
623 }
624
625 #[must_use]
627 #[profiling::function]
628 pub fn kinetic_energy(&self, rb_mprops: &RigidBodyMassProps) -> Real {
629 let mut energy = (rb_mprops.mass() * self.linvel.norm_squared()) / 2.0;
630
631 #[cfg(feature = "dim2")]
632 if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
633 let inertia_sqrt = 1.0 / rb_mprops.effective_world_inv_inertia_sqrt;
634 energy += (inertia_sqrt * self.angvel).powi(2) / 2.0;
635 }
636
637 #[cfg(feature = "dim3")]
638 if !rb_mprops.effective_world_inv_inertia_sqrt.is_zero() {
639 let inertia_sqrt = rb_mprops
640 .effective_world_inv_inertia_sqrt
641 .inverse_unchecked();
642 energy += (inertia_sqrt * self.angvel).norm_squared() / 2.0;
643 }
644
645 energy
646 }
647
648 pub fn apply_impulse(&mut self, rb_mprops: &RigidBodyMassProps, impulse: Vector<Real>) {
652 self.linvel += impulse.component_mul(&rb_mprops.effective_inv_mass);
653 }
654
655 #[cfg(feature = "dim2")]
659 pub fn apply_torque_impulse(&mut self, rb_mprops: &RigidBodyMassProps, torque_impulse: Real) {
660 self.angvel += rb_mprops.effective_world_inv_inertia_sqrt
661 * (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse);
662 }
663
664 #[cfg(feature = "dim3")]
668 pub fn apply_torque_impulse(
669 &mut self,
670 rb_mprops: &RigidBodyMassProps,
671 torque_impulse: Vector<Real>,
672 ) {
673 self.angvel += rb_mprops.effective_world_inv_inertia_sqrt
674 * (rb_mprops.effective_world_inv_inertia_sqrt * torque_impulse);
675 }
676
677 pub fn apply_impulse_at_point(
681 &mut self,
682 rb_mprops: &RigidBodyMassProps,
683 impulse: Vector<Real>,
684 point: Point<Real>,
685 ) {
686 let torque_impulse = (point - rb_mprops.world_com).gcross(impulse);
687 self.apply_impulse(rb_mprops, impulse);
688 self.apply_torque_impulse(rb_mprops, torque_impulse);
689 }
690}
691
692impl std::ops::Mul<Real> for RigidBodyVelocity {
693 type Output = Self;
694
695 #[must_use]
696 fn mul(self, rhs: Real) -> Self {
697 RigidBodyVelocity {
698 linvel: self.linvel * rhs,
699 angvel: self.angvel * rhs,
700 }
701 }
702}
703
704impl std::ops::Add<RigidBodyVelocity> for RigidBodyVelocity {
705 type Output = Self;
706
707 #[must_use]
708 fn add(self, rhs: Self) -> Self {
709 RigidBodyVelocity {
710 linvel: self.linvel + rhs.linvel,
711 angvel: self.angvel + rhs.angvel,
712 }
713 }
714}
715
716impl std::ops::AddAssign<RigidBodyVelocity> for RigidBodyVelocity {
717 fn add_assign(&mut self, rhs: Self) {
718 self.linvel += rhs.linvel;
719 self.angvel += rhs.angvel;
720 }
721}
722
723#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
724#[derive(Clone, Debug, Copy, PartialEq)]
725pub struct RigidBodyDamping {
727 pub linear_damping: Real,
729 pub angular_damping: Real,
731}
732
733impl Default for RigidBodyDamping {
734 fn default() -> Self {
735 Self {
736 linear_damping: 0.0,
737 angular_damping: 0.0,
738 }
739 }
740}
741
742#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
743#[derive(Clone, Debug, Copy, PartialEq)]
744pub struct RigidBodyForces {
746 pub force: Vector<Real>,
748 pub torque: AngVector<Real>,
750 pub gravity_scale: Real,
753 pub user_force: Vector<Real>,
755 pub user_torque: AngVector<Real>,
757}
758
759impl Default for RigidBodyForces {
760 fn default() -> Self {
761 Self {
762 force: na::zero(),
763 torque: na::zero(),
764 gravity_scale: 1.0,
765 user_force: na::zero(),
766 user_torque: na::zero(),
767 }
768 }
769}
770
771impl RigidBodyForces {
772 #[must_use]
774 pub fn integrate(
775 &self,
776 dt: Real,
777 init_vels: &RigidBodyVelocity,
778 mprops: &RigidBodyMassProps,
779 ) -> RigidBodyVelocity {
780 let linear_acc = self.force.component_mul(&mprops.effective_inv_mass);
781 let angular_acc = mprops.effective_world_inv_inertia_sqrt
782 * (mprops.effective_world_inv_inertia_sqrt * self.torque);
783
784 RigidBodyVelocity {
785 linvel: init_vels.linvel + linear_acc * dt,
786 angvel: init_vels.angvel + angular_acc * dt,
787 }
788 }
789
790 pub fn compute_effective_force_and_torque(
793 &mut self,
794 gravity: &Vector<Real>,
795 mass: &Vector<Real>,
796 ) {
797 self.force = self.user_force + gravity.component_mul(mass) * self.gravity_scale;
798 self.torque = self.user_torque;
799 }
800
801 pub fn apply_force_at_point(
803 &mut self,
804 rb_mprops: &RigidBodyMassProps,
805 force: Vector<Real>,
806 point: Point<Real>,
807 ) {
808 self.user_force += force;
809 self.user_torque += (point - rb_mprops.world_com).gcross(force);
810 }
811}
812
813#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
814#[derive(Clone, Debug, Copy, PartialEq)]
815pub struct RigidBodyCcd {
817 pub ccd_thickness: Real,
820 pub ccd_max_dist: Real,
823 pub ccd_active: bool,
829 pub ccd_enabled: bool,
831 pub soft_ccd_prediction: Real,
833}
834
835impl Default for RigidBodyCcd {
836 fn default() -> Self {
837 Self {
838 ccd_thickness: Real::MAX,
839 ccd_max_dist: 0.0,
840 ccd_active: false,
841 ccd_enabled: false,
842 soft_ccd_prediction: 0.0,
843 }
844 }
845}
846
847impl RigidBodyCcd {
848 pub fn max_point_velocity(&self, vels: &RigidBodyVelocity) -> Real {
851 #[cfg(feature = "dim2")]
852 return vels.linvel.norm() + vels.angvel.abs() * self.ccd_max_dist;
853 #[cfg(feature = "dim3")]
854 return vels.linvel.norm() + vels.angvel.norm() * self.ccd_max_dist;
855 }
856
857 pub fn is_moving_fast(
859 &self,
860 dt: Real,
861 vels: &RigidBodyVelocity,
862 forces: Option<&RigidBodyForces>,
863 ) -> bool {
864 let threshold = self.ccd_thickness / 10.0;
873
874 if let Some(forces) = forces {
875 let linear_part = (vels.linvel + forces.force * dt).norm();
876 #[cfg(feature = "dim2")]
877 let angular_part = (vels.angvel + forces.torque * dt).abs() * self.ccd_max_dist;
878 #[cfg(feature = "dim3")]
879 let angular_part = (vels.angvel + forces.torque * dt).norm() * self.ccd_max_dist;
880 let vel_with_forces = linear_part + angular_part;
881 vel_with_forces > threshold
882 } else {
883 self.max_point_velocity(vels) * dt > threshold
884 }
885 }
886}
887
888#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
889#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, Hash)]
890pub struct RigidBodyIds {
892 pub(crate) active_island_id: usize,
893 pub(crate) active_set_id: usize,
894 pub(crate) active_set_offset: usize,
895 pub(crate) active_set_timestamp: u32,
896}
897
898#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
899#[derive(Default, Clone, Debug, PartialEq, Eq)]
900pub struct RigidBodyColliders(pub Vec<ColliderHandle>);
906
907impl RigidBodyColliders {
908 pub fn detach_collider(
910 &mut self,
911 rb_changes: &mut RigidBodyChanges,
912 co_handle: ColliderHandle,
913 ) {
914 if let Some(i) = self.0.iter().position(|e| *e == co_handle) {
915 rb_changes.set(
916 RigidBodyChanges::MODIFIED | RigidBodyChanges::COLLIDERS,
917 true,
918 );
919 self.0.swap_remove(i);
920 }
921 }
922
923 pub fn attach_collider(
925 &mut self,
926 rb_changes: &mut RigidBodyChanges,
927 rb_ccd: &mut RigidBodyCcd,
928 rb_mprops: &mut RigidBodyMassProps,
929 rb_pos: &RigidBodyPosition,
930 co_handle: ColliderHandle,
931 co_pos: &mut ColliderPosition,
932 co_parent: &ColliderParent,
933 co_shape: &ColliderShape,
934 co_mprops: &ColliderMassProps,
935 ) {
936 rb_changes.set(
937 RigidBodyChanges::MODIFIED | RigidBodyChanges::COLLIDERS,
938 true,
939 );
940
941 co_pos.0 = rb_pos.position * co_parent.pos_wrt_parent;
942 rb_ccd.ccd_thickness = rb_ccd.ccd_thickness.min(co_shape.ccd_thickness());
943
944 let shape_bsphere = co_shape.compute_bounding_sphere(&co_parent.pos_wrt_parent);
945 rb_ccd.ccd_max_dist = rb_ccd
946 .ccd_max_dist
947 .max(shape_bsphere.center.coords.norm() + shape_bsphere.radius);
948
949 let mass_properties = co_mprops
950 .mass_properties(&**co_shape)
951 .transform_by(&co_parent.pos_wrt_parent);
952 self.0.push(co_handle);
953 rb_mprops.local_mprops += mass_properties;
954 rb_mprops.update_world_mass_properties(&rb_pos.position);
955 }
956
957 pub fn update_positions(
959 &self,
960 colliders: &mut ColliderSet,
961 modified_colliders: &mut Vec<ColliderHandle>,
962 parent_pos: &Isometry<Real>,
963 ) {
964 for handle in &self.0 {
965 let co = colliders.index_mut_internal(*handle);
967 let new_pos = parent_pos * co.parent.as_ref().unwrap().pos_wrt_parent;
968
969 if !co.changes.contains(ColliderChanges::MODIFIED) {
970 modified_colliders.push(*handle);
971 }
972
973 co.changes |= ColliderChanges::POSITION;
976 co.pos = ColliderPosition(new_pos);
977 }
978 }
979}
980
981#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
982#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
983pub struct RigidBodyDominance(pub i8);
985
986impl RigidBodyDominance {
987 pub fn effective_group(&self, status: &RigidBodyType) -> i16 {
989 if status.is_dynamic() {
990 self.0 as i16
991 } else {
992 i8::MAX as i16 + 1
993 }
994 }
995}
996
997#[derive(Copy, Clone, Debug, PartialEq)]
1002#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1003pub struct RigidBodyActivation {
1004 pub normalized_linear_threshold: Real,
1009 pub angular_threshold: Real,
1011 pub time_until_sleep: Real,
1013 pub time_since_can_sleep: Real,
1015 pub sleeping: bool,
1017}
1018
1019impl Default for RigidBodyActivation {
1020 fn default() -> Self {
1021 Self::active()
1022 }
1023}
1024
1025impl RigidBodyActivation {
1026 pub fn default_normalized_linear_threshold() -> Real {
1028 0.4
1029 }
1030
1031 pub fn default_angular_threshold() -> Real {
1033 0.5
1034 }
1035
1036 pub fn default_time_until_sleep() -> Real {
1039 2.0
1040 }
1041
1042 pub fn active() -> Self {
1044 RigidBodyActivation {
1045 normalized_linear_threshold: Self::default_normalized_linear_threshold(),
1046 angular_threshold: Self::default_angular_threshold(),
1047 time_until_sleep: Self::default_time_until_sleep(),
1048 time_since_can_sleep: 0.0,
1049 sleeping: false,
1050 }
1051 }
1052
1053 pub fn inactive() -> Self {
1055 RigidBodyActivation {
1056 normalized_linear_threshold: Self::default_normalized_linear_threshold(),
1057 angular_threshold: Self::default_angular_threshold(),
1058 time_until_sleep: Self::default_time_until_sleep(),
1059 time_since_can_sleep: Self::default_time_until_sleep(),
1060 sleeping: true,
1061 }
1062 }
1063
1064 pub fn cannot_sleep() -> Self {
1066 RigidBodyActivation {
1067 normalized_linear_threshold: -1.0,
1068 angular_threshold: -1.0,
1069 ..Self::active()
1070 }
1071 }
1072
1073 #[inline]
1075 pub fn is_active(&self) -> bool {
1076 !self.sleeping
1077 }
1078
1079 #[inline]
1081 pub fn wake_up(&mut self, strong: bool) {
1082 self.sleeping = false;
1083 if strong {
1084 self.time_since_can_sleep = 0.0;
1085 }
1086 }
1087
1088 #[inline]
1090 pub fn sleep(&mut self) {
1091 self.sleeping = true;
1092 self.time_since_can_sleep = self.time_until_sleep;
1093 }
1094}