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#[derive(Debug, Clone)]
20pub struct RigidBody {
21 pub(crate) pos: RigidBodyPosition,
22 pub(crate) mprops: RigidBodyMassProps,
23 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 pub(crate) activation: RigidBodyActivation,
35 pub(crate) changes: RigidBodyChanges,
36 pub(crate) body_type: RigidBodyType,
38 pub(crate) dominance: RigidBodyDominance,
40 pub(crate) enabled: bool,
41 pub(crate) additional_solver_iterations: usize,
42 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 pub fn copy_from(&mut self, other: &RigidBody) {
96 let RigidBody {
99 pos,
100 mprops,
101 integrated_vels,
102 vels,
103 damping,
104 forces,
105 ccd,
106 ids: _ids, colliders: _colliders, activation,
109 changes: _changes, 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 pub fn additional_solver_iterations(&self) -> usize {
139 self.additional_solver_iterations
140 }
141
142 pub fn set_additional_solver_iterations(&mut self, additional_iterations: usize) {
152 self.additional_solver_iterations = additional_iterations;
153 }
154
155 pub fn activation(&self) -> &RigidBodyActivation {
157 &self.activation
158 }
159
160 pub fn activation_mut(&mut self) -> &mut RigidBodyActivation {
162 self.changes |= RigidBodyChanges::SLEEP;
163 &mut self.activation
164 }
165
166 pub fn is_enabled(&self) -> bool {
168 self.enabled
169 }
170
171 pub fn set_enabled(&mut self, enabled: bool) {
173 if enabled != self.enabled {
174 if enabled {
175 self.changes = RigidBodyChanges::all();
180 } else {
181 self.changes |= RigidBodyChanges::ENABLED_OR_DISABLED;
182 }
183
184 self.enabled = enabled;
185 }
186 }
187
188 #[inline]
190 pub fn linear_damping(&self) -> Real {
191 self.damping.linear_damping
192 }
193
194 #[inline]
196 pub fn set_linear_damping(&mut self, damping: Real) {
197 self.damping.linear_damping = damping;
198 }
199
200 #[inline]
202 pub fn angular_damping(&self) -> Real {
203 self.damping.angular_damping
204 }
205
206 #[inline]
208 pub fn set_angular_damping(&mut self, damping: Real) {
209 self.damping.angular_damping = damping
210 }
211
212 pub fn body_type(&self) -> RigidBodyType {
214 self.body_type
215 }
216
217 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 #[inline]
235 pub fn center_of_mass(&self) -> &Point<Real> {
236 &self.mprops.world_com
237 }
238
239 #[inline]
241 pub fn local_center_of_mass(&self) -> &Point<Real> {
242 &self.mprops.local_mprops.local_com
243 }
244
245 #[inline]
247 pub fn mass_properties(&self) -> &RigidBodyMassProps {
248 &self.mprops
249 }
250
251 #[inline]
256 pub fn effective_dominance_group(&self) -> i16 {
257 self.dominance.effective_group(&self.body_type)
258 }
259
260 #[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 #[inline]
275 pub fn locked_axes(&self) -> LockedAxes {
276 self.mprops.flags
277 }
278
279 #[inline]
280 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 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 #[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 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 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 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 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 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 #[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 #[cfg(feature = "dim3")]
427 pub fn is_translation_locked(&self) -> bool {
428 self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED)
429 }
430
431 #[cfg(feature = "dim2")]
433 pub fn is_rotation_locked(&self) -> bool {
434 self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z)
435 }
436
437 #[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 pub fn enable_ccd(&mut self, enabled: bool) {
451 self.ccd.ccd_enabled = enabled;
452 }
453
454 pub fn is_ccd_enabled(&self) -> bool {
456 self.ccd.ccd_enabled
457 }
458
459 pub fn set_soft_ccd_prediction(&mut self, prediction_distance: Real) {
470 self.ccd.soft_ccd_prediction = prediction_distance;
471 }
472
473 pub fn soft_ccd_prediction(&self) -> Real {
478 self.ccd.soft_ccd_prediction
479 }
480
481 pub fn is_ccd_active(&self) -> bool {
493 self.ccd.ccd_active
494 }
495
496 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 #[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 #[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 pub fn colliders(&self) -> &[ColliderHandle] {
576 &self.colliders.0[..]
577 }
578
579 pub fn is_dynamic(&self) -> bool {
583 self.body_type == RigidBodyType::Dynamic
584 }
585
586 pub fn is_kinematic(&self) -> bool {
590 self.body_type.is_kinematic()
591 }
592
593 pub fn is_fixed(&self) -> bool {
597 self.body_type == RigidBodyType::Fixed
598 }
599
600 pub fn mass(&self) -> Real {
604 self.mprops.local_mprops.mass()
605 }
606
607 pub fn next_position(&self) -> &Isometry<Real> {
613 &self.pos.next_position
614 }
615
616 pub fn gravity_scale(&self) -> Real {
618 self.forces.gravity_scale
619 }
620
621 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 pub fn dominance_group(&self) -> i8 {
635 self.dominance.0
636 }
637
638 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 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 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 pub fn sleep(&mut self) {
682 self.activation.sleep();
683 self.vels = RigidBodyVelocity::zero();
684 }
685
686 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 pub fn is_sleeping(&self) -> bool {
700 self.activation.sleeping
705 }
706
707 pub fn is_moving(&self) -> bool {
709 !self.vels.linvel.is_zero() || !self.vels.angvel.is_zero()
710 }
711
712 pub fn vels(&self) -> &RigidBodyVelocity {
714 &self.vels
715 }
716
717 pub fn linvel(&self) -> &Vector<Real> {
719 &self.vels.linvel
720 }
721
722 #[cfg(feature = "dim2")]
724 pub fn angvel(&self) -> Real {
725 self.vels.angvel
726 }
727
728 #[cfg(feature = "dim3")]
730 pub fn angvel(&self) -> &Vector<Real> {
731 &self.vels.angvel
732 }
733
734 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 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 #[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 #[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 #[inline]
810 pub fn position(&self) -> &Isometry<Real> {
811 &self.pos.position
812 }
813
814 #[inline]
816 pub fn translation(&self) -> &Vector<Real> {
817 &self.pos.position.translation.vector
818 }
819
820 #[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 self.update_world_mass_properties();
832
833 if wake_up && self.is_dynamic() {
835 self.wake_up(true)
836 }
837 }
838 }
839
840 #[inline]
842 pub fn rotation(&self) -> &Rotation<Real> {
843 &self.pos.position.rotation
844 }
845
846 #[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 self.update_world_mass_properties();
856
857 if wake_up && self.is_dynamic() {
859 self.wake_up(true)
860 }
861 }
862 }
863
864 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 self.update_world_mass_properties();
881
882 if wake_up && self.is_dynamic() {
884 self.wake_up(true)
885 }
886 }
887 }
888
889 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 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 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 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 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 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 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
953impl RigidBody {
955 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 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 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 #[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 #[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 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
1033impl RigidBody {
1035 #[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 #[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 #[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 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 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 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 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 pub fn kinetic_energy(&self) -> Real {
1126 self.vels.kinetic_energy(&self.mprops)
1127 }
1128
1129 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 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#[derive(Clone, Debug, PartialEq)]
1147#[must_use = "Builder functions return the updated builder"]
1148pub struct RigidBodyBuilder {
1149 pub position: Isometry<Real>,
1151 pub linvel: Vector<Real>,
1153 pub angvel: AngVector<Real>,
1155 pub gravity_scale: Real,
1157 pub linear_damping: Real,
1159 pub angular_damping: Real,
1161 pub body_type: RigidBodyType,
1163 mprops_flags: LockedAxes,
1164 additional_mass_properties: RigidBodyAdditionalMassProps,
1166 pub can_sleep: bool,
1168 pub sleeping: bool,
1170 pub ccd_enabled: bool,
1174 pub soft_ccd_prediction: Real,
1185 pub dominance_group: i8,
1187 pub enabled: bool,
1189 pub user_data: u128,
1191 pub additional_solver_iterations: usize,
1196}
1197
1198impl Default for RigidBodyBuilder {
1199 fn default() -> Self {
1200 Self::dynamic()
1201 }
1202}
1203
1204impl RigidBodyBuilder {
1205 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 #[deprecated(note = "use `RigidBodyBuilder::fixed()` instead")]
1230 pub fn new_static() -> Self {
1231 Self::fixed()
1232 }
1233 #[deprecated(note = "use `RigidBodyBuilder::kinematic_velocity_based()` instead")]
1235 pub fn new_kinematic_velocity_based() -> Self {
1236 Self::kinematic_velocity_based()
1237 }
1238 #[deprecated(note = "use `RigidBodyBuilder::kinematic_position_based()` instead")]
1240 pub fn new_kinematic_position_based() -> Self {
1241 Self::kinematic_position_based()
1242 }
1243
1244 pub fn fixed() -> Self {
1246 Self::new(RigidBodyType::Fixed)
1247 }
1248
1249 pub fn kinematic_velocity_based() -> Self {
1251 Self::new(RigidBodyType::KinematicVelocityBased)
1252 }
1253
1254 pub fn kinematic_position_based() -> Self {
1256 Self::new(RigidBodyType::KinematicPositionBased)
1257 }
1258
1259 pub fn dynamic() -> Self {
1261 Self::new(RigidBodyType::Dynamic)
1262 }
1263
1264 pub fn additional_solver_iterations(mut self, additional_iterations: usize) -> Self {
1269 self.additional_solver_iterations = additional_iterations;
1270 self
1271 }
1272
1273 pub fn gravity_scale(mut self, scale_factor: Real) -> Self {
1275 self.gravity_scale = scale_factor;
1276 self
1277 }
1278
1279 pub fn dominance_group(mut self, group: i8) -> Self {
1281 self.dominance_group = group;
1282 self
1283 }
1284
1285 pub fn translation(mut self, translation: Vector<Real>) -> Self {
1287 self.position.translation.vector = translation;
1288 self
1289 }
1290
1291 pub fn rotation(mut self, angle: AngVector<Real>) -> Self {
1293 self.position.rotation = Rotation::new(angle);
1294 self
1295 }
1296
1297 pub fn position(mut self, pos: Isometry<Real>) -> Self {
1299 self.position = pos;
1300 self
1301 }
1302
1303 pub fn user_data(mut self, data: u128) -> Self {
1305 self.user_data = data;
1306 self
1307 }
1308
1309 pub fn additional_mass_properties(mut self, mprops: MassProperties) -> Self {
1323 self.additional_mass_properties = RigidBodyAdditionalMassProps::MassProps(mprops);
1324 self
1325 }
1326
1327 pub fn additional_mass(mut self, mass: Real) -> Self {
1343 self.additional_mass_properties = RigidBodyAdditionalMassProps::Mass(mass);
1344 self
1345 }
1346
1347 pub fn locked_axes(mut self, locked_axes: LockedAxes) -> Self {
1349 self.mprops_flags = locked_axes;
1350 self
1351 }
1352
1353 pub fn lock_translations(mut self) -> Self {
1355 self.mprops_flags.set(LockedAxes::TRANSLATION_LOCKED, true);
1356 self
1357 }
1358
1359 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 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 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 #[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 #[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 pub fn linear_damping(mut self, factor: Real) -> Self {
1434 self.linear_damping = factor;
1435 self
1436 }
1437
1438 pub fn angular_damping(mut self, factor: Real) -> Self {
1443 self.angular_damping = factor;
1444 self
1445 }
1446
1447 pub fn linvel(mut self, linvel: Vector<Real>) -> Self {
1449 self.linvel = linvel;
1450 self
1451 }
1452
1453 pub fn angvel(mut self, angvel: AngVector<Real>) -> Self {
1455 self.angvel = angvel;
1456 self
1457 }
1458
1459 pub fn can_sleep(mut self, can_sleep: bool) -> Self {
1461 self.can_sleep = can_sleep;
1462 self
1463 }
1464
1465 pub fn ccd_enabled(mut self, enabled: bool) -> Self {
1469 self.ccd_enabled = enabled;
1470 self
1471 }
1472
1473 pub fn soft_ccd_prediction(mut self, prediction_distance: Real) -> Self {
1484 self.soft_ccd_prediction = prediction_distance;
1485 self
1486 }
1487
1488 pub fn sleeping(mut self, sleeping: bool) -> Self {
1490 self.sleeping = sleeping;
1491 self
1492 }
1493
1494 pub fn enabled(mut self, enabled: bool) -> Self {
1496 self.enabled = enabled;
1497 self
1498 }
1499
1500 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}